The-Simpsons-Hit-and-Run/game/code/presentation/gui/guimenu.cpp

1368 lines
41 KiB
C++

//===========================================================================
// Copyright (C) 2000 Radical Entertainment Ltd. All rights reserved.
//
// Component: CGuiMenu
//
// Description: Implementation of the CGuiMenu class.
//
// Authors: Darwin Chau
// Tony Chu
//
// Revisions Date Author Revision
// 2000/12/4 DChau Created
// 2002/06/06 TChu Modified for SRR2
//
//===========================================================================
//===========================================================================
// Includes
//===========================================================================
#include <presentation/gui/guimenu.h>
#include <presentation/gui/guiscreen.h>
#include <presentation/gui/guisystem.h>
#include <presentation/gui/guiuserinputhandler.h>
#include <presentation/gui/utility/specialfx.h>
#include <input/inputmanager.h>
#include <memory/srrmemory.h>
#include <events/eventmanager.h>
#include <raddebug.hpp> // Foundation
#include <radmath/trig.hpp> // RadMath
// Scrooby
//
#include <group.h>
#include <page.h>
#include <sprite.h>
#include <text.h>
//===========================================================================
// Global Data, Local Data, Local Classes
//===========================================================================
const tColour DEFAULT_SELECTED_ITEM_COLOUR( 255, 255, 0 );
const tColour DEFAULT_DISABLED_ITEM_COLOUR( 128, 128, 128 ); // the same as in guiscreenmemorycard.cpp
const tColour DEFAULT_OUTLINE_COLOUR( 0, 0, 0, 192 );
const float SLIDER_FULL_RANGE_TIME = 2000; // in milliseconds
const int SELECTION_MADE_DURATION = 250; // in milliseconds
#ifdef RAD_WIN32
const float ARROW_SCALE = 0.5f;
#endif
//===========================================================================
// Public Member Functions - CGuiMenu
//===========================================================================
//===========================================================================
// CGuiMenu::CGuiMenu
//===========================================================================
// Description: Constructor.
//
// Constraints: None.
//
// Parameters: None.
//
// Return: N/A.
//
//===========================================================================
CGuiMenu::CGuiMenu( CGuiEntity* pParent, int maxNumItems,
eMenuType menuType,
int specialEffects )
: CGuiEntity( pParent ),
m_menuType( menuType ),
m_specialEffects( static_cast<short>( specialEffects ) ),
m_menuItems( NULL ),
m_numItems( 0 ),
m_selection( NO_SELECTION ),
m_pCursor( NULL ),
m_isSelectionMade( false ),
m_isHighlightEnabled( true ),
m_highlightColour( DEFAULT_SELECTED_ITEM_COLOUR ),
m_selectionMadeOutlineColour( tColour( 255, 0, 0, 192 ) ),
m_isGreyOutEnabled( true ),
m_elapsedTime( 0 ),
m_selectionMadeElapsedTime( 0 ),
#ifdef RAD_WIN32
m_bIsSelectionOutlined( false ),
m_selectionOutlineColour( tColour( 0, 0, 255, 192 ) ),
#endif
m_controllerID( -1 )
{
MEMTRACK_PUSH_GROUP( "GUIMenu" );
rAssertMsg( ( specialEffects & 0xFFFF0000 ) == 0, "Bitmask Overflow!" );
// create array of 'maxNumItems' menu items
//
rAssert( maxNumItems > 0 );
m_menuItems = new GuiMenuItem*[ maxNumItems ];
rAssert( m_menuItems != NULL );
for( int i = 0; i < maxNumItems; i++ )
{
m_menuItems[ i ] = NULL;
}
MEMTRACK_POP_GROUP( "GUIMenu" );
}
//===========================================================================
// CGuiMenu::~CGuiMenu
//===========================================================================
// Description: Destructor.
//
// Constraints: None.
//
// Parameters: None.
//
// Return: N/A.
//
//===========================================================================
CGuiMenu::~CGuiMenu()
{
if( m_menuItems != NULL )
{
for( int i = 0; i < m_numItems; i++ )
{
if( m_menuItems[ i ] != NULL )
{
delete m_menuItems[ i ];
m_menuItems[ i ] = NULL;
}
}
delete [] m_menuItems;
m_menuItems = NULL;
}
}
//===========================================================================
// CGuiMenu::HandleMessage
//===========================================================================
// Description: Message handler for this class.
//
// Constraints: None.
//
// Parameters:
//
// Return: N/A.
//
//===========================================================================
void CGuiMenu::HandleMessage( eGuiMessage message, unsigned int param1,
unsigned int param2 )
{
if( m_isSelectionMade && this->IsControllerMessage( message ) )
{
// selection has already been made, ignore all controller messages
//
return;
}
switch( message )
{
case GUI_MSG_UPDATE:
{
if( m_selection != NO_SELECTION )
{
this->UpdateCurrentSelection( param1 );
}
break;
}
case GUI_MSG_CONTROLLER_UP:
{
this->ChangeSelection( -1 );
break;
}
case GUI_MSG_CONTROLLER_DOWN:
{
this->ChangeSelection( +1 );
break;
}
case GUI_MSG_CONTROLLER_LEFT:
{
this->DecrementSelectionValue();
break;
}
case GUI_MSG_CONTROLLER_RIGHT:
{
this->IncrementSelectionValue();
break;
}
case GUI_MSG_CONTROLLER_SELECT:
{
this->MakeSelection();
break;
}
#ifdef RAD_WIN32
case GUI_MSG_MOUSE_OVER:
{
this->SetNewSelection(param1);
break;
}
case GUI_MSG_MOUSE_LCLICKHOLD:
{
this->OutlineSelection( (param1!=0) );
break;
}
#endif
default:
{
break;
}
}
}
//===========================================================================
// CGuiMenu::AddMenuItem
//===========================================================================
// Description:
//
// Constraints: None.
//
// Parameters:
//
// Return: N/A.
//
//===========================================================================
GuiMenuItem* CGuiMenu::AddMenuItem( Scrooby::BoundedDrawable* pItem,
Scrooby::BoundedDrawable* pItemValue,
Scrooby::Polygon* pSlider,
Scrooby::Sprite* pSliderImage,
Scrooby::Sprite* pItemValueArrowL,
Scrooby::Sprite* pItemValueArrowR,
int attributes )
{
rAssert( m_menuItems[ m_numItems ] == NULL );
// create a new menu item based on menu type
//
switch( m_menuType )
{
case GUI_TEXT_MENU:
{
m_menuItems[ m_numItems ] = new GuiMenuItemText;
break;
}
case GUI_SPRITE_MENU:
{
m_menuItems[ m_numItems ] = new GuiMenuItemSprite;
break;
}
default:
{
rAssertMsg( false, "Invalid menu type!" );
break;
}
}
rAssert( m_menuItems[ m_numItems ] != NULL );
GuiMenuItem* pMenuItem = m_menuItems[ m_numItems ];
m_menuItems[ m_numItems ]->SetItem( pItem );
// for items w/ value toggle
//
if( pItemValue != NULL )
{
m_menuItems[ m_numItems ]->SetItemValue( pItemValue );
// hide arrows by default, if exists
//
if( pItemValueArrowL != NULL )
{
pItemValueArrowL->SetVisible( false );
#ifdef RAD_WIN32
pItemValueArrowL->ScaleAboutCenter( ARROW_SCALE );
#endif
m_menuItems[ m_numItems ]->m_itemValueArrowL = pItemValueArrowL;
}
if( pItemValueArrowR != NULL )
{
pItemValueArrowR->SetVisible( false );
#ifdef RAD_WIN32
pItemValueArrowR->ScaleAboutCenter( ARROW_SCALE );
#endif
m_menuItems[ m_numItems ]->m_itemValueArrowR = pItemValueArrowR;
}
}
if( m_menuType == GUI_TEXT_MENU )
{
if( (attributes & TEXT_OUTLINE_ENABLED) > 0 )
{
// turn on text outlining
//
m_menuItems[ m_numItems ]->SetDisplayOutline( true );
}
#ifdef RAD_WIN32
pItem->SetVerticalJustification( Scrooby::Top );
#endif
}
// for items w/ sliders
//
if( pSliderImage != NULL )
{
m_menuItems[ m_numItems ]->m_slider.SetScroobyImage( pSliderImage );
}
m_menuItems[ m_numItems ]->m_attributes = attributes;
m_menuItems[ m_numItems ]->m_defaultColour = pItem->GetColour();
m_numItems++;
// select first item by default
//
if( m_numItems == 1 )
{
SelectItem( 0 );
}
return pMenuItem;
}
//===========================================================================
// CGuiMenu::SetMenuItemEnabled
//===========================================================================
// Description: Enable/disable menu item.
//
// Constraints: None.
//
// Parameters:
//
// Return:
//
//===========================================================================
void CGuiMenu::SetMenuItemEnabled( int index, bool enabled, bool changeVisibility )
{
GuiMenuItem* currentMenuItem = this->GetMenuItem( index );
rAssert( currentMenuItem != NULL );
Scrooby::BoundedDrawable* currentItem = currentMenuItem->GetItem();
rAssert( currentItem != NULL );
Scrooby::BoundedDrawable* currentItemValue = currentMenuItem->GetItemValue();
if( enabled )
{
currentMenuItem->m_attributes |= SELECTION_ENABLED;
if( index != m_selection )
{
if( m_isGreyOutEnabled )
{
// restore default item colour
//
currentItem->SetColour( currentMenuItem->m_defaultColour );
if( currentItemValue != NULL )
{
currentItemValue->SetColour( currentMenuItem->m_defaultColour );
}
}
// show cursor
//
if( m_pCursor != NULL )
{
m_pCursor->SetVisible( true );
}
if( m_selection == NO_SELECTION )
{
m_selection = 0;
this->SelectItem( index );
}
}
}
else // !enabled
{
currentMenuItem->m_attributes &= ~SELECTION_ENABLED;
// if item disabled is current selection, select next enabled item
//
if( index == m_selection )
{
this->ChangeSelection( +1, false );
if( index == m_selection )
{
// reset cursor to first selection, and hide it
//
this->MoveCursor( m_selection, 0 );
if( m_pCursor != NULL )
{
m_pCursor->SetVisible( false );
}
// this means all selections have been disabled
//
m_selection = NO_SELECTION;
}
}
if( m_isGreyOutEnabled )
{
// grey out item colour
//
currentItem->SetColour( DEFAULT_DISABLED_ITEM_COLOUR );
if( currentItemValue != NULL )
{
currentItemValue->SetColour( DEFAULT_DISABLED_ITEM_COLOUR );
}
}
}
if( changeVisibility )
{
currentItem->SetVisible( enabled );
if( currentItemValue != NULL )
{
currentItemValue->SetVisible( enabled );
}
}
}
bool CGuiMenu::IsMenuItemEnabled( int index )
{
GuiMenuItem* currentMenuItem = this->GetMenuItem( index );
rAssert( currentMenuItem != NULL );
return (currentMenuItem->m_attributes & SELECTION_ENABLED);
}
//===========================================================================
// CGuiMenu::Reset
//===========================================================================
// Description: Unselect all menu items.
//
// Constraints: None.
//
// Parameters: N/A.
//
// Return: N/A.
//
//===========================================================================
void CGuiMenu::Reset( int defaultSelection )
{
// un-select current item
if( m_selection != NO_SELECTION )
{
this->UnselectItem( m_selection );
}
// select first item
this->SelectItem( defaultSelection );
}
//===========================================================================
// CGuiMenu::SetHighlightColour
//===========================================================================
// Description: Sets the menu highlight colour.
//
// Constraints: None.
//
// Parameters: N/A.
//
// Return: N/A.
//
//===========================================================================
void CGuiMenu::SetHighlightColour( bool isEnabled, tColour colour )
{
m_isHighlightEnabled = isEnabled;
m_highlightColour = colour;
}
//===========================================================================
// CGuiMenu::SetSelectionValue
//===========================================================================
// Description:
//
// Constraints: None.
//
// Parameters: N/A.
//
// Return: N/A.
//
//===========================================================================
void CGuiMenu::SetSelectionValue( int index, int value )
{
if( value >= 0 && value < m_menuItems[ index ]->m_itemValueCount )
{
m_menuItems[ index ]->SetItemValueIndex( value );
// Notify screen that selection value has changed
m_pParent->HandleMessage( GUI_MSG_MENU_SELECTION_VALUE_CHANGED, index, value );
}
}
//===========================================================================
// CGuiMenu::SetSelectionValueCount
//===========================================================================
// Description:
//
// Constraints: None.
//
// Parameters: N/A.
//
// Return: N/A.
//
//===========================================================================
void CGuiMenu::SetSelectionValueCount( int index, int count )
{
m_menuItems[ index ]->m_itemValueCount = count;
// if( index == m_selection )
{
// show arrows if more than one value to toggle; otherwise, hide them (partially)
//
bool showArrows = (m_menuItems[ index ]->m_itemValueCount > 1);
if( m_menuItems[ index ]->m_itemValueArrowL != NULL &&
m_menuItems[ index ]->m_itemValueArrowR != NULL )
{
m_menuItems[ index ]->m_itemValueArrowL->SetAlpha( showArrows ? 1.0f : 0.4f );
m_menuItems[ index ]->m_itemValueArrowR->SetAlpha( showArrows ? 1.0f : 0.4f );
}
}
}
//===========================================================================
// CGuiMenu::MakeSelection
//===========================================================================
// Description:
//
// Constraints: None.
//
// Parameters: N/A.
//
// Return: N/A.
//
//===========================================================================
void CGuiMenu::MakeSelection( bool isSelectionMade )
{
if (m_selection == NO_SELECTION) return;//------------->
if( (m_menuItems[ m_selection ]->m_attributes & SELECTABLE) > 0 )
{
if( isSelectionMade )
{
if( m_selection != NO_SELECTION )
{
if( m_menuType == GUI_TEXT_MENU )
{
m_menuItems[ m_selection ]->SetOutlineColour( m_selectionMadeOutlineColour );
#ifdef RAD_WIN32
if( m_bIsSelectionOutlined )
m_menuItems[ m_selection ]->GetItem()->SetColour( DEFAULT_SELECTED_ITEM_COLOUR );
#endif
}
m_selectionMadeElapsedTime = 0;
GetEventManager()->TriggerEvent( EVENT_FE_MENU_SELECT );
// tell parent screen to ignore all controller inputs until
// selection-made effect is completed
//
CGuiScreen* parentScreen = static_cast<CGuiScreen*>( m_pParent );
rAssert( parentScreen );
parentScreen->SetIngoreControllerInputs( true );
m_isSelectionMade = true;
}
}
else
{
CGuiScreen* parentScreen = static_cast<CGuiScreen*>( m_pParent );
rAssert( parentScreen );
parentScreen->SetIngoreControllerInputs( false );
if( m_menuType == GUI_TEXT_MENU )
{
m_menuItems[ m_selection ]->SetOutlineColour( DEFAULT_OUTLINE_COLOUR );
}
// restore current item's regular L/R arrows, if exist
//
if( m_menuItems[ m_selection ]->m_itemValueArrowL != NULL &&
m_menuItems[ m_selection ]->m_itemValueArrowR != NULL )
{
m_menuItems[ m_selection ]->m_itemValueArrowL->SetIndex( 0 );
m_menuItems[ m_selection ]->m_itemValueArrowR->SetIndex( 0 );
}
m_pParent->HandleMessage( GUI_MSG_MENU_SELECTION_MADE, m_selection );
m_isSelectionMade = false;
}
}
}
//===========================================================================
// Protected Member Functions - CGuiMenu
//===========================================================================
//===========================================================================
// CGuiMenu::SelectItem
//===========================================================================
// Description: Select specified item.
//
// Constraints: None.
//
// Parameters: N/A.
//
// Return: N/A.
//
//===========================================================================
void CGuiMenu::SelectItem( int index )
{
rAssert( index >= 0 && index < m_numItems );
rAssert( m_menuItems[ index ] != NULL );
// move cursor
if( index != m_selection )
{
this->MoveCursor( m_selection, index );
}
// reset elapsed time
m_elapsedTime = 0;
if( m_isHighlightEnabled && m_menuType == GUI_TEXT_MENU )
{
m_menuItems[ index ]->GetItem()->SetColour( m_highlightColour );
}
// apply to item value also, if exists
if( m_menuItems[ index ]->GetItemValue() != NULL )
{
if( m_isHighlightEnabled && m_menuType == GUI_TEXT_MENU )
{
m_menuItems[ index ]->GetItemValue()->SetColour( m_highlightColour );
}
// show arrows, if exists
//
if( m_menuItems[ index ]->m_itemValueArrowL != NULL &&
m_menuItems[ index ]->m_itemValueArrowR != NULL )
{
m_menuItems[ index ]->m_itemValueArrowL->SetVisible( true );
m_menuItems[ index ]->m_itemValueArrowR->SetVisible( true );
}
}
/*
if( m_specialEffects & MENU_SFX_DROP_SHADOW )
{
// turn on drop shadow
m_menuItems[ index ]->m_item->SetDisplayShadow( true );
// apply to item value also, if exists
if( m_menuItems[ index ]->m_itemValue != NULL )
{
m_menuItems[ index ]->m_itemValue->SetDisplayShadow( true );
}
}
*/
m_selection = index;
}
//===========================================================================
// CGuiMenu::UnselectItem
//===========================================================================
// Description: Unselect specified item.
//
// Constraints: None.
//
// Parameters: N/A.
//
// Return: N/A.
//
//===========================================================================
void CGuiMenu::UnselectItem( int index )
{
rAssert( index >= 0 && index < m_numItems );
rAssert( m_menuItems[ index ] != NULL );
if( m_menuType == GUI_TEXT_MENU )
{
m_menuItems[ index ]->GetItem()->SetColour( m_menuItems[ index ]->m_defaultColour );
}
// apply to item value also, if exists
if( m_menuItems[ index ]->GetItemValue() != NULL )
{
if( m_menuType == GUI_TEXT_MENU )
{
m_menuItems[ index ]->GetItemValue()->SetColour( m_menuItems[ index ]->m_defaultColour );
}
// hide arrows until item is selected
//
if( m_menuItems[ index ]->m_itemValueArrowL != NULL &&
m_menuItems[ index ]->m_itemValueArrowR != NULL )
{
m_menuItems[ index ]->m_itemValueArrowL->SetVisible( false );
m_menuItems[ index ]->m_itemValueArrowR->SetVisible( false );
}
}
if( m_specialEffects & MENU_SFX_SIZE_PULSE )
{
// reset scale
m_menuItems[ index ]->GetItem()->ResetTransformation();
// apply to item value also, if exists
if( m_menuItems[ index ]->GetItemValue() != NULL )
{
m_menuItems[ index ]->GetItemValue()->ResetTransformation();
}
}
/*
if( m_specialEffects & MENU_SFX_DROP_SHADOW )
{
// turn off drop shadow
m_menuItems[ index ]->m_item->SetDisplayShadow( false );
// apply to item value also, if exists
if( m_menuItems[ index ]->m_itemValue != NULL )
{
m_menuItems[ index ]->m_itemValue->SetDisplayShadow( false );
}
}
*/
}
//===========================================================================
// CGuiMenu::ChangeSelection
//===========================================================================
// Description: Select the next menu item.
//
// Constraints: None.
//
// Parameters: N/A.
//
// Return: N/A.
//
//===========================================================================
void CGuiMenu::ChangeSelection( int deltaItems, bool isUserInput )
{
if( m_selection != NO_SELECTION )
{
rAssert( m_numItems > 0 );
// Increment and check for wrap around.
//
int newSelection = (m_selection + deltaItems + m_numItems) % m_numItems;
// Skip to next enabled selection if new selection is disabled
while( newSelection != m_selection )
{
if( m_menuItems[ newSelection ]->m_attributes & SELECTION_ENABLED )
{
// Unselect the current item.
//
this->UnselectItem( m_selection );
// Notify screen that menu selection has changed
// (param1 = new selection, param2 = old selection)
//
m_pParent->HandleMessage( GUI_MSG_MENU_SELECTION_CHANGED, newSelection, m_selection );
// Make the new selection.
//
this->SelectItem( newSelection );
if( isUserInput )
{
GetEventManager()->TriggerEvent( EVENT_FE_MENU_UPORDOWN );
}
break;
}
newSelection = (newSelection + deltaItems + m_numItems) % m_numItems;
}
}
}
#ifdef RAD_WIN32
//===========================================================================
// CGuiMenu::ChangeSelection
//===========================================================================
// Description: Select a specific selection.
//
// Constraints: None.
//
// Parameters: N/A.
//
// Return: N/A.
//
//===========================================================================
void CGuiMenu::SetNewSelection( int newSelection, bool isUserInput )
{
if( m_selection != NO_SELECTION )
{
rAssert( m_numItems > 0 );
if( newSelection != m_selection )
{
if( m_menuItems[ newSelection ]->m_attributes & SELECTION_ENABLED )
{
// Unselect the current item.
//
this->UnselectItem( m_selection );
// Notify screen that menu selection has changed
// (param1 = new selection, param2 = old selection)
//
m_pParent->HandleMessage( GUI_MSG_MENU_SELECTION_CHANGED, newSelection, m_selection );
// Make the new selection.
//
this->SelectItem( newSelection );
if( isUserInput )
{
GetEventManager()->TriggerEvent( EVENT_FE_MENU_UPORDOWN );
}
}
}
}
}
//===========================================================================
// CGuiMenu::OutlineSelection
//===========================================================================
// Description: Outlines a specific selection.
//
// Constraints: None.
//
// Parameters: N/A.
//
// Return: N/A.
//
//===========================================================================
void CGuiMenu::OutlineSelection( bool bOutline )
{
if (m_selection == NO_SELECTION) return;//------------->
if( (m_menuItems[ m_selection ]->m_attributes & SELECTABLE) > 0 )
{
if( m_menuType == GUI_TEXT_MENU )
{
if( bOutline )
m_menuItems[ m_selection ]->GetItem()->SetColour( m_selectionOutlineColour );
else
m_menuItems[ m_selection ]->GetItem()->SetColour( DEFAULT_SELECTED_ITEM_COLOUR );
m_bIsSelectionOutlined = bOutline;
}
}
}
#endif
//===========================================================================
// CGuiMenu::IncrementSelectionValue
//===========================================================================
// Description:
//
// Constraints: None.
//
// Parameters: N/A.
//
// Return: N/A.
//
//===========================================================================
void CGuiMenu::IncrementSelectionValue( bool isUserInput )
{
if( m_selection != NO_SELECTION &&
m_menuItems[ m_selection ]->GetItemValue() != NULL )
{
int currentIndex = m_menuItems[ m_selection ]->GetItemValueIndex();
int newIndex = currentIndex;
if( currentIndex < m_menuItems[ m_selection ]->m_itemValueCount - 1 )
{
newIndex = currentIndex + 1;
}
else if( m_menuItems[ m_selection ]->m_attributes & VALUES_WRAPPED )
{
// wrap around to beginning
newIndex = 0;
}
if( newIndex != currentIndex )
{
m_menuItems[ m_selection ]->SetItemValueIndex( newIndex );
// Notify screen that selection value has changed
m_pParent->HandleMessage( GUI_MSG_MENU_SELECTION_VALUE_CHANGED, m_selection, newIndex );
if( isUserInput )
{
GetEventManager()->TriggerEvent( EVENT_FE_MENU_UPORDOWN );
}
}
}
}
//===========================================================================
// CGuiMenu::DecrementSelectionValue
//===========================================================================
// Description:
//
// Constraints: None.
//
// Parameters: N/A.
//
// Return: N/A.
//
//===========================================================================
void CGuiMenu::DecrementSelectionValue( bool isUserInput )
{
if( m_selection != NO_SELECTION &&
m_menuItems[ m_selection ]->GetItemValue() != NULL )
{
int currentIndex = m_menuItems[ m_selection ]->GetItemValueIndex();
int newIndex = currentIndex;
if( currentIndex > 0 )
{
newIndex = currentIndex - 1;
}
else if( m_menuItems[ m_selection ]->m_attributes & VALUES_WRAPPED )
{
// wrap around to end
newIndex = m_menuItems[ m_selection ]->m_itemValueCount - 1;
}
if( newIndex != currentIndex )
{
rAssertMsg( newIndex != -1, "This means item value count is zero!" );
m_menuItems[ m_selection ]->SetItemValueIndex( newIndex );
// Notify screen that selection value has changed
m_pParent->HandleMessage( GUI_MSG_MENU_SELECTION_VALUE_CHANGED, m_selection, newIndex );
if( isUserInput )
{
GetEventManager()->TriggerEvent( EVENT_FE_MENU_UPORDOWN );
}
}
}
}
//===========================================================================
// Private Member Functions - CGuiMenu
//===========================================================================
//===========================================================================
// CGuiMenu::UpdateCurrentSelection
//===========================================================================
// Description: Updates current selection.
//
// Constraints: None.
//
// Parameters:
//
// Return:
//
//===========================================================================
void CGuiMenu::UpdateCurrentSelection( int elapsedTime )
{
rAssert( m_selection >= 0 && m_selection < m_numItems );
Scrooby::BoundedDrawable* currentItem = m_menuItems[ m_selection ]->GetItem();
rAssert( currentItem != NULL );
if( m_isSelectionMade ) // update "selection made" effect
{
m_selectionMadeElapsedTime += elapsedTime;
if( m_selectionMadeElapsedTime > SELECTION_MADE_DURATION )
{
this->MakeSelection( false );
}
}
else // update current selection
{
const unsigned int ITEM_PULSE_PERIOD = 600; // in milliseconds
if( m_specialEffects & MENU_SFX_COLOUR_PULSE )
{
// pulse text colour
//
tColour textColour;
GuiSFX::ModulateColour( &textColour,
(float)m_elapsedTime,
(float)ITEM_PULSE_PERIOD,
tColour( 255, 224, 32 ), // m_menuItems[ m_selection ]->m_defaultColour,
m_highlightColour );
currentItem->SetColour( textColour );
}
if( m_specialEffects & MENU_SFX_SIZE_PULSE )
{
// pulse text size
//
const float ITEM_SCALE_FACTOR = 0.10f;
currentItem->ResetTransformation();
// if( m_elapsedTime < ITEM_PULSE_PERIOD )
{
// TC: [IMPROVE] Man, this looks ugly!
//
static const float THETA_OFFSET = -rmt::ASin( -0.5f ); // = -ASin( (1 - center) / amplitude )
float scale = GuiSFX::Pulse( (float)m_elapsedTime,
(float)ITEM_PULSE_PERIOD,
1.0f + ITEM_SCALE_FACTOR / 2,
ITEM_SCALE_FACTOR,
THETA_OFFSET );
int width = 0;
int height = 0;
currentItem->GetBoundingBoxSize( width, height );
// scale text about (left center, right center, or middle center)
//
if( currentItem->GetHorizontalJustification() == Scrooby::Left )
{
currentItem->ScaleAboutPoint( scale, 0, height / 2 );
}
else if( currentItem->GetHorizontalJustification() == Scrooby::Right )
{
currentItem->ScaleAboutPoint( scale, width, height / 2 );
}
else
{
currentItem->ScaleAboutCenter( scale );
}
}
}
// update slider, if exists on current selection
//
ImageSlider* currentItemSlider = &(m_menuItems[ m_selection ]->m_slider);
if( currentItemSlider->m_pImage != NULL )
{
bool hasSliderValueChanged = false;
int numUserInputHandlers = GetGuiSystem()->GetNumUserInputHandlers();
for( int i = 0; i < numUserInputHandlers; i++ )
{
if( m_controllerID != -1 && m_controllerID != static_cast<short>( i ) )
{
// ignore other controller inputs
//
continue;
}
CGuiUserInputHandler* userInputHandler = GetGuiSystem()->GetUserInputHandler( i );
if( userInputHandler != NULL )
{
#ifdef RAD_WIN32
if( userInputHandler->IsXAxisOnLeft() ||
GetInputManager()->GetFEMouse()->OnSliderHorizontalClickDrag() == MDIR_LEFT )
#else
if( userInputHandler->IsButtonDown( GuiInput::Left ) ||
userInputHandler->IsXAxisOnLeft() )
#endif
{
float newValue = currentItemSlider->m_value - elapsedTime / SLIDER_FULL_RANGE_TIME;
if( newValue < 0.0f )
{
newValue = 0.0f; // clamp lower-end at 0.0
}
if( newValue != currentItemSlider->m_value )
{
currentItemSlider->SetValue( newValue );
hasSliderValueChanged = true;
}
}
#ifdef RAD_WIN32
if( userInputHandler->IsXAxisOnRight() ||
GetInputManager()->GetFEMouse()->OnSliderHorizontalClickDrag() == MDIR_RIGHT )
#else
if( userInputHandler->IsButtonDown( GuiInput::Right ) ||
userInputHandler->IsXAxisOnRight() )
#endif
{
float newValue = currentItemSlider->m_value + elapsedTime / SLIDER_FULL_RANGE_TIME;
if( newValue > 1.0f )
{
newValue = 1.0f; // clamp higher-end at 1.0
}
if( newValue != currentItemSlider->m_value )
{
currentItemSlider->SetValue( newValue );
hasSliderValueChanged = true;
}
}
}
}
if( hasSliderValueChanged )
{
// notify screen that slider value has changed
//
m_pParent->HandleMessage( GUI_MSG_MENU_SELECTION_VALUE_CHANGED, m_selection );
}
else
{
// otherwise, notify screen that slider value is currently not changing
//
m_pParent->HandleMessage( GUI_MSG_MENU_SLIDER_NOT_CHANGING, m_selection );
}
}
// update L/R arrows (if exists for current selection)
//
if( m_menuItems[ m_selection ]->m_itemValueArrowL != NULL &&
m_menuItems[ m_selection ]->m_itemValueArrowR != NULL )
{
m_menuItems[ m_selection ]->m_itemValueArrowL->SetIndex( 0 );
m_menuItems[ m_selection ]->m_itemValueArrowR->SetIndex( 0 );
// if there are more than one item to choose from
//
if( m_menuItems[ m_selection ]->m_itemValueCount > 1 )
{
int numUserInputHandlers = GetGuiSystem()->GetNumUserInputHandlers();
for( int i = 0; i < numUserInputHandlers; i++ )
{
if( m_controllerID != -1 && m_controllerID != static_cast<short>( i ) )
{
// ignore other controller inputs
//
continue;
}
CGuiUserInputHandler* userInputHandler = GetGuiSystem()->GetUserInputHandler( i );
if( userInputHandler != NULL )
{
#ifdef RAD_WIN32
if( userInputHandler->IsXAxisOnLeft() ||
GetInputManager()->GetFEMouse()->LeftButtonDownOn() == HOTSPOT_ARROWLEFT )
#else
if( userInputHandler->IsButtonDown( GuiInput::Left ) ||
userInputHandler->IsXAxisOnLeft() )
#endif
{
rAssert( m_menuItems[ m_selection ]->m_itemValueArrowL->GetNumOfImages() > 1 );
m_menuItems[ m_selection ]->m_itemValueArrowL->SetIndex( 1 );
}
#ifdef RAD_WIN32
if( userInputHandler->IsXAxisOnRight() ||
GetInputManager()->GetFEMouse()->LeftButtonDownOn() == HOTSPOT_ARROWRIGHT )
#else
if( userInputHandler->IsButtonDown( GuiInput::Right ) ||
userInputHandler->IsXAxisOnRight() )
#endif
{
rAssert( m_menuItems[ m_selection ]->m_itemValueArrowR->GetNumOfImages() > 1 );
m_menuItems[ m_selection ]->m_itemValueArrowR->SetIndex( 1 );
}
}
}
}
}
// update elapsed time
//
m_elapsedTime = (m_elapsedTime + elapsedTime) % ITEM_PULSE_PERIOD;
}
}
//===========================================================================
// CGuiMenu::MoveCursor
//===========================================================================
// Description: Move cursor from previous selection to next selection.
//
// Constraints: None.
//
// Parameters:
//
// Return:
//
//===========================================================================
void CGuiMenu::MoveCursor( int previousIndex, int nextIndex )
{
// if cursor exists
//
if( m_pCursor != NULL && previousIndex != NO_SELECTION )
{
Scrooby::BoundedDrawable* item = NULL;
int x1, y1, x2, y2;
// get location of previous item
item = m_menuItems[ previousIndex ]->GetItem();
rAssert( item != NULL );
item->GetOriginPosition( x1, y1 );
// get location of next item
item = m_menuItems[ nextIndex ]->GetItem();
rAssert( item != NULL );
item->GetOriginPosition( x2, y2 );
// translate cursor
m_pCursor->Translate( x2 - x1, y2 - y1 );
}
}
//===========================================================================
// Public Member Functions - CGuiMenu2D
//===========================================================================
CGuiMenu2D::CGuiMenu2D( CGuiEntity* pParent,
int numItems,
int numColumns,
eMenuType menuType,
int specialEffects )
: CGuiMenu( pParent, numItems, menuType, specialEffects ),
m_numColumns( static_cast<short>( numColumns ) )
{
}
CGuiMenu2D::~CGuiMenu2D()
{
}
void
CGuiMenu2D::HandleMessage( eGuiMessage message, unsigned int param1,
unsigned int param2 )
{
if( m_isSelectionMade && this->IsControllerMessage( message ) )
{
// selection has already been made, ignore all controller messages
//
return;
}
switch( message )
{
case GUI_MSG_CONTROLLER_LEFT:
{
this->ChangeSelection( -1 );
break;
}
case GUI_MSG_CONTROLLER_RIGHT:
{
this->ChangeSelection( +1 );
break;
}
case GUI_MSG_CONTROLLER_UP:
{
this->ChangeSelection( -m_numColumns );
break;
}
case GUI_MSG_CONTROLLER_DOWN:
{
this->ChangeSelection( +m_numColumns );
break;
}
default:
{
CGuiMenu::HandleMessage( message, param1, param2 );
break;
}
}
}
//===========================================================================
// Public Member Functions - CGuiMenuPrompt
//===========================================================================
CGuiMenuPrompt::CGuiMenuPrompt( CGuiEntity* pParent,
Scrooby::Page* pPage,
int numResponses,
int specialEffects )
:
CGuiMenu( pParent, numResponses, GUI_TEXT_MENU, specialEffects ),
m_numResponses( static_cast<short>( numResponses ) )
{
rAssert( pPage != NULL );
Scrooby::Group* menu = pPage->GetGroup( "Menu" );
rAssert( menu != NULL );
// add response menu items
//
for( short i = 0; i < m_numResponses; i++ )
{
char textName[ 32 ];
sprintf( textName, "Response%d", i );
this->AddMenuItem( menu->GetText( textName ) );
}
}
CGuiMenuPrompt::~CGuiMenuPrompt()
{
}
void
CGuiMenuPrompt::SetNumResponses( int numResponses )
{
for( short i = 0; i < m_numResponses; i++ )
{
this->SetMenuItemEnabled( i, (i < numResponses), true );
}
}
void
CGuiMenuPrompt::SetResponse( int index, ePromptResponse response )
{
rAssert( static_cast<short>( index ) >= 0 && static_cast<short>( index ) < m_numResponses );
GuiMenuItem* menuItem = this->GetMenuItem( index );
rAssert( menuItem != NULL );
Scrooby::Text* textItem = dynamic_cast<Scrooby::Text*>( menuItem->GetItem() );
rAssert( textItem != NULL );
textItem->SetIndex( response );
}
CGuiMenuPrompt::ePromptResponse
CGuiMenuPrompt::GetResponse( int index ) const
{
rAssert( static_cast<short>( index ) >= 0 && static_cast<short>( index ) < m_numResponses );
GuiMenuItem* menuItem = this->GetMenuItem( index );
rAssert( menuItem != NULL );
Scrooby::Text* textItem = dynamic_cast<Scrooby::Text*>( menuItem->GetItem() );
rAssert( textItem != NULL );
return static_cast<ePromptResponse>( textItem->GetIndex() );
}
CGuiMenuPrompt::ePromptResponse
CGuiMenuPrompt::GetCurrentResponse() const
{
return this->GetResponse( m_selection );
}