From 9035439f61537f0a0c9396682ef4c13b69cf6b44 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Tue, 11 Dec 2012 16:43:06 +0000 Subject: [PATCH 1/4] Fixed: token field first responder flicker when clicking tokens. Without this change, clicking a token in a first responder token field would cause it to momentarily lose first responder status and then immediately gain it back. This fix makes it so that tokens never try to become the first responder, resulting in a more stable token field as tokens are selected and deselected. --- AppKit/CPTokenField.j | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/AppKit/CPTokenField.j b/AppKit/CPTokenField.j index c223e6c4a..b15aec542 100755 --- a/AppKit/CPTokenField.j +++ b/AppKit/CPTokenField.j @@ -1284,6 +1284,11 @@ var CPScrollDestinationNone = 0, return "tokenfield-token"; } +- (BOOL)acceptsFirstResponder +{ + return NO; +} + - (id)initWithFrame:(CPRect)frame { if (self = [super initWithFrame:frame]) From c2bf47eca2aaad43cb35d4570c3d722c056956ce Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Tue, 11 Dec 2012 17:15:24 +0000 Subject: [PATCH 2/4] Support CPThemeStateEditable for text fields. --- AppKit/CPTextField.j | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/AppKit/CPTextField.j b/AppKit/CPTextField.j index 76d50f339..5e27a56b7 100644 --- a/AppKit/CPTextField.j +++ b/AppKit/CPTextField.j @@ -308,6 +308,11 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); if (shouldBeEditable) _isSelectable = YES; + if (_isEditable) + [self setThemeState:CPThemeStateEditable]; + else + [self unsetThemeState:CPThemeStateEditable]; + // We only allow first responder status if the field is editable and enabled. if (!shouldBeEditable && [[self window] firstResponder] === self) [[self window] makeFirstResponder:nil]; From d27e33394139dbcd6f5a7c1ce43d6f41b7834301 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Tue, 11 Dec 2012 17:19:02 +0000 Subject: [PATCH 3/4] Fixed: tokens could be deleted in an non editable token field. Prior to this fix, clicking the (X) button on a token would delete the token even if the field was not actually editable. --- AppKit/CPTokenField.j | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/AppKit/CPTokenField.j b/AppKit/CPTokenField.j index b15aec542..396cbf6ce 100755 --- a/AppKit/CPTokenField.j +++ b/AppKit/CPTokenField.j @@ -570,6 +570,7 @@ var CPScrollDestinationNone = 0, [newToken setTokenField:self]; [newToken setRepresentedObject:tokenObject]; [newToken setStringValue:tokenValue]; + [newToken setEditable:[self isEditable]]; [contentView addSubview:newToken]; } @@ -615,6 +616,13 @@ var CPScrollDestinationNone = 0, } } +- (void)setEditable:(BOOL)shouldBeEditable +{ + [super setEditable:shouldBeEditable]; + + [[self _tokens] makeObjectsPerformSelector:@selector(setEditable:) withObject:shouldBeEditable]; +} + - (void)sendAction:(SEL)anAction to:(id)anObject { _shouldNotifyTarget = NO; @@ -1324,6 +1332,12 @@ var CPScrollDestinationNone = 0, _representedObject = representedObject; } +- (void)setEditable:(BOOL)shouldBeEditable +{ + [super setEditable:shouldBeEditable]; + [self setNeedsLayout]; +} + - (CGSize)_minimumFrameSize { var size = _CGSizeMakeZero(), @@ -1349,6 +1363,7 @@ var CPScrollDestinationNone = 0, { [_deleteButton setTarget:self]; [_deleteButton setAction:@selector(_delete:)]; + [_deleteButton setEnabled:[self isEditable]]; var frame = [bezelView frame], buttonOffset = [_deleteButton currentValueForThemeAttribute:@"offset"], @@ -1370,7 +1385,8 @@ var CPScrollDestinationNone = 0, - (void)_delete:(id)sender { - [_tokenField _deleteToken:self]; + if ([self isEditable]) + [_tokenField _deleteToken:self]; } @end From bd1f64bfdeff42d9406c593e0941e98cbf783403 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Tue, 11 Dec 2012 17:27:13 +0000 Subject: [PATCH 4/4] Only show token delete button on hover, and only when token field is editable. Before this change the close button showed at all times, even for token fields which weren't even editable. This change brings us closer to Cocoa in that there's no token delete button most of the time, and just like in Cocoa there are more controls available on hover. (Although in Cocoa there's a disclosure arrow and we have a close button instead.) --- AppKit/CPTokenField.j | 22 ++++++++++++++++++++++ AppKit/Themes/Aristo/ThemeDescriptors.j | 13 +++++++------ 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/AppKit/CPTokenField.j b/AppKit/CPTokenField.j index 396cbf6ce..5bc5828f2 100755 --- a/AppKit/CPTokenField.j +++ b/AppKit/CPTokenField.j @@ -1338,6 +1338,28 @@ var CPScrollDestinationNone = 0, [self setNeedsLayout]; } +- (BOOL)setThemeState:(CPThemeState)aState +{ + var r = [super setThemeState:aState]; + + // Share hover state with the delete button. + if (r && aState === CPThemeStateHovered) + [_deleteButton setThemeState:aState]; + + return r; +} + +- (BOOL)unsetThemeState:(CPThemeState)aState +{ + var r = [super unsetThemeState:aState]; + + // Share hover state with the delete button. + if (r && aState === CPThemeStateHovered) + [_deleteButton unsetThemeState:aState]; + + return r; +} + - (CGSize)_minimumFrameSize { var size = _CGSizeMakeZero(), diff --git a/AppKit/Themes/Aristo/ThemeDescriptors.j b/AppKit/Themes/Aristo/ThemeDescriptors.j index 5c77deb67..4eaa51738 100755 --- a/AppKit/Themes/Aristo/ThemeDescriptors.j +++ b/AppKit/Themes/Aristo/ThemeDescriptors.j @@ -1089,7 +1089,7 @@ var themedButtonValues = nil, [@"text-color", textHighlightedColor, CPThemeStateHighlighted], [@"bezel-inset", CGInsetMakeZero(), CPThemeStateBezeled], - [@"content-inset", CGInsetMake(2.0, 22.0, 2.0, 15.0), CPThemeStateBezeled], + [@"content-inset", CGInsetMake(2.0, 20.0, 2.0, 20.0), CPThemeStateBezeled], // Minimum height == maximum height since tokens are fixed height. [@"min-size", CGSizeMake(0.0, 19.0)], @@ -1112,16 +1112,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(17, 6), CPThemeStateBordered] ]; [self registerThemeValues:themeValues forView:button];