/** * 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.widgets.assemblies; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import org.jagatoo.commands.AlphabeticalCommandsKeyComparator; import org.jagatoo.commands.Command; import org.jagatoo.commands.NoParamCommandBase; import org.jagatoo.input.devices.components.DeviceComponent; import org.jagatoo.input.devices.components.Key; import org.jagatoo.input.devices.components.Keys; import org.jagatoo.logging.LogChannel; import org.jagatoo.logging.LogInterface; import org.jagatoo.logging.LogLevel; import org.openmali.types.twodee.Dim2f; import org.openmali.vecmath2.Colorf; import org.openmali.vecmath2.Tuple2f; import org.xith3d.scenegraph.Texture2D; import org.xith3d.scenegraph.Texture2DCanvas; import org.xith3d.ui.hud.HUD; import org.xith3d.ui.hud.__HUD_PrivilegedAccess; import org.xith3d.ui.hud.base.BackgroundSettableWidget; import org.xith3d.ui.hud.base.Border; import org.xith3d.ui.hud.base.Widget; import org.xith3d.ui.hud.borders.BorderFactory; import org.xith3d.ui.hud.listeners.TextFieldListener; import org.xith3d.ui.hud.listeners.WidgetKeyboardAdapter; import org.xith3d.ui.hud.listmodels.TextListModel; import org.xith3d.ui.hud.utils.HUDFont; import org.xith3d.ui.hud.utils.PopUpable; import org.xith3d.ui.hud.utils.ScrollMode; import org.xith3d.ui.hud.utils.TileMode; import org.xith3d.ui.hud.utils.WidgetMover; import org.xith3d.ui.hud.widgets.List; import org.xith3d.ui.hud.widgets.TextField; import org.xith3d.utility.comparator.IgnoreCaseComparator; import org.xith3d.utility.comparator.StartsWithIgnoreCaseComparator; /** * A Console is what you will know from many kinds of games * mostly from FPS games. Logging is dumped to it and you can type commands. * * @author Marvin Froehlich (aka Qudus) */ public class HUDConsole extends BackgroundSettableWidget implements PopUpable, LogInterface { public static class Description extends BackgroundSettableWidget.BackgroundSettableDescriptionBase { private Border.Description borderDesc; private List.Description listDesc; private TextField.Description inputBoxDesc; private List.Description previewListDesc; private float listInputBoxGap; private float inputBoxHeight; private HUDFont listFont; private Colorf listFontColorNormal; private Colorf listFontColorWarning; private Colorf listFontColorError; public void setBorderDescription( Border.Description borderDesc ) { this.borderDesc = borderDesc; } public Border.Description getBorderDescription() { return ( borderDesc ); } public void setListFontColorNormal( Colorf color ) { this.listFontColorNormal = color; } public Colorf getListFontColorNormal() { return ( listFontColorNormal ); } public void setListFontColorWarning( Colorf color ) { this.listFontColorWarning = color; } public Colorf getListFontColorWarning() { return ( listFontColorWarning ); } public void setListFontColorError( Colorf color ) { this.listFontColorError = color; } public Colorf getListFontColorError() { return ( listFontColorError ); } public void setListFont( HUDFont listFont ) { this.listFont = listFont; } public HUDFont getListFont() { return ( listFont ); } public void setListDescription( List.Description listDesc ) { this.listDesc = listDesc; } public List.Description getListDescription() { return ( listDesc ); } public void setInputBoxDescription( TextField.Description inputBoxDesc ) { this.inputBoxDesc = inputBoxDesc; } public TextField.Description getInputBoxDescription() { return ( inputBoxDesc ); } public void setPreviewListDescription( List.Description listDesc ) { this.previewListDesc = listDesc; } public List.Description getPreviewListDescription() { return ( previewListDesc ); } public void setListInputBoxGap( float gap ) { this.listInputBoxGap = gap; } public float getListInputBoxGap() { return ( listInputBoxGap ); } public void setInputBoxHeight( float height ) { this.inputBoxHeight = height; } public float getInputBoxHeight() { return ( inputBoxHeight ); } @Override public Description clone() { return ( new Description( this ) ); } public Description( HUDConsole.Description template ) { super( template.getBackgroundColor(), template.getBackgroundTexture() ); this.borderDesc = template.getBorderDescription().clone(); this.listFontColorNormal = template.getListFontColorNormal(); this.listFontColorWarning = template.getListFontColorWarning(); this.listFontColorError = template.getListFontColorError(); this.listFont = template.getListFont(); this.listDesc = template.getListDescription().clone(); this.inputBoxDesc = template.getInputBoxDescription().clone(); this.previewListDesc = template.getPreviewListDescription().clone(); this.listInputBoxGap = template.getListInputBoxGap(); this.inputBoxHeight = template.getInputBoxHeight(); } public Description( Border.Description borderDesc, Texture2D backgroundTexture, Colorf backgroundColor, Colorf listFontColorNormal, Colorf listFontColorWarning, Colorf listFontColorError, List.Description listDesc, TextField.Description inputBoxDesc, List.Description previewListDesc, float listTextFieldGap, float inputBoxHeight ) { super( backgroundColor, backgroundTexture ); this.borderDesc = borderDesc; this.listFontColorNormal = listFontColorNormal; this.listFontColorWarning = listFontColorWarning; this.listFontColorError = listFontColorError; this.listDesc = listDesc; this.inputBoxDesc = inputBoxDesc; this.previewListDesc = previewListDesc; this.listInputBoxGap = listTextFieldGap; this.inputBoxHeight = inputBoxHeight; } public Description() { super( Colorf.DARK_GRAY, null ); this.borderDesc = new Border.Description( 10, 10, 10, 10 ); this.listFontColorNormal = Colorf.WHITE; this.listFontColorWarning = Colorf.ORANGE; this.listFontColorError = Colorf.RED; this.listDesc = HUD.getTheme().getListDescription(); this.inputBoxDesc = HUD.getTheme().getTextFieldDescription(); this.listInputBoxGap = 10f; this.inputBoxHeight = 20f; listDesc.setBorderDescription( new Border.Description( 2, 2, 2, 2, Colorf.LIGHT_GRAY ) ); listDesc.setBackgroundColor( null ); listDesc.setBackgroundTexture( (Texture2D)null ); inputBoxDesc.setBorderDescription( new Border.Description( 2, 2, 2, 2, Colorf.LIGHT_GRAY ) ); inputBoxDesc.setBackgroundColor( null ); inputBoxDesc.setBackgroundTexture( (Texture2D)null ); inputBoxDesc.setFontColor( listFontColorNormal, false ); inputBoxDesc.setCaretTexture( "white" ); this.previewListDesc = listDesc.clone(); previewListDesc.setBackgroundColor( this.getBackgroundColor() ); previewListDesc.setBackgroundTexture( this.getBackgroundTexture() ); } public Description( Texture2D backgroundTexture ) { this(); this.setBackgroundColor( null ); this.setBackgroundTexture( backgroundTexture ); } public Description( Colorf backgroundColor ) { this(); this.setBackgroundColor( backgroundColor ); this.setBackgroundTexture( (Texture2D)null ); } public Description( Texture2D backgroundTexture, Colorf listFontColorNormal, Colorf listFontColorWarning, Colorf listFontColorError ) { this(); this.setBackgroundColor( null ); this.setBackgroundTexture( backgroundTexture ); this.listFontColorNormal = listFontColorNormal; this.listFontColorWarning = listFontColorWarning; this.listFontColorError = listFontColorError; inputBoxDesc.setFontColor( listFontColorNormal, false ); } public Description( Colorf backgroundColor, Colorf listFontColorNormal, Colorf listFontColorWarning, Colorf listFontColorError ) { this(); this.setBackgroundColor( backgroundColor ); this.setBackgroundTexture( (Texture2D)null ); this.listFontColorNormal = listFontColorNormal; this.listFontColorWarning = listFontColorWarning; this.listFontColorError = listFontColorError; inputBoxDesc.setFontColor( listFontColorNormal, false ); } } private static final class InputBox extends TextField { /** * {@inheritDoc} */ @Override protected boolean blocksFocusMoveDeviceComponent( DeviceComponent dc ) { if ( super.blocksFocusMoveDeviceComponent( dc ) ) return ( true ); if ( dc == Keys.UP ) return ( true ); if ( dc == Keys.DOWN ) return ( true ); return ( false ); } public InputBox( float width, float height ) { super( width, height ); } public InputBox( float width, float height, TextField.Description desc ) { super( width, height, "", desc ); } } /** * This {@link Command} simply tells a Console to dump all known {@link Command}s. * * @author Marvin Froehlich (aka Qudus) */ private class HelpCommand extends NoParamCommandBase { /** * {@inheritDoc} */ public String execute( Boolean inputInfo ) { HUDConsole.this.dumpKnownCommands(); return ( "dump known commands." ); } public final String execute() { return ( execute( (Boolean)null ) ); } public HelpCommand() { super( "help" ); } } private final List list; private final float listInputBoxGap; private final TextField inputBox; private final List commandPreview; private boolean isPoppedUp = true; private boolean trimMessages = true; private final WidgetMover mover = new WidgetMover( this ) { @Override protected void onMovementStopped() { if ( !isPoppedUp() ) { // Set invisible to save performance! HUDConsole.this.setVisible( false ); if ( getHUD() != null ) { getHUD().disposeFocus(); } } } }; private Boolean initiallyVisible; private int logLevel; private int channelFilter; private final Colorf errorColor; private final Colorf warningColor; private final Colorf normalColor; private final ArrayList<String> enteredCommands = new ArrayList<String>(); private final HashMap<String, Command> registeredCommands = new HashMap<String, Command>(); private final ArrayList<ConsoleListener> listeners = new ArrayList<ConsoleListener>(); /** * Adds a {@link ConsoleListener} to the list of notified listeners. * * @param l */ public final void addConsoleListener( ConsoleListener l ) { listeners.add( l ); } /** * Removes a {@link ConsoleListener} from the list of notified listeners. * * @param l */ public final void removeConsoleListener( ConsoleListener l ) { listeners.remove( l ); } private final boolean compare( float v1, float v2 ) { return ( Math.abs( v2 - v1 ) < ( this.getWidth() + this.getHeight() ) / 1000f ); } private boolean isCommandPreviewVisible() { return ( commandPreview.isVisible() && ( commandPreview.getHUD() != null ) ); } private void setCommandPreviewListVisible( boolean visible ) { if ( visible ) { if ( isCommandPreviewVisible() ) return; Tuple2f loc = Tuple2f.fromPool(); getHUD().getCoordinatesConverter().getAbsoluteLocationOnHUD( inputBox, loc ); __HUD_PrivilegedAccess.addVolatilePopup( getHUD(), commandPreview, null, loc.getX() + 10f, loc.getY() + inputBox.getHeight() ); Tuple2f.toPool( loc ); } else { if ( !isCommandPreviewVisible() ) return; __HUD_PrivilegedAccess.removeVolatilePopup( getHUD() ); //commandPreview.setVisible( false ); } } private final void popUp( boolean p, boolean jump ) { if ( !p ) { setCommandPreviewListVisible( false ); } final HUD hud = getHUD(); boolean doIt = false; if ( !mover.isMoving() ) { if ( isPoppedUp() && !p ) { // fade out... if ( ( compare( this.getTop(), 0f ) ) && ( compare( this.getLeft(), 0f ) ) && ( compare( this.getWidth(), hud.getResX() ) ) ) { // fade out to top in half a second mover.setDestinationLocation( 0f, -this.getHeight() ); mover.setSpeed( this.getHeight() * 2f ); doIt = true; } else if ( ( compare( this.getTop(), 0f ) ) && ( compare( this.getLeft(), 0f ) ) && ( compare( this.getHeight(), hud.getResY() ) ) ) { // fade out to left in half a second mover.setDestinationLocation( -this.getWidth(), 0f ); mover.setSpeed( this.getWidth() * 2f ); doIt = true; } else if ( ( compare( this.getTop(), hud.getResY() - this.getHeight() ) ) && ( compare( this.getLeft(), 0f ) ) && ( compare( this.getWidth(), hud.getResX() ) ) ) { // fade out to bottom in half a second mover.setDestinationLocation( 0f, hud.getResY() ); mover.setSpeed( this.getHeight() * 2f ); doIt = true; } else if ( ( compare( this.getTop(), 0f ) ) && ( compare( this.getLeft(), hud.getResX() - this.getWidth() ) ) && ( compare( this.getHeight(), hud.getResY() ) ) ) { // fade out to right in half a second mover.setDestinationLocation( hud.getResX(), 0f ); mover.setSpeed( this.getWidth() * 2f ); doIt = true; } } else if ( !isPoppedUp() && p ) { // fade in... if ( this.getTop() < -( this.getHeight() / 2f ) ) { // fade in from top in half a second mover.setDestinationLocation( 0f, 0f ); mover.setSpeed( this.getHeight() * 2f ); doIt = true; } else if ( this.getLeft() < -( this.getWidth() / 2f ) ) { // fade in from left in half a second mover.setDestinationLocation( 0f, 0f ); mover.setSpeed( this.getWidth() * 2f ); doIt = true; } else if ( this.getTop() > hud.getResY() - ( this.getHeight() / 2f ) ) { // fade in from bottom in half a second mover.setDestinationLocation( 0f, hud.getResY() - this.getHeight() ); mover.setSpeed( this.getHeight() * 2f ); doIt = true; } else if ( this.getLeft() > hud.getResX() - ( this.getWidth() / 2f ) ) { // fade in from right in half a second mover.setDestinationLocation( hud.getResX() - this.getWidth(), 0f ); mover.setSpeed( this.getWidth() * 2f ); doIt = true; } } } if ( doIt ) { if ( !jump ) { if ( !isPoppedUp() && p ) { // force visibility this.setVisible( true ); if ( isInputBoxVisible() ) inputBox.requestFocus(); else list.requestFocus(); } mover.startMoving(); } else { this.setLocation( mover.getDestinationLocation() ); if ( !p ) hud.disposeFocus(); } } isPoppedUp = p; } /** * {@inheritDoc} */ public void popUp( boolean p ) { popUp( p, false ); } /** * {@inheritDoc} */ public boolean isPoppedUp() { return ( isPoppedUp ); } /** * Sets the color to be used for the given LogLevel.<br> * Currently ERROR, EXCEPTION and REGULAR use distinct colors * and DEBUG, EXHAUSTIVE and PROFILE will use the REGULAR color. * * @param logLevel * @param color */ public void setListFontColor( int logLevel, Colorf color ) { if ( color == null ) throw new NullPointerException( "color" ); switch ( logLevel ) { case LogLevel.ERROR: errorColor.set( color ); break; case LogLevel.EXCEPTION: warningColor.set( color ); break; case LogLevel.DEBUG: case LogLevel.EXHAUSTIVE: case LogLevel.PROFILE: case LogLevel.REGULAR: normalColor.set( color ); break; } throw new IllegalArgumentException( "This LogLevel is invalid." ); } /** * @return the color to be used for the given LogLevel.<br> * Currently ERROR, EXCEPTION and REGULAR use distinct colors * and DEBUG, EXHAUSTIVE and PROFILE will use the REGULAR color. * * @param logLevel */ public Colorf getListFontColor( int logLevel ) { switch ( logLevel ) { case LogLevel.ERROR: return ( errorColor ); case LogLevel.EXCEPTION: return ( warningColor ); case LogLevel.DEBUG: case LogLevel.EXHAUSTIVE: case LogLevel.PROFILE: case LogLevel.REGULAR: return ( normalColor ); } throw new IllegalArgumentException( "This LogLevel is invalid." ); } public final void setLogLevel( int logLevel ) { this.logLevel = logLevel; } public final int getLogLevel() { return ( logLevel ); } public final void setChannelFilter( int filter ) { this.channelFilter = filter; } public final int getChannelFilter() { return ( channelFilter ); } public final boolean acceptsChannel( LogChannel channel ) { return ( ( channelFilter & channel.getID() ) > 0 ); } public boolean println( String message, Colorf color ) { if ( trimMessages ) message = message.trim(); if ( message.length() > 0 ) { list.addItem( message, color ); return ( true ); } return ( false ); } public final boolean println( int logLevel, String message ) { return ( println( message, getListFontColor( logLevel ) ) ); } public final boolean println( String message ) { return ( println( LogLevel.REGULAR, message ) ); } /** * {@inheritDoc} */ public final void print( LogChannel channel, int logLevel, String message ) { if ( ( acceptsChannel( channel ) ) && ( logLevel <= this.logLevel ) ) { println( logLevel, message ); } } /** * {@inheritDoc} */ public final void println( LogChannel channel, int logLevel, String message ) { if ( ( acceptsChannel( channel ) ) && ( logLevel <= this.logLevel ) ) { println( logLevel, message ); } } private final int findCommandPreviewIndex( String command ) { for ( int i = 0; i < enteredCommands.size(); i++ ) { final int cmp = IgnoreCaseComparator.compareIC( command, enteredCommands.get( i ) ); if ( cmp < 0 ) { return ( i ); } else if ( cmp == 0 ) { // This command already exists! return ( -1 ); } } return ( enteredCommands.size() ); } private final void addCommandToPreview( String command, String previewString ) { final int index = findCommandPreviewIndex( command ); if ( index >= 0 ) { enteredCommands.add( index, previewString ); } } private static String getCommandSignature( Command command ) { String[] params = command.getParameterTypes(); String sig = command.getKey(); if ( params != null ) { for ( int i = 0; i < params.length; i++ ) { if ( i == 0 ) sig += "( " + params[ i ]; else if ( i == params.length - 1 ) sig += ", " + params[ i ] + " )"; else sig += ", " + params[ i ]; } } else { sig += "()"; } return ( sig ); } public void registerCommand( Command command ) { String sig = getCommandSignature( command ); addCommandToPreview( command.getKey(), sig ); registeredCommands.put( command.getKey(), command ); } public void registerCommands( Command[] commands ) { for ( int i = 0; i < commands.length; i++ ) { registerCommand( commands[ i ] ); } } public void registerCommands( java.util.List< Command > commands ) { for ( int i = 0; i < commands.size(); i++ ) { registerCommand( commands.get( i ) ); } } public Command[] getRegisteredCommands() { Command[] commands = new Command[ registeredCommands.size() ]; int i = 0; for ( Command cmd : registeredCommands.values() ) { commands[i++] = cmd; } Arrays.sort( commands, AlphabeticalCommandsKeyComparator.getInstance() ); return ( commands ); } /** * Dumps all registered Commands to the console. */ public void dumpKnownCommands() { for ( Command command : getRegisteredCommands() ) { println( getCommandSignature( command ) ); } } /** * This event is fired when a command has been typed to the input-box.<br> * * @param commandLine the entered command */ protected void onCommandEntered( String commandLine ) { commandLine = commandLine.trim(); /* String commandKey = commandLine; int firstSpace = commandLine.indexOf( ' ' ); if ( firstSpace > 0 ) { commandKey = commandLine.substring( 0, firstSpace ); } else { firstSpace = commandLine.indexOf( '(' ); if ( firstSpace > 0 ) { commandKey = commandLine.substring( 0, firstSpace ); } } */ //commandLine = commandKey; addCommandToPreview( commandLine, commandLine ); setCommandPreviewListVisible( false ); commandPreview.setSelectedIndex( -1 ); // notify listeners... for ( int i = 0; i < listeners.size(); i++ ) { listeners.get( i ).onCommandEntered( this, commandLine ); } } protected void updatePreviewListSize( List previewList ) { previewList.setSize( previewList.getMinWidthThatFitsItems(), 100f ); previewList.setHeightByItems( Math.min( previewList.getItemsCount(), 5 ) ); } protected void updateTypePreview( String text ) { if ( enteredCommands.size() == 0 ) { setCommandPreviewListVisible( false ); return; } int first = Collections.binarySearch( enteredCommands, text, StartsWithIgnoreCaseComparator.INSTANCE ); if ( first < 0 ) { setCommandPreviewListVisible( false ); return; } while ( ( first > 0 ) && StartsWithIgnoreCaseComparator.startsWithIC( enteredCommands.get( first - 1 ), text ) ) { first--; } TextListModel model = (TextListModel)commandPreview.getModel(); model.clear(); int i = first; String ec = enteredCommands.get( first ); do { model.addItem( ec ); i++; if ( i >= enteredCommands.size() ) break; ec = enteredCommands.get( i ); } while ( StartsWithIgnoreCaseComparator.startsWithIC( ec, text ) ); model.markListDirty(); setCommandPreviewListVisible( true ); updatePreviewListSize( commandPreview ); } /** * {@inheritDoc} */ public void flush() { } /** * {@inheritDoc} */ public void close() { } /** * Sets the array of chars ignored by this HUDConsole. * This is especially useful when a printable char's key is used to popup * the console. * * @param ignoredChars */ public void setIgnoredChars( char... ignoredChars ) { inputBox.setIgnoredChars( ignoredChars ); } /** * @return the array of chars ignored by this HUDConsole. * This is especially useful when a printable char's key is used to popup * the console. */ public char[] getIgnoredChars() { return ( inputBox.getIgnoredChars() ); } /** * Sets if the messages should be trimmed before display.<br> * Default is 'true'. * * @param trimMessages 'true' if messages should be trimmed. */ public void setTrimMessages( boolean trimMessages ) { this.trimMessages = trimMessages; } /** * @return 'true' if messages are trimmed before displaying them */ public boolean isTrimMessages() { return ( trimMessages ); } /** * Defines, if the {@link HUDConsole}'s input-box is visible or hidden. * * @param visible */ public void setInputBoxVisible( boolean visible ) { this.inputBox.setVisible( visible ); if ( !visible && inputBox.hasFocus( true ) ) list.requestFocus(); update(); } /** * @return if the {@link HUDConsole}'s input-box is visible or hidden. */ public boolean isInputBoxVisible() { return ( inputBox.isVisible() ); } @Override protected void onAttachedToHUD( HUD hud ) { super.onAttachedToHUD( hud ); if ( ( initiallyVisible != null ) && !initiallyVisible.booleanValue() ) { initiallyVisible = null; popUp( false, true ); } } /** * {@inheritDoc} */ @Override protected void onSizeChanged( float oldWidth, float oldHeight, float newWidth, float newHeight ) { final float innerWidth; final float innerHeight; if ( getBorder() == null ) { innerWidth = this.getWidth(); innerHeight = this.getHeight(); } else { innerWidth = this.getWidth() - getBorder().getLeftWidth() - getBorder().getRightWidth(); innerHeight = this.getHeight() - getBorder().getTopHeight() - getBorder().getBottomHeight(); } float inputBoxHeight = 0f; if ( inputBox.isVisible() ) { inputBox.setSize( innerWidth, inputBox.getHeight() ); inputBoxHeight = inputBox.getHeight(); if ( getBorder() != null ) getWidgetAssembler().reposition( inputBox, getBorder().getLeftWidth(), this.getHeight() - getBorder().getBottomHeight() - inputBox.getHeight() ); else getWidgetAssembler().reposition( inputBox, 0f, this.getHeight() - inputBox.getHeight() ); if ( isCommandPreviewVisible() ) { commandPreview.setLocation( commandPreview.getLeft(), commandPreview.getTop() + ( newHeight - oldHeight ) ); } float inputBoxLeft = getWidgetAssembler().getPositionX( inputBox ); float inputBoxTop = getWidgetAssembler().getPositionY( inputBox ); getWidgetAssembler().reposition( commandPreview, inputBoxLeft + 10f, inputBoxTop + inputBox.getHeight() ); } list.setSize( innerWidth, innerHeight - inputBoxHeight - ( inputBox.isVisible() ? listInputBoxGap : 0f ) ); if ( getBorder() != null ) getWidgetAssembler().reposition( list, getBorder().getLeftWidth(), getBorder().getTopHeight() ); else getWidgetAssembler().reposition( list, 0f, 0f ); } /** * {@inheritDoc} */ @Override protected void drawWidget( Texture2DCanvas texCanvas, int offsetX, int offsetY, int width, int height, boolean drawsSelf ) { } /** * {@inheritDoc} */ @Override protected void init() { Dim2f buffer = Dim2f.fromPool(); getSizePixels2HUD_( getContentLeftPX(), getContentTopPX(), buffer ); float contentLeft = buffer.getWidth(); float contentTop = buffer.getHeight(); float contentBottom = 0f; if ( getBorder() != null ) { getSizePixels2HUD_( 0, getBorder().getBottomHeight(), buffer ); contentBottom = buffer.getHeight(); } float inputBoxLeft = contentLeft; float inputBoxTop = this.getHeight() - contentBottom - inputBox.getHeight(); getWidgetAssembler().addWidget( inputBox, inputBoxLeft, inputBoxTop ); inputBox.getMinimalSize( buffer ); float inputBoxHeight = buffer.getHeight(); Dim2f.toPool( buffer ); float contentWidth = getContentWidth(); inputBox.setSize( contentWidth, inputBoxHeight ); list.setSize( contentWidth, getContentHeight() - inputBox.getHeight() - listInputBoxGap ); getWidgetAssembler().addWidget( list, contentLeft, contentTop ); inputBoxTop = this.getHeight() - contentBottom - inputBox.getHeight(); getWidgetAssembler().reposition( inputBox, inputBoxLeft, inputBoxTop ); getWidgetAssembler().setKeyEventsDispatched( true ); getWidgetAssembler().setPickDispatched( true ); inputBox.requestFocus(); inputBox.addTextFieldListener( new TextFieldListener() { public void onCharTyped( TextField textField, char ch ) { updateTypePreview( textField.getText() ); } public void onCharDeleted( TextField textField ) { updateTypePreview( textField.getText() ); } public void onEscapeHit( TextField textField ) { setCommandPreviewListVisible( false ); } public void onTabHit( TextField textField ) { } public void onEnterHit( TextField textField ) { final String commandLine; if ( isCommandPreviewVisible() && ( commandPreview.getSelectedIndex() >= 0 ) ) { commandLine = (String)commandPreview.getSelectedItem(); Command command = null; int pos = commandLine.indexOf( '(' ); if ( pos >= 0 ) command = registeredCommands.get( commandLine.substring( 0, pos ) ); if ( command != null ) { if ( command.getNumParameters() == 0 ) { inputBox.setText( "" ); if ( command instanceof HelpCommand ) { ( (HelpCommand)command ).execute(); setCommandPreviewListVisible( false ); commandPreview.setSelectedIndex( -1 ); } else { onCommandEntered( command.getKey() + "()" ); } } else { inputBox.setText( command.getKey() + "( )" ); inputBox.setCaretPosition( inputBox.getText().length() - 2 ); updateTypePreview( inputBox.getText() ); } return; } } else { commandLine = textField.getText(); } if ( println( commandLine ) ) { inputBox.setText( "" ); onCommandEntered( commandLine ); } } } ); inputBox.addKeyboardListener( new WidgetKeyboardAdapter() { @Override public void onKeyPressed( Widget widget, Key key, int modifierMask, long when ) { switch ( key.getKeyID() ) { case UP: if ( isCommandPreviewVisible() ) { commandPreview.selectPreviousItem(); } break; case DOWN: if ( isCommandPreviewVisible() ) { commandPreview.selectNextItem(); } break; } } } ); } public HUDConsole( float width, float height, int channelFilter, int logLevel, Description desc, boolean initiallyVisible ) { super( true, true, desc.getBackgroundColor(), desc.getBackgroundTexture(), TileMode.TILE_BOTH ); this.logLevel = logLevel; this.channelFilter = channelFilter; this.normalColor = new Colorf( desc.getListFontColorNormal() ); this.warningColor = new Colorf( desc.getListFontColorWarning() ); this.errorColor = new Colorf( desc.getListFontColorError() ); if ( desc.getBorderDescription() != null ) this.setBorder( BorderFactory.createBorder( desc.getBorderDescription() ) ); float innerWidth = getWidth(); float innerHeight = getHeight(); this.listInputBoxGap = desc.getListInputBoxGap(); if ( desc.getInputBoxDescription() == null ) this.inputBox = new InputBox( innerWidth, 20f ); else this.inputBox = new InputBox( innerWidth, 20f, desc.getInputBoxDescription() ); inputBox.setAutoSizeEnabled( false ); inputBox.setIgnoredChars( '^' ); if ( desc.getListDescription() == null ) this.list = new List( innerWidth, innerHeight - inputBox.getHeight() - listInputBoxGap, null ); else this.list = List.newTextList( innerWidth, innerHeight - inputBox.getHeight() - listInputBoxGap, desc.getListDescription() ); list.setFixedToBottom( true ); this.commandPreview = List.newTextList( true, 120f, 100f, desc.getPreviewListDescription() ); commandPreview.setScrollMode( ScrollMode.NEVER ); commandPreview.setFontColor( inputBox.getFontColor() ); this.initiallyVisible = new Boolean( initiallyVisible ); setSize( width, height ); setZIndex( HUD.CURSOR_Z_INDEX - 10 ); registerCommand( new HelpCommand() ); } public HUDConsole( float width, float height, int channelFilter, Description desc, boolean initiallyVisible ) { this( width, height, channelFilter, LogLevel.REGULAR, desc, initiallyVisible ); } public HUDConsole( float width, float height, Description desc, boolean initiallyVisible ) { this( width, height, LogChannel.MASK_ALL, LogLevel.REGULAR, desc, initiallyVisible ); } public HUDConsole( float width, float height, int channelFilter, int logLevel, boolean initiallyVisible ) { this( width, height, channelFilter, logLevel, new Description(), initiallyVisible ); } public HUDConsole( float width, float height, int channelFilter, boolean initiallyVisible ) { this( width, height, channelFilter, LogLevel.REGULAR, initiallyVisible ); } public HUDConsole( float width, float height, boolean initiallyVisible ) { this( width, height, LogChannel.MASK_ALL, LogLevel.REGULAR, initiallyVisible ); } }