/** * 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; import java.util.ArrayList; import org.jagatoo.input.devices.components.MouseButton; import org.openmali.types.twodee.Dim2f; import org.openmali.types.twodee.Dim2i; import org.xith3d.scenegraph.Texture2D; import org.xith3d.scenegraph.Texture2DCanvas; import org.xith3d.ui.hud.HUD; import org.xith3d.ui.hud.base.AbstractButton; import org.xith3d.ui.hud.base.BackgroundSettableWidget; import org.xith3d.ui.hud.base.Widget; import org.xith3d.ui.hud.listeners.ScrollbarListener; import org.xith3d.ui.hud.utils.DrawUtils; import org.xith3d.ui.hud.utils.HUDTextureUtils; import org.xith3d.ui.hud.utils.TileMode; /** * A simple Scrollbar implementation used to scroll content on the HUD. * * @author Amos Wenger (aka BlueSky) * @author Marvin Froehlich (aka Qudus) */ public class Scrollbar extends BackgroundSettableWidget { /** * Scrolldirection of the Scrollbar * * @author Marvin Froehlich (aka Qudus) */ public enum Direction { HORIZONTAL, VERTICAL, ; } /** * This class is used to describe a (set of) Scrollbar Widget(s). You can * pass it to the Scrollbar constructor. Modifications on the used instance * after creating the Scrollbar Widget won't have any effect. * * @author Marvin Froehlich (aka Qudus) */ public static class Description extends Widget.DescriptionBase { private Direction direction; private Texture2D backgroundTexture; private Texture2D decTexture; private Texture2D incTexture; private Texture2D handleLTTexture; private Texture2D handleRBTexture; private Texture2D handleBodyTexture; private Texture2D handleDecoTexture; private boolean smoothScrolling; /** * Sets the direction in which the Scrollbar scrolls. */ public void setDirection( Direction direc ) { this.direction = direc; } /** * @return the direction in which the Scrollbar scrolls. */ public final Direction getDirection() { return ( direction ); } /** * Sets the background texture to use. * * @param texture the texture */ public void setBackgroundTexture( Texture2D texture ) { this.backgroundTexture = texture; } /** * Sets the background texture to use. * * @param texture the texture */ public final void setBackgroundTexture( String texture ) { setBackgroundTexture( HUDTextureUtils.getTexture( texture, true ) ); } /** * @return the background texture to use */ public final Texture2D getBackgroundTexture() { return ( backgroundTexture ); } /** * Sets the texture to use for the increment button. * * @param texture the texture */ public void setIncrementTexture( Texture2D texture ) { if ( texture == null ) throw new IllegalArgumentException( "texture must not be null" ); this.incTexture = texture; } /** * Sets the texture to use for the increment button. * * @param texture the texture */ public final void setIncrementTexture( String texture ) { setIncrementTexture( HUDTextureUtils.getTexture( texture, true ) ); } /** * @return the texture to use for the increment button */ public final Texture2D getIncrementTexture() { return ( incTexture ); } /** * Sets the texture to use for the decrement button. * * @param texture the texture */ public void setDecrementTexture( Texture2D texture ) { if ( texture == null ) throw new IllegalArgumentException( "texture must not be null" ); this.decTexture = texture; } /** * Sets the texture to use for the decrement button. * * @param texture the texture */ public final void setDecrementTexture( String texture ) { setDecrementTexture( HUDTextureUtils.getTexture( texture, true ) ); } /** * @return the texture to use for the decrement button */ public final Texture2D getDecrementTexture() { return ( decTexture ); } /** * Sets the textures to use for the handle. * * @param handleLTTexture; * @param handleRBTexture; * @param handleBodyTexture; * @param handleDecoTexture; */ public void setHandleTextures( Texture2D handleLTTexture, Texture2D handleRBTexture, Texture2D handleBodyTexture, Texture2D handleDecoTexture ) { this.handleLTTexture = handleLTTexture; this.handleRBTexture = handleRBTexture; this.handleBodyTexture = handleBodyTexture; this.handleDecoTexture = handleDecoTexture; } /** * Sets the textures to use for the handle. * * @param handleLTTexture; * @param handleRBTexture; * @param handleBodyTexture; * @param handleDecoTexture; */ public final void setHandleTextures( String handleLTTexture, String handleRBTexture, String handleBodyTexture, String handleDecoTexture ) { setHandleTextures( HUDTextureUtils.getTextureOrNull( handleLTTexture, true ), HUDTextureUtils.getTextureOrNull( handleRBTexture, true ), HUDTextureUtils.getTextureOrNull( handleBodyTexture, true ), HUDTextureUtils.getTextureOrNull( handleDecoTexture, true ) ); } /** * @return the texture to use for the left or top part of the handle. */ public final Texture2D getHandleLeftTopTexture() { return ( handleLTTexture ); } /** * @return the texture to use for the right or bottom part of the handle. */ public final Texture2D getHandleRightBottomTexture() { return ( handleRBTexture ); } /** * @return the texture to use for the body part of the handle. */ public final Texture2D getHandleBodyTexture() { return ( handleBodyTexture ); } /** * @return the texture to use for the handle decoration. */ public final Texture2D getHandleDecoTexture() { return ( handleDecoTexture ); } /** * If true, the handle doesn't snap to discrete positiones depending on * the available scroll values. * * @param b enable/disable */ public void setSmoothScrolling( boolean b ) { this.smoothScrolling = b; } /** * @return true, if the handle doesn't snap to discrete positiones depending on * the available scroll values. */ public final boolean getSmoothScrolling() { return ( smoothScrolling ); } /** * Clone-Constructor. * * @param desc the original to be duplicated */ public void set( Description desc ) { this.direction = desc.direction; this.backgroundTexture = desc.backgroundTexture; this.decTexture = desc.decTexture; this.incTexture = desc.incTexture; this.handleLTTexture = desc.handleLTTexture; this.handleRBTexture = desc.handleRBTexture; this.handleBodyTexture = desc.handleBodyTexture; this.handleDecoTexture = desc.handleDecoTexture; this.smoothScrolling = desc.smoothScrolling; } /** * @return a Clone of this Scrollbar.Description. */ @Override public Description clone() { return ( new Description( this ) ); } /** * Clone-Constructor. * * @param desc the original to be duplicated */ public Description( Description desc ) { this.set( desc ); } /** * Creates a new Scrollbar.Description. * * @param direction the direction in which the Scrollbar scrolls * @param backgroundTexture the background texture to use * @param handleLTTexture the handle texture to use * @param handleRBTexture the handle texture to use * @param handleBodyTexture the handle texture to use * @param handleDecoTexture the handle texture to use * @param decTexture the decrement button texture to use * @param incTexture the decrement button texture to use * @param smoothScrolling use smooth scrolling? */ public Description( Direction direction, Texture2D backgroundTexture, Texture2D handleLTTexture, Texture2D handleRBTexture, Texture2D handleBodyTexture, Texture2D handleDecoTexture, Texture2D decTexture, Texture2D incTexture, boolean smoothScrolling ) { this.direction = direction; this.backgroundTexture = backgroundTexture; this.decTexture = decTexture; this.incTexture = incTexture; this.handleLTTexture = handleLTTexture; this.handleRBTexture = handleRBTexture; this.handleBodyTexture = handleBodyTexture; this.handleDecoTexture = handleDecoTexture; this.smoothScrolling = smoothScrolling; } /** * Creates a new Scrollbar.Description. * * @param direction the direction in which the Scrollbar scrolls * @param backgroundTexture the background texture to use * @param handleLTTexture the handle texture to use * @param handleRBTexture the handle texture to use * @param handleBodyTexture the handle texture to use * @param handleDecoTexture the handle texture to use * @param decTexture the decrement button texture to use * @param incTexture the decrement button texture to use * @param smoothScrolling use smooth scrolling? */ public Description( Direction direction, String backgroundTexture, String handleLTTexture, String handleRBTexture, String handleBodyTexture, String handleDecoTexture, String decTexture, String incTexture, boolean smoothScrolling ) { this( direction, HUDTextureUtils.getTexture( backgroundTexture, true ), HUDTextureUtils.getTexture( handleLTTexture, true ), HUDTextureUtils.getTexture( handleRBTexture, true ), HUDTextureUtils.getTexture( handleBodyTexture, true ), HUDTextureUtils.getTextureOrNull( handleDecoTexture, true ), HUDTextureUtils.getTexture( decTexture, true ), HUDTextureUtils.getTexture( incTexture, true ), smoothScrolling ); } } private Direction direction; private final AbstractButton decButton; private final AbstractButton incButton; private Texture2D handleLTTex; private Texture2D handleRBTex; private Texture2D handleBodyTex; private Texture2D handleDecoTex; private int sizePX; private int currentHandlePosPx = -1; private int forcedHandlePosPx = -1; private boolean isScrolling = false; private float scrollStartMousePos; private int scrollStartHandlePos; private int minValue = 0; private int maxValue = 100; private int pageSize = 1; private int smallIncrement = 1; private int value = 0; private boolean smoothScrolling; private boolean needsRedrawAfterMouseButtonReleased = false; private final ArrayList<ScrollbarListener> scrollbarListeners = new ArrayList<ScrollbarListener>(); /** * @return the direction in which the Scrollbar scrolls */ public final Direction getDirection() { return ( direction ); } private int getHandleSize() { Dim2i buffer = Dim2i.fromPool(); getSizeHUD2Pixels_( decButton.getWidth(), decButton.getHeight(), buffer ); int decBtnWidth = buffer.getWidth(); int decBtnHeight = buffer.getHeight(); getSizeHUD2Pixels_( incButton.getWidth(), incButton.getHeight(), buffer ); int incBtnWidth = buffer.getWidth(); int incBtnHeight = buffer.getHeight(); Dim2i.toPool( buffer ); int pageSize = getPageSize();//Math.max( 1, Math.min( getPageSize(), getMaxValue() - getMinValue() ) ); float total = pageSize + getMaxValue() - getMinValue(); int handleSize = 32; if ( getDirection() == Direction.HORIZONTAL ) { float areaWidth = getWidthPX() - decBtnWidth - incBtnWidth; int handleLeftSize = HUDTextureUtils.getTextureWidth( handleLTTex ); int handleRightSize = HUDTextureUtils.getTextureWidth( handleRBTex ); handleSize = Math.max( handleLeftSize + handleRightSize, (int)( pageSize * areaWidth / total ) ); } else { float areaHeight = getHeightPX() - decBtnHeight - incBtnHeight; int handleTopSize = HUDTextureUtils.getTextureHeight( handleLTTex ); int handleBottomSize = HUDTextureUtils.getTextureHeight( handleRBTex ); handleSize = Math.max( handleTopSize + handleBottomSize, (int)( pageSize * areaHeight / total ) ); } return ( handleSize ); } /** * Checks, if the mouse is over the handle. * * @param currentHandlePosPx * @param mouseX widget local mouse-x * @param mouseY widget local mouse-y * * @return -1, if the mouse is on the smaller side of the handle, +1, if it is on the greater side, 0 if it is over the handle. */ protected int getMousePosition( int currentHandlePosPx, int mouseX, int mouseY ) { if ( getDirection() == Direction.HORIZONTAL ) { if ( mouseX < currentHandlePosPx ) return ( -1 ); if ( mouseX > currentHandlePosPx + getHandleSize() ) return ( +1 ); } else// if ( getDirection() == Direction.VERTICAL ) { if ( mouseY < currentHandlePosPx ) return ( -1 ); if ( mouseY > currentHandlePosPx + getHandleSize() ) return ( +1 ); } return ( 0 ); } /** * {@inheritDoc} */ @Override protected void onMouseButtonPressed( MouseButton button, float x, float y, long when, long lastWhen, boolean isTopMost, boolean hasFocus ) { super.onMouseButtonPressed( button, x, y, when, lastWhen, isTopMost, hasFocus ); if ( isTopMost && ( getMaxValue() > getMinValue() ) ) { Widget picked = getWidgetAssembler().pick( x, y ); if ( picked == decButton ) { // decrement the value setValue( getValue() - getSmallIncrement() ); } else if ( picked == incButton ) { // increment the value setValue( getValue() + getSmallIncrement() ); } else { Dim2i buffer = Dim2i.fromPool(); getSizeHUD2Pixels_( x, y, buffer ); int localX = buffer.getWidth(); int localY = buffer.getHeight(); Dim2i.toPool( buffer ); if ( getMousePosition( currentHandlePosPx, localX, localY ) == 0 ) { bindToGlobalMouseMovement(); scrollStartHandlePos = currentHandlePosPx; if ( getDirection() == Direction.HORIZONTAL ) { scrollStartMousePos = x; } else if ( getDirection() == Direction.VERTICAL ) { scrollStartMousePos = y; } this.isScrolling = true; this.needsRedrawAfterMouseButtonReleased = true; } } } } /** * {@inheritDoc} */ @Override protected void onMouseButtonReleased( MouseButton button, float x, float y, long when, long lastWhen, boolean isTopMost, boolean hasFocus ) { super.onMouseButtonReleased( button, x, y, when, lastWhen, isTopMost, hasFocus ); this.isScrolling = false; if ( getSmoothScrolling() ) { if ( needsRedrawAfterMouseButtonReleased ) setTextureDirty(); this.needsRedrawAfterMouseButtonReleased = false; } } /** * {@inheritDoc} */ @Override protected void onMouseMoved( float x, float y, int buttonsState, long when, boolean isTopMost, boolean hasFocus ) { super.onMouseMoved( x, y, buttonsState, when, isTopMost, hasFocus ); if ( isScrolling && ( getMaxValue() > getMinValue() ) ) { int oldForcedHandlePosPx = forcedHandlePosPx; int newValue; if ( getDirection() == Direction.HORIZONTAL ) { float dx = x - scrollStartMousePos; Dim2i buffer = Dim2i.fromPool(); getSizeHUD2Pixels_( decButton.getWidth(), decButton.getHeight(), buffer ); int decBtnWidth = buffer.getWidth(); getSizeHUD2Pixels_( incButton.getWidth(), incButton.getHeight(), buffer ); int incBtnWidth = buffer.getWidth(); getSizeHUD2Pixels_( this.getWidth(), 0, buffer ); int widgetWidthPx = buffer.getWidth(); getSizeHUD2Pixels_( scrollStartHandlePos + dx, 0, buffer ); int scrollHandlePos = buffer.getWidth(); Dim2i.toPool( buffer ); int handleSize = getHandleSize(); int barRestWidth = widgetWidthPx - decBtnWidth - incBtnWidth - handleSize; forcedHandlePosPx = Math.max( decBtnWidth, Math.min( scrollHandlePos, barRestWidth + decBtnWidth ) ); newValue = Math.round( ( ( forcedHandlePosPx - decBtnWidth ) * ( getMaxValue() - getMinValue() ) ) / (float)barRestWidth ) + getMinValue(); if ( !getSmoothScrolling() ) { forcedHandlePosPx = decBtnWidth + barRestWidth * ( newValue - getMinValue() ) / ( getMaxValue() - getMinValue() ); } } else// if ( getDirection() == Direction.VERTICAL ) { float dy = y - scrollStartMousePos; Dim2i buffer = Dim2i.fromPool(); getSizeHUD2Pixels_( decButton.getWidth(), decButton.getHeight(), buffer ); int decBtnHeight = buffer.getHeight(); getSizeHUD2Pixels_( incButton.getWidth(), incButton.getHeight(), buffer ); int incBtnHeight = buffer.getHeight(); getSizeHUD2Pixels_( 0, this.getHeight(), buffer ); int widgetHeightPx = buffer.getHeight(); getSizeHUD2Pixels_( scrollStartHandlePos + dy, 0, buffer ); int scrollHandlePos = buffer.getWidth(); Dim2i.toPool( buffer ); int handleSize = getHandleSize(); int barRestHeight = widgetHeightPx - decBtnHeight - incBtnHeight - handleSize; forcedHandlePosPx = Math.max( decBtnHeight, Math.min( scrollHandlePos, barRestHeight + decBtnHeight ) ); newValue = Math.round( ( ( forcedHandlePosPx - decBtnHeight ) * ( getMaxValue() - getMinValue() ) ) / (float)barRestHeight ) + getMinValue(); if ( !getSmoothScrolling() ) { forcedHandlePosPx = decBtnHeight + barRestHeight * ( newValue - getMinValue() ) / ( getMaxValue() - getMinValue() ); } } if ( newValue != getValue() ) { setValue( newValue ); } else if ( forcedHandlePosPx != oldForcedHandlePosPx ) { setTextureDirty(); } } } /** * Sets the lower bound of scroll values. */ public void setMinValue( int minValue ) { if ( minValue > maxValue ) throw new IllegalArgumentException( "minValue must never be greater than maxValue." ); if ( this.minValue == minValue ) return; this.minValue = minValue; setTextureDirty(); } /** * @return the lower bound of scroll values */ public final int getMinValue() { return ( minValue ); } /** * Sets the upper bound of scroll values. */ public void setMaxValue( int maxValue ) { if ( maxValue < minValue ) throw new IllegalArgumentException( "maxValue must never be less than minValue." ); if ( this.maxValue == maxValue ) return; this.maxValue = maxValue; setTextureDirty(); } /** * @return the upper bound of scroll values */ public final int getMaxValue() { return ( maxValue ); } /** * Sets the lower bound of scroll values. * * @param minValue * @param maxValue */ public void setMinAndMax( int minValue, int maxValue ) { if ( minValue > maxValue ) throw new IllegalArgumentException( "minValue must be <= maxValue." ); if ( ( minValue == this.minValue ) && ( maxValue == this.maxValue ) ) return; this.minValue = minValue; this.maxValue = maxValue; setTextureDirty(); } /** * Sets the page size, which indirectly defines the size of the handle. * * @param pageSize */ public void setPageSize( int pageSize ) { this.pageSize = pageSize; } /** * Gets the page size, which indirectly defines the size of the handle. * * @return the page size. */ public final int getPageSize() { return ( pageSize ); } /** * Sets the step to increment the Scrollbar's value by when the increment * button is clicked. */ public void setSmallIncrement( int value ) { this.smallIncrement = value; } /** * @return the step to increment the Scrollbar's value by when the increment * button is clicked */ public final int getSmallIncrement() { return ( smallIncrement ); } /** * Sets the lower bound of scroll values. * * @param minValue * @param maxValue * @param value * @param pageSize */ public void setMinMaxAndValue( int minValue, int maxValue, int value, int pageSize ) { if ( minValue > maxValue ) throw new IllegalArgumentException( "minValue must be <= maxValue." ); if ( ( value < minValue ) || ( value > maxValue ) ) throw new IllegalArgumentException( "value must be >= minValue and <= maxValue." ); if ( ( minValue == this.minValue ) && ( maxValue == this.maxValue ) ) return; this.minValue = minValue; this.maxValue = maxValue; this.value = value; this.pageSize = pageSize;//Math.max( 1, Math.min( pageSize, maxValue - minValue ) ); setTextureDirty(); } /** * Sets the lower bound of scroll values. * * @param minValue * @param maxValue * @param value */ public final void setMinMaxAndValue( int minValue, int maxValue, int value ) { setMinMaxAndValue( minValue, maxValue, value, ( maxValue - minValue ) / 5 ); } /** * @param oldValue * @param newValue */ protected void onScrollbarValueChanged( int oldValue, int newValue ) { //final Direction direction = this.getDirection(); for ( int i = 0; i < scrollbarListeners.size(); i++ ) { scrollbarListeners.get( i ).onScrollbarValueChanged( this, newValue ); } } /** * Sets the current scroll value * * @param value */ public boolean setValue( int value ) { value = Math.max( getMinValue(), Math.min( value, getMaxValue() ) ); if ( value == this.value ) return ( false ); int oldValue = this.value; this.value = value; setTextureDirty(); onScrollbarValueChanged( oldValue, value ); return ( true ); } /** * @return the current scroll value */ public final int getValue() { return ( value ); } /** * Adds a ScrollbarListener to the List to be notified, when the value has * changed. * * @param l the new ScrollbarListener */ public void addScrollbarListener( ScrollbarListener l ) { scrollbarListeners.add( l ); } /** * Removes a ScrollbarListener from the List. * * @param l the ScrollbarListener to be removed */ public boolean removeScrollbarListener( ScrollbarListener l ) { return ( scrollbarListeners.remove( l ) ); } /** * If true, the handle doesn't snap to discrete positiones depending on the * available scroll values. * * @param b enable/disable */ public void setSmoothScrolling( boolean b ) { this.smoothScrolling = b; } /** * @return true, if the handle doesn't snap to discrete positiones depending on the * available scroll values. */ public final boolean getSmoothScrolling() { return ( smoothScrolling ); } /** * If this Scrollbar's Direction is Horizontal, the height in pixels is returned. * If this Scrollbar's Direction is Vertical, the width in pixels is returned. * * @return the width or height in pixels. */ public final int getWidthOrHeightInPixels() { return ( sizePX ); } /** * {@inheritDoc} */ @Override protected void onSizeChanged( float oldWidth, float oldHeight, float newWidth, float newHeight ) { super.onSizeChanged( oldWidth, oldHeight, newWidth, newHeight ); if ( getDirection() == Direction.HORIZONTAL ) { if ( decButton != null ) { decButton.setSize( decButton.getWidth(), newHeight ); if ( getWidgetAssembler().contains( decButton ) ) getWidgetAssembler().reposition( decButton, 0f, 0f ); } if ( incButton != null ) { incButton.setSize( incButton.getWidth(), newHeight ); if ( getWidgetAssembler().contains( incButton ) ) getWidgetAssembler().reposition( incButton, newWidth - incButton.getWidth(), 0f ); } } else //if (getDirection() == Direction.VERTICAL) { if ( decButton != null ) { decButton.setSize( newWidth, decButton.getHeight() ); if ( getWidgetAssembler().contains( decButton ) ) getWidgetAssembler().reposition( decButton, 0f, 0f ); } if ( incButton != null ) { incButton.setSize( newWidth, incButton.getHeight() ); if ( getWidgetAssembler().contains( incButton ) ) getWidgetAssembler().reposition( incButton, 0f, newHeight - incButton.getHeight() ); } } // unnecessary! already done in setSize(). //setTextureDirty(); } protected int drawHandle( Texture2DCanvas texCanvas, int offsetX, int offsetY, int width, int height, Texture2D handleLTTex, Texture2D handleRBTex, Texture2D handleBodyTex, Texture2D handleDecoTex, int forcedHandlePos ) { int handlePos; int handleDecoratorWidth = 0; int handleDecoratorHeight = 0; if ( handleDecoTex != null ) { handleDecoratorWidth = HUDTextureUtils.getTextureWidth( handleDecoTex ); handleDecoratorHeight = HUDTextureUtils.getTextureWidth( handleDecoTex ); } if ( getDirection() == Direction.HORIZONTAL ) { int handleLeftSize = HUDTextureUtils.getTextureWidth( handleLTTex ); int handleRightSize = HUDTextureUtils.getTextureWidth( handleRBTex ); int handleSize = getHandleSize(); if ( forcedHandlePos >= 0 ) handlePos = forcedHandlePos; else handlePos = ( width - handleSize ) * ( getValue() - getMinValue() ) / ( getMaxValue() - getMinValue() ); DrawUtils.drawImage( null, handleLTTex, null, texCanvas, offsetX + handlePos, offsetY, handleLeftSize, height ); DrawUtils.drawImage( null, handleRBTex, null, texCanvas, offsetX + handlePos + handleSize - handleRightSize, offsetY, handleRightSize, height ); DrawUtils.drawImage( null, handleBodyTex, TileMode.TILE_X, texCanvas, offsetX + handlePos + handleLeftSize, offsetY, handleSize - handleLeftSize - handleRightSize, height ); if ( ( handleDecoTex != null ) && ( handleSize - handleLeftSize - handleRightSize >= handleDecoratorWidth ) ) DrawUtils.drawImage( null, handleDecoTex, null, texCanvas, offsetX + handlePos + ( ( handleSize - handleDecoratorWidth ) / 2 ), offsetY + ( ( height - handleDecoratorHeight ) / 2 ), handleDecoratorWidth, handleDecoratorHeight ); } else { int handleTopSize = HUDTextureUtils.getTextureHeight( handleLTTex ); int handleBottomSize = HUDTextureUtils.getTextureHeight( handleRBTex ); int handleSize = getHandleSize(); if ( forcedHandlePos >= 0 ) handlePos = forcedHandlePos; else handlePos = ( height - handleSize ) * ( getValue() - getMinValue() ) / ( getMaxValue() - getMinValue() ); DrawUtils.drawImage( null, handleLTTex, null, texCanvas, offsetX, offsetY + handlePos, width, handleTopSize ); DrawUtils.drawImage( null, handleRBTex, null, texCanvas, offsetX, offsetY + handlePos + handleSize - handleBottomSize, width, handleBottomSize ); DrawUtils.drawImage( null, handleBodyTex, TileMode.TILE_Y, texCanvas, offsetX, offsetY + handlePos + handleTopSize, width, handleSize - handleTopSize - handleBottomSize ); if ( ( handleDecoTex != null ) && ( handleSize - handleTopSize - handleBottomSize >= handleDecoratorHeight ) ) DrawUtils.drawImage( null, handleDecoTex, null, texCanvas, offsetX + ( ( width - handleDecoratorWidth ) / 2 ), offsetY + handlePos + ( ( handleSize - handleDecoratorHeight ) / 2 ), handleDecoratorWidth, handleDecoratorHeight ); } return ( handlePos ); } @Override protected void drawWidget( Texture2DCanvas texCanvas, int offsetX, int offsetY, int width, int height, boolean drawsSelf ) { if ( getMaxValue() > getMinValue() ) { Dim2i buffer = Dim2i.fromPool(); getSizeHUD2Pixels_( decButton.getWidth(), decButton.getHeight(), buffer ); int decBtnWidth = buffer.getWidth(); int decBtnHeight = buffer.getHeight(); getSizeHUD2Pixels_( incButton.getWidth(), incButton.getHeight(), buffer ); int incBtnWidth = buffer.getWidth(); int incBtnHeight = buffer.getHeight(); Dim2i.toPool( buffer ); if ( getDirection() == Direction.HORIZONTAL ) { this.currentHandlePosPx = decBtnWidth + drawHandle( texCanvas, offsetX + decBtnWidth, offsetY, width - decBtnWidth - incBtnWidth, height, handleLTTex, handleRBTex, handleBodyTex, handleDecoTex, isScrolling ? forcedHandlePosPx - decBtnWidth : -1 ); } else { this.currentHandlePosPx = decBtnHeight + drawHandle( texCanvas, offsetX, offsetY + decBtnHeight, width, height - decBtnHeight - incBtnHeight, handleLTTex, handleRBTex, handleBodyTex, handleDecoTex, isScrolling ? forcedHandlePosPx - decBtnHeight : -1 ); } } } /** * {@inheritDoc} */ @Override protected void init() { final Dim2f buffer = Dim2f.fromPool(); getSizePixels2HUD_( sizePX, sizePX, buffer ); if ( this.getWidth() < 0f ) { // vertical super.setSize( buffer.getWidth(), this.getHeight() ); } else if ( this.getHeight() < 0f ) { // horizontal setSize( this.getWidth(), buffer.getHeight() ); } if ( getDirection() == Direction.HORIZONTAL ) { getSizePixels2HUD_( HUDTextureUtils.getTextureWidth( ( (Button)decButton ).getTextureNormal() ), 0, buffer ); decButton.setSize( buffer.getWidth(), this.getHeight() ); getWidgetAssembler().addWidget( decButton, 0f, 0f ); getSizePixels2HUD_( HUDTextureUtils.getTextureWidth( ( (Button)incButton ).getTextureNormal() ), 0, buffer ); incButton.setSize( buffer.getWidth(), this.getHeight() ); getWidgetAssembler().addWidget( incButton, getWidth() - incButton.getWidth(), 0f ); } else if ( getDirection() == Direction.VERTICAL ) { getSizePixels2HUD_( 0, HUDTextureUtils.getTextureHeight( ( (Button)decButton ).getTextureNormal() ), buffer ); decButton.setSize( this.getWidth(), buffer.getHeight() ); getWidgetAssembler().addWidget( decButton, 0f, 0f ); getSizePixels2HUD_( 0, HUDTextureUtils.getTextureHeight( ( (Button)incButton ).getTextureNormal() ), buffer ); incButton.setSize( this.getWidth(), buffer.getHeight() ); getWidgetAssembler().addWidget( incButton, 0f, getHeight() - incButton.getHeight() ); } Dim2f.toPool( buffer ); setSize( this.getWidth(), this.getHeight(), true ); setTextureDirty(); } /** * Creates a new Scrollbar. * * @param width the width of the Scrollbar * @param height the height of the Scrollbar * @param sbDesc a Scrollbar.Description instance holding information about * this new Scrollbar */ public Scrollbar( float width, float height, Description sbDesc ) { super( false, true, width, height, null, sbDesc.getBackgroundTexture(), TileMode.TILE_BOTH ); this.direction = sbDesc.getDirection(); this.decButton = new Button( false, HUDTextureUtils.getTextureWidth( sbDesc.decTexture ), HUDTextureUtils.getTextureHeight( sbDesc.decTexture ), sbDesc.decTexture, null, null ); this.incButton = new Button( false, HUDTextureUtils.getTextureWidth( sbDesc.incTexture ), HUDTextureUtils.getTextureHeight( sbDesc.incTexture ), sbDesc.incTexture, null, null ); this.handleLTTex = sbDesc.getHandleLeftTopTexture(); this.handleRBTex = sbDesc.getHandleRightBottomTexture(); this.handleBodyTex = sbDesc.getHandleBodyTexture(); this.handleDecoTex = sbDesc.getHandleDecoTexture(); if ( getDirection() == Direction.HORIZONTAL ) { if ( getBackgroundTexture() != null ) this.sizePX = HUDTextureUtils.getTextureHeight( getBackgroundTexture() ); else if ( sbDesc.getDecrementTexture() != null ) this.sizePX = HUDTextureUtils.getTextureHeight( sbDesc.getDecrementTexture() ); else if ( sbDesc.getIncrementTexture() != null ) this.sizePX = HUDTextureUtils.getTextureHeight( sbDesc.getIncrementTexture() ); else this.sizePX = 16; // fallback! } else if ( getDirection() == Direction.VERTICAL ) { if ( getBackgroundTexture() != null ) this.sizePX = HUDTextureUtils.getTextureWidth( getBackgroundTexture() ); else if ( sbDesc.getDecrementTexture() != null ) this.sizePX = HUDTextureUtils.getTextureWidth( sbDesc.getDecrementTexture() ); else if ( sbDesc.getIncrementTexture() != null ) this.sizePX = HUDTextureUtils.getTextureWidth( sbDesc.getIncrementTexture() ); else this.sizePX = 16; // fallback! } this.smoothScrolling = sbDesc.getSmoothScrolling(); } /** * Creates a new Scrollbar. * * @param length the length of the Scrollbar * @param zIndex the z-index of the Scrollbar * @param sbDesc a Scrollbar.Description instance holding information about * this new Scrollbar */ public Scrollbar( float length, Description sbDesc ) { this( ( sbDesc.direction == Direction.HORIZONTAL ) ? length : -1f, ( sbDesc.direction == Direction.HORIZONTAL ) ? -1f : length, sbDesc ); } private static Description getThemedDesc( Direction direction ) { if ( direction == Direction.HORIZONTAL ) return ( HUD.getTheme().getScrollbarDescriptionHorizontal() ); return ( HUD.getTheme().getScrollbarDescriptionVertical() ); } /** * Creates a new Scrollbar. * * @param width the width of the Scrollbar * @param height the height of the Scrollbar * @param direction the scroll-direction */ public Scrollbar( float width, float height, Direction direction ) { this( width, height, getThemedDesc( direction ) ); } /** * Creates a new Scrollbar. * * @param length if (direction == HORIZONTAL), this is the width of the * Scrollbar. if (direction == VERTICAL), this is the height of * the Scrollbar. * @param direction the scroll-direction */ public Scrollbar( float length, Direction direction ) { this( length, getThemedDesc( direction ) ); } }