PageRenderTime 55ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/Time/srcExternals/uk/co/soulwire/gui/SimpleGUI.as

https://github.com/soundstep/soundstep-utils
ActionScript | 1193 lines | 772 code | 238 blank | 183 comment | 87 complexity | f51e954f33743dfe1c916e4a0e4ada18 MD5 | raw file
  1. /**
  2. *
  3. * uk.co.soulwire.gui.SimpleGUI
  4. *
  5. * @version 1.00 | Jan 13, 2011
  6. * @author Justin Windle
  7. *
  8. * SimpleGUI is a single Class utility designed for AS3 projects where a developer needs to
  9. * quickly add UI controls for variables or functions to a sketch. Properties can be controlled
  10. * with just one line of code using a variety of components from the fantastic Minimal Comps set
  11. * by Keith Peters, as well as custom components written for SimpleGUI such as the FileChooser
  12. *
  13. * Credit to Keith Peters for creating Minimal Comps which this class uses
  14. * http://www.minimalcomps.com/
  15. * http://www.bit-101.com/
  16. *
  17. **/
  18. package uk.co.soulwire.gui
  19. {
  20. import com.bit101.components.CheckBox;
  21. import com.bit101.components.ColorChooser;
  22. import com.bit101.components.ComboBox;
  23. import com.bit101.components.Component;
  24. import com.bit101.components.HUISlider;
  25. import com.bit101.components.Label;
  26. import com.bit101.components.NumericStepper;
  27. import com.bit101.components.PushButton;
  28. import com.bit101.components.RangeSlider;
  29. import com.bit101.components.Style;
  30. import flash.display.Bitmap;
  31. import flash.display.BitmapData;
  32. import flash.display.DisplayObjectContainer;
  33. import flash.display.Sprite;
  34. import flash.display.Stage;
  35. import flash.events.ContextMenuEvent;
  36. import flash.events.Event;
  37. import flash.events.EventDispatcher;
  38. import flash.events.KeyboardEvent;
  39. import flash.events.MouseEvent;
  40. import flash.geom.Rectangle;
  41. import flash.net.FileReference;
  42. import flash.system.System;
  43. import flash.ui.ContextMenu;
  44. import flash.ui.ContextMenuItem;
  45. import flash.utils.Dictionary;
  46. import flash.utils.getQualifiedClassName;
  47. /**
  48. * SimpleGUI
  49. */
  50. public class SimpleGUI extends EventDispatcher
  51. {
  52. // ----------------------------------------------------------------
  53. // CONSTANTS
  54. // ----------------------------------------------------------------
  55. public static const VERSION : Number = 1.02;
  56. private static const TOOLBAR_HEIGHT : int = 13;
  57. private static const COMPONENT_MARGIN : int = 8; private static const COLUMN_MARGIN : int = 1; private static const GROUP_MARGIN : int = 1; private static const PADDING : int = 4; private static const MARGIN : int = 1;
  58. // ----------------------------------------------------------------
  59. // PRIVATE MEMBERS
  60. // ----------------------------------------------------------------
  61. private var _components : Vector.<Component> = new Vector.<Component>();
  62. private var _parameters : Dictionary = new Dictionary();
  63. private var _container : Sprite = new Sprite();
  64. private var _target : DisplayObjectContainer;
  65. private var _active : Component;
  66. private var _stage : Stage;
  67. private var _toolbar : Sprite = new Sprite(); private var _message : Label = new Label();
  68. private var _version : Label = new Label();
  69. private var _toggle : Sprite = new Sprite();
  70. private var _lineH : Bitmap = new Bitmap(); private var _lineV : Bitmap = new Bitmap();
  71. private var _tween : Number = 0.0;
  72. private var _width : Number = 0.0;
  73. private var _hotKey : String;
  74. private var _column : Sprite;
  75. private var _group : Sprite;
  76. private var _dirty : Boolean;
  77. private var _hidden : Boolean;
  78. private var _showToggle : Boolean = true;
  79. // ----------------------------------------------------------------
  80. // CONSTRUCTOR
  81. // ----------------------------------------------------------------
  82. public function SimpleGUI(target : DisplayObjectContainer, title : String = null, hotKey : * = null)
  83. {
  84. _target = target;
  85. _toggle.x = MARGIN;
  86. _toggle.y = MARGIN;
  87. _toolbar.x = MARGIN;
  88. _toolbar.y = MARGIN;
  89. _container.x = MARGIN;
  90. _container.y = TOOLBAR_HEIGHT + (MARGIN * 2);
  91. initStyles();
  92. initToolbar();
  93. initContextMenu();
  94. if (_target.stage) onAddedToStage(null);
  95. else _target.addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
  96. _target.addEventListener(Event.ADDED, onTargetAdded);
  97. if(hotKey) this.hotKey = hotKey;
  98. addColumn(title);
  99. addGroup();
  100. hide();
  101. }
  102. // ----------------------------------------------------------------
  103. // PUBLIC METHODS
  104. // ----------------------------------------------------------------
  105. /**
  106. * Shows the GUI
  107. */
  108. public function show() : void
  109. {
  110. _lineV.visible = false;
  111. _target.addChild(_container);
  112. _target.addChild(_toolbar);
  113. _target.addChild(_toggle);
  114. _hidden = false;
  115. }
  116. /**
  117. * Hides the GUI
  118. */
  119. public function hide() : void
  120. {
  121. _lineV.visible = true;
  122. if (!_showToggle && _target.contains(_toggle)) _target.removeChild(_toggle);
  123. if (_target.contains(_container)) _target.removeChild(_container);
  124. if (_target.contains(_toolbar)) _target.removeChild(_toolbar);
  125. _hidden = true;
  126. }
  127. /**
  128. * Populates the system clipboard with Actionscript code, setting all
  129. * controlled properties to their current values
  130. */
  131. public function save() : void
  132. {
  133. var path : String;
  134. var prop : Object;
  135. var target : Object;
  136. var targets : Array;
  137. var options : Object;
  138. var component : Component;
  139. var output : String = '';
  140. for (var i : int = 0; i < _components.length; i++)
  141. {
  142. component = _components[i];
  143. options = _parameters[component];
  144. if (options.hasOwnProperty("target"))
  145. {
  146. targets = [].concat(options.target);
  147. for (var j : int = 0; j < targets.length; ++j)
  148. {
  149. path = targets[j];
  150. prop = getProp(path);
  151. target = getTarget(path);
  152. output += path + " = " + target[prop] + ';\n';
  153. }
  154. }
  155. }
  156. message = "Settings copied to clipboard";
  157. System.setClipboard(output);
  158. }
  159. /**
  160. * Generic method for adding controls. This is called internally by
  161. * specific control methods. It is best to use explicit methods for
  162. * adding controls (such as addSlider and addToggle), however this
  163. * method has been exposed for flexibility
  164. *
  165. * @param type The class definition of the component to add
  166. * @param options The options to configure the component with
  167. */
  168. public function addControl(type : Class, options : Object) : Component
  169. {
  170. var component : Component = new type();
  171. // apply settings
  172. for (var option : String in options)
  173. {
  174. if (component.hasOwnProperty(option))
  175. {
  176. component[option] = options[option];
  177. }
  178. }
  179. // subscribe to component events
  180. if (component is PushButton || component is CheckBox)
  181. {
  182. component.addEventListener(MouseEvent.CLICK, onComponentClicked);
  183. }
  184. else if (component is ComboBox)
  185. {
  186. component.addEventListener(Event.SELECT, onComponentChanged);
  187. }
  188. else
  189. {
  190. component.addEventListener(Event.CHANGE, onComponentChanged);
  191. }
  192. // listen for first draw
  193. component.addEventListener(Component.DRAW, onComponentDraw);
  194. // add a label if necessary
  195. if (!component.hasOwnProperty("label") && options.hasOwnProperty("label") && type !== Label)
  196. {
  197. var container : Sprite = new Sprite();
  198. var label : Label = new Label();
  199. label.text = options.label;
  200. label.draw();
  201. component.x = label.width + 5;
  202. container.addChild(label);
  203. container.addChild(component);
  204. _group.addChild(container);
  205. }
  206. else
  207. {
  208. _group.addChild(component);
  209. }
  210. _parameters[component] = options;
  211. _components.push(component);
  212. update();
  213. //component.width = 200;
  214. return component;
  215. }
  216. /**
  217. * Adds a column to the GUI
  218. *
  219. * @param title An optional title to display at the top of the column
  220. */
  221. public function addColumn(title : String = null) : void
  222. {
  223. _column = new Sprite();
  224. _container.addChild(_column);
  225. addGroup(title);
  226. }
  227. /**
  228. * Creates a separator with an optional title to help segment groups
  229. * of controls
  230. *
  231. * @param title An optional title to display at the top of the group
  232. */
  233. public function addGroup(title : String = null) : void
  234. {
  235. if (_group && _group.numChildren == 0)
  236. {
  237. _group.parent.removeChild(_group);
  238. }
  239. _group = new Sprite();
  240. _column.addChild(_group);
  241. if (title)
  242. {
  243. addLabel(title.toUpperCase());
  244. }
  245. }
  246. /**
  247. * Adds a label
  248. *
  249. * @param text The text content of the label
  250. */
  251. public function addLabel(text : String) : void
  252. {
  253. addControl(Label, {text : text.toUpperCase()});
  254. }
  255. /**
  256. * Adds a toggle control for a boolean value
  257. *
  258. * @param target The name of the property to be controlled
  259. * @param options An optional object containing initialisation parameters
  260. * for the control, the keys of which should correspond to properties on
  261. * the control. Additional values can also be placed within this object,
  262. * such as a callback function. If a String is passed as this parameter,
  263. * it will be used as the control's label, though it is recommended that
  264. * you instead pass the label as a property within the options object
  265. */
  266. public function addToggle(target : String, options : Object = null) : void
  267. {
  268. options = parseOptions(target, options);
  269. var params : Object = {};
  270. params.target = target;
  271. addControl(CheckBox, merge(params, options));
  272. }
  273. public function addButton(label : String, options : Object = null) : void
  274. {
  275. options = parseOptions(label, options);
  276. var params : Object = {};
  277. params.label = label;
  278. addControl(PushButton, merge(params, options));
  279. }
  280. /**
  281. * Adds a slider control for a numerical value
  282. *
  283. * @param target The name of the property to be controlled
  284. * @param minimum The minimum slider value
  285. * @param maximum The maximum slider value
  286. * @param options An optional object containing initialisation parameters
  287. * for the control, the keys of which should correspond to properties on
  288. * the control. Additional values can also be placed within this object,
  289. * such as a callback function. If a String is passed as this parameter,
  290. * it will be used as the control's label, though it is recommended that
  291. * you instead pass the label as a property within the options object
  292. */
  293. public function addSlider(target : String, minimum : Number, maximum : Number, options : Object = null) : void
  294. {
  295. options = parseOptions(target, options);
  296. var params : Object = {};
  297. params.target = target;
  298. params.minimum = minimum;
  299. params.maximum = maximum;
  300. addControl(HUISlider, merge(params, options));
  301. }
  302. /**
  303. * Adds a range slider control for a numerical value
  304. *
  305. * @param target The name of the property to be controlled
  306. * @param minimum The minimum slider value
  307. * @param maximum The maximum slider value
  308. * @param options An optional object containing initialisation parameters
  309. * for the control, the keys of which should correspond to properties on
  310. * the control. Additional values can also be placed within this object,
  311. * such as a callback function. If a String is passed as this parameter,
  312. * it will be used as the control's label, though it is recommended that
  313. * you instead pass the label as a property within the options object
  314. */
  315. public function addRange(target1 : String, target2 : String, minimum : Number, maximum : Number, options : Object = null) : void
  316. {
  317. var target : Array = [target1, target2];
  318. options = parseOptions(target.join(" / "), options);
  319. var params : Object = {};
  320. params.target = target;
  321. params.minimum = minimum;
  322. params.maximum = maximum;
  323. addControl(HUIRangeSlider, merge(params, options));
  324. }
  325. /**
  326. * Adds a numeric stepper control for a numerical value
  327. *
  328. * @param target The name of the property to be controlled
  329. * @param minimum The minimum stepper value
  330. * @param maximum The maximum stepper value
  331. * @param options An optional object containing initialisation parameters
  332. * for the control, the keys of which should correspond to properties on
  333. * the control. Additional values can also be placed within this object,
  334. * such as a callback function. If a String is passed as this parameter,
  335. * it will be used as the control's label, though it is recommended that
  336. * you instead pass the label as a property within the options object
  337. */
  338. public function addStepper(target : String, minimum : Number, maximum : Number, options : Object = null) : void
  339. {
  340. options = parseOptions(target, options);
  341. var params : Object = {};
  342. params.target = target;
  343. params.minimum = minimum;
  344. params.maximum = maximum;
  345. addControl(NumericStepper, merge(params, options));
  346. }
  347. /**
  348. * Adds a colour picker
  349. *
  350. * @param target The name of the property to be controlled
  351. * @param options An optional object containing initialisation parameters
  352. * for the control, the keys of which should correspond to properties on
  353. * the control. Additional values can also be placed within this object,
  354. * such as a callback function. If a String is passed as this parameter,
  355. * it will be used as the control's label, though it is recommended that
  356. * you instead pass the label as a property within the options object
  357. */
  358. public function addColour(target : String, options : Object = null) : void
  359. {
  360. options = parseOptions(target, options);
  361. var params : Object = {};
  362. params.target = target;
  363. params.usePopup = true;
  364. addControl(ColorChooser, merge(params, options));
  365. }
  366. /**
  367. * Adds a combo box of values for a property
  368. *
  369. * @param target The name of the property to be controlled
  370. * @param items A list of selectable items for the combo box in the form
  371. * or [{label:"The Label", data:anObject},...]
  372. * @param options An optional object containing initialisation parameters
  373. * for the control, the keys of which should correspond to properties on
  374. * the control. Additional values can also be placed within this object,
  375. * such as a callback function. If a String is passed as this parameter,
  376. * it will be used as the control's label, though it is recommended that
  377. * you instead pass the label as a property within the options object
  378. */
  379. public function addComboBox(target : String, items : Array, options : Object = null) : void
  380. {
  381. options = parseOptions(target, options);
  382. var params : Object = {};
  383. var prop : String = getProp(target);
  384. var targ : Object = getTarget(target);
  385. params.target = target;
  386. params.items = items;
  387. params.defaultLabel = targ[prop];
  388. params.numVisibleItems = Math.min(items.length, 5);
  389. addControl(StyledCombo, merge(params, options));
  390. }
  391. /**
  392. * Adds a file chooser for a File object
  393. *
  394. * @param label The label for the file
  395. * @param file The File object to control
  396. * @param onComplete A callback function to trigger when the file's data is loaded
  397. * @param filter An optional list of FileFilters to apply when selecting the file
  398. * @param options An optional object containing initialisation parameters
  399. * for the control, the keys of which should correspond to properties on
  400. * the control. Additional values can also be placed within this object,
  401. * such as a callback function. If a String is passed as this parameter,
  402. * it will be used as the control's label, though it is recommended that
  403. * you instead pass the label as a property within the options object
  404. */
  405. public function addFileChooser(label : String, file : FileReference, onComplete : Function, filter : Array = null, options : Object = null) : void
  406. {
  407. options = parseOptions(label, options);
  408. var params : Object = {};
  409. params.file = file;
  410. params.label = label;
  411. params.width = 220;
  412. params.filter = filter;
  413. params.onComplete = onComplete;
  414. addControl(FileChooser, merge(params, options));
  415. }
  416. /**
  417. * Adds a save button to the controls. The save method can also be called
  418. * manually or by pressing the 's' key. Saving populates the system clipboard
  419. * with Actionscript code, setting all controlled properties to their current values
  420. *
  421. * @param label The label for the save button
  422. * @param options An optional object containing initialisation parameters
  423. * for the control, the keys of which should correspond to properties on
  424. * the control. Additional values can also be placed within this object,
  425. * such as a callback function. If a String is passed as this parameter,
  426. * it will be used as the control's label, though it is recommended that
  427. * you instead pass the label as a property within the options object
  428. */
  429. public function addSaveButton(label : String = "Save", options : Object = null) : void
  430. {
  431. addGroup("Save Current Settings (S)");
  432. options = parseOptions(label, options);
  433. var params : Object = {};
  434. params.label = label;
  435. var button : PushButton = addControl(PushButton, merge(params, options)) as PushButton;
  436. button.addEventListener(MouseEvent.CLICK, onSaveButtonClicked);
  437. }
  438. // ----------------------------------------------------------------
  439. // PRIVATE METHODS
  440. // ----------------------------------------------------------------
  441. private function initStyles() : void
  442. {
  443. Style.PANEL = 0x333333;
  444. Style.BACKGROUND = 0x333333;
  445. Style.INPUT_TEXT = 0xEEEEEE;
  446. Style.LABEL_TEXT = 0xEEEEEE;
  447. Style.BUTTON_FACE = 0x555555;
  448. Style.DROPSHADOW = 0x000000;
  449. }
  450. private function initToolbar() : void
  451. {
  452. _toolbar.x += TOOLBAR_HEIGHT + 1;
  453. _version = new Label();
  454. _version.text = "SimpelGUI v" + VERSION;
  455. _version.alpha = 0.5;
  456. _message = new Label();
  457. _message.alpha = 0.6;
  458. _message.x = 2;
  459. _version.y = _message.y = -3;
  460. _toggle.graphics.beginFill(0x333333, 0.9);
  461. _toggle.graphics.drawRect(0, 0, TOOLBAR_HEIGHT, TOOLBAR_HEIGHT);
  462. _toggle.graphics.endFill();
  463. _toolbar.addChild(_version);
  464. _toolbar.addChild(_message);
  465. _toggle.addEventListener(MouseEvent.CLICK, onToggleClicked);
  466. _toggle.buttonMode = true;
  467. //
  468. _lineH.bitmapData = new BitmapData(5, 1, false, 0xFFFFFF); _lineV.bitmapData = new BitmapData(1, 5, false, 0xFFFFFF);
  469. _lineH.x = (TOOLBAR_HEIGHT * 0.5) - 3; _lineH.y = (TOOLBAR_HEIGHT * 0.5) - 1;
  470. _lineV.x = (TOOLBAR_HEIGHT * 0.5) - 1; _lineV.y = (TOOLBAR_HEIGHT * 0.5) - 3;
  471. _toggle.addChild(_lineH); _toggle.addChild(_lineV);
  472. }
  473. private function initContextMenu() : void
  474. {
  475. var menu : * = _target.contextMenu || new ContextMenu();
  476. var item : ContextMenuItem = new ContextMenuItem("Toggle Controls", true);
  477. item.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, onContextMenuItemSelected);
  478. menu.customItems.push(item);
  479. _target.contextMenu = menu;
  480. }
  481. private function commit(component : Component = null) : void
  482. {
  483. if (component)
  484. {
  485. _active = component;
  486. apply(component, true);
  487. }
  488. else
  489. {
  490. for (var i : int = 0; i < _components.length; i++)
  491. {
  492. component = _components[i];
  493. apply(component, false);
  494. }
  495. }
  496. update();
  497. }
  498. private function apply(component : Component, extended : Boolean = false) : void
  499. {
  500. var i : int;
  501. var path : String;
  502. var prop : Object; var target : Object;
  503. var targets : Array;
  504. var options : Object = _parameters[component];
  505. if (options.hasOwnProperty("target"))
  506. {
  507. targets = [].concat(options.target);
  508. for (i = 0; i < targets.length; i++)
  509. {
  510. path = targets[i];
  511. prop = getProp(path);
  512. target = getTarget(path);
  513. if (component is CheckBox)
  514. {
  515. target[prop] = component["selected"];
  516. }
  517. else if (component is RangeSlider)
  518. {
  519. target[prop] = component[i == 0 ? "lowValue" : "highValue"];
  520. }
  521. else if (component is ComboBox)
  522. {
  523. if(component["selectedItem"])
  524. {
  525. target[prop] = component["selectedItem"].data;
  526. }
  527. }
  528. else if(component.hasOwnProperty("value"))
  529. {
  530. target[prop] = component["value"];
  531. }
  532. }
  533. }
  534. if (extended && options.hasOwnProperty("callback"))
  535. {
  536. options.callback.apply(_target, options.callbackParams || []);
  537. }
  538. }
  539. private function update() : void
  540. {
  541. var i : int;
  542. var j : int;
  543. var path : String;
  544. var prop : Object; var target : Object; var targets : Array;
  545. var options : Object;
  546. var component : Component;
  547. for (i = 0; i < _components.length; i++)
  548. {
  549. component = _components[i];
  550. if (component == _active) continue;
  551. options = _parameters[component];
  552. if (options.hasOwnProperty("target"))
  553. {
  554. targets = [].concat(options.target);
  555. for (j = 0; j < targets.length; j++)
  556. {
  557. path = targets[j];
  558. prop = getProp(path);
  559. target = getTarget(path);
  560. if (component is CheckBox)
  561. {
  562. component["selected"] = target[prop];
  563. }
  564. else if (component is RangeSlider)
  565. {
  566. component[j == 0 ? "lowValue" : "highValue"] = target[prop];
  567. }
  568. else if ( component is ComboBox)
  569. {
  570. var items : Array = component["items"];
  571. for (var k : int = 0; k < items.length; k++)
  572. {
  573. if(items[k].data == target[prop])
  574. {
  575. if(component["selectedIndex"] != k)
  576. {
  577. component["selectedIndex"] = k;
  578. break;
  579. }
  580. }
  581. }
  582. }
  583. else if(component.hasOwnProperty("value"))
  584. {
  585. component["value"] = target[prop];
  586. }
  587. }
  588. }
  589. }
  590. }
  591. private function invalidate() : void
  592. {
  593. _container.addEventListener(Event.ENTER_FRAME, onEnterFrame);
  594. _dirty = true;
  595. }
  596. private function draw() : void
  597. {
  598. var i : int;
  599. var j : int;
  600. var k : int;
  601. var ghs : Array;
  602. var gw : int = 0;
  603. var gh : int = 0;
  604. var gy : int = 0;
  605. var cx : int = 0;
  606. var cw : int = 0;
  607. var group : Sprite;
  608. var column : Sprite;
  609. var component : Sprite;
  610. var bounds : Rectangle;
  611. for (i = 0; i < _container.numChildren; i++)
  612. {
  613. column = _container.getChildAt(i) as Sprite;
  614. column.x = cx;
  615. gy = cw = 0;
  616. ghs = [];
  617. for (j = 0; j < column.numChildren; j++)
  618. {
  619. group = column.getChildAt(j) as Sprite;
  620. group.y = gy;
  621. gw = 0;
  622. gh = PADDING;
  623. for (k = 0; k < group.numChildren; k++)
  624. {
  625. component = group.getChildAt(k) as Sprite;
  626. bounds = component.getBounds(component);
  627. component.x = PADDING - bounds.x;
  628. component.y = gh - bounds.y;
  629. gw = Math.max(gw, bounds.width);
  630. gh += bounds.height + (k < group.numChildren - 1 ? COMPONENT_MARGIN : 0);
  631. }
  632. gh += PADDING;
  633. ghs[j] = gh;
  634. gy += gh + GROUP_MARGIN;
  635. cw = Math.max(cw, gw);
  636. }
  637. cw += (PADDING * 2);
  638. for (j = 0; j < column.numChildren; j++)
  639. {
  640. group = column.getChildAt(j) as Sprite;
  641. for (k = 0; k < group.numChildren - 1; k++)
  642. {
  643. component = group.getChildAt(k) as Sprite;
  644. bounds = component.getBounds(component);
  645. bounds.bottom += COMPONENT_MARGIN / 2;
  646. component.graphics.clear();
  647. component.graphics.lineStyle(0, 0x000000, 0.1);
  648. component.graphics.moveTo(bounds.left, bounds.bottom);
  649. component.graphics.lineTo(bounds.x + cw - (PADDING * 2), bounds.bottom);
  650. }
  651. group.graphics.clear();
  652. group.graphics.beginFill(0x333333, 0.9);
  653. group.graphics.drawRect(0, 0, cw, ghs[j]);
  654. group.graphics.endFill();
  655. }
  656. cx += cw + COLUMN_MARGIN;
  657. }
  658. _width = cx - COLUMN_MARGIN;
  659. _version.x = _width - _toolbar.x -_version.width - 2;
  660. _toolbar.graphics.clear();
  661. _toolbar.graphics.beginFill(0x333333, 0.9);
  662. _toolbar.graphics.drawRect(0, 0, _width - _toolbar.x, TOOLBAR_HEIGHT);
  663. _toolbar.graphics.endFill();
  664. }
  665. private function parseOptions(target : String, options : Object) : Object
  666. {
  667. options = clone(options);
  668. var type : String = getQualifiedClassName(options);
  669. switch(type)
  670. {
  671. case "String" :
  672. return {label: options};
  673. case "Object" :
  674. options.label = options.label || propToLabel(target);
  675. return options;
  676. default :
  677. return {label: propToLabel(target)};
  678. }
  679. }
  680. private function getTarget(path : String) : Object
  681. {
  682. var target : Object = _target;
  683. var hierarchy : Array = path.split('.');
  684. if (hierarchy.length == 1) return _target;
  685. for (var i : int = 0; i < hierarchy.length - 1; i++)
  686. {
  687. target = target[hierarchy[i]];
  688. }
  689. return target;
  690. }
  691. private function getProp(path : String) : String
  692. {
  693. return /[_a-z0-9]+$/i.exec(path)[0];
  694. }
  695. private function merge(source : Object, destination : Object) : Object
  696. {
  697. var combined : Object = clone(destination);
  698. for (var prop : String in source)
  699. {
  700. if (!destination.hasOwnProperty(prop))
  701. {
  702. combined[prop] = source[prop];
  703. }
  704. }
  705. return combined;
  706. }
  707. private function clone(source : Object) : Object
  708. {
  709. var copy : Object = {};
  710. for (var prop : String in source)
  711. {
  712. copy[prop] = source[prop];
  713. }
  714. return copy;
  715. }
  716. private function propToLabel(prop : String) : String
  717. {
  718. return prop .replace(/[_]+([a-zA-Z0-9]+)|([0-9]+)/g, " $1$2 ")
  719. .replace(/(?<=[a-z0-9])([A-Z])|(?<=[a-z])([0-9])/g, " $1$2")
  720. .replace(/^(\w)|\s+(\w)|\.+(\w)/g, capitalise)
  721. .replace(/^\s|\s$|(?<=\s)\s+/g, '');
  722. }
  723. private function capitalise(...args) : String
  724. {
  725. return String(' ' + args[1] + args[2] + args[3]).toUpperCase();
  726. }
  727. // ----------------------------------------------------------------
  728. // EVENT HANDLERS
  729. // ----------------------------------------------------------------
  730. private function onAddedToStage(event : Event) : void
  731. {
  732. _stage = _target.stage;
  733. _target.removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
  734. _target.stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyPressed);
  735. }
  736. private function onTargetAdded(event : Event) : void
  737. {
  738. if (!_hidden) show();
  739. }
  740. private function onSaveButtonClicked(event : MouseEvent) : void
  741. {
  742. save();
  743. }
  744. private function onToggleClicked(event : MouseEvent) : void
  745. {
  746. _hidden ? show() : hide();
  747. }
  748. private function onContextMenuItemSelected(event : ContextMenuEvent) : void
  749. {
  750. _hidden ? show() : hide();
  751. }
  752. private function onComponentClicked(event : MouseEvent) : void
  753. {
  754. commit(event.target as Component);
  755. }
  756. private function onComponentChanged(event : Event) : void
  757. {
  758. commit(event.target as Component);
  759. }
  760. private function onComponentDraw(event : Event) : void
  761. {
  762. var component : Component = event.target as Component;
  763. component.removeEventListener(Component.DRAW, onComponentDraw);
  764. invalidate();
  765. }
  766. private function onEnterFrame(event : Event) : void
  767. {
  768. _container.removeEventListener(Event.ENTER_FRAME, onEnterFrame);
  769. if(_dirty)
  770. {
  771. _dirty = false;
  772. draw();
  773. }
  774. }
  775. private function onKeyPressed(event : KeyboardEvent) : void
  776. {
  777. if(hotKey && event.keyCode == hotKey.toUpperCase().charCodeAt(0))
  778. {
  779. _hidden ? show() : hide();
  780. }
  781. if(event.keyCode == 83)
  782. {
  783. save();
  784. }
  785. }
  786. private function onMessageEnterFrame(event : Event) : void
  787. {
  788. _tween += 0.01;
  789. _message.alpha = 1.0 - (-0.5 * (Math.cos(Math.PI * _tween) - 1));
  790. if (_message.alpha < 0.0001)
  791. {
  792. _message.removeEventListener(Event.ENTER_FRAME, onMessageEnterFrame);
  793. _message.text = '';
  794. }
  795. }
  796. // ----------------------------------------------------------------
  797. // PUBLIC ACCESSORS
  798. // ----------------------------------------------------------------
  799. public function get showToggle() : Boolean
  800. {
  801. return _showToggle;
  802. }
  803. public function set showToggle( value : Boolean ) : void
  804. {
  805. _showToggle = value;
  806. if (_hidden) hide();
  807. }
  808. public function set message(value : String) : void
  809. {
  810. _tween = 0.0;
  811. _message.alpha = 1.0;
  812. _message.text = value.toUpperCase();
  813. _message.addEventListener(Event.ENTER_FRAME, onMessageEnterFrame);
  814. }
  815. public function get hotKey() : *
  816. {
  817. return _hotKey;
  818. }
  819. public function set hotKey( value : * ) : void
  820. {
  821. if (value is String)
  822. {
  823. _hotKey = value;
  824. }
  825. else if (value is int)
  826. {
  827. _hotKey = String.fromCharCode(value);
  828. }
  829. else
  830. {
  831. throw new Error("HotKey must be a String or an integer");
  832. }
  833. message = "Hotkey set to '" + _hotKey + "'";
  834. }
  835. public function get components():Vector.<Component> {
  836. return _components;
  837. }
  838. }
  839. }
  840. import com.bit101.components.ComboBox;
  841. import com.bit101.components.Component;
  842. import com.bit101.components.HRangeSlider;
  843. import com.bit101.components.InputText;
  844. import com.bit101.components.Label;
  845. import com.bit101.components.PushButton;
  846. import flash.events.Event;
  847. import flash.events.MouseEvent;
  848. import flash.net.FileReference;
  849. internal class HUIRangeSlider extends HRangeSlider
  850. {
  851. private var _label : Label = new Label();
  852. private var _offset : Number = 0.0;
  853. override protected function addChildren() : void
  854. {
  855. super.addChildren();
  856. _label.y = -5;
  857. addChild(_label);
  858. }
  859. override public function draw() : void
  860. {
  861. _offset = x = _label.width + 5;
  862. _width = Math.min(200 - _offset, 200);
  863. _label.x = -_offset;
  864. super.draw();
  865. }
  866. public function get label() : String
  867. {
  868. return _label.text;
  869. }
  870. public function set label(value : String) : void
  871. {
  872. _label.text = value;
  873. _label.draw();
  874. }
  875. }
  876. internal class FileChooser extends Component
  877. {
  878. public var filter : Array = [];
  879. public var onComplete : Function;
  880. private var _label : Label = new Label();
  881. private var _file : FileReference;
  882. private var _filePath : InputText = new InputText();
  883. private var _button : PushButton = new PushButton();
  884. override protected function addChildren() : void
  885. {
  886. super.addChildren();
  887. _button.x = 125;
  888. _button.width = 75;
  889. _button.label = "Browse";
  890. _button.addEventListener(MouseEvent.CLICK, onButtonClicked);
  891. _filePath.enabled = false;
  892. _filePath.width = 120;
  893. _filePath.height = _button.height;
  894. _button.y = _filePath.y = 20;
  895. addChild(_filePath);
  896. addChild(_button);
  897. addChild(_label);
  898. }
  899. private function onButtonClicked(event : MouseEvent) : void
  900. {
  901. if (_file) _file.browse(filter);
  902. }
  903. private function onFileSelected(event : Event) : void
  904. {
  905. _filePath.text = _file.name;
  906. _file.addEventListener(Event.COMPLETE, onFileComplete);
  907. _file.load();
  908. }
  909. private function onFileComplete(event : Event) : void
  910. {
  911. if (onComplete != null) onComplete();
  912. }
  913. override public function set width(w : Number) : void
  914. {
  915. super.width = w;
  916. _button.x = w - _button.width;
  917. _filePath.width = w - _button.width - 5;
  918. }
  919. public function get label() : String
  920. {
  921. return _label.text;
  922. }
  923. public function set label( value : String ) : void
  924. {
  925. _label.text = value;
  926. }
  927. public function get file() : FileReference
  928. {
  929. return _file;
  930. }
  931. public function set file( value : FileReference ) : void
  932. {
  933. if (_file)
  934. {
  935. _file.removeEventListener(Event.SELECT, onFileSelected);
  936. }
  937. _file = value;
  938. _file.addEventListener(Event.SELECT, onFileSelected);
  939. if(_file.data)
  940. {
  941. _filePath.text = _file.name;
  942. }
  943. }
  944. }
  945. internal class StyledCombo extends ComboBox
  946. {
  947. override protected function addChildren() : void
  948. {
  949. super.addChildren();
  950. _list.defaultColor = 0x333333;
  951. _list.alternateColor = 0x444444;
  952. _list.selectedColor = 0x111111;
  953. _list.rolloverColor = 0x555555;
  954. }
  955. }