mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-09-14 14:41:28 +00:00
Merge branch 'refs/heads/slevenbits-tokenfield-menu'
This commit is contained in:
+204
-26
@@ -27,13 +27,14 @@
|
||||
@import <Foundation/CPIndexSet.j>
|
||||
@import <Foundation/CPTimer.j>
|
||||
|
||||
@import "_CPAutocompleteMenu.j"
|
||||
@import "CPButton.j"
|
||||
@import "CPPopUpButton.j"
|
||||
@import "CPScrollView.j"
|
||||
@import "CPTableView.j"
|
||||
@import "CPText.j"
|
||||
@import "CPTextField.j"
|
||||
@import "CPWindow_Constants.j"
|
||||
@import "_CPAutocompleteMenu.j"
|
||||
|
||||
@global CPApp
|
||||
|
||||
@@ -59,6 +60,9 @@ var CPScrollDestinationNone = 0,
|
||||
CPScrollDestinationLeft = 1,
|
||||
CPScrollDestinationRight = 2;
|
||||
|
||||
CPTokenFieldDisclosureButtonType = 0;
|
||||
CPTokenFieldDeleteButtonType = 1;
|
||||
|
||||
@implementation CPTokenField : CPTextField
|
||||
{
|
||||
CPScrollView _tokenScrollView;
|
||||
@@ -76,6 +80,8 @@ var CPScrollDestinationNone = 0,
|
||||
CPEvent _mouseDownEvent;
|
||||
|
||||
BOOL _shouldNotifyTarget;
|
||||
|
||||
int _buttonType @accessors(property=buttonType);
|
||||
}
|
||||
|
||||
+ (CPCharacterSet)defaultTokenizingCharacterSet
|
||||
@@ -104,6 +110,7 @@ var CPScrollDestinationNone = 0,
|
||||
{
|
||||
_completionDelay = [[self class] defaultCompletionDelay];
|
||||
_tokenizingCharacterSet = [[self class] defaultTokenizingCharacterSet];
|
||||
_buttonType = CPTokenFieldDisclosureButtonType;
|
||||
[self setBezeled:YES];
|
||||
|
||||
[self _init];
|
||||
@@ -561,7 +568,7 @@ var CPScrollDestinationNone = 0,
|
||||
|
||||
if (newToken === nil)
|
||||
{
|
||||
newToken = [[_CPTokenFieldToken alloc] init];
|
||||
newToken = [_CPTokenFieldToken new];
|
||||
[newToken setTokenField:self];
|
||||
[newToken setRepresentedObject:tokenObject];
|
||||
[newToken setStringValue:tokenValue];
|
||||
@@ -1089,6 +1096,8 @@ var CPScrollDestinationNone = 0,
|
||||
tokenFrame = fitAndFrame(tokenViewSize.width, tokenViewSize.height);
|
||||
|
||||
[tokenView setFrame:tokenFrame];
|
||||
|
||||
[tokenView setButtonType:_buttonType];
|
||||
}
|
||||
|
||||
if (isEditing && !_selectedRange.length && _CPMaxRange(_selectedRange) >= [tokens count])
|
||||
@@ -1241,6 +1250,30 @@ var CPScrollDestinationNone = 0,
|
||||
return aString;
|
||||
}
|
||||
|
||||
- (BOOL)_hasMenuForRepresentedObject:(id)aRepresentedObject
|
||||
{
|
||||
var delegate = [self delegate];
|
||||
if ([delegate respondsToSelector:@selector(tokenField:hasMenuForRepresentedObject:)] &&
|
||||
[delegate respondsToSelector:@selector(tokenField:menuForRepresentedObject:)])
|
||||
return [delegate tokenField:self hasMenuForRepresentedObject:aRepresentedObject];
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (CPMenu)_menuForRepresentedObject:(id)aRepresentedObject
|
||||
{
|
||||
var delegate = [self delegate];
|
||||
if ([delegate respondsToSelector:@selector(tokenField:hasMenuForRepresentedObject:)] &&
|
||||
[delegate respondsToSelector:@selector(tokenField:menuForRepresentedObject:)])
|
||||
{
|
||||
var hasMenu = [delegate tokenField:self hasMenuForRepresentedObject:aRepresentedObject];
|
||||
if (hasMenu)
|
||||
return [delegate tokenField:self menuForRepresentedObject:aRepresentedObject] || nil;
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
// We put the string on the pasteboard before calling this delegate method.
|
||||
// By default, we write the NSStringPboardType as well as an array of NSStrings.
|
||||
// - (BOOL)tokenField:(NSTokenField *)tokenField writeRepresentedObjects:(NSArray *)objects toPasteboard:(NSPasteboard *)pboard;
|
||||
@@ -1265,13 +1298,25 @@ var CPScrollDestinationNone = 0,
|
||||
[_autocompleteMenu _hideCompletions];
|
||||
}
|
||||
|
||||
|
||||
- (void)setButtonType:(int)aButtonType
|
||||
{
|
||||
if (_buttonType === aButtonType)
|
||||
return;
|
||||
|
||||
_buttonType = aButtonType;
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation _CPTokenFieldToken : CPTextField
|
||||
{
|
||||
_CPTokenFieldTokenCloseButton _deleteButton;
|
||||
CPTokenField _tokenField;
|
||||
id _representedObject;
|
||||
_CPTokenFieldTokenCloseButton _deleteButton;
|
||||
_CPTokenFieldTokenDisclosureButton _disclosureButton;
|
||||
CPTokenField _tokenField;
|
||||
id _representedObject;
|
||||
int _buttonType;
|
||||
}
|
||||
|
||||
+ (CPString)defaultThemeClass
|
||||
@@ -1288,12 +1333,10 @@ var CPScrollDestinationNone = 0,
|
||||
{
|
||||
if (self = [super initWithFrame:frame])
|
||||
{
|
||||
_deleteButton = [[_CPTokenFieldTokenCloseButton alloc] initWithFrame:CGRectMakeZero()];
|
||||
[self addSubview:_deleteButton];
|
||||
|
||||
[self setEditable:NO];
|
||||
[self setHighlighted:NO];
|
||||
[self setBezeled:YES];
|
||||
[self setButtonType:CPTokenFieldDisclosureButtonType];
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -1317,6 +1360,7 @@ var CPScrollDestinationNone = 0,
|
||||
- (void)setRepresentedObject:(id)representedObject
|
||||
{
|
||||
_representedObject = representedObject;
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
- (void)setEditable:(BOOL)shouldBeEditable
|
||||
@@ -1329,9 +1373,12 @@ var CPScrollDestinationNone = 0,
|
||||
{
|
||||
var r = [super setThemeState:aState];
|
||||
|
||||
// Share hover state with the delete button.
|
||||
if (r && aState === CPThemeStateHovered)
|
||||
[_deleteButton setThemeState:aState];
|
||||
// Share hover state with the disclosure and delete buttons.
|
||||
if (aState & CPThemeStateHovered)
|
||||
{
|
||||
[_disclosureButton setThemeState:CPThemeStateHovered];
|
||||
[_deleteButton setThemeState:CPThemeStateHovered];
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -1340,9 +1387,12 @@ var CPScrollDestinationNone = 0,
|
||||
{
|
||||
var r = [super unsetThemeState:aState];
|
||||
|
||||
// Share hover state with the delete button.
|
||||
if (r && aState === CPThemeStateHovered)
|
||||
[_deleteButton unsetThemeState:aState];
|
||||
// Share hover state with the disclosure and delete button.
|
||||
if (aState & CPThemeStateHovered)
|
||||
{
|
||||
[_disclosureButton unsetThemeState:CPThemeStateHovered];
|
||||
[_deleteButton unsetThemeState:CPThemeStateHovered];
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -1360,6 +1410,47 @@ var CPScrollDestinationNone = 0,
|
||||
return size;
|
||||
}
|
||||
|
||||
- (void)setButtonType:(int)aButtonType
|
||||
{
|
||||
if (_buttonType === aButtonType)
|
||||
return;
|
||||
|
||||
_buttonType = aButtonType;
|
||||
|
||||
if (_buttonType === CPTokenFieldDisclosureButtonType)
|
||||
{
|
||||
if (_deleteButton)
|
||||
{
|
||||
[_deleteButton removeFromSuperview];
|
||||
_deleteButton = nil;
|
||||
}
|
||||
|
||||
if (!_disclosureButton)
|
||||
{
|
||||
_disclosureButton = [[_CPTokenFieldTokenDisclosureButton alloc] initWithFrame:CGRectMakeZero()];
|
||||
[self addSubview:_disclosureButton];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_disclosureButton)
|
||||
{
|
||||
[_disclosureButton removeFromSuperview];
|
||||
_disclosureButton = nil;
|
||||
}
|
||||
|
||||
if (!_deleteButton)
|
||||
{
|
||||
_deleteButton = [[_CPTokenFieldTokenCloseButton alloc] initWithFrame:CGRectMakeZero()];
|
||||
[self addSubview:_deleteButton];
|
||||
[_deleteButton setTarget:self];
|
||||
[_deleteButton setAction:@selector(_delete:)];
|
||||
}
|
||||
}
|
||||
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
[super layoutSubviews];
|
||||
@@ -1368,17 +1459,33 @@ var CPScrollDestinationNone = 0,
|
||||
positioned:CPWindowBelow
|
||||
relativeToEphemeralSubviewNamed:@"content-view"];
|
||||
|
||||
if (bezelView)
|
||||
if (bezelView && _tokenField)
|
||||
{
|
||||
[_deleteButton setTarget:self];
|
||||
[_deleteButton setAction:@selector(_delete:)];
|
||||
[_deleteButton setEnabled:[self isEditable]];
|
||||
switch (_buttonType)
|
||||
{
|
||||
case CPTokenFieldDisclosureButtonType:
|
||||
var shouldBeEnabled = [self hasMenu];
|
||||
[_disclosureButton setHidden:!shouldBeEnabled];
|
||||
|
||||
var frame = [bezelView frame],
|
||||
buttonOffset = [_deleteButton currentValueForThemeAttribute:@"offset"],
|
||||
buttonSize = [_deleteButton currentValueForThemeAttribute:@"min-size"];
|
||||
if (shouldBeEnabled)
|
||||
[_disclosureButton setMenu:[self menu]];
|
||||
|
||||
[_deleteButton setFrame:_CGRectMake(CGRectGetMaxX(frame) - buttonOffset.x, CGRectGetMinY(frame) + buttonOffset.y, buttonSize.width, buttonSize.height)];
|
||||
var frame = [bezelView frame],
|
||||
buttonOffset = [_disclosureButton currentValueForThemeAttribute:@"offset"],
|
||||
buttonSize = [_disclosureButton currentValueForThemeAttribute:@"min-size"];
|
||||
|
||||
[_disclosureButton setFrame:_CGRectMake(CGRectGetMaxX(frame) - buttonOffset.x, CGRectGetMinY(frame) + buttonOffset.y, buttonSize.width, buttonSize.height)];
|
||||
break;
|
||||
case CPTokenFieldDeleteButtonType:
|
||||
[_deleteButton setEnabled:[self isEditable] && [self isEnabled]];
|
||||
|
||||
var frame = [bezelView frame],
|
||||
buttonOffset = [_deleteButton currentValueForThemeAttribute:@"offset"],
|
||||
buttonSize = [_deleteButton currentValueForThemeAttribute:@"min-size"];
|
||||
|
||||
[_deleteButton setFrame:_CGRectMake(CGRectGetMaxX(frame) - buttonOffset.x, CGRectGetMinY(frame) + buttonOffset.y, buttonSize.width, buttonSize.height)];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1398,11 +1505,18 @@ var CPScrollDestinationNone = 0,
|
||||
[_tokenField _deleteToken:self];
|
||||
}
|
||||
|
||||
- (BOOL)hasMenu
|
||||
{
|
||||
return [_tokenField _hasMenuForRepresentedObject:_representedObject];
|
||||
}
|
||||
|
||||
- (CPMenu)menu
|
||||
{
|
||||
return [_tokenField _menuForRepresentedObject:_representedObject];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
/*
|
||||
Theming hook.
|
||||
*/
|
||||
@implementation _CPTokenFieldTokenCloseButton : CPButton
|
||||
{
|
||||
}
|
||||
@@ -1421,11 +1535,73 @@ var CPScrollDestinationNone = 0,
|
||||
return "tokenfield-token-close-button";
|
||||
}
|
||||
|
||||
- (void)mouseEntered:(CPEvent)anEvent
|
||||
{
|
||||
// Don't toggle hover state from within the button - we use the hover state of the token field as a whole.
|
||||
}
|
||||
|
||||
- (void)mouseExited:(CPEvent)anEvent
|
||||
{
|
||||
// Don't toggle hover state from within the button - we use the hover state of the token field as a whole.
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation _CPTokenFieldTokenDisclosureButton : CPPopUpButton
|
||||
{
|
||||
}
|
||||
|
||||
+ (id)themeAttributes
|
||||
{
|
||||
var attributes = [CPButton themeAttributes];
|
||||
|
||||
[attributes setObject:_CGPointMake(15, 5) forKey:@"offset"];
|
||||
|
||||
return attributes;
|
||||
}
|
||||
|
||||
+ (CPString)defaultThemeClass
|
||||
{
|
||||
return "tokenfield-token-disclosure-button";
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
{
|
||||
if (self = [self initWithFrame:aFrame pullsDown:YES])
|
||||
{
|
||||
[self setBordered:YES];
|
||||
[super setTitle:@""];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setTitle:(CPString)aTitle
|
||||
{
|
||||
// skip
|
||||
}
|
||||
|
||||
- (void)synchronizeTitleAndSelectedItem
|
||||
{
|
||||
// skip
|
||||
}
|
||||
|
||||
- (void)mouseEntered:(CPEvent)anEvent
|
||||
{
|
||||
// Don't toggle hover state from within the button - we use the hover state of the token field as a whole.
|
||||
}
|
||||
|
||||
- (void)mouseExited:(CPEvent)anEvent
|
||||
{
|
||||
// Don't toggle hover state from within the button - we use the hover state of the token field as a whole.
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
var CPTokenFieldTokenizingCharacterSetKey = "CPTokenFieldTokenizingCharacterSetKey",
|
||||
CPTokenFieldCompletionDelayKey = "CPTokenFieldCompletionDelay";
|
||||
CPTokenFieldCompletionDelayKey = "CPTokenFieldCompletionDelay",
|
||||
CPTokenFieldButtonTypeKey = "CPTokenFieldButtonTypeKey";
|
||||
|
||||
@implementation CPTokenField (CPCoding)
|
||||
|
||||
@@ -1437,6 +1613,7 @@ var CPTokenFieldTokenizingCharacterSetKey = "CPTokenFieldTokenizingCharacterSe
|
||||
{
|
||||
_tokenizingCharacterSet = [aCoder decodeObjectForKey:CPTokenFieldTokenizingCharacterSetKey] || [[self class] defaultTokenizingCharacterSet];
|
||||
_completionDelay = [aCoder decodeDoubleForKey:CPTokenFieldCompletionDelayKey] || [[self class] defaultCompletionDelay];
|
||||
_buttonType = [aCoder decodeIntForKey:CPTokenFieldButtonTypeKey] || CPTokenFieldDisclosureButtonType;
|
||||
|
||||
[self _init];
|
||||
|
||||
@@ -1453,6 +1630,7 @@ var CPTokenFieldTokenizingCharacterSetKey = "CPTokenFieldTokenizingCharacterSe
|
||||
|
||||
[aCoder encodeInt:_tokenizingCharacterSet forKey:CPTokenFieldTokenizingCharacterSetKey];
|
||||
[aCoder encodeDouble:_completionDelay forKey:CPTokenFieldCompletionDelayKey];
|
||||
[aCoder encodeInt:_buttonType forKey:CPTokenFieldButtonTypeKey];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 2.7 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.7 KiB |
@@ -1174,6 +1174,32 @@ var themedButtonValues = nil,
|
||||
return token;
|
||||
}
|
||||
|
||||
+ (_CPTokenFieldTokenDisclosureButton)themedTokenFieldDisclosureButton
|
||||
{
|
||||
var button = [[_CPTokenFieldTokenDisclosureButton alloc] initWithFrame:CGRectMake(0, 0, 9, 9)],
|
||||
|
||||
arrowImage = PatternColor("token-disclosure.png", 7.0, 6.0),
|
||||
arrowImageHiglighted = PatternColor("token-disclosure-highlighted.png", 7.0, 6.0),
|
||||
|
||||
themeValues =
|
||||
[
|
||||
[@"content-inset", CGInsetMake(0.0, 0.0, 0.0, 0.0), CPThemeStateNormal],
|
||||
|
||||
[@"bezel-color", nil, CPThemeStateBordered],
|
||||
[@"bezel-color", arrowImage, CPThemeStateBordered | CPThemeStateHovered],
|
||||
[@"bezel-color", arrowImageHiglighted, CPThemeStateBordered | CPThemeStateHovered | CPThemeStateHighlighted],
|
||||
|
||||
[@"min-size", CGSizeMake(7.0, 6.0)],
|
||||
[@"max-size", CGSizeMake(7.0, 6.0)],
|
||||
|
||||
[@"offset", CGPointMake(17, 7)]
|
||||
];
|
||||
|
||||
[self registerThemeValues:themeValues forView:button];
|
||||
|
||||
return button;
|
||||
}
|
||||
|
||||
+ (_CPTokenFieldTokenCloseButton)themedTokenFieldTokenCloseButton
|
||||
{
|
||||
var button = [[_CPTokenFieldTokenCloseButton alloc] initWithFrame:CGRectMake(0, 0, 9, 9)],
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 2.7 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.7 KiB |
@@ -709,7 +709,7 @@ var themedButtonValues = nil,
|
||||
[@"text-color", textDisabledColor, CPThemeStateDisabled],
|
||||
|
||||
[@"bezel-inset", CGInsetMake(0.0, 0.0, 0.0, 0.0), CPThemeStateBezeled],
|
||||
[@"content-inset", CGInsetMake(1.0, 24.0, 2.0, 16.0), CPThemeStateBezeled],
|
||||
[@"content-inset", CGInsetMake(1.0, 20.0, 2.0, 20.0), CPThemeStateBezeled],
|
||||
|
||||
// Minimum height == maximum height since tokens are fixed height.
|
||||
[@"min-size", CGSizeMake(0.0, 19.0)],
|
||||
@@ -723,6 +723,32 @@ var themedButtonValues = nil,
|
||||
return token;
|
||||
}
|
||||
|
||||
+ (_CPTokenFieldTokenDisclosureButton)themedTokenFieldDisclosureButton
|
||||
{
|
||||
var button = [[_CPTokenFieldTokenDisclosureButton alloc] initWithFrame:CGRectMake(0, 0, 9, 9)],
|
||||
|
||||
arrowImage = PatternColor("token-disclosure.png", 7.0, 6.0),
|
||||
arrowImageHiglighted = PatternColor("token-disclosure-highlighted.png", 7.0, 6.0),
|
||||
|
||||
themeValues =
|
||||
[
|
||||
[@"content-inset", CGInsetMake(0.0, 0.0, 0.0, 0.0), CPThemeStateNormal],
|
||||
|
||||
[@"bezel-color", nil, CPThemeStateBordered],
|
||||
[@"bezel-color", arrowImage, CPThemeStateBordered | CPThemeStateHovered],
|
||||
[@"bezel-color", arrowImageHiglighted, CPThemeStateBordered | CPThemeStateHovered | CPThemeStateHighlighted],
|
||||
|
||||
[@"min-size", CGSizeMake(7.0, 6.0)],
|
||||
[@"max-size", CGSizeMake(7.0, 6.0)],
|
||||
|
||||
[@"offset", CGPointMake(16, 7)]
|
||||
];
|
||||
|
||||
[self registerThemeValues:themeValues forView:button];
|
||||
|
||||
return button;
|
||||
}
|
||||
|
||||
+ (_CPTokenFieldTokenCloseButton)themedTokenFieldTokenCloseButton
|
||||
{
|
||||
var button = [[_CPTokenFieldTokenCloseButton alloc] initWithFrame:CGRectMake(0, 0, 9, 9)],
|
||||
@@ -732,16 +758,17 @@ var themedButtonValues = nil,
|
||||
|
||||
themeValues =
|
||||
[
|
||||
[@"bezel-color", bezelColor, CPThemeStateBordered],
|
||||
[@"bezel-color", bezelHighlightedColor, CPThemeStateBordered | CPThemeStateHighlighted],
|
||||
[@"bezel-color", bezelColor, CPThemeStateBordered | CPThemeStateHovered],
|
||||
[@"bezel-color", [bezelColor colorWithAlphaComponent:0], CPThemeStateBordered | CPThemeStateDisabled],
|
||||
[@"bezel-color", bezelHighlightedColor, CPThemeStateBordered | CPThemeStateHighlighted],
|
||||
|
||||
[@"min-size", CGSizeMake(8.0, 8.0)],
|
||||
[@"max-size", CGSizeMake(8.0, 8.0)],
|
||||
|
||||
[@"bezel-inset", CGInsetMake(0.0, 0.0, 0.0, 0.0), CPThemeStateBordered],
|
||||
[@"bezel-inset", CGInsetMake(0.0, 0.0, 0.0, 0.0), CPThemeStateBordered | CPThemeStateHighlighted],
|
||||
[@"bezel-inset", CGInsetMake(0.0, 0.0, 0.0, 0.0), CPThemeStateBordered],
|
||||
[@"bezel-inset", CGInsetMake(0.0, 0.0, 0.0, 0.0), CPThemeStateBordered | CPThemeStateHighlighted],
|
||||
|
||||
[@"offset", CGPointMake(17, 6), CPThemeStateBordered]
|
||||
[@"offset", CGPointMake(16, 6), CPThemeStateBordered]
|
||||
];
|
||||
|
||||
[self registerThemeValues:themeValues forView:button];
|
||||
|
||||
@@ -115,8 +115,13 @@ var _CPAutocompleteMenuMaximumHeight = 307;
|
||||
|
||||
- (void)setIndexOfSelectedItem:(int)anIndex
|
||||
{
|
||||
[tableView selectRowIndexes:[CPIndexSet indexSetWithIndex:anIndex] byExtendingSelection:NO];
|
||||
[tableView scrollRowToVisible:anIndex];
|
||||
if (anIndex == CPNotFound)
|
||||
[tableView selectRowIndexes:[CPIndexSet indexSet] byExtendingSelection:NO];
|
||||
else
|
||||
{
|
||||
[tableView selectRowIndexes:[CPIndexSet indexSetWithIndex:anIndex] byExtendingSelection:NO];
|
||||
[tableView scrollRowToVisible:anIndex];
|
||||
}
|
||||
}
|
||||
|
||||
- (int)indexOfSelectedItem
|
||||
|
||||
@@ -88,10 +88,23 @@ var STATES = ['Alabama', 'Alaska', 'Arizona', 'Arkansas', 'California', 'Colorad
|
||||
[tokenFieldD setDelegate:self];
|
||||
|
||||
var tokenFieldDEditable = [CPCheckBox checkBoxWithTitle:"Editable"];
|
||||
[tokenFieldDEditable setFrame:CGRectMake(525, CGRectGetMinY([tokenFieldD frame]), 200, 30)];
|
||||
[tokenFieldDEditable sizeToFit];
|
||||
[tokenFieldDEditable setFrameOrigin:CGPointMake(525, 5 + CGRectGetMinY([tokenFieldD frame]))];
|
||||
[tokenFieldDEditable bind:CPValueBinding toObject:tokenFieldD withKeyPath:@"editable" options:nil];
|
||||
[contentView addSubview:tokenFieldDEditable];
|
||||
|
||||
var tokenFieldDMenus = [CPCheckBox checkBoxWithTitle:"Menus"];
|
||||
[tokenFieldDMenus sizeToFit];
|
||||
[tokenFieldDMenus setFrameOrigin:CGPointMake(CGRectGetMaxX([tokenFieldDEditable frame]) + 5, 5 + CGRectGetMinY([tokenFieldD frame]))];
|
||||
[tokenFieldDMenus bind:CPValueBinding toObject:self withKeyPath:@"tokenFieldDHasMenus" options:nil];
|
||||
[contentView addSubview:tokenFieldDMenus];
|
||||
|
||||
var tokenFieldDClose = [CPCheckBox checkBoxWithTitle:"Close Buttons"];
|
||||
[tokenFieldDClose sizeToFit];
|
||||
[tokenFieldDClose setFrameOrigin:CGPointMake(CGRectGetMaxX([tokenFieldDMenus frame]) + 5, 5 + CGRectGetMinY([tokenFieldD frame]))];
|
||||
[tokenFieldDClose bind:CPValueBinding toObject:self withKeyPath:@"tokenFieldDHasCloseButtons" options:nil];
|
||||
[contentView addSubview:tokenFieldDClose];
|
||||
|
||||
allPersons = [
|
||||
[Person personWithFirstName:@"Luc" lastName:@"Vauvillier"],
|
||||
[Person personWithFirstName:@"John" lastName:@"Doe"],
|
||||
@@ -113,6 +126,37 @@ var STATES = ['Alabama', 'Alaska', 'Arizona', 'Arkansas', 'California', 'Colorad
|
||||
|
||||
}
|
||||
|
||||
- (void)setTokenFieldDHasMenus:(BOOL)shouldHaveMenus
|
||||
{
|
||||
if (shouldHaveMenus)
|
||||
{
|
||||
[[tokenFieldD objectValue] enumerateObjectsUsingBlock:function(aPerson)
|
||||
{
|
||||
var menu = [CPMenu new];
|
||||
for (var i = 0; i < 3; i++)
|
||||
[menu addItem:[[CPMenuItem alloc] initWithTitle:[CPString stringWithFormat:@"%@ Item %i", aPerson, i] action:nil keyEquivalent:nil]];
|
||||
aPerson.menu = menu;
|
||||
}];
|
||||
}
|
||||
else
|
||||
[[tokenFieldD objectValue] makeObjectsPerformSelector:@selector(setMenu:) withObject:nil];
|
||||
}
|
||||
|
||||
- (BOOL)tokenFieldDHasMenus
|
||||
{
|
||||
return !![[[tokenFieldD objectValue] firstObject] menu];
|
||||
}
|
||||
|
||||
- (void)setTokenFieldDHasCloseButtons:(BOOL)shouldHaveCloseButtons
|
||||
{
|
||||
[tokenFieldD setButtonType:shouldHaveCloseButtons ? CPTokenFieldDeleteButtonType : CPTokenFieldDisclosureButtonType];
|
||||
}
|
||||
|
||||
- (BOOL)tokenFieldDHasCloseButtons
|
||||
{
|
||||
return !![tokenFieldD buttonType] === CPTokenFieldDeleteButtonType;
|
||||
}
|
||||
|
||||
- (void)getObjectValues:(id)sender
|
||||
{
|
||||
alert([tokenFieldD objectValue]);
|
||||
@@ -177,6 +221,16 @@ var STATES = ['Alabama', 'Alaska', 'Arizona', 'Arkansas', 'California', 'Colorad
|
||||
return tokens;
|
||||
}
|
||||
|
||||
- (BOOL)tokenField:(CPTokenField)aTokenField hasMenuForRepresentedObject:(id)aRepresentedObject
|
||||
{
|
||||
return !!aRepresentedObject.menu;
|
||||
}
|
||||
|
||||
- (CPMenu)tokenField:(CPTokenField)aTokenField menuForRepresentedObject:(id)aRepresentedObject
|
||||
{
|
||||
return aRepresentedObject.menu;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
// A sample of a custom Object
|
||||
@@ -185,6 +239,8 @@ var STATES = ['Alabama', 'Alaska', 'Arizona', 'Arkansas', 'California', 'Colorad
|
||||
{
|
||||
CPString _firstName;
|
||||
CPString _lastName;
|
||||
|
||||
CPMenu menu @accessors;
|
||||
}
|
||||
|
||||
+ (id)personWithFirstName:(CPString)aFirstName lastName:(CPString)aLastName
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
<dict>
|
||||
<key>CPApplicationDelegateClass</key>
|
||||
<string>AppController</string>
|
||||
<key>CPDefaultTheme</key>
|
||||
<string>Aristo2</string>
|
||||
<key>CPBundleName</key>
|
||||
<string>CPTokenFieldTest</string>
|
||||
<key>CPPrincipalClass</key>
|
||||
|
||||
Reference in New Issue
Block a user