00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 @import <Foundation/CPObject.j>
00027
00028 @import "CPPopUpButton.j"
00029 @import "CPToolbarItem.j"
00030
00031
00032
00033
00034
00035
00036 CPToolbarDisplayModeDefault = 0;
00037
00038
00039
00040
00041 CPToolbarDisplayModeIconAndLabel = 1;
00042
00043
00044
00045
00046 CPToolbarDisplayModeIconOnly = 2;
00047
00048
00049
00050
00051 CPToolbarDisplayModeLabelOnly = 3;
00052
00053 var CPToolbarsByIdentifier = nil;
00054 var CPToolbarConfigurationsByIdentifier = nil;
00055
00082 @implementation CPToolbar : CPObject
00083 {
00084 CPString _identifier;
00085 CPToolbarDisplayMode _displayMode;
00086 BOOL _showsBaselineSeparator;
00087 BOOL _allowsUserCustomization;
00088 BOOL _isVisible;
00089
00090 id _delegate;
00091
00092 CPArray _itemIdentifiers;
00093
00094 CPDictionary _identifiedItems;
00095 CPArray _defaultItems;
00096 CPArray _allowedItems;
00097 CPArray _selectableItems;
00098
00099 CPArray _items;
00100 CPArray _itemsSortedByVisibilityPriority;
00101
00102 CPView _toolbarView;
00103 }
00104
00105
00106 + (void)initialize
00107 {
00108 if (self != [CPToolbar class])
00109 return;
00110
00111 CPToolbarsByIdentifier = [CPDictionary dictionary];
00112 CPToolbarConfigurationsByIdentifier = [CPDictionary dictionary];
00113 }
00114
00115
00116 + (void)_addToolbar:(CPToolbar)toolbar forIdentifier:(CPString)identifier
00117 {
00118 var toolbarsSharingIdentifier = [CPToolbarsByIdentifier objectForKey:identifier];
00119
00120 if (!toolbarsSharingIdentifier)
00121 {
00122 toolbarsSharingIdentifier = []
00123 [CPToolbarsByIdentifier setObject:toolbarsSharingIdentifier forKey:identifier];
00124 }
00125
00126 [toolbarsSharingIdentifier addObject:toolbar];
00127 }
00128
00134 - (id)initWithIdentifier:(CPString)anIdentifier
00135 {
00136 self = [super init];
00137
00138 if (self)
00139 {
00140 _items = [];
00141
00142 _identifier = anIdentifier;
00143 _isVisible = YES;
00144
00145 [CPToolbar _addToolbar:self forIdentifier:_identifier];
00146 }
00147
00148 return self;
00149 }
00150
00151
00155 - (void)setDisplayMode:(CPToolbarDisplayMode)aDisplayMode
00156 {
00157
00158 }
00159
00163 - (CPString)identifier
00164 {
00165 return _identifier;
00166 }
00167
00171 - (id)delegate
00172 {
00173 return _delegate;
00174 }
00175
00179 - (BOOL)isVisible
00180 {
00181 return _isVisible;
00182 }
00183
00188 - (void)setVisible:(BOOL)aFlag
00189 {
00190 if (_isVisible == aFlag)
00191 return;
00192
00193 _isVisible = aFlag;
00194
00195 [_window _setToolbarVisible:_isVisible];
00196 [self _reloadToolbarItems];
00197 }
00198
00203 - (void)setDelegate:(id)aDelegate
00204 {
00205 if (_delegate == aDelegate)
00206 return;
00207
00208 _delegate = aDelegate;
00209
00210 [self _reloadToolbarItems];
00211 }
00212
00213
00214 - (void)_loadConfiguration
00215 {
00216
00217 }
00218
00219
00220 - (CPView)_toolbarView
00221 {
00222 if (!_toolbarView)
00223 {
00224 _toolbarView = [[_CPToolbarView alloc] initWithFrame:CPRectMake(0.0, 0.0, 1200.0, 59.0)];
00225 [_toolbarView setAutoresizingMask:CPViewWidthSizable];
00226
00227 [_toolbarView setToolbar:self];
00228 }
00229
00230 return _toolbarView;
00231 }
00232
00233
00234 - (void)_reloadToolbarItems
00235 {
00236 if (![_toolbarView superview] || !_delegate)
00237 return;
00238
00239 var count = [_itemIdentifiers count];
00240
00241 if (!count)
00242 {
00243 _itemIdentifiers = [[_delegate toolbarDefaultItemIdentifiers:self] mutableCopy];
00244 count = [_itemIdentifiers count];
00245 }
00246
00247 [[_toolbarView subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)];
00248
00249 _items = [];
00250
00251 var index = 0;
00252
00253 for (; index < count; ++index)
00254 {
00255 var identifier = _itemIdentifiers[index],
00256 item = [CPToolbarItem _standardItemWithItemIdentifier:identifier];
00257
00258 if (!item)
00259 item = [[_delegate toolbar:self itemForItemIdentifier:identifier willBeInsertedIntoToolbar:YES] copy];
00260
00261 if (item == nil)
00262 [CPException raise:CPInvalidArgumentException
00263 reason:sprintf(@"_delegate %s returned nil toolbar item returned for identifier %s", _delegate, identifier)];
00264
00265 [_items addObject:item];
00266 }
00267
00268
00269
00270
00271
00272
00273 _itemsSortedByVisibilityPriority = [_items sortedArrayUsingFunction:_CPToolbarItemVisibilityPriorityCompare context:NULL];
00274
00275 [_toolbarView reloadToolbarItems];
00276 }
00277
00281 - (CPArray)items
00282 {
00283 return _items;
00284 }
00285
00289 - (CPArray)visibleItems
00290 {
00291 return [_toolbarView visibleItems];
00292 }
00293
00297 - (CPArray)itemsSortedByVisibilityPriority
00298 {
00299 return _itemsSortedByVisibilityPriority;
00300 }
00301
00302
00303 - (id)_itemForItemIdentifier:(CPString)identifier willBeInsertedIntoToolbar:(BOOL)toolbar
00304 {
00305 var item = [_identifiedItems objectForKey:identifier];
00306 if (!item)
00307 {
00308 item = [CPToolbarItem _standardItemWithItemIdentifier:identifier];
00309 if (_delegate && !item)
00310 {
00311 item = [[_delegate toolbar:self itemForItemIdentifier:identifier willBeInsertedIntoToolbar:toolbar] copy];
00312 if (!item)
00313 [CPException raise:CPInvalidArgumentException
00314 reason:sprintf(@"_delegate %s returned nil toolbar item returned for identifier %s", _delegate, identifier)];
00315 }
00316
00317 [_identifiedItems setObject:item forKey:identifier];
00318 }
00319
00320 return item;
00321 }
00322
00323
00324 - (id)_itemsWithIdentifiers:(CPArray)identifiers
00325 {
00326 var items = [];
00327 for (var i = 0; i < identifiers.length; i++)
00328 [items addObject:[self _itemForItemIdentifier:identifiers[i] willBeInsertedIntoToolbar:NO]];
00329
00330 return items;
00331 }
00332
00333
00334 -(id)_defaultToolbarItems
00335 {
00336 if (!_defaultItems)
00337 if ([_delegate respondsToSelector:@selector(toolbarDefaultItemIdentifiers:)])
00338 _defaultItems = [self _itemsWithIdentifiers:[_delegate toolbarDefaultItemIdentifiers:self]];
00339
00340 return _defaultItems;
00341 }
00342
00343 @end
00344
00345
00346 var CPToolbarIdentifierKey = "CPToolbarIdentifierKey",
00347 CPToolbarDisplayModeKey = "CPToolbarDisplayModeKey",
00348 CPToolbarShowsBaselineSeparatorKey = "CPToolbarShowsBaselineSeparatorKey",
00349 CPToolbarAllowsUserCustomizationKey = "CPToolbarAllowsUserCustomizationKey",
00350 CPToolbarIsVisibleKey = "CPToolbarIsVisibleKey",
00351 CPToolbarDelegateKey = "CPToolbarDelegateKey",
00352 CPToolbarIdentifiedItemsKey = "CPToolbarIdentifiedItemsKey",
00353 CPToolbarDefaultItemsKey = "CPToolbarDefaultItemsKey",
00354 CPToolbarAllowedItemsKey = "CPToolbarAllowedItemsKey",
00355 CPToolbarSelectableItemsKey = "CPToolbarSelectableItemsKey";
00356
00357 @implementation CPToolbar (CPCoding)
00358
00359
00360
00361
00362
00363 - (id)initWithCoder:(CPCoder)aCoder
00364 {
00365 self = [super init];
00366
00367 if (self)
00368 {
00369 _identifier = [aCoder decodeObjectForKey:CPToolbarIdentifierKey];
00370 _displayMode = [aCoder decodeIntForKey:CPToolbarDisplayModeKey];
00371 _showsBaselineSeparator = [aCoder decodeBoolForKey:CPToolbarShowsBaselineSeparatorKey];
00372 _allowsUserCustomization = [aCoder decodeBoolForKey:CPToolbarAllowsUserCustomizationKey];
00373 _isVisible = [aCoder decodeBoolForKey:CPToolbarIsVisibleKey];
00374
00375 _identifiedItems = [aCoder decodeObjectForKey:CPToolbarIdentifiedItemsKey];
00376 _defaultItems = [aCoder decodeObjectForKey:CPToolbarDefaultItemsKey];
00377 _allowedItems = [aCoder decodeObjectForKey:CPToolbarAllowedItemsKey];
00378 _selectableItems = [aCoder decodeObjectForKey:CPToolbarSelectableItemsKey];
00379
00380 _items = [];
00381 [CPToolbar _addToolbar:self forIdentifier:_identifier];
00382
00383 [self setDelegate:[aCoder decodeObjectForKey:CPToolbarDelegateKey]];
00384 }
00385
00386 return self;
00387 }
00388
00389
00390
00391
00392
00393 - (void)encodeWithCoder:(CPCoder)aCoder
00394 {
00395 [aCoder encodeObject:_identifier forKey:CPToolbarIdentifierKey];
00396 [aCoder encodeInt:_displayMode forKey:CPToolbarDisplayModeKey];
00397 [aCoder encodeBool:_showsBaselineSeparator forKey:CPToolbarShowsBaselineSeparatorKey];
00398 [aCoder encodeBool:_allowsUserCustomization forKey:CPToolbarAllowsUserCustomizationKey];
00399 [aCoder encodeBool:_isVisible forKey:CPToolbarIsVisibleKey];
00400
00401 [aCoder encodeObject:_identifiedItems forKey:CPToolbarIdentifiedItemsKey];
00402 [aCoder encodeObject:_defaultItems forKey:CPToolbarDefaultItemsKey];
00403 [aCoder encodeObject:_allowedItems forKey:CPToolbarAllowedItemsKey];
00404 [aCoder encodeObject:_selectableItems forKey:CPToolbarSelectableItemsKey];
00405
00406 [aCoder encodeConditionalObject:_delegate forKey:CPToolbarDelegateKey];
00407 }
00408
00409 @end
00410
00411
00412 var _CPToolbarViewBackgroundColor = nil,
00413 _CPToolbarViewExtraItemsImage = nil,
00414 _CPToolbarViewExtraItemsAlternateImage = nil;
00415
00416 var TOOLBAR_TOP_MARGIN = 5.0,
00417 TOOLBAR_ITEM_MARGIN = 10.0,
00418 TOOLBAR_EXTRA_ITEMS_WIDTH = 20.0;
00419
00420 var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
00421 {
00422 return { index:anIndex, view:aView, label:aLabel, minWidth:aMinWidth };
00423 }
00424
00425
00426 @implementation _CPToolbarView : CPView
00427 {
00428 CPToolbar _toolbar;
00429
00430 CPIndexSet _flexibleWidthIndexes;
00431 CPIndexSet _visibleFlexibleWidthIndexes;
00432
00433 CPDictionary _itemInfos;
00434
00435 CPArray _visibleItems;
00436 CPArray _invisibleItems;
00437
00438 CPPopUpButton _additionalItemsButton;
00439 }
00440
00441 + (void)initialize
00442 {
00443 if (self != [_CPToolbarView class])
00444 return;
00445
00446 var bundle = [CPBundle bundleForClass:self];
00447
00448 _CPToolbarViewBackgroundColor = [CPColor colorWithPatternImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPToolbarView/_CPToolbarViewBackground.png"] size:CGSizeMake(1.0, 59.0)]];
00449
00450 _CPToolbarViewExtraItemsImage = [[CPImage alloc] initWithContentsOfFile: [bundle pathForResource:"_CPToolbarView/_CPToolbarViewExtraItemsImage.png"] size: CPSizeMake(10.0, 15.0)];
00451
00452 _CPToolbarViewExtraItemsAlternateImage = [[CPImage alloc] initWithContentsOfFile: [bundle pathForResource:"_CPToolbarView/_CPToolbarViewExtraItemsAlternateImage.png"] size:CGSizeMake(10.0, 15.0)];
00453 }
00454
00455 - (id)initWithFrame:(CGRect)aFrame
00456 {
00457 self = [super initWithFrame:aFrame];
00458
00459 if (self)
00460 {
00461 _minWidth = 0;
00462
00463 [self setBackgroundColor:_CPToolbarViewBackgroundColor];
00464
00465 _additionalItemsButton = [[CPPopUpButton alloc] initWithFrame:CGRectMake(0.0, 0.0, 10.0, 15.0) pullsDown:YES];
00466 [_additionalItemsButton setBordered:NO];
00467
00468 [_additionalItemsButton setImagePosition:CPImageOnly];
00469 [[_additionalItemsButton menu] setShowsStateColumn:NO];
00470
00471 [_additionalItemsButton setAlternateImage:_CPToolbarViewExtraItemsAlternateImage];
00472 }
00473
00474 return self;
00475 }
00476
00477 - (void)setToolbar:(CPToolbar)aToolbar
00478 {
00479 _toolbar = aToolbar;
00480 }
00481
00482 - (CPToolbar)toolbar
00483 {
00484 return _toolbar;
00485 }
00486
00487
00488 - (void)resizeSubviewsWithOldSize:(CGSize)aSize
00489 {
00490 [self layoutSubviews];
00491 }
00492
00493 - (void)layoutSubviews
00494 {
00495
00496 var items = [_toolbar items],
00497 width = CGRectGetWidth([self bounds]),
00498 minWidth = _minWidth,
00499 flexibleItemIndexes = [CPIndexSet indexSet],
00500
00501 invisibleItemsSortedByPriority = [];
00502
00503 _visibleItems = items;
00504
00505
00506
00507 if (width < minWidth)
00508 {
00509 width -= TOOLBAR_EXTRA_ITEMS_WIDTH;
00510
00511 _visibleItems = [_visibleItems copy];
00512
00513 var itemsSortedByVisibilityPriority = [_toolbar itemsSortedByVisibilityPriority],
00514 count = itemsSortedByVisibilityPriority.length;
00515
00516
00517 while (minWidth > width)
00518 {
00519 var item = itemsSortedByVisibilityPriority[count--];
00520
00521 minWidth -= [self minWidthForItem:item] + TOOLBAR_ITEM_MARGIN;
00522
00523 [_visibleItems removeObjectIdenticalTo:item];
00524 [invisibleItemsSortedByPriority addObject:item];
00525
00526 [[self viewForItem:item] setHidden:YES];
00527 [[self labelForItem:item] setHidden:YES];
00528 }
00529 }
00530
00531
00532
00533
00534 var index = _visibleItems.length,
00535 height = 0.0;
00536
00537 while (index--)
00538 {
00539 var item = _visibleItems[index],
00540 minSize = [item minSize],
00541 view = [self viewForItem:item];
00542
00543 if (minSize.width != [item maxSize].width)
00544 [flexibleItemIndexes addIndex:index];
00545
00546
00547
00548 else
00549 [view setFrameSize:CGSizeMake([item minSize].width, CGRectGetHeight([view frame]))];
00550
00551
00552
00553 [view setHidden:NO];
00554 [[self labelForItem:item] setHidden:NO];
00555
00556 if (height < minSize.height)
00557 height = minSize.height;
00558 }
00559
00560 var remainingSpace = width - minWidth,
00561 proportionate = 0.0;
00562
00563
00564
00565
00566 while (remainingSpace && [flexibleItemIndexes count])
00567 {
00568
00569 proportionate += remainingSpace / [flexibleItemIndexes count];
00570
00571
00572 remainingSpace = 0.0;
00573
00574 var index = CPNotFound;
00575
00576 while ((index = [flexibleItemIndexes indexGreaterThanIndex:index]) != CPNotFound)
00577 {
00578 var item = _visibleItems[index];
00579 view = [self viewForItem:item],
00580 viewFrame = [view frame],
00581
00582 proposedWidth = [item minSize].width + proportionate,
00583 constrainedWidth = MIN(proposedWidth, [item maxSize].width);
00584
00585 if (constrainedWidth < proposedWidth)
00586 {
00587 [flexibleItemIndexes removeIndex:index];
00588
00589 remainingSpace += proposedWidth - constrainedWidth;
00590 }
00591
00592 [view setFrameSize:CGSizeMake(constrainedWidth, CGRectGetHeight(viewFrame))];
00593 }
00594 }
00595
00596
00597 var count = _visibleItems.length,
00598 x = TOOLBAR_ITEM_MARGIN,
00599 fullHeightItems = [];
00600
00601 for (index = 0; index < count; ++index)
00602 {
00603 var item = _visibleItems[index],
00604 view = [self viewForItem:item],
00605
00606 viewFrame = [view frame],
00607 viewWidth = CGRectGetWidth(viewFrame),
00608
00609 label = [self labelForItem:item],
00610 labelFrame = [label frame],
00611 labelWidth = CGRectGetWidth(labelFrame),
00612
00613 itemWidth = MAX([self minWidthForItem:item], viewWidth),
00614
00615 viewHeight = CGRectGetHeight(viewFrame);
00616
00617
00618
00619 [view setFrame:CGRectMake(x + (itemWidth - viewWidth) / 2.0, TOOLBAR_TOP_MARGIN + (height - viewHeight) / 2.0, viewWidth, viewHeight)];
00620 [label setFrameOrigin:CGPointMake(x + (itemWidth - labelWidth) / 2.0, TOOLBAR_TOP_MARGIN + height + 2.0)];
00621
00622 x += itemWidth + TOOLBAR_ITEM_MARGIN;
00623
00624 if ([item itemIdentifier] == CPToolbarSeparatorItemIdentifier)
00625 fullHeightItems.push(item);
00626 }
00627
00628 for (index = 0, count = fullHeightItems.length; index < count; ++index)
00629 {
00630 var view = [self viewForItem:fullHeightItems[index]],
00631 viewHeight = 53.0;
00632
00633
00634 [view setFrame:CGRectMake(CGRectGetMinX([view frame]), (59.0 - viewHeight) / 2.0, CGRectGetWidth([view frame]), viewHeight)];
00635 }
00636
00637 if ([invisibleItemsSortedByPriority count])
00638 {
00639 var index = 0,
00640 count = [items count];
00641
00642 _invisibleItems = [];
00643
00644 for (; index < count; ++index)
00645 {
00646 var item = items[index];
00647
00648 if ([invisibleItemsSortedByPriority indexOfObjectIdenticalTo:item] != CPNotFound)
00649 [_invisibleItems addObject:item];
00650 }
00651
00652 [_additionalItemsButton setFrameOrigin:CGPointMake(width + 5.0, (CGRectGetHeight([self bounds]) - CGRectGetHeight([_additionalItemsButton frame])) / 2.0)];
00653
00654 [self addSubview:_additionalItemsButton];
00655
00656 [_additionalItemsButton removeAllItems];
00657
00658 var index = 0,
00659 count = [_invisibleItems count];
00660
00661 [_additionalItemsButton addItemWithTitle:@"Additional Items"];
00662 [[_additionalItemsButton itemArray][0] setImage:_CPToolbarViewExtraItemsImage];
00663
00664 for (; index < count; ++index)
00665 {
00666 var item = _invisibleItems[index];
00667
00668 [_additionalItemsButton addItemWithTitle:[item label]];
00669
00670 var menuItem = [_additionalItemsButton itemArray][index + 1];
00671
00672 [menuItem setImage:[item image]];
00673
00674 [menuItem setTarget:[item target]];
00675 [menuItem setAction:[item action]];
00676 }
00677 }
00678 else
00679 [_additionalItemsButton removeFromSuperview];
00680
00681 }
00682
00683 - (CPView)viewForItem:(CPToolbarItem)anItem
00684 {
00685 var info = [_itemInfos objectForKey:[anItem hash]];
00686
00687 if (!info)
00688 return nil;
00689
00690 return info.view;
00691 }
00692
00693 - (CPTextField)labelForItem:(CPToolbarItem)anItem
00694 {
00695 var info = [_itemInfos objectForKey:[anItem hash]];
00696
00697 if (!info)
00698 return nil;
00699
00700 return info.label;
00701 }
00702
00703 - (float)minWidthForItem:(CPToolbarItem)anItem
00704 {
00705 var info = [_itemInfos objectForKey:[anItem hash]];
00706
00707 if (!info)
00708 return 0;
00709
00710 return info.minWidth;
00711 }
00712
00713 - (void)reloadToolbarItems
00714 {
00715
00716 var subviews = [self subviews],
00717 count = subviews.length;
00718
00719 while (count--)
00720 [subviews removeObjectAtIndex:count];
00721
00722
00723 var items = [_toolbar items],
00724 index = 0;
00725
00726 count = items.length;
00727
00728 _itemInfos = [CPDictionary dictionary];
00729 _minWidth = TOOLBAR_ITEM_MARGIN;
00730
00731 for (; index < count; ++index)
00732 {
00733 var item = items[index],
00734 view = [item view];
00735
00736
00737 if (!view)
00738 {
00739 view = [[CPButton alloc] initWithFrame:CGRectMake(0.0, 0.0, 32.0, 32.0)];
00740
00741 [view setBordered:NO];
00742
00743 [view setImage:[item image]];
00744 [view setAlternateImage:[item alternateImage]];
00745
00746 [view setTarget:[item target]];
00747 [view setAction:[item action]];
00748
00749 [view setImagePosition:CPImageOnly];
00750 }
00751
00752 [self addSubview:view];
00753
00754
00755 var label = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
00756
00757 [label setStringValue:[item label]];
00758 [label setFont:[CPFont systemFontOfSize:11.0]];
00759 [label sizeToFit];
00760
00761 [label setTarget:[item target]];
00762 [label setAction:[item action]];
00763
00764 [self addSubview:label];
00765
00766 var minSize = [item minSize],
00767 minWidth = MAX(minSize.width, CGRectGetWidth([label frame]));
00768
00769 [_itemInfos setObject:_CPToolbarItemInfoMake(index, view, label, minWidth) forKey:[item hash]];
00770
00771 _minWidth += minWidth + TOOLBAR_ITEM_MARGIN;
00772
00773
00774
00775
00776 }
00777
00778 [self layoutSubviews];
00779 }
00780
00781 @end
00782
00783
00784 var _CPToolbarItemVisibilityPriorityCompare = function(lhs, rhs)
00785 {
00786 var lhsVisibilityPriority = [lhs visibilityPriority],
00787 rhsVisibilityPriority = [rhs visibilityPriority];
00788
00789 if (lhsVisibilityPriority == rhsVisibilityPriority)
00790 return CPOrderedSame;
00791
00792 if (lhsVisibilityPriority > rhsVisibilityPriority)
00793 return CPOrderedAscending;
00794
00795 return CPOrderedDescending;
00796 }