/** * 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.base; /** * A {@link ListModel} holds data for a List Widget. * * @author Marvin Froehlich (aka Qudus) */ public abstract class ListModel { private AbstractList list; private boolean usesFixedHeight = true; private float fixedItemHeight = -1f; private int selectedIndex = -1; void setList( AbstractList list ) { this.list = list; markListDirty(); } /** * Gets the List Widget, that this model is used for (can be null). * * @return the List Widget, that this model is used for. */ protected final AbstractList getList() { return ( list ); } /** * Gets an array of all Widgets, that are used by this model. * * @return an array of all Widgets, that are used by this model. */ protected abstract Widget[] getUsedWidgets(); /** * Adds a new Item at the given position. * * @param index * @param item */ protected abstract void addItemImpl( int index, Object item ); /** * Adds a new Item at the given position. * * @param index * @param item */ public final void addItem( int index, Object item ) { if ( ( index < 0 ) || ( index > getItemsCount() ) ) throw new IllegalArgumentException( "index must be in range [0, itemsCount]." ); addItemImpl( index, item ); } /** * Adds a new Item at the end of the list. * * @param item * * @return the index, at which the item has been added. */ public final int addItem( Object item ) { int index = getItemsCount(); addItemImpl( index, item ); return ( index ); } /** * Adds all items from the given List to this ListModel. * * @param items */ @SuppressWarnings( "unchecked" ) public void addItems( java.util.List items ) { for ( Object item : items ) { addItem( item ); } } /** * Adds all items from the given array to this ListModel. * * @param items */ public void addItems( Object[] items ) { for ( Object item : items ) { addItem( item ); } } /** * Sets the item at the given position. * * @param index * @param item */ protected abstract void setItemImpl( int index, Object item ); /** * Sets the item at the given position. * * @param index * @param item */ public final void setItem( int index, Object item ) { if ( ( index < 0 ) || ( index >= getItemsCount() ) ) throw new IllegalArgumentException( "index must be in range [0, itemsCount)." ); setItemImpl( index, item ); } /** * Removes an Item at the given position. * * @param index * * @return the removed Item or null, if there was no item at the given index. */ protected abstract Object removeItemImpl( int index ); /** * Removes an Item at the given position. * * @param index * * @return the removed Item or null, if there was no item at the given index. */ public final Object removeItem( int index ) { if ( ( index < 0 ) || ( index >= getItemsCount() ) ) throw new IllegalArgumentException( "index must be in range [0, itemsCount)." ); return ( removeItemImpl( index ) ); } /** * Clears the list. */ public abstract void clear(); /** * Gets the number of items in the list. * * @return the number of items in the list. */ public abstract int getItemsCount(); /** * Gets the item at index index. This item must be handleable by the used Widget. * * @param index * * @return the index'th item. */ protected abstract Object getItemImpl( int index ); /** * Gets the item at index index. This item must be handleable by the used Widget. * * @param index * * @return the index'th item. */ public Object getItem( int index ) { if ( ( index < 0 ) || ( index >= getItemsCount() ) ) return ( null ); return ( getItemImpl( index ) ); } /** * Gets the Widget, that is used to render the specified item. * This method should not do anything to the returned Widget. * All setup stuff is done in the {@link #prepareWidget(Widget, Object)} method. * * @param itemIndex * * @return the raw Widget. */ protected abstract Widget getWidgetImpl( int itemIndex ); /** * This method is called right before the Widget is used to render a specific item.<br> * It must only return the Widget. * * @param listContentWidth * @param widget * @param item * @param itemIndex */ protected abstract void prepareWidgetImpl( float listContentWidth, Widget widget, Object item, int itemIndex ); /** * This method is called right before the Widget is used to render a specific item. * * @param listContentWidth * @param widget * @param item * @param itemIndex */ protected void prepareWidget( float listContentWidth, Widget widget, Object item, int itemIndex ) { if ( getUsesFixedHeight() ) widget.setSize( listContentWidth, getItemHeight( 0 ) ); else widget.setSize( listContentWidth, getItemHeight( itemIndex ) ); prepareWidgetImpl( listContentWidth, widget, item, itemIndex ); } /** * Gets the Widget to render the specified item. * The Widget will be fully setup to be rendered to the list. * * @param listContentWidth * @param itemIndex * * @return the fully setup Widget. */ final Widget getWidget( float listContentWidth, int itemIndex ) { Object item = getItem( itemIndex ); Widget widget = getWidgetImpl( itemIndex ); prepareWidget( listContentWidth, widget, item, itemIndex ); return ( widget ); } /** * Gets the Widget to render the specified item. * The Widget will be fully setup to be rendered to the list. * * @param itemIndex * * @return the fully setup Widget. */ protected final Widget getWidget( int itemIndex ) { return ( getWidget( getList().getContentWidth(), itemIndex ) ); } /** * Checks, whether hovering the items needs the List to be redrawn. * * @return if hovering the items needs a redraw. */ public boolean hoverNeedsRedraw() { return ( false ); } /** * Checks, if the item should be selected after it was clicked at the specified location. * * @param itemIndex * @param itemTop * @param itemBottom * @param mouseX * @param mouseY * * @return should the item get selected? */ protected boolean checkOnMouseButtonPressedImpl( int itemIndex, float itemTop, float itemBottom, float mouseX, float mouseY ) { return ( true ); } /** * Checks, if the item should be selected after it was clicked at the specified location. * * @param itemIndex * @param itemLeft * @param itemTop * @param itemBottom * @param mouseX * @param mouseY * * @return should the item get selected? */ public final boolean checkOnMouseButtonPressed( int itemIndex, float itemLeft, float listContentWidth, float itemTop, float itemBottom, float mouseX, float mouseY ) { Widget widget = getWidgetImpl( itemIndex ); getList().getWidgetAssembler().reposition( widget, itemLeft, itemTop ); widget.setSize( listContentWidth, itemBottom - itemTop ); return ( checkOnMouseButtonPressedImpl( itemIndex, itemTop, itemBottom, mouseX, mouseY ) ); } /** * Sets, whether all items have the same height. * If true, getItemHeight(0) is used for all items. * Default: true. * * @param usesFixedHeight */ public void setUsesFixedHeight( boolean usesFixedHeight ) { if ( usesFixedHeight == this.usesFixedHeight ) return; this.usesFixedHeight = usesFixedHeight; this.fixedItemHeight = -1f; } /** * Returns, whether all items have the same height. * If true, getItemHeight(0) is used for all items. * Default: true. * * @return whether all items have the same height. */ public final boolean getUsesFixedHeight() { return ( usesFixedHeight ); } /** * Gets the item's height in HUD space. If getUsesFixedHeight() is true, only the value of the first item is used for all. * * @param itemIndex * * @return the item's height. */ protected abstract float getItemHeightImpl( int itemIndex ); /** * Gets the item's height in HUD space. If getUsesFixedHeight() is true, only the value of the first item is used for all. * * @param itemIndex * * @return the item's height. */ public final float getItemHeight( int itemIndex ) { if ( itemIndex < 0 ) return ( -1f ); if ( itemIndex >= getItemsCount() ) return ( -1f ); if ( getUsesFixedHeight() ) { if ( fixedItemHeight < 0f ) { fixedItemHeight = getItemHeightImpl( itemIndex ); } return ( fixedItemHeight ); } return ( getItemHeightImpl( itemIndex ) ); } /** * Gets the item's minimum width in HUD space. * * @param itemIndex * * @return the item's minimum height. */ protected abstract float getMinItemWidthImpl( int itemIndex ); /** * Gets the item's minimum width in HUD space. * * @param itemIndex * * @return the item's minimum height. */ public final float getMinItemWidth( int itemIndex ) { if ( itemIndex < 0 ) return ( -1f ); if ( itemIndex >= getItemsCount() ) return ( -1f ); return ( getMinItemWidthImpl( itemIndex ) ); } /** * Sets the selected index. * * @param index */ public void setSelectedIndex( int index ) { this.selectedIndex = index; } /** * Gets the selected index. * This method is not used by the (default) list implementation. {@link #isSelected(int)} is used instead, which is more flexible. * * @return the selected index. */ public int getSelectedIndex() { return ( selectedIndex ); } /** * Gets the selected item. * * @return the selected item. */ public Object getSelectedItem() { int selIdx = getSelectedIndex(); if ( ( selIdx < 0 ) || ( selIdx >= getItemsCount() ) ) return ( null ); return ( getItem( selIdx ) ); } /** * Queries, whether the specified index is selected. * * @param index * * @return index selected? */ public boolean isSelected( int index ) { return ( index == selectedIndex ); } /** * Notifies the List be be redrawn. */ public void markListDirty() { if ( list != null ) list.updateSizesAndMarkDirty(); } }