54 + (void)setDefaultHudTheme:(
CPTheme)aTheme
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([anObject
class]));
146 className = [aClass themeClass];
155 return [_attributes objectForKey:className];
179 return [attributes allKeys];
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];
317 - (id)initForReadingWithData:(
CPData)data bundle:(
CPBundle)aBundle
319 self = [
super initForReadingWithData:data];
332 - (BOOL)awakenCustomResources
347 if (state === undefined)
349 if (aStateName.indexOf(
'+') === -1)
354 states = aStateName.split(
'+'),
355 count = states.length;
359 var stateName = states[count],
362 if (individualState === undefined)
369 state |= individualState;
384 if (name !== undefined)
387 if (!(aState & (aState - 1)))
393 for (; state < aState; state <<= 1)
422 @implementation _CPThemeAttribute :
CPObject
429 _CPThemeAttribute _parentAttribute;
432 - (id)initWithName:(
CPString)aName defaultValue:(
id)aDefaultValue
440 _defaultValue = aDefaultValue;
454 return _defaultValue;
459 return [_values count] > 0;
464 return ([_values count] === 1) && (Number([_values allKeys][0]) ===
CPThemeStateNormal);
467 - (void)setValue:(
id)aValue
471 if (aValue === undefined || aValue === nil)
477 - (void)setValue:(
id)aValue forState:(
CPThemeState)aState
481 if ((aValue === undefined) || (aValue === nil))
482 [_values removeObjectForKey:String(aState)];
484 [_values setObject:aValue forKey:String(aState)];
489 return [
self valueForState:CPThemeStateNormal];
494 var value = _cache[aState];
497 if (value !== undefined)
500 value = [_values objectForKey:String(aState)];
506 if (aState & (aState - 1))
508 var highestOneCount = 0,
509 states = [_values allKeys],
510 count = states.length;
515 var state = Number(states[count]);
518 if ((state & aState) === state)
522 if (oneCount === undefined)
525 if (oneCount > highestOneCount)
527 highestOneCount = oneCount;
528 value = [_values objectForKey:String(state)];
535 if (value === undefined || value === nil)
536 value = [_values objectForKey:String(CPThemeStateNormal)];
539 if (value === undefined || value === nil)
540 value = [_parentAttribute valueForState:aState];
542 if (value === undefined || value === nil)
543 value = _defaultValue;
545 _cache[aState] = value;
550 - (void)setParentAttribute:(_CPThemeAttribute)anAttribute
552 if (_parentAttribute === anAttribute)
556 _parentAttribute = anAttribute;
559 - (_CPThemeAttribute)attributeMergedWithAttribute:(_CPThemeAttribute)anAttribute
561 var mergedAttribute = [[_CPThemeAttribute alloc] initWithName:_name defaultValue:_defaultValue];
563 mergedAttribute._values = [_values copy];
564 [mergedAttribute._values addEntriesFromDictionary:anAttribute._values];
566 return mergedAttribute;
571 @implementation _CPThemeAttribute (CPCoding)
573 - (id)initWithCoder:(
CPCoder)aCoder
581 _name = [aCoder decodeObjectForKey:@"name"];
582 _defaultValue = [aCoder decodeObjectForKey:@"defaultValue"];
585 if ([aCoder containsValueForKey:
@"value"])
589 if ([aCoder containsValueForKey:
@"state"])
590 state =
CPThemeState([aCoder decodeObjectForKey:
@"state"]);
592 [_values setObject:[aCoder decodeObjectForKey:"value"] forKey:state];
596 var encodedValues = [aCoder decodeObjectForKey:@"values"],
597 keys = [encodedValues allKeys],
602 var key = keys[count];
604 [_values setObject:[encodedValues objectForKey:key] forKey:CPThemeState(key)];
612 - (void)encodeWithCoder:(
CPCoder)aCoder
614 [aCoder encodeObject:_name forKey:@"name"];
615 [aCoder encodeObject:_defaultValue forKey:@"defaultValue"];
617 var keys = [_values allKeys],
622 var onlyKey = keys[0];
625 [aCoder encodeObject:CPThemeStateName(Number(onlyKey)) forKey:@"state"];
627 [aCoder encodeObject:[_values objectForKey:onlyKey] forKey:@"value"];
635 var key = keys[count];
637 [encodedValues setObject:[_values objectForKey:key] forKey:CPThemeStateName(Number(key))];
640 [aCoder encodeObject:encodedValues forKey:@"values"];
647 3 , 1 , 2 , 2 , 3 , 2 , 3 ,
648 3 , 4 , 1 , 2 , 2 , 3 , 2 ,
649 3 , 3 , 4 , 2 , 3 , 3 , 4 ,
650 3 , 4 , 4 , 5 , 1 , 2 , 2 ,
651 3 , 2 , 3 , 3 , 4 , 2 , 3 ,
652 3 , 4 , 3 , 4 , 4 , 5 , 2 ,
653 3 , 3 , 4 , 3 , 4 , 4 , 5 ,
654 3 , 4 , 4 , 5 , 4 , 5 , 5 ,
665 aNumber &= (aNumber - 1);
677 var values = aThemeAttribute._values,
678 count = [values count],
679 key =
"$a" + [aThemeAttribute name];
683 var state = [values allKeys][0];
685 if (Number(state) === 0)
687 [aCoder encodeObject:[values objectForKey:state] forKey:key];
695 [aCoder encodeObject:aThemeAttribute forKey:key];
705 var key =
"$a" + anAttributeName;
707 if (![aCoder containsValueForKey:key])
708 var attribute = [[_CPThemeAttribute alloc] initWithName:anAttributeName defaultValue:aDefaultValue];
712 var attribute = [aCoder decodeObjectForKey:key];
714 if (!attribute.isa || ![attribute isKindOfClass:[_CPThemeAttribute
class]])
716 var themeAttribute = [[_CPThemeAttribute alloc] initWithName:anAttributeName defaultValue:aDefaultValue];
718 [themeAttribute setValue:attribute];
720 attribute = themeAttribute;
724 if (aTheme && aClass)