Fix numerous issues with toolbar customization

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@30143 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Doug Simons 2010-04-13 21:38:31 +00:00
parent c46d450978
commit fe66919f5b
6 changed files with 240 additions and 97 deletions

View file

@ -1,3 +1,16 @@
2010-04-13 Doug Simons <doug.simons@testplant.com>
* Headers/Additions/GNUstepGUI/GSToolbarView.h:
* Source/GSToolbarView.m:
* Source/GSToolbarCustomizationPalette.m:
* Source/NSToolbar.m:
* Source/NSToolbarItem.m:
Fix numerous issues with toolbar customization, including: fix
crash when customization palette closed; make customization palette
a floating panel centered below toolbar; rewrote dragging code
to work well; layout toolbar items when added to toolbar; resize
customization palette to fit items; etc.
2010-04-13 Jonathan Gillaspie <jonathan.gillaspie@testplant.com>
* Source/GSToolTips.m: Use a single retain window for tooltips instead of a

View file

@ -55,12 +55,14 @@ typedef enum {
NSToolbar *_toolbar;
NSClipView *_clipView;
GSToolbarClippedItemsButton *_clippedItemsMark;
NSMutableArray *_visibleBackViews;
unsigned int _borderMask;
NSRect _rectAvailable;
float _heightFromLayout;
}
+ (int) draggedItemIndex;
+ (void) setDraggedItemIndex:(int)sourceIndex;
- (id) initWithFrame: (NSRect)frame;
// Accessors

View file

@ -99,6 +99,7 @@
// Loop over all subviews
while ((layoutedView = [e nextObject]) != nil)
{
[(id)layoutedView layout];
NSRect frame = [layoutedView frame];
NSSize size = frame.size;
float height = size.height;
@ -124,9 +125,18 @@
[layoutedView setFrameOrigin: NSMakePoint(hAccumulator,
maxHeight - vAccumulator)];
[layoutedView setAutoresizingMask:NSViewMinYMargin];
hAccumulator += width;
index++;
}
maxHeight -= vAccumulator; // adjust for final row
if (maxHeight != 0) // need to grow (or shrink) the window to accommodate more (or fewer) items
{
NSRect windowFrame = [[self window] frame];
windowFrame.origin.y += maxHeight;
windowFrame.size.height -= maxHeight;
[[self window] setFrame:windowFrame display:NO];
}
}
- (void) setToolbarItems: (NSArray *)items
@ -204,12 +214,12 @@
[nc removeObserver: self];
DESTROY(_customizationWindow);
DESTROY(_customizationView);
DESTROY(_defaultTemplateView);
DESTROY(_sizeCheckBox);
DESTROY(_displayPopup);
DESTROY(_doneButton);
// DESTROY(_customizationWindow);
// DESTROY(_customizationView);
// DESTROY(_defaultTemplateView);
// DESTROY(_sizeCheckBox);
// DESTROY(_displayPopup);
// DESTROY(_doneButton);
DESTROY(_defaultItems);
DESTROY(_allowedItems);
@ -223,6 +233,19 @@
NSDebugLLog(DEBUG_LEVEL, @"GSToolbarCustomizationPalette awaking from nib");
[_defaultTemplateView setAutoresizingMask:NSViewWidthSizable | NSViewMaxYMargin];
{
// for now, _defaultTemplateView isn't implemented, so remove it
NSRect dtvFrame = [_defaultTemplateView frame];
[_defaultTemplateView removeFromSuperview];
// expand _customizationView to fill the space
NSRect cvFrame = [_customizationView frame];
cvFrame.size.height += dtvFrame.size.height;
cvFrame.origin.y -= dtvFrame.size.height;
[_customizationView setFrame:cvFrame];
}
[nc addObserver: self
selector: @selector(paletteDidEnd:)
name: NSWindowWillCloseNotification
@ -301,6 +324,17 @@
when it goes away. */
_toolbar = toolbar;
// position the customization window centered just below the toolbar
NSView *toolbarView = [_toolbar _toolbarView];
NSRect toolbarFrame = [toolbarView convertRect:[toolbarView bounds] toView:nil];
NSPoint bottomCenter = NSMakePoint(toolbarFrame.origin.x + (toolbarFrame.size.width/2), toolbarFrame.origin.y);
bottomCenter = [[toolbarView window] convertBaseToScreen:bottomCenter];
NSRect windowFrame = [_customizationWindow frame];
NSPoint topCenter = NSMakePoint(windowFrame.origin.x + (windowFrame.size.width/2), windowFrame.origin.y + windowFrame.size.height);
windowFrame.origin.x += bottomCenter.x-topCenter.x;
windowFrame.origin.y += bottomCenter.y-topCenter.y;
[_customizationWindow setFrame:windowFrame display:NO];
[_customizationWindow setLevel:NSFloatingWindowLevel];
[_customizationWindow makeKeyAndOrderFront: self];
}

