/** * Copyright (c) 2003-2008, 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.utils; import org.jagatoo.input.devices.components.DeviceComponent; import org.jagatoo.input.devices.components.MouseButton; import org.openmali.types.twodee.Dim2f; import org.xith3d.ui.hud.HUD; import org.xith3d.ui.hud.base.Widget; import org.xith3d.ui.hud.base.WidgetAssembler; import org.xith3d.ui.hud.base.WidgetContainer; import org.xith3d.ui.hud.base.__HUD_base_PrivilegedAccess; import org.xith3d.ui.hud.listeners.ScrollbarListener; import org.xith3d.ui.hud.listeners.WidgetContainerListener; import org.xith3d.ui.hud.listeners.WidgetLocationListener; import org.xith3d.ui.hud.listeners.WidgetMouseListener; import org.xith3d.ui.hud.listeners.WidgetSizeListener; import org.xith3d.ui.hud.widgets.Image; import org.xith3d.ui.hud.widgets.Scrollbar; /** * A ScrollHandler is capable of managing communication between a scrollable Widget * and the ScrollBars as well as properly adding the ScrollBars to the Widget * on demand. * * @author Marvin Froehlich (aka Qudus) */ public abstract class ScrollHandler implements ScrollbarListener, WidgetContainerListener, WidgetLocationListener, WidgetSizeListener, WidgetMouseListener { private final Widget widget; private final WidgetAssembler widgetAssembler; private float maxRight = 0f, maxBottom = 0f; private ScrollMode mode = ScrollMode.AUTO; private Scrollbar scrollbarH = null, scrollbarV = null; private Image spacerImage; private int numIgnoredEvents_H = 0; private int numIgnoredEvents_V = 0; public abstract void onScrolled( Scrollbar.Direction direction, int newValue ); /** * {@inheritDoc} */ public void onScrollbarValueChanged( Scrollbar scrollbar, int newValue ) { if ( ( scrollbar.getDirection() == Scrollbar.Direction.HORIZONTAL ) && ( numIgnoredEvents_H > 0 ) ) { numIgnoredEvents_H--; return; } if ( ( scrollbar.getDirection() == Scrollbar.Direction.VERTICAL ) && ( numIgnoredEvents_V > 0 ) ) { numIgnoredEvents_V--; return; } onScrolled( scrollbar.getDirection(), newValue ); } public void setScrollMode( ScrollMode mode ) { this.mode = mode; } public final ScrollMode getScrollMode() { return ( mode ); } public void setLineHeight( int lineHeight ) { if ( scrollbarV == null ) return; scrollbarV.setSmallIncrement( lineHeight ); } public final int getLineHeight() { if ( scrollbarV == null ) return ( 0 ); return ( scrollbarV.getSmallIncrement() ); } public void setScrollHValue( int value ) { if ( scrollbarH == null ) return; numIgnoredEvents_H++; scrollbarH.setValue( value ); } public void setScrollVValue( int value ) { if ( scrollbarV == null ) return; numIgnoredEvents_V++; scrollbarV.setValue( value ); } private final void mergeWidgetIntoBounds( Widget widget ) { if ( widget.getLeft() + widget.getWidth() > maxRight ) { maxRight = widget.getLeft() + widget.getWidth(); } if ( widget.getTop() + widget.getHeight() > maxBottom ) { maxBottom = widget.getTop() + widget.getHeight(); } } private void updateScrollbarsFromBounds() { final boolean scrollHForced = ( ( mode == ScrollMode.ALWAYS ) || ( mode == ScrollMode.ALWAYS_HORIZONTAL ) ); final boolean scrollVForced = ( ( mode == ScrollMode.ALWAYS ) || ( mode == ScrollMode.ALWAYS_VERTICAL ) ); if ( scrollbarH != null ) scrollbarH.setVisible( scrollHForced ); if ( scrollbarV != null ) scrollbarV.setVisible( scrollVForced ); if ( spacerImage != null ) spacerImage.setVisible( false ); widgetAssembler.setAdditionalContentSize( 0, 0, 0, 0 ); if ( mode != ScrollMode.NEVER ) { float contentWidth = widget.getContentWidth(); float contentHeight = widget.getContentHeight(); int acw = 0; int ach = 0; boolean scrollV = false; boolean scrollH = false; if ( ( scrollbarV != null ) && ( scrollVForced || ( maxBottom > contentHeight ) ) ) { scrollV = true; scrollbarV.setVisible( true ); acw = scrollbarV.getWidthOrHeightInPixels(); widgetAssembler.setAdditionalContentSize( 0, 0, -acw, -ach ); contentWidth = widget.getContentWidth(); contentHeight = widget.getContentHeight(); } if ( ( scrollbarH != null ) && ( scrollHForced || ( maxRight > contentWidth ) ) ) { scrollH = true; scrollbarH.setVisible( true ); ach = scrollbarH.getWidthOrHeightInPixels(); widgetAssembler.setAdditionalContentSize( 0, 0, -acw, -ach ); contentWidth = widget.getContentWidth(); contentHeight = widget.getContentHeight(); } if ( ( scrollbarV != null ) && !scrollbarV.isVisible() && ( scrollbarH != null ) && scrollbarH.isVisible() && ( scrollVForced || ( maxBottom > contentHeight ) ) ) { scrollV = true; scrollbarV.setVisible( true ); acw = scrollbarV.getWidthOrHeightInPixels(); widgetAssembler.setAdditionalContentSize( 0, 0, -acw, -ach ); contentWidth = widget.getContentWidth(); contentHeight = widget.getContentHeight(); } if ( ( scrollbarV != null ) && ( maxBottom > contentHeight ) ) { int maxValue = (int)Math.ceil( maxBottom - contentHeight ); int value = Math.min( scrollbarV.getValue(), maxValue ); scrollbarV.setMinMaxAndValue( 0, maxValue, value, (int)contentHeight ); } else { scrollbarV.setMinMaxAndValue( 0, 0, 0 ); } if ( ( scrollbarH != null ) && ( maxRight > contentWidth ) ) { int maxValue = (int)Math.ceil( maxRight - contentWidth ); int value = Math.min( scrollbarH.getValue(), maxValue ); scrollbarH.setMinMaxAndValue( 0, maxValue, value, (int)contentWidth ); } else { scrollbarH.setMinMaxAndValue( 0, 0, 0 ); } //if ( ( spacerImage != null ) && ( scrollbarH != null ) && scrollbarH.isVisible() && ( scrollbarV != null ) && scrollbarV.isVisible() ) if ( ( spacerImage != null ) && scrollH && scrollV ) { spacerImage.setVisible( true ); } } } private final void updateBounds() { if ( ( !( widget instanceof WidgetContainer ) ) || ( widget.getHUD() == null ) ) return; WidgetContainer wc = (WidgetContainer)widget; maxRight = 0f; maxBottom = 0f; for ( int i = 0; i < wc.getWidgetsCount(); i++ ) { Widget w = wc.getWidget( i ); mergeWidgetIntoBounds( w ); } updateScrollbarsFromBounds(); } public void setBounds( float maxRight, float maxBottom ) { this.maxRight = maxRight; this.maxBottom = maxBottom; updateScrollbarsFromBounds(); } /** * {@inheritDoc} */ public void onWidgetAttachedToContainer( Widget widget, WidgetContainer container ) { if ( widget != this.widget ) { widget.addSizeListener( this ); widget.addLocationListener( this ); mergeWidgetIntoBounds( widget ); } } /** * {@inheritDoc} */ public void onWidgetDetachedFromContainer( Widget widget, WidgetContainer container ) { if ( widget != this.widget ) { widget.removeSizeListener( this ); widget.removeLocationListener( this ); mergeWidgetIntoBounds( widget ); } } /** * {@inheritDoc} */ public void onWidgetAttachedToHUD( Widget widget, HUD hud ) { if ( widget == this.widget ) { updateScrollbarSizesToMatchWidget(); //updateScrollbarsFromBounds(); updateBounds(); } } /** * {@inheritDoc} */ public void onWidgetDetachedFromHUD( Widget widget, HUD hud ) { } /** * {@inheritDoc} */ public void onWidgetDragStarted( Widget widget ) { } /** * {@inheritDoc} */ public void onWidgetDragStopped( Widget widget ) { } /** * {@inheritDoc} */ public void onWidgetLocationChanged( Widget widget, float oldLeft, float oldTop, float newLeft, float newTop ) { updateBounds(); } /** * {@inheritDoc} */ public void onWidgetSizeChanged( Widget widget, float oldWidth, float oldHeight, float newWidth, float newHeight ) { if ( widget == this.widget ) { if ( widget.getHUD() != null ) updateScrollbarSizesToMatchWidget(); } else { updateBounds(); } } /** * {@inheritDoc} */ public void onMouseButtonPressed( Widget widget, MouseButton button, float x, float y, long when, long lastWhen, boolean isTopMost, boolean hasFocus ) { } /** * {@inheritDoc} */ public void onMouseButtonReleased( Widget widget, MouseButton button, float x, float y, long when, long lastWhen, boolean isTopMost, boolean hasFocus ) { } /** * {@inheritDoc} */ public void onMouseMoved( Widget widget, float x, float y, int buttonsState, long when, boolean isTopMost, boolean hasFocus ) { } /** * {@inheritDoc} */ public void onMouseStopped( Widget widget, float x, float y, long when, boolean isTopMost, boolean hasFocus ) { } /** * {@inheritDoc} */ public void onMouseWheelMoved( Widget widget, int delta, boolean isPageMove, float x, float y, long when, boolean isTopMost ) { if ( ( scrollbarV != null ) && scrollbarV.isVisible() ) { scrollbarV.setValue( scrollbarV.getValue() - ( delta * scrollbarV.getSmallIncrement() ) ); return; } if ( ( scrollbarH != null ) && scrollbarH.isVisible() ) { scrollbarH.setValue( scrollbarH.getValue() - ( delta * scrollbarH.getSmallIncrement() ) ); return; } } /** * {@inheritDoc} */ public void onMouseEntered( Widget widget, boolean isTopMost, boolean hasFocus ) { } /** * {@inheritDoc} */ public void onMouseExited( Widget widget, boolean isTopMost, boolean hasFocus ) { } /** * {@inheritDoc} */ public void onInputStateChanged( Widget widget, DeviceComponent comp, int delta, int state, long when, boolean isTopMost, boolean hasFocus ) { } /** * Creates the horizontal {@link Scrollbar}. * * @param width the width to cover * * @return the horizontal {@link Scrollbar}. */ protected Scrollbar createHorizontalScrollbar( float width ) { return ( new Scrollbar( width, Scrollbar.Direction.HORIZONTAL ) ); } /** * Creates the vertical {@link Scrollbar}. * * @param height the height to cover * * @return the vertical {@link Scrollbar}. */ protected Scrollbar createVerticalScrollbar( float height ) { return ( new Scrollbar( height, Scrollbar.Direction.VERTICAL ) ); } private void updateScrollbarSizesToMatchWidget() { float left = 0f; float top = 0f; float width = widget.getWidth(); float height = widget.getHeight(); if ( widget.getBorder() != null ) { Dim2f buffer1 = Dim2f.fromPool(); Dim2f buffer2 = Dim2f.fromPool(); __HUD_base_PrivilegedAccess.getBorderSizeInHUDSpace( widget, buffer1, buffer2 ); left += buffer1.getWidth(); top += buffer1.getHeight(); width -= buffer1.getWidth() + buffer2.getWidth(); height -= buffer1.getHeight() + buffer2.getHeight(); Dim2f.toPool( buffer2 ); Dim2f.toPool( buffer1 ); } final boolean scrollHorizontal = ( ( scrollbarH != null ) && scrollbarH.isVisible() ); final boolean scrollVertical = ( ( scrollbarV != null ) && scrollbarV.isVisible() ); int sbW = 0, sbH = 0; if ( scrollHorizontal ) { scrollbarH.setSize( width - ( scrollVertical ? scrollbarV.getWidth() : 0f ), scrollbarH.getHeight() ); widgetAssembler.reposition( scrollbarH, left, top + height - scrollbarH.getHeight() ); sbH = scrollbarH.getWidthOrHeightInPixels(); } if ( scrollVertical ) { scrollbarV.setSize( scrollbarV.getWidth(), height - ( scrollHorizontal ? scrollbarH.getHeight() : 0f ) ); widgetAssembler.reposition( scrollbarV, left + width - scrollbarV.getWidth(), top ); sbW = scrollbarV.getWidthOrHeightInPixels(); } if ( scrollHorizontal && scrollVertical ) { this.spacerImage.setSize( scrollbarV.getWidth(), scrollbarH.getHeight() ); widgetAssembler.reposition( spacerImage, left + width - scrollbarV.getWidth(), top + height - scrollbarH.getHeight() ); } widgetAssembler.setAdditionalContentSize( 0, 0, -sbW, -sbH ); } public ScrollHandler( Widget widget, WidgetAssembler widgetAssembler, boolean scrollHorizontal, boolean scrollVertical ) { if ( !scrollHorizontal && !scrollVertical ) throw new IllegalArgumentException( "A ScrollHandler is useless without any scroll direction being handled." ); this.widget = widget; this.widgetAssembler = widgetAssembler; widgetAssembler.setPickDispatched( true ); float left = 0f; float top = 0f; float width = widget.getWidth(); float height = widget.getHeight(); final float defaultSBSize = 16f; if ( scrollHorizontal ) { this.scrollbarH = createHorizontalScrollbar( width - ( scrollVertical ? defaultSBSize : 0f ) ); scrollbarH.addScrollbarListener( this ); widgetAssembler.addWidget( scrollbarH, left, top + height - defaultSBSize ); } if ( scrollVertical ) { this.scrollbarV = createVerticalScrollbar( height - ( scrollHorizontal ? defaultSBSize : 0f ) ); scrollbarV.addScrollbarListener( this ); widgetAssembler.addWidget( scrollbarV, left + width - defaultSBSize, top ); } if ( scrollHorizontal && scrollVertical ) { this.spacerImage = new Image( false, defaultSBSize, defaultSBSize, HUD.getTheme().getScrollPanelSpaceTexture() ); widgetAssembler.addWidget( spacerImage, left + width - defaultSBSize, top + height - defaultSBSize ); } widget.addSizeListener( this ); widget.addContainerListener( this ); widget.addMouseListener( this ); } }