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