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 "_CPMenuManager.j"
00029 @import "CPApplication.j"
00030 @import "CPClipView.j"
00031 @import "CPMenuItem.j"
00032 @import "CPPanel.j"
00033
00034 #include "../CoreGraphics/CGGeometry.h"
00035 #include "../Platform/Platform.h"
00036
00037
00038 CPMenuDidAddItemNotification = @"CPMenuDidAddItemNotification";
00039 CPMenuDidChangeItemNotification = @"CPMenuDidChangeItemNotification";
00040 CPMenuDidRemoveItemNotification = @"CPMenuDidRemoveItemNotification";
00041
00042 CPMenuDidEndTrackingNotification = @"CPMenuDidEndTrackingNotification";
00043
00044 var MENUBAR_HEIGHT = 28.0;
00045
00046 var _CPMenuBarVisible = NO,
00047 _CPMenuBarTitle = @"",
00048 _CPMenuBarIconImage = nil,
00049 _CPMenuBarIconImageAlphaValue = 1.0,
00050 _CPMenuBarAttributes = nil,
00051 _CPMenuBarSharedWindow = nil;
00052
00060 @implementation CPMenu : CPObject
00061 {
00062 CPMenu _supermenu;
00063
00064 CPString _title;
00065 CPString _name;
00066
00067 CPFont _font;
00068
00069 float _minimumWidth;
00070
00071 CPMutableArray _items;
00072
00073 BOOL _autoenablesItems;
00074 BOOL _showsStateColumn;
00075
00076 id _delegate;
00077
00078 CPMenuItem _highlightedIndex;
00079 _CPMenuWindow _menuWindow;
00080 }
00081
00082
00083
00084 + (void)initialize
00085 {
00086 [[self class] setMenuBarAttributes:[CPDictionary dictionary]];
00087 }
00088
00089 + (BOOL)menuBarVisible
00090 {
00091 return _CPMenuBarVisible;
00092 }
00093
00094 + (void)setMenuBarVisible:(BOOL)menuBarShouldBeVisible
00095 {
00096 if (_CPMenuBarVisible === menuBarShouldBeVisible)
00097 return;
00098
00099 _CPMenuBarVisible = menuBarShouldBeVisible;
00100
00101 if ([CPPlatform supportsNativeMainMenu])
00102 return;
00103
00104 if (menuBarShouldBeVisible)
00105 {
00106 if (!_CPMenuBarSharedWindow)
00107 _CPMenuBarSharedWindow = [[_CPMenuBarWindow alloc] init];
00108
00109 [_CPMenuBarSharedWindow setMenu:[CPApp mainMenu]];
00110
00111 [_CPMenuBarSharedWindow setTitle:_CPMenuBarTitle];
00112 [_CPMenuBarSharedWindow setIconImage:_CPMenuBarIconImage];
00113 [_CPMenuBarSharedWindow setIconImageAlphaValue:_CPMenuBarIconImageAlphaValue];
00114
00115 [_CPMenuBarSharedWindow setColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarBackgroundColor"]];
00116 [_CPMenuBarSharedWindow setTextColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarTextColor"]];
00117 [_CPMenuBarSharedWindow setTitleColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarTitleColor"]];
00118 [_CPMenuBarSharedWindow setTextShadowColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarTextShadowColor"]];
00119 [_CPMenuBarSharedWindow setTitleShadowColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarTitleShadowColor"]];
00120 [_CPMenuBarSharedWindow setHighlightColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarHighlightColor"]];
00121 [_CPMenuBarSharedWindow setHighlightTextColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarHighlightTextColor"]];
00122 [_CPMenuBarSharedWindow setHighlightTextShadowColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarHighlightTextShadowColor"]];
00123
00124 [_CPMenuBarSharedWindow orderFront:self];
00125 }
00126 else
00127 [_CPMenuBarSharedWindow orderOut:self];
00128
00129
00130 #if PLATFORM(DOM)
00131 [[CPPlatformWindow primaryPlatformWindow] resizeEvent:nil];
00132 #endif
00133 }
00134
00135 + (void)setMenuBarTitle:(CPString)aTitle
00136 {
00137 _CPMenuBarTitle = aTitle;
00138 [_CPMenuBarSharedWindow setTitle:_CPMenuBarTitle];
00139 }
00140
00141 + (CPString)menuBarTitle
00142 {
00143 return _CPMenuBarTitle;
00144 }
00145
00146 + (void)setMenuBarIconImage:(CPImage)anImage
00147 {
00148 _CPMenuBarImage = anImage;
00149 [_CPMenuBarSharedWindow setIconImage:anImage];
00150 }
00151
00152 + (CPImage)menuBarIconImage
00153 {
00154 return _CPMenuBarImage;
00155 }
00156
00157
00158 + (void)setMenuBarAttributes:(CPDictionary)attributes
00159 {
00160 if (_CPMenuBarAttributes == attributes)
00161 return;
00162
00163 _CPMenuBarAttributes = [attributes copy];
00164
00165 var textColor = [attributes objectForKey:@"CPMenuBarTextColor"],
00166 titleColor = [attributes objectForKey:@"CPMenuBarTitleColor"],
00167 textShadowColor = [attributes objectForKey:@"CPMenuBarTextShadowColor"],
00168 titleShadowColor = [attributes objectForKey:@"CPMenuBarTitleShadowColor"],
00169 highlightColor = [attributes objectForKey:@"CPMenuBarHighlightColor"],
00170 highlightTextColor = [attributes objectForKey:@"CPMenuBarHighlightTextColor"],
00171 highlightTextShadowColor = [attributes objectForKey:@"CPMenuBarHighlightTextShadowColor"];
00172
00173 if (!textColor && titleColor)
00174 [_CPMenuBarAttributes setObject:titleColor forKey:@"CPMenuBarTextColor"];
00175
00176 else if (textColor && !titleColor)
00177 [_CPMenuBarAttributes setObject:textColor forKey:@"CPMenuBarTitleColor"];
00178
00179 else if (!textColor && !titleColor)
00180 {
00181 [_CPMenuBarAttributes setObject:[CPColor colorWithRed:0.051 green:0.2 blue:0.275 alpha:1.0] forKey:@"CPMenuBarTextColor"];
00182 [_CPMenuBarAttributes setObject:[CPColor colorWithRed:0.051 green:0.2 blue:0.275 alpha:1.0] forKey:@"CPMenuBarTitleColor"];
00183 }
00184
00185 if (!textShadowColor && titleShadowColor)
00186 [_CPMenuBarAttributes setObject:titleShadowColor forKey:@"CPMenuBarTextShadowColor"];
00187
00188 else if (textShadowColor && !titleShadowColor)
00189 [_CPMenuBarAttributes setObject:textShadowColor forKey:@"CPMenuBarTitleShadowColor"];
00190
00191 else if (!textShadowColor && !titleShadowColor)
00192 {
00193 [_CPMenuBarAttributes setObject:[CPColor whiteColor] forKey:@"CPMenuBarTextShadowColor"];
00194 [_CPMenuBarAttributes setObject:[CPColor whiteColor] forKey:@"CPMenuBarTitleShadowColor"];
00195 }
00196
00197 if (!highlightColor)
00198 [_CPMenuBarAttributes setObject:[CPColor colorWithCalibratedRed:94.0/255.0 green:130.0/255.0 blue:186.0/255.0 alpha:1.0] forKey:@"CPMenuBarHighlightColor"];
00199
00200 if (!highlightTextColor)
00201 [_CPMenuBarAttributes setObject:[CPColor whiteColor] forKey:@"CPMenuBarHighlightTextColor"];
00202
00203 if (!highlightTextShadowColor)
00204 [_CPMenuBarAttributes setObject:[CPColor blackColor] forKey:@"CPMenuBarHighlightTextShadowColor"];
00205
00206 if (_CPMenuBarSharedWindow)
00207 {
00208 [_CPMenuBarSharedWindow setColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarBackgroundColor"]];
00209 [_CPMenuBarSharedWindow setTextColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarTextColor"]];
00210 [_CPMenuBarSharedWindow setTitleColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarTitleColor"]];
00211 [_CPMenuBarSharedWindow setTextShadowColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarTextShadowColor"]];
00212 [_CPMenuBarSharedWindow setTitleShadowColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarTitleShadowColor"]];
00213 [_CPMenuBarSharedWindow setHighlightColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarHighlightColor"]];
00214 [_CPMenuBarSharedWindow setHighlightTextColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarHighlightTextColor"]];
00215 [_CPMenuBarSharedWindow setHighlightTextShadowColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarHighlightTextShadowColor"]];
00216 }
00217 }
00218
00219 + (CPDictionary)menuBarAttributes
00220 {
00221 return _CPMenuBarAttributes;
00222 }
00223
00224 + (void)_setMenuBarIconImageAlphaValue:(float)anAlphaValue
00225 {
00226 _CPMenuBarIconImageAlphaValue = anAlphaValue;
00227 [_CPMenuBarSharedWindow setIconImageAlphaValue:anAlphaValue];
00228 }
00229
00230 - (float)menuBarHeight
00231 {
00232 if (self === [CPApp mainMenu])
00233 return MENUBAR_HEIGHT;
00234
00235 return 0.0;
00236 }
00237
00238 + (float)menuBarHeight
00239 {
00240 return MENUBAR_HEIGHT;
00241 }
00242
00243
00249 - (id)initWithTitle:(CPString)aTitle
00250 {
00251 self = [super init];
00252
00253 if (self)
00254 {
00255 _title = aTitle;
00256 _items = [];
00257
00258 _autoenablesItems = YES;
00259 _showsStateColumn = YES;
00260
00261 [self setMinimumWidth:0];
00262 }
00263
00264 return self;
00265 }
00266
00267 - (id)init
00268 {
00269 return [self initWithTitle:@""];
00270 }
00271
00272
00278 - (void)insertItem:(CPMenuItem)aMenuItem atIndex:(unsigned)anIndex
00279 {
00280 var menu = [aMenuItem menu];
00281
00282 if (menu)
00283 if (menu !== self)
00284 [CPException raise:CPInternalInconsistencyException reason:@"Attempted to insert item into menu that was already in another menu."];
00285 else
00286 return;
00287
00288 [aMenuItem setMenu:self];
00289 [_items insertObject:aMenuItem atIndex:anIndex];
00290
00291 [[CPNotificationCenter defaultCenter]
00292 postNotificationName:CPMenuDidAddItemNotification
00293 object:self
00294 userInfo:[CPDictionary dictionaryWithObject:anIndex forKey:@"CPMenuItemIndex"]];
00295
00296 }
00297
00306 - (CPMenuItem)insertItemWithTitle:(CPString)aTitle action:(SEL)anAction keyEquivalent:(CPString)aKeyEquivalent atIndex:(unsigned)anIndex
00307 {
00308 var item = [[CPMenuItem alloc] initWithTitle:aTitle action:anAction keyEquivalent:aKeyEquivalent];
00309
00310 [self insertItem:item atIndex:anIndex];
00311
00312 return item;
00313 }
00314
00319 - (void)addItem:(CPMenuItem)aMenuItem
00320 {
00321 [self insertItem:aMenuItem atIndex:[_items count]];
00322 }
00323
00332 - (CPMenuItem)addItemWithTitle:(CPString)aTitle action:(SEL)anAction keyEquivalent:(CPString)aKeyEquivalent
00333 {
00334 return [self insertItemWithTitle:aTitle action:anAction keyEquivalent:aKeyEquivalent atIndex:[_items count]];
00335 }
00336
00341 - (void)removeItem:(CPMenuItem)aMenuItem
00342 {
00343 [self removeItemAtIndex:[_items indexOfObjectIdenticalTo:aMenuItem]];
00344 }
00345
00350 - (void)removeItemAtIndex:(unsigned)anIndex
00351 {
00352 if (anIndex < 0 || anIndex >= _items.length)
00353 return;
00354
00355 [_items[anIndex] setMenu:nil];
00356 [_items removeObjectAtIndex:anIndex];
00357
00358 [[CPNotificationCenter defaultCenter]
00359 postNotificationName:CPMenuDidRemoveItemNotification
00360 object:self
00361 userInfo:[CPDictionary dictionaryWithObject:anIndex forKey:@"CPMenuItemIndex"]];
00362 }
00363
00368 - (void)itemChanged:(CPMenuItem)aMenuItem
00369 {
00370 if ([aMenuItem menu] != self)
00371 return;
00372
00373 [[CPNotificationCenter defaultCenter]
00374 postNotificationName:CPMenuDidChangeItemNotification
00375 object:self
00376 userInfo:[CPDictionary dictionaryWithObject:[_items indexOfObjectIdenticalTo:aMenuItem] forKey:@"CPMenuItemIndex"]];
00377 }
00378
00379
00385 - (CPMenuItem)itemWithTag:(int)aTag
00386 {
00387 var index = [self indexOfItemWithTag:aTag];
00388
00389 if (index == CPNotFound)
00390 return nil;
00391
00392 return _items[index];
00393 }
00394
00400 - (CPMenuItem)itemWithTitle:(CPString)aTitle
00401 {
00402 var index = [self indexOfItemWithTitle:aTitle];
00403
00404 if (index == CPNotFound)
00405 return nil;
00406
00407 return _items[index];
00408 }
00409
00414 - (CPMenuItem)itemAtIndex:(int)anIndex
00415 {
00416 return [_items objectAtIndex:anIndex];
00417 }
00418
00422 - (unsigned)numberOfItems
00423 {
00424 return [_items count];
00425 }
00426
00430 - (CPArray)itemArray
00431 {
00432 return _items;
00433 }
00434
00435
00441 - (int)indexOfItem:(CPMenuItem)aMenuItem
00442 {
00443 if ([aMenuItem menu] !== self)
00444 return CPNotFound;
00445
00446 return [_items indexOfObjectIdenticalTo:aMenuItem];
00447 }
00448
00454 - (int)indexOfItemWithTitle:(CPString)aTitle
00455 {
00456 var index = 0,
00457 count = _items.length;
00458
00459 for (; index < count; ++index)
00460 if ([_items[index] title] === aTitle)
00461 return index;
00462
00463 return CPNotFound;
00464 }
00465
00471 - (int)indexOfItemWithTag:(int)aTag
00472 {
00473 var index = 0,
00474 count = _items.length;
00475
00476 for (; index < count; ++index)
00477 if ([_items[index] tag] == aTag)
00478 return index;
00479
00480 return CPNotFound;
00481 }
00482
00489 - (int)indexOfItemWithTarget:(id)aTarget andAction:(SEL)anAction
00490 {
00491 var index = 0,
00492 count = _items.length;
00493
00494 for (; index < count; ++index)
00495 {
00496 var item = _items[index];
00497
00498 if ([item target] == aTarget && (!anAction || [item action] == anAction))
00499 return index;
00500 }
00501
00502 return CPNotFound;
00503 }
00504
00510 - (int)indexOfItemWithRepresentedObject:(id)anObject
00511 {
00512 var index = 0,
00513 count = _items.length;
00514
00515 for (; index < count; ++index)
00516 if ([[_items[index] representedObject] isEqual:anObject])
00517 return index;
00518
00519 return CPNotFound;
00520 }
00521
00527 - (int)indexOfItemWithSubmenu:(CPMenu)aMenu
00528 {
00529 var index = 0,
00530 count = _items.length;
00531
00532 for (; index < count; ++index)
00533 if ([_items[index] submenu] == aMenu)
00534 return index;
00535
00536 return CPNotFound;
00537 }
00538
00539
00545 - (void)setSubmenu:(CPMenu)aMenu forItem:(CPMenuItem)aMenuItem
00546 {
00547 [aMenuItem setTarget:aMenuItem];
00548 [aMenuItem setAction:@selector(submenuAction:)];
00549
00550 [aMenuItem setSubmenu:aMenu];
00551 }
00552
00559 - (void)submenuAction:(id)aSender
00560 {
00561
00562 }
00563
00567 - (CPMenu)supermenu
00568 {
00569 return _supermenu;
00570 }
00571
00576 - (void)setSupermenu:(CPMenu)aMenu
00577 {
00578 _supermenu = aMenu;
00579 }
00580
00585 - (BOOL)isTornOff
00586 {
00587 return !_supermenu || self == [CPApp mainMenu];
00588 }
00589
00590
00595 - (void)setAutoenablesItems:(BOOL)aFlag
00596 {
00597 _autoenablesItems = aFlag;
00598 }
00599
00603 - (BOOL)autoenablesItems
00604 {
00605 return _autoenablesItems;
00606 }
00607
00611 - (void)update
00612 {
00613
00614 }
00615
00616
00621 - (void)setTitle:(CPString)aTitle
00622 {
00623 _title = aTitle;
00624 }
00625
00629 - (CPString)title
00630 {
00631 return _title;
00632 }
00633
00634 - (void)setMinimumWidth:(float)aMinimumWidth
00635 {
00636 _minimumWidth = aMinimumWidth;
00637 }
00638
00639 - (float)minimumWidth
00640 {
00641 return _minimumWidth;
00642 }
00643
00644 - (void)_performActionOfHighlightedItemChain
00645 {
00646 var highlightedItem = [self highlightedItem];
00647
00648 while ([highlightedItem submenu] && [highlightedItem action] === @selector(submenuAction:))
00649 highlightedItem = [[highlightedItem submenu] highlightedItem];
00650
00651
00652
00653
00654 if (highlightedItem && [highlightedItem isEnabled])
00655 [CPApp sendAction:[highlightedItem action] to:[highlightedItem target] from:highlightedItem];
00656 }
00657
00658
00659 + (CGRect)_constraintRectForView:(CPView)aView
00660 {
00661 if ([CPPlatform isBrowser])
00662 return CGRectInset([[[aView window] platformWindow] contentBounds], 5.0, 5.0);
00663
00664 return CGRectInset([[[aView window] screen] visibleFrame], 5.0, 5.0);
00665 }
00666
00667 - (void)popUpMenuPositioningItem:(CPMenuItem)anItem atLocation:(CGPoint)aLocation inView:(CPView)aView callback:(Function)aCallback
00668 {
00669 [self _popUpMenuPositioningItem:anItem
00670 atLocation:aLocation
00671 topY:aLocation.y
00672 bottomY:aLocation.y
00673 inView:aView
00674 callback:aCallback];
00675 }
00676
00677 - (void)_popUpMenuPositioningItem:(CPMenuItem)anItem atLocation:(CGPoint)aLocation topY:(float)aTopY bottomY:(float)aBottomY inView:(CPView)aView callback:(Function)aCallback
00678 {
00679 var itemIndex = 0;
00680
00681 if (anItem)
00682 {
00683 itemIndex = [self indexOfItem:anItem];
00684
00685 if (itemIndex === CPNotFound)
00686 throw "In call to popUpMenuPositioningItem:atLocation:inView:callback:, menu item " +
00687 anItem + " is not present in menu " + self;
00688 }
00689
00690 var theWindow = [aView window];
00691
00692 if (aView && !theWindow)
00693 throw "In call to popUpMenuPositioningItem:atLocation:inView:callback:, view is not in any window.";
00694
00695 var delegate = [self delegate];
00696
00697 if ([delegate respondsToSelector:@selector(menuWillOpen:)])
00698 [delegate menuWillOpen:aMenu];
00699
00700
00701 if (aView)
00702 aLocation = [theWindow convertBaseToGlobal:[aView convertPoint:aLocation toView:nil]];
00703
00704
00705 var menuWindow = [_CPMenuWindow menuWindowWithMenu:self font:[self font]];
00706
00707 [menuWindow setBackgroundStyle:_CPMenuWindowPopUpBackgroundStyle];
00708
00709 if (anItem)
00710
00711
00712 aLocation.y -= [menuWindow deltaYForItemAtIndex:itemIndex];
00713
00714
00715 var constraintRect = [CPMenu _constraintRectForView:aView];
00716
00717 [menuWindow setFrameOrigin:aLocation];
00718 [menuWindow setConstraintRect:constraintRect];
00719
00720
00721 if (![menuWindow hasMinimumNumberOfVisibleItems])
00722 {
00723 var unconstrainedFrame = [menuWindow unconstrainedFrame],
00724 unconstrainedY = CGRectGetMinY(unconstrainedFrame);
00725
00726
00727 if (unconstrainedY >= CGRectGetMaxY(constraintRect) || [menuWindow canScrollDown])
00728 {
00729
00730 if (aView)
00731 aTopY = [theWindow convertBaseToGlobal:[aView convertPoint:CGPointMake(0.0, aTopY) toView:nil]].y;
00732
00733 unconstrainedFrame.origin.y = MIN(CGRectGetMaxY(constraintRect), aTopY) - CGRectGetHeight(unconstrainedFrame);
00734 }
00735
00736
00737 else if (unconstrainedY < CGRectGetMinY(constraintRect) || [menuWindow canScrollUp])
00738 {
00739
00740 if (aView)
00741 aBottomY = [theWindow convertBaseToGlobal:[aView convertPoint:CGPointMake(0.0, aBottomY) toView:nil]].y;
00742
00743 unconstrainedFrame.origin.y = MAX(CGRectGetMinY(constraintRect), aBottomY);
00744 }
00745
00746 [menuWindow setFrameOrigin:CGRectIntersection(unconstrainedFrame, constraintRect).origin];
00747 }
00748
00749
00750 [menuWindow orderFront:self];
00751
00752
00753 [[_CPMenuManager sharedMenuManager]
00754 beginTracking:[CPApp currentEvent]
00755 menuContainer:menuWindow
00756 constraintRect:constraintRect
00757 callback:[CPMenu trackingCallbackWithCallback:aCallback]];
00758 }
00759
00760 + (Function)trackingCallbackWithCallback:(Function)aCallback
00761 {
00762 return function(aMenuWindow, aMenu)
00763 {
00764 [aMenuWindow setMenu:nil];
00765 [aMenuWindow orderOut:self];
00766
00767 [_CPMenuWindow poolMenuWindow:aMenuWindow];
00768
00769 if (aCallback)
00770 aCallback(aMenu);
00771
00772 [aMenu _performActionOfHighlightedItemChain];
00773 }
00774 }
00775
00776 + (void)popUpContextMenu:(CPMenu)aMenu withEvent:(CPEvent)anEvent forView:(CPView)aView
00777 {
00778 [self popUpContextMenu:aMenu withEvent:anEvent forView:aView withFont:nil];
00779 }
00780
00781 + (void)popUpContextMenu:(CPMenu)aMenu withEvent:(CPEvent)anEvent forView:(CPView)aView withFont:(CPFont)aFont
00782 {
00783 var delegate = [aMenu delegate];
00784
00785 if ([delegate respondsToSelector:@selector(menuWillOpen:)])
00786 [delegate menuWillOpen:aMenu];
00787
00788 if (!aFont)
00789 aFont = [CPFont systemFontOfSize:12.0];
00790
00791 var theWindow = [aView window],
00792 menuWindow = [_CPMenuWindow menuWindowWithMenu:aMenu font:aFont];
00793
00794 [menuWindow setBackgroundStyle:_CPMenuWindowPopUpBackgroundStyle];
00795
00796 var constraintRect = [CPMenu _constraintRectForView:aView],
00797 aLocation = [[anEvent window] convertBaseToGlobal:[anEvent locationInWindow]];
00798
00799 [menuWindow setConstraintRect:constraintRect];
00800 [menuWindow setFrameOrigin:aLocation];
00801
00802
00803 if (![menuWindow hasMinimumNumberOfVisibleItems])
00804 {
00805 var unconstrainedFrame = [menuWindow unconstrainedFrame],
00806 unconstrainedY = CGRectGetMinY(unconstrainedFrame);
00807
00808
00809 if (unconstrainedY >= CGRectGetMaxY(constraintRect) || [menuWindow canScrollDown])
00810 unconstrainedFrame.origin.y = MIN(CGRectGetMaxY(constraintRect), aLocation.y) - CGRectGetHeight(unconstrainedFrame);
00811
00812
00813 else if (unconstrainedY < CGRectGetMinY(constraintRect) || [menuWindow canScrollUp])
00814 unconstrainedFrame.origin.y = MAX(CGRectGetMinY(constraintRect), aLocation.y);
00815
00816 [menuWindow setFrameOrigin:CGRectIntersection(unconstrainedFrame, constraintRect).origin];
00817 }
00818
00819 [menuWindow orderFront:self];
00820
00821 [[_CPMenuManager sharedMenuManager]
00822 beginTracking:anEvent
00823 menuContainer:menuWindow
00824 constraintRect:[CPMenu _constraintRectForView:aView]
00825 callback:[CPMenu trackingCallbackWithCallback:nil]];
00826 }
00827
00828
00833 - (void)setShowsStateColumn:(BOOL)shouldShowStateColumn
00834 {
00835 _showsStateColumn = shouldShowStateColumn;
00836 }
00837
00841 - (BOOL)showsStateColumn
00842 {
00843 return _showsStateColumn;
00844 }
00845
00846
00851 - (CPMenuItem)highlightedItem
00852 {
00853 return _highlightedIndex >= 0 ? _items[_highlightedIndex] : nil;
00854 }
00855
00856
00857
00858 - (void)setDelegate:(id)aDelegate
00859 {
00860 _delegate = aDelegate;
00861 }
00862
00863 - (id)delegate
00864 {
00865 return _delegate;
00866 }
00867
00868
00872 - (void)cancelTracking
00873 {
00874 [[CPRunLoop currentRunLoop] performSelector:@selector(_fireCancelTrackingEvent) target:self argument:nil order:0 modes:[CPDefaultRunLoopMode]];
00875 }
00876
00877 - (void)_fireCancelTrackingEvent
00878 {
00879 [CPApp sendEvent:[CPEvent
00880 otherEventWithType:CPAppKitDefined
00881 location:_CGPointMakeZero()
00882 modifierFlags:0
00883 timestamp:0
00884 windowNumber:0
00885 context:0
00886 subtype:0
00887 data1:0
00888 data2:0]];
00889
00890
00891
00892
00893
00894
00895 [_CPDisplayServer run];
00896 }
00897
00898
00899 - (void)_setMenuWindow:(_CPMenuWindow)aMenuWindow
00900 {
00901 _menuWindow = aMenuWindow;
00902 }
00903
00904 - (void)setFont:(CPFont)aFont
00905 {
00906 _font = aFont;
00907 }
00908
00909 - (CPFont)font
00910 {
00911 return _font;
00912 }
00913
00920 - (BOOL)performKeyEquivalent:(CPEvent)anEvent
00921 {
00922 if (_autoenablesItems)
00923 [self update];
00924
00925 var index = 0,
00926 count = _items.length,
00927 characters = [anEvent charactersIgnoringModifiers],
00928 modifierFlags = [anEvent modifierFlags];
00929
00930 for(; index < count; ++index)
00931 {
00932 var item = _items[index],
00933 modifierMask = [item keyEquivalentModifierMask];
00934
00935 if ([item keyEquivalent] === [[item keyEquivalent] uppercaseString])
00936 modifierMask |= CPShiftKeyMask;
00937
00938 if (CPBrowserIsOperatingSystem(CPWindowsOperatingSystem) && (modifierMask & CPCommandKeyMask))
00939 {
00940 modifierMask |= CPControlKeyMask;
00941 modifierMask &= ~CPCommandKeyMask;
00942 }
00943
00944 if ((modifierFlags & (CPShiftKeyMask | CPAlternateKeyMask | CPCommandKeyMask | CPControlKeyMask)) == modifierMask &&
00945 [characters caseInsensitiveCompare:[item keyEquivalent]] == CPOrderedSame)
00946 {
00947 if ([item isEnabled])
00948 [self performActionForItemAtIndex:index];
00949 else
00950 {
00951
00952 }
00953
00954 return YES;
00955 }
00956
00957 if ([[item submenu] performKeyEquivalent:anEvent])
00958 return YES;
00959 }
00960
00961 return NO;
00962 }
00963
00964
00969 - (void)performActionForItemAtIndex:(unsigned)anIndex
00970 {
00971 var item = _items[anIndex];
00972
00973 [CPApp sendAction:[item action] to:[item target] from:item];
00974 }
00975
00976
00977
00978
00979
00980 - (BOOL)_itemIsHighlighted:(CPMenuItem)aMenuItem
00981 {
00982 return _items[_highlightedIndex] == aMenuItem;
00983 }
00984
00985
00986
00987
00988 - (void)_highlightItemAtIndex:(int)anIndex
00989 {
00990 if (_highlightedIndex === anIndex)
00991 return;
00992
00993 if (_highlightedIndex !== CPNotFound)
00994 [[_items[_highlightedIndex] _menuItemView] highlight:NO];
00995
00996 _highlightedIndex = anIndex;
00997
00998 if (_highlightedIndex !== CPNotFound)
00999 [[_items[_highlightedIndex] _menuItemView] highlight:YES];
01000 }
01001
01002 - (void)_setMenuName:(CPString)aName
01003 {
01004 if (_name === aName)
01005 return;
01006
01007 _name = aName;
01008
01009 if (_name === @"CPMainMenu")
01010 [CPApp setMainMenu:self];
01011 }
01012
01013 - (CPString)_menuName
01014 {
01015 return _name;
01016 }
01017
01018 - (void)awakeFromCib
01019 {
01020 if (_name === @"_CPMainMenu")
01021 {
01022 [self _setMenuName:@"CPMainMenu"];
01023 [CPMenu setMenuBarVisible:YES];
01024 }
01025 }
01026
01027 - (void)_menuWithName:(CPString)aName
01028 {
01029 if (aName === _name)
01030 return self;
01031
01032 for (var i = 0, count = [_items count]; i < count; i++)
01033 {
01034 var menu = [[_items[i] submenu] _menuWithName:aName];
01035
01036 if (menu)
01037 return menu;
01038 }
01039
01040 return nil;
01041 }
01042
01043 @end
01044
01045
01046 var CPMenuTitleKey = @"CPMenuTitleKey",
01047 CPMenuNameKey = @"CPMenuNameKey",
01048 CPMenuItemsKey = @"CPMenuItemsKey",
01049 CPMenuShowsStateColumnKey = @"CPMenuShowsStateColumnKey";
01050
01051 @implementation CPMenu (CPCoding)
01052
01058 - (id)initWithCoder:(CPCoder)aCoder
01059 {
01060 self = [super init];
01061
01062 if (self)
01063 {
01064 _title = [aCoder decodeObjectForKey:CPMenuTitleKey];
01065 _items = [aCoder decodeObjectForKey:CPMenuItemsKey];
01066
01067 [self _setMenuName:[aCoder decodeObjectForKey:CPMenuNameKey]];
01068
01069 _showsStateColumn = ![aCoder containsValueForKey:CPMenuShowsStateColumnKey] || [aCoder decodeBoolForKey:CPMenuShowsStateColumnKey];
01070
01071 [self setMinimumWidth:0];
01072 }
01073
01074 return self;
01075 }
01076
01081 - (void)encodeWithCoder:(CPCoder)aCoder
01082 {
01083 [aCoder encodeObject:_title forKey:CPMenuTitleKey];
01084
01085 if (_name)
01086 [aCoder encodeObject:_name forKey:CPMenuNameKey];
01087
01088 [aCoder encodeObject:_items forKey:CPMenuItemsKey];
01089
01090 if (!_showsStateColumn)
01091 [aCoder encodeBool:_showsStateColumn forKey:CPMenuShowsStateColumnKey];
01092 }
01093
01094 @end
01095
01096 @import "_CPMenuBarWindow.j"
01097 @import "_CPMenuWindow.j"
01098