29 var CPMenuItemStringRepresentationDictionary = @{
85 unsigned _keyEquivalentModifierMask;
87 int _mnemonicLocation;
90 int _indentationLevel;
93 id _representedObject;
98 _CPMenuItemView _menuItemView;
101 + (Class)_binderClassForBinding:(
CPString)aBinding
103 if ([aBinding hasPrefix:CPEnabledBinding])
105 else if (aBinding === CPTargetBinding || [aBinding hasPrefix:CPArgumentBinding])
108 return [
super _binderClassForBinding:aBinding];
113 return [
self initWithTitle:@"" action:nil keyEquivalent:nil];
123 - (id)initWithTitle:(
CPString)aTitle action:(
SEL)anAction keyEquivalent:(
CPString)aKeyEquivalent
141 _keyEquivalent = aKeyEquivalent ||
@"";
144 _indentationLevel = 0;
157 - (void)setEnabled:(BOOL)isEnabled
159 if (_isEnabled === isEnabled)
162 if (!isEnabled && [
self isHighlighted])
163 [_menu _highlightItemAtIndex:CPNotFound];
165 _isEnabled = !!isEnabled;
167 [_menuItemView setDirty];
168 [_menu itemChanged:self];
184 - (void)setHidden:(BOOL)isHidden
186 if (_isHidden == isHidden)
189 _isHidden = isHidden;
191 [_menu itemChanged:self];
205 - (BOOL)isHiddenOrHasHiddenAncestor
210 var supermenu = [_menu supermenu];
212 if ([[supermenu itemAtIndex:[supermenu indexOfItemWithSubmenu:_menu]] isHiddenOrHasHiddenAncestor])
223 - (void)setTarget:(
id)aTarget
240 - (void)setAction:(
SEL)anAction
262 if (_title == aTitle)
267 [_menuItemView setDirty];
269 [_menu itemChanged:self];
283 - (void)setTextColor:(
CPString)aColor
292 - (void)setFont:(
CPFont)aFont
299 [_menu itemChanged:self];
301 [_menuItemView setDirty];
327 - (void)setTag:(
int)aTag
348 - (void)setState:(
int)aState
350 if (_state == aState)
355 [_menu itemChanged:self];
357 [_menuItemView setDirty];
378 - (void)setImage:(
CPImage)anImage
380 if (_image == anImage)
385 [_menuItemView setDirty];
387 [_menu itemChanged:self];
402 - (void)setAlternateImage:(
CPImage)anImage
404 _alternateImage = anImage;
412 return _alternateImage;
420 - (void)setOnStateImage:(
CPImage)anImage
422 if (_onStateImage == anImage)
425 _onStateImage = anImage;
426 [_menu itemChanged:self];
434 return _onStateImage;
441 - (void)setOffStateImage:(
CPImage)anImage
443 if (_offStateImage == anImage)
446 _offStateImage = anImage;
447 [_menu itemChanged:self];
455 return _offStateImage;
462 - (void)setMixedStateImage:(
CPImage)anImage
464 if (_mixedStateImage == anImage)
467 _mixedStateImage = anImage;
468 [_menu itemChanged:self];
477 return _mixedStateImage;
485 - (void)setSubmenu:(
CPMenu)aMenu
487 if (_submenu === aMenu)
490 var supermenu = [_submenu supermenu];
494 reason: @"Can't add submenu \"" + [aMenu
title] + "\" to item \"" + [
self title] + "\", because it is already submenu of \"" + [[aMenu
supermenu]
title] + "\""];
500 [_submenu setSupermenu:_menu];
501 [_submenu setTitle:[
self title]]
503 [
self setTarget:_menu];
504 [
self setAction:@selector(submenuAction:)];
508 [
self setTarget:nil];
509 [
self setAction:NULL];
512 [_menuItemView setDirty];
514 [_menu itemChanged:self];
530 return _submenu ? YES : NO;
540 var separatorItem = [[
self alloc] initWithTitle:@"" action:nil keyEquivalent:nil];
542 separatorItem._isSeparator = YES;
544 return separatorItem;
550 - (BOOL)isSeparatorItem
560 - (void)setMenu:(
CPMenu)aMenu
579 - (void)setKeyEquivalent:(
CPString)aString
581 _keyEquivalent = aString ||
@"";
589 return _keyEquivalent;
602 - (void)setKeyEquivalentModifierMask:(
unsigned)aMask
604 _keyEquivalentModifierMask = aMask;
617 - (unsigned)keyEquivalentModifierMask
619 return _keyEquivalentModifierMask;
622 - (
CPString)keyEquivalentStringRepresentation
624 if (![_keyEquivalent length])
627 var
string = _keyEquivalent.toUpperCase(),
629 (
string === _keyEquivalent && _keyEquivalent.toLowerCase() !== _keyEquivalent.toUpperCase());
631 if ([CPMenuItemStringRepresentationDictionary objectForKey:
string])
632 string = [CPMenuItemStringRepresentationDictionary objectForKey:string];
637 string =
"\u2318" + string;
640 string =
"\u21E7" + string;
643 string =
"\u2325" + string;
646 string =
"\u2303" + string;
651 string =
"Shift-" + string;
653 if (_keyEquivalentModifierMask & CPAlternateKeyMask)
654 string =
"Alt-" + string;
656 if (_keyEquivalentModifierMask &
CPControlKeyMask || _keyEquivalentModifierMask & CPCommandKeyMask)
657 string =
"Ctrl-" + string;
669 - (void)setMnemonicLocation:(
unsigned)aLocation
671 _mnemonicLocation = aLocation;
677 - (unsigned)mnemonicLocation
679 return _mnemonicLocation;
686 - (void)setTitleWithMnemonicLocation:(
CPString)aTitle
688 var location = [aTitle rangeOfString:@"&"].location;
691 [
self setTitle:aTitle];
694 [
self setTitle:[aTitle substringToIndex:location] + [aTitle substringFromIndex:location + 1]];
695 [
self setMnemonicLocation:location];
704 return _mnemonicLocation ==
CPNotFound ?
@"" : [_title characterAtIndex:_mnemonicLocation];
713 - (void)setAlternate:(BOOL)isAlternate
715 _isAlternate = isAlternate;
733 - (void)setIndentationLevel:(
unsigned)aLevel
736 [
CPException raise:CPInvalidArgumentException
reason:"setIndentationLevel: argument must be greater than or equal to 0."];
738 _indentationLevel = MIN(15, aLevel);
744 - (unsigned)indentationLevel
746 return _indentationLevel;
754 - (void)setToolTip:(
CPString)aToolTip
773 - (void)setRepresentedObject:(
id)anObject
775 _representedObject = anObject;
781 - (id)representedObject
783 return _representedObject;
792 - (void)setView:(
CPView)aView
799 [_menuItemView setDirty];
801 [_menu itemChanged:self];
817 - (BOOL)isHighlighted
819 return [[
self menu] highlightedItem] ==
self;
822 #pragma mark CPObject Overrides
832 item._isSeparator = _isSeparator;
834 [item setTitle:_title];
835 [item setFont:_font];
836 [item setTarget:_target];
837 [item setAction:_action];
838 [item setEnabled:_isEnabled];
839 [item setHidden:_isHidden]
841 [item setState:_state];
842 [item setImage:_image];
843 [item setAlternateImage:_alternateImage];
844 [item setOnStateImage:_onStateImage];
845 [item setOffStateImage:_offStateImage];
846 [item setMixedStateImage:_mixedStateImage];
847 [item setKeyEquivalent:_keyEquivalent];
848 [item setKeyEquivalentModifierMask:_keyEquivalentModifierMask];
849 [item setMnemonicLocation:_mnemonicLocation];
850 [item setAlternate:_isAlternate];
851 [item setIndentationLevel:_indentationLevel];
852 [item setToolTip:_toolTip];
853 [item setRepresentedObject:_representedObject];
863 #pragma mark Internal
871 _menuItemView = [[_CPMenuItemView alloc] initWithFrame:CGRectMakeZero() forMenuItem:self];
873 return _menuItemView;
876 - (BOOL)_isSelectable
878 return ![
self submenu] || [
self action] !==
@selector(submenuAction:) || [
self target] !== [
self menu];
881 - (BOOL)_isMenuBarButton
883 return ![
self submenu] && [
self menu] === [CPApp mainMenu];
888 return [
super description] +
@" target: " + [self target] +
@" action: " +
CPStringFromSelector([self action]);
893 var CPMenuItemIsSeparatorKey =
@"CPMenuItemIsSeparatorKey",
895 CPMenuItemTitleKey =
@"CPMenuItemTitleKey",
896 CPMenuItemTargetKey =
@"CPMenuItemTargetKey",
897 CPMenuItemActionKey =
@"CPMenuItemActionKey",
899 CPMenuItemIsEnabledKey =
@"CPMenuItemIsEnabledKey",
900 CPMenuItemIsHiddenKey =
@"CPMenuItemIsHiddenKey",
902 CPMenuItemTagKey =
@"CPMenuItemTagKey",
903 CPMenuItemStateKey =
@"CPMenuItemStateKey",
905 CPMenuItemImageKey =
@"CPMenuItemImageKey",
906 CPMenuItemAlternateImageKey =
@"CPMenuItemAlternateImageKey",
908 CPMenuItemSubmenuKey =
@"CPMenuItemSubmenuKey",
909 CPMenuItemMenuKey =
@"CPMenuItemMenuKey",
911 CPMenuItemKeyEquivalentKey =
@"CPMenuItemKeyEquivalentKey",
912 CPMenuItemKeyEquivalentModifierMaskKey =
@"CPMenuItemKeyEquivalentModifierMaskKey",
914 CPMenuItemIndentationLevelKey =
@"CPMenuItemIndentationLevelKey",
916 CPMenuItemRepresentedObjectKey =
@"CPMenuItemRepresentedObjectKey",
917 CPMenuItemViewKey =
@"CPMenuItemViewKey";
919 #define DEFAULT_VALUE(aKey, aDefaultValue) [aCoder containsValueForKey:(aKey)] ? [aCoder decodeObjectForKey:(aKey)] : (aDefaultValue)
920 #define ENCODE_IFNOT(aKey, aValue, aDefaultValue) if ((aValue) !== (aDefaultValue)) [aCoder encodeObject:(aValue) forKey:(aKey)];
922 @implementation CPMenuItem (CPCoding)
928 - (id)initWithCoder:(
CPCoder)aCoder
935 _isSeparator = [aCoder containsValueForKey:CPMenuItemIsSeparatorKey] && [aCoder decodeBoolForKey:CPMenuItemIsSeparatorKey];
937 _title = [aCoder decodeObjectForKey:CPMenuItemTitleKey];
941 _target = [aCoder decodeObjectForKey:CPMenuItemTargetKey];
942 _action = [aCoder decodeObjectForKey:CPMenuItemActionKey];
945 _isHidden = [aCoder decodeBoolForKey:CPMenuItemIsHiddenKey];
946 _tag = [aCoder decodeIntForKey:CPMenuItemTagKey];
947 _state = [aCoder decodeIntForKey:CPMenuItemStateKey];
949 _image = [aCoder decodeObjectForKey:CPMenuItemImageKey];
950 _alternateImage = [aCoder decodeObjectForKey:CPMenuItemAlternateImageKey];
956 _menu = [aCoder decodeObjectForKey:CPMenuItemMenuKey];
957 [
self setSubmenu:[aCoder decodeObjectForKey:CPMenuItemSubmenuKey]];
959 _keyEquivalent = [aCoder decodeObjectForKey:CPMenuItemKeyEquivalentKey] ||
@"";
960 _keyEquivalentModifierMask = [aCoder decodeIntForKey:CPMenuItemKeyEquivalentModifierMaskKey];
966 [
self setIndentationLevel:[aCoder decodeIntForKey:CPMenuItemIndentationLevelKey]];
970 _representedObject = [aCoder decodeObjectForKey:CPMenuItemRepresentedObjectKey];
971 _view = [aCoder decodeObjectForKey:CPMenuItemViewKey];
981 - (void)encodeWithCoder:(
CPCoder)aCoder
984 [aCoder encodeBool:_isSeparator forKey:CPMenuItemIsSeparatorKey];
986 [aCoder encodeObject:_title forKey:CPMenuItemTitleKey];
988 [aCoder encodeObject:_target forKey:CPMenuItemTargetKey];
989 [aCoder encodeObject:_action forKey:CPMenuItemActionKey];
998 ENCODE_IFNOT(CPMenuItemAlternateImageKey, _alternateImage, nil);
1003 if (_keyEquivalent && _keyEquivalent.length)
1004 [aCoder encodeObject:_keyEquivalent forKey:CPMenuItemKeyEquivalentKey];
1006 if (_keyEquivalentModifierMask)
1007 [aCoder encodeObject:_keyEquivalentModifierMask forKey:CPMenuItemKeyEquivalentModifierMaskKey];
1009 if (_indentationLevel > 0)
1010 [aCoder encodeInt:_indentationLevel forKey:CPMenuItemIndentationLevelKey];
1012 ENCODE_IFNOT(CPMenuItemRepresentedObjectKey, _representedObject, nil);