View file

@ -66,6 +66,8 @@ static const int ClippedItemsViewWidth = 28;
static const int current_version = 1;
static NSColorList *SystemExtensionsColors;
static int draggedItemIndex = NSNotFound;
// Toolbar color extensions
static void initSystemExtensionsColors(void)
@ -315,73 +317,161 @@ static void initSystemExtensionsColors(void)
// Dragging related methods
+ (int) draggedItemIndex
{
return draggedItemIndex;
}
+ (void) setDraggedItemIndex:(int)sourceIndex
{
draggedItemIndex = sourceIndex;
}
- (int) _insertionIndexAtPoint: (NSPoint)location
{
id hitView = [self hitTest: location];
NSRect hitViewFrame = [hitView frame];
int index;
if ((hitView != nil)
&& ([hitView isKindOfClass: NSClassFromString(@"GSToolbarButton")]
|| [hitView isKindOfClass: NSClassFromString(@"GSToolbarBackView")]))
NSArray *visibleBackViews = [self _visibleBackViews];
location = [_clipView convertPoint:location fromView:nil];
if (draggedItemIndex == NSNotFound)
{
index = [_toolbar _indexOfItem: [hitView toolbarItem]];
if (location.x - hitViewFrame.origin.x > hitViewFrame.size.width / 2)
index++;
return index;
//simply locate the nearest location between existing items
for (index=0; index < [visibleBackViews count]; index++)
{
NSRect itemRect = [[visibleBackViews objectAtIndex:index] frame];
if (location.x < (itemRect.origin.x + (itemRect.size.width/2)))
{
NSLog(@"AT location %d", index);
return index;
}
}
return [visibleBackViews count];
}
return NSNotFound;
else
{
// don't return a different index unless drag has crossed the midpoint of its neighbor
NSRect itemRect;
BOOL draggingLeft = YES;
if (draggedItemIndex < [visibleBackViews count])
{
itemRect = [[visibleBackViews objectAtIndex:draggedItemIndex] frame];
draggingLeft = (location.x < (itemRect.origin.x + (itemRect.size.width/2)));
}
if (draggingLeft)
{
// dragging to the left of dragged item's current location
for (index=0; index < draggedItemIndex; index++)
{
itemRect = [[visibleBackViews objectAtIndex:index] frame];
if (location.x < (itemRect.origin.x + (itemRect.size.width/2)))
{
NSLog(@"To the LEFT of %d", index);
return index;
}
}
}
else
{
// dragging to the right of current location
for (index=[visibleBackViews count]-1; index > draggedItemIndex; index--)
{
itemRect = [[visibleBackViews objectAtIndex:index] frame];
if (location.x > (itemRect.origin.x + (itemRect.size.width/2)))
{
NSLog(@"To the RIGHT of %d", index);
return index;
}
}
}
return draggedItemIndex;
}
}
- (NSDragOperation) updateItemWhileDragging:(id <NSDraggingInfo>)info exited:(BOOL)exited
{
NSToolbarItem *item = [[info draggingSource] toolbarItem];
NSString *identifier = [item itemIdentifier];
NSToolbar *toolbar = [self toolbar];
NSArray *allowedItemIdentifiers = [[toolbar delegate] toolbarAllowedItemIdentifiers: toolbar];
// don't accept any dragging if the customization palette isn't running for this toolbar
if (![toolbar customizationPaletteIsRunning] || ![allowedItemIdentifiers containsObject: identifier])
{
return NSDragOperationNone;
}
if (draggedItemIndex == NSNotFound) // initialize the index for this drag session
{
// if duplicate items aren't allowed, see if we already have such an item
if (![item allowsDuplicatesInToolbar])
{
NSArray *items = [toolbar items];
int index;
for (index=0; index<[items count]; index++)
{
NSToolbarItem *anItem = [items objectAtIndex:index];
if ([[anItem itemIdentifier] isEqual:identifier])
{
draggedItemIndex = index; // drag the existing item
break;
}
}
}
}
else if (draggedItemIndex == -1)
{
// re-entering after being dragged off -- treat as unknown location
draggedItemIndex = NSNotFound;
}
int newIndex = [self _insertionIndexAtPoint: [info draggingLocation]];
if (draggedItemIndex != NSNotFound)
{
// existing item being dragged -- either move or remove it
if (exited)
{
[toolbar _removeItemAtIndex:draggedItemIndex broadcast:YES];
draggedItemIndex = -1; // no longer in our items
}
else
{
if (newIndex != draggedItemIndex)
{
[toolbar _moveItemFromIndex: draggedItemIndex toIndex: newIndex broadcast: YES];
draggedItemIndex = newIndex;
}
}
}
else if (!exited)
{
// new item being dragged in -- add it
[toolbar _insertItemWithItemIdentifier: identifier
atIndex: newIndex
broadcast: YES];
draggedItemIndex = newIndex;
}
return NSDragOperationGeneric;
}
- (NSDragOperation) draggingEntered: (id <NSDraggingInfo>)info
{
NSToolbar *toolbar = [self toolbar];
NSArray *allowedItemIdentifiers =
[[toolbar delegate] toolbarAllowedItemIdentifiers: toolbar];
NSString *itemIdentifier =
[(NSToolbarItem *)[[info draggingSource] toolbarItem] itemIdentifier];
if ([self _insertionIndexAtPoint: [info draggingLocation]] != NSNotFound
&& [allowedItemIdentifiers containsObject: itemIdentifier])
{
return NSDragOperationGeneric;
}
return NSDragOperationNone;
return [self updateItemWhileDragging:info exited:NO];
}
- (NSDragOperation) draggingUpdated: (id <NSDraggingInfo>)info
{
NSToolbar *toolbar = [self toolbar];
NSArray *allowedItemIdentifiers =
[[toolbar delegate] toolbarAllowedItemIdentifiers: toolbar];
NSString *itemIdentifier =
[(NSToolbarItem *)[[info draggingSource] toolbarItem] itemIdentifier];
if ([self _insertionIndexAtPoint: [info draggingLocation]] != NSNotFound
&& [allowedItemIdentifiers containsObject: itemIdentifier])
{
return NSDragOperationGeneric;
}
return NSDragOperationNone;
return [self updateItemWhileDragging:info exited:NO];
}
- (void) draggingEnded: (id <NSDraggingInfo>)info
{
NSPasteboard *pboard = [info draggingPasteboard];
NSString *str = [pboard stringForType: [[pboard types] objectAtIndex: 0]];
int index = [str intValue];
NSToolbar *toolbar = [self toolbar];
[toolbar _concludeRemoveItem:
[[info draggingSource] toolbarItem] atIndex: index broadcast: YES];
draggedItemIndex = NSNotFound;
}
- (void) draggingExited: (id <NSDraggingInfo>)info
{
// Nothing to do
[self updateItemWhileDragging:info exited:YES];
}
- (BOOL) prepareForDragOperation: (id <NSDraggingInfo>)info
@ -391,30 +481,11 @@ static void initSystemExtensionsColors(void)
- (BOOL) performDragOperation: (id <NSDraggingInfo>)info
{
NSPasteboard *pboard = [info draggingPasteboard];
NSString *str = [pboard stringForType: [[pboard types] objectAtIndex: 0]];
int index = [str intValue];
NSToolbar *toolbar = [self toolbar];
NSToolbarItem *item = [[info draggingSource] toolbarItem];
int newIndex = [self _insertionIndexAtPoint: [info draggingLocation]];
if(index == -1)
{
NSString *identifier = [item itemIdentifier];
if([_toolbar _containsItemWithIdentifier: identifier] == NO)
{
[toolbar _insertItemWithItemIdentifier: identifier
atIndex: newIndex
broadcast: YES];
}
RELEASE(item);
}
else
{
[toolbar _insertPassivelyItem:item atIndex: index];
RELEASE(item);
[toolbar _moveItemFromIndex: index toIndex: newIndex broadcast: YES];
}
[self updateItemWhileDragging:info exited:NO];
draggedItemIndex = NSNotFound;
// save the configuration...
[toolbar _saveConfig];
@ -549,7 +620,7 @@ static void initSystemExtensionsColors(void)
float x = 0;
float newHeight = 0;
// ---
NSArray *subviews = [self subviews];
NSArray *subviews = [_clipView subviews];
//_heightFromLayout = 0;
@ -774,8 +845,8 @@ static void initSystemExtensionsColors(void)
int i, n = [items count];
float backViewsWidth = 0, toolbarWidth = [self frame].size.width;
[_visibleBackViews release];
_visibleBackViews = [[NSMutableArray alloc] init];
//[_visibleBackViews release];
NSMutableArray *_visibleBackViews = [NSMutableArray array];
for (i = 0; i < n; i++)
{

View file

@ -943,7 +943,7 @@ static GSValidationCenter *vc = nil;
while ((itemIdentifier = [e nextObject]) != nil)
{
[self _insertItemWithItemIdentifier: itemIdentifier
atIndex: i
atIndex: [_items count]
broadcast: NO];
i++;
}
@ -1176,6 +1176,7 @@ static GSValidationCenter *vc = nil;
object: self
userInfo: [NSDictionary dictionaryWithObject: item forKey: @"item"]];
[item _setToolbar: self];
[item _layout];
[_items insertObject: item atIndex: index];
// We reload the toolbarView each time a new item is added except when

View file

@ -261,7 +261,7 @@ NSString *GSMovableToolbarItemPboardType = @"GSMovableToolbarItemPboardType";
NSImage *image = [[NSImage alloc] initWithSize: viewSize];
NSCell *cell = [self cell];
NSPasteboard *pboard;
int index = -1;
int index = NSNotFound;
// Prepare the drag
@ -286,6 +286,7 @@ NSString *GSMovableToolbarItemPboardType = @"GSMovableToolbarItemPboardType";
{
index = [toolbar _indexOfItem: _toolbarItem];
}
[GSToolbarView setDraggedItemIndex:index];
[pboard setString: [NSString stringWithFormat:@"%d", index]
forType: GSMovableToolbarItemPboardType];
@ -306,19 +307,14 @@ NSString *GSMovableToolbarItemPboardType = @"GSMovableToolbarItemPboardType";
- (void) draggedImage: (NSImage *)dragImage beganAt: (NSPoint)location
{
/* We retain the toolbar item to be able to have have it reinsered later by
the dragging destination. */
// FIXME: Where is this released?
RETAIN(_toolbarItem);
[[_toolbarItem toolbar] _performRemoveItem: _toolbarItem];
//nothing to do
}
- (void) draggedImage: (NSImage *)dragImage
endedAt: (NSPoint)location
operation: (NSDragOperation)operation
{
RELEASE(self); // The view is no more needed : no more drawing to do with it.
//nothing to do
}
- (unsigned int) draggingSourceOperationMaskForLocal: (BOOL)isLocal
@ -616,7 +612,19 @@ NSString *GSMovableToolbarItemPboardType = @"GSMovableToolbarItemPboardType";
if ([view superview] == nil) // Show the view to eventually hide it later
[self addSubview: view];
if([view respondsToSelector:@selector(sizeToFit)])
{
NSSize newSize, minSize = [_toolbarItem minSize];
[view performSelector:@selector(sizeToFit)];
newSize = [view frame].size;
if (newSize.width < minSize.width || newSize.height < minSize.height)
{
newSize.width = MAX(newSize.width, minSize.width);
newSize.height = MAX(newSize.height, minSize.height);
[view setFrameSize:newSize];
}
}
// Adjust the layout in accordance with NSToolbarSizeMode
switch ([[_toolbarItem toolbar] sizeMode])
{
@ -742,7 +750,7 @@ NSString *GSMovableToolbarItemPboardType = @"GSMovableToolbarItemPboardType";
NSSize viewSize = [self frame].size;
NSImage *image = [[NSImage alloc] initWithSize: viewSize];
NSPasteboard *pboard;
int index = -1;
int index = NSNotFound;
// Prepare the drag
@ -765,6 +773,7 @@ NSString *GSMovableToolbarItemPboardType = @"GSMovableToolbarItemPboardType";
{
index = [toolbar _indexOfItem: _toolbarItem];
}
[GSToolbarView setDraggedItemIndex:index];
[pboard setString: [NSString stringWithFormat:@"%d", index]
forType: GSMovableToolbarItemPboardType];
@ -786,19 +795,14 @@ NSString *GSMovableToolbarItemPboardType = @"GSMovableToolbarItemPboardType";
- (void) draggedImage: (NSImage *)dragImage beganAt: (NSPoint)location
{
/* We retain the toolbar item to be able to have have it reinsered later by
the dragging destination. */
// FIXME: Where is this released?
RETAIN(_toolbarItem);
[[_toolbarItem toolbar] _performRemoveItem: _toolbarItem];
//nothing to do
}
- (void) draggedImage: (NSImage *)dragImage
endedAt: (NSPoint)location
operation: (NSDragOperation)operation
{
RELEASE(self); // The view is no more needed : no more drawing to do with it.
//nothing to do
}
- (unsigned int) draggingSourceOperationMaskForLocal: (BOOL)isLocal
@ -939,7 +943,8 @@ NSString *GSMovableToolbarItemPboardType = @"GSMovableToolbarItemPboardType";
[NSImage imageNamed: @"common_ToolbarSeparatorItem"]];
/* We bypass the toolbar item accessor to set the image in order to have it
(48 * 48) not resized. */
[self setPaletteLabel: _(@"Separator")];
[[self _backView] setFrameSize: NSMakeSize(30, ItemBackViewDefaultHeight)];
return self;
@ -960,6 +965,12 @@ NSString *GSMovableToolbarItemPboardType = @"GSMovableToolbarItemPboardType";
if ([self toolbar] != nil)
[backView setFrameSize: NSMakeSize(30, [backView frame].size.height)];
}
- (BOOL) allowsDuplicatesInToolbar
{
return YES;
}
@end
// ---- NSToolbarSpaceItemIdentifier
@ -984,6 +995,12 @@ NSString *GSMovableToolbarItemPboardType = @"GSMovableToolbarItemPboardType";
{
return nil;
}
- (BOOL) allowsDuplicatesInToolbar
{
return YES;
}
@end
// ---- NSToolbarFlexibleSpaceItemIdentifier
@ -1033,6 +1050,11 @@ NSString *GSMovableToolbarItemPboardType = @"GSMovableToolbarItemPboardType";
return YES;
}
- (BOOL) allowsDuplicatesInToolbar
{
return YES;
}
@end
// ---- NSToolbarShowColorsItemIdentifier