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

/examples/lib/SimpleGUI.as

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