00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 @import <Foundation/CPArray.j>
00024 @import <Foundation/CPDictionary.j>
00025 @import <Foundation/CPNotificationCenter.j>
00026 @import <Foundation/CPString.j>
00027
00028 @import "CPApplication.j"
00029 @import "CPClipView.j"
00030 @import "CPMenuItem.j"
00031 @import "CPPanel.j"
00032
00033 #include "Platform/Platform.h"
00034
00035
00036 CPMenuDidAddItemNotification = @"CPMenuDidAddItemNotification";
00037 CPMenuDidChangeItemNotification = @"CPMenuDidChangeItemNotification";
00038 CPMenuDidRemoveItemNotification = @"CPMenuDidRemoveItemNotification";
00039
00040 CPMenuDidEndTrackingNotification = @"CPMenuDidEndTrackingNotification";
00041
00042 var MENUBAR_HEIGHT = 19.0;
00043
00044 var _CPMenuBarVisible = NO,
00045 _CPMenuBarTitle = @"",
00046 _CPMenuBarIconImage = nil,
00047 _CPMenuBarIconImageAlphaValue = 1.0,
00048 _CPMenuBarAttributes = nil,
00049 _CPMenuBarSharedWindow = nil;
00050
00055 @implementation CPMenu : CPObject
00056 {
00057 CPString _title;
00058
00059 CPMutableArray _items;
00060 CPMenu _attachedMenu;
00061
00062 BOOL _autoenablesItems;
00063 BOOL _showsStateColumn;
00064
00065 id _delegate;
00066
00067 CPMenuItem _highlightedIndex;
00068 _CPMenuWindow _menuWindow;
00069 }
00070
00071
00072
00073 + (BOOL)menuBarVisible
00074 {
00075 return _CPMenuBarVisible;
00076 }
00077
00078 + (void)setMenuBarVisible:(BOOL)menuBarShouldBeVisible
00079 {
00080 if (_CPMenuBarVisible == menuBarShouldBeVisible)
00081 return;
00082
00083 _CPMenuBarVisible = menuBarShouldBeVisible;
00084
00085 if (menuBarShouldBeVisible)
00086 {
00087 if (!_CPMenuBarSharedWindow)
00088 _CPMenuBarSharedWindow = [[_CPMenuBarWindow alloc] init];
00089
00090 [_CPMenuBarSharedWindow setMenu:[CPApp mainMenu]];
00091
00092 [_CPMenuBarSharedWindow setTitle:_CPMenuBarTitle];
00093 [_CPMenuBarSharedWindow setIconImage:_CPMenuBarIconImage];
00094 [_CPMenuBarSharedWindow setIconImageAlphaValue:_CPMenuBarIconImageAlphaValue];
00095
00096 [_CPMenuBarSharedWindow setColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarBackgroundColor"]];
00097 [_CPMenuBarSharedWindow setTextColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarTextColor"]];
00098 [_CPMenuBarSharedWindow setTitleColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarTitleColor"]];
00099
00100 [_CPMenuBarSharedWindow orderFront:self];
00101 }
00102 else
00103 [_CPMenuBarWindow orderOut:self];
00104
00105
00106 #if PLATFORM(DOM)
00107 [[CPDOMWindowBridge sharedDOMWindowBridge] _bridgeResizeEvent:nil];
00108 #endif
00109 }
00110
00111 + (void)setMenuBarTitle:(CPString)aTitle
00112 {
00113 _CPMenuBarTitle = aTitle;
00114 [_CPMenuBarSharedWindow setTitle:_CPMenuBarTitle];
00115 }
00116
00117 + (CPString)menuBarTitle
00118 {
00119 return _CPMenuBarTitle;
00120 }
00121
00122 + (void)setMenuBarIconImage:(CPImage)anImage
00123 {
00124 _CPMenuBarImage = anImage;
00125 [_CPMenuBarSharedWindow setIconImage:anImage];
00126 }
00127
00128 + (CPImage)menuBarIconImage
00129 {
00130 return _CPMenuBarImage;
00131 }
00132
00133 + (void)setMenuBarAttributes:(CPDictionary)attributes
00134 {
00135 if (_CPMenuBarAttributes == attributes)
00136 return;
00137
00138 _CPMenuBarAttributes = [attributes copy];
00139
00140 var textColor = [attributes objectForKey:@"CPMenuBarTextColor"],
00141 titleColor = [attributes objectForKey:@"CPMenuBarTitleColor"];
00142
00143 if (!textColor && titleColor)
00144 [_CPMenuBarAttributes setObject:titleColor forKey:@"CPMenuBarTextColor"];
00145
00146 else if (textColor && !titleColor)
00147 [_CPMenuBarAttributes setObject:textColor forKey:@"CPMenuBarTitleColor"];
00148
00149 else if (!textColor && !titleColor)
00150 {
00151 [_CPMenuBarAttributes setObject:[CPColor blackColor] forKey:@"CPMenuBarTextColor"];
00152 [_CPMenuBarAttributes setObject:[CPColor blackColor] forKey:@"CPMenuBarTitleColor"];
00153 }
00154
00155 if (_CPMenuBarSharedWindow)
00156 {
00157 [_CPMenuBarSharedWindow setColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarBackgroundColor"]];
00158 [_CPMenuBarSharedWindow setTextColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarTextColor"]];
00159 [_CPMenuBarSharedWindow setTitleColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarTitleColor"]];
00160 }
00161 }
00162
00163 + (CPDictionary)menuBarAttributes
00164 {
00165 return _CPMenuBarAttributes;
00166 }
00167
00168 + (void)_setMenuBarIconImageAlphaValue:(float)anAlphaValue
00169 {
00170 _CPMenuBarIconImageAlphaValue = anAlphaValue;
00171 [_CPMenuBarSharedWindow setIconImageAlphaValue:anAlphaValue];
00172 }
00173
00174 - (float)menuBarHeight
00175 {
00176 if (self == [CPApp mainMenu])
00177 return MENUBAR_HEIGHT;
00178
00179 return 0.0;
00180 }
00181
00182
00188 - (id)initWithTitle:(CPString)aTitle
00189 {
00190 self = [super init];
00191
00192 if (self)
00193 {
00194 _title = aTitle;
00195 _items = [];
00196
00197 _autoenablesItems = YES;
00198 _showsStateColumn = YES;
00199 }
00200
00201 return self;
00202 }
00203
00204
00210 - (void)insertItem:(CPMenuItem)aMenuItem atIndex:(unsigned)anIndex
00211 {
00212 var menu = [aMenuItem menu];
00213
00214 if (menu)
00215 if (menu != self)
00216 [CPException raise:CPInternalInconsistencyException reason:@"Attempted to insert item into menu that was already in another menu."];
00217 else
00218 return;
00219
00220 [aMenuItem setMenu:self];
00221 [_items insertObject:aMenuItem atIndex:anIndex];
00222
00223 [[CPNotificationCenter defaultCenter]
00224 postNotificationName:CPMenuDidAddItemNotification
00225 object:self
00226 userInfo:[CPDictionary dictionaryWithObject:anIndex forKey:@"CPMenuItemIndex"]];
00227
00228 }
00229
00238 - (CPMenuItem)insertItemWithTitle:(CPString)aTitle action:(SEL)anAction keyEquivalent:(CPString)aKeyEquivalent atIndex:(unsigned)anIndex
00239 {
00240 var item = [[CPMenuItem alloc] initWithTitle:aTitle action:anAction keyEquivalent:aKeyEquivalent];
00241
00242 [self insertItem:item atIndex:anIndex];
00243
00244 return item;
00245 }
00246
00251 - (void)addItem:(CPMenuItem)aMenuItem
00252 {
00253 [self insertItem:aMenuItem atIndex:[_items count]];
00254 }
00255
00264 - (CPMenuItem)addItemWithTitle:(CPString)aTitle action:(SEL)anAction keyEquivalent:(CPString)aKeyEquivalent
00265 {
00266 return [self insertItemWithTitle:aTitle action:anAction keyEquivalent:aKeyEquivalent atIndex:[_items count]];
00267 }
00268
00273 - (void)removeItem:(CPMenuItem)aMenuItem
00274 {
00275 [self removeItemAtIndex:[_items indexOfObjectIdenticalTo:aMenuItem]];
00276 }
00277
00282 - (void)removeItemAtIndex:(unsigned)anIndex
00283 {
00284 if (anIndex < 0 || anIndex >= _items.length)
00285 return;
00286
00287 [_items[anIndex] setMenu:nil];
00288 [_items removeObjectAtIndex:anIndex];
00289
00290 [[CPNotificationCenter defaultCenter]
00291 postNotificationName:CPMenuDidRemoveItemNotification
00292 object:self
00293 userInfo:[CPDictionary dictionaryWithObject:anIndex forKey:@"CPMenuItemIndex"]];
00294 }
00295
00300 - (void)itemChanged:(CPMenuItem)aMenuItem
00301 {
00302 if ([aMenuItem menu] != self)
00303 return;
00304
00305 [[CPNotificationCenter defaultCenter]
00306 postNotificationName:CPMenuDidChangeItemNotification
00307 object:self
00308 userInfo:[CPDictionary dictionaryWithObject:[_items indexOfObjectIdenticalTo:aMenuItem] forKey:@"CPMenuItemIndex"]];
00309 }
00310
00311
00317 - (CPMenuItem)menuWithTag:(int)aTag
00318 {
00319 var index = [self indexOfItemWithTag:aTag];
00320
00321 if (index == CPNotFound)
00322 return nil;
00323
00324 return _items[index];
00325 }
00326
00332 - (CPMenuItem)menuWithTitle:(CPString)aTitle
00333 {
00334 var index = [self indexOfItemWithTitle:aTitle];
00335
00336 if (index == CPNotFound)
00337 return nil;
00338
00339 return _items[index];
00340 }
00341
00346 - (CPMenuItem)itemAtIndex:(int)anIndex
00347 {
00348 return [_items objectAtIndex:anIndex];
00349 }
00350
00354 - (unsigned)numberOfItems
00355 {
00356 return [_items count];
00357 }
00358
00362 - (CPArray)itemArray
00363 {
00364 return _items;
00365 }
00366
00367
00373 - (int)indexOfItem:(CPMenuItem)aMenuItem
00374 {
00375 if ([aMenuItem menu] != self)
00376 return CPNotFound;
00377
00378 return [_items indexOfObjectIdenticalTo:aMenuItem];
00379 }
00380
00386 - (int)indexOfItemWithTitle:(CPString)aTitle
00387 {
00388 var index = 0,
00389 count = _items.length;
00390
00391 for (; index < count; ++index)
00392 if ([_items[index] title] === aTitle)
00393 return index;
00394
00395 return CPNotFound;
00396 }
00397
00403 - (int)indexOfItemWithTag:(int)aTag
00404 {
00405 var index = 0,
00406 count = _items.length;
00407
00408 for (; index < count; ++index)
00409 if ([_items[index] tag] == aTag)
00410 return index;
00411
00412 return CPNotFound;
00413 }
00414
00421 - (int)indexOfItemWithTarget:(id)aTarget andAction:(SEL)anAction
00422 {
00423 var index = 0,
00424 count = _items.length;
00425
00426 for (; index < count; ++index)
00427 {
00428 var item = _items[index];
00429
00430 if ([item target] == aTarget && (!anAction || [item action] == anAction))
00431 return index;
00432 }
00433
00434 return CPNotFound;
00435 }
00436
00442 - (int)indexOfItemWithRepresentedObject:(id)anObject
00443 {
00444 var index = 0,
00445 count = _items.length;
00446
00447 for (; index < count; ++index)
00448 if ([[_items[index] representedObject] isEqual:anObject])
00449 return index;
00450
00451 return CPNotFound;
00452 }
00453
00459 - (int)indexOfItemWithSubmenu:(CPMenu)aMenu
00460 {
00461 var index = 0,
00462 count = _items.length;
00463
00464 for (; index < count; ++index)
00465 if ([_items[index] submenu] == aMenu)
00466 return index;
00467
00468 return CPNotFound;
00469 }
00470
00471
00477 - (void)setSubmenu:(CPMenu)aMenu forItem:(CPMenuItem)aMenuItem
00478 {
00479 [aMenuItem setTarget:aMenuItem];
00480 [aMenuItem setAction:@selector(submenuAction:)];
00481
00482 [aMenuItem setSubmenu:aMenu];
00483 }
00484
00491 - (void)submenuAction:(id)aSender
00492 {
00493
00494 }
00495
00499 - (CPMenu)attachedMenu
00500 {
00501 return _attachedMenu;
00502 }
00503
00507 - (BOOL)isAttached
00508 {
00509 return _isAttached;
00510 }
00511
00515 - (CGPoint)locationOfSubmenu:(CPMenu)aMenu
00516 {
00517
00518 }
00519
00523 - (CPMenu)supermenu
00524 {
00525 return _supermenu;
00526 }
00527
00532 - (void)setSupermenu:(CPMenu)aMenu
00533 {
00534 _supermenu = aMenu;
00535 }
00536
00541 - (BOOL)isTornOff
00542 {
00543 return !_supermenu || self == [CPApp mainMenu];
00544 }
00545
00546
00551 - (void)setAutoenablesItems:(BOOL)aFlag
00552 {
00553 _autoenablesItems = aFlag;
00554 }
00555
00559 - (BOOL)autoenablesItems
00560 {
00561 return _autoenablesItems;
00562 }
00563
00567 - (void)update
00568 {
00569
00570 }
00571
00572
00577 - (void)setTitle:(CPString)aTitle
00578 {
00579 _title = aTitle;
00580 }
00581
00585 - (CPString)title
00586 {
00587 return _title;
00588 }
00589
00590
00591
00592 + (void)popUpContextMenu:(CPMenu)aMenu withEvent:(CPEvent)anEvent forView:(CPView)aView
00593 {
00594 [self popUpContextMenu:aMenu withEvent:anEvent forView:aView withFont:nil];
00595 }
00596
00597 + (void)popUpContextMenu:(CPMenu)aMenu withEvent:(CPEvent)anEvent forView:(CPView)aView withFont:(CPFont)aFont
00598 {
00599 [self _popUpContextMenu:aMenu withEvent:anEvent forView:aView withFont:aFont forMenuBar:NO];
00600 }
00601
00602 + (void)_popUpContextMenu:(CPMenu)aMenu withEvent:(CPEvent)anEvent forView:(CPView)aView withFont:(CPFont)aFont forMenuBar:(BOOL)isForMenuBar
00603 {
00604 var delegate = [aMenu delegate];
00605
00606 if ([delegate respondsToSelector:@selector(menuWillOpen:)])
00607 [delegate menuWillOpen:aMenu];
00608
00609 if (!aFont)
00610 aFont = [CPFont systemFontOfSize:12.0];
00611
00612 var theWindow = [aView window],
00613 menuWindow = [_CPMenuWindow menuWindowWithMenu:aMenu font:aFont];
00614
00615 [menuWindow setDelegate:self];
00616 [menuWindow setBackgroundStyle:isForMenuBar ? _CPMenuWindowMenuBarBackgroundStyle : _CPMenuWindowPopUpBackgroundStyle];
00617
00618 [menuWindow setFrameOrigin:[[anEvent window] convertBaseToBridge:[anEvent locationInWindow]]];
00619
00620 [menuWindow orderFront:self];
00621 [menuWindow beginTrackingWithEvent:anEvent sessionDelegate:self didEndSelector:@selector(_menuWindowDidFinishTracking:highlightedItem:)];
00622 }
00623
00624 + (void)_menuWindowDidFinishTracking:(_CPMenuWindow)aMenuWindow highlightedItem:(CPMenuItem)aMenuItem
00625 {
00626 [_CPMenuWindow poolMenuWindow:aMenuWindow];
00627
00628
00629
00630
00631
00632
00633 var target = nil,
00634 action = [aMenuItem action];
00635
00636 if (!action)
00637 {
00638
00639
00640 }
00641
00642
00643 else
00644 target = [aMenuItem target];
00645
00646 [CPApp sendAction:action to:target from:nil];
00647 }
00648
00649
00654 - (void)setShowsStateColumn:(BOOL)shouldShowStateColumn
00655 {
00656 _showsStateColumn = shouldShowStateColumn;
00657 }
00658
00662 - (BOOL)showsStateColumn
00663 {
00664 return _showsStateColumn;
00665 }
00666
00667
00672 - (CPMenuItem)highlightedItem
00673 {
00674 return _highlightedIndex >= 0 ? _items[_highlightedIndex] : nil;
00675 }
00676
00677
00678
00679 - (void)setDelegate:(id)aDelegate
00680 {
00681 _delegate = aDelegate;
00682 }
00683
00684 - (id)delegate
00685 {
00686 return _delegate;
00687 }
00688
00689
00693 - (void)cancelTracking
00694 {
00695 [_menuWindow cancelTracking];
00696 }
00697
00698
00699 - (void)_setMenuWindow:(_CPMenuWindow)aMenuWindow
00700 {
00701 _menuWindow = aMenuWindow;
00702 }
00703
00710 - (BOOL)performKeyEquivalent:(CPEvent)anEvent
00711 {
00712 if (_autoenablesItems)
00713 [self update];
00714
00715 var index = 0,
00716 count = _items.length,
00717 characters = [anEvent charactersIgnoringModifiers],
00718 modifierFlags = [anEvent modifierFlags];
00719
00720 for(; index < count; ++index)
00721 {
00722 var item = _items[index],
00723 modifierMask = [item keyEquivalentModifierMask];
00724
00725 if ((modifierFlags & (CPShiftKeyMask | CPAlternateKeyMask | CPCommandKeyMask | CPControlKeyMask)) == modifierMask &&
00726 [characters caseInsensitiveCompare:[item keyEquivalent]] == CPOrderedSame)
00727 {
00728 if ([item isEnabled])
00729 [self performActionForItemAtIndex:index];
00730 else
00731 {
00732
00733 }
00734
00735 return YES;
00736 }
00737
00738 if ([[item submenu] performKeyEquivalent:anEvent])
00739 return YES;
00740 }
00741
00742 return NO;
00743 }
00744
00745
00750 - (void)performActionForItemAtIndex:(unsigned)anIndex
00751 {
00752 var item = _items[anIndex];
00753
00754 [CPApp sendAction:[item action] to:[item target] from:item];
00755 }
00756
00757
00758
00759
00760
00761 - (BOOL)_itemIsHighlighted:(CPMenuItem)aMenuItem
00762 {
00763 return _items[_highlightedIndex] == aMenuItem;
00764 }
00765
00766
00767
00768
00769 - (void)_highlightItemAtIndex:(int)anIndex
00770 {
00771 var previousHighlightedIndex = _highlightedIndex;
00772
00773 _highlightedIndex = anIndex;
00774
00775 if (previousHighlightedIndex != CPNotFound)
00776 [[_items[previousHighlightedIndex] _menuItemView] highlight:NO];
00777
00778 if (_highlightedIndex != CPNotFound)
00779 [[_items[_highlightedIndex] _menuItemView] highlight:YES];
00780 }
00781
00782 @end
00783
00784
00785 var CPMenuTitleKey = @"CPMenuTitleKey",
00786 CPMenuItemsKey = @"CPMenuItemsKey";
00787
00788 @implementation CPMenu (CPCoding)
00789
00795 - (id)initWithCoder:(CPCoder)aCoder
00796 {
00797 self = [super init];
00798
00799 if (self)
00800 {
00801 _title = [aCoder decodeObjectForKey:CPMenuTitleKey];
00802 _items = [aCoder decodeObjectForKey:CPMenuItemsKey];
00803 }
00804
00805 return self;
00806 }
00807
00812 - (void)encodeWithCoder:(CPCoder)aCoder
00813 {
00814 [aCoder encodeObject:_title forKey:CPMenuTitleKey];
00815 [aCoder encodeObject:_items forKey:CPMenuItemsKey];
00816 }
00817
00818 @end
00819
00820 var _CPMenuWindowPool = [],
00821 _CPMenuWindowPoolCapacity = 5,
00822
00823 _CPMenuWindowBackgroundColors = [],
00824
00825 _CPMenuWindowScrollingStateUp = -1,
00826 _CPMenuWindowScrollingStateDown = 1,
00827 _CPMenuWindowScrollingStateNone = 0;
00828
00829 _CPMenuWindowMenuBarBackgroundStyle = 0;
00830 _CPMenuWindowPopUpBackgroundStyle = 1;
00831 _CPMenuWindowAttachedMenuBackgroundStyle = 2;
00832
00833 var STICKY_TIME_INTERVAL = 500,
00834
00835 TOP_MARGIN = 5.0,
00836 LEFT_MARGIN = 1.0,
00837 RIGHT_MARGIN = 1.0,
00838 BOTTOM_MARGIN = 5.0,
00839
00840 SCROLL_INDICATOR_HEIGHT = 16.0;
00841
00842
00843
00844
00845 @implementation _CPMenuWindow : CPWindow
00846 {
00847 _CPMenuView _menuView;
00848 CPClipView _menuClipView;
00849 CPView _lastMouseOverMenuView;
00850
00851 CPImageView _moreAboveView;
00852 CPImageView _moreBelowView;
00853
00854 id _sessionDelegate;
00855 SEL _didEndSelector;
00856
00857 CPTimeInterval _startTime;
00858 int _scrollingState;
00859 CGPoint _lastScreenLocation;
00860
00861 BOOL _isShowingTopScrollIndicator;
00862 BOOL _isShowingBottomScrollIndicator;
00863 BOOL _trackingCanceled;
00864
00865 CGRect _unconstrainedFrame;
00866 }
00867
00868 + (id)menuWindowWithMenu:(CPMenu)aMenu font:(CPFont)aFont
00869 {
00870 var menuWindow = nil;
00871
00872 if (_CPMenuWindowPool.length)
00873 menuWindow = _CPMenuWindowPool.pop();
00874 else
00875 menuWindow = [[_CPMenuWindow alloc] init];
00876
00877 [menuWindow setFont:aFont];
00878 [menuWindow setMenu:aMenu];
00879
00880 return menuWindow;
00881 }
00882
00883 + (void)poolMenuWindow:(_CPMenuWindow)aMenuWindow
00884 {
00885 if (!aMenuWindow || _CPMenuWindowPool.length >= _CPMenuWindowPoolCapacity)
00886 return;
00887
00888 _CPMenuWindowPool.push(aMenuWindow);
00889 }
00890
00891 + (void)initialize
00892 {
00893 if (self != [_CPMenuWindow class])
00894 return;
00895
00896 var bundle = [CPBundle bundleForClass:self];
00897
00898 _CPMenuWindowMoreAboveImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowMoreAbove.png"] size:CGSizeMake(38.0, 18.0)];
00899 _CPMenuWindowMoreBelowImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowMoreBelow.png"] size:CGSizeMake(38.0, 18.0)];
00900 }
00901
00902 - (id)init
00903 {
00904 self = [super initWithContentRect:CGRectMakeZero() styleMask:CPBorderlessWindowMask];
00905
00906 if (self)
00907 {
00908 [self setLevel:CPTornOffMenuWindowLevel];
00909 [self setHasShadow:YES];
00910 [self setAcceptsMouseMovedEvents:YES];
00911
00912 _unconstrainedFrame = CGRectMakeZero();
00913
00914 var contentView = [self contentView];
00915
00916 _menuView = [[_CPMenuView alloc] initWithFrame:CGRectMakeZero()];
00917
00918 _menuClipView = [[CPClipView alloc] initWithFrame:CGRectMake(LEFT_MARGIN, TOP_MARGIN, 0.0, 0.0)];
00919 [_menuClipView setDocumentView:_menuView];
00920
00921 [contentView addSubview:_menuClipView];
00922
00923 _moreAboveView = [[CPImageView alloc] initWithFrame:CGRectMakeZero()];
00924
00925 [_moreAboveView setImage:_CPMenuWindowMoreAboveImage];
00926 [_moreAboveView setFrameSize:[_CPMenuWindowMoreAboveImage size]];
00927
00928 [contentView addSubview:_moreAboveView];
00929
00930 _moreBelowView = [[CPImageView alloc] initWithFrame:CGRectMakeZero()];
00931
00932 [_moreBelowView setImage:_CPMenuWindowMoreBelowImage];
00933 [_moreBelowView setFrameSize:[_CPMenuWindowMoreBelowImage size]];
00934
00935 [contentView addSubview:_moreBelowView];
00936 }
00937
00938 return self;
00939 }
00940
00941 - (void)setFont:(CPFont)aFont
00942 {
00943 [_menuView setFont:aFont];
00944 }
00945
00946 - (void)setBackgroundStyle:(_CPMenuWindowBackgroundStyle)aBackgroundStyle
00947 {
00948 var color = _CPMenuWindowBackgroundColors[aBackgroundStyle];
00949
00950 if (!color)
00951 {
00952 var bundle = [CPBundle bundleForClass:[self class]];
00953
00954 if (aBackgroundStyle == _CPMenuWindowPopUpBackgroundStyle)
00955 color = [CPColor colorWithPatternImage:[[CPNinePartImage alloc] initWithImageSlices:
00956 [
00957 [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowRounded0.png"] size:CGSizeMake(4.0, 4.0)],
00958 [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow1.png"] size:CGSizeMake(1.0, 4.0)],
00959 [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowRounded2.png"] size:CGSizeMake(4.0, 4.0)],
00960
00961 [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow3.png"] size:CGSizeMake(4.0, 1.0)],
00962 [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow4.png"] size:CGSizeMake(1.0, 1.0)],
00963 [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow5.png"] size:CGSizeMake(4.0, 1.0)],
00964
00965 [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowRounded6.png"] size:CGSizeMake(4.0, 4.0)],
00966 [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow7.png"] size:CGSizeMake(1.0, 4.0)],
00967 [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowRounded8.png"] size:CGSizeMake(4.0, 4.0)]
00968 ]]];
00969
00970 else if (aBackgroundStyle == _CPMenuWindowMenuBarBackgroundStyle)
00971 color = [CPColor colorWithPatternImage:[[CPNinePartImage alloc] initWithImageSlices:
00972 [
00973 [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow3.png"] size:CGSizeMake(4.0, 0.0)],
00974 [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow4.png"] size:CGSizeMake(1.0, 0.0)],
00975 [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow5.png"] size:CGSizeMake(4.0, 0.0)],
00976
00977 [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow3.png"] size:CGSizeMake(4.0, 1.0)],
00978 [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow4.png"] size:CGSizeMake(1.0, 1.0)],
00979 [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow5.png"] size:CGSizeMake(4.0, 1.0)],
00980
00981 [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowRounded6.png"] size:CGSizeMake(4.0, 4.0)],
00982 [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow7.png"] size:CGSizeMake(1.0, 4.0)],
00983 [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowRounded8.png"] size:CGSizeMake(4.0, 4.0)]
00984 ]]];
00985
00986 _CPMenuWindowBackgroundColors[aBackgroundStyle] = color;
00987 }
00988
00989 [self setBackgroundColor:color];
00990 }
00991
00992 - (void)setMenu:(CPMenu)aMenu
00993 {
00994 [aMenu _setMenuWindow:self];
00995 [_menuView setMenu:aMenu];
00996
00997 var menuViewSize = [_menuView frame].size;
00998
00999 [self setFrameSize:CGSizeMake(LEFT_MARGIN + menuViewSize.width + RIGHT_MARGIN, TOP_MARGIN + menuViewSize.height + BOTTOM_MARGIN)];
01000
01001 [_menuView scrollPoint:CGPointMake(0.0, 0.0)];
01002 [_menuClipView setFrame:CGRectMake(LEFT_MARGIN, TOP_MARGIN, menuViewSize.width, menuViewSize.height)];
01003 }
01004
01005 - (void)setMinWidth:(float)aWidth
01006 {
01007 var size = [self frame].size;
01008
01009 [self setFrameSize:CGSizeMake(MAX(size.width, aWidth), size.height)];
01010 }
01011
01012 - (CGPoint)rectForItemAtIndex:(int)anIndex
01013 {
01014 return [_menuView convertRect:[_menuView rectForItemAtIndex:anIndex] toView:nil];
01015 }
01016
01017 - (void)orderFront:(id)aSender
01018 {
01019 [self constrainToScreen];
01020
01021 [super orderFront:aSender];
01022 }
01023
01024 - (void)constrainToScreen
01025 {
01026 _unconstrainedFrame = CGRectMakeCopy([self frame]);
01027
01028 var screenBounds = CGRectInset([[CPDOMWindowBridge sharedDOMWindowBridge] contentBounds], 5.0, 5.0),
01029 constrainedFrame = CGRectIntersection(_unconstrainedFrame, screenBounds),
01030 menuViewOrigin = [self convertBaseToBridge:CGPointMake(LEFT_MARGIN, TOP_MARGIN)];
01031
01032 constrainedFrame.origin.x = CGRectGetMinX(_unconstrainedFrame);
01033 constrainedFrame.size.width = CGRectGetWidth(_unconstrainedFrame);
01034
01035 if (CGRectGetWidth(constrainedFrame) > CGRectGetWidth(screenBounds))
01036 constrainedFrame.size.width = CGRectGetWidth(screenBounds);
01037
01038 if (CGRectGetMaxX(constrainedFrame) > CGRectGetMaxX(screenBounds))
01039 constrainedFrame.origin.x -= CGRectGetMaxX(constrainedFrame) - CGRectGetMaxX(screenBounds);
01040
01041 if (CGRectGetMinX(constrainedFrame) < CGRectGetMinX(screenBounds))
01042 constrainedFrame.origin.x = CGRectGetMinX(screenBounds);
01043
01044 [super setFrame:constrainedFrame];
01045
01046 var topMargin = TOP_MARGIN,
01047 bottomMargin = BOTTOM_MARGIN,
01048
01049 contentView = [self contentView],
01050 bounds = [contentView bounds];
01051
01052 var moreAbove = menuViewOrigin.y < CGRectGetMinY(constrainedFrame) + TOP_MARGIN,
01053 moreBelow = menuViewOrigin.y + CGRectGetHeight([_menuView frame]) > CGRectGetMaxY(constrainedFrame) - BOTTOM_MARGIN;
01054
01055 if (moreAbove)
01056 {
01057 topMargin += SCROLL_INDICATOR_HEIGHT;
01058
01059 var frame = [_moreAboveView frame];
01060
01061 [_moreAboveView setFrameOrigin:CGPointMake((CGRectGetWidth(bounds) - CGRectGetWidth(frame)) / 2.0, (TOP_MARGIN + SCROLL_INDICATOR_HEIGHT - CGRectGetHeight(frame)) / 2.0)];
01062 }
01063
01064 [_moreAboveView setHidden:!moreAbove];
01065
01066 if (moreBelow)
01067 {
01068 bottomMargin += SCROLL_INDICATOR_HEIGHT;
01069
01070 [_moreBelowView setFrameOrigin:CGPointMake((CGRectGetWidth(bounds) - CGRectGetWidth([_moreBelowView frame])) / 2.0, CGRectGetHeight(bounds) - SCROLL_INDICATOR_HEIGHT - BOTTOM_MARGIN)];
01071 }
01072
01073 [_moreBelowView setHidden:!moreBelow];
01074
01075 var clipFrame = CGRectMake(LEFT_MARGIN, topMargin, CGRectGetWidth(constrainedFrame) - LEFT_MARGIN - RIGHT_MARGIN, CGRectGetHeight(constrainedFrame) - topMargin - bottomMargin)
01076
01077 [_menuClipView setFrame:clipFrame];
01078 [_menuView setFrameSize:CGSizeMake(CGRectGetWidth(clipFrame), CGRectGetHeight([_menuView frame]))];
01079
01080 [_menuView scrollPoint:CGPointMake(0.0, [self convertBaseToBridge:clipFrame.origin].y - menuViewOrigin.y)];
01081 }
01082
01083 - (void)cancelTracking
01084 {
01085 _trackingCanceled = YES;
01086 }
01087
01088 - (void)beginTrackingWithEvent:(CPEvent)anEvent sessionDelegate:(id)aSessionDelegate didEndSelector:(SEL)aDidEndSelector
01089 {
01090 _startTime = [anEvent timestamp];
01091 _scrollingState = _CPMenuWindowScrollingStateNone;
01092 _trackingCanceled = NO;
01093
01094 _sessionDelegate = aSessionDelegate;
01095 _didEndSelector = aDidEndSelector;
01096
01097 [self trackEvent:anEvent];
01098 }
01099
01100 - (void)trackEvent:(CPEvent)anEvent
01101 {
01102 var type = [anEvent type],
01103 theWindow = [anEvent window],
01104 screenLocation = theWindow ? [theWindow convertBaseToBridge:[anEvent locationInWindow]] : [anEvent locationInWindow];
01105
01106 if (type == CPPeriodic)
01107 {
01108 var constrainedBounds = CGRectInset([[CPDOMWindowBridge sharedDOMWindowBridge] contentBounds], 5.0, 5.0);
01109
01110 if (_scrollingState == _CPMenuWindowScrollingStateUp)
01111 {
01112 if (CGRectGetMinY(_unconstrainedFrame) < CGRectGetMinY(constrainedBounds))
01113 _unconstrainedFrame.origin.y += 10;
01114 }
01115 else if (_scrollingState == _CPMenuWindowScrollingStateDown)
01116 if (CGRectGetMaxY(_unconstrainedFrame) > CGRectGetHeight(constrainedBounds))
01117 _unconstrainedFrame.origin.y -= 10;
01118
01119 [self setFrame:_unconstrainedFrame];
01120 [self constrainToScreen];
01121
01122 screenLocation = _lastScreenLocation;
01123 }
01124
01125 _lastScreenLocation = screenLocation;
01126
01127 var menu = [_menuView menu],
01128 menuLocation = [self convertBridgeToBase:screenLocation],
01129 activeItemIndex = [_menuView itemIndexAtPoint:[_menuView convertPoint:menuLocation fromView:nil]],
01130 mouseOverMenuView = [[menu itemAtIndex:activeItemIndex] view];
01131
01132
01133 if (mouseOverMenuView)
01134 {
01135 if (!_lastMouseOverMenuView)
01136 [menu _highlightItemAtIndex:CPNotFound];
01137
01138 if (_lastMouseOverMenuView != mouseOverMenuView)
01139 {
01140 [mouseOverMenuView mouseExited:anEvent];
01141
01142 [_lastMouseOverMenuView mouseEntered:anEvent];
01143
01144 _lastMouseOverMenuView = mouseOverMenuView;
01145 }
01146
01147 [self sendEvent:[CPEvent mouseEventWithType:type location:menuLocation modifierFlags:[anEvent modifierFlags]
01148 timestamp:[anEvent timestamp] windowNumber:[self windowNumber] context:nil
01149 eventNumber:0 clickCount:[anEvent clickCount] pressure:[anEvent pressure]]];
01150 }
01151 else
01152 {
01153 if (_lastMouseOverMenuView)
01154 {
01155 [_lastMouseOverMenuView mouseExited:anEvent];
01156 _lastMouseOverMenuView = nil;
01157 }
01158
01159 [menu _highlightItemAtIndex:[_menuView itemIndexAtPoint:[_menuView convertPoint:[self convertBridgeToBase:screenLocation] fromView:nil]]];
01160
01161 if (type == CPMouseMoved || type == CPLeftMouseDragged || type == CPLeftMouseDown)
01162 {
01163 var frame = [self frame],
01164 oldScrollingState = _scrollingState;
01165
01166 _scrollingState = _CPMenuWindowScrollingStateNone;
01167
01168
01169 if (screenLocation.y < CGRectGetMinY(frame) + TOP_MARGIN + SCROLL_INDICATOR_HEIGHT)
01170 _scrollingState = _CPMenuWindowScrollingStateUp;
01171
01172
01173 else if (screenLocation.y > CGRectGetMaxY(frame) - BOTTOM_MARGIN - SCROLL_INDICATOR_HEIGHT)
01174 _scrollingState = _CPMenuWindowScrollingStateDown;
01175
01176 if (_scrollingState != oldScrollingState)
01177
01178 if (_scrollingState == _CPMenuWindowScrollingStateNone)
01179 [CPEvent stopPeriodicEvents];
01180
01181 else if (oldScrollingState == _CPMenuWindowScrollingStateNone)
01182 [CPEvent startPeriodicEventsAfterDelay:0.0 withPeriod:0.04];
01183 }
01184
01185 else if (type == CPLeftMouseUp && ([anEvent timestamp] - _startTime > STICKY_TIME_INTERVAL))
01186 {
01187
01188 if (_scrollingState != _CPMenuWindowScrollingStateNone)
01189 [CPEvent stopPeriodicEvents];
01190
01191 [self cancelTracking];
01192 }
01193 }
01194
01195 if (_trackingCanceled)
01196 {
01197
01198 [CPEvent stopPeriodicEvents];
01199
01200 var highlightedItem = [[_menuView menu] highlightedItem];
01201
01202 [menu _highlightItemAtIndex:CPNotFound];
01203
01204
01205 [_menuView setMenu:nil];
01206
01207 [self orderOut:self];
01208
01209 if (_sessionDelegate && _didEndSelector)
01210 objj_msgSend(_sessionDelegate, _didEndSelector, self, highlightedItem);
01211
01212 [[CPNotificationCenter defaultCenter]
01213 postNotificationName:CPMenuDidEndTrackingNotification
01214 object:menu];
01215
01216 var delegate = [menu delegate];
01217
01218 if ([delegate respondsToSelector:@selector(menuDidClose:)])
01219 [delegate menuDidClose:menu];
01220
01221 return;
01222 }
01223
01224 [CPApp setTarget:self selector:@selector(trackEvent:) forNextEventMatchingMask:CPPeriodicMask | CPMouseMovedMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
01225 }
01226
01227 @end
01228
01229
01230
01231
01232 @implementation _CPMenuView : CPView
01233 {
01234 CPArray _menuItemViews;
01235
01236 CPFont _font;
01237 }
01238
01239
01240
01241
01242
01243
01244
01245
01246
01247
01248
01249 - (void)setFont:(CPFont)aFont
01250 {
01251 _font = aFont;
01252 }
01253
01254 - (CGRect)rectForItemAtIndex:(int)anIndex
01255 {
01256 return [_menuItemViews[anIndex == CPNotFound ? 0 : anIndex] frame];
01257 }
01258
01259 - (int)itemIndexAtPoint:(CGPoint)aPoint
01260 {
01261 var index = 0,
01262 count = _menuItemViews.length;
01263
01264 for (; index < count; ++index)
01265 {
01266 var view = _menuItemViews[index];
01267
01268 if ([view isHidden])
01269 continue;
01270
01271 if (CGRectContainsPoint([view frame], aPoint))
01272 return index;
01273 }
01274
01275 return CPNotFound;
01276 }
01277
01278 - (void)setMenu:(CPMenu)aMenu
01279 {
01280 [super setMenu:aMenu];
01281
01282 [_menuItemViews makeObjectsPerformSelector:@selector(removeFromSuperview)];
01283
01284 _menuItemViews = [];
01285
01286 var menu = [self menu];
01287
01288 if (!menu)
01289 return;
01290
01291 var items = [menu itemArray],
01292 index = 0,
01293 count = [items count],
01294 maxWidth = 0,
01295 y = 0,
01296 showsStateColumn = [menu showsStateColumn];
01297
01298 for (; index < count; ++index)
01299 {
01300 var item = items[index],
01301 view = [item _menuItemView];
01302
01303 _menuItemViews.push(view);
01304
01305 if ([item isHidden])
01306 continue;
01307
01308 [view setFont:_font];
01309 [view setShowsStateColumn:showsStateColumn];
01310 [view synchronizeWithMenuItem];
01311
01312 [view setFrameOrigin:CGPointMake(0.0, y)];
01313
01314 [self addSubview:view];
01315
01316 var size = [view minSize],
01317 width = size.width;
01318
01319 if (maxWidth < width)
01320 maxWidth = width;
01321
01322 y += size.height;
01323 }
01324
01325 for (index = 0; index < count; ++index)
01326 {
01327 var view = _menuItemViews[index];
01328
01329 [view setFrameSize:CGSizeMake(maxWidth, CGRectGetHeight([view frame]))];
01330 }
01331
01332 [self setAutoresizesSubviews:NO];
01333 [self setFrameSize:CGSizeMake(maxWidth, y)];
01334 [self setAutoresizesSubviews:YES];
01335 }
01336
01337 @end
01338
01339 var MENUBAR_HEIGHT = 29.0,
01340 MENUBAR_MARGIN = 10.0,
01341 MENUBAR_LEFT_MARGIN = 10.0,
01342 MENUBAR_RIGHT_MARGIN = 10.0;
01343
01344 var _CPMenuBarWindowBackgroundColor = nil,
01345 _CPMenuBarWindowFont = nil;
01346
01347 @implementation _CPMenuBarWindow : CPPanel
01348 {
01349 CPMenu _menu;
01350 CPView _highlightView;
01351 CPArray _menuItemViews;
01352
01353 CPMenuItem _trackingMenuItem;
01354
01355 CPImageView _iconImageView;
01356 CPTextField _titleField;
01357
01358 CPColor _textColor;
01359 CPColor _titleColor;
01360 }
01361
01362 + (void)initialize
01363 {
01364 if (self != [_CPMenuBarWindow class])
01365 return;
01366
01367 var bundle = [CPBundle bundleForClass:self];
01368
01369 _CPMenuBarWindowFont = [CPFont systemFontOfSize:11.0];
01370 }
01371
01372 - (id)init
01373 {
01374 var bridgeWidth = CGRectGetWidth([[CPDOMWindowBridge sharedDOMWindowBridge] contentBounds]);
01375
01376 self = [super initWithContentRect:CGRectMake(0.0, 0.0, bridgeWidth, MENUBAR_HEIGHT) styleMask:CPBorderlessWindowMask];
01377
01378 if (self)
01379 {
01380
01381 [self setLevel:-1];
01382 [self setAutoresizingMask:CPWindowWidthSizable];
01383
01384 var contentView = [self contentView];
01385
01386 [contentView setAutoresizesSubviews:NO];
01387
01388 [self setBecomesKeyOnlyIfNeeded:YES];
01389
01390
01391 _iconImageView = [[CPImageView alloc] initWithFrame:CGRectMake(0.0, 0.0, 16.0, 16.0)];
01392
01393 [contentView addSubview:_iconImageView];
01394
01395 _titleField = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
01396
01397 [_titleField setFont:[CPFont boldSystemFontOfSize:12.0]];
01398 [_titleField setAlignment:CPCenterTextAlignment];
01399
01400 [contentView addSubview:_titleField];
01401 }
01402
01403 return self;
01404 }
01405
01406 - (void)setTitle:(CPString)aTitle
01407 {
01408 #if PLATFORM(DOM)
01409 var bundleName = [[CPBundle mainBundle] objectForInfoDictionaryKey:@"CPBundleName"];
01410
01411 if (![bundleName length])
01412 document.title = aTitle;
01413 else if ([aTitle length])
01414 document.title = aTitle + @" - " + bundleName;
01415 else
01416 document.title = bundleName;
01417 #endif
01418
01419 [_titleField setStringValue:aTitle];
01420 [_titleField sizeToFit];
01421
01422 [self tile];
01423 }
01424
01425 - (void)setIconImage:(CPImage)anImage
01426 {
01427 [_iconImageView setImage:anImage];
01428 [_iconImageView setHidden:anImage == nil];
01429
01430 [self tile];
01431 }
01432
01433 - (void)setIconImageAlphaValue:(float)anAlphaValue
01434 {
01435 [_iconImageView setAlphaValue:anAlphaValue];
01436 }
01437
01438 - (void)setColor:(CPColor)aColor
01439 {
01440 if (!aColor)
01441 {
01442 if (!_CPMenuBarWindowBackgroundColor)
01443 _CPMenuBarWindowBackgroundColor = [CPColor colorWithPatternImage:[[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[_CPMenuBarWindow class]] pathForResource:@"_CPMenuBarWindow/_CPMenuBarWindowBackground.png"] size:CGSizeMake(1.0, 18.0)]];
01444
01445 [[self contentView] setBackgroundColor:_CPMenuBarWindowBackgroundColor];
01446 }
01447 else
01448 [[self contentView] setBackgroundColor:aColor];
01449 }
01450
01451 - (void)setTextColor:(CPColor)aColor
01452 {
01453 if (_textColor == aColor)
01454 return;
01455
01456 _textColor = aColor;
01457
01458 [_menuItemViews makeObjectsPerformSelector:@selector(setTextColor:) withObject:_textColor];
01459 }
01460
01461 - (void)setTitleColor:(CPColor)aColor
01462 {
01463 if (_titleColor == aColor)
01464 return;
01465
01466 _titleColor = aColor;
01467
01468 [_titleField setTextColor:aColor ? aColor : [CPColor blackColor]];
01469 }
01470
01471 - (void)setMenu:(CPMenu)aMenu
01472 {
01473 if (_menu == aMenu)
01474 return;
01475
01476 var defaultCenter = [CPNotificationCenter defaultCenter];
01477
01478 if (_menu)
01479 {
01480 [defaultCenter
01481 removeObserver:self
01482 name:CPMenuDidAddItemNotification
01483 object:_menu];
01484
01485 [defaultCenter
01486 removeObserver:self
01487 name:CPMenuDidChangeItemNotification
01488 object:_menu];
01489
01490 [defaultCenter
01491 removeObserver:self
01492 name:CPMenuDidRemoveItemNotification
01493 object:_menu];
01494
01495 var items = [_menu itemArray],
01496 count = items.length;
01497
01498 while (count--)
01499 [[items[count] _menuItemView] removeFromSuperview];
01500 }
01501
01502 _menu = aMenu;
01503
01504 if (_menu)
01505 {
01506 [defaultCenter
01507 addObserver:self
01508 selector:@selector(menuDidAddItem:)
01509 name:CPMenuDidAddItemNotification
01510 object:_menu];
01511
01512 [defaultCenter
01513 addObserver:self
01514 selector:@selector(menuDidChangeItem:)
01515 name:CPMenuDidChangeItemNotification
01516 object:_menu];
01517
01518 [defaultCenter
01519 addObserver:self
01520 selector:@selector(menuDidRemoveItem:)
01521 name:CPMenuDidRemoveItemNotification
01522 object:_menu];
01523 }
01524
01525 _menuItemViews = [];
01526
01527 var contentView = [self contentView],
01528 items = [_menu itemArray],
01529 count = items.length;
01530
01531 for (index = 0; index < count; ++index)
01532 {
01533 var item = items[index],
01534 menuItemView = [item _menuItemView];
01535
01536 _menuItemViews.push(menuItemView);
01537
01538 [menuItemView setShowsStateColumn:NO];
01539 [menuItemView setBelongsToMenuBar:YES];
01540 [menuItemView setFont:_CPMenuBarWindowFont];
01541 [menuItemView setTextColor:_textColor];
01542 [menuItemView setHidden:[item isHidden]];
01543
01544 [menuItemView synchronizeWithMenuItem];
01545
01546 [contentView addSubview:menuItemView];
01547 }
01548
01549 [self tile];
01550 }
01551
01552 - (void)menuDidChangeItem:(CPNotification)aNotification
01553 {
01554 var menuItem = [_menu itemAtIndex:[[aNotification userInfo] objectForKey:@"CPMenuItemIndex"]],
01555 menuItemView = [menuItem _menuItemView];
01556
01557 [menuItemView setHidden:[menuItem isHidden]];
01558 [menuItemView synchronizeWithMenuItem];
01559
01560 [self tile];
01561 }
01562
01563 - (void)menuDidAddItem:(CPNotification)aNotification
01564 {
01565 var index = [[aNotification userInfo] objectForKey:@"CPMenuItemIndex"],
01566 menuItem = [_menu itemAtIndex:index],
01567 menuItemView = [menuItem _menuItemView];
01568
01569 [_menuItemViews insertObject:menuItemView atIndex:index];
01570
01571 [menuItemView setShowsStateColumn:NO];
01572 [menuItemView setBelongsToMenuBar:YES];
01573 [menuItemView setFont:_CPMenuBarWindowFont];
01574 [menuItemView setTextColor:_textColor];
01575 [menuItemView setHidden:[menuItem isHidden]];
01576
01577 [menuItemView synchronizeWithMenuItem];
01578
01579 [[self contentView] addSubview:menuItemView];
01580
01581 [self tile];
01582 }
01583
01584 - (void)menuDidRemoveItem:(CPNotification)aNotification
01585 {
01586 var index = [[aNotification userInfo] objectForKey:@"CPMenuItemIndex"],
01587 menuItemView = [_menuItemViews objectAtIndex:index];
01588
01589 [_menuItemViews removeObjectAtIndex:index];
01590
01591 [menuItemView removeFromSuperview];
01592
01593 [self tile];
01594 }
01595
01596 - (CGRect)frameForMenuItem:(CPMenuItem)aMenuItem
01597 {
01598 var frame = [[aMenuItem _menuItemView] frame];
01599
01600 frame.origin.x -= 5.0;
01601 frame.origin.y = 0;
01602 frame.size.width += 10.0;
01603 frame.size.height = MENUBAR_HEIGHT;
01604
01605 return frame;
01606 }
01607
01608 - (CPView)menuItemAtPoint:(CGPoint)aPoint
01609 {
01610 var items = [_menu itemArray],
01611 count = items.length;
01612
01613 while (count--)
01614 {
01615 var item = items[count];
01616
01617 if ([item isHidden] || [item isSeparatorItem])
01618 continue;
01619
01620 if (CGRectContainsPoint([self frameForMenuItem:item], aPoint))
01621 return item;
01622 }
01623
01624 return nil;
01625 }
01626
01627 - (void)mouseDown:(CPEvent)anEvent
01628 {
01629 _trackingMenuItem = [self menuItemAtPoint:[anEvent locationInWindow]];
01630
01631 if (![_trackingMenuItem isEnabled])
01632 return;
01633
01634 if ([[_trackingMenuItem _menuItemView] eventOnSubmenu:anEvent])
01635 return [self showMenu:anEvent];
01636
01637 if ([_trackingMenuItem isEnabled])
01638 [self trackEvent:anEvent];
01639 }
01640
01641 - (void)trackEvent:(CPEvent)anEvent
01642 {
01643 var type = [anEvent type];
01644
01645 if (type === CPPeriodic)
01646 return [self showMenu:anEvent];
01647
01648 var frame = [self frameForMenuItem:_trackingMenuItem],
01649 menuItemView = [_trackingMenuItem _menuItemView],
01650 onMenuItemView = CGRectContainsPoint(frame, [anEvent locationInWindow]);
01651
01652 if (type == CPLeftMouseDown)
01653 {
01654 if ([_trackingMenuItem submenu] != nil)
01655 {
01656
01657 if (![_trackingMenuItem action])
01658 return [self showMenu:anEvent];
01659
01660
01661 [CPEvent startPeriodicEventsAfterDelay:0.0 withPeriod:0.5];
01662 }
01663
01664 [menuItemView highlight:onMenuItemView];
01665 }
01666
01667 else if (type == CPLeftMouseDragged)
01668 {
01669 if (!onMenuItemView && [_trackingMenuItem submenu])
01670 return [self showMenu:anEvent];
01671
01672 [menuItemView highlight:onMenuItemView];
01673 }
01674
01675 else
01676 {
01677 [CPEvent stopPeriodicEvents];
01678
01679 [menuItemView highlight:NO];
01680
01681 if (onMenuItemView)
01682 [CPApp sendAction:[_trackingMenuItem action] to:[_trackingMenuItem target] from:nil];
01683
01684 return;
01685 }
01686
01687 [CPApp setTarget:self selector:@selector(trackEvent:) forNextEventMatchingMask:CPPeriodicMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
01688 }
01689
01690 - (void)showMenu:(CPEvent)anEvent
01691 {
01692 [CPEvent stopPeriodicEvents];
01693
01694 var frame = [self frameForMenuItem:_trackingMenuItem],
01695 menuItemView = [_trackingMenuItem _menuItemView];
01696
01697 if (!_highlightView)
01698 {
01699 _highlightView = [[CPView alloc] initWithFrame:frame];
01700
01701 [_highlightView setBackgroundColor:[CPColor colorWithCalibratedRed:81.0 / 255.0 green:83.0 / 255.0 blue:109.0 / 255.0 alpha:1.0]];
01702 }
01703 else
01704 [_highlightView setFrame:frame];
01705
01706 [[self contentView] addSubview:_highlightView positioned:CPWindowBelow relativeTo:menuItemView];
01707
01708 [menuItemView activate:YES];
01709
01710 var submenu = [_trackingMenuItem submenu];
01711
01712 [[CPNotificationCenter defaultCenter]
01713 addObserver:self
01714 selector:@selector(menuDidEndTracking:)
01715 name:CPMenuDidEndTrackingNotification
01716 object:submenu];
01717
01718 [CPMenu _popUpContextMenu:submenu
01719 withEvent:[CPEvent mouseEventWithType:CPLeftMouseDown location:CGPointMake(CGRectGetMinX(frame), CGRectGetMaxY(frame))
01720 modifierFlags:[anEvent modifierFlags] timestamp:[anEvent timestamp] windowNumber:[self windowNumber]
01721 context:nil eventNumber:0 clickCount:[anEvent clickCount] pressure:[anEvent pressure]]
01722 forView:[self contentView]
01723 withFont:nil
01724 forMenuBar:YES];
01725 }
01726
01727 - (void)menuDidEndTracking:(CPNotification)aNotification
01728 {
01729 [_highlightView removeFromSuperview];
01730
01731 [[_trackingMenuItem _menuItemView] activate:NO];
01732
01733 [[CPNotificationCenter defaultCenter]
01734 removeObserver:self
01735 name:CPMenuDidEndTrackingNotification
01736 object:[aNotification object]];
01737 }
01738
01739 - (void)tile
01740 {
01741 var items = [_menu itemArray],
01742 index = 0,
01743 count = items.length,
01744
01745 x = MENUBAR_LEFT_MARGIN,
01746 y = 0.0,
01747 isLeftAligned = YES;
01748
01749 for (; index < count; ++index)
01750 {
01751 var item = items[index];
01752
01753 if ([item isSeparatorItem])
01754 {
01755 x = CGRectGetWidth([self frame]) - MENUBAR_RIGHT_MARGIN;
01756 isLeftAligned = NO;
01757
01758 continue;
01759 }
01760
01761 if ([item isHidden])
01762 continue;
01763
01764 var menuItemView = [item _menuItemView],
01765 frame = [menuItemView frame];
01766
01767 if (isLeftAligned)
01768 {
01769 [menuItemView setFrameOrigin:CGPointMake(x, (MENUBAR_HEIGHT - 1.0 - CGRectGetHeight(frame)) / 2.0)];
01770
01771 x += CGRectGetWidth([menuItemView frame]) + MENUBAR_MARGIN;
01772 }
01773 else
01774 {
01775 [menuItemView setFrameOrigin:CGPointMake(x - CGRectGetWidth(frame), (MENUBAR_HEIGHT - 1.0 - CGRectGetHeight(frame)) / 2.0)];
01776
01777 x = CGRectGetMinX([menuItemView frame]) - MENUBAR_MARGIN;
01778 }
01779 }
01780
01781 var bounds = [[self contentView] bounds],
01782 titleFrame = [_titleField frame];
01783
01784 if ([_iconImageView isHidden])
01785 [_titleField setFrameOrigin:CGPointMake((CGRectGetWidth(bounds) - CGRectGetWidth(titleFrame)) / 2.0, (CGRectGetHeight(bounds) - CGRectGetHeight(titleFrame)) / 2.0)];
01786 else
01787 {
01788 var iconFrame = [_iconImageView frame],
01789 iconWidth = CGRectGetWidth(iconFrame),
01790 totalWidth = iconWidth + CGRectGetWidth(titleFrame);
01791
01792 [_iconImageView setFrameOrigin:CGPointMake((CGRectGetWidth(bounds) - totalWidth) / 2.0, (CGRectGetHeight(bounds) - CGRectGetHeight(iconFrame)) / 2.0)];
01793 [_titleField setFrameOrigin:CGPointMake((CGRectGetWidth(bounds) - totalWidth) / 2.0 + iconWidth, (CGRectGetHeight(bounds) - CGRectGetHeight(titleFrame)) / 2.0)];
01794 }
01795 }
01796
01797 - (void)setFrameSize:(CGSize)aSize
01798 {
01799 [super setFrameSize:aSize];
01800
01801 [self tile];
01802 }
01803
01804 @end