33 CPUInteger _selectedIndex;
34 CPRectEdge _preferredEdge;
39 return "popup-button";
42 + (CPSet)keyPathsForValuesAffectingSelectedIndex
44 return [CPSet setWithObject:@"objectValue"];
47 + (CPSet)keyPathsForValuesAffectingSelectedTag
49 return [CPSet setWithObject:@"objectValue"];
52 + (CPSet)keyPathsForValuesAffectingSelectedItem
54 return [CPSet setWithObject:@"objectValue"];
63 - (id)initWithFrame:(CGRect)aFrame pullsDown:(BOOL)shouldPullDown
90 - (id)initWithFrame:(CGRect)aFrame
105 - (void)setPullsDown:(BOOL)shouldPullDown
108 var changed = [
self setThemeState:CPPopUpButtonStatePullsDown];
117 if ([items count] <= 0)
156 - (void)addItemsWithTitles:(CPArray)titles
159 count = [titles count];
161 for (; index < count; ++index)
162 [
self addItemWithTitle:titles[index]];
170 - (void)insertItemWithTitle:(
CPString)aTitle atIndex:(
int)anIndex
173 count = [items count];
176 if ([items[count] title] == aTitle)
185 - (void)removeAllItems
205 - (void)removeItemAtIndex:(
int)anIndex
219 if (indexOfSelectedItem < 0 || indexOfSelectedItem > [
self numberOfItems] - 1)
236 - (int)indexOfSelectedItem
238 return _selectedIndex;
255 - (void)selectItemAtIndex:(CPUInteger)anIndex
260 - (void)setSelectedIndex:(CPUInteger)anIndex
265 - (CPUInteger)selectedIndex
274 - (void)setObjectValue:(
id)anIndex
278 anIndex = parseInt(+anIndex, 10);
280 if (indexOfSelectedItem === anIndex)
283 if (indexOfSelectedItem >= 0 && ![
self pullsDown])
286 _selectedIndex = anIndex;
288 if (indexOfSelectedItem >= 0 && ![
self pullsDown])
296 return _selectedIndex;
303 - (void)selectItemWithTag:(
int)aTag
356 - (CPArray)itemTitles
361 count = [items count];
363 for (; index < count; ++index)
364 titles.push([items[index] title]);
406 - (int)indexOfItemWithTag:(
int)aTag
426 - (int)indexOfItemWithRepresentedObject:(
id)anObject
438 - (int)indexOfItemWithTarget:(
id)aTarget action:(
SEL)anAction
440 return [[
self menu] indexOfItemWithTarget:aTarget action:anAction];
449 - (CPRectEdge)preferredEdge
451 return _preferredEdge;
459 - (void)setPreferredEdge:(CPRectEdge)aRectEdge
461 _preferredEdge = aRectEdge;
471 if ([
self title] === aTitle)
474 if ([
self pullsDown])
478 if ([items count] <= 0)
483 [items[0] setTitle:aTitle];
518 - (void)synchronizeTitleAndSelectedItem
522 if ([
self pullsDown])
526 if ([items count] > 0)
536 - (void)observeValueForKeyPath:(
CPString)aKeyPath ofObject:(
id)anObject change:(
CPDictionary)changes context:(
id)aContext
540 if (!pullsDown && aKeyPath ===
@"selectedItem.changeCount" ||
541 pullsDown && (aKeyPath ===
@"_firstItem" || aKeyPath ===
@"_firstItem.changeCount"))
545 if (aKeyPath ===
@"menu")
547 aKeyPath =
@"menu.items";
549 [changes
setObject:CPKeyValueChangeSetting
forKey:CPKeyValueChangeKindKey];
553 if (aKeyPath ===
@"menu.items")
555 var changeKind = [changes
objectForKey:CPKeyValueChangeKindKey],
561 indexes = [changes
objectForKey:CPKeyValueChangeIndexesKey];
563 if ([indexes containsIndex:0] && [
self pullsDown])
564 [
self _firstItemDidChange];
566 if (![
self pullsDown] && [indexes containsIndex:indexOfSelectedItem])
569 indexOfSelectedItem = 0;
574 while ((index = [indexes indexGreaterThanIndex:index]) !==
CPNotFound &&
575 index <= indexOfSelectedItem)
576 --indexOfSelectedItem;
584 var indexes = [changes
objectForKey:CPKeyValueChangeIndexesKey];
586 if (pullsDown && [indexes containsIndex:0] ||
587 !pullsDown && [indexes containsIndex:indexOfSelectedItem])
594 var newItems = [changes
objectForKey:CPKeyValueChangeNewKey];
596 [newItems enumerateObjectsUsingBlock:function(aMenuItem)
598 var action = [aMenuItem
action];
603 if (action === @selector(_popUpItemAction:))
609 [
self _firstItemDidChange];
617 var indexes = [changes
objectForKey:CPKeyValueChangeIndexesKey];
619 if ([
self pullsDown] && [indexes containsIndex:0])
621 [
self _firstItemDidChange];
623 if ([
self numberOfItems] > 1)
628 while ((index = [indexes indexGreaterThanIndex:index]) !==
CPNotFound &&
629 index <= originalIndex)
636 if (indexOfSelectedItem < 0)
644 while ((index = [indexes indexGreaterThanIndex:index]) !==
CPNotFound &&
645 index <= indexOfSelectedItem)
646 ++indexOfSelectedItem;
659 if (![
self isEnabled] || ![
self numberOfItems])
665 if (
menu._lastCloseEvent === anEvent)
671 minimumWidth = CGRectGetWidth(
bounds);
676 if ([
self pullsDown])
678 var positionedItem = nil,
679 location = CGPointMake(0.0, CGRectGetMaxY(
bounds) - 1);
685 standardLeftMargin = [_CPMenuWindow _standardLeftMargin] + [_CPMenuItemStandardView _standardLeftMargin],
686 location = CGPointMake(CGRectGetMinX(contentRect) - standardLeftMargin, 0.0);
688 minimumWidth += standardLeftMargin;
691 [
menu _highlightItemAtIndex:CPNotFound];
697 _popUpMenuPositioningItem:positionedItem
699 topY:CGRectGetMinY(bounds)
700 bottomY:CGRectGetMaxY(bounds)
702 callback:function(aMenu)
706 var highlightedItem = [aMenu highlightedItem];
708 if ([highlightedItem _isSelectable])
734 - (void)_popUpItemAction:(
id)aSender
736 [
self sendAction:[
self action] to:[
self target]];
739 - (void)_firstItemDidChange
741 [
self willChangeValueForKey:@"_firstItem"];
742 [
self didChangeValueForKey:@"_firstItem"];
744 [[
self _firstItem] setHidden:YES];
749 if ([
self numberOfItems] <= 0)
752 return [[
self menu] itemAtIndex:0];
755 - (void)takeValueFromKeyPath:(
CPString)aKeyPath ofObjects:(CPArray)objects
757 var count = objects.
length,
758 value = [objects[0] valueForKeyPath:aKeyPath];
764 if (value !== [objects[count] valueForKeyPath:aKeyPath])
772 + (Class)_binderClassForBinding:(
CPString)aBinding
782 var capitalizedBinding = aBinding.charAt(0).toUpperCase() + aBinding.substr(1);
784 return [CPClassFromString(@"_CPPopUpButton" + capitalizedBinding + "Binder") class];
787 return [
super _binderClassForBinding:aBinding];
797 - (void)_reverseSetBinding
799 [_CPPopUpButtonSelectionBinder _reverseSetValueFromExclusiveBinderForObject:self];
801 [
super _reverseSetBinding];
805 @implementation _CPPopUpButtonContentBinder :
CPBinder
810 - (CPInteger)_getInsertNullOffset
812 var options = [_info objectForKey:CPOptionsKey];
814 return [options objectForKey:CPInsertsNullPlaceholderBindingOption] ? 1 : 0;
819 var options = [_info objectForKey:CPOptionsKey],
820 placeholder = [options objectForKey:CPNullPlaceholderBindingOption] ||
@"";
822 if (placeholder === [
CPNull null])
828 - (id)transformValue:(CPArray)contentArray withOptions:(
CPDictionary)options
834 - (void)setValue:(CPArray)contentArray forBinding:(
CPString)aBinding
836 [
self _setContent:contentArray];
837 [
self _setContentValuesIfNeeded:contentArray];
840 - (id)valueForBinding:(
CPString)aBinding
842 return [
self _content];
845 - (void)_setContent:(CPArray)aValue
847 var count = [aValue count],
848 options = [_info objectForKey:CPOptionsKey],
849 offset = [
self _getInsertNullOffset];
851 if (count + offset != [_source numberOfItems])
853 [_source removeAllItems];
856 [_source addItemWithTitle:[
self _getNullPlaceholder]];
858 for (var i = 0; i < count; i++)
861 [
self _setValue:[aValue objectAtIndex:i] forItem:item withOptions:options];
862 [_source addItem:item];
867 for (var i = 0; i < count; i++)
869 [
self _setValue:[aValue objectAtIndex:i] forItem:[_source itemAtIndex:i + offset] withOptions:options];
874 - (void)_setContentValuesIfNeeded:(CPArray)values
876 var offset = [
self _getInsertNullOffset];
881 [[_source itemAtIndex:0] setTitle:[
self _getNullPlaceholder]];
883 var count = [values count];
885 for (var i = 0; i < count; i++)
886 [[_source itemAtIndex:i + offset] setTitle:[[values objectAtIndex:i] description]];
892 var value = [
self _transformValue:aValue withOptions:options];
896 - (id)_transformValue:(
id)aValue withOptions:(
CPDictionary)options
898 return [
super transformValue:aValue withOptions:options];
903 return [_source valueForKeyPath:@"itemArray.representedObject"];
907 @implementation _CPPopUpButtonContentValuesBinder : _CPPopUpButtonContentBinder
912 - (void)setValue:(CPArray)aValue forBinding:(
CPString)aBinding
914 [
super _setContent:aValue];
919 if (aValue === [
CPNull null])
922 var value = [
self _transformValue:aValue withOptions:options];
928 return [_source valueForKeyPath:@"itemArray.title"];
932 @implementation _CPPopUpButtonSelectionBinder :
CPBinder
937 - (void)setPlaceholderValue:(
id)aValue withMarker:(
CPString)aMarker forBinding:(
CPString)aBinding
939 [
self setValue:aValue forBinding:aBinding];
942 - (CPInteger)_getInsertNullOffset
946 return [options
objectForKey:CPInsertsNullPlaceholderBindingOption] ? 1 : 0;
950 @implementation _CPPopUpButtonSelectedIndexBinder : _CPPopUpButtonSelectionBinder
955 - (void)setValue:(
id)aValue forBinding:(
CPString)aBinding
957 [_source selectItemAtIndex:aValue + [
self _getInsertNullOffset]];
960 - (id)valueForBinding:(
CPString)aBinding
962 return [_source indexOfSelectedItem] - [self _getInsertNullOffset];
966 @implementation _CPPopUpButtonSelectedObjectBinder : _CPPopUpButtonSelectionBinder
971 - (void)setValue:(
id)aValue forBinding:(
CPString)aBinding
973 var index = [_source indexOfItemWithRepresentedObject:aValue],
974 offset = [
self _getInsertNullOffset];
993 [_source selectItemAtIndex:index];
996 - (id)valueForBinding:(
CPString)aBinding
998 return [[_source selectedItem] representedObject];
1002 @implementation _CPPopUpButtonSelectedTagBinder : _CPPopUpButtonSelectionBinder
1007 - (void)setValue:(
id)aValue forBinding:(
CPString)aBinding
1009 [_source selectItemWithTag:aValue];
1012 - (id)valueForBinding:(
CPString)aBinding
1014 return [[_source selectedItem] tag];
1018 @implementation _CPPopUpButtonSelectedValueBinder : _CPPopUpButtonSelectionBinder
1023 - (void)setValue:(
id)aValue forBinding:(
CPString)aBinding
1025 [_source selectItemWithTitle:aValue];
1028 - (id)valueForBinding:(
CPString)aBinding
1030 return [_source titleOfSelectedItem];
1059 CPLog.warn(
self +
" was encoded with an older version of Cappuccino. Please nib2cib the original nib again or open and re-save in Atlas.");
1061 [
self setMenu:[aCoder decodeObjectForKey:DEPRECATED_CPPopUpButtonMenuKey]];
1062 [
self setObjectValue:[aCoder decodeObjectForKey:DEPRECATED_CPPopUpButtonSelectedIndexKey]];