/**
* 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;
import java.util.ArrayList;
import java.util.HashMap;
import org.jagatoo.datatypes.NamedObject;
import org.jagatoo.input.InputSystemException;
import org.jagatoo.input.actions.AbstractInvokableInputAction;
import org.jagatoo.input.actions.InvokableInputAction;
import org.jagatoo.input.devices.InputDevice;
import org.jagatoo.input.devices.components.DeviceComponent;
import org.jagatoo.input.devices.components.DigitalDeviceComponent;
import org.openmali.vecmath2.Colorf;
import org.xith3d.ui.hud.HUD;
import org.xith3d.ui.hud.base.WidgetContainer;
import org.xith3d.ui.hud.utils.HUDFont;
import org.xith3d.ui.hud.widgets.Button;
/**
* The {@link MenuSystem} is a manager class, that manages instances of
* {@link MenuGroup}, which manage instances of {@link Menu}.
*
* @author Marvin Froehlich (aka Qudus)
*/
public class MenuSystem
{
private Button.Description accessorDesc = null;
private Colorf backgroundColor = Colorf.parseColor( "#846D2F" );
private Colorf borderColor = Colorf.DARK_GRAY;
private HUDFont captionFont = HUDFont.getFont( "Baveuse", HUDFont.PLAIN, 24 );
private Colorf captionFontColor = Colorf.ORANGE;
private final HUD hud;
private final WidgetContainer parentContainer;
private final float width;
private final float height;
private final int menuZIndex;
private boolean visible = false;
private final ArrayList< MenuGroup > menuGroups = new ArrayList< MenuGroup >();
private final HashMap< String, MenuGroup > menuGroupsMap = new HashMap< String, MenuGroup >();
private MenuGroup currentMenuGroup = null;
private final ArrayList< MenuSystemListener > listeners = new ArrayList< MenuSystemListener >();
private DigitalDeviceComponent globalMenuSystemAccessor = null;
private final InvokableInputAction menuAccessAction = new AbstractInvokableInputAction( 0 )
{
public String invokeAction( InputDevice device, DeviceComponent comp, int delta, int state, long nanoTime ) throws InputSystemException
{
if ( state == 0 )
return ( null );
if ( MenuSystem.this.isVisible() )
{
if ( ( getCurrentMenuGroup() != null ) && ( getCurrentMenuGroup().getPreviousMenuGroup() != null ) )
{
setCurrentMenuGroup( getCurrentMenuGroup().getPreviousMenuGroup() );
}
else
{
setVisible( false );
}
}
else
{
setVisible( true );
}
return ( null );
}
};
public void setMenuSystemAccessor( DigitalDeviceComponent accessor )
{
if ( globalMenuSystemAccessor != null )
globalMenuSystemAccessor.unbindAction( menuAccessAction );
this.globalMenuSystemAccessor = accessor;
if ( globalMenuSystemAccessor != null )
globalMenuSystemAccessor.bindAction( menuAccessAction );
}
public final DigitalDeviceComponent getMenuSystemAccessor()
{
return ( globalMenuSystemAccessor );
}
/**
* @return the assotiated {@link HUD}.
*/
public final HUD getHUD()
{
return ( hud );
}
/**
* @return the {@link WidgetContainer}, the {@link MenuGroup}'s {@link Menu}s
* are added to. This might be the HUD itself!
*/
public final WidgetContainer getContainer()
{
return ( parentContainer );
}
public final float getWidth()
{
return ( width );
}
public final float getHeight()
{
return ( height );
}
public final int getMenuZIndex()
{
return ( menuZIndex );
}
public void setVisible( boolean visible )
{
final boolean wasVisible = this.visible;
this.visible = visible;
if ( !wasVisible && visible )
{
fireOnMenuSystemEntered();
}
else if ( wasVisible && !visible )
{
fireOnMenuSystemExited();
}
if ( currentMenuGroup != null )
{
currentMenuGroup.setVisible( visible );
}
if ( visible )
{
hud.disposeFocus();
if ( currentMenuGroup != null )
{
currentMenuGroup.getMenuGroupWidget().getAccessorPanel().requestFocus();
}
}
}
public final boolean isVisible()
{
return ( visible );
}
public final Colorf getMenuCaptionFontColor()
{
return ( captionFontColor );
}
public final void setAccessorDescription( Button.Description desc )
{
this.accessorDesc = desc;
}
public final void setMenuBackgroundColor( Colorf color )
{
this.backgroundColor = color;
}
public final Colorf getMenuBackgroundColor()
{
return ( backgroundColor );
}
public final void setMenuBorderColor( Colorf color )
{
this.borderColor = color;
}
public final Colorf getMenuBorderColor()
{
return ( borderColor );
}
public final void setMenuCaptionFont( HUDFont font )
{
this.captionFont = font;
}
public final HUDFont getMenuCaptionFont()
{
return ( captionFont );
}
public final void setMenuCaptionFontColor( Colorf color )
{
this.captionFontColor = color;
}
public final Button.Description getAccessorDescription()
{
return ( accessorDesc );
}
public void addMenuGroup( MenuGroup group )
{
menuGroups.add( group );
menuGroupsMap.put( group.getName(), group );
if ( menuGroups.size() == 1 )
setCurrentMenuGroup( group );
group.init( this );
}
public final MenuGroup getMenuGroup( int index )
{
return ( menuGroups.get( index ) );
}
public final MenuGroup getMenuGroup( String name )
{
return ( menuGroupsMap.get( name ) );
}
public final int getMenuGroupsCount()
{
return ( menuGroups.size() );
}
public void setCurrentMenuGroup( MenuGroup menuGroup )
{
if ( menuGroup == null )
{
throw new IllegalArgumentException( "menuGroup must not be" );
}
this.currentMenuGroup = menuGroup;
for ( int i = 0; i < menuGroups.size(); i++ )
{
menuGroups.get( i ).setVisible( false );
}
menuGroup.setVisible( this.isVisible() );
}
public MenuGroup setCurrentMenuGroup( String menuGroupName )
{
final MenuGroup menuGroup = menuGroupsMap.get( menuGroupName );
if ( menuGroup == null )
{
throw new IllegalArgumentException( "MenuGroup \"" + menuGroupName + "\" not found!" );
}
setCurrentMenuGroup( menuGroup );
return ( menuGroup );
}
public final MenuGroup getCurrentMenuGroup()
{
return ( currentMenuGroup );
}
public MenuGroup findMenuGroup( Object menuID )
{
if ( menuID == null )
return ( null );
for ( int i = 0; i < menuGroups.size(); i++ )
{
final MenuGroup mg = menuGroups.get( i );
if ( mg.equals( menuID ) )
{
return ( mg );
}
/*
else if ( mg.equals( String.valueOf( menuID ) ) )
{
return ( mg );
}
*/
else if ( ( menuID instanceof NamedObject ) && ( mg.getName().equals( menuID ) ) )
{
return ( mg );
}
else if ( mg.getName().equals( String.valueOf( menuID ) ) )
{
return ( mg );
}
for ( int j = 0; j < mg.getMenusCount(); j++ )
{
final Menu menu = mg.getMenu( j );
if ( menu.equals( menuID ) )
{
return ( mg );
}
/*
else if ( menu.equals( String.valueOf( menuID ) ) )
{
return ( mg );
}
*/
else if ( ( menuID instanceof NamedObject ) && ( menu.getName().equals( menuID ) ) )
{
return ( mg );
}
else if ( menu.getName().equals( String.valueOf( menuID ) ) )
{
return ( mg );
}
}
}
return ( null );
}
public Menu findMenu( Object menuID )
{
if ( menuID == null )
return ( null );
for ( int i = 0; i < menuGroups.size(); i++ )
{
final MenuGroup mg = menuGroups.get( i );
for ( int j = 0; j < mg.getMenusCount(); j++ )
{
final Menu menu = mg.getMenu( j );
if ( menu.equals( menuID ) )
{
return ( menu );
}
else if ( menu.equals( menuID.toString() ) )
{
return ( menu );
}
else if ( ( menuID instanceof NamedObject ) && ( menu.getName().equals( menuID ) ) )
{
return ( menu );
}
else if ( menu.getName().equals( menuID.toString() ) )
{
return ( menu );
}
}
}
return ( null );
}
/**
* Adds a listner to the MenuSystem, that is notified of MenuSystem state changes.
*
* @param l
*/
public final void addMenuSystemListener( MenuSystemListener l )
{
listeners.add( l );
}
public final void removeMenuSystemListener( MenuSystemListener l )
{
listeners.remove( l );
}
protected boolean fireBeforeMenuSystemStateChanged( String currentMenu, Object target )
{
for ( int i = 0; i < listeners.size(); i++ )
{
if ( listeners.get( i ).beforeMenuStateChanged( this, currentMenu, target ) )
return ( true );
}
return ( false );
}
protected void fireOnMenuSystemStateChanged( String oldMenu, Object target )
{
for ( int i = 0; i < listeners.size(); i++ )
{
listeners.get( i ).onMenuStateChanged( this, oldMenu, target );
}
}
protected void fireOnSettingChanged( Menu menu, String setting, Object value )
{
for ( int i = 0; i < listeners.size(); i++ )
{
listeners.get( i ).onSettingChanged( this, menu, setting, value );
}
}
protected boolean fireOnMenuActionPerformed( MenuGroup menuGroup, Menu menu, String action )
{
boolean consumed = false;
for ( int i = 0; i < listeners.size(); i++ )
{
consumed = listeners.get( i ).onMenuActionPerformed( this, menuGroup, menu, action ) || consumed;
}
return ( consumed );
}
protected void fireOnMenuSystemEntered()
{
for ( int i = 0; i < listeners.size(); i++ )
{
listeners.get( i ).onMenuSystemEntered( this );
}
}
protected void fireOnMenuSystemExited()
{
for ( int i = 0; i < listeners.size(); i++ )
{
listeners.get( i ).onMenuSystemExited( this );
}
}
protected void onOtherMenuRequested( Object menuID )
{
if ( menuID == null )
{
setVisible( false );
return;
}
final MenuGroup currentMG = getCurrentMenuGroup();
final Menu currentMenu = ( currentMG != null ) ? currentMG.getCurrentActiveMenu() : null;
final MenuGroup mg = findMenuGroup( menuID );
final Menu menu = findMenu( menuID );
// fire before-event
if ( ( currentMG != mg ) || ( currentMenu != menu ) )
{
if ( ( mg == null ) && ( menu == null ) )
{
if ( ( currentMenu == null ) && ( fireBeforeMenuSystemStateChanged( currentMG.getName(), menuID ) ) )
return;
else if ( ( currentMenu != null ) && ( fireBeforeMenuSystemStateChanged( currentMenu.getName(), menuID ) ) )
return;
}
else if ( menu == null )
{
if ( currentMenu != mg.getCurrentActiveMenu() )
{
if ( ( currentMenu == null ) && ( fireBeforeMenuSystemStateChanged( currentMG.getName(), mg.getName() ) ) )
return;
else if ( ( currentMenu != null ) && ( fireBeforeMenuSystemStateChanged( currentMenu.getName(), mg.getName() ) ) )
return;
}
}
else
{
if ( currentMenu != menu )
{
if ( ( currentMenu == null ) && ( fireBeforeMenuSystemStateChanged( currentMG.getName(), menu.getName() ) ) )
return;
else if ( ( currentMenu != null ) && ( fireBeforeMenuSystemStateChanged( currentMenu.getName(), menu.getName() ) ) )
return;
}
}
}
// fire state-change-event
if ( mg == null )
{
if ( currentMenu == null )
fireOnMenuSystemStateChanged( currentMG.getName(), menuID );
else
fireOnMenuSystemStateChanged( currentMenu.getName(), menuID );
}
else
{
if ( ( currentMG != mg ) || ( currentMenu != menu ) )
{
if ( menu == null )
{
currentMG.setCurrentActiveMenu( null );
mg.setCurrentActiveMenu( null );
this.setCurrentMenuGroup( mg );
if ( currentMenu != mg.getCurrentActiveMenu() )
{
if ( currentMenu == null )
fireOnMenuSystemStateChanged( currentMG.getName(), mg.getName() );
else
fireOnMenuSystemStateChanged( currentMenu.getName(), mg.getName() );
}
}
else
{
currentMG.setCurrentActiveMenu( null );
mg.setCurrentActiveMenu( menu );
this.setCurrentMenuGroup( mg );
if ( currentMenu != menu )
{
if ( currentMenu == null )
fireOnMenuSystemStateChanged( currentMG.getName(), menu.getName() );
else
fireOnMenuSystemStateChanged( currentMenu.getName(), menu.getName() );
}
}
}
}
}
/**
* Creates a new {@link MenuGroup}.
*
* @param hud the assotiated {@link HUD}
* @param parentContainer the {@link WidgetContainer}, the {@link MenuGroup}'s {@link Menu}s
* are added to. This might be the HUD itself!
* @param width the design with of the {@link Menu}s
* @param height the design height of the {@link Menu}s
* @param menuZIndex
*/
public MenuSystem( HUD hud, WidgetContainer parentContainer, float width, float height, int menuZIndex )
{
if ( ( hud == null ) || ( parentContainer == null ) )
throw new IllegalArgumentException( "Neither hud nor parentContainer must be null" );
this.hud = hud;
this.parentContainer = parentContainer;
this.width = width;
this.height = height;
this.menuZIndex = menuZIndex;
}
/**
* Creates a new {@link MenuGroup}.
*
* @param hud the assotiated {@link HUD}
* @param width the design with of the {@link Menu}s
* @param height the design height of the {@link Menu}s
* @param menuZIndex
*/
public MenuSystem( HUD hud, float width, float height, int menuZIndex )
{
this( hud, hud.getContentPane(), width, height, menuZIndex );
}
/**
* Creates a new {@link MenuGroup}.
*
* @param hud the assotiated {@link HUD}
* @param width the design with of the {@link Menu}s
* @param height the design height of the {@link Menu}s
*/
public MenuSystem( HUD hud, float width, float height )
{
this( hud, hud.getContentPane(), width, height, 1000 );
}
/**
* Creates a new {@link MenuGroup}.
*
* @param hud the assotiated {@link HUD}
*/
public MenuSystem( HUD hud )
{
this( hud, hud.getContentPane(), hud.getResX(), hud.getResY(), 1000 );
}
}