53 + (void)setDefaultHudTheme:(
CPTheme)aTheme
103 - (CPArray)classNames
105 return [_attributes allKeys];
125 if ([aClass isKindOfClass:[
CPString class]])
138 if ([aClass respondsToSelector:
@selector(defaultThemeClass)])
140 className = [aClass defaultThemeClass];
142 else if ([aClass respondsToSelector:
@selector(themeClass)])
144 CPLog.warn(
@"%@ themeClass is deprecated in favor of defaultThemeClass",
CPStringFromClass(aClass));
145 className = [aClass themeClass];
153 return [_attributes objectForKey:className];
177 return [attributes allKeys];
179 return [CPArray array];
195 - (_CPThemeAttribute)attributeWithName:(
CPString)aName forClass:(
id)aClass
202 return [attributes objectForKey:aName];
218 - (id)valueForAttributeWithName:(
CPString)aName forClass:(
id)aClass
243 return [attribute valueForState:aState];
246 - (void)takeThemeFromObject:(
id)anObject
248 var attributes = [anObject _themeAttributeDictionary],
250 attributeNames = [attributes keyEnumerator],
251 objectThemeClass = [anObject themeClass];
253 while ((attributeName = [attributeNames nextObject]) !== nil)
254 [
self _recordAttribute:[attributes objectForKey:attributeName] forClass:objectThemeClass];
257 - (void)_recordAttribute:(_CPThemeAttribute)anAttribute forClass:(
CPString)aClass
259 if (![anAttribute hasValues])
262 var attributes = [_attributes objectForKey:aClass];
268 [_attributes setObject:attributes forKey:aClass];
271 var
name = [anAttribute name],
272 existingAttribute = [attributes objectForKey:name];
274 if (existingAttribute)
275 [attributes setObject:[existingAttribute attributeMergedWithAttribute:anAttribute] forKey:name];
277 [attributes setObject:anAttribute forKey:name];
293 _name = [aCoder decodeObjectForKey:CPThemeNameKey];
294 _attributes = [aCoder decodeObjectForKey:CPThemeAttributesKey];
304 [aCoder encodeObject:_name forKey:CPThemeNameKey];
305 [aCoder encodeObject:_attributes forKey:CPThemeAttributesKey];
311 #pragma mark CSS Theming 336 - (void)setCSSResourcesPath:(
CPString)pathToResources
338 [_attributes enumerateKeysAndObjectsUsingBlock:function(aKey, anObject, stop)
340 [anObject enumerateKeysAndObjectsUsingBlock:function(aKey2, anObject2, stop2)
344 [[anObject2 values] enumerateKeysAndObjectsUsingBlock:function(aKey3, anObject3, stop3)
346 if (anObject3.isa && ([anObject3 isKindOfClass:CPImage] || [anObject3 isKindOfClass:CPColor]) && [anObject3 cssDictionary])
349 [
self _fixPathInCSSDictionary:[anObject3 cssDictionary] withPathToResources:pathToResources];
350 [
self _fixPathInCSSDictionary:[anObject3 cssBeforeDictionary] withPathToResources:pathToResources];
351 [
self _fixPathInCSSDictionary:[anObject3 cssAfterDictionary] withPathToResources:pathToResources];
358 - (void)_fixPathInCSSDictionary:(
CPDictionary)aDictionary withPathToResources:(
CPString)pathToResources
362 [aDictionary
setObject:[anObject stringByReplacingOccurrencesOfString:@"%%" withString:pathToResources]
forKey:aKey];
381 var stateNameKeys = [];
382 this._stateNames = {};
384 for (var key in stateNames)
386 if (!stateNames.hasOwnProperty(key))
389 if (key !==
'normal')
391 this._stateNames[key] =
true;
392 stateNameKeys.push(key);
396 if (stateNameKeys.length === 0)
398 stateNameKeys.push(
'normal');
399 this._stateNames['normal'] =
true;
402 stateNameKeys.sort();
403 this._stateNameString = stateNameKeys[0];
405 var stateNameLength = stateNameKeys.length;
407 for (var stateIndex = 1; stateIndex < stateNameLength; stateIndex++)
408 this._stateNameString = this._stateNameString +
"+" + stateNameKeys[stateIndex];
410 this._stateNameCount = stateNameLength;
415 return this._stateNameString;
418 ThemeState.prototype.hasThemeState =
function(aState)
420 if (!aState || !aState._stateNames)
424 for (var stateName in aState._stateNames)
426 if (!aState._stateNames.hasOwnProperty(stateName))
429 if (!this._stateNames[stateName])
435 ThemeState.prototype.isSubsetOf =
function(aState)
437 if (aState._stateNameCount <
this._stateNameCount)
440 for (var key in this._stateNames)
442 if (!this._stateNames.hasOwnProperty(key))
445 if (!aState._stateNames[key])
451 ThemeState.prototype.without =
function(aState)
453 if (!aState || aState === [
CPNull null])
461 result = firstTransform[aState._stateNameString];
469 for (var stateName in this._stateNames)
471 if (!this._stateNames.hasOwnProperty(stateName))
474 if (!aState._stateNames[stateName])
475 newStates[stateName] =
true;
483 firstTransform[aState._stateNameString] = result;
495 result = firstTransform[aState._stateNameString];
501 result = CPThemeState(
this, aState);
506 firstTransform[aState._stateNameString] = result;
511 var CPThemeStates = {},
515 ThemeState._cacheThemeState =
function(aState)
518 var themeState = CPThemeStates[String(aState)];
520 if (themeState === undefined)
523 CPThemeStates[String(themeState)] = themeState;
537 function CPThemeState()
539 if (arguments.length < 1)
540 throw "CPThemeState() must be called with at least one string argument";
544 if (arguments.length === 1 && typeof arguments[0] ===
'string')
546 themeState = CPThemeStates[arguments[0]];
548 if (themeState !== undefined)
554 for (var argIndex = 0; argIndex < arguments.length; argIndex++)
556 if (arguments[argIndex] === [
CPNull null] || !arguments[argIndex])
559 if (typeof arguments[argIndex] ===
'object')
561 for (var stateName in arguments[argIndex]._stateNames)
563 if (!arguments[argIndex]._stateNames.hasOwnProperty(stateName))
566 stateNames[stateName] =
true;
571 var allNames = arguments[argIndex].split(
'+');
573 for (var nameIndex = 0; nameIndex < allNames.length; nameIndex++)
574 stateNames[allNames[nameIndex]] = true;
587 - (id)initForReadingWithData:(
CPData)data bundle:(
CPBundle)aBundle
589 self = [
super initForReadingWithData:data];
602 - (BOOL)awakenCustomResources
609 CPThemeStateNormal = CPThemeState(
"normal");
635 @implementation _CPThemeAttribute :
CPObject 642 _CPThemeAttribute _themeDefaultAttribute;
645 - (id)initWithName:(
CPString)aName defaultValue:(
id)aDefaultValue defaultAttribute:(_CPThemeAttribute)aDefaultAttribute
653 _defaultValue = aDefaultValue;
655 if (aDefaultAttribute)
656 _themeDefaultAttribute = aDefaultAttribute;
669 return _defaultValue;
674 return [_values count] > 0;
677 - (_CPThemeAttribute)attributeBySettingValue:(
id)aValue
679 var attribute = [[_CPThemeAttribute alloc] initWithName:_name defaultValue:_defaultValue defaultAttribute:_themeDefaultAttribute];
681 if (aValue !== undefined && aValue !== nil)
687 - (_CPThemeAttribute)attributeBySettingValue:(
id)aValue forState:(
ThemeState)aState
689 var shouldRemoveValue = aValue === undefined || aValue === nil,
690 attribute = [[_CPThemeAttribute alloc] initWithName:_name defaultValue:_defaultValue defaultAttribute:_themeDefaultAttribute],
695 values = [values copy];
697 if (shouldRemoveValue)
698 [values removeObjectForKey:String(aState)];
700 [values setObject:aValue forKey:String(aState)];
702 attribute._values = values;
704 else if (!shouldRemoveValue)
707 [values setObject:aValue forKey:String(aState)];
708 attribute._values = values;
716 return [
self valueForState:CPThemeStateNormal];
722 var stateName = String(aState),
723 value = _cache[stateName];
726 if (value !== undefined)
730 value = [_values objectForKey:stateName];
732 if ((value !== undefined) && (value !== nil))
733 return _cache[stateName] = value;
737 if (aState._stateNameCount > 1)
739 var largestThemeState = [
self largestThemeStateMatchForState:aState returnedValue:@ref(value)];
741 if ((value !== undefined) && (value !== nil))
742 return _cache[stateName] = value;
746 value = [_values objectForKey:String(CPThemeStateNormal)];
748 if ((value !== undefined) && (value !== nil))
749 return _cache[stateName] = value;
752 value = [_themeDefaultAttribute valueForState:aState];
754 if ((value !== undefined) && (value !== nil))
755 return _cache[stateName] = value;
758 value = _defaultValue;
762 if (value === [
CPNull null])
765 return _cache[stateName] = value;
768 - (CPInteger)largestThemeStateMatchForState:(
ThemeState)aState returnedValue:(
id)valueRef
770 var stateName = String(aState),
772 states = [_values allKeys],
773 count = states ? states.length : 0,
774 largestThemeState = 0;
778 var stateObject = CPThemeState(states[count]);
780 if (stateObject.isSubsetOf(aState) && stateObject._stateNameCount > largestThemeState)
782 value = [_values objectForKey:states[count]];
783 largestThemeState = stateObject._stateNameCount;
788 var defaultAttributeFoundValue,
789 defaultAttributeMatchLength = [_themeDefaultAttribute largestThemeStateMatchForState:aState returnedValue:@ref(defaultAttributeFoundValue)];
791 if (defaultAttributeMatchLength > largestThemeState)
793 value = defaultAttributeFoundValue;
794 largestThemeState = defaultAttributeMatchLength;
797 @deref(valueRef) = value;
798 return largestThemeState;
801 - (_CPThemeAttribute)attributeBySettingParentAttribute:(_CPThemeAttribute)anAttribute
803 if (_themeDefaultAttribute === anAttribute)
806 var attribute = [[_CPThemeAttribute alloc] initWithName:_name defaultValue:_defaultValue defaultAttribute:anAttribute];
808 attribute._values = [_values copy];
813 - (_CPThemeAttribute)attributeMergedWithAttribute:(_CPThemeAttribute)anAttribute
815 var mergedAttribute = [[_CPThemeAttribute alloc] initWithName:_name defaultValue:_defaultValue defaultAttribute:_themeDefaultAttribute];
817 mergedAttribute._values = [_values copy];
819 if (anAttribute._values)
820 mergedAttribute._values ? [mergedAttribute._values addEntriesFromDictionary:anAttribute._values] : [anAttribute._values copy];
822 return mergedAttribute;
827 return [
super description] +
@" Name: " + _name +
@", defaultAttribute: " + _themeDefaultAttribute +
@", defaultValue: " + _defaultValue +
@", values: " + _values;
836 @implementation _CPThemeAttribute (CPCoding)
838 - (id)initWithCoder:(
CPCoder)aCoder
846 _name = [aCoder decodeObjectForKey:@"name"];
847 _defaultValue = [aCoder decodeObjectForKey:@"defaultValue"];
851 if ([aCoder containsValueForKey:
@"value"])
855 if ([aCoder containsValueForKey:
@"state"])
856 state = [aCoder decodeObjectForKey:@"state"];
860 [_values setObject:[aCoder decodeObjectForKey:"value"] forKey:state];
864 var encodedValues = [aCoder decodeObjectForKey:@"values"],
865 keys = [encodedValues allKeys],
870 var key = keys[count];
872 [_values setObject:[encodedValues objectForKey:key] forKey:key];
880 - (void)encodeWithCoder:(
CPCoder)aCoder
882 [aCoder encodeObject:_name forKey:@"name"];
883 [aCoder encodeObject:_defaultValue forKey:@"defaultValue"];
885 var keys = [_values allKeys],
886 count = keys ? keys.length : 0;
890 var onlyKey = keys[0];
892 if (onlyKey !== String(CPThemeStateNormal))
893 [aCoder encodeObject:onlyKey forKey:@"state"];
895 [aCoder encodeObject:[_values objectForKey:onlyKey] forKey:@"value"];
899 var encodedValues = @{};
903 var key = keys[count];
905 [encodedValues setObject:[_values objectForKey:key] forKey:key];
908 [aCoder encodeObject:encodedValues forKey:@"values"];
916 var values = aThemeAttribute._values,
917 count = [values count],
918 key =
"$a" + [aThemeAttribute name];
922 var state = [values allKeys][0];
926 [aCoder encodeObject:[values objectForKey:state] forKey:key];
934 [aCoder encodeObject:aThemeAttribute forKey:key];
944 var key =
"$a" + attribute._name;
946 if ([aCoder containsValueForKey:key])
950 var decodedAttribute = [aCoder decodeObjectForKey:key];
954 if (!decodedAttribute || !decodedAttribute.isa || ![decodedAttribute isKindOfClass:[_CPThemeAttribute
class]])
955 attribute = [attribute attributeBySettingValue:decodedAttribute];
957 attribute = decodedAttribute;
function CPStringFromClass(aClass)
CPThemeStateControlSizeMini
An object representation of nil.
ThemeState prototype CPThemeWithoutTransform
id valueForAttributeWithName:inState:forClass:(CPString aName, [inState] ThemeState aState, [forClass] id aClass)
CPThemeStateAutocompleting
A Cappuccino wrapper for any data type.
Unarchives objects created using CPKeyedArchiver.
A mutable key-value pair collection.
function ThemeState(stateNames)
var CPThemeDefaultHudTheme
CPThemeStateTableDataView
An immutable string (collection of characters).
function CPThemeAttributeDecode(aCoder, attribute)
_CPThemeAttribute attributeWithName:forClass:(CPString aName, [forClass] id aClass)
CPThemeStateSelectedDataView
function CPThemeAttributeEncode(aCoder, aThemeAttribute)
CPDictionary attributesForClass:(id aClass)
Defines methods for use when archiving & restoring (enc/decoding).
CPThemeStateFirstResponder
void enumerateKeysAndObjectsUsingBlock:(Function/*(id aKey, id anObject, @ref BOOL stop) */aFunction)
CPTheme themeNamed:(CPString aName)
var ParentAttributeForCoder
CPThemeStateControlSizeSmall
CPThemeStateControlSizeRegular
ThemeState prototype CPThemeAndTransform
id valueForAttributeWithName:forClass:(CPString aName, [forClass] id aClass)
void setObject:forKey:(id anObject, [forKey] id aKey)
function CPClassFromString(aClassName)
FrameUpdater prototype description