1/* 2 <Title>GSToolbarView.m</title> 3 4 <abstract>The toolbar view class.</abstract> 5 6 Copyright (C) 2004-2015 Free Software Foundation, Inc. 7 8 Author: Quentin Mathe <qmathe@club-internet.fr> 9 Date: January 2004 10 11 This file is part of the GNUstep GUI Library. 12 13 This library is free software; you can redistribute it and/or 14 modify it under the terms of the GNU Lesser General Public 15 License as published by the Free Software Foundation; either 16 version 2 of the License, or (at your option) any later version. 17 18 This library is distributed in the hope that it will be useful, 19 but WITHOUT ANY WARRANTY; without even the implied warranty of 20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 21 Lesser General Public License for more details. 22 23 You should have received a copy of the GNU Lesser General Public 24 License along with this library; see the file COPYING.LIB. 25 If not, see <http://www.gnu.org/licenses/> or write to the 26 Free Software Foundation, 51 Franklin Street, Fifth Floor, 27 Boston, MA 02110-1301, USA. 28*/ 29 30#import <Foundation/NSObject.h> 31#import <Foundation/NSArray.h> 32#import <Foundation/NSDictionary.h> 33#import <Foundation/NSEnumerator.h> 34#import <Foundation/NSException.h> 35#import <Foundation/NSNotification.h> 36#import <Foundation/NSUserDefaults.h> 37#import <Foundation/NSString.h> 38#import "AppKit/NSButton.h" 39#import "AppKit/NSClipView.h" 40#import "AppKit/NSDragging.h" 41#import "AppKit/NSEvent.h" 42#import "AppKit/NSImage.h" 43#import "AppKit/NSMenu.h" 44#import "AppKit/NSPasteboard.h" 45// It contains GSMovableToolbarItemPboardType declaration 46#import "AppKit/NSToolbarItem.h" 47#import "AppKit/NSView.h" 48#import "AppKit/NSWindow.h" 49 50#import "GNUstepGUI/GSTheme.h" 51#import "GNUstepGUI/GSToolbarView.h" 52 53#import "NSToolbarFrameworkPrivate.h" 54 55typedef enum { 56 ToolbarViewDefaultHeight = 62, 57 ToolbarViewRegularHeight = 62, 58 ToolbarViewSmallHeight = 52 59} ToolbarViewHeight; 60 61// Borrow this from NSToolbarItem.m 62static const int InsetItemViewX = 10; 63 64static const int ClippedItemsViewWidth = 28; 65 66static NSUInteger draggedItemIndex = NSNotFound; 67 68/* 69 * Toolbar related code 70 */ 71 72@interface GSToolbarButton 73- (NSToolbarItem *) toolbarItem; 74@end 75 76@interface GSToolbarBackView 77- (NSToolbarItem *) toolbarItem; 78@end 79 80@interface GSToolbarClippedItemsButton : NSButton 81{ 82 NSToolbar *_toolbar; 83} 84 85- (id) init; 86 87// Accessors 88- (NSMenu *) overflowMenu; 89/* This method cannot be called "menu" otherwise it would override NSResponder 90 method with the same name. */ 91 92- (void) layout; 93- (void) setToolbar: (NSToolbar *)toolbar; 94@end 95 96@implementation GSToolbarClippedItemsButton 97- (id) init 98{ 99 NSImage *image = [NSImage imageNamed: @"common_ToolbarClippedItemsMark"]; 100 NSRect dummyRect = NSMakeRect(0, 0, ClippedItemsViewWidth, 100); 101 // The correct height will be set by the layout method 102 103 if ((self = [super initWithFrame: dummyRect]) != nil) 104 { 105 [self setBordered: NO]; 106 [[self cell] setHighlightsBy: NSChangeGrayCellMask 107 | NSChangeBackgroundCellMask]; 108 [self setAutoresizingMask: NSViewNotSizable]; 109 [self setImagePosition: NSImageOnly]; 110 [image setScalesWhenResized: YES]; 111 // [image setSize: NSMakeSize(20, 20)]; 112 [self setImage: image]; 113 return self; 114 } 115 return nil; 116} 117 118/* 119 * Not really used, it is here to be used by the developer who want to adjust 120 * easily a toolbar view attached to a toolbar which is not bind to a window. 121 */ 122- (void) layout 123{ 124 NSSize layoutSize = NSMakeSize([self frame].size.width, 125 [[_toolbar _toolbarView] _heightFromLayout]); 126 127 [self setFrameSize: layoutSize]; 128} 129 130- (void) mouseDown: (NSEvent *)event 131{ 132 NSMenu *clippedItemsMenu = [self menuForEvent: event]; 133 134 [super highlight: YES]; 135 136 if (clippedItemsMenu != nil) 137 { 138 [NSMenu popUpContextMenu: clippedItemsMenu withEvent: event 139 forView: self]; 140 } 141 142 [super highlight: NO]; 143} 144 145- (NSMenu *) menuForEvent: (NSEvent *)event 146{ 147 if ([event type] == NSLeftMouseDown) 148 { 149 return [self overflowMenu]; 150 } 151 return nil; 152} 153 154- (NSMenu *) overflowMenu 155{ 156 /* This method cannot be called "menu" otherwise it would 157 override NSResponder method with the same name. */ 158 NSMenu *menu = [[NSMenu alloc] initWithTitle: @""]; 159 NSEnumerator *e; 160 id item; 161 NSArray *visibleItems; 162 163 visibleItems = [_toolbar visibleItems]; 164 165 e = [[_toolbar items] objectEnumerator]; 166 while ((item = [e nextObject]) != nil) 167 { 168 if (![visibleItems containsObject: item]) 169 { 170 id menuItem; 171 172 menuItem = [item menuFormRepresentation]; 173 if (menuItem == nil) 174 menuItem = [item _defaultMenuFormRepresentation]; 175 176 if (menuItem != nil) 177 { 178 [item validate]; 179 [menu addItem: menuItem]; 180 } 181 } 182 } 183 184 return AUTORELEASE(menu); 185} 186 187// Accessors 188 189- (void) setToolbar: (NSToolbar *)toolbar 190{ 191 // Don't do an ASSIGN here, the toolbar view retains us. 192 _toolbar = toolbar; 193} 194@end 195 196// --- 197 198// Implementation GSToolbarView 199 200@implementation GSToolbarView 201+ (void) initialize 202{ 203 if (self == [GSToolbarView class]) 204 { 205 } 206} 207 208- (id) initWithFrame: (NSRect)frame 209{ 210 if ((self = [super initWithFrame: frame]) == nil) 211 { 212 return nil; 213 } 214 215 _heightFromLayout = ToolbarViewDefaultHeight; 216 [self setFrame: NSMakeRect(frame.origin.x, frame.origin.y, 217 frame.size.width, _heightFromLayout)]; 218 219 _clipView = [[NSClipView alloc] initWithFrame: 220 NSMakeRect(0, 0, frame.size.width, 221 _heightFromLayout)]; 222 [_clipView setAutoresizingMask: (NSViewWidthSizable | NSViewHeightSizable)]; 223 [_clipView setDrawsBackground: NO]; 224 [self addSubview: _clipView]; 225 // Adjust the clip view frame 226 [self setBorderMask: GSToolbarViewTopBorder | GSToolbarViewBottomBorder 227 | GSToolbarViewRightBorder | GSToolbarViewLeftBorder]; 228 229 _clippedItemsMark = [[GSToolbarClippedItemsButton alloc] init]; 230 231 [self registerForDraggedTypes: 232 [NSArray arrayWithObject: GSMovableToolbarItemPboardType]]; 233 234 return self; 235} 236 237- (void) dealloc 238{ 239 //NSLog(@"Toolbar view dealloc"); 240 241 [[NSNotificationCenter defaultCenter] removeObserver: self]; 242 243 RELEASE(_clippedItemsMark); 244 RELEASE(_clipView); 245 246 [super dealloc]; 247} 248 249// Dragging related methods 250 251+ (NSUInteger) draggedItemIndex 252{ 253 return draggedItemIndex; 254} 255 256+ (void) setDraggedItemIndex:(NSUInteger)sourceIndex 257{ 258 draggedItemIndex = sourceIndex; 259} 260 261- (int) _insertionIndexAtPoint: (NSPoint)location 262{ 263 NSUInteger index; 264 NSArray *visibleBackViews = [self _visibleBackViews]; 265 266 location = [_clipView convertPoint:location fromView:nil]; 267 if (draggedItemIndex == NSNotFound) 268 { 269 //simply locate the nearest location between existing items 270 for (index = 0; index < [visibleBackViews count]; index++) 271 { 272 NSRect itemRect = [[visibleBackViews objectAtIndex:index] frame]; 273 if (location.x < (itemRect.origin.x + (itemRect.size.width/2))) 274 { 275 NSLog(@"At location %lu", (unsigned long)index); 276 return index; 277 } 278 } 279 return [visibleBackViews count]; 280 } 281 else 282 { 283 // don't return a different index unless drag has crossed the midpoint of its neighbor 284 NSRect itemRect; 285 BOOL draggingLeft = YES; 286 if (draggedItemIndex < [visibleBackViews count]) 287 { 288 itemRect = [[visibleBackViews objectAtIndex:draggedItemIndex] frame]; 289 draggingLeft = (location.x < (itemRect.origin.x + (itemRect.size.width/2))); 290 } 291 if (draggingLeft) 292 { 293 // dragging to the left of dragged item's current location 294 for (index=0; index < draggedItemIndex; index++) 295 { 296 itemRect = [[visibleBackViews objectAtIndex:index] frame]; 297 if (location.x < (itemRect.origin.x + (itemRect.size.width/2))) 298 { 299 return index; 300 } 301 } 302 } 303 else 304 { 305 // dragging to the right of current location 306 // Never called for [visibleBackViews count] == 0 307 for (index=[visibleBackViews count]-1; index > draggedItemIndex; index--) 308 { 309 itemRect = [[visibleBackViews objectAtIndex:index] frame]; 310 if (location.x > (itemRect.origin.x + (itemRect.size.width/2))) 311 { 312 return index; 313 } 314 } 315 } 316 return draggedItemIndex; 317 } 318} 319 320#define OUTSIDE_INDEX (NSNotFound - 1) 321 322- (NSDragOperation) updateItemWhileDragging:(id <NSDraggingInfo>)info exited:(BOOL)exited 323{ 324 NSToolbarItem *item = [[info draggingSource] toolbarItem]; 325 NSString *identifier = [item itemIdentifier]; 326 NSToolbar *toolbar = [self toolbar]; 327 NSArray *allowedItemIdentifiers = [toolbar _allowedItemIdentifiers]; 328 int newIndex; 329 330 // don't accept any dragging if the customization palette isn't running for this toolbar 331 if (![toolbar customizationPaletteIsRunning] || ![allowedItemIdentifiers containsObject: identifier]) 332 { 333 return NSDragOperationNone; 334 } 335 336 if (draggedItemIndex == NSNotFound) // initialize the index for this drag session 337 { 338 // if duplicate items aren't allowed, see if we already have such an item 339 if (![item allowsDuplicatesInToolbar]) 340 { 341 NSArray *items = [toolbar items]; 342 NSUInteger index; 343 for (index=0; index<[items count]; index++) 344 { 345 NSToolbarItem *anItem = [items objectAtIndex:index]; 346 if ([[anItem itemIdentifier] isEqual:identifier]) 347 { 348 draggedItemIndex = index; // drag the existing item 349 break; 350 } 351 } 352 } 353 } 354 else if (draggedItemIndex == OUTSIDE_INDEX) 355 { 356 // re-entering after being dragged off -- treat as unknown location 357 draggedItemIndex = NSNotFound; 358 } 359 360 newIndex = [self _insertionIndexAtPoint: [info draggingLocation]]; 361 362 if (draggedItemIndex != NSNotFound) 363 { 364 // existing item being dragged -- either move or remove it 365 if (exited) 366 { 367 [toolbar _removeItemAtIndex:draggedItemIndex broadcast:YES]; 368 draggedItemIndex = OUTSIDE_INDEX; // no longer in our items 369 } 370 else 371 { 372 if (newIndex != draggedItemIndex) 373 { 374 [toolbar _moveItemFromIndex: draggedItemIndex toIndex: newIndex broadcast: YES]; 375 draggedItemIndex = newIndex; 376 } 377 } 378 } 379 else if (!exited) 380 { 381 // new item being dragged in -- add it 382 [toolbar _insertItemWithItemIdentifier: identifier 383 atIndex: newIndex 384 broadcast: YES]; 385 draggedItemIndex = newIndex; 386 } 387 return NSDragOperationGeneric; 388} 389 390- (NSDragOperation) draggingEntered: (id <NSDraggingInfo>)info 391{ 392 return [self updateItemWhileDragging: info exited: NO]; 393} 394 395- (NSDragOperation) draggingUpdated: (id <NSDraggingInfo>)info 396{ 397 return [self updateItemWhileDragging: info exited: NO]; 398} 399 400- (void) draggingEnded: (id <NSDraggingInfo>)info 401{ 402 draggedItemIndex = NSNotFound; 403} 404 405- (void) draggingExited: (id <NSDraggingInfo>)info 406{ 407 [self updateItemWhileDragging: info exited: YES]; 408} 409 410- (BOOL) prepareForDragOperation: (id <NSDraggingInfo>)info 411{ 412 return YES; 413} 414 415- (BOOL) performDragOperation: (id <NSDraggingInfo>)info 416{ 417 NSToolbar *toolbar = [self toolbar]; 418 419 [self updateItemWhileDragging: info exited: NO]; 420 421 draggedItemIndex = NSNotFound; 422 423 // save the configuration... 424 [toolbar _saveConfig]; 425 426 return YES; 427} 428 429- (void) concludeDragOperation: (id <NSDraggingInfo>)info 430{ 431 // Nothing to do currently 432} 433 434// More overrided methods 435 436- (void) drawRect: (NSRect)aRect 437{ 438 [[GSTheme theme] drawToolbarRect: aRect 439 frame: [self frame] 440 borderMask: _borderMask]; 441} 442 443- (BOOL) isOpaque 444{ 445 if ([[[GSTheme theme] toolbarBackgroundColor] alphaComponent] < 1.0) 446 { 447 return NO; 448 } 449 else 450 { 451 return YES; 452 } 453} 454 455- (void) windowDidResize: (NSNotification *)notification 456{ 457 if ([self superview] == nil) 458 return; 459 460 [self _reload]; 461} 462 463- (void) viewWillMoveToSuperview: (NSView *)newSuperview 464{ 465 [super viewWillMoveToSuperview: newSuperview]; 466 467 [_toolbar _toolbarViewWillMoveToSuperview: newSuperview]; 468 // Allow to update the validation system which is window specific 469} 470 471- (void) viewDidMoveToWindow 472{ 473 NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; 474 475 /* NSView method called when a view is moved to a window (NSView has a 476 variable _window). */ 477 [super viewDidMoveToWindow]; 478 479 [nc removeObserver: self name: NSWindowDidResizeNotification object: nil]; 480 [nc addObserver: self selector: @selector(windowDidResize:) 481 name: NSWindowDidResizeNotification 482 object: _window]; 483} 484 485// Accessors 486 487- (unsigned int) borderMask 488{ 489 return _borderMask; 490} 491 492- (NSToolbar *) toolbar 493{ 494 return _toolbar; 495} 496 497- (void) setBorderMask: (unsigned int)borderMask 498{ 499 NSRect toolbarViewFrame = [self frame]; 500 NSRect rect = NSMakeRect(0, 0, toolbarViewFrame.size.width, 501 toolbarViewFrame.size.height); 502 503 _borderMask = borderMask; 504 505 // Take in account the border 506 if (_borderMask & GSToolbarViewBottomBorder) 507 { 508 rect = NSMakeRect(rect.origin.x, ++rect.origin.y, rect.size.width, 509 --rect.size.height); 510 } 511 512 if (_borderMask & GSToolbarViewTopBorder) 513 { 514 rect = NSMakeRect(rect.origin.x, rect.origin.y, rect.size.width, 515 --rect.size.height); 516 } 517 518 if (_borderMask & GSToolbarViewLeftBorder) 519 { 520 rect = NSMakeRect(++rect.origin.x, rect.origin.y, --rect.size.width, 521 rect.size.height); 522 } 523 524 if (_borderMask & GSToolbarViewRightBorder) 525 { 526 rect = NSMakeRect(rect.origin.x, rect.origin.y, --rect.size.width, 527 rect.size.height); 528 } 529 530 [_clipView setFrame: rect]; 531} 532 533- (void) setToolbar: (NSToolbar *)toolbar 534{ 535 if (_toolbar == toolbar) 536 return; 537 538 _toolbar = toolbar; 539 540 [_clippedItemsMark setToolbar: _toolbar]; 541 // Load the toolbar in the toolbar view 542 [self _reload]; 543} 544 545// Private methods 546 547- (void) _handleBackViewsFrame 548{ 549 float x = 0; 550 float newHeight = 0; 551 NSArray *subviews = [_clipView subviews]; 552 NSEnumerator *e = [[_toolbar items] objectEnumerator]; 553 NSToolbarItem *item; 554 555 while ((item = [e nextObject]) != nil) 556 { 557 NSView *itemBackView; 558 NSRect itemBackViewFrame; 559 560 itemBackView = [item _backView]; 561 if ([subviews containsObject: itemBackView] == NO 562 || [item _isModified] 563 || [item _isFlexibleSpace]) 564 { 565 // When a label is changed, _isModified returns YES to let us known we 566 // must recalculate the text length and then the size for the edited 567 // item back view 568 [item _layout]; 569 } 570 571 itemBackViewFrame = [itemBackView frame]; 572 [itemBackView setFrame: NSMakeRect(x, itemBackViewFrame.origin.y, 573 itemBackViewFrame.size.width, itemBackViewFrame.size.height)]; 574 575 x += [itemBackView frame].size.width; 576 577 if (itemBackViewFrame.size.height > newHeight) 578 newHeight = itemBackViewFrame.size.height; 579 } 580 581 if (newHeight > 0) 582 _heightFromLayout = newHeight; 583} 584 585- (void) _takeInAccountFlexibleSpaces 586{ 587 NSArray *items = [_toolbar items]; 588 NSEnumerator *e; 589 NSToolbarItem *item; 590 NSView *backView, *view; 591 CGFloat lengthAvailable; 592 BOOL mustAdjustNext = NO; 593 CGFloat x = 0, visibleItemsMinWidth = 0, backViewsWidth = 0; 594 NSMutableArray *variableWidthItems = [NSMutableArray array]; 595 int flexibleItemsCount = 0, maxWidthItemsCount = 0; 596 CGFloat spacePerFlexItem, extraSpace = 0; 597 CGFloat toolbarWidth = [self frame].size.width; 598 int i, n = [items count]; 599 NSMutableArray *visibleItems = [NSMutableArray array]; 600 static const int FlexItemWeight = 4; // non-space flexible item counts as much as 4 flexible spaces 601 602 if (n == 0) 603 return; 604 605 // First determine which items can fit in toolbar if all are at their minimum width. 606 // We'd like to show as many items as possible. These are our visibleItems. 607 for (i=0; i < n; i++) 608 { 609 item = [items objectAtIndex:i]; 610 backView = [item _backView]; 611 view = [item view]; 612 if (view != nil) 613 backViewsWidth += [item minSize].width + 2*InsetItemViewX; 614 else 615 backViewsWidth += [backView frame].size.width; 616 617 if ((backViewsWidth + ClippedItemsViewWidth <= toolbarWidth) 618 || (i == n - 1 && backViewsWidth <= toolbarWidth)) 619 { 620 visibleItemsMinWidth = backViewsWidth; 621 [visibleItems addObject:item]; 622 } 623 else 624 { 625 break; 626 } 627 } 628 // next, figure out how much additional space there is for expanding flexible items 629 lengthAvailable = toolbarWidth - visibleItemsMinWidth; 630 if ([visibleItems count] < n) 631 lengthAvailable -= ClippedItemsViewWidth; 632 633 if (lengthAvailable < 1) 634 return; 635 636 // We want to divide available space evenly among all flexible items, but some items may 637 // reach their maximum width, making more space available for the other items. 638 // To do this, first we count the flexible items, gathering a list of those that may 639 // have a maximum width. 640 // To match observed behavior on Cocoa (which is NOT as documented!) we allocate only 1/4 641 // as much space to flexible spaces as we do to other flexible items. 642 e = [visibleItems objectEnumerator]; 643 while ((item = [e nextObject]) != nil) 644 { 645 if ([item _isFlexibleSpace]) 646 { 647 flexibleItemsCount++; 648 } 649 else 650 { 651 CGFloat minWidth = [item minSize].width; 652 CGFloat maxWidth = [item maxSize].width; 653 if (minWidth < maxWidth) 654 { 655 [variableWidthItems addObject:item]; 656 flexibleItemsCount += FlexItemWeight; // gets FlexItemWeight times the weight of a flexible space 657 } 658 } 659 } 660 if (flexibleItemsCount == 0) 661 return; 662 663 // Now go through any variableWidthItems to see if the available space per item would 664 // cause any of them to exceed their maximum width, and calculate the extra space available 665 spacePerFlexItem = MAX(lengthAvailable / flexibleItemsCount, 0); 666 e = [variableWidthItems objectEnumerator]; 667 while ((item = [e nextObject]) != nil) 668 { 669 CGFloat minWidth = [item minSize].width; 670 CGFloat maxWidth = [item maxSize].width; 671 if (maxWidth-minWidth < spacePerFlexItem * FlexItemWeight) 672 { 673 extraSpace += spacePerFlexItem * FlexItemWeight - (maxWidth-minWidth); // give back unneeded space 674 maxWidthItemsCount += FlexItemWeight; 675 } 676 } 677 // Recalculate spacePerFlexItem (unless all flexible items are going to their max width) 678 if (flexibleItemsCount > maxWidthItemsCount) 679 spacePerFlexItem += extraSpace / (flexibleItemsCount-maxWidthItemsCount); 680 681 // Finally, go through all items, adjusting their width and positioning them as needed 682 e = [items objectEnumerator]; 683 while ((item = [e nextObject]) != nil) 684 { 685 backView = [item _backView]; 686 if ([item _isFlexibleSpace]) 687 { 688 NSRect backViewFrame = [backView frame]; 689 690 [backView setFrame: NSMakeRect(x, backViewFrame.origin.y, 691 spacePerFlexItem, 692 backViewFrame.size.height)]; 693 mustAdjustNext = YES; 694 } 695 else if ([variableWidthItems indexOfObjectIdenticalTo:item] != NSNotFound) 696 { 697 NSRect backViewFrame = [backView frame]; 698 CGFloat maxFlex = [item maxSize].width - [item minSize].width; 699 CGFloat flexAmount = MIN(maxFlex, spacePerFlexItem * FlexItemWeight); 700 CGFloat newWidth = [item minSize].width + flexAmount + 2 * InsetItemViewX; 701 [backView setFrame: NSMakeRect(x, backViewFrame.origin.y, 702 newWidth, 703 backViewFrame.size.height)]; 704 mustAdjustNext = YES; 705 } 706 else if (mustAdjustNext) 707 { 708 NSRect backViewFrame = [backView frame]; 709 710 [backView setFrame: NSMakeRect(x, backViewFrame.origin.y, 711 backViewFrame.size.width, backViewFrame.size.height)]; 712 } 713 view = [item view]; 714 if (view != nil) 715 { 716 NSRect viewFrame = [view frame]; 717 // Subtract InsetItemViewX 718 viewFrame.size.width = [backView frame].size.width - 2 * InsetItemViewX; 719 viewFrame.origin.x = InsetItemViewX; 720 [view setFrame: viewFrame]; 721 } 722 x += [backView frame].size.width; 723 } 724} 725 726- (void) _handleViewsVisibility 727{ 728 NSArray *backViews; 729 NSArray *subviews; 730 NSEnumerator *e; 731 NSView *backView; 732 733 /* The back views which are associated with each toolbar item (the toolbar 734 items doesn't reflect the toolbar view content) */ 735 backViews = [[_toolbar items] valueForKey: @"_backView"]; 736 737 // We remove each back view associated with a removed toolbar item 738 e = [[_clipView subviews] objectEnumerator]; 739 while ((backView = [e nextObject]) != nil) 740 { 741 if ([backViews containsObject: backView] == NO) 742 { 743 if ([backView superview] != nil) 744 [backView removeFromSuperview]; 745 } 746 } 747 748 // We add each backView associated with an added toolbar item 749 subviews = [_clipView subviews]; 750 e = [backViews objectEnumerator]; 751 while ((backView = [e nextObject]) != nil) 752 { 753 if ([subviews containsObject: backView] == NO) 754 { 755 [_clipView addSubview: backView]; 756 } 757 } 758} 759 760- (void) _manageClipView 761{ 762 NSRect clipViewFrame = [_clipView frame]; 763 int count = [[_toolbar items] count]; 764 // Retrieve the back views which should be visible now that the resize 765 // process has been taken in account 766 NSArray *visibleBackViews = [self _visibleBackViews]; 767 768 if ([visibleBackViews count] < count) 769 { 770 NSView *lastVisibleBackView = [visibleBackViews lastObject]; 771 float width = 0; 772 773 // Resize the clip view 774 if (lastVisibleBackView != nil) 775 width = NSMaxX([lastVisibleBackView frame]); 776 [_clipView setFrame: NSMakeRect(clipViewFrame.origin.x, 777 clipViewFrame.origin.y, 778 width, 779 clipViewFrame.size.height)]; 780 781 // Adjust the clipped items mark frame handling 782 [_clippedItemsMark layout]; 783 784 // We get the new _clipView frame 785 clipViewFrame = [_clipView frame]; 786 [_clippedItemsMark setFrameOrigin: NSMakePoint( 787 [self frame].size.width - ClippedItemsViewWidth, clipViewFrame.origin.y)]; 788 789 if ([_clippedItemsMark superview] == nil) 790 [self addSubview: _clippedItemsMark]; 791 792 } 793 else if (([_clippedItemsMark superview] != nil) 794 && ([visibleBackViews count] == count)) 795 { 796 [_clippedItemsMark removeFromSuperview]; 797 798 [_clipView setFrame: NSMakeRect(clipViewFrame.origin.x, 799 clipViewFrame.origin.y, 800 [self frame].size.width, 801 clipViewFrame.size.height)]; 802 } 803} 804 805- (void) _reload 806{ 807 // First, we resize 808 [self _handleBackViewsFrame]; 809 [self _takeInAccountFlexibleSpaces]; 810 811 [self _handleViewsVisibility]; 812 /* We manage the clipped items view in the case it should become visible or 813 invisible */ 814 [self _manageClipView]; 815 816 [self setNeedsDisplay: YES]; 817} 818 819// Accessors private methods 820 821- (float) _heightFromLayout 822{ 823 float height = _heightFromLayout; 824 825 if (_borderMask & GSToolbarViewBottomBorder) 826 { 827 height++; 828 } 829 830 if (_borderMask & GSToolbarViewTopBorder) 831 { 832 height++; 833 } 834 835 return height; 836} 837 838/* 839 * Will return the visible (not clipped) back views in the toolbar view even 840 * when the toolbar is not visible. 841 * May be should be renamed _notClippedBackViews method. 842 */ 843- (NSArray *) _visibleBackViews 844{ 845 NSArray *items = [_toolbar items]; 846 NSView *backView, *view; 847 int i, n = [items count]; 848 float backViewsWidth = 0, toolbarWidth = [self frame].size.width; 849 850 NSMutableArray *visibleBackViews = [NSMutableArray array]; 851 852 for (i = 0; i < n; i++) 853 { 854 NSToolbarItem *item = [items objectAtIndex:i]; 855 backView = [item _backView]; 856 view = [item view]; 857 if (view != nil) 858 backViewsWidth += [item minSize].width + 2*InsetItemViewX; 859 else 860 backViewsWidth += [backView frame].size.width; 861 862 if ((backViewsWidth + ClippedItemsViewWidth <= toolbarWidth) 863 || (i == n - 1 && backViewsWidth <= toolbarWidth)) 864 { 865 [visibleBackViews addObject: backView]; 866 } 867 } 868 869 return visibleBackViews; 870} 871 872- (NSColor *) standardBackgroundColor 873{ 874 NSLog(@"Use of deprecated method %@", NSStringFromSelector(_cmd)); 875 return nil; 876} 877 878- (BOOL) _usesStandardBackgroundColor 879{ 880 NSLog(@"Use of deprecated method %@", NSStringFromSelector(_cmd)); 881 return NO; 882} 883 884- (void) _setUsesStandardBackgroundColor: (BOOL)standard 885{ 886 NSLog(@"Use of deprecated method %@", NSStringFromSelector(_cmd)); 887} 888 889- (NSMenu *) menuForEvent: (NSEvent *)event 890{ 891 NSMenu *menu = [[[NSMenu alloc] initWithTitle: @""] autorelease]; 892 id <NSMenuItem> customize = [menu insertItemWithTitle: _(@"Customize Toolbar") action:@selector(runCustomizationPalette:) keyEquivalent:@"" atIndex:0]; 893 [customize setTarget: _toolbar]; 894 return menu; 895} 896 897 898 899@end 900