/** * Copyright (c) 2003-2009, Xith3D Project Group all rights reserved. * * Portions based on the Java3D interface, Copyright by Sun Microsystems. * Many thanks to the developers of Java3D and Sun Microsystems for their * innovation and design. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the 'Xith3D Project Group' nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) A * RISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE */ package org.xith3d.ui.hud.menusystem.menus.settings; import java.util.ArrayList; import java.util.HashMap; import org.jagatoo.commands.CommandsRegistry; import org.jagatoo.input.actions.LabeledInputAction; import org.jagatoo.input.devices.components.DeviceComponent; import org.jagatoo.input.devices.components.Key; import org.jagatoo.input.devices.components.MouseButton; import org.jagatoo.input.devices.components.MouseButtons; import org.jagatoo.input.managers.InputBindingsManager; import org.jagatoo.input.managers.InputBindingsSet; import org.openmali.vecmath2.Colorf; import org.xith3d.ui.hud.base.Widget; import org.xith3d.ui.hud.borders.ColoredBorder; import org.xith3d.ui.hud.layout.FillLayout; import org.xith3d.ui.hud.layout.GridLayout; import org.xith3d.ui.hud.layout.LayoutManager; import org.xith3d.ui.hud.listeners.WidgetInputAdapter; import org.xith3d.ui.hud.listeners.WidgetInputListener; import org.xith3d.ui.hud.listeners.WidgetMouseAdapter; import org.xith3d.ui.hud.listeners.WidgetMouseListener; import org.xith3d.ui.hud.menusystem.menus.MenuBase; import org.xith3d.ui.hud.utils.HUDFont; import org.xith3d.ui.hud.widgets.Label; import org.xith3d.ui.hud.widgets.Panel; import org.xith3d.ui.text2d.TextAlignment; /** * This is a settings menu for general key-bindings * to bind keys to {@link LabeledInputAction}s. * * @author Marvin Froehlich (aka Qudus) */ public class InputBindingsSettingsMenu extends MenuBase { public static final String NAME = InputBindingsSettingsMenu.class.getSimpleName(); private final LabeledInputAction[] actions; private final HashMap< LabeledInputAction, Label[] > actionLabelMap = new HashMap< LabeledInputAction, Label[] >(); private final HashMap< Label, LabeledInputAction > labelActionMap = new HashMap< Label, LabeledInputAction >(); private final InputBindingsManager< LabeledInputAction > inputBindings; private Label bindingQuery; private Label lastClickedLabel = null; public void setBinding( DeviceComponent comp, LabeledInputAction action, InputBindingsSet set ) { LabeledInputAction bound = inputBindings.getBoundAction( comp ); if ( bound != null ) { Label[] boundLabels = actionLabelMap.get( bound ); if ( boundLabels[ 0 ].getText().equals( comp.getName() ) ) boundLabels[ 0 ].setText( "" ); else if ( boundLabels[ 1 ].getText().equals( comp.getName() ) ) boundLabels[ 1 ].setText( "" ); } final Label targetLabel; if ( set == InputBindingsSet.PRIMARY ) targetLabel = actionLabelMap.get( action )[ 0 ]; else //if ( set == InputBindingSet.SECONDARY ) targetLabel = actionLabelMap.get( action )[ 1 ]; inputBindings.bind( comp, action, set ); targetLabel.setText( comp.getLocalizedName() ); } public void resetBinding( LabeledInputAction action, InputBindingsSet set ) { if ( inputBindings.unbind( action ) != null ) { final Label targetLabel; if ( set == InputBindingsSet.PRIMARY ) targetLabel = actionLabelMap.get( action )[ 0 ]; else //if ( set == InputBindingSet.SECONDARY ) targetLabel = actionLabelMap.get( action )[ 1 ]; targetLabel.setText( "" ); } } public LabeledInputAction getBinding( DeviceComponent comp ) { return ( inputBindings.getBoundAction( comp ) ); } public DeviceComponent getBoundComponent( LabeledInputAction action, InputBindingsSet set ) { return ( inputBindings.getBoundComponent( action, set ) ); } public void clearBindings() { inputBindings.unbindAll(); for ( Label label: labelActionMap.keySet() ) { label.setText( "" ); } } @SuppressWarnings( "unchecked" ) public < A extends LabeledInputAction > void setBindings( InputBindingsManager< A > inputBindings ) { clearBindings(); for ( LabeledInputAction action: actions ) { for ( InputBindingsSet set: InputBindingsSet.values() ) { final DeviceComponent comp = inputBindings.getBoundComponent( (A)action, set ); if ( comp != null ) { setBinding( comp, action, set ); } } } } public InputBindingsManager< LabeledInputAction > getBindings() { return ( inputBindings ); } private WidgetInputListener bindingSetListener = new WidgetInputAdapter() { private final void handleInput( DeviceComponent comp ) { bindingQuery.removeInputListener( bindingSetListener ); if ( lastClickedLabel == null ) return; bindingQuery.setClickable( false ); bindingQuery.setPickable( false ); bindingQuery.setVisible( false ); final LabeledInputAction action = labelActionMap.get( lastClickedLabel ); setBinding( comp, action, (InputBindingsSet)lastClickedLabel.getUserObject() ); getMenuGroup().fireOnSettingChanged( InputBindingsSettingsMenu.this, "input_binding", comp.getName() + "=>" + action.getLocalizedText() ); lastClickedLabel = null; } @Override public void onKeyPressed( Widget widget, Key key, int modifierMask, long when ) { handleInput( key ); } @Override public void onMouseWheelMoved( Widget widget, int delta, boolean isPageMove, float x, float y, long when, boolean isTopMost ) { if ( delta > 0 ) handleInput( MouseButtons.WHEEL_UP ); else handleInput( MouseButtons.WHEEL_DOWN ); } @Override public void onMouseButtonPressed( Widget widget, MouseButton button, float x, float y, long when, long lastWhen, boolean isTopMost, boolean hasFocus ) { handleInput( button ); } }; private WidgetMouseListener bindingInputListener = new WidgetMouseAdapter() { @Override public void onMouseButtonReleased( Widget widget, MouseButton button, float x, float y, long when, long lastWhen, boolean isTopMost, boolean hasFocus ) { lastClickedLabel = (Label)widget; if ( ( lastWhen != -1L ) && ( ( when - lastWhen ) < 300L ) ) { float parentLeft = 0f; float parentTop = 0f; float parentResX = 0f; float parentResY = 0f; if ( widget.getContainer() != null ) { parentLeft = widget.getContainer().getLeft(); parentTop = widget.getContainer().getTop(); parentResX = widget.getContainer().getResX(); parentResY = widget.getContainer().getResY(); } else if ( widget.getHUD() != null ) { parentResX = widget.getHUD().getResX(); parentResY = widget.getHUD().getResY(); } bindingQuery.setLocation( parentLeft + 2f, parentTop + 2f ); bindingQuery.setSize( parentResX - 4f, parentResY - 4f ); bindingQuery.setClickable( true ); bindingQuery.setPickable( true ); bindingQuery.setVisible( true ); bindingQuery.requestFocus(); bindingQuery.addInputListener( bindingSetListener ); } } }; private ArrayList< Widget > earlyWidgets; /** * {@inheritDoc} */ @Override protected void initWidgets() { if ( earlyWidgets != null ) { for ( int i = 0; i < earlyWidgets.size(); i++ ) { addWidget( earlyWidgets.get( i ) ); } earlyWidgets = null; } } private Panel createMiniPanel( float height, int borderBottom, int borderRight, int borderTop, int borderLeft, Colorf backgroundColor ) { Panel panel = new Panel( 200f, height, backgroundColor ); panel.setLayout( new FillLayout() ); panel.setBorder( new ColoredBorder( borderBottom, borderRight, borderTop, borderLeft, Colorf.DARK_GRAY ) ); return ( panel ); } private void addHeaderLine( HUDFont font ) { Panel panel1 = createMiniPanel( 30f, 1, 1, 1, 1, null ); Label label1 = new Label( 0f, 0f, "Command", font, Colorf.BLACK, TextAlignment.CENTER_LEFT ); label1.setPadding( 0, 3, 0, 3 ); panel1.addWidget( label1 ); earlyWidgets.add( panel1 ); Panel panel2 = createMiniPanel( 30f, 1, 1, 1, 0, null ); Label label2 = new Label( 0f, 0f, "Key 1", font, Colorf.BLACK, TextAlignment.CENTER_CENTER ); panel2.addWidget( label2 ); earlyWidgets.add( panel2 ); Panel panel3 = createMiniPanel( 30f, 1, 1, 1, 0, null ); Label label3 = new Label( 0f, 0f, "Key 2", font, Colorf.BLACK, TextAlignment.CENTER_CENTER ); panel3.addWidget( label3 ); earlyWidgets.add( panel3 ); Panel panel4 = createMiniPanel( 5f, 0, 1, 0, 1, null ); earlyWidgets.add( panel4 ); Panel panel5 = createMiniPanel( 5f, 0, 1, 0, 0, null ); earlyWidgets.add( panel5 ); Panel panel6 = createMiniPanel( 5f, 0, 1, 0, 0, null ); earlyWidgets.add( panel6 ); } private void addBindingLine( String caption, LabeledInputAction command, HUDFont font ) { final int borderTop = ( actionLabelMap.size() == 0 ) ? 1: 0; Panel panel1 = createMiniPanel( 30f, 1, 1, borderTop, 1, null ); Label label1 = new Label( 1f, 1f, caption, font, Colorf.BLACK, TextAlignment.CENTER_LEFT ); label1.setPadding( 0, 3, 0, 3 ); panel1.addWidget( label1 ); earlyWidgets.add( panel1 ); Panel panel2 = createMiniPanel( 30f, 1, 1, borderTop, 0, Colorf.BLACK ); Label label2 = new Label( 1f, 1f, "", font, Colorf.WHITE, TextAlignment.CENTER_CENTER ); label2.setUserObject( InputBindingsSet.PRIMARY ); label2.addMouseListener( bindingInputListener ); panel2.addWidget( label2 ); earlyWidgets.add( panel2 ); Panel panel3 = createMiniPanel( 30f, 1, 1, borderTop, 0, Colorf.BLACK ); Label label3 = new Label( 1f, 1f, "", font, Colorf.WHITE, TextAlignment.CENTER_CENTER ); label3.setUserObject( InputBindingsSet.SECONDARY ); label3.addMouseListener( bindingInputListener ); panel3.addWidget( label3 ); earlyWidgets.add( panel3 ); actionLabelMap.put( command, new Label[] { label2, label3 } ); labelActionMap.put( label2, command ); labelActionMap.put( label3, command ); } private InputBindingsSettingsMenu( float width, float height, LabeledInputAction[] commands, Object[] commandObjs ) { super( width, height, InputBindingsSettingsMenu.NAME, new String[] { "save" } ); if ( commands == null ) { this.actions = new LabeledInputAction[ commandObjs.length ]; for ( int i = 0; i < commandObjs.length; i++ ) { this.actions[ i ] = (LabeledInputAction)commandObjs[ i ]; } } else { this.actions = commands; } this.inputBindings = new InputBindingsManager< LabeledInputAction >( this.actions.length ); this.setLayout( new GridLayout( 0, 3, 0f, 0f, 10f, 10f, 10f, 10f ) ); HUDFont font = HUDFont.getFont( "Verdana", HUDFont.PLAIN, 12 ); earlyWidgets = new ArrayList< Widget >(); addHeaderLine( font.derive( HUDFont.BOLD ) ); for ( int i = 0; i < this.actions.length; i++ ) { final LabeledInputAction command = this.actions[ i ]; addBindingLine( command.getLocalizedText(), command, font ); } this.bindingQuery = new Label( 0f, 0f, "PRESS_KEY", font.derive( HUDFont.BOLD ), Colorf.GREEN, TextAlignment.CENTER_CENTER ); this.bindingQuery.setZIndex( 10 ); bindingQuery.setBackgroundColor( Colorf.BLACK ); this.addWidget( bindingQuery, 100f, 100f, LayoutManager.IGNORED_BY_LAYOUT ); bindingQuery.setVisible( false ); bindingQuery.setClickable( false ); bindingQuery.setPickable( false ); } public InputBindingsSettingsMenu( float width, float height, LabeledInputAction[] commands ) { this( width, height, commands, null ); } public InputBindingsSettingsMenu( float width, float height, CommandsRegistry< ? extends LabeledInputAction > commandsReg ) { this( width, height, null, commandsReg.values() ); } public InputBindingsSettingsMenu( float width, LabeledInputAction[] commands ) { this( width, 0f, commands ); setMinimalHeight(); } public InputBindingsSettingsMenu( float width, CommandsRegistry< ? extends LabeledInputAction > commandsReg ) { this( width, 0f, commandsReg ); setMinimalHeight(); } }