diff --git a/ChangeLog b/ChangeLog index 7ef1fc6c9..dbfbce35d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2004-09-02 Quentin Mathe + + * Headers/AppKit/NSToolbarItem.h: Added GSMovableToolbarPboardType + declaration. + * Source/NSToolbarItem.m: Added the toolbar items rearranging possibility by + implementing the dragging source methods. + * Source/GSToolbar.m: Added or reworked some methods to support model updates + without direct view effects to manipulate the toolbar items when a dragging + session happens. + * Source/GSToolbarView.m: Added the toolbar items rearranging possibility by + implementing the dragging destination methods. And added a method to + support the insertion index calculation based on the mouse location. + 2004-09-01 Adam Fedor * Source/NSPrintInfo.m ([NSPrintInfo -paperSize]): Avoid returning diff --git a/Headers/AppKit/NSToolbarItem.h b/Headers/AppKit/NSToolbarItem.h index c6c6078e2..8d74b8c17 100644 --- a/Headers/AppKit/NSToolbarItem.h +++ b/Headers/AppKit/NSToolbarItem.h @@ -141,4 +141,7 @@ APPKIT_EXPORT NSString *NSToolbarPrintItemIdentifier; - (BOOL) validateToolbarItem: (NSToolbarItem *)toolbarItem; @end +// Extra private stuff +extern NSString *GSMovableToolbarItemPboardType; + #endif /* _GNUstep_H_NSToolbarItem */ diff --git a/Source/GSToolbar.m b/Source/GSToolbar.m index fe9054cf6..6cf82336f 100644 --- a/Source/GSToolbar.m +++ b/Source/GSToolbar.m @@ -32,18 +32,19 @@ #include #include #include +#include #include +#include +#include +#include +#include #include #include "AppKit/NSApplication.h" +#include "AppKit/NSEvent.h" +#include "AppKit/NSMenu.h" +#include "AppKit/NSNibLoading.h" #include "AppKit/NSToolbarItem.h" #include "AppKit/NSView.h" -#include "AppKit/NSClipView.h" -#include "AppKit/NSButton.h" -#include "AppKit/NSNibLoading.h" -#include "AppKit/NSBezierPath.h" -#include "AppKit/NSImage.h" -#include "AppKit/NSMenu.h" -#include "AppKit/NSEvent.h" #include "AppKit/NSWindow.h" #include "AppKit/NSWindow+Toolbar.h" #include "GNUstepGUI/GSToolbarView.h" @@ -482,9 +483,14 @@ static GSValidationCenter *vc; - (void) _setConfigurationFromDictionary: (NSDictionary *)configDict broadcast: (BOOL)broadcast; - (void) _setDelegate: (id)delegate broadcast: (BOOL)broadcast; +- (void) _moveItemFromIndex: (int)index toIndex: (int)newIndex broadcast: (BOOL)broadcast; // Few other private methods - (void) _build; +- (int) _indexOfItem: (NSToolbarItem *)item; +- (void) _insertPassivelyItem: (NSToolbarItem *)item atIndex: (int)newIndex; +- (void) _performRemoveItem: (NSToolbarItem *)item; +- (void) _concludeRemoveItem: (NSToolbarItem *)item atIndex: (int)index broadcast: (BOOL)broadcast; - (void) _loadConfig; - (NSToolbarItem *) _toolbarItemForIdentifier: (NSString *)itemIdent; - (GSToolbar *) _toolbarModel; @@ -898,6 +904,23 @@ static GSValidationCenter *vc; _build = NO; } +- (int) _indexOfItem: (NSToolbarItem *)item +{ + return [_items indexOfObjectIdenticalTo: item]; +} + +- (void) _insertPassivelyItem: (NSToolbarItem *)item atIndex: (int)newIndex +{ + if (![_items containsObject: item]) + { + [_items insertObject: item atIndex: newIndex]; + } + else + { + NSLog(@"Error: the toolbar already contains the item to insert."); + } +} + - (void) _loadConfig { if (_identifier != nil) @@ -1034,15 +1057,25 @@ static GSValidationCenter *vc; - (void) _removeItemAtIndex: (int)index broadcast: (BOOL)broadcast { - id item; + id item = [_items objectAtIndex: index]; + + RETAIN(item); + [self _performRemoveItem: item]; + [self _concludeRemoveItem: item atIndex: index broadcast: broadcast]; + RELEASE(item); +} - item = RETAIN([_items objectAtIndex: index]); - [_items removeObjectAtIndex: index]; +- (void) _performRemoveItem: (NSToolbarItem *)item +{ + [_items removeObject: item]; [_toolbarView _reload]; +} + +- (void) _concludeRemoveItem: (NSToolbarItem *)item atIndex: (int)index broadcast: (BOOL)broadcast +{ [nc postNotificationName: NSToolbarDidRemoveItemNotification object: self userInfo: [NSDictionary dictionaryWithObject: item forKey: @"item"]]; - RELEASE(item); if (broadcast) { @@ -1136,6 +1169,30 @@ static GSValidationCenter *vc; } } +- (void) _moveItemFromIndex: (int)index toIndex: (int)newIndex broadcast: (BOOL)broadcast +{ + id item; + + item = RETAIN([_items objectAtIndex: index]); + [_items removeObjectAtIndex: index]; + if (newIndex > [_items count] - 1) + { + [_items addObject: item]; + } + else + { + [_items insertObject: item atIndex: newIndex]; + } + [_toolbarView _reload]; + + RELEASE(item); + + if (broadcast) + { + TRANSMIT(_moveItemFromIndex: index toIndex: newIndex broadcast: NO); + } +} + // Private Accessors - (void) _setToolbarView: (GSToolbarView *)toolbarView diff --git a/Source/GSToolbarView.m b/Source/GSToolbarView.m index cceffa202..fd84cc6ea 100644 --- a/Source/GSToolbarView.m +++ b/Source/GSToolbarView.m @@ -29,19 +29,24 @@ #include #include #include +#include +#include #include #include -#include "AppKit/NSToolbarItem.h" #include "AppKit/NSBezierPath.h" #include "AppKit/NSButton.h" #include "AppKit/NSClipView.h" #include "AppKit/NSColor.h" #include "AppKit/NSColorList.h" +#include "AppKit/NSDragging.h" #include "AppKit/NSEvent.h" #include "AppKit/NSImage.h" #include "AppKit/NSMenu.h" +#include "AppKit/NSPasteboard.h" +#include "AppKit/NSToolbarItem.h" // It contains GSMovableToolbarItemPboardType declaration #include "AppKit/NSView.h" #include "AppKit/NSWindow.h" +#include "GNUstepGUI/GSToolbar.h" #include "GNUstepGUI/GSToolbarView.h" typedef enum { @@ -138,6 +143,12 @@ static void initSystemExtensionsColors(void) */ @interface GSToolbar (GNUstepPrivate) - (void) _build; + +- (void) _concludeRemoveItem: (NSToolbarItem *)item atIndex: (int)index broadcast: (BOOL)broadcast; +- (int) _indexOfItem: (NSToolbarItem *)item; +- (void) _insertPassivelyItem: (NSToolbarItem *)item atIndex: (int)newIndex; +- (void) _moveItemFromIndex: (int)index toIndex: (int)newIndex broadcast: (BOOL)broacast; + - (void) _toolbarViewWillMoveToSuperview: (NSView *)newSuperview; // Accessors @@ -155,12 +166,21 @@ static void initSystemExtensionsColors(void) - (BOOL) _isFlexibleSpace; @end +@interface GSToolbarButton +- (NSToolbarItem *) toolbarItem; +@end + +@interface GSToolbarBackView +- (NSToolbarItem *) toolbarItem; +@end + @interface GSToolbarView (GNUstepPrivate) - (void) _handleBackViewsFrame; - (void) _handleViewsVisibility; - (void) _reload; - (void) _setToolbar: (GSToolbar *)toolbar; - (void) _takeInAccountFlexibleSpaces; +- (int) _insertionIndexAtPoint: (NSPoint)location; // Accessors - (float) _heightFromLayout; @@ -190,6 +210,13 @@ static void initSystemExtensionsColors(void) - (void) setToolbar: (GSToolbar *)toolbar; @end +@interface GSToolbarClipView : NSClipView +{ + +} + +@end + @implementation GSToolbarClippedItemsButton - (id) init { @@ -279,6 +306,14 @@ static void initSystemExtensionsColors(void) } @end +// --- + +@implementation GSToolbarClipView + +// Nothing here + +@end + // Implementation GSToolbarView @implementation GSToolbarView @@ -314,19 +349,19 @@ static void initSystemExtensionsColors(void) switch (_sizeMode) { - case NSToolbarSizeModeDefault: - toolbarViewHeight = ToolbarViewDefaultHeight; - break; - case NSToolbarSizeModeRegular: - toolbarViewHeight = ToolbarViewRegularHeight; - break; - case NSToolbarSizeModeSmall: - toolbarViewHeight = ToolbarViewSmallHeight; - break; - default: - // Raise exception - toolbarViewHeight = 0; - } + case NSToolbarSizeModeDefault: + toolbarViewHeight = ToolbarViewDefaultHeight; + break; + case NSToolbarSizeModeRegular: + toolbarViewHeight = ToolbarViewRegularHeight; + break; + case NSToolbarSizeModeSmall: + toolbarViewHeight = ToolbarViewSmallHeight; + break; + default: + // Raise exception + toolbarViewHeight = 0; + } [self setFrame: NSMakeRect(frame.origin.x, frame.origin.y, @@ -335,7 +370,7 @@ static void initSystemExtensionsColors(void) // --- - _clipView = [[NSClipView alloc] initWithFrame: NSMakeRect(0, 0, 100, 100)]; + _clipView = [[GSToolbarClipView alloc] initWithFrame: NSMakeRect(0, 0, 100, 100)]; [_clipView setAutoresizingMask: (NSViewWidthSizable | NSViewHeightSizable)]; @@ -355,6 +390,8 @@ static void initSystemExtensionsColors(void) // deallocated with the class when the application quits. // --- + + [self registerForDraggedTypes: [NSArray arrayWithObject: GSMovableToolbarItemPboardType]]; return self; } @@ -380,6 +417,68 @@ static void initSystemExtensionsColors(void) [super dealloc]; } +// Dragging related methods + +- (NSDragOperation) draggingEntered: (id )info +{ + if ([self _insertionIndexAtPoint: [info draggingLocation]] != NSNotFound); + { + return NSDragOperationGeneric; + } + + return NSDragOperationNone; +} + +- (NSDragOperation) draggingUpdated: (id )info +{ + if ([self _insertionIndexAtPoint: [info draggingLocation]] != NSNotFound); + { + return NSDragOperationGeneric; + } + + return NSDragOperationNone; +} + +- (void) draggingEnded: (id )info +{ + NSPasteboard *pboard = [info draggingPasteboard]; + NSString *str = [pboard stringForType: [[pboard types] objectAtIndex: 0]]; + int index = [str intValue]; + GSToolbar *toolbar = [self toolbar]; + + [toolbar _concludeRemoveItem: [[info draggingSource] toolbarItem] atIndex: index broadcast: YES]; +} + +- (void) draggingExited: (id )info +{ + // Nothing to do +} + +- (BOOL) prepareForDragOperation: (id )info +{ + return YES; +} + +- (BOOL) performDragOperation: (id )info +{ + NSPasteboard *pboard = [info draggingPasteboard]; + NSString *str = [pboard stringForType: [[pboard types] objectAtIndex: 0]]; + int index = [str intValue]; + GSToolbar *toolbar = [self toolbar]; + NSToolbarItem *item = [[info draggingSource] toolbarItem]; + int newIndex = [self _insertionIndexAtPoint: [info draggingLocation]]; // Calculate the index + + [toolbar _insertPassivelyItem:item atIndex: index]; + RELEASE(item); + [toolbar _moveItemFromIndex: index toIndex: newIndex broadcast: YES]; + return YES; +} + +- (void) concludeDragOperation: (id )info +{ + // Nothing to do currently +} + // More overrided methods - (void) drawRect: (NSRect)aRect @@ -756,6 +855,25 @@ static void initSystemExtensionsColors(void) } +- (int) _insertionIndexAtPoint: (NSPoint)location +{ + id hitView = [self hitTest: location]; + NSRect hitViewFrame = [hitView frame];; + int index; + + if ((hitView != nil) + & ([hitView isKindOfClass: [GSToolbarButton class]] + || [hitView isKindOfClass: [GSToolbarBackView class]])) + { + index = [_toolbar _indexOfItem: [hitView toolbarItem]]; + if (location.x - hitViewFrame.origin.x > hitViewFrame.size.width / 2) + index++; + + return index; + } + return NSNotFound; +} + // Accessors private methods - (float) _heightFromLayout diff --git a/Source/NSToolbarItem.m b/Source/NSToolbarItem.m index 313562704..a448f2c2f 100644 --- a/Source/NSToolbarItem.m +++ b/Source/NSToolbarItem.m @@ -29,21 +29,26 @@ */ #include -#include +#include #include - +#include +#include +#include #include "AppKit/NSApplication.h" -#include "AppKit/NSToolbarItem.h" -#include "AppKit/NSMenu.h" -#include "AppKit/NSMenuItem.h" -#include "AppKit/NSImage.h" #include "AppKit/NSButton.h" #include "AppKit/NSButtonCell.h" -#include "AppKit/NSFont.h" +#include "AppKit/NSDragging.h" #include "AppKit/NSEvent.h" +#include "AppKit/NSFont.h" +#include "AppKit/NSImage.h" +#include "AppKit/NSMenu.h" +#include "AppKit/NSMenuItem.h" #include "AppKit/NSParagraphStyle.h" +#include "AppKit/NSPasteboard.h" +#include "AppKit/NSView.h" #include "GNUstepGUI/GSToolbar.h" #include "GNUstepGUI/GSToolbarView.h" +#include "AppKit/NSToolbarItem.h" /* * Each NSToolbarItem object are coupled with a backView which is their representation @@ -83,8 +88,13 @@ static NSFont *NormalFont = nil; // See NSToolbarItem -initialize method static NSFont *SmallFont = nil; +NSString *GSMovableToolbarItemPboardType = @"GSMovableToolbarItemPboardType"; + @interface GSToolbar (GNUstepPrivate) - (GSToolbarView *) _toolbarView; +- (int) _indexOfItem: (NSToolbarItem *)item; // Used by drag setup + +- (void) _performRemoveItem: (NSToolbarItem *)item; // Used by drag setup @end @interface NSToolbarItem (GNUstepPrivate) @@ -260,15 +270,79 @@ static NSFont *SmallFont = nil; } +/* + * The code below should be kept in sync with GSToolbarBackView methods which have identical names + */ + - (void) mouseDown: (NSEvent *)event { - if ([_toolbarItem _selectable] && [self state]) - return; // Abort in case the button is selectable and selected - // HACK: must be improved to handle drag event - - [super mouseDown: event]; + if ([event modifierFlags] == NSCommandKeyMask) + { + NSSize viewSize = [self frame].size; + NSImage *image = [[NSImage alloc] initWithSize: viewSize]; + NSCell *cell = [self cell]; + NSPasteboard *pboard; + GSToolbar *toolbar = [_toolbarItem toolbar]; + int index; + + AUTORELEASE(image); + + // Prepare the drag + + RETAIN(self); // We need to keep this view (aka self) to be able to draw the drag image. + + // Draw the drag content in an image + + // The code below is only partially supported by GNUstep, then NSImage needs to be improved + [image lockFocus]; + [cell setShowsFirstResponder: NO]; // To remove the dotted rect + [cell drawWithFrame: NSMakeRect(0, 0, viewSize.width, viewSize.height) inView: nil]; + [cell setShowsFirstResponder: YES]; + [image unlockFocus]; + + pboard = [NSPasteboard pasteboardWithName: NSDragPboard]; + [pboard declareTypes: [NSArray arrayWithObject: GSMovableToolbarItemPboardType] owner: nil]; + index = [toolbar _indexOfItem: _toolbarItem]; + [pboard setString: [NSString stringWithFormat:@"%d", index] forType: GSMovableToolbarItemPboardType]; + + [self dragImage: image + at: NSMakePoint(0.0, 0.0) + offset: NSMakeSize(0.0, 0.0) + event: event + pasteboard: pboard + source: self + slideBack: NO]; + } + else + { + [super mouseDown: event]; + } } +- (void) draggedImage: (NSImage *)dragImage beganAt: (NSPoint)location +{ + GSToolbar *toolbar = [_toolbarItem toolbar]; + + RETAIN(_toolbarItem); + // We retain the toolbar item to be able to have have it reinsered later by the dragging destination. + + [toolbar _performRemoveItem: _toolbarItem]; +} + +- (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. +} + +- (unsigned int) draggingSourceOperationMaskForLocal: (BOOL)isLocal +{ + return isLocal ? NSDragOperationGeneric : NSDragOperationNone; +} + +/* + * End of the code to keep in sync + */ + - (BOOL) sendAction: (SEL)action to: (id)target { if ([_toolbarItem _selectable]) @@ -341,7 +415,6 @@ static NSFont *SmallFont = nil; * Please make sure the output remains always correct. */ // We ignore aRect value - [aString drawInRect: titleRect]; } @@ -594,6 +667,90 @@ static NSFont *SmallFont = nil; DESTROY(attrStr); } +- (NSView *) hitTest: (NSPoint)point +{ + NSEvent *event = [NSApp currentEvent]; + + if ([self mouse: point inRect: [self frame]] + && [event modifierFlags] == NSCommandKeyMask + && [event type] == NSLeftMouseDown) + { + return self; + } + else + { + return [super hitTest: point]; + } +} + +/* + * The code below should be kept in sync with GSToolbarButton methods which have identical names + */ + +- (void) mouseDown: (NSEvent *)event +{ + if ([event modifierFlags] == NSCommandKeyMask) + { + NSSize viewSize = [self frame].size; + NSImage *image = [[NSImage alloc] initWithSize: viewSize]; + NSPasteboard *pboard; + GSToolbar *toolbar = [_toolbarItem toolbar]; + int index; + + AUTORELEASE(image); + + // Prepare the drag + + RETAIN(self); // We need to keep this view (aka self) to be able to draw the drag image. + + // The code below is only partially supported by GNUstep, then NSImage needs to be improved + [image lockFocus]; + [self drawRect: NSMakeRect(0, 0, viewSize.width, viewSize.height)]; + [image unlockFocus]; + + pboard = [NSPasteboard pasteboardWithName: NSDragPboard]; + [pboard declareTypes: [NSArray arrayWithObject: GSMovableToolbarItemPboardType] owner: nil]; + index = [toolbar _indexOfItem: _toolbarItem]; + [pboard setString: [NSString stringWithFormat:@"%d", index] forType: GSMovableToolbarItemPboardType]; + + [self dragImage: image + at: NSMakePoint(0.0, 0.0) + offset: NSMakeSize(0.0, 0.0) + event: event + pasteboard: pboard + source: self + slideBack: NO]; + } + else + { + [super mouseDown: event]; + } +} + +- (void) draggedImage: (NSImage *)dragImage beganAt: (NSPoint)location +{ + GSToolbar *toolbar = [_toolbarItem toolbar]; + + RETAIN(_toolbarItem); + // We retain the toolbar item to be able to have have it reinsered later by the dragging destination. + + [toolbar _performRemoveItem: _toolbarItem]; +} + +- (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. +} + +- (unsigned int) draggingSourceOperationMaskForLocal: (BOOL)isLocal +{ + return isLocal ? NSDragOperationGeneric : NSDragOperationNone; +} + +/* + * End of the code to keep in sync + */ + - (NSToolbarItem *)toolbarItem { return _toolbarItem;