diff --git a/src/as/com/threerings/mx/controls/CommandMenu.as b/src/as/com/threerings/mx/controls/CommandMenu.as index 323b8f451..adfbcfbc2 100644 --- a/src/as/com/threerings/mx/controls/CommandMenu.as +++ b/src/as/com/threerings/mx/controls/CommandMenu.as @@ -1,22 +1,36 @@ package com.threerings.mx.controls { +import flash.display.DisplayObject; import flash.display.DisplayObjectContainer; +import flash.geom.Rectangle; + import mx.controls.Menu; import mx.core.mx_internal; import mx.events.MenuEvent; import com.threerings.mx.events.CommandEvent; +/** + * A pretty standard menu that can submit CommandEvents if menu items + * have "command" and possibly "arg" properties. + * + * Example dataProvider array: + * [ { label: "Go home", icon: homeIconClass, + * command: Controller.GO_HOME, arg: homeId }, + * { type: "separator"}, + * { label: "Other places", children: subMenuArray } + * ]; + * + * See "Defining menu structure and data" in the Flex manual for the + * full list. + */ public class CommandMenu extends Menu { public function CommandMenu () { super(); - iconFunction = getIconFor; - labelFunction = getLabelFor; - addEventListener(MenuEvent.ITEM_CLICK, itemClicked); } @@ -24,12 +38,10 @@ public class CommandMenu extends Menu * Factory method to create a command menu. * * @param parent The parent of this menu. - * @param items an array of menu items, where each item is another array - * with the following format: [ text, iconClass, command, arg ]. Arg is - * optional. + * @param items an array of menu items. */ public static function createMenu ( - parent :DisplayObjectContainer, items :Array) :CommandMenu + parent :DisplayObjectContainer, items :Array) :CommandMenu { var menu :CommandMenu = new CommandMenu(); menu.tabEnabled = false; @@ -38,30 +50,76 @@ public class CommandMenu extends Menu return menu; } + /** + * Actually pop up the menu. This can be used instead of show(). + */ + public function popUp ( + trigger :DisplayObject, popUpwards :Boolean = true) :void + { + var r :Rectangle = trigger.getBounds(trigger.stage); + + if (popUpwards) { + show(r.x, 0); + // then, reposition the y once we know our size + y = r.y - getExplicitOrMeasuredHeight(); + + } else { + // simply position it below the trigger + show(r.x, r.y + r.height); + } + } + /** * Callback for MenuEvent.ITEM_CLICK. */ protected function itemClicked (event :MenuEvent) :void { - event.stopImmediatePropagation(); - var element :Array = (event.item as Array); - - CommandEvent.dispatch(mx_internal::parentDisplayObject, - String(element[2]), element[3]); + var cmd :String = getItemCommand(event.item); + if (cmd != null) { + event.stopImmediatePropagation(); + var arg :Object = getItemArgument(event.item); + CommandEvent.dispatch(mx_internal::parentDisplayObject, cmd, arg); + } } - // our function for retrieving a label for a menu entry - protected function getLabelFor (obj :Object) :String + /** + * Get the command for the specified item, if any. + * Somewhat similar to bits in the DefaultDataDescriptor. + */ + protected function getItemCommand (item :Object) :String { - var element :Array = (obj as Array); - return String(element[0]); + try { + if (item is XML) { + return String(item.@command); + + } else if (item is Object) { + return String(item.command); + } + } catch (e :Error) { + // fall through + } + + return null; } - // our function for retrieving an icon for a menu entry - protected function getIconFor (obj :Object) :Class + /** + * Get the command for the specified item, if any. + * Somewhat similar to bits in the DefaultDataDescriptor. + */ + protected function getItemArgument (item :Object) :Object { - var element :Array = (obj as Array); - return Class(element[1]); + try { + if (item is XML) { + return item.@arg; + + } else if (item is Object) { + return item.arg; + } + } catch (e :Error) { + // fall through + } + + return null; } } }