749 lines
19 KiB
C++
749 lines
19 KiB
C++
#include "global.h"
|
|
#include "OptionsList.h"
|
|
#include "GameState.h"
|
|
#include "RageLog.h"
|
|
#include "Course.h"
|
|
#include "SongUtil.h"
|
|
#include "StepsUtil.h"
|
|
#include "Style.h"
|
|
#include "InputEventPlus.h"
|
|
#include "CodeDetector.h"
|
|
#include "InputMapper.h"
|
|
#include "PlayerState.h"
|
|
|
|
#define LINE(sLineName) THEME->GetMetric (m_sName,ssprintf("Line%s",sLineName.c_str()))
|
|
#define MAX_ITEMS_BEFORE_SPLIT THEME->GetMetricI(m_sName,"MaxItemsBeforeSplit")
|
|
#define ITEMS_SPLIT_WIDTH THEME->GetMetricF(m_sName,"ItemsSplitWidth")
|
|
#define DIRECT_LINES THEME->GetMetric (m_sName,"DirectLines")
|
|
#define TOP_MENUS THEME->GetMetric (m_sName,"TopMenus")
|
|
|
|
static const RString RESET_ROW = "ResetOptions";
|
|
|
|
void OptionListRow::Load( OptionsList *pOptions, const RString &sType )
|
|
{
|
|
m_pOptions = pOptions;
|
|
ITEMS_SPACING_Y .Load(sType,"ItemsSpacingY");
|
|
|
|
m_Text.resize( 1 );
|
|
m_Text[0].SetName( "Text" );
|
|
m_Text[0].LoadFromFont( THEME->GetPathF(sType, "normal") );
|
|
ActorUtil::LoadAllCommands( m_Text[0], sType );
|
|
|
|
m_Underlines.resize( 1 );
|
|
m_Underlines[0].Load( THEME->GetPathG(sType, "underline") );
|
|
m_Underlines[0]->SetName( "Underline" );
|
|
ActorUtil::LoadAllCommands( *m_Underlines[0], sType );
|
|
|
|
m_Text[0].PlayCommand( "On" );
|
|
m_Underlines[0]->PlayCommand( "On" );
|
|
}
|
|
|
|
// GetTitleForHandler
|
|
// can always use the title
|
|
// can have special speed row titles, note skin, or any SELECT_ONE
|
|
|
|
void OptionListRow::SetFromHandler( const OptionRowHandler *pHandler )
|
|
{
|
|
this->FinishTweening();
|
|
this->RemoveAllChildren();
|
|
|
|
if( pHandler == NULL )
|
|
return;
|
|
|
|
int iNum = max( pHandler->m_Def.m_vsChoices.size(), m_Text.size() )+1;
|
|
m_Text.resize( iNum, m_Text[0] );
|
|
m_Underlines.resize( iNum, m_Underlines[0] );
|
|
|
|
for( unsigned i = 0; i < pHandler->m_Def.m_vsChoices.size(); ++i )
|
|
{
|
|
// init underlines
|
|
this->AddChild( m_Underlines[i] );
|
|
|
|
// init text
|
|
this->AddChild( &m_Text[i] );
|
|
}
|
|
|
|
SetTextFromHandler( pHandler );
|
|
|
|
const unsigned iCnt = pHandler->m_Def.m_vsChoices.size();
|
|
m_bItemsInTwoRows = (int) iCnt > MAX_ITEMS_BEFORE_SPLIT;
|
|
const float fWidth = ITEMS_SPLIT_WIDTH;
|
|
float fY = 0;
|
|
for( unsigned i = 0; i < iCnt; ++i )
|
|
{
|
|
float fX = 0;
|
|
if( m_bItemsInTwoRows )
|
|
{
|
|
if( (i % 2) == 0 )
|
|
fX = -fWidth/2;
|
|
else
|
|
fX = +fWidth/2;
|
|
}
|
|
|
|
// set the Y position of each item in the line
|
|
m_Text[i].SetXY( fX, fY );
|
|
m_Underlines[i]->SetXY( fX, fY );
|
|
|
|
if( m_bItemsInTwoRows )
|
|
m_Underlines[i]->PlayCommand( "SetTwoRows" );
|
|
else
|
|
m_Underlines[i]->PlayCommand( "SetOneRow" );
|
|
|
|
if( !m_bItemsInTwoRows || (i % 2) == 1 || i+1 == iCnt )
|
|
fY += ITEMS_SPACING_Y;
|
|
}
|
|
|
|
int iExit = pHandler->m_Def.m_vsChoices.size();
|
|
m_Text[iExit].SetText( "Exit" ); // XXX localize
|
|
m_Text[iExit].SetXY( 0, fY );
|
|
this->AddChild( &m_Text[iExit] );
|
|
}
|
|
|
|
void OptionListRow::SetTextFromHandler( const OptionRowHandler *pHandler )
|
|
{
|
|
ASSERT( pHandler );
|
|
for( unsigned i = 0; i < pHandler->m_Def.m_vsChoices.size(); ++i )
|
|
{
|
|
// init text
|
|
RString sText = pHandler->GetThemedItemText( i );
|
|
|
|
RString sDest = pHandler->GetScreen( i );
|
|
if( m_pOptions->m_setDirectRows.find(sDest) != m_pOptions->m_setDirectRows.end() && sDest.size() )
|
|
{
|
|
const OptionRowHandler *pTarget = m_pOptions->m_Rows[sDest];
|
|
if( pTarget->m_Def.m_selectType == SELECT_ONE )
|
|
{
|
|
int iSelection = m_pOptions->GetOneSelection(sDest);
|
|
sText += ": " + pTarget->GetThemedItemText( iSelection );
|
|
}
|
|
}
|
|
|
|
m_Text[i].SetText( sText );
|
|
}
|
|
}
|
|
|
|
void OptionListRow::SetUnderlines( const vector<bool> &aSelections, const OptionRowHandler *pHandler )
|
|
{
|
|
for( unsigned i = 0; i < aSelections.size(); ++i )
|
|
{
|
|
Actor *pActor = m_Underlines[i];
|
|
|
|
bool bSelected = aSelections[i];
|
|
RString sDest = pHandler->GetScreen( i );
|
|
if( sDest.size() )
|
|
{
|
|
/* This is a submenu. Underline the row if its options have been changed
|
|
* from the default. */
|
|
const OptionRowHandler *pTarget = m_pOptions->m_Rows[sDest];
|
|
if( pTarget->m_Def.m_selectType == SELECT_ONE )
|
|
{
|
|
int iSelection = m_pOptions->GetOneSelection(sDest);
|
|
const OptionRowHandler *lHandler = m_pOptions->m_Rows.find(sDest)->second;
|
|
int iDefault = lHandler->GetDefaultOption();
|
|
if( iDefault != -1 && iSelection != iDefault )
|
|
bSelected |= true;
|
|
}
|
|
else if( pTarget->m_Def.m_selectType == SELECT_MULTIPLE )
|
|
{
|
|
const vector<bool> &bTargetSelections = m_pOptions->m_bSelections.find(sDest)->second;
|
|
for( unsigned j=0; j<bTargetSelections.size(); j++ )
|
|
{
|
|
if( bTargetSelections[j] )
|
|
bSelected = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
pActor->PlayCommand( bSelected?"Show":"Hide" );
|
|
}
|
|
}
|
|
|
|
void OptionListRow::PositionCursor( Actor *pCursor, int iSelection )
|
|
{
|
|
float fX = m_Text[iSelection].GetDestX();
|
|
float fY = m_Text[iSelection].GetDestY();
|
|
if( m_bItemsInTwoRows )
|
|
pCursor->PlayCommand( "PositionTwoRows" );
|
|
else
|
|
pCursor->PlayCommand( "PositionOneRow" );
|
|
pCursor->SetXY( fX, fY );
|
|
}
|
|
|
|
OptionsList::OptionsList()
|
|
{
|
|
m_iCurrentRow = 0;
|
|
m_pLinked = NULL;
|
|
}
|
|
|
|
OptionsList::~OptionsList()
|
|
{
|
|
FOREACHM( RString, OptionRowHandler *, m_Rows, hand )
|
|
delete hand->second;
|
|
}
|
|
|
|
void OptionsList::Load( RString sType, PlayerNumber pn )
|
|
{
|
|
TOP_MENU.Load( sType, "TopMenu" );
|
|
|
|
m_pn = pn;
|
|
m_bStartIsDown = false;
|
|
|
|
m_Codes.Load( sType );
|
|
|
|
m_Cursor.Load( THEME->GetPathG(sType, "cursor") );
|
|
m_Cursor->SetName( "Cursor" );
|
|
ActorUtil::LoadAllCommands( *m_Cursor, sType );
|
|
this->AddChild( m_Cursor );
|
|
|
|
vector<RString> asDirectLines;
|
|
split( DIRECT_LINES, ",", asDirectLines, true );
|
|
FOREACH( RString, asDirectLines, s )
|
|
m_setDirectRows.insert( *s );
|
|
|
|
vector<RString> setToLoad;
|
|
split( TOP_MENUS, ",", setToLoad );
|
|
m_setTopMenus.insert( setToLoad.begin(), setToLoad.end() );
|
|
|
|
while( !setToLoad.empty() )
|
|
{
|
|
RString sLineName = *setToLoad.begin();
|
|
setToLoad.erase( setToLoad.begin() );
|
|
|
|
if( m_Rows.find(sLineName) != m_Rows.end() )
|
|
continue;
|
|
|
|
RString sRowCommands = LINE(sLineName);
|
|
Commands cmds;
|
|
ParseCommands( sRowCommands, cmds );
|
|
|
|
OptionRowHandler *pHand = OptionRowHandlerUtil::Make( cmds );
|
|
if( pHand == NULL )
|
|
RageException::Throw( "Invalid OptionRowHandler '%s' in %s::Line%s", cmds.GetOriginalCommandString().c_str(), m_sName.c_str(), sLineName.c_str() );
|
|
|
|
m_Rows[sLineName] = pHand;
|
|
m_asLoadedRows.push_back( sLineName );
|
|
|
|
for( size_t i = 0; i < pHand->m_Def.m_vsChoices.size(); ++i )
|
|
{
|
|
RString sScreen = pHand->GetScreen(i);
|
|
if( !sScreen.empty() )
|
|
setToLoad.push_back( sScreen );
|
|
}
|
|
}
|
|
|
|
for( int i = 0; i < 2; ++i )
|
|
{
|
|
m_Row[i].SetName( "OptionsList" );
|
|
m_Row[i].Load( this, "OptionsList" );
|
|
ActorUtil::LoadAllCommands( m_Row[i], sType );
|
|
this->AddChild( &m_Row[i] );
|
|
}
|
|
|
|
this->PlayCommand( "TweenOff" );
|
|
this->FinishTweening();
|
|
}
|
|
|
|
void OptionsList::Reset()
|
|
{
|
|
/* Import options. */
|
|
FOREACHM( RString, OptionRowHandler *, m_Rows, hand )
|
|
{
|
|
RString sLineName = hand->first;
|
|
ImportRow( sLineName );
|
|
}
|
|
}
|
|
|
|
void OptionsList::Open()
|
|
{
|
|
this->PlayCommand( "Reset" );
|
|
|
|
Message msg("OptionsListOpened");
|
|
msg.SetParam( "Player", m_pn );
|
|
MESSAGEMAN->Broadcast( msg );
|
|
|
|
/* Push the initial menu. */
|
|
ASSERT( m_asMenuStack.size() == 0 );
|
|
Push( TOP_MENU );
|
|
|
|
this->FinishTweening();
|
|
m_Row[!m_iCurrentRow].SetFromHandler( NULL );
|
|
this->PlayCommand( "TweenOn" );
|
|
}
|
|
|
|
void OptionsList::Close()
|
|
{
|
|
Message msg("OptionsListClosed");
|
|
msg.SetParam( "Player", m_pn );
|
|
MESSAGEMAN->Broadcast( msg );
|
|
|
|
m_bStartIsDown = false;
|
|
m_asMenuStack.clear();
|
|
this->PlayCommand( "TweenOff" );
|
|
}
|
|
|
|
RString OptionsList::GetCurrentRow() const
|
|
{
|
|
ASSERT( !m_asMenuStack.empty() ); // called while the menu was closed
|
|
return m_asMenuStack.back();
|
|
}
|
|
|
|
const OptionRowHandler *OptionsList::GetCurrentHandler()
|
|
{
|
|
RString sCurrentRow = GetCurrentRow();
|
|
return m_Rows[sCurrentRow];
|
|
}
|
|
|
|
int OptionsList::GetOneSelection( RString sRow, bool bAllowFail ) const
|
|
{
|
|
map<RString, vector<bool> >::const_iterator it = m_bSelections.find(sRow);
|
|
ASSERT_M( it != m_bSelections.end(), sRow );
|
|
const vector<bool> &bSelections = it->second;
|
|
for( unsigned i=0; i<bSelections.size(); i++ )
|
|
{
|
|
if( bSelections[i] )
|
|
return i;
|
|
}
|
|
|
|
ASSERT( bAllowFail ); // shouldn't call this if not expecting one to be selected
|
|
return -1;
|
|
}
|
|
|
|
void OptionsList::PositionCursor()
|
|
{
|
|
m_Row[m_iCurrentRow].PositionCursor( m_Cursor, m_iMenuStackSelection );
|
|
}
|
|
|
|
/* Toggle to the next menu. This is used to switch quickly through option submenus,
|
|
* to choose many options or to find the one you're looking for. For that goal,
|
|
* it's not helpful to switch only through the options listed in the current parent
|
|
* menu; always toggle through the whole set. Skip menus that only contain other
|
|
* menus. */
|
|
void OptionsList::SwitchMenu( int iDir )
|
|
{
|
|
/* Consider the menu as a list, where the main menu is the first item and the
|
|
* submenus follow. This allows consistent navigation; moving right from the
|
|
* main menu walks through the menus, moving left goes back as far as the main
|
|
* menu. Don't loop, so it's harder to lose track of menus. */
|
|
RString sTopRow = m_asMenuStack.front();
|
|
const OptionRowHandler *pHandler = m_Rows[sTopRow];
|
|
int iCurrentRow = 0;
|
|
if( m_asMenuStack.size() == 1 )
|
|
iCurrentRow = -1;
|
|
else
|
|
iCurrentRow = FindScreenInHandler( pHandler, m_asMenuStack.back() );
|
|
|
|
iCurrentRow += iDir;
|
|
if( iCurrentRow >= 0 )
|
|
{
|
|
if( iCurrentRow >= (int) pHandler->m_Def.m_vsChoices.size() )
|
|
return;
|
|
RString sDest = pHandler->GetScreen( iCurrentRow );
|
|
if( sDest.empty() )
|
|
return;
|
|
|
|
if( m_asMenuStack.size() == 1 )
|
|
m_asMenuStack.push_back( sDest );
|
|
else
|
|
m_asMenuStack.back() = sDest;
|
|
}
|
|
else
|
|
{
|
|
if( m_asMenuStack.size() == 1 )
|
|
return;
|
|
|
|
m_asMenuStack.pop_back();
|
|
}
|
|
|
|
SetDefaultCurrentRow();
|
|
SwitchToCurrentRow();
|
|
TweenOnCurrentRow( iDir > 0 );
|
|
}
|
|
|
|
void OptionsList::MoveItem( const RString &sRowName, int iMove )
|
|
{
|
|
}
|
|
|
|
void OptionsList::Input( const InputEventPlus &input )
|
|
{
|
|
Message msg("");
|
|
if( m_Codes.InputMessage(input, msg) )
|
|
this->HandleMessage( msg );
|
|
|
|
const OptionRowHandler *pHandler = GetCurrentHandler();
|
|
|
|
PlayerNumber pn = input.pn;
|
|
if( m_bStartIsDown )
|
|
{
|
|
if( input.MenuI == GAME_BUTTON_LEFT || input.MenuI == GAME_BUTTON_RIGHT )
|
|
{
|
|
if( input.type != IET_FIRST_PRESS )
|
|
return;
|
|
|
|
m_bAcceptStartRelease = false;
|
|
|
|
const RString &sCurrentRow = m_asMenuStack.back();
|
|
vector<bool> &bSelections = m_bSelections[sCurrentRow];
|
|
if( m_iMenuStackSelection == (int)bSelections.size() )
|
|
return;
|
|
|
|
RString sDest = pHandler->GetScreen( m_iMenuStackSelection );
|
|
if( m_setDirectRows.find(sDest) != m_setDirectRows.end() && sDest.size() )
|
|
{
|
|
const OptionRowHandler *pTarget = m_Rows[sDest];
|
|
vector<bool> &bTargetSelections = m_bSelections[sDest];
|
|
|
|
if( pTarget->m_Def.m_selectType == SELECT_ONE )
|
|
{
|
|
int iSelection = GetOneSelection(sDest);
|
|
int iDir = (input.MenuI == GAME_BUTTON_RIGHT? +1:-1);
|
|
iSelection += iDir;
|
|
wrap( iSelection, bTargetSelections.size() );
|
|
SelectItem( sDest, iSelection );
|
|
|
|
Message lMsg("OptionsListQuickChange");
|
|
lMsg.SetParam( "Player", pn );
|
|
lMsg.SetParam( "Direction", iDir );
|
|
MESSAGEMAN->Broadcast( lMsg );
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
if( input.MenuI == GAME_BUTTON_LEFT )
|
|
{
|
|
if( input.type == IET_RELEASE )
|
|
return;
|
|
|
|
if( INPUTMAPPER->IsBeingPressed(GAME_BUTTON_RIGHT, pn) )
|
|
{
|
|
if( input.type == IET_FIRST_PRESS )
|
|
SwitchMenu( -1 );
|
|
return;
|
|
}
|
|
|
|
--m_iMenuStackSelection;
|
|
wrap( m_iMenuStackSelection, pHandler->m_Def.m_vsChoices.size()+1 ); // +1 for exit row
|
|
PositionCursor();
|
|
|
|
Message lMsg("OptionsListLeft");
|
|
lMsg.SetParam( "Player", input.pn );
|
|
MESSAGEMAN->Broadcast( lMsg );
|
|
return;
|
|
}
|
|
else if( input.MenuI == GAME_BUTTON_RIGHT )
|
|
{
|
|
if( input.type == IET_RELEASE )
|
|
return;
|
|
|
|
if( INPUTMAPPER->IsBeingPressed(GAME_BUTTON_LEFT, pn) )
|
|
{
|
|
if( input.type == IET_FIRST_PRESS )
|
|
SwitchMenu( +1 );
|
|
return;
|
|
}
|
|
|
|
++m_iMenuStackSelection;
|
|
wrap( m_iMenuStackSelection, pHandler->m_Def.m_vsChoices.size()+1 ); // +1 for exit row
|
|
PositionCursor();
|
|
|
|
Message lMsg("OptionsListRight");
|
|
lMsg.SetParam( "Player", input.pn );
|
|
MESSAGEMAN->Broadcast( lMsg );
|
|
return;
|
|
}
|
|
else if( input.MenuI == GAME_BUTTON_START )
|
|
{
|
|
if( input.type == IET_FIRST_PRESS )
|
|
{
|
|
m_bStartIsDown = true;
|
|
m_bAcceptStartRelease = true;
|
|
return;
|
|
}
|
|
if( input.type == IET_RELEASE )
|
|
{
|
|
if( m_bAcceptStartRelease )
|
|
Start();
|
|
m_bStartIsDown = false;
|
|
}
|
|
|
|
return;
|
|
}
|
|
else if( input.MenuI == GAME_BUTTON_SELECT )
|
|
{
|
|
if( input.type != IET_FIRST_PRESS )
|
|
return;
|
|
// if( input.type == IET_RELEASE )
|
|
{
|
|
Close();
|
|
return;
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
void OptionsList::SwitchToCurrentRow()
|
|
{
|
|
m_iCurrentRow = !m_iCurrentRow;
|
|
|
|
/* Set up the new row. */
|
|
m_Row[m_iCurrentRow].SetFromHandler( GetCurrentHandler() );
|
|
m_Row[m_iCurrentRow].SetUnderlines( m_bSelections[m_asMenuStack.back()], GetCurrentHandler() );
|
|
PositionCursor();
|
|
|
|
Message msg("OptionsMenuChanged");
|
|
msg.SetParam( "Player", m_pn );
|
|
msg.SetParam( "Menu", m_asMenuStack.back() );
|
|
MESSAGEMAN->Broadcast( msg );
|
|
}
|
|
|
|
/* After setting up a new row, tween it on. */
|
|
void OptionsList::TweenOnCurrentRow( bool bForward )
|
|
{
|
|
OptionListRow &OldRow = m_Row[!m_iCurrentRow];
|
|
OptionListRow &NewRow = m_Row[m_iCurrentRow];
|
|
|
|
/* Tween out the old row. */
|
|
if( bForward )
|
|
OldRow.PlayCommand( "TweenOutForward" );
|
|
else
|
|
OldRow.PlayCommand( "TweenOutBackward" );
|
|
|
|
/* Tween in the old row. */
|
|
if( bForward )
|
|
NewRow.PlayCommand( "TweenInForward" );
|
|
else
|
|
NewRow.PlayCommand( "TweenInBackward" );
|
|
}
|
|
|
|
void OptionsList::ImportRow( RString sRow )
|
|
{
|
|
vector<bool> aSelections[NUM_PLAYERS];
|
|
vector<PlayerNumber> vpns;
|
|
vpns.push_back( m_pn );
|
|
OptionRowHandler *pHandler = m_Rows[sRow];
|
|
aSelections[ m_pn ].resize( pHandler->m_Def.m_vsChoices.size() );
|
|
pHandler->ImportOption( NULL, vpns, aSelections );
|
|
m_bSelections[sRow] = aSelections[ m_pn ];
|
|
|
|
if( m_setTopMenus.find(sRow) != m_setTopMenus.end() )
|
|
fill( m_bSelections[sRow].begin(), m_bSelections[sRow].end(), false );
|
|
}
|
|
|
|
void OptionsList::ExportRow( RString sRow )
|
|
{
|
|
if( m_setTopMenus.find(sRow) != m_setTopMenus.end() )
|
|
return;
|
|
|
|
vector<bool> aSelections[NUM_PLAYERS];
|
|
aSelections[m_pn] = m_bSelections[sRow];
|
|
|
|
vector<PlayerNumber> vpns;
|
|
vpns.push_back( m_pn );
|
|
|
|
m_Rows[sRow]->ExportOption( vpns, aSelections );
|
|
}
|
|
|
|
void OptionsList::SetDefaultCurrentRow()
|
|
{
|
|
/* If all items on the row just point to other menus, default to 0. */
|
|
m_iMenuStackSelection = 0;
|
|
|
|
const RString &sCurrentRow = m_asMenuStack.back();
|
|
const OptionRowHandler *pHandler = m_Rows.find(sCurrentRow)->second;
|
|
if( pHandler->m_Def.m_selectType == SELECT_ONE )
|
|
{
|
|
/* One item is selected, so position the cursor on it. */
|
|
m_iMenuStackSelection = GetOneSelection( sCurrentRow, true );
|
|
if( m_iMenuStackSelection == -1 )
|
|
m_iMenuStackSelection = 0;
|
|
}
|
|
}
|
|
|
|
int OptionsList::FindScreenInHandler( const OptionRowHandler *pHandler, RString sScreen )
|
|
{
|
|
for( size_t i = 0; i < pHandler->m_Def.m_vsChoices.size(); ++i )
|
|
{
|
|
if( pHandler->GetScreen(i) == sScreen )
|
|
return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
void OptionsList::Pop()
|
|
{
|
|
if( m_asMenuStack.size() == 1 )
|
|
{
|
|
Close();
|
|
return;
|
|
}
|
|
|
|
RString sLastMenu = m_asMenuStack.back();
|
|
|
|
m_asMenuStack.pop_back();
|
|
|
|
/* Choose the default option. */
|
|
SetDefaultCurrentRow();
|
|
|
|
/* If the old menu exists as a target from the new menu, switch to it. */
|
|
const OptionRowHandler *pHandler = GetCurrentHandler();
|
|
int iIndex = FindScreenInHandler( pHandler, sLastMenu );
|
|
if( iIndex != -1 )
|
|
m_iMenuStackSelection = iIndex;
|
|
|
|
SwitchToCurrentRow();
|
|
TweenOnCurrentRow( false );
|
|
}
|
|
|
|
void OptionsList::Push( RString sDest )
|
|
{
|
|
m_asMenuStack.push_back( sDest );
|
|
SetDefaultCurrentRow();
|
|
SwitchToCurrentRow();
|
|
}
|
|
|
|
void OptionsList::SelectItem( const RString &sRowName, int iMenuItem )
|
|
{
|
|
const OptionRowHandler *pHandler = m_Rows[sRowName];
|
|
vector<bool> &bSelections = m_bSelections[sRowName];
|
|
|
|
if( pHandler->m_Def.m_selectType == SELECT_MULTIPLE )
|
|
{
|
|
bool bSelected = !bSelections[iMenuItem];
|
|
bSelections[iMenuItem] = bSelected;
|
|
|
|
// if( bSelected )
|
|
// m_SoundToggleOn.Play();
|
|
// else
|
|
// m_SoundToggleOff.Play();
|
|
}
|
|
else // data.selectType != SELECT_MULTIPLE
|
|
{
|
|
fill( bSelections.begin(), bSelections.end(), false );
|
|
bSelections[iMenuItem] = true;
|
|
}
|
|
|
|
SelectionsChanged( sRowName );
|
|
UpdateMenuFromSelections();
|
|
}
|
|
|
|
void OptionsList::SelectionsChanged( const RString &sRowName )
|
|
{
|
|
const OptionRowHandler *pHandler = m_Rows[sRowName];
|
|
vector<bool> &bSelections = m_bSelections[sRowName];
|
|
|
|
if( pHandler->m_Def.m_bOneChoiceForAllPlayers && m_pLinked != NULL )
|
|
{
|
|
vector<bool> &bLinkedSelections = m_pLinked->m_bSelections[sRowName];
|
|
bLinkedSelections = bSelections;
|
|
|
|
if( m_pLinked->IsOpened() )
|
|
m_pLinked->UpdateMenuFromSelections();
|
|
|
|
m_pLinked->ExportRow( sRowName );
|
|
}
|
|
|
|
ExportRow( sRowName );
|
|
}
|
|
|
|
void OptionsList::UpdateMenuFromSelections()
|
|
{
|
|
const vector<bool> &bCurrentSelections = m_bSelections.find(GetCurrentRow())->second;
|
|
m_Row[m_iCurrentRow].SetUnderlines( bCurrentSelections, GetCurrentHandler() );
|
|
m_Row[m_iCurrentRow].SetTextFromHandler( GetCurrentHandler() );
|
|
}
|
|
|
|
bool OptionsList::Start()
|
|
{
|
|
const OptionRowHandler *pHandler = GetCurrentHandler();
|
|
const RString &sCurrentRow = m_asMenuStack.back();
|
|
vector<bool> &bSelections = m_bSelections[sCurrentRow];
|
|
if( m_iMenuStackSelection == (int)bSelections.size() )
|
|
{
|
|
Pop();
|
|
|
|
Message msg("OptionsListPop");
|
|
msg.SetParam( "Player", m_pn );
|
|
MESSAGEMAN->Broadcast( msg );
|
|
|
|
return m_asMenuStack.empty();
|
|
}
|
|
|
|
{
|
|
RString sIconText;
|
|
GameCommand gc;
|
|
pHandler->GetIconTextAndGameCommand( m_iMenuStackSelection, sIconText, gc );
|
|
if( gc.m_sName == RESET_ROW )
|
|
{
|
|
GAMESTATE->m_pPlayerState[m_pn]->ResetToDefaultPlayerOptions( ModsLevel_Preferred );
|
|
GAMESTATE->ResetToDefaultSongOptions( ModsLevel_Preferred );
|
|
|
|
/* Import options. */
|
|
FOREACHM( RString, OptionRowHandler *, m_Rows, hand )
|
|
{
|
|
ImportRow( hand->first );
|
|
SelectionsChanged( hand->first );
|
|
}
|
|
|
|
UpdateMenuFromSelections();
|
|
|
|
Message msg("OptionsListReset");
|
|
msg.SetParam( "Player", m_pn );
|
|
MESSAGEMAN->Broadcast( msg );
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
RString sDest = pHandler->GetScreen( m_iMenuStackSelection );
|
|
if( sDest.size() )
|
|
{
|
|
Push( sDest );
|
|
TweenOnCurrentRow( true );
|
|
|
|
Message msg("OptionsListPush");
|
|
msg.SetParam( "Player", m_pn );
|
|
MESSAGEMAN->Broadcast( msg );
|
|
|
|
return false;
|
|
}
|
|
|
|
SelectItem( GetCurrentRow(), m_iMenuStackSelection );
|
|
|
|
/* Move to the exit row. */
|
|
m_iMenuStackSelection = (int)bSelections.size();
|
|
PositionCursor();
|
|
|
|
Message msg("OptionsListStart");
|
|
msg.SetParam( "Player", m_pn );
|
|
MESSAGEMAN->Broadcast( msg );
|
|
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
* Copyright (c) 2006 Glenn Maynard
|
|
* All rights reserved.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the
|
|
* "Software"), to deal in the Software without restriction, including
|
|
* without limitation the rights to use, copy, modify, merge, publish,
|
|
* distribute, and/or sell copies of the Software, and to permit persons to
|
|
* whom the Software is furnished to do so, provided that the above
|
|
* copyright notice(s) and this permission notice appear in all copies of
|
|
* the Software and that both the above copyright notice(s) and this
|
|
* permission notice appear in supporting documentation.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
|
|
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
|
|
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
|
|
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
|
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
* PERFORMANCE OF THIS SOFTWARE.
|
|
*/
|
|
|