/AppKit/CPTheme.j

http://github.com/cacaodev/cappuccino · Unknown · 826 lines · 658 code · 168 blank · 0 comment · 0 complexity · 1351dd3d497dce175bec78205625c8c9 MD5 · raw file

  1. /*
  2. * CPTheme.j
  3. * AppKit
  4. *
  5. * Created by Francisco Tolmasky.
  6. * Copyright 2009, 280 North, Inc.
  7. *
  8. * This library is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU Lesser General Public
  10. * License as published by the Free Software Foundation; either
  11. * version 2.1 of the License, or (at your option) any later version.
  12. *
  13. * This library is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. * Lesser General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with this library; if not, write to the Free Software
  20. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  21. */
  22. @import <Foundation/CPObject.j>
  23. @import <Foundation/CPMutableArray.j>
  24. @import <Foundation/CPString.j>
  25. @import <Foundation/CPKeyedUnarchiver.j>
  26. @class CPView
  27. @class _CPThemeAttribute
  28. var CPThemesByName = { },
  29. CPThemeDefaultTheme = nil,
  30. CPThemeDefaultHudTheme = nil;
  31. /*!
  32. @ingroup appkit
  33. */
  34. @implementation CPTheme : CPObject
  35. {
  36. CPString _name;
  37. CPDictionary _attributes;
  38. }
  39. + (void)setDefaultTheme:(CPTheme)aTheme
  40. {
  41. CPThemeDefaultTheme = aTheme;
  42. }
  43. + (CPTheme)defaultTheme
  44. {
  45. return CPThemeDefaultTheme;
  46. }
  47. /*!
  48. Set the default HUD theme. If set to nil, the default described in defaultHudTheme
  49. will be used.
  50. */
  51. + (void)setDefaultHudTheme:(CPTheme)aTheme
  52. {
  53. CPThemeDefaultHudTheme = aTheme;
  54. }
  55. /*!
  56. The default HUD theme is (sometimes) used for windows with the CPHUDBackgroundWindowMask
  57. style mask. The default is theme with the name of the default theme with -HUD appended
  58. at the end.
  59. */
  60. + (CPTheme)defaultHudTheme
  61. {
  62. if (!CPThemeDefaultHudTheme)
  63. CPThemeDefaultHudTheme = [CPTheme themeNamed:[[self defaultTheme] name] + "-HUD"];
  64. return CPThemeDefaultHudTheme;
  65. }
  66. + (CPTheme)themeNamed:(CPString)aName
  67. {
  68. return CPThemesByName[aName];
  69. }
  70. - (id)initWithName:(CPString)aName
  71. {
  72. self = [super init];
  73. if (self)
  74. {
  75. _name = aName;
  76. _attributes = @{};
  77. CPThemesByName[_name] = self;
  78. }
  79. return self;
  80. }
  81. - (CPString)name
  82. {
  83. return _name;
  84. }
  85. /*!
  86. Returns an array of names of themed classes defined in this theme, as found in its
  87. ThemeDescriptors.j file.
  88. NOTE: The names are not class names (such as "CPButton"), but the names returned
  89. by the class' +defaultThemeClass method. For example, the name for CPCheckBox is "check-box",
  90. as defined in CPCheckBox::themeClass.
  91. */
  92. - (CPArray)classNames
  93. {
  94. return [_attributes allKeys];
  95. }
  96. /*!
  97. Returns a dictionary of all theme attributes defined for the given class, as found in the
  98. theme's ThemeDescriptors.j file. The keys of the dictionary are attribute names, and the values
  99. are instances of _CPThemeAttribute.
  100. For a description of valid values for \c aClass, see \ref attributeNamesForClass:.
  101. @param aClass The themed class whose attributes you want to retrieve
  102. @return A dictionary of attributes or nil
  103. */
  104. - (CPDictionary)attributesForClass:(id)aClass
  105. {
  106. if (!aClass)
  107. return nil;
  108. var className = nil;
  109. if ([aClass isKindOfClass:[CPString class]])
  110. {
  111. // See if it is a class name
  112. var theClass = CPClassFromString(aClass);
  113. if (theClass)
  114. aClass = theClass;
  115. else
  116. className = aClass;
  117. }
  118. if (!className)
  119. {
  120. if ([aClass isKindOfClass:[CPView class]])
  121. {
  122. if ([aClass respondsToSelector:@selector(defaultThemeClass)])
  123. className = [aClass defaultThemeClass];
  124. else if ([aClass respondsToSelector:@selector(themeClass)])
  125. {
  126. CPLog.warn(@"%@ themeClass is deprecated in favor of defaultThemeClass", CPStringFromClass(aClass));
  127. className = [aClass themeClass];
  128. }
  129. else
  130. return nil;
  131. }
  132. else
  133. [CPException raise:CPInvalidArgumentException reason:@"aClass must be a class object or a string."];
  134. }
  135. return [_attributes objectForKey:className];
  136. }
  137. /*!
  138. Returns an array of names of all theme attributes defined for the given class, as found in the
  139. theme's ThemeDescriptors.j file.
  140. The \c aClass parameter can be one of the following:
  141. - A class instance, for example the result of [CPCheckBox class]. The class must be a subclass
  142. of CPView.
  143. - A class name, for example "CPCheckBox".
  144. - A themed class name, for example "check-box".
  145. If \c aClass does not refer to a themed class in this theme, nil is returned.
  146. @param aClass The themed class whose attributes you want to retrieve
  147. @return An array of attribute names or nil
  148. */
  149. - (CPDictionary)attributeNamesForClass:(id)aClass
  150. {
  151. var attributes = [self attributesForClass:aClass];
  152. if (attributes)
  153. return [attributes allKeys];
  154. else
  155. return [CPArray array];
  156. }
  157. /*!
  158. Returns a theme attribute defined for the given class, as found in the
  159. theme's ThemeDescriptors.j file.
  160. \c aName should be the attribute name as you would pass to the method
  161. CPView::valueForThemeAttribute:.
  162. For a description of valid values for \c aClass, see \ref attributeNamesForClass:.
  163. @param aName The name of the attribute you want to retrieve
  164. @param aClass The themed class in which to look for the attribute
  165. @return An instance of _CPThemeAttribute or nil
  166. */
  167. - (_CPThemeAttribute)attributeWithName:(CPString)aName forClass:(id)aClass
  168. {
  169. var attributes = [self attributesForClass:aClass];
  170. if (!attributes)
  171. return nil;
  172. return [attributes objectForKey:aName];
  173. }
  174. /*!
  175. Returns the value for a theme attribute in its normal state, as defined for the given class
  176. in the theme's ThemeDescriptors.j file.
  177. \c aName should be the attribute name as you would pass to the method
  178. CPView::valueForThemeAttribute:.
  179. For a description of valid values for \c aClass, see \ref attributeNamesForClass:.
  180. @param aName The name of the attribute whose value you want to retrieve
  181. @param aClass The themed class in which to look for the attribute
  182. @return A value or nil
  183. */
  184. - (id)valueForAttributeWithName:(CPString)aName forClass:(id)aClass
  185. {
  186. return [self valueForAttributeWithName:aName inState:CPThemeStateNormal forClass:aClass];
  187. }
  188. /*!
  189. Returns the value for a theme attribute in a given state, as defined for the given class
  190. in the theme's ThemeDescriptors.j file. This is the equivalent of the method
  191. CPView::valueForThemeAttribute:inState:, but retrieves the value from the theme definition as
  192. opposed to a single view's current theme state.
  193. For a description of valid values for \c aClass, see \ref attributeNamesForClass:.
  194. @param aName The name of the attribute whose value you want to retrieve
  195. @param aState The state qualifier for the attribute
  196. @param aClass The themed class in which to look for the attribute
  197. @return A value or nil
  198. */
  199. - (id)valueForAttributeWithName:(CPString)aName inState:(ThemeState)aState forClass:(id)aClass
  200. {
  201. var attribute = [self attributeWithName:aName forClass:aClass];
  202. if (!attribute)
  203. return nil;
  204. return [attribute valueForState:aState];
  205. }
  206. - (void)takeThemeFromObject:(id)anObject
  207. {
  208. var attributes = [anObject _themeAttributeDictionary],
  209. attributeName = nil,
  210. attributeNames = [attributes keyEnumerator],
  211. objectThemeClass = [anObject themeClass];
  212. while ((attributeName = [attributeNames nextObject]) !== nil)
  213. [self _recordAttribute:[attributes objectForKey:attributeName] forClass:objectThemeClass];
  214. }
  215. - (void)_recordAttribute:(_CPThemeAttribute)anAttribute forClass:(CPString)aClass
  216. {
  217. if (![anAttribute hasValues])
  218. return;
  219. var attributes = [_attributes objectForKey:aClass];
  220. if (!attributes)
  221. {
  222. attributes = @{};
  223. [_attributes setObject:attributes forKey:aClass];
  224. }
  225. var name = [anAttribute name],
  226. existingAttribute = [attributes objectForKey:name];
  227. if (existingAttribute)
  228. [attributes setObject:[existingAttribute attributeMergedWithAttribute:anAttribute] forKey:name];
  229. else
  230. [attributes setObject:anAttribute forKey:name];
  231. }
  232. @end
  233. var CPThemeNameKey = @"CPThemeNameKey",
  234. CPThemeAttributesKey = @"CPThemeAttributesKey";
  235. @implementation CPTheme (CPCoding)
  236. - (id)initWithCoder:(CPCoder)aCoder
  237. {
  238. self = [super init];
  239. if (self)
  240. {
  241. _name = [aCoder decodeObjectForKey:CPThemeNameKey];
  242. _attributes = [aCoder decodeObjectForKey:CPThemeAttributesKey];
  243. CPThemesByName[_name] = self;
  244. }
  245. return self;
  246. }
  247. - (void)encodeWithCoder:(CPCoder)aCoder
  248. {
  249. [aCoder encodeObject:_name forKey:CPThemeNameKey];
  250. [aCoder encodeObject:_attributes forKey:CPThemeAttributesKey];
  251. }
  252. @end
  253. /*!
  254. * ThemeStates are immutable objects representing a particular ThemeState. Applications should never be creating
  255. * ThemeStates directly but should instead use the CPThemeState function.
  256. */
  257. function ThemeState(stateNames)
  258. {
  259. var stateNameKeys = [];
  260. this._stateNames = {};
  261. for (key in stateNames)
  262. {
  263. if (!stateNames.hasOwnProperty(key))
  264. continue;
  265. if (key !== 'normal')
  266. {
  267. this._stateNames[key] = true;
  268. stateNameKeys.push(key);
  269. }
  270. }
  271. if (stateNameKeys.length === 0)
  272. {
  273. stateNameKeys.push('normal');
  274. this._stateNames['normal'] = true;
  275. }
  276. stateNameKeys.sort();
  277. this._stateNameString = stateNameKeys[0];
  278. var stateNameLength = stateNameKeys.length;
  279. for (var stateIndex = 1; stateIndex < stateNameLength; stateIndex++)
  280. this._stateNameString = this._stateNameString + "+" + stateNameKeys[stateIndex];
  281. this._stateNameCount = stateNameLength;
  282. }
  283. ThemeState.prototype.toString = function()
  284. {
  285. return this._stateNameString;
  286. }
  287. ThemeState.prototype.hasThemeState = function(aState)
  288. {
  289. if (!aState || !aState._stateNames)
  290. return false;
  291. // We can do this in O(n) because both states have their stateNames already sorted.
  292. for (var stateName in aState._stateNames)
  293. {
  294. if (!aState._stateNames.hasOwnProperty(stateName))
  295. continue;
  296. if (!this._stateNames[stateName])
  297. return false;
  298. }
  299. return true;
  300. }
  301. ThemeState.prototype.isSubsetOf = function(aState)
  302. {
  303. if (aState._stateNameCount < this._stateNameCount)
  304. return false;
  305. for (var key in this._stateNames)
  306. {
  307. if (!this._stateNames.hasOwnProperty(key))
  308. continue;
  309. if (!aState._stateNames[key])
  310. return false;
  311. }
  312. return true;
  313. }
  314. ThemeState.prototype.without = function(aState)
  315. {
  316. if (!aState || aState === [CPNull null])
  317. return this;
  318. var newStates = {};
  319. for (var stateName in this._stateNames)
  320. {
  321. if (!this._stateNames.hasOwnProperty(stateName))
  322. continue;
  323. if (!aState._stateNames[stateName])
  324. newStates[stateName] = true;
  325. }
  326. return ThemeState._cacheThemeState(new ThemeState(newStates));
  327. }
  328. ThemeState.prototype.and = function(aState)
  329. {
  330. return CPThemeState(this, aState);
  331. }
  332. var CPThemeStates = {};
  333. ThemeState._cacheThemeState = function(aState)
  334. {
  335. // We do this caching so themeState equality works. Basically, doing CPThemeState('foo+bar') === CPThemeState('bar', 'foo') will return true.
  336. var themeState = CPThemeStates[String(aState)];
  337. if (themeState === undefined)
  338. {
  339. themeState = aState;
  340. CPThemeStates[String(themeState)] = themeState;
  341. }
  342. return themeState;
  343. }
  344. /*!
  345. * This method can be called in multiple ways:
  346. * CPThemeState('state1') - creates a new CPThemeState that corresponds to the string 'state1'
  347. * CPThemeState('state1', 'state2') - creates a new composite CPThemeState made up of both 'state1' or 'state2'
  348. * CPThemeState('state1+state2') - The same as CPThemeState('state1', 'state2')
  349. * CPThemeState(state1, state2) - creates a new composite CPThemeState made up of state1 and state2
  350. * where state1 and state2 are not strings but are themselves CPThemeStates.
  351. */
  352. function CPThemeState()
  353. {
  354. if (arguments.length < 1)
  355. throw "CPThemeState() must be called with at least one string argument";
  356. var themeState;
  357. if (arguments.length === 1 && typeof arguments[0] === 'string')
  358. {
  359. themeState = CPThemeStates[arguments[0]];
  360. if (themeState !== undefined)
  361. return themeState;
  362. }
  363. var stateNames = {};
  364. for (var argIndex = 0; argIndex < arguments.length; argIndex++)
  365. {
  366. if (arguments[argIndex] === [CPNull null] || !arguments[argIndex])
  367. continue;
  368. if (typeof arguments[argIndex] === 'object')
  369. {
  370. for (var stateName in arguments[argIndex]._stateNames)
  371. {
  372. if (!arguments[argIndex]._stateNames.hasOwnProperty(stateName))
  373. continue;
  374. stateNames[stateName] = true;
  375. }
  376. }
  377. else
  378. {
  379. var allNames = arguments[argIndex].split('+');
  380. for (var nameIndex = 0; nameIndex < allNames.length; nameIndex++)
  381. stateNames[allNames[nameIndex]] = true;
  382. }
  383. }
  384. themeState = ThemeState._cacheThemeState(new ThemeState(stateNames));
  385. return themeState;
  386. }
  387. @implementation _CPThemeKeyedUnarchiver : CPKeyedUnarchiver
  388. {
  389. CPBundle _bundle;
  390. }
  391. - (id)initForReadingWithData:(CPData)data bundle:(CPBundle)aBundle
  392. {
  393. self = [super initForReadingWithData:data];
  394. if (self)
  395. _bundle = aBundle;
  396. return self;
  397. }
  398. - (CPBundle)bundle
  399. {
  400. return _bundle;
  401. }
  402. - (BOOL)awakenCustomResources
  403. {
  404. return YES;
  405. }
  406. @end
  407. CPThemeStateNormal = CPThemeState("normal");
  408. CPThemeStateDisabled = CPThemeState("disabled");
  409. CPThemeStateHovered = CPThemeState("hovered");
  410. CPThemeStateHighlighted = CPThemeState("highlighted");
  411. CPThemeStateSelected = CPThemeState("selected");
  412. CPThemeStateTableDataView = CPThemeState("tableDataView");
  413. CPThemeStateSelectedDataView = CPThemeState("selectedTableDataView");
  414. CPThemeStateGroupRow = CPThemeState("CPThemeStateGroupRow");
  415. CPThemeStateBezeled = CPThemeState("bezeled");
  416. CPThemeStateBordered = CPThemeState("bordered");
  417. CPThemeStateEditable = CPThemeState("editable");
  418. CPThemeStateEditing = CPThemeState("editing");
  419. CPThemeStateVertical = CPThemeState("vertical");
  420. CPThemeStateDefault = CPThemeState("default");
  421. CPThemeStateCircular = CPThemeState("circular");
  422. CPThemeStateAutocompleting = CPThemeState("autocompleting");
  423. CPThemeStateFirstResponder = CPThemeState("firstResponder");
  424. CPThemeStateMainWindow = CPThemeState("mainWindow");
  425. CPThemeStateKeyWindow = CPThemeState("keyWindow");
  426. CPThemeStateControlSizeRegular = CPThemeState("controlSizeRegular");
  427. CPThemeStateControlSizeSmall = CPThemeState("controlSizeSmall");
  428. CPThemeStateControlSizeMini = CPThemeState("controlSizeMini");
  429. @implementation _CPThemeAttribute : CPObject
  430. {
  431. CPString _name;
  432. id _defaultValue;
  433. CPDictionary _values @accessors(readonly, getter=values);
  434. JSObject _cache;
  435. _CPThemeAttribute _themeDefaultAttribute;
  436. }
  437. - (id)initWithName:(CPString)aName defaultValue:(id)aDefaultValue
  438. {
  439. self = [super init];
  440. if (self)
  441. {
  442. _cache = { };
  443. _name = aName;
  444. _defaultValue = aDefaultValue;
  445. _values = @{};
  446. }
  447. return self;
  448. }
  449. - (CPString)name
  450. {
  451. return _name;
  452. }
  453. - (id)defaultValue
  454. {
  455. return _defaultValue;
  456. }
  457. - (BOOL)hasValues
  458. {
  459. return [_values count] > 0;
  460. }
  461. - (void)setValue:(id)aValue
  462. {
  463. _cache = {};
  464. if (aValue === undefined || aValue === nil)
  465. _values = @{};
  466. else
  467. _values = @{ String(CPThemeStateNormal): aValue };
  468. }
  469. - (void)setValue:(id)aValue forState:(ThemeState)aState
  470. {
  471. _cache = { };
  472. if ((aValue === undefined) || (aValue === nil))
  473. [_values removeObjectForKey:String(aState)];
  474. else
  475. [_values setObject:aValue forKey:String(aState)];
  476. }
  477. - (id)value
  478. {
  479. return [self valueForState:CPThemeStateNormal];
  480. }
  481. - (id)valueForState:(ThemeState)aState
  482. {
  483. var stateName = String(aState),
  484. value = _cache[stateName];
  485. // This can be nil.
  486. if (value !== undefined)
  487. return value;
  488. value = [_values objectForKey:stateName];
  489. if (value === undefined || value === nil)
  490. {
  491. // If this is a composite state, find the closest partial subset match.
  492. if (aState._stateNameCount > 1)
  493. {
  494. var states = [_values allKeys],
  495. count = states.length,
  496. largestThemeState = 0;
  497. while (count--)
  498. {
  499. var stateObject = CPThemeState(states[count]);
  500. if (stateObject.isSubsetOf(aState) && stateObject._stateNameCount > largestThemeState)
  501. {
  502. value = [_values objectForKey:states[count]];
  503. largestThemeState = stateObject._stateNameCount;
  504. }
  505. }
  506. }
  507. // Still don't have a value? OK, let's use the normal value.
  508. if (value === undefined || value === nil)
  509. value = [_values objectForKey:String(CPThemeStateNormal)];
  510. }
  511. if (value === undefined || value === nil)
  512. value = [_themeDefaultAttribute valueForState:aState];
  513. if (value === undefined || value === nil)
  514. {
  515. value = _defaultValue;
  516. // Class theme attributes cannot use nil because it's a dictionary.
  517. // So transform CPNull into nil.
  518. if (value === [CPNull null])
  519. value = nil;
  520. }
  521. _cache[stateName] = value;
  522. return value;
  523. }
  524. - (void)setParentAttribute:(_CPThemeAttribute)anAttribute
  525. {
  526. if (_themeDefaultAttribute === anAttribute)
  527. return;
  528. _cache = { };
  529. _themeDefaultAttribute = anAttribute;
  530. }
  531. - (_CPThemeAttribute)attributeMergedWithAttribute:(_CPThemeAttribute)anAttribute
  532. {
  533. var mergedAttribute = [[_CPThemeAttribute alloc] initWithName:_name defaultValue:_defaultValue];
  534. mergedAttribute._values = [_values copy];
  535. [mergedAttribute._values addEntriesFromDictionary:anAttribute._values];
  536. return mergedAttribute;
  537. }
  538. @end
  539. @implementation _CPThemeAttribute (CPCoding)
  540. - (id)initWithCoder:(CPCoder)aCoder
  541. {
  542. self = [super init];
  543. if (self)
  544. {
  545. _cache = {};
  546. _name = [aCoder decodeObjectForKey:@"name"];
  547. _defaultValue = [aCoder decodeObjectForKey:@"defaultValue"];
  548. _values = @{};
  549. if ([aCoder containsValueForKey:@"value"])
  550. {
  551. var state = String(CPThemeStateNormal);
  552. if ([aCoder containsValueForKey:@"state"])
  553. state = [aCoder decodeObjectForKey:@"state"];
  554. [_values setObject:[aCoder decodeObjectForKey:"value"] forKey:state];
  555. }
  556. else
  557. {
  558. var encodedValues = [aCoder decodeObjectForKey:@"values"],
  559. keys = [encodedValues allKeys],
  560. count = keys.length;
  561. while (count--)
  562. {
  563. var key = keys[count];
  564. [_values setObject:[encodedValues objectForKey:key] forKey:key];
  565. }
  566. }
  567. }
  568. return self;
  569. }
  570. - (void)encodeWithCoder:(CPCoder)aCoder
  571. {
  572. [aCoder encodeObject:_name forKey:@"name"];
  573. [aCoder encodeObject:_defaultValue forKey:@"defaultValue"];
  574. var keys = [_values allKeys],
  575. count = keys.length;
  576. if (count === 1)
  577. {
  578. var onlyKey = keys[0];
  579. if (onlyKey !== String(CPThemeStateNormal))
  580. [aCoder encodeObject:onlyKey forKey:@"state"];
  581. [aCoder encodeObject:[_values objectForKey:onlyKey] forKey:@"value"];
  582. }
  583. else
  584. {
  585. var encodedValues = @{};
  586. while (count--)
  587. {
  588. var key = keys[count];
  589. [encodedValues setObject:[_values objectForKey:key] forKey:key];
  590. }
  591. [aCoder encodeObject:encodedValues forKey:@"values"];
  592. }
  593. }
  594. @end
  595. function CPThemeAttributeEncode(aCoder, aThemeAttribute)
  596. {
  597. var values = aThemeAttribute._values,
  598. count = [values count],
  599. key = "$a" + [aThemeAttribute name];
  600. if (count === 1)
  601. {
  602. var state = [values allKeys][0];
  603. if (state === String(CPThemeStateNormal))
  604. {
  605. [aCoder encodeObject:[values objectForKey:state] forKey:key];
  606. return YES;
  607. }
  608. }
  609. if (count >= 1)
  610. {
  611. [aCoder encodeObject:aThemeAttribute forKey:key];
  612. return YES;
  613. }
  614. return NO;
  615. }
  616. function CPThemeAttributeDecode(aCoder, anAttributeName, aDefaultValue, aTheme, aClass)
  617. {
  618. var key = "$a" + anAttributeName;
  619. if (![aCoder containsValueForKey:key])
  620. var attribute = [[_CPThemeAttribute alloc] initWithName:anAttributeName defaultValue:aDefaultValue];
  621. else
  622. {
  623. var attribute = [aCoder decodeObjectForKey:key];
  624. if (!attribute || !attribute.isa || ![attribute isKindOfClass:[_CPThemeAttribute class]])
  625. {
  626. var themeAttribute = [[_CPThemeAttribute alloc] initWithName:anAttributeName defaultValue:aDefaultValue];
  627. [themeAttribute setValue:attribute];
  628. attribute = themeAttribute;
  629. }
  630. }
  631. if (aTheme && aClass)
  632. [attribute setParentAttribute:[aTheme attributeWithName:anAttributeName forClass:aClass]];
  633. return attribute;
  634. }
  635. /* TO AUTO CREATE THESE:
  636. function bit_count(bits)
  637. {
  638. var count = 0;
  639. while (bits)
  640. {
  641. ++count;
  642. bits &= (bits - 1);
  643. }
  644. return count ;
  645. }
  646. zeros = "000000000";
  647. function pad(string, digits)
  648. {
  649. return zeros.substr(0, digits - string.length) + string;
  650. }
  651. var str = ""
  652. str += '[';
  653. for (i = 0;i < Math.pow(2,6);++i)
  654. {
  655. str += bit_count(i) + " /*" + pad(i.toString(2),6) + "*" + "/, ";
  656. }
  657. print(str+']');
  658. */