diff --git a/AppKit/CPButton.j b/AppKit/CPButton.j index e2b7c1074..c78d160e8 100644 --- a/AppKit/CPButton.j +++ b/AppKit/CPButton.j @@ -280,7 +280,7 @@ CPButtonImageOffset = 3.0; break; case CPOffState: - [self unsetThemeState:[CPThemeStateSelected, CPButtonStateMixed, CPThemeStateHighlighted]]; + [self unsetThemeStates:[CPThemeStateSelected, CPButtonStateMixed, CPThemeStateHighlighted]]; } } diff --git a/AppKit/CPButtonBar.j b/AppKit/CPButtonBar.j index f27819689..322d8c65a 100644 --- a/AppKit/CPButtonBar.j +++ b/AppKit/CPButtonBar.j @@ -272,15 +272,15 @@ currentButtonOffset += width - 1; } - [button setValue:normalColor forThemeAttribute:@"bezel-color" inState:[CPThemeStateNormal, CPThemeStateBordered]]; - [button setValue:highlightedColor forThemeAttribute:@"bezel-color" inState:[CPThemeStateHighlighted, CPThemeStateBordered, ]]; - [button setValue:disabledColor forThemeAttribute:@"bezel-color" inState:[CPThemeStateDisabled, CPThemeStateBordered]]; + [button setValue:normalColor forThemeAttribute:@"bezel-color" inStates:[CPThemeStateNormal, CPThemeStateBordered]]; + [button setValue:highlightedColor forThemeAttribute:@"bezel-color" inStates:[CPThemeStateHighlighted, CPThemeStateBordered, ]]; + [button setValue:disabledColor forThemeAttribute:@"bezel-color" inStates:[CPThemeStateDisabled, CPThemeStateBordered]]; [button setValue:textColor forThemeAttribute:@"text-color" inState:CPThemeStateBordered]; // FIXME shouldn't need this - [button setValue:normalColor forThemeAttribute:@"bezel-color" inState:[CPThemeStateNormal, CPThemeStateBordered, CPPopUpButtonStatePullsDown]]; - [button setValue:highlightedColor forThemeAttribute:@"bezel-color" inState:[CPThemeStateHighlighted, CPThemeStateBordered, CPPopUpButtonStatePullsDown]]; - [button setValue:disabledColor forThemeAttribute:@"bezel-color" inState:[CPThemeStateDisabled, CPThemeStateBordered, CPPopUpButtonStatePullsDown]]; + [button setValue:normalColor forThemeAttribute:@"bezel-color" inStates:[CPThemeStateNormal, CPThemeStateBordered, CPPopUpButtonStatePullsDown]]; + [button setValue:highlightedColor forThemeAttribute:@"bezel-color" inStates:[CPThemeStateHighlighted, CPThemeStateBordered, CPPopUpButtonStatePullsDown]]; + [button setValue:disabledColor forThemeAttribute:@"bezel-color" inStates:[CPThemeStateDisabled, CPThemeStateBordered, CPPopUpButtonStatePullsDown]]; [self addSubview:button]; } diff --git a/AppKit/CPDatePicker/_CPDatePickerCalendar.j b/AppKit/CPDatePicker/_CPDatePickerCalendar.j index c4ecb3866..b3140cab1 100644 --- a/AppKit/CPDatePicker/_CPDatePickerCalendar.j +++ b/AppKit/CPDatePicker/_CPDatePickerCalendar.j @@ -1114,30 +1114,30 @@ var CPShortWeekDayNameArrayEn = [@"Mo", @"Tu", @"We", @"Th", @"Fr", @"Sa", @"Su" [_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-shadow-color" inState:CPThemeStateDisabled] forThemeAttribute:@"text-shadow-color" inState:CPThemeStateDisabled]; [_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-shadow-offset" inState:CPThemeStateDisabled] forThemeAttribute:@"text-shadow-offset" inState:CPThemeStateDisabled]; - [_textField setValue:[_datePicker valueForThemeAttribute:@"tile-font" inState:[CPThemeStateDisabled, CPThemeStateSelected]] forThemeAttribute:@"font" inState:[CPThemeStateDisabled, CPThemeStateSelected]]; - [_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-color" inState:[CPThemeStateDisabled, CPThemeStateSelected]]forThemeAttribute:@"text-color" inState:[CPThemeStateDisabled, CPThemeStateSelected]]; - [_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-shadow-color" inState:[CPThemeStateDisabled, CPThemeStateSelected]] forThemeAttribute:@"text-shadow-color" inState:[CPThemeStateDisabled, CPThemeStateSelected]]; - [_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-shadow-offset" inState:[CPThemeStateDisabled, CPThemeStateSelected]] forThemeAttribute:@"text-shadow-offset" inState:[CPThemeStateDisabled, CPThemeStateSelected]]; + [_textField setValue:[_datePicker valueForThemeAttribute:@"tile-font" inStates:[CPThemeStateDisabled, CPThemeStateSelected]] forThemeAttribute:@"font" inStates:[CPThemeStateDisabled, CPThemeStateSelected]]; + [_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-color" inStates:[CPThemeStateDisabled, CPThemeStateSelected]]forThemeAttribute:@"text-color" inStates:[CPThemeStateDisabled, CPThemeStateSelected]]; + [_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-shadow-color" inStates:[CPThemeStateDisabled, CPThemeStateSelected]] forThemeAttribute:@"text-shadow-color" inStates:[CPThemeStateDisabled, CPThemeStateSelected]]; + [_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-shadow-offset" inStates:[CPThemeStateDisabled, CPThemeStateSelected]] forThemeAttribute:@"text-shadow-offset" inStates:[CPThemeStateDisabled, CPThemeStateSelected]]; [_textField setValue:[_datePicker valueForThemeAttribute:@"tile-font" inState:CPThemeStateHighlighted] forThemeAttribute:@"font" inState:CPThemeStateHighlighted]; [_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-color" inState:CPThemeStateHighlighted] forThemeAttribute:@"text-color" inState:CPThemeStateHighlighted]; [_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-shadow-color" inState:CPThemeStateHighlighted] forThemeAttribute:@"text-shadow-color" inState:CPThemeStateHighlighted]; [_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-shadow-offset" inState:CPThemeStateHighlighted] forThemeAttribute:@"text-shadow-offset" inState:CPThemeStateHighlighted]; - [_textField setValue:[_datePicker valueForThemeAttribute:@"tile-font" inState:[CPThemeStateHighlighted, CPThemeStateSelected]] forThemeAttribute:@"font" inState:[CPThemeStateHighlighted, CPThemeStateSelected]]; - [_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-color" inState:[CPThemeStateHighlighted, CPThemeStateSelected]] forThemeAttribute:@"text-color" inState:[CPThemeStateHighlighted, CPThemeStateSelected]]; - [_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-shadow-color" inState:[CPThemeStateHighlighted, CPThemeStateSelected]] forThemeAttribute:@"text-shadow-color" inState:[CPThemeStateHighlighted, CPThemeStateSelected]]; - [_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-shadow-offset" inState:[CPThemeStateHighlighted, CPThemeStateSelected]] forThemeAttribute:@"text-shadow-offset" inState:[CPThemeStateHighlighted, CPThemeStateSelected]]; + [_textField setValue:[_datePicker valueForThemeAttribute:@"tile-font" inStates:[CPThemeStateHighlighted, CPThemeStateSelected]] forThemeAttribute:@"font" inStates:[CPThemeStateHighlighted, CPThemeStateSelected]]; + [_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-color" inStates:[CPThemeStateHighlighted, CPThemeStateSelected]] forThemeAttribute:@"text-color" inStates:[CPThemeStateHighlighted, CPThemeStateSelected]]; + [_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-shadow-color" inStates:[CPThemeStateHighlighted, CPThemeStateSelected]] forThemeAttribute:@"text-shadow-color" inStates:[CPThemeStateHighlighted, CPThemeStateSelected]]; + [_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-shadow-offset" inStates:[CPThemeStateHighlighted, CPThemeStateSelected]] forThemeAttribute:@"text-shadow-offset" inStates:[CPThemeStateHighlighted, CPThemeStateSelected]]; - [_textField setValue:[_datePicker valueForThemeAttribute:@"tile-font" inState:[CPThemeStateDisabled, CPThemeStateHighlighted, CPThemeStateSelected]] forThemeAttribute:@"font" inState:[CPThemeStateDisabled, CPThemeStateHighlighted, CPThemeStateSelected]]; - [_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-color" inState:[CPThemeStateDisabled, CPThemeStateHighlighted, CPThemeStateSelected]] forThemeAttribute:@"text-color" inState:[CPThemeStateDisabled, CPThemeStateHighlighted, CPThemeStateSelected]]; - [_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-shadow-color" inState:[CPThemeStateDisabled, CPThemeStateHighlighted, CPThemeStateSelected]] forThemeAttribute:@"text-shadow-color" inState:[CPThemeStateDisabled, CPThemeStateHighlighted, CPThemeStateSelected]]; - [_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-shadow-offset" inState:[CPThemeStateDisabled, CPThemeStateHighlighted, CPThemeStateSelected]] forThemeAttribute:@"text-shadow-offset" inState:[CPThemeStateDisabled, CPThemeStateHighlighted, CPThemeStateSelected]]; + [_textField setValue:[_datePicker valueForThemeAttribute:@"tile-font" inStates:[CPThemeStateDisabled, CPThemeStateHighlighted, CPThemeStateSelected]] forThemeAttribute:@"font" inStates:[CPThemeStateDisabled, CPThemeStateHighlighted, CPThemeStateSelected]]; + [_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-color" inStates:[CPThemeStateDisabled, CPThemeStateHighlighted, CPThemeStateSelected]] forThemeAttribute:@"text-color" inStates:[CPThemeStateDisabled, CPThemeStateHighlighted, CPThemeStateSelected]]; + [_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-shadow-color" inStates:[CPThemeStateDisabled, CPThemeStateHighlighted, CPThemeStateSelected]] forThemeAttribute:@"text-shadow-color" inStates:[CPThemeStateDisabled, CPThemeStateHighlighted, CPThemeStateSelected]]; + [_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-shadow-offset" inStates:[CPThemeStateDisabled, CPThemeStateHighlighted, CPThemeStateSelected]] forThemeAttribute:@"text-shadow-offset" inStates:[CPThemeStateDisabled, CPThemeStateHighlighted, CPThemeStateSelected]]; - [_textField setValue:[_datePicker valueForThemeAttribute:@"tile-font" inState:[CPThemeStateDisabled, CPThemeStateHighlighted]] forThemeAttribute:@"font" inState:[CPThemeStateDisabled, CPThemeStateHighlighted]]; - [_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-color" inState:[CPThemeStateDisabled, CPThemeStateHighlighted]] forThemeAttribute:@"text-color" inState:[CPThemeStateDisabled, CPThemeStateHighlighted]]; - [_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-shadow-color" inState:[CPThemeStateDisabled, CPThemeStateHighlighted]] forThemeAttribute:@"text-shadow-color" inState:[CPThemeStateDisabled, CPThemeStateHighlighted]]; - [_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-shadow-offset" inState:[CPThemeStateDisabled, CPThemeStateHighlighted]] forThemeAttribute:@"text-shadow-offset" inState:[CPThemeStateDisabled, CPThemeStateHighlighted]]; + [_textField setValue:[_datePicker valueForThemeAttribute:@"tile-font" inStates:[CPThemeStateDisabled, CPThemeStateHighlighted]] forThemeAttribute:@"font" inStates:[CPThemeStateDisabled, CPThemeStateHighlighted]]; + [_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-color" inStates:[CPThemeStateDisabled, CPThemeStateHighlighted]] forThemeAttribute:@"text-color" inStates:[CPThemeStateDisabled, CPThemeStateHighlighted]]; + [_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-shadow-color" inStates:[CPThemeStateDisabled, CPThemeStateHighlighted]] forThemeAttribute:@"text-shadow-color" inStates:[CPThemeStateDisabled, CPThemeStateHighlighted]]; + [_textField setValue:[_datePicker valueForThemeAttribute:@"tile-text-shadow-offset" inStates:[CPThemeStateDisabled, CPThemeStateHighlighted]] forThemeAttribute:@"text-shadow-offset" inStates:[CPThemeStateDisabled, CPThemeStateHighlighted]]; [self addSubview:_textField]; diff --git a/AppKit/CPStepper.j b/AppKit/CPStepper.j index 3436d062f..42442ea04 100644 --- a/AppKit/CPStepper.j +++ b/AppKit/CPStepper.j @@ -188,12 +188,12 @@ [_buttonUp setFrame:upFrame]; [_buttonDown setFrame:downFrame]; - [_buttonUp setValue:[self valueForThemeAttribute:@"bezel-color-up-button" inState:[controlSizeThemeState, CPThemeStateBordered]] forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered]; - [_buttonUp setValue:[self valueForThemeAttribute:@"bezel-color-up-button" inState:[controlSizeThemeState, CPThemeStateBordered, CPThemeStateDisabled]] forThemeAttribute:@"bezel-color" inState:[CPThemeStateBordered, CPThemeStateDisabled]]; - [_buttonUp setValue:[self valueForThemeAttribute:@"bezel-color-up-button" inState:[controlSizeThemeState, CPThemeStateBordered, CPThemeStateHighlighted]] forThemeAttribute:@"bezel-color" inState:[CPThemeStateBordered, CPThemeStateHighlighted]]; - [_buttonDown setValue:[self valueForThemeAttribute:@"bezel-color-down-button" inState:[controlSizeThemeState, CPThemeStateBordered]] forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered]; - [_buttonDown setValue:[self valueForThemeAttribute:@"bezel-color-down-button" inState:[controlSizeThemeState, CPThemeStateBordered, CPThemeStateDisabled]] forThemeAttribute:@"bezel-color" inState:[CPThemeStateBordered, CPThemeStateDisabled]]; - [_buttonDown setValue:[self valueForThemeAttribute:@"bezel-color-down-button" inState:[controlSizeThemeState, CPThemeStateBordered, CPThemeStateHighlighted]] forThemeAttribute:@"bezel-color" inState:[CPThemeStateBordered, CPThemeStateHighlighted]]; + [_buttonUp setValue:[self valueForThemeAttribute:@"bezel-color-up-button" inStates:[controlSizeThemeState, CPThemeStateBordered]] forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered]; + [_buttonUp setValue:[self valueForThemeAttribute:@"bezel-color-up-button" inStates:[controlSizeThemeState, CPThemeStateBordered, CPThemeStateDisabled]] forThemeAttribute:@"bezel-color" inStates:[CPThemeStateBordered, CPThemeStateDisabled]]; + [_buttonUp setValue:[self valueForThemeAttribute:@"bezel-color-up-button" inStates:[controlSizeThemeState, CPThemeStateBordered, CPThemeStateHighlighted]] forThemeAttribute:@"bezel-color" inStates:[CPThemeStateBordered, CPThemeStateHighlighted]]; + [_buttonDown setValue:[self valueForThemeAttribute:@"bezel-color-down-button" inStates:[controlSizeThemeState, CPThemeStateBordered]] forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered]; + [_buttonDown setValue:[self valueForThemeAttribute:@"bezel-color-down-button" inStates:[controlSizeThemeState, CPThemeStateBordered, CPThemeStateDisabled]] forThemeAttribute:@"bezel-color" inStates:[CPThemeStateBordered, CPThemeStateDisabled]]; + [_buttonDown setValue:[self valueForThemeAttribute:@"bezel-color-down-button" inStates:[controlSizeThemeState, CPThemeStateBordered, CPThemeStateHighlighted]] forThemeAttribute:@"bezel-color" inStates:[CPThemeStateBordered, CPThemeStateHighlighted]]; } - (void)_sizeToFit diff --git a/AppKit/CPTableHeaderView.j b/AppKit/CPTableHeaderView.j index 36d6d1ef1..3c4532d2c 100644 --- a/AppKit/CPTableHeaderView.j +++ b/AppKit/CPTableHeaderView.j @@ -622,7 +622,7 @@ var CPTableHeaderViewResizeZone = 3.0, [[headerView subviews] makeObjectsPerformSelector:@selector(setHidden:) withObject:YES]; // The underlying column header shows normal state - [headerView unsetThemeState:CPThemeStateHighlighted | CPThemeStateSelected]; + [headerView unsetThemeStates:[CPThemeStateHighlighted, CPThemeStateSelected]]; // Keep track of the location within the column header where the original mousedown occurred _columnDragHeaderView = [_columnDragView viewWithTag:CPTableHeaderViewDragColumnHeaderTag]; diff --git a/AppKit/CPTableView.j b/AppKit/CPTableView.j index d2f2edb58..0762c2b9d 100644 --- a/AppKit/CPTableView.j +++ b/AppKit/CPTableView.j @@ -6400,18 +6400,12 @@ var CPTableViewDataSourceKey = @"CPTableViewDataSourceKey", - (BOOL)setThemeState:(ThemeState)aState { - if (aState.isa && [aState isKindOfClass:CPArray]) - aState = CPThemeState.apply(null, aState); - [super setThemeState:aState]; [self recursivelyPerformSelector:@selector(setThemeState:) withObject:aState startingFrom:self]; } - (BOOL)unsetThemeState:(ThemeState)aState { - if (aState.isa && [aState isKindOfClass:CPArray]) - aState = CPThemeState.apply(null, aState); - [super unsetThemeState:aState]; [self recursivelyPerformSelector:@selector(unsetThemeState:) withObject:aState startingFrom:self]; } diff --git a/AppKit/CPTheme.j b/AppKit/CPTheme.j index 749b8fa4a..a9246cc89 100644 --- a/AppKit/CPTheme.j +++ b/AppKit/CPTheme.j @@ -36,7 +36,6 @@ var CPThemesByName = { }, /*! @ingroup appkit */ - @implementation CPTheme : CPObject { CPString _name; @@ -327,6 +326,7 @@ function ThemeState(stateNames) { if (!stateNames.hasOwnProperty(key)) continue; + if (key !== 'normal') { this._stateNames[key] = true; @@ -344,8 +344,10 @@ function ThemeState(stateNames) this._stateNameString = stateNameKeys[0]; var stateNameLength = stateNameKeys.length; + for (var stateIndex = 1; stateIndex < stateNameLength; stateIndex++) this._stateNameString = this._stateNameString + "+" + stateNameKeys[stateIndex]; + this._stateNameCount = stateNameLength; } @@ -392,7 +394,19 @@ ThemeState.prototype.without = function(aState) if (!aState || aState === [CPNull null]) return this; + var firstTransform = CPThemeWithoutTransform[this._stateNameString], + result; + + if (firstTransform) + { + result = firstTransform[aState._stateNameString]; + + if (result) + return result; + } + var newStates = {}; + for (var stateName in this._stateNames) { if (!this._stateNames.hasOwnProperty(stateName)) @@ -402,25 +416,54 @@ ThemeState.prototype.without = function(aState) newStates[stateName] = true; } - return ThemeState._cacheThemeState(new ThemeState(newStates)); + result = ThemeState._cacheThemeState(new ThemeState(newStates)); + + if (!firstTransform) + firstTransform = CPThemeWithoutTransform[this._stateNameString] = {}; + + firstTransform[aState._stateNameString] = result; + + return result; } ThemeState.prototype.and = function(aState) { - return CPThemeState(this, aState); + var firstTransform = CPThemeAndTransform[this._stateNameString], + result; + + if (firstTransform) + { + result = firstTransform[aState._stateNameString]; + + if (result) + return result; + } + + result = CPThemeState(this, aState); + + if (!firstTransform) + firstTransform = CPThemeAndTransform[this._stateNameString] = {}; + + firstTransform[aState._stateNameString] = result; + + return result; } -var CPThemeStates = {}; +var CPThemeStates = {}, + CPThemeWithoutTransform = {}, + CPThemeAndTransform = {}; ThemeState._cacheThemeState = function(aState) { // We do this caching so themeState equality works. Basically, doing CPThemeState('foo+bar') === CPThemeState('bar', 'foo') will return true. var themeState = CPThemeStates[String(aState)]; + if (themeState === undefined) { themeState = aState; CPThemeStates[String(themeState)] = themeState; } + return themeState; } @@ -438,14 +481,17 @@ function CPThemeState() throw "CPThemeState() must be called with at least one string argument"; var themeState; + if (arguments.length === 1 && typeof arguments[0] === 'string') { themeState = CPThemeStates[arguments[0]]; + if (themeState !== undefined) return themeState; } var stateNames = {}; + for (var argIndex = 0; argIndex < arguments.length; argIndex++) { if (arguments[argIndex] === [CPNull null] || !arguments[argIndex]) @@ -457,12 +503,14 @@ function CPThemeState() { if (!arguments[argIndex]._stateNames.hasOwnProperty(stateName)) continue; + stateNames[stateName] = true; } } else { var allNames = arguments[argIndex].split('+'); + for (var nameIndex = 0; nameIndex < allNames.length; nameIndex++) stateNames[allNames[nameIndex]] = true; } @@ -522,6 +570,9 @@ CPThemeStateControlSizeRegular = CPThemeState("controlSizeRegular"); CPThemeStateControlSizeSmall = CPThemeState("controlSizeSmall"); CPThemeStateControlSizeMini = CPThemeState("controlSizeMini"); +CPThemeStateNormalString = String(CPThemeStateNormal); + + @implementation _CPThemeAttribute : CPObject { CPString _name; @@ -532,7 +583,7 @@ CPThemeStateControlSizeMini = CPThemeState("controlSizeMini"); _CPThemeAttribute _themeDefaultAttribute; } -- (id)initWithName:(CPString)aName defaultValue:(id)aDefaultValue +- (id)initWithName:(CPString)aName defaultValue:(id)aDefaultValue defaultAttribute:(_CPThemeAttribute)aDefaultAttribute { self = [super init]; @@ -541,7 +592,9 @@ CPThemeStateControlSizeMini = CPThemeState("controlSizeMini"); _cache = { }; _name = aName; _defaultValue = aDefaultValue; - _values = @{}; + + if (aDefaultAttribute) + _themeDefaultAttribute = aDefaultAttribute; } return self; @@ -562,24 +615,41 @@ CPThemeStateControlSizeMini = CPThemeState("controlSizeMini"); return [_values count] > 0; } -- (void)setValue:(id)aValue +- (_CPThemeAttribute)attributeBySettingValue:(id)aValue { - _cache = {}; + var attribute = [[_CPThemeAttribute alloc] initWithName:_name defaultValue:_defaultValue defaultAttribute:_themeDefaultAttribute]; - if (aValue === undefined || aValue === nil) - _values = @{}; - else - _values = @{ String(CPThemeStateNormal): aValue }; + if (aValue !== undefined && aValue !== nil) + attribute._values = @{ CPThemeStateNormalString: aValue }; + + return attribute; } -- (void)setValue:(id)aValue forState:(ThemeState)aState +- (_CPThemeAttribute)attributeBySettingValue:(id)aValue forState:(ThemeState)aState { - _cache = { }; + var shouldRemoveValue = aValue === undefined || aValue === nil, + attribute = [[_CPThemeAttribute alloc] initWithName:_name defaultValue:_defaultValue defaultAttribute:_themeDefaultAttribute], + values = _values; - if ((aValue === undefined) || (aValue === nil)) - [_values removeObjectForKey:String(aState)]; - else - [_values setObject:aValue forKey:String(aState)]; + if (values != null) + { + values = [values copy]; + + if (shouldRemoveValue) + [values removeObjectForKey:String(aState)]; + else + [values setObject:aValue forKey:String(aState)]; + + attribute._values = values; + } + else if (!shouldRemoveValue) + { + values = [[CPDictionary alloc] init]; + [values setObject:aValue forKey:String(aState)]; + attribute._values = values; + } + + return attribute; } - (id)value @@ -604,7 +674,7 @@ CPThemeStateControlSizeMini = CPThemeState("controlSizeMini"); if (aState._stateNameCount > 1) { var states = [_values allKeys], - count = states.length, + count = states ? states.length : 0, largestThemeState = 0; while (count--) @@ -642,27 +712,41 @@ CPThemeStateControlSizeMini = CPThemeState("controlSizeMini"); return value; } -- (void)setParentAttribute:(_CPThemeAttribute)anAttribute +- (_CPThemeAttribute)attributeBySettingParentAttribute:(_CPThemeAttribute)anAttribute { if (_themeDefaultAttribute === anAttribute) - return; + return self; - _cache = { }; - _themeDefaultAttribute = anAttribute; + var attribute = [[_CPThemeAttribute alloc] initWithName:_name defaultValue:_defaultValue defaultAttribute:anAttribute]; + + attribute._values = [_values copy]; + + return attribute; } - (_CPThemeAttribute)attributeMergedWithAttribute:(_CPThemeAttribute)anAttribute { - var mergedAttribute = [[_CPThemeAttribute alloc] initWithName:_name defaultValue:_defaultValue]; + var mergedAttribute = [[_CPThemeAttribute alloc] initWithName:_name defaultValue:_defaultValue defaultAttribute:_themeDefaultAttribute]; mergedAttribute._values = [_values copy]; - [mergedAttribute._values addEntriesFromDictionary:anAttribute._values]; + + if (anAttribute._values) + mergedAttribute._values ? [mergedAttribute._values addEntriesFromDictionary:anAttribute._values] : [anAttribute._values copy]; return mergedAttribute; } +- (CPString)description +{ + return [super description] + @" Name: " + _name + @", defaultAttribute: " + _themeDefaultAttribute + @", defaultValue: " + _defaultValue + @", values: " + _values; +} + @end + +// This is used to pass 'parrentAttribute' to the coder +var ParentAttributeForCoder = nil; + @implementation _CPThemeAttribute (CPCoding) - (id)initWithCoder:(CPCoder)aCoder @@ -676,13 +760,16 @@ CPThemeStateControlSizeMini = CPThemeState("controlSizeMini"); _name = [aCoder decodeObjectForKey:@"name"]; _defaultValue = [aCoder decodeObjectForKey:@"defaultValue"]; _values = @{}; + _themeDefaultAttribute = ParentAttributeForCoder; if ([aCoder containsValueForKey:@"value"]) { - var state = String(CPThemeStateNormal); + var state; if ([aCoder containsValueForKey:@"state"]) state = [aCoder decodeObjectForKey:@"state"]; + else + state = CPThemeStateNormalString [_values setObject:[aCoder decodeObjectForKey:"value"] forKey:state]; } @@ -710,7 +797,7 @@ CPThemeStateControlSizeMini = CPThemeState("controlSizeMini"); [aCoder encodeObject:_defaultValue forKey:@"defaultValue"]; var keys = [_values allKeys], - count = keys.length; + count = keys ? keys.length : 0; if (count === 1) { @@ -748,7 +835,7 @@ function CPThemeAttributeEncode(aCoder, aThemeAttribute) { var state = [values allKeys][0]; - if (state === String(CPThemeStateNormal)) + if (state === CPThemeStateNormalString) { [aCoder encodeObject:[values objectForKey:state] forKey:key]; @@ -766,30 +853,24 @@ function CPThemeAttributeEncode(aCoder, aThemeAttribute) return NO; } -function CPThemeAttributeDecode(aCoder, anAttributeName, aDefaultValue, aTheme, aClass) +function CPThemeAttributeDecode(aCoder, attribute) { - var key = "$a" + anAttributeName; + var key = "$a" + attribute._name; - if (![aCoder containsValueForKey:key]) - var attribute = [[_CPThemeAttribute alloc] initWithName:anAttributeName defaultValue:aDefaultValue]; - - else + if ([aCoder containsValueForKey:key]) { - var attribute = [aCoder decodeObjectForKey:key]; + ParentAttributeForCoder = attribute._themeDefaultAttribute; - if (!attribute || !attribute.isa || ![attribute isKindOfClass:[_CPThemeAttribute class]]) - { - var themeAttribute = [[_CPThemeAttribute alloc] initWithName:anAttributeName defaultValue:aDefaultValue]; + var decodedAttribute = [aCoder decodeObjectForKey:key]; - [themeAttribute setValue:attribute]; + ParentAttributeForCoder = nil; - attribute = themeAttribute; - } + if (!decodedAttribute || !decodedAttribute.isa || ![decodedAttribute isKindOfClass:[_CPThemeAttribute class]]) + attribute = [attribute attributeBySettingValue:decodedAttribute]; + else + attribute = decodedAttribute; } - if (aTheme && aClass) - [attribute setParentAttribute:[aTheme attributeWithName:anAttributeName forClass:aClass]]; - return attribute; } diff --git a/AppKit/CPTokenField.j b/AppKit/CPTokenField.j index 3724b20a2..858b11495 100644 --- a/AppKit/CPTokenField.j +++ b/AppKit/CPTokenField.j @@ -1475,9 +1475,6 @@ CPTokenFieldDeleteButtonType = 1; - (BOOL)setThemeState:(ThemeState)aState { - if (aState.isa && [aState isKindOfClass:CPArray]) - aState = CPThemeState.apply(null, aState); - var r = [super setThemeState:aState]; // Share hover state with the disclosure and delete buttons. @@ -1492,9 +1489,6 @@ CPTokenFieldDeleteButtonType = 1; - (BOOL)unsetThemeState:(ThemeState)aState { - if (aState.isa && [aState isKindOfClass:CPArray]) - aState = CPThemeState.apply(null, aState); - var r = [super unsetThemeState:aState]; // Share hover state with the disclosure and delete button. diff --git a/AppKit/CPView.j b/AppKit/CPView.j index 0057c0b89..3041765a7 100644 --- a/AppKit/CPView.j +++ b/AppKit/CPView.j @@ -3386,8 +3386,19 @@ setBoundsOrigin: [self unsetThemeState:CPThemeStateAppearanceVibrantDark]; } - [_subviews makeObjectsPerformSelector:@selector(_recomputeAppearance)]; -} +// var start = [CPDate new]; + + for (var i = 0, size = [_subviews count]; i < size; i++) + { + [[_subviews objectAtIndex:i] _recomputeAppearance]; + } +// [_subviews makeObjectsPerformSelector:@selector(_recomputeAppearance)]; + +/* var now = [CPDate new]; + var elapsedSeconds = [now timeIntervalSinceReferenceDate] - [start timeIntervalSinceReferenceDate]; + + CPLog.trace(@"_recomputeAppearance " + [_subviews count] + " subviews in " + elapsedSeconds + @" seconds"); +*/} @end diff --git a/AppKit/Themes/Aristo2/ThemeDescriptors.j b/AppKit/Themes/Aristo2/ThemeDescriptors.j index aed9a6362..ee6917791 100644 --- a/AppKit/Themes/Aristo2/ThemeDescriptors.j +++ b/AppKit/Themes/Aristo2/ThemeDescriptors.j @@ -326,7 +326,7 @@ var themedButtonValues = nil, var button = [self button]; [button setTitle:@"OK"]; - [button setThemeState:[CPButtonStateBezelStyleRounded, CPThemeStateDefault]]; + [button setThemeStates:[CPButtonStateBezelStyleRounded, CPThemeStateDefault]]; return button; } diff --git a/AppKit/Themes/BlendKit/BKThemeDescriptor.j b/AppKit/Themes/BlendKit/BKThemeDescriptor.j index 801c6e6ae..1512c480e 100644 --- a/AppKit/Themes/BlendKit/BKThemeDescriptor.j +++ b/AppKit/Themes/BlendKit/BKThemeDescriptor.j @@ -232,7 +232,12 @@ var ItemSizes = { }, state = attributeValueState[2]; if (state) - [aView setValue:value forThemeAttribute:attribute inState:state]; + { + if (state.isa && [state isKindOfClass:CPArray]) + [aView setValue:value forThemeAttribute:attribute inStates:state]; + else + [aView setValue:value forThemeAttribute:attribute inState:state]; + } else [aView setValue:value forThemeAttribute:attribute]; } @@ -304,7 +309,12 @@ var ItemSizes = { }, } if (state) - [aView setValue:value forThemeAttribute:attribute inState:state]; + { + if (state.isa && [state isKindOfClass:CPArray]) + [aView setValue:value forThemeAttribute:attribute inStates:state]; + else + [aView setValue:value forThemeAttribute:attribute inState:state]; + } else [aView setValue:value forThemeAttribute:attribute]; } diff --git a/AppKit/_CPAutocompleteMenu.j b/AppKit/_CPAutocompleteMenu.j index cf25c025d..f1b3ecb41 100644 --- a/AppKit/_CPAutocompleteMenu.j +++ b/AppKit/_CPAutocompleteMenu.j @@ -171,9 +171,9 @@ var _CPAutocompleteMenuMaximumHeight = 307; var dataView = [tableColumn dataView], fontNormal = [dataView valueForThemeAttribute:@"font" inState:CPThemeStateTableDataView], - fontSelected = [dataView valueForThemeAttribute:@"font" inState:[CPThemeStateTableDataView, CPThemeStateSelectedDataView]], + fontSelected = [dataView valueForThemeAttribute:@"font" inStates:[CPThemeStateTableDataView, CPThemeStateSelectedDataView]], contentInsetNormal = [dataView valueForThemeAttribute:@"content-inset" inState:CPThemeStateTableDataView], - contentInsetSelected = [dataView valueForThemeAttribute:@"content-inset" inState:[CPThemeStateTableDataView, CPThemeStateSelectedDataView]]; + contentInsetSelected = [dataView valueForThemeAttribute:@"content-inset" inStates:[CPThemeStateTableDataView, CPThemeStateSelectedDataView]]; var mergedString = contentArray.join("\n"); diff --git a/AppKit/_CPObject+Theme.j b/AppKit/_CPObject+Theme.j index e63dfffc2..20f32da85 100644 --- a/AppKit/_CPObject+Theme.j +++ b/AppKit/_CPObject+Theme.j @@ -23,8 +23,6 @@ @import "CPTheme.j" -var CachedThemeAttributes = nil; - var CPViewThemeClassKey = @"CPViewThemeClassKey", CPViewThemeStateKey = @"CPViewThemeStateKey"; @@ -38,8 +36,11 @@ var CPViewThemeClassKey = @"CPViewThemeClassKey", - (unsigned)themeState; - (BOOL)hasThemeState:(ThemeState)aState; +- (BOOL)hasThemeStates:(CPArray)states; - (BOOL)setThemeState:(ThemeState)aState; +- (BOOL)setThemeStates:(CPArray)aState; - (BOOL)unsetThemeState:(ThemeState)aState; +- (BOOL)unsetThemeStates:(CPArray)aState; - (BOOL)hasThemeAttribute:(CPString)aName; - (void)objectDidChangeTheme; @@ -74,31 +75,55 @@ var CPViewThemeClassKey = @"CPViewThemeClassKey", - (BOOL)hasThemeState:(ThemeState)aState { - if (aState.isa && [aState isKindOfClass:CPArray]) - return _themeState.hasThemeState.apply(_themeState, aState); +#if DEBUG +// TODO: To allow aState to be an array is now deprecated. An exception is thrown only in Debug version as +// the preformance cost for this check is to high. We should remove this check in a future release. + if (aState && aState.isa && [aState isKindOfClass:CPArray]) + [CPException raise:CPInvalidArgumentException reason:@"aState can't be an array. Please use 'hasThemeStates: instead: " + aState]; +#endif + + return _themeState.hasThemeState(aState); +} + +- (BOOL)hasThemeStates:(CPArray)states +{ + var i = [states count], + aState = [states objectAtIndex:--i]; + + while (i > 0) + aState = aState.and([states objectAtIndex:--i]); return _themeState.hasThemeState(aState); } - (BOOL)setThemeState:(ThemeState)aState { +#if DEBUG +// TODO: To allow aState to be an array is now deprecated. An exception is thrown only in Debug version as +// the preformance cost for this check is to high. We should remove this check in a future release. if (aState && aState.isa && [aState isKindOfClass:CPArray]) - aState = CPThemeState.apply(null, aState); + [CPException raise:CPInvalidArgumentException reason:@"aState can't be an array. Please use 'setThemeStates: instead: " + aState]; +#endif if (_themeState.hasThemeState(aState)) return NO; - _themeState = CPThemeState(_themeState, aState); + _themeState = _themeState.and(aState); return YES; } - (BOOL)unsetThemeState:(ThemeState)aState { +#if DEBUG +// TODO: To allow aState to be an array is now deprecated. An exception is thrown only in Debug version as +// the preformance cost for this check is to high. We should remove this check in a future release. if (aState && aState.isa && [aState isKindOfClass:CPArray]) - aState = CPThemeState.apply(null, aState); + [CPException raise:CPInvalidArgumentException reason:@"aState can't be an array. Please use 'unsetThemeStates: instead: " + aState]; +#endif var oldThemeState = _themeState; + _themeState = _themeState.without(aState); if (oldThemeState === _themeState) @@ -107,6 +132,28 @@ var CPViewThemeClassKey = @"CPViewThemeClassKey", return YES; } +- (BOOL)setThemeStates:(CPArray)states +{ + var i = [states count], + aState = [states objectAtIndex:--i]; + + while (i > 0) + aState = aState.and([states objectAtIndex:--i]); + + return [self setThemeState:aState]; +} + +- (BOOL)unsetThemeStates:(CPArray)states +{ + var i = [states count], + aState = [states objectAtIndex:--i]; + + while (i > 0) + aState = aState.and([states objectAtIndex:--i]); + + return [self unsetThemeState:aState]; +} + #pragma mark Theme Attributes + (CPString)defaultThemeClass @@ -134,25 +181,30 @@ var CPViewThemeClassKey = @"CPViewThemeClassKey", [self _loadThemeAttributes]; } -+ (CPArray)_themeAttributes -{ - if (!CachedThemeAttributes) - CachedThemeAttributes = {}; +var NULL_THEME = {}; ++ (CPArray)_themeAttributesForTheme:(CPTheme)theme andThemeClass:(CPString)themeClassName +{ var theClass = [self class], - CPObjectClass = [CPObject class], - attributes = [], - nullValue = [CPNull null]; + theClassName = class_getName(theClass), + themeClassNameCache = theme != nil ? theme._cachedThemeAttributes || (theme._cachedThemeAttributes = {}) : NULL_THEME, + themedCacheAttributes = themeClassNameCache[themeClassName] || (themeClassNameCache[themeClassName] = {}), + attributes = themedCacheAttributes[theClassName]; + + if (attributes) + return attributes; + else + attributes = []; + + var CPObjectClass = [CPObject class]; for (; theClass && theClass !== CPObjectClass; theClass = [theClass superclass]) { - var cachedAttributes = CachedThemeAttributes[class_getName(theClass)]; + var cachedAttributes = themedCacheAttributes[class_getName(theClass)]; if (cachedAttributes) { attributes = attributes.length ? attributes.concat(cachedAttributes) : attributes; - CachedThemeAttributes[[self className]] = attributes; - break; } @@ -167,38 +219,34 @@ var CPViewThemeClassKey = @"CPViewThemeClassKey", while (attributeCount--) { var attributeName = attributeKeys[attributeCount], - attributeValue = [attributeDictionary objectForKey:attributeName]; + attributeValue = [attributeDictionary objectForKey:attributeName], + themeAttribute = [[_CPThemeAttribute alloc] initWithName:attributeName defaultValue:attributeValue defaultAttribute:[theme attributeWithName:attributeName forClass:themeClassName]]; - attributes.push(attributeValue === nullValue ? nil : attributeValue); - attributes.push(attributeName); + attributes.push(themeAttribute); } } + themedCacheAttributes[theClassName] = attributes; + return attributes; } - (void)_loadThemeAttributes { var theClass = [self class], - attributes = [theClass _themeAttributes], + attributes = [theClass _themeAttributesForTheme:[self theme] andThemeClass:[self themeClass]], count = attributes.length; if (!count) return; - var theme = [self theme], - themeClass = [self themeClass]; - _themeAttributes = {}; while (count--) { - var attributeName = attributes[count--], - attribute = [[_CPThemeAttribute alloc] initWithName:attributeName defaultValue:attributes[count]]; + var attribute = attributes[count]; - [attribute setParentAttribute:[theme attributeWithName:attributeName forClass:themeClass]]; - - _themeAttributes[attributeName] = attribute; + _themeAttributes[attribute._name] = attribute; } } @@ -228,7 +276,7 @@ var CPViewThemeClassKey = @"CPViewThemeClassKey", for (var attributeName in _themeAttributes) { if (_themeAttributes.hasOwnProperty(attributeName)) - [_themeAttributes[attributeName] setParentAttribute:[theme attributeWithName:attributeName forClass:themeClass]]; + _themeAttributes[attributeName] = [_themeAttributes[attributeName] attributeBySettingParentAttribute:[theme attributeWithName:attributeName forClass:themeClass]]; } } @@ -253,48 +301,96 @@ var CPViewThemeClassKey = @"CPViewThemeClassKey", - (void)setValue:(id)aValue forThemeAttribute:(CPString)aName inState:(ThemeState)aState { - if (aState.isa && [aState isKindOfClass:CPArray]) - aState = CPThemeState.apply(null, aState); +#if DEBUG +// TODO: To allow aState to be an array is now deprecated. An exception is thrown only in Debug version as +// the preformance cost for this check is to high. We should remove this check in a future release. + if (aState.isa && [aState isKindOfClass:CPArray]) + [CPException raise:CPInvalidArgumentException reason:self + @": aState can't be an array. Please use 'setValue:forThemeAttribute:inStates:' instead: " + aState]; +#endif - if (!_themeAttributes || !_themeAttributes[aName]) + var themeAttr = _themeAttributes && _themeAttributes[aName]; + + if (!themeAttr) [CPException raise:CPInvalidArgumentException reason:[self className] + " does not contain theme attribute '" + aName + "'"]; - [_themeAttributes[aName] setValue:aValue forState:aState]; + _themeAttributes[aName] = [themeAttr attributeBySettingValue:aValue forState:aState]; +} + +- (void)setValue:(id)aValue forThemeAttribute:(CPString)aName inStates:(CPArray)states +{ + var i = [states count], + aState = [states objectAtIndex:--i]; + + while (i > 0) + aState = aState.and([states objectAtIndex:--i]); + + var themeAttr = _themeAttributes && _themeAttributes[aName]; + + if (!themeAttr) + [CPException raise:CPInvalidArgumentException reason:[self className] + " does not contain theme attribute '" + aName + "'"]; + + _themeAttributes[aName] = [themeAttr attributeBySettingValue:aValue forState:aState]; } - (void)setValue:(id)aValue forThemeAttribute:(CPString)aName { - if (!_themeAttributes || !_themeAttributes[aName]) + var themeAttr = _themeAttributes && _themeAttributes[aName]; + + if (!themeAttr) [CPException raise:CPInvalidArgumentException reason:[self className] + " does not contain theme attribute '" + aName + "'"]; - [_themeAttributes[aName] setValue:aValue]; + _themeAttributes[aName] = [themeAttr attributeBySettingValue:aValue]; } - (id)valueForThemeAttribute:(CPString)aName inState:(ThemeState)aState { +#if DEBUG if (aState.isa && [aState isKindOfClass:CPArray]) - aState = CPThemeState.apply(null, aState); + [CPException raise:CPInvalidArgumentException reason:@"aState can't be an array. Please use 'valueForThemeAttribute:inStates:' instead: " + aState]; +#endif - if (!_themeAttributes || !_themeAttributes[aName]) + var themeAttr = _themeAttributes && _themeAttributes[aName]; + + if (!themeAttr) [CPException raise:CPInvalidArgumentException reason:[self className] + " does not contain theme attribute '" + aName + "'"]; - return [_themeAttributes[aName] valueForState:aState]; + return [themeAttr valueForState:aState]; +} + +- (id)valueForThemeAttribute:(CPString)aName inStates:(CPArray)states +{ + var i = [states count], + aState = [states objectAtIndex:--i]; + + while (i > 0) + aState = aState.and([states objectAtIndex:--i]); + + var themeAttr = _themeAttributes && _themeAttributes[aName]; + + if (!themeAttr) + [CPException raise:CPInvalidArgumentException reason:[self className] + " does not contain theme attribute '" + aName + "'"]; + + return [themeAttr valueForState:aState]; } - (id)valueForThemeAttribute:(CPString)aName { - if (!_themeAttributes || !_themeAttributes[aName]) + var themeAttr = _themeAttributes && _themeAttributes[aName]; + + if (!themeAttr) [CPException raise:CPInvalidArgumentException reason:[self className] + " does not contain theme attribute '" + aName + "'"]; - return [_themeAttributes[aName] value]; + return [themeAttr value]; } - (id)currentValueForThemeAttribute:(CPString)aName { - if (!_themeAttributes || !_themeAttributes[aName]) + var themeAttr = _themeAttributes && _themeAttributes[aName]; + + if (!themeAttr) [CPException raise:CPInvalidArgumentException reason:[self className] + " does not contain theme attribute '" + aName + "'"]; - return [_themeAttributes[aName] valueForState:_themeState]; + return [themeAttr valueForState:_themeState]; } - (BOOL)hasThemeAttribute:(CPString)aName @@ -320,7 +416,10 @@ var CPViewThemeClassKey = @"CPViewThemeClassKey", state = attributeValueState[2]; if (state) - [self setValue:value forThemeAttribute:attribute inState:state]; + if (state.isa && [state isKindOfClass:CPArray]) + [self setValue:value forThemeAttribute:attribute inStates:state]; + else + [self setValue:value forThemeAttribute:attribute inState:state]; else [self setValue:value forThemeAttribute:attribute]; } @@ -367,14 +466,14 @@ var CPViewThemeClassKey = @"CPViewThemeClassKey", var theClass = [self class], themeClass = [self themeClass], - attributes = [theClass _themeAttributes], + attributes = [theClass _themeAttributesForTheme:_theme andThemeClass:themeClass], count = attributes.length; while (count--) { - var attributeName = attributes[count--]; + var attribute = attributes[count]; - _themeAttributes[attributeName] = CPThemeAttributeDecode(aCoder, attributeName, attributes[count], _theme, themeClass); + _themeAttributes[attribute._name] = CPThemeAttributeDecode(aCoder, attribute); } } diff --git a/Tests/AppKit/CPThemeTest.j b/Tests/AppKit/CPThemeTest.j index e6fc1494c..f0e21e987 100644 --- a/Tests/AppKit/CPThemeTest.j +++ b/Tests/AppKit/CPThemeTest.j @@ -56,20 +56,20 @@ - (void)testThemeAttributeValueForState { - var themeAttribute = [[_CPThemeAttribute alloc] initWithName:@"test" defaultValue:5]; + var themeAttribute = [[_CPThemeAttribute alloc] initWithName:@"test" defaultValue:5 defaultAttribute:nil]; [self assertTrue:([themeAttribute valueForState:CPThemeState("aState")] == 5) message:"Return the default value for the theme attribute if the theme attribute has no value defined for the given state"]; - [themeAttribute setValue:7 forState:CPThemeState("aState")]; + themeAttribute = [themeAttribute attributeBySettingValue:7 forState:CPThemeState("aState")]; [self assertTrue:([themeAttribute valueForState:CPThemeState("aState")] == 7) message:"Return the correct value for the state if the state is defined"]; - [themeAttribute setValue:8 forState:CPThemeState('normal')]; + themeAttribute = [themeAttribute attributeBySettingValue:8 forState:CPThemeState('normal')]; [self assertTrue:([themeAttribute valueForState:CPThemeState("aState1")] == 8) message:"Return the normal value for the state if the theme attribute has no value defined for the given state but has a value for the normal state defined"]; - [themeAttribute setValue:10 forState:CPThemeState('aState3+aState4')]; + themeAttribute = [themeAttribute attributeBySettingValue:10 forState:CPThemeState('aState3+aState4')]; [self assertTrue:([themeAttribute valueForState:CPThemeState("aState3")] == 8) message:"Return the normal value for the state if the state is only a partial match on the theme attributes defined states"]; [self assertTrue:([themeAttribute valueForState:CPThemeState("aState4+aState3")] == 10) message:"Correctly match combined states on the theme attribute"]; - [themeAttribute setValue:9 forState:CPThemeState('aState3')]; + themeAttribute = [themeAttribute attributeBySettingValue:9 forState:CPThemeState('aState3')]; [self assertTrue:([themeAttribute valueForState:CPThemeState("aState8+aState3+aState4")] == 10) message:"Return the largest partial subset match for a combined state that isn't a perfect match"]; } diff --git a/Tests/AppKit/CPViewTest.j b/Tests/AppKit/CPViewTest.j index 9c11b4de5..5131a2fc3 100644 --- a/Tests/AppKit/CPViewTest.j +++ b/Tests/AppKit/CPViewTest.j @@ -69,7 +69,7 @@ var methodCalled; [self assertTrue:[view hasThemeState:CPThemeStateDisabled] message:@"CPView should be in state CPThemeStateDisabled"]; [self assertTrue:[view hasThemeState:CPThemeStateBordered] message:@"CPView should be in state CPThemeStateBordered"]; [self assertTrue:[view hasThemeState:CPThemeState(CPThemeStateBordered, CPThemeStateDisabled)] message:@"CPView should be in the combined state of CPThemeStateDisabled and CPThemeStateBordered"]; - [self assertTrue:[view hasThemeState:[CPThemeStateBordered, CPThemeStateDisabled]] message:@"hasThemeState works with an array argument"]; + [self assertTrue:[view hasThemeStates:[CPThemeStateBordered, CPThemeStateDisabled]] message:@"hasThemeState works with an array argument"]; [self assertFalse:[view hasThemeState:CPThemeState(CPThemeStateNormal)] message:@"CPView should not be in CPThemeStateNormal"]; } @@ -94,7 +94,7 @@ var methodCalled; [self assert:String(CPThemeState(CPThemeStateDisabled, CPThemeStateHighlighted)) equals:String([view themeState]) message:@"The view should be in the combined state of CPThemeStateDisabled and CPThemeStateHighlighted"]; [view unsetThemeState:[view themeState]]; - [view setThemeState:[CPThemeStateSelected, CPThemeStateDisabled]]; + [view setThemeStates:[CPThemeStateSelected, CPThemeStateDisabled]]; [self assert:String(CPThemeState(CPThemeStateDisabled, CPThemeStateSelected)) equals:String([view themeState]) message:@"setThemeState works with array argument"]; } @@ -117,20 +117,20 @@ var methodCalled; [self assert:String(CPThemeStateNormal) equals:String([view themeState]) message:@"CPView should be able to unset a combined theme state"]; [view setThemeState:CPThemeState(CPThemeStateDisabled, CPThemeStateHighlighted, CPThemeStateBordered)]; - [view unsetThemeState:[CPThemeStateBordered, CPThemeStateHighlighted]]; + [view unsetThemeStates:[CPThemeStateBordered, CPThemeStateHighlighted]]; [self assert:String(CPThemeStateDisabled) equals:String([view themeState]) message:@"unsetThemeState works with array argument"]; [view setThemeState:CPThemeStateDisabled]; - [view unsetThemeState:[CPThemeStateDisabled, CPThemeStateHighlighted]]; + [view unsetThemeStates:[CPThemeStateDisabled, CPThemeStateHighlighted]]; [self assert:String(CPThemeStateNormal) equals:String([view themeState]) message:@"CPView should be able to unset a combined theme state that has more theme states than the view currently has"]; [view setThemeState:CPThemeState(CPThemeStateDisabled, CPThemeStateBordered)]; - var returnValue = [view unsetThemeState:[CPThemeStateDisabled, CPThemeStateHighlighted]]; + var returnValue = [view unsetThemeStates:[CPThemeStateDisabled, CPThemeStateHighlighted]]; [self assert:String(CPThemeStateBordered) equals:String([view themeState]) message:@"CPView should be able to unset a combined theme state that has not entirely overlapping themestates"]; [self assertTrue:returnValue message:@"When unsetThemeState successfully unsets anything, it return YES"]; [view setThemeState:CPThemeState(CPThemeStateDisabled, CPThemeStateBordered)]; - var returnValue = [view unsetThemeState:[CPThemeStateSelected, CPThemeStateHighlighted]]; + var returnValue = [view unsetThemeStates:[CPThemeStateSelected, CPThemeStateHighlighted]]; [self assert:String(CPThemeState(CPThemeStateDisabled, CPThemeStateBordered)) equals:String([view themeState]) message:@"CPView not unset any theme states it does not have"]; [self assertFalse:returnValue message:@"When unsetThemeState doesn't unset anything, it returns NO"];