ftp.nice.ch/pub/next/developer/resources/classes/CustomMenu.s.tar.gz#/CustomMenuSources/CustomMenu/CustomMenu.subproj/CustomMenu.m

This is CustomMenu.m in view mode; [Download] [Up]

// Written by Gideon King
 
//
// Source file      : CustomMenu.m
// Created by       : gideon@berd
// Created on       : Fri Sep 8 16:26:38 NZST 1995
// RCS File         : $Source: /Ramoth/Black.Albatross/CVS/CustomMenu/CustomMenu.subproj/CustomMenu.m,v $
// Last modified    : $Date: 1995/09/10 22:38:07 $
// Last modified by : $Author: gideon $
// Current Revision : $Revision: 1.1.1.1 $
//
 
static const char RCSId[] = "$Id: CustomMenu.m,v 1.1.1.1 1995/09/10 22:38:07 gideon Exp $";
 

// This class is set up to be the destination of the drag operation. It creates new menu items as required,
// and deletes unwanted items when you Control-click on the item. I tried all sorts of strategies to remove
// submenus, and didn't sort it out. What I therefore do is remove the item from the submenu and close myself,
// so you can't get at me again. This means that you can't access the menu again, and it is not saved to the
// menu list file, so it only takes up a bit of memory until you restart the app. Not very nice, and I'd like 
// to sort it out. Any suggestions???

#import "CustomMenu.h"

@implementation CustomMenu

- (const char *)version
{
	return RCSId;
}

- myInit
{
	const char *const types[] = {MHMenuCellPboardType};
	
	// Register which pasteboard we you will accept
    [self registerForDraggedTypes:(const char *const*)&types count:1];
	
	return self;
}

// Normal menu initialisers
- init
{
	[super init];
	[self myInit];
	return self;
}

- initTitle:(const char *)aTitle
{
	[super initTitle:aTitle];
	[self myInit];
	return self;
}

// Used in this case for removing menu items when a Control key is down
- mouseDown:(NXEvent *)theEvent
{		
	// Only remove the item from the menu a Control key is down
	// This is not really a very destructive operation, so we won't ask for confirmation
	if (theEvent->flags & NX_CONTROLMASK)
	{	
		if ([matrix cellCount] > 1)
		{
			// To avoid removing it from the view hierarchy while it is still lockFocused
			[self perform:@selector(removeCell:) with:[matrix selectedCell] afterDelay:0 cancelPrevious:YES];
		}
		else
		{
			// They have just thrown away the last item on this menu - let's get rid of the menu itself
			id itemList = [supermenu itemList];
			int i;
			
			for (i = 0; i < [itemList cellCount]; i++)
			{
				id thisCell = [itemList cellAt:i :0];
				
				if((strcmp([self title], [thisCell title]) == 0) && ([thisCell tag] == 42131))
				{	// We have found the cell which controls us
					[itemList removeRowAt:i andFree:YES];
					[supermenu setItemList:itemList];
					[supermenu display];
					
// The following doesn't work for some reason - when you click on the main menu again, it tells you that it
// is trying to send the message isSelectable to a freed object. I don't understand!
//					[self perform:@selector(free) with:nil afterDelay:10 cancelPrevious:YES];

					[self perform:@selector(close) with:nil afterDelay:10 cancelPrevious:YES];

					return self;
				}
			}
		}
	}	
	else
	{
		[super mouseDown:theEvent];
	}
    return self;
}

// methods to be the destination of a dragging operation
- (NXDragOperation)draggingEntered:sender
{
	return NX_DragOperationCopy;
}

- (BOOL)prepareForDragOperation:sender
{
	return YES;
}

- (BOOL)performDragOperation:sender
{
	// Here is where we do the real work
	id pboard = [sender draggingPasteboard];
    NXStream *stream;
    NXTypedStream *ts;
	id newCell;
	
	// Read the dragged cell from the pasteboard
	stream = [pboard readTypeToStream:MHMenuCellPboardType];
	ts = NXOpenTypedStream(stream, NX_READONLY);
	newCell = NXReadObject(ts);
	NXCloseTypedStream(ts);
	NXCloseMemory(stream, NX_FREEBUFFER);
	
	// Now add the cell to the end of the menu
	// This could be enhanced to note where they dropped and insert a cell at the appropriate place
	[matrix addRow];
	[matrix putCell:newCell at:[matrix cellCount]-1 :0];
	[self setItemList:matrix];
	[self display];
	return YES;
}

// Done with a performWith... to avoid lockFocus problems
- removeCell:aCell
{
	int row, col;
	
	[matrix getRow:&row andCol:&col ofCell:aCell];
	[matrix removeRowAt:row andFree:YES];
	[self setItemList:matrix];
	[self display];
	return self;
}

@end

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.