54 + (void)setDefaultHudTheme:(
CPTheme)aTheme
104 - (CPArray)classNames
106 return [_attributes allKeys];
126 if ([aClass isKindOfClass:[
CPString class]])
139 if ([aClass isKindOfClass:[
CPView class]])
141 if ([aClass respondsToSelector:
@selector(defaultThemeClass)])
142 className = [aClass defaultThemeClass];
143 else if ([aClass respondsToSelector:
@selector(themeClass)])
145 CPLog.warn(
@"%@ themeClass is deprecated in favor of defaultThemeClass",
CPStringFromClass(aClass));
146 className = [aClass themeClass];
155 return [_attributes objectForKey:className];
179 return [attributes allKeys];
181 return [CPArray array];
197 - (_CPThemeAttribute)attributeWithName:(
CPString)aName forClass:(
id)aClass
204 return [attributes objectForKey:aName];
220 - (id)valueForAttributeWithName:(
CPString)aName forClass:(
id)aClass
245 return [attribute valueForState:aState];
248 - (void)takeThemeFromObject:(
id)anObject
250 var attributes = [anObject _themeAttributeDictionary],
252 attributeNames = [attributes keyEnumerator],
253 objectThemeClass = [anObject themeClass];
255 while ((attributeName = [attributeNames nextObject]) !== nil)
256 [
self _recordAttribute:[attributes objectForKey:attributeName] forClass:objectThemeClass];
259 - (void)_recordAttribute:(_CPThemeAttribute)anAttribute forClass:(
CPString)aClass
261 if (![anAttribute hasValues])
264 var attributes = [_attributes objectForKey:aClass];
270 [_attributes setObject:attributes forKey:aClass];
273 var
name = [anAttribute name],
274 existingAttribute = [attributes objectForKey:name];
276 if (existingAttribute)
277 [attributes setObject:[existingAttribute attributeMergedWithAttribute:anAttribute] forKey:name];
279 [attributes setObject:anAttribute forKey:name];
295 _name = [aCoder decodeObjectForKey:CPThemeNameKey];
296 _attributes = [aCoder decodeObjectForKey:CPThemeAttributesKey];
306 [aCoder encodeObject:_name forKey:CPThemeNameKey];
307 [aCoder encodeObject:_attributes forKey:CPThemeAttributesKey];
318 var stateNameKeys = [];
319 this._stateNames = {};
321 for (key in stateNames)
323 if (!stateNames.hasOwnProperty(key))
325 if (key !==
'normal')
327 this._stateNames[key] =
true;
328 stateNameKeys.push(key);
332 if (stateNameKeys.length === 0)
334 stateNameKeys.push(
'normal');
335 this._stateNames['normal'] =
true;
338 stateNameKeys.sort();
339 this._stateNameString = stateNameKeys[0];
341 var stateNameLength = stateNameKeys.length;
342 for (var stateIndex = 1; stateIndex < stateNameLength; stateIndex++)
343 this._stateNameString = this._stateNameString +
"+" + stateNameKeys[stateIndex];
344 this._stateNameCount = stateNameLength;
349 return this._stateNameString;
352 ThemeState.prototype.hasThemeState =
function(aState)
354 if (!aState || !aState._stateNames)
358 for (var stateName in aState._stateNames)
360 if (!aState._stateNames.hasOwnProperty(stateName))
363 if (!this._stateNames[stateName])
369 ThemeState.prototype.isSubsetOf =
function(aState)
371 if (aState._stateNameCount <
this._stateNameCount)
374 for (var key in this._stateNames)
376 if (!this._stateNames.hasOwnProperty(key))
379 if (!aState._stateNames[key])
385 ThemeState.prototype.without =
function(aState)
387 if (!aState || aState === [
CPNull null])
391 for (var stateName in this._stateNames)
393 if (!this._stateNames.hasOwnProperty(stateName))
396 if (!aState._stateNames[stateName])
397 newStates[stateName] =
true;
405 return CPThemeState(
this, aState);
408 var CPThemeStates = {};
410 ThemeState._cacheThemeState =
function(aState)
413 var themeState = CPThemeStates[String(aState)];
414 if (themeState === undefined)
417 CPThemeStates[String(themeState)] = themeState;
430 function CPThemeState()
432 if (arguments.length < 1)
433 throw "CPThemeState() must be called with at least one string argument";
436 if (arguments.length === 1 && typeof arguments[0] ===
'string')
438 themeState = CPThemeStates[arguments[0]];
439 if (themeState !== undefined)
444 for (var argIndex = 0; argIndex < arguments.length; argIndex++)
446 if (arguments[argIndex] === [
CPNull null] || !arguments[argIndex])
449 if (typeof arguments[argIndex] ===
'object')
451 for (var stateName in arguments[argIndex]._stateNames)
453 if (!arguments[argIndex]._stateNames.hasOwnProperty(stateName))
455 stateNames[stateName] =
true;
460 var allNames = arguments[argIndex].split(
'+');
461 for (var nameIndex = 0; nameIndex < allNames.length; nameIndex++)
462 stateNames[allNames[nameIndex]] = true;
475 - (id)initForReadingWithData:(
CPData)data bundle:(
CPBundle)aBundle
477 self = [
super initForReadingWithData:data];
490 - (BOOL)awakenCustomResources
497 CPThemeStateNormal = CPThemeState(
"normal");
520 @implementation _CPThemeAttribute :
CPObject
527 _CPThemeAttribute _themeDefaultAttribute;
530 - (id)initWithName:(
CPString)aName defaultValue:(
id)aDefaultValue
538 _defaultValue = aDefaultValue;
552 return _defaultValue;
557 return [_values count] > 0;
560 - (void)setValue:(
id)aValue
564 if (aValue === undefined || aValue === nil)
567 _values = @{ String(CPThemeStateNormal): aValue };
570 - (void)setValue:(
id)aValue forState:(
ThemeState)aState
574 if ((aValue === undefined) || (aValue === nil))
575 [_values removeObjectForKey:String(aState)];
577 [_values setObject:aValue forKey:String(aState)];
582 return [
self valueForState:CPThemeStateNormal];
587 var stateName = String(aState),
588 value = _cache[stateName];
591 if (value !== undefined)
594 value = [_values objectForKey:stateName];
596 if (value === undefined || value === nil)
599 if (aState._stateNameCount > 1)
601 var states = [_values allKeys],
602 count = states.length,
603 largestThemeState = 0;
607 var stateObject = CPThemeState(states[count]);
609 if (stateObject.isSubsetOf(aState) && stateObject._stateNameCount > largestThemeState)
611 value = [_values objectForKey:states[count]];
612 largestThemeState = stateObject._stateNameCount;
618 if (value === undefined || value === nil)
619 value = [_values objectForKey:String(CPThemeStateNormal)];
622 if (value === undefined || value === nil)
623 value = [_themeDefaultAttribute valueForState:aState];
625 if (value === undefined || value === nil)
627 value = _defaultValue;
631 if (value === [
CPNull null])
635 _cache[stateName] = value;
640 - (void)setParentAttribute:(_CPThemeAttribute)anAttribute
642 if (_themeDefaultAttribute === anAttribute)
646 _themeDefaultAttribute = anAttribute;
649 - (_CPThemeAttribute)attributeMergedWithAttribute:(_CPThemeAttribute)anAttribute
651 var mergedAttribute = [[_CPThemeAttribute alloc] initWithName:_name defaultValue:_defaultValue];
653 mergedAttribute._values = [_values copy];
654 [mergedAttribute._values addEntriesFromDictionary:anAttribute._values];
656 return mergedAttribute;
661 @implementation _CPThemeAttribute (CPCoding)
663 - (id)initWithCoder:(
CPCoder)aCoder
671 _name = [aCoder decodeObjectForKey:@"name"];
672 _defaultValue = [aCoder decodeObjectForKey:@"defaultValue"];
675 if ([aCoder containsValueForKey:
@"value"])
677 var state = String(CPThemeStateNormal);
679 if ([aCoder containsValueForKey:
@"state"])
680 state = [aCoder decodeObjectForKey:@"state"];
682 [_values setObject:[aCoder decodeObjectForKey:"value"] forKey:state];
686 var encodedValues = [aCoder decodeObjectForKey:@"values"],
687 keys = [encodedValues allKeys],
692 var key = keys[count];
694 [_values setObject:[encodedValues objectForKey:key] forKey:key];
702 - (void)encodeWithCoder:(
CPCoder)aCoder
704 [aCoder encodeObject:_name forKey:@"name"];
705 [aCoder encodeObject:_defaultValue forKey:@"defaultValue"];
707 var keys = [_values allKeys],
712 var onlyKey = keys[0];
714 if (onlyKey !== String(CPThemeStateNormal))
715 [aCoder encodeObject:onlyKey forKey:@"state"];
717 [aCoder encodeObject:[_values objectForKey:onlyKey] forKey:@"value"];
721 var encodedValues = @{};
725 var key = keys[count];
727 [encodedValues setObject:[_values objectForKey:key] forKey:key];
730 [aCoder encodeObject:encodedValues forKey:@"values"];
738 var values = aThemeAttribute._values,
739 count = [values count],
740 key =
"$a" + [aThemeAttribute name];
744 var state = [values allKeys][0];
746 if (state === String(CPThemeStateNormal))
748 [aCoder encodeObject:[values objectForKey:state] forKey:key];
756 [aCoder encodeObject:aThemeAttribute forKey:key];
766 var key =
"$a" + anAttributeName;
768 if (![aCoder containsValueForKey:key])
769 var attribute = [[_CPThemeAttribute alloc] initWithName:anAttributeName defaultValue:aDefaultValue];
773 var attribute = [aCoder decodeObjectForKey:key];
775 if (!attribute || !attribute.isa || ![attribute isKindOfClass:[_CPThemeAttribute
class]])
777 var themeAttribute = [[_CPThemeAttribute alloc] initWithName:anAttributeName defaultValue:aDefaultValue];
779 [themeAttribute setValue:attribute];
781 attribute = themeAttribute;
785 if (aTheme && aClass)