UNPKG

@qooxdoo/framework

Version:

The JS Framework for Coders

389 lines (314 loc) 8.92 kB
/* ************************************************************************ qooxdoo - the new era of web development http://qooxdoo.org Copyright: 2004-2008 1&1 Internet AG, Germany, http://www.1und1.de License: MIT: https://opensource.org/licenses/MIT See the LICENSE file in the project's top-level directory for details. Authors: * Sebastian Werner (wpbasti) * Andreas Ecker (ecker) ************************************************************************ */ /** * A button which acts as a normal button and shows a menu on one * of the sides to open something like a history list. * * @childControl button {qx.ui.form.Button} button to execute action * @childControl arrow {qx.ui.form.MenuButton} arrow to open the popup */ qx.Class.define("qx.ui.form.SplitButton", { extend : qx.ui.core.Widget, include : [qx.ui.core.MExecutable], implement : [qx.ui.form.IExecutable], /* ***************************************************************************** CONSTRUCTOR ***************************************************************************** */ /** * @param label {String} Label to use * @param icon {String?null} Icon to use * @param menu {qx.ui.menu.Menu} Connect to menu instance * @param command {qx.ui.command.Command} Command instance to connect with */ construct : function(label, icon, menu, command) { this.base(arguments); this._setLayout(new qx.ui.layout.HBox); // Force arrow creation this._createChildControl("arrow"); // Add pointer listeners this.addListener("pointerover", this._onPointerOver, this, true); this.addListener("pointerout", this._onPointerOut, this, true); // Add key listeners this.addListener("keydown", this._onKeyDown); this.addListener("keyup", this._onKeyUp); // Process incoming arguments if (label != null) { this.setLabel(label); } if (icon != null) { this.setIcon(icon); } if (menu != null) { this.setMenu(menu); } if (command != null) { this.setCommand(command); } }, /* ***************************************************************************** PROPERTIES ***************************************************************************** */ properties : { // overridden appearance : { refine : true, init : "splitbutton" }, // overridden focusable : { refine : true, init : true }, /** The label/caption/text of the qx.ui.basic.Atom instance */ label : { apply : "_applyLabel", nullable : true, check : "String" }, /** Any URI String supported by qx.ui.basic.Image to display an icon */ icon : { check : "String", apply : "_applyIcon", nullable : true, themeable : true }, /** * Configure the visibility of the sub elements/widgets. * Possible values: both, text, icon */ show : { init : "both", check : [ "both", "label", "icon" ], themeable : true, inheritable : true, apply : "_applyShow", event : "changeShow" }, /** The menu instance to show when tapping on the button */ menu : { check : "qx.ui.menu.Menu", nullable : true, apply : "_applyMenu", event : "changeMenu" } }, /* ***************************************************************************** MEMBERS ***************************************************************************** */ members : { __cursorIsOut : null, /* --------------------------------------------------------------------------- WIDGET API --------------------------------------------------------------------------- */ // overridden _createChildControlImpl : function(id, hash) { var control; switch(id) { case "button": control = new qx.ui.form.Button; control.addListener("execute", this._onButtonExecute, this); control.setFocusable(false); this._addAt(control, 0, {flex: 1}); break; case "arrow": control = new qx.ui.form.MenuButton(); control.setFocusable(false); control.setShow("both"); this._addAt(control, 1); break; } return control || this.base(arguments, id); }, // overridden /** * @lint ignoreReferenceField(_forwardStates) */ _forwardStates : { hovered : 1, focused : 1 }, /* --------------------------------------------------------------------------- PROPERTY APPLY ROUTINES --------------------------------------------------------------------------- */ // property apply _applyLabel : function(value, old) { var button = this.getChildControl("button"); value == null ? button.resetLabel() : button.setLabel(value); }, // property apply _applyIcon : function(value, old) { var button = this.getChildControl("button"); value == null ? button.resetIcon() : button.setIcon(value); }, // property apply _applyMenu : function(value, old) { var arrow = this.getChildControl("arrow"); if (value) { arrow.resetEnabled(); arrow.setMenu(value); value.setOpener(this); value.addListener("changeVisibility", this._onChangeMenuVisibility, this); } else { arrow.setEnabled(false); arrow.resetMenu(); } if (old) { old.removeListener("changeVisibility", this._onChangeMenuVisibility, this); old.resetOpener(); } }, // property apply _applyShow : function(value, old) { // pass: is already inherited to the button }, /* --------------------------------------------------------------------------- EVENT LISTENERS --------------------------------------------------------------------------- */ /** * Listener for <code>pointerover</code> event * * @param e {qx.event.type.Pointer} pointerover event */ _onPointerOver : function(e) { // Captured listener // Whole stop for event, do not let the // inner buttons know about this event. e.stopPropagation(); // Add hover state, is forwarded to the buttons this.addState("hovered"); // Delete cursor out flag delete this.__cursorIsOut; }, /** * Listener for <code>pointerout</code> event * * @param e {qx.event.type.Pointer} pointerout event */ _onPointerOut : function(e) { // Captured listener // Whole stop for event, do not let the // inner buttons know about this event. e.stopPropagation(); // First simple state check if (!this.hasState("hovered")) { return; } // Only when the related target is not part of the button var related = e.getRelatedTarget(); if (qx.ui.core.Widget.contains(this, related)) { return; } // When the menu is visible (cursor moved to the menu) // keep the hover state on the whole button var menu = this.getMenu(); if (menu && menu.isVisible()) { this.__cursorIsOut = true; return; } // Finally remove state this.removeState("hovered"); }, /** * Event listener for all keyboard events * * @param e {qx.event.type.KeySequence} Event object */ _onKeyDown : function(e) { var button = this.getChildControl("button"); switch(e.getKeyIdentifier()) { case "Enter": case "Space": button.removeState("abandoned"); button.addState("pressed"); } }, /** * Event listener for all keyboard events * * @param e {qx.event.type.KeySequence} Event object */ _onKeyUp : function(e) { var button = this.getChildControl("button"); switch(e.getKeyIdentifier()) { case "Enter": case "Space": if (button.hasState("pressed")) { button.removeState("abandoned"); button.removeState("pressed"); button.execute(); } } }, /** * Event listener for button's execute event. * * @param e {qx.event.type.Event} execute event of the button */ _onButtonExecute : function(e) { // forward execute event this.execute(); }, /** * Event listener for visibility changes of the menu * * @param e {qx.event.type.Data} property change event */ _onChangeMenuVisibility : function(e) { if (!this.getMenu().isVisible() && this.__cursorIsOut) { this.removeState("hovered"); } } } });