PageRenderTime 67ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 1ms

/AnimViewTool/src/ui/SimpleGUI.as

https://bitbucket.org/ntibor22/spritesheet
ActionScript | 1191 lines | 763 code | 238 blank | 190 comment | 87 complexity | bc0f3234124a9715eab477372d378ba5 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 ui
  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 = 8; private static const MARGIN : int = 2;
  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);
  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});
  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. Style.setStyle(Style.LIGHT);
  450. }
  451. private function initToolbar() : void
  452. {
  453. _toolbar.x += TOOLBAR_HEIGHT + 1;
  454. _version = new Label();
  455. _version.text = "SimpelGUI v" + VERSION;
  456. _version.alpha = 0.5;
  457. _message = new Label();
  458. _message.alpha = 0.6;
  459. _message.x = 2;
  460. _version.y = _message.y = -3;
  461. _toggle.graphics.beginFill(0x333333, 0.9);
  462. _toggle.graphics.drawRect(0, 0, TOOLBAR_HEIGHT, TOOLBAR_HEIGHT);
  463. _toggle.graphics.endFill();
  464. //_toolbar.addChild(_version);
  465. _toolbar.addChild(_message);
  466. _toggle.addEventListener(MouseEvent.CLICK, onToggleClicked);
  467. _toggle.buttonMode = true;
  468. //
  469. _lineH.bitmapData = new BitmapData(5, 1, false, 0xFFFFFF); _lineV.bitmapData = new BitmapData(1, 5, false, 0xFFFFFF);
  470. _lineH.x = (TOOLBAR_HEIGHT * 0.5) - 3; _lineH.y = (TOOLBAR_HEIGHT * 0.5) - 1;
  471. _lineV.x = (TOOLBAR_HEIGHT * 0.5) - 1; _lineV.y = (TOOLBAR_HEIGHT * 0.5) - 3;
  472. _toggle.addChild(_lineH); _toggle.addChild(_lineV);
  473. }
  474. private function initContextMenu() : void
  475. {
  476. var menu : * = _target.contextMenu || new ContextMenu();
  477. var item : ContextMenuItem = new ContextMenuItem("Toggle Controls", true);
  478. item.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, onContextMenuItemSelected);
  479. menu.customItems.push(item);
  480. _target.contextMenu = menu;
  481. }
  482. private function commit(component : Component = null) : void
  483. {
  484. if (component)
  485. {
  486. _active = component;
  487. apply(component, true);
  488. }
  489. else
  490. {
  491. for (var i : int = 0; i < _components.length; i++)
  492. {
  493. component = _components[i];
  494. apply(component, false);
  495. }
  496. }
  497. update();
  498. }
  499. private function apply(component : Component, extended : Boolean = false) : void
  500. {
  501. var i : int;
  502. var path : String;
  503. var prop : Object; var target : Object;
  504. var targets : Array;
  505. var options : Object = _parameters[component];
  506. if (options.hasOwnProperty("target"))
  507. {
  508. targets = [].concat(options.target);
  509. for (i = 0; i < targets.length; i++)
  510. {
  511. path = targets[i];
  512. prop = getProp(path);
  513. target = getTarget(path);
  514. if (component is CheckBox)
  515. {
  516. target[prop] = component["selected"];
  517. }
  518. else if (component is RangeSlider)
  519. {
  520. target[prop] = component[i == 0 ? "lowValue" : "highValue"];
  521. }
  522. else if (component is ComboBox)
  523. {
  524. if(component["selectedItem"])
  525. {
  526. target[prop] = component["selectedItem"].data;
  527. }
  528. }
  529. else if(component.hasOwnProperty("value"))
  530. {
  531. target[prop] = component["value"];
  532. }
  533. }
  534. }
  535. if (extended && options.hasOwnProperty("callback"))
  536. {
  537. options.callback.apply(_target, options.callbackParams || []);
  538. }
  539. }
  540. private function update() : void
  541. {
  542. var i : int;
  543. var j : int;
  544. var path : String;
  545. var prop : Object; var target : Object; var targets : Array;
  546. var options : Object;
  547. var component : Component;
  548. for (i = 0; i < _components.length; i++)
  549. {
  550. component = _components[i];
  551. if (component == _active) continue;
  552. options = _parameters[component];
  553. if (options.hasOwnProperty("target"))
  554. {
  555. targets = [].concat(options.target);
  556. for (j = 0; j < targets.length; j++)
  557. {
  558. path = targets[j];
  559. prop = getProp(path);
  560. target = getTarget(path);
  561. if (component is CheckBox)
  562. {
  563. component["selected"] = target[prop];
  564. }
  565. else if (component is RangeSlider)
  566. {
  567. component[j == 0 ? "lowValue" : "highValue"] = target[prop];
  568. }
  569. else if ( component is ComboBox)
  570. {
  571. var items : Array = component["items"];
  572. for (var k : int = 0; k < items.length; k++)
  573. {
  574. if(items[k].data == target[prop])
  575. {
  576. if(component["selectedIndex"] != k)
  577. {
  578. component["selectedIndex"] = k;
  579. break;
  580. }
  581. }
  582. }
  583. }
  584. else if(component.hasOwnProperty("value"))
  585. {
  586. component["value"] = target[prop];
  587. }
  588. }
  589. }
  590. }
  591. }
  592. private function invalidate() : void
  593. {
  594. _container.addEventListener(Event.ENTER_FRAME, onEnterFrame);
  595. _dirty = true;
  596. }
  597. private function draw() : void
  598. {
  599. var i : int;
  600. var j : int;
  601. var k : int;
  602. var ghs : Array;
  603. var gw : int = 0;
  604. var gh : int = 0;
  605. var gy : int = 0;
  606. var cx : int = 0;
  607. var cw : int = 0;
  608. var group : Sprite;
  609. var column : Sprite;
  610. var component : Sprite;
  611. var bounds : Rectangle;
  612. for (i = 0; i < _container.numChildren; i++)
  613. {
  614. column = _container.getChildAt(i) as Sprite;
  615. column.x = cx;
  616. gy = cw = 0;
  617. ghs = [];
  618. for (j = 0; j < column.numChildren; j++)
  619. {
  620. group = column.getChildAt(j) as Sprite;
  621. group.y = gy;
  622. gw = 0;
  623. gh = PADDING;
  624. for (k = 0; k < group.numChildren; k++)
  625. {
  626. component = group.getChildAt(k) as Sprite;
  627. bounds = component.getBounds(component);
  628. component.x = PADDING - bounds.x;
  629. component.y = gh - bounds.y;
  630. gw = Math.max(gw, bounds.width);
  631. gh += bounds.height + (k < group.numChildren - 1 ? COMPONENT_MARGIN : 0);
  632. }
  633. gh += PADDING;
  634. ghs[j] = gh;
  635. gy += gh + GROUP_MARGIN;
  636. cw = Math.max(cw, gw);
  637. }
  638. cw += (PADDING * 2);
  639. for (j = 0; j < column.numChildren; j++)
  640. {
  641. group = column.getChildAt(j) as Sprite;
  642. for (k = 0; k < group.numChildren - 1; k++)
  643. {
  644. component = group.getChildAt(k) as Sprite;
  645. bounds = component.getBounds(component);
  646. bounds.bottom += COMPONENT_MARGIN / 2;
  647. component.graphics.clear();
  648. component.graphics.lineStyle(0, 0x000000, 0.1);
  649. component.graphics.moveTo(bounds.left, bounds.bottom);
  650. component.graphics.lineTo(bounds.x + cw - (PADDING * 2), bounds.bottom);
  651. }
  652. group.graphics.clear();
  653. group.graphics.beginFill(0xe8e8e8, 0.9);
  654. group.graphics.drawRect(0, 0, cw, ghs[j]);
  655. group.graphics.endFill();
  656. }
  657. cx += cw + COLUMN_MARGIN;
  658. }
  659. _width = cx - COLUMN_MARGIN;
  660. _version.x = _width - _toolbar.x -_version.width - 2;
  661. _toolbar.graphics.clear();
  662. _toolbar.graphics.beginFill(0x333333, 0.9);
  663. _toolbar.graphics.drawRect(0, 0, _width - _toolbar.x, TOOLBAR_HEIGHT);
  664. _toolbar.graphics.endFill();
  665. }
  666. private function parseOptions(target : String, options : Object) : Object
  667. {
  668. options = clone(options);
  669. var type : String = getQualifiedClassName(options);
  670. switch(type)
  671. {
  672. case "String" :
  673. return {label: options};
  674. case "Object" :
  675. options.label = options.label || propToLabel(target);
  676. return options;
  677. default :
  678. return {label: propToLabel(target)};
  679. }
  680. }
  681. private function getTarget(path : String) : Object
  682. {
  683. var target : Object = _target;
  684. var hierarchy : Array = path.split('.');
  685. if (hierarchy.length == 1) return _target;
  686. for (var i : int = 0; i < hierarchy.length - 1; i++)
  687. {
  688. target = target[hierarchy[i]];
  689. }
  690. return target;
  691. }
  692. private function getProp(path : String) : String
  693. {
  694. return /[_a-z0-9]+$/i.exec(path)[0];
  695. }
  696. private function merge(source : Object, destination : Object) : Object
  697. {
  698. var combined : Object = clone(destination);
  699. for (var prop : String in source)
  700. {
  701. if (!destination.hasOwnProperty(prop))
  702. {
  703. combined[prop] = source[prop];
  704. }
  705. }
  706. return combined;
  707. }
  708. private function clone(source : Object) : Object
  709. {
  710. var copy : Object = {};
  711. for (var prop : String in source)
  712. {
  713. copy[prop] = source[prop];
  714. }
  715. return copy;
  716. }
  717. private function propToLabel(prop : String) : String
  718. {
  719. return prop .replace(/[_]+([a-zA-Z0-9]+)|([0-9]+)/g, " $1$2 ")
  720. .replace(/(?<=[a-z0-9])([A-Z])|(?<=[a-z])([0-9])/g, " $1$2")
  721. .replace(/^(\w)|\s+(\w)|\.+(\w)/g, capitalise)
  722. .replace(/^\s|\s$|(?<=\s)\s+/g, '');
  723. }
  724. private function capitalise(...args) : String
  725. {
  726. return String(' ' + args[1] + args[2] + args[3]);
  727. }
  728. // ----------------------------------------------------------------
  729. // EVENT HANDLERS
  730. // ----------------------------------------------------------------
  731. private function onAddedToStage(event : Event) : void
  732. {
  733. _stage = _target.stage;
  734. _target.removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
  735. _target.stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyPressed);
  736. }
  737. private function onTargetAdded(event : Event) : void
  738. {
  739. if (!_hidden) show();
  740. }
  741. private function onSaveButtonClicked(event : MouseEvent) : void
  742. {
  743. save();
  744. }
  745. private function onToggleClicked(event : MouseEvent) : void
  746. {
  747. _hidden ? show() : hide();
  748. }
  749. private function onContextMenuItemSelected(event : ContextMenuEvent) : void
  750. {
  751. _hidden ? show() : hide();
  752. }
  753. private function onComponentClicked(event : MouseEvent) : void
  754. {
  755. commit(event.target as Component);
  756. }
  757. private function onComponentChanged(event : Event) : void
  758. {
  759. commit(event.target as Component);
  760. }
  761. private function onComponentDraw(event : Event) : void
  762. {
  763. var component : Component = event.target as Component;
  764. component.removeEventListener(Component.DRAW, onComponentDraw);
  765. invalidate();
  766. }
  767. private function onEnterFrame(event : Event) : void
  768. {
  769. _container.removeEventListener(Event.ENTER_FRAME, onEnterFrame);
  770. if(_dirty)
  771. {
  772. _dirty = false;
  773. draw();
  774. }
  775. }
  776. private function onKeyPressed(event : KeyboardEvent) : void
  777. {
  778. if(hotKey && event.keyCode == hotKey.toUpperCase().charCodeAt(0))
  779. {
  780. _hidden ? show() : hide();
  781. }
  782. if(event.keyCode == 83)
  783. {
  784. save();
  785. }
  786. }
  787. private function onMessageEnterFrame(event : Event) : void
  788. {
  789. _tween += 0.01;
  790. _message.alpha = 1.0 - (-0.5 * (Math.cos(Math.PI * _tween) - 1));
  791. if (_message.alpha < 0.0001)
  792. {
  793. _message.removeEventListener(Event.ENTER_FRAME, onMessageEnterFrame);
  794. _message.text = '';
  795. }
  796. }
  797. // ----------------------------------------------------------------
  798. // PUBLIC ACCESSORS
  799. // ----------------------------------------------------------------
  800. public function get showToggle() : Boolean
  801. {
  802. return _showToggle;
  803. }
  804. public function set showToggle( value : Boolean ) : void
  805. {
  806. _showToggle = value;
  807. if (_hidden) hide();
  808. }
  809. public function set message(value : String) : void
  810. {
  811. _tween = 0.0;
  812. _message.alpha = 1.0;
  813. _message.text = value.toUpperCase();
  814. _message.addEventListener(Event.ENTER_FRAME, onMessageEnterFrame);
  815. }
  816. public function get hotKey() : *
  817. {
  818. return _hotKey;
  819. }
  820. public function set hotKey( value : * ) : void
  821. {
  822. if (value is String)
  823. {
  824. _hotKey = value;
  825. }
  826. else if (value is int)
  827. {
  828. _hotKey = String.fromCharCode(value);
  829. }
  830. else
  831. {
  832. throw new Error("HotKey must be a String or an integer");
  833. }
  834. message = "Hotkey set to '" + _hotKey + "'";
  835. }
  836. }
  837. }
  838. import com.bit101.components.ComboBox;
  839. import com.bit101.components.Component;
  840. import com.bit101.components.HRangeSlider;
  841. import com.bit101.components.InputText;
  842. import com.bit101.components.Label;
  843. import com.bit101.components.PushButton;
  844. import flash.events.Event;
  845. import flash.events.MouseEvent;
  846. import flash.net.FileReference;
  847. internal class HUIRangeSlider extends HRangeSlider
  848. {
  849. private var _label : Label = new Label();
  850. private var _offset : Number = 0.0;
  851. override protected function addChildren() : void
  852. {
  853. super.addChildren();
  854. _label.y = -5;
  855. addChild(_label);
  856. }
  857. override public function draw() : void
  858. {
  859. _offset = x = _label.width + 5;
  860. _width = Math.min(200 - _offset, 200);
  861. _label.x = -_offset;
  862. super.draw();
  863. }
  864. public function get label() : String
  865. {
  866. return _label.text;
  867. }
  868. public function set label(value : String) : void
  869. {
  870. _label.text = value;
  871. _label.draw();
  872. }
  873. }
  874. internal class FileChooser extends Component
  875. {
  876. public var filter : Array = [];
  877. public var onComplete : Function;
  878. private var _label : Label = new Label();
  879. private var _file : FileReference;
  880. private var _filePath : InputText = new InputText();
  881. private var _button : PushButton = new PushButton();
  882. override protected function addChildren() : void
  883. {
  884. super.addChildren();
  885. _button.x = 125;
  886. _button.width = 75;
  887. _button.label = "Browse";
  888. _button.addEventListener(MouseEvent.CLICK, onButtonClicked);
  889. _filePath.enabled = false;
  890. _filePath.width = 120;
  891. _filePath.height = _button.height;
  892. _button.y = _filePath.y = 20;
  893. addChild(_filePath);
  894. addChild(_button);
  895. addChild(_label);
  896. }
  897. private function onButtonClicked(event : MouseEvent) : void
  898. {
  899. if (_file) _file.browse(filter);
  900. }
  901. private function onFileSelected(event : Event) : void
  902. {
  903. _filePath.text = _file.name;
  904. _file.addEventListener(Event.COMPLETE, onFileComplete);
  905. _file.load();
  906. }
  907. private function onFileComplete(event : Event) : void
  908. {
  909. if (onComplete != null) onComplete();
  910. }
  911. override public function set width(w : Number) : void
  912. {
  913. super.width = w;
  914. _button.x = w - _button.width;
  915. _filePath.width = w - _button.width - 5;
  916. }
  917. public function get label() : String
  918. {
  919. return _label.text;
  920. }
  921. public function set label( value : String ) : void
  922. {
  923. _label.text = value;
  924. }
  925. public function get file() : FileReference
  926. {
  927. return _file;
  928. }
  929. public function set file( value : FileReference ) : void
  930. {
  931. if (_file)
  932. {
  933. _file.removeEventListener(Event.SELECT, onFileSelected);
  934. }
  935. _file = value;
  936. _file.addEventListener(Event.SELECT, onFileSelected);
  937. if(_file.data)
  938. {
  939. _filePath.text = _file.name;
  940. }
  941. }
  942. }
  943. internal class StyledCombo extends ComboBox
  944. {
  945. override protected function addChildren() : void
  946. {
  947. super.addChildren();
  948. _list.defaultColor = 0x333333;
  949. _list.alternateColor = 0x444444;
  950. _list.selectedColor = 0x111111;
  951. _list.rolloverColor = 0x555555;
  952. }
  953. }