Adds Dual List Mode to ScreenSelectMaster. This allows for themers to maintain two separate lists depending on number of players joined. Overcomes some problems such as wanting the list to only contain selectable items if using a scroller. Untested with icon cursor and needs optimising still.

This commit is contained in:
Andrew Livy
2009-05-02 15:30:04 +00:00
parent a84e00a39f
commit 2e8dc57f3d
5 changed files with 601 additions and 98 deletions
+28 -1
View File
@@ -120,6 +120,12 @@ IdleTimeoutSeconds=30
IdleTimeoutScreen=THEME:GetMetric("Common","FirstAttractScreen")
OutDelay=.2
DoublePressToSelect=false
UseTwoLists=false
OptionOrderBUp=""
OptionOrderBDown=""
OptionOrderBLeft=""
OptionOrderBRight=""
OptionOrderBAuto=""
[ScreenExit]
Class="ScreenExit"
@@ -130,6 +136,13 @@ AllowOperatorMenuButton=false
Class="ScreenTitleMenu"
Fallback="ScreenTitleMenu"
ChoiceNames="1"
ChoiceNamesB=""
OptionOrderBUp=""
OptionOrderBDown=""
OptionOrderBLeft=""
OptionOrderBRight=""
OptionOrderBAuto=""
[ScreenCaution]
Fallback="ScreenSplash"
@@ -209,6 +222,13 @@ ExplanationPage2Y=0
HeaderOnCommand=
HeaderOffCommand=
DoublePressToSelect=false
UseTwoLists=false
ChoiceNamesB=""
OptionOrderBUp=""
OptionOrderBDown=""
OptionOrderBLeft=""
OptionOrderBRight=""
OptionOrderBAuto=""
[ScreenSelectPlayMode]
Fallback="ScreenWithMenuElements"
@@ -266,6 +286,12 @@ ExplanationPage2Y=0
HeaderOnCommand=
HeaderOffCommand=
DoublePressToSelect=false
OptionOrderBUp=
OptionOrderBDown=
OptionOrderBLeft=
OptionOrderBRight=
OptionOrderBAuto=
UseTwoLists=
[ScreenSelectMode]
Fallback="ScreenSelect"
@@ -2656,6 +2682,7 @@ DisabledColor=#606060
DoublePressToSelect=false
# Blank defaults for a few options.
IconChoice1SwitchToPage1Command=
IconChoice1SwitchToPage2Command=
@@ -2946,7 +2973,7 @@ Unlock0020X=SCREEN_CENTER_X-70
Unlock0020Y=SCREEN_CENTER_Y+85
DancePointsZoom=2
[ScreenHighScores]
[ScreenHighScores]http://clickingandscreaming.com/2009/05/01/youtube-and-bullying-cause-or-solution/
Fallback="ScreenAttract"
Class="ScreenHighScores"
TimerSeconds=-1
+117 -13
View File
@@ -13,6 +13,10 @@
#define CHOICE( s ) THEME->GetMetric (m_sName,ssprintf("Choice%s",s.c_str()))
#define IDLE_TIMEOUT_SCREEN THEME->GetMetric (m_sName,"IdleTimeoutScreen")
#define UPDATE_ON_MESSAGE THEME->GetMetric (m_sName,"UpdateOnMessage")
#define USE_TWO_LISTS THEME->GetMetricB (m_sName,"UseTwoLists")
#define CHOICE_NAMESB THEME->GetMetric (m_sName,"ChoiceNamesB")
#define CHOICEB( s ) THEME->GetMetric (m_sName,ssprintf("ChoiceB%s",s.c_str()))
void ScreenSelect::Init()
{
@@ -54,16 +58,55 @@ void ScreenSelect::Init()
mc.Load( c, cmd );
m_aGameCommands.push_back( mc );
}
m_iSelectedList = 0;
if(USE_TWO_LISTS)
{
m_bUsingTwoLists = true;
vector<RString> asChoiceNames2;
split( CHOICE_NAMESB, ",", asChoiceNames2, true );
for( unsigned c=0; c<asChoiceNames2.size(); c++ )
{
RString sChoiceName = asChoiceNames2[c];
GameCommand mc;
mc.ApplyCommitsScreens( false );
mc.m_sName = sChoiceName;
Commands cmd = ParseCommands( CHOICEB(sChoiceName) );
mc.Load( c, cmd );
m_aGameCommandsB.push_back( mc );
}
}
else
{
m_bUsingTwoLists = false;
}
}
if( !m_aGameCommands.size() )
RageException::Throw( "Screen \"%s\" does not set any choices.", m_sName.c_str() );
if(USE_TWO_LISTS)
{
if(!m_aGameCommandsB.size() )
RageException::Throw ("Screen \"%s\" has specified two lists, but does not set any choices for the second list.",m_sName.c_str() );
}
}
void ScreenSelect::BeginScreen()
{
ScreenWithMenuElements::BeginScreen();
if(USE_TWO_LISTS)
{
if( GAMESTATE->GetNumSidesJoined() > 1 )
{
m_iSelectedList = 1;
this->UpdateSelectableChoices();
}
}
m_timerIdleComment.GetDeltaTime();
m_timerIdleTimeout.GetDeltaTime();
}
@@ -111,11 +154,20 @@ void ScreenSelect::Input( const InputEventPlus &input )
if( input.MenuI == GAME_BUTTON_START && input.type == IET_FIRST_PRESS && GAMESTATE->JoinInput(input.pn) )
{
// HACK: Only play start sound for the 2nd player who joins. The
// start sound for the 1st player will be played by ScreenTitleMenu
// when the player makes a selection on the screen.
if( GAMESTATE->GetNumSidesJoined() > 1 )
{
if(USE_TWO_LISTS)
{
m_iSelectedList = 1;
this->UpdateSelectableChoices();
}
// HACK: Only play start sound for the 2nd player who joins. The
// start sound for the 1st player will be played by ScreenTitleMenu
// when the player makes a selection on the screen.
SCREENMAN->PlayStartSound();
}
if( !ALLOW_DISABLED_PLAYER_INPUT )
return; // don't let the screen handle the MENU_START press
@@ -162,20 +214,72 @@ void ScreenSelect::HandleScreenMessage( const ScreenMessage SM )
if( bAllPlayersChoseTheSame )
{
const GameCommand &gc = m_aGameCommands[iMastersIndex];
m_sNextScreen = gc.m_sScreen;
if( !gc.m_bInvalid )
gc.ApplyToAllPlayers();
if(USE_TWO_LISTS) // using two lists
{
if(m_iSelectedList == 0) // first list is selected
{
const GameCommand &gc = m_aGameCommands[iMastersIndex];
m_sNextScreen = gc.m_sScreen;
if( !gc.m_bInvalid )
gc.ApplyToAllPlayers();
}
else // second list is selected
{
const GameCommand &gc = m_aGameCommandsB[iMastersIndex];
m_sNextScreen = gc.m_sScreen;
if( !gc.m_bInvalid )
gc.ApplyToAllPlayers();
}
}
else // not using two lists
{
const GameCommand &gc = m_aGameCommands[iMastersIndex];
m_sNextScreen = gc.m_sScreen;
if( !gc.m_bInvalid )
gc.ApplyToAllPlayers();
}
}
else
{
FOREACH_HumanPlayer( p )
if(USE_TWO_LISTS) // using two lists
{
int iIndex = this->GetSelectionIndex(p);
const GameCommand &gc = m_aGameCommands[iIndex];
m_sNextScreen = gc.m_sScreen;
if( !gc.m_bInvalid )
gc.Apply( p );
if(m_iSelectedList == 0) // first list is selected
{
FOREACH_HumanPlayer( p )
{
int iIndex = this->GetSelectionIndex(p);
const GameCommand &gc = m_aGameCommands[iIndex];
m_sNextScreen = gc.m_sScreen;
if( !gc.m_bInvalid )
gc.Apply( p );
}
}
else
{
FOREACH_HumanPlayer( p )
{
int iIndex = this->GetSelectionIndex(p);
const GameCommand &gc = m_aGameCommandsB[iIndex];
m_sNextScreen = gc.m_sScreen;
if( !gc.m_bInvalid )
gc.Apply( p );
}
}
}
else // only using a single list
{
FOREACH_HumanPlayer( p )
{
int iIndex = this->GetSelectionIndex(p);
const GameCommand &gc = m_aGameCommands[iIndex];
m_sNextScreen = gc.m_sScreen;
if( !gc.m_bInvalid )
gc.Apply( p );
}
}
}
+4
View File
@@ -25,7 +25,11 @@ protected:
virtual int GetSelectionIndex( PlayerNumber pn ) = 0;
virtual void UpdateSelectableChoices() = 0; // derived screens must handle this
unsigned int m_iSelectedList;
bool m_bUsingTwoLists;
vector<GameCommand> m_aGameCommands; // derived classes should look here for what choices are available
vector<GameCommand> m_aGameCommandsB; // only used if the theme requires a second list
vector<RString> m_asSubscribedMessages;
+439 -84
View File
@@ -29,6 +29,9 @@ static RString CURSOR_OFFSET_Y_FROM_ICON_NAME( size_t p ) { return ssprintf("Cur
/* e.g. "OptionOrderLeft=0:1,1:2,2:3,3:4" */
static RString OPTION_ORDER_NAME( size_t dir ) { return "OptionOrder"+MenuDirToString((MenuDir)dir); }
static RString OPTION_ORDER_NAME_LIST2( size_t dir ) { return "OptionOrderB"+MenuDirToString((MenuDir)dir); }
REGISTER_SCREEN_CLASS( ScreenSelectMaster );
#define GetActiveElementPlayerNumbers( vpns ) \
@@ -60,6 +63,10 @@ void ScreenSelectMaster::Init()
PRE_SWITCH_PAGE_SECONDS.Load( m_sName, "PreSwitchPageSeconds" );
POST_SWITCH_PAGE_SECONDS.Load( m_sName, "PostSwitchPageSeconds" );
OPTION_ORDER.Load( m_sName, OPTION_ORDER_NAME, NUM_MenuDir );
OPTION_ORDER2.Load( m_sName, OPTION_ORDER_NAME_LIST2, NUM_MenuDir );
WRAP_CURSOR.Load( m_sName, "WrapCursor" );
WRAP_SCROLLER.Load( m_sName, "WrapScroller" );
LOOP_SCROLLER.Load( m_sName, "LoopScroller" );
@@ -102,7 +109,6 @@ void ScreenSelectMaster::Init()
FOREACH( PlayerNumber, vpns, p )
m_vsprScroll[*p].resize( m_aGameCommands.size() );
for( unsigned c=0; c<m_aGameCommands.size(); c++ )
{
GameCommand& mc = m_aGameCommands[c];
@@ -148,6 +154,125 @@ void ScreenSelectMaster::Init()
}
}
// using two lists, load the stuff for the 2nd one
if(m_bUsingTwoLists)
{
// Resize vectors depending on how many choices there are
m_vsprIconB.resize( m_aGameCommandsB.size() );
FOREACH( PlayerNumber, vpns, p )
m_vsprScrollB[*p].resize( m_aGameCommandsB.size() );
for( unsigned c=0; c<m_aGameCommandsB.size(); c++ )
{
GameCommand& mc = m_aGameCommandsB[c];
LuaThreadVariable var( "GameCommand", LuaReference::Create(&mc) );
// init icon
if( SHOW_ICON )
{
vector<RString> vs;
vs.push_back( "List2 Icon" );
if( PER_CHOICE_ICON_ELEMENT )
vs.push_back( "List2 Choice" + mc.m_sName );
RString sElement = join( " ", vs );
m_vsprIconB[c].Load( THEME->GetPathG(m_sName,sElement) );
RString sName = "List2 Icon" "List2 Choice" + mc.m_sName;
m_vsprIconB[c]->SetName( sName );
if( USE_ICON_METRICS )
LOAD_ALL_COMMANDS_AND_SET_XY( m_vsprIconB[c] );
this->AddChild( m_vsprIconB[c] );
}
// init scroll
if( SHOW_SCROLLER )
{
FOREACH( PlayerNumber, vpns, p )
{
vector<RString> vs;
vs.push_back( "List2 Scroll" );
if( PER_CHOICE_SCROLL_ELEMENT )
vs.push_back( "List2 Choice" + mc.m_sName );
if( !SHARED_SELECTION )
vs.push_back( PLAYER_APPEND_NO_SPACE(*p) );
RString sElement = join( " ", vs );
m_vsprScrollB[*p][c].Load( THEME->GetPathG(m_sName,sElement) );
RString sName = "List2 Scroll" "List2 Choice" + mc.m_sName;
if( !SHARED_SELECTION )
sName += PLAYER_APPEND_NO_SPACE(*p);
m_vsprScrollB[*p][c]->SetName( sName );
m_ScrollerB[*p].AddChild( m_vsprScrollB[*p][c] );
}
}
}
// init scroll
if( SHOW_SCROLLER )
{
FOREACH( PlayerNumber, vpns, p )
{
m_ScrollerB[*p].SetLoop( LOOP_SCROLLER );
m_ScrollerB[*p].SetNumItemsToDraw( SCROLLER_NUM_ITEMS_TO_DRAW );
m_ScrollerB[*p].Load2();
m_ScrollerB[*p].SetTransformFromReference( SCROLLER_TRANSFORM );
m_ScrollerB[*p].SetSecondsPerItem( SCROLLER_SECONDS_PER_ITEM );
m_ScrollerB[*p].SetNumSubdivisions( SCROLLER_SUBDIVISIONS );
m_ScrollerB[*p].SetName( "Scroller"+PLAYER_APPEND_NO_SPACE(*p) );
LOAD_ALL_COMMANDS_AND_SET_XY( m_ScrollerB[*p] );
this->AddChild( &m_ScrollerB[*p] );
}
}
FOREACH_MenuDir( dir )
{
const RString order = OPTION_ORDER2.GetValue( dir );
vector<RString> parts;
split( order, ",", parts, true );
for( unsigned part = 0; part < parts.size(); ++part )
{
int from, to;
if( sscanf( parts[part], "%d:%d", &from, &to ) != 2 )
{
LOG->Warn( "%s::OptionOrderB%s parse error", m_sName.c_str(), MenuDirToString(dir).c_str() );
continue;
}
--from;
--to;
m_mapCurrentChoiceToNextChoiceB[dir][from] = to;
}
if( m_mapCurrentChoiceToNextChoiceB[dir].empty() ) // Didn't specify any mappings
{
// Fill with reasonable defaults
for( unsigned c = 0; c < m_aGameCommandsB.size(); ++c )
{
int add;
switch( dir )
{
case MenuDir_Up:
case MenuDir_Left:
add = -1;
break;
default:
add = +1;
break;
}
m_mapCurrentChoiceToNextChoiceB[dir][c] = c + add;
/* Always wrap around MenuDir_Auto. */
if( dir == MenuDir_Auto || (bool)WRAP_CURSOR )
wrap( m_mapCurrentChoiceToNextChoiceB[dir][c], m_aGameCommandsB.size() );
else
m_mapCurrentChoiceToNextChoiceB[dir][c] = clamp( m_mapCurrentChoiceToNextChoiceB[dir][c], 0, (int)m_aGameCommandsB.size()-1 );
}
}
}
} // end of list2 init
// init scroll
if( SHOW_SCROLLER )
{
@@ -331,8 +456,8 @@ void ScreenSelectMaster::HandleScreenMessage( const ScreenMessage SM )
MenuStart( iep );
}
}
}
}
int ScreenSelectMaster::GetSelectionIndex( PlayerNumber pn )
@@ -345,15 +470,62 @@ void ScreenSelectMaster::UpdateSelectableChoices()
vector<PlayerNumber> vpns;
GetActiveElementPlayerNumbers( vpns );
for( unsigned c=0; c<m_aGameCommands.size(); c++ )
if(m_bUsingTwoLists && m_iSelectedList == 1) // using two lists and on the 2nd list
{
if( SHOW_ICON )
m_vsprIcon[c]->PlayCommand( m_aGameCommands[c].IsPlayable()? "Enabled":"Disabled" );
FOREACH( PlayerNumber, vpns, p )
if( m_vsprScroll[*p][c].IsLoaded() )
m_vsprScroll[*p][c]->PlayCommand( m_aGameCommands[c].IsPlayable()? "Enabled":"Disabled" );
for( unsigned c=0; c<m_aGameCommands.size(); c++ )
{
if( SHOW_ICON )
{
m_vsprIcon[c]->PlayCommand( "List2Enabled" );
}
FOREACH( PlayerNumber, vpns, p )
if( m_vsprScroll[*p][c].IsLoaded() )
{
m_vsprScroll[*p][c]->PlayCommand( "List2Enabled" );
}
}
for( unsigned c=0; c<m_aGameCommandsB.size(); c++ )
{
if( SHOW_ICON )
{
m_vsprIconB[c]->PlayCommand( "List2Enabled" );
m_vsprIconB[c]->PlayCommand( m_aGameCommandsB[c].IsPlayable()? "Enabled":"Disabled" );
// we will make element 0 the new selection, so it will gain focus
if(c==0)
m_vsprIconB[c]->PlayCommand( "GainFocus" );
else // everything else loses focus
m_vsprIconB[c]->PlayCommand( "LoseFocus" );
}
FOREACH( PlayerNumber, vpns, p )
if( m_vsprScrollB[*p][c].IsLoaded() )
{
m_vsprScrollB[*p][c]->PlayCommand( "List2Enabled" );
m_vsprScrollB[*p][c]->PlayCommand( m_aGameCommandsB[c].IsPlayable()? "Enabled":"Disabled" );
if(c==0)
m_vsprScrollB[*p][c]->PlayCommand( "GainFocus" );
else // everything else loses focus
m_vsprScrollB[*p][c]->PlayCommand( "LoseFocus" );
}
}
}
else
{
for( unsigned c=0; c<m_aGameCommands.size(); c++ )
{
if( SHOW_ICON )
m_vsprIcon[c]->PlayCommand( m_aGameCommands[c].IsPlayable()? "Enabled":"Disabled" );
FOREACH( PlayerNumber, vpns, p )
if( m_vsprScroll[*p][c].IsLoaded() )
m_vsprScroll[*p][c]->PlayCommand( m_aGameCommands[c].IsPlayable()? "Enabled":"Disabled" );
}
}
/*
@@ -363,15 +535,36 @@ void ScreenSelectMaster::UpdateSelectableChoices()
* If any options are playable, make sure one is selected.
*/
FOREACH_HumanPlayer( p )
if( !m_aGameCommands[m_iChoice[p]].IsPlayable() )
Move( p, MenuDir_Auto );
{
if(m_bUsingTwoLists && m_iSelectedList == 1)
{
m_iChoice[p] = 0; // reset their choice position since we are moving to the new list
if( !m_aGameCommandsB[m_iChoice[p]].IsPlayable() )
Move( p, MenuDir_Auto );
}
else
{
if( !m_aGameCommands[m_iChoice[p]].IsPlayable() )
Move( p, MenuDir_Auto );
}
}
}
bool ScreenSelectMaster::AnyOptionsArePlayable() const
{
for( unsigned i = 0; i < m_aGameCommands.size(); ++i )
if( m_aGameCommands[i].IsPlayable() )
return true;
// if they're using the second list
if(m_bUsingTwoLists && m_iSelectedList == 1)
{
for( unsigned i = 0; i < m_aGameCommandsB.size(); ++i )
if( m_aGameCommandsB[i].IsPlayable() )
return true;
}
else
{
for( unsigned i = 0; i < m_aGameCommands.size(); ++i )
if( m_aGameCommands[i].IsPlayable() )
return true;
}
return false;
}
@@ -384,18 +577,38 @@ bool ScreenSelectMaster::Move( PlayerNumber pn, MenuDir dir )
int iSwitchToIndex = m_iChoice[pn];
set<int> seen;
try_again:
map<int,int>::const_iterator iter = m_mapCurrentChoiceToNextChoice[dir].find( iSwitchToIndex );
if( iter != m_mapCurrentChoiceToNextChoice[dir].end() )
iSwitchToIndex = iter->second;
if( iSwitchToIndex < 0 || iSwitchToIndex >= (int) m_aGameCommands.size() ) // out of choice range
return false; // can't go that way
if( seen.find(iSwitchToIndex) != seen.end() )
return false; // went full circle and none found
seen.insert( iSwitchToIndex );
// moving list 2
if(m_bUsingTwoLists && m_iSelectedList == 1)
{
map<int,int>::const_iterator iter = m_mapCurrentChoiceToNextChoiceB[dir].find( iSwitchToIndex );
if( iter != m_mapCurrentChoiceToNextChoiceB[dir].end() )
iSwitchToIndex = iter->second;
if( !m_aGameCommands[iSwitchToIndex].IsPlayable() )
goto try_again;
if( iSwitchToIndex < 0 || iSwitchToIndex >= (int) m_aGameCommandsB.size() ) // out of choice range
return false; // can't go that way
if( seen.find(iSwitchToIndex) != seen.end() )
return false; // went full circle and none found
seen.insert( iSwitchToIndex );
if( !m_aGameCommandsB[iSwitchToIndex].IsPlayable() )
goto try_again;
}
else
{
map<int,int>::const_iterator iter = m_mapCurrentChoiceToNextChoice[dir].find( iSwitchToIndex );
if( iter != m_mapCurrentChoiceToNextChoice[dir].end() )
iSwitchToIndex = iter->second;
if( iSwitchToIndex < 0 || iSwitchToIndex >= (int) m_aGameCommands.size() ) // out of choice range
return false; // can't go that way
if( seen.find(iSwitchToIndex) != seen.end() )
return false; // went full circle and none found
seen.insert( iSwitchToIndex );
if( !m_aGameCommands[iSwitchToIndex].IsPlayable() )
goto try_again;
}
return ChangeSelection( pn, dir, iSwitchToIndex );
}
@@ -624,16 +837,75 @@ bool ScreenSelectMaster::ChangeSelection( PlayerNumber pn, MenuDir dir, int iNew
bNewAlreadyHadFocus |= m_iChoice[p2] == iNewChoice;
}
//todo: condense this section
if(DOUBLE_PRESS_TO_SELECT)
{
// this player is currently on a single press, which they are cancelling
if(m_bDoubleChoice[pn])
if(m_bUsingTwoLists && m_iSelectedList == 1)
{
// this player is currently on a single press, which they are cancelling
if(m_bDoubleChoice[pn])
{
if( !bOldStillHasFocus )
m_vsprIconB[iOldChoice]->PlayCommand( "LostSelectedLoseFocus" );
if( !bNewAlreadyHadFocus )
m_vsprIconB[iNewChoice]->PlayCommand( "LostSelectedGainFocus" );
}
else
{
if( !bOldStillHasFocus )
m_vsprIconB[iOldChoice]->PlayCommand( "LoseFocus" );
if( !bNewAlreadyHadFocus )
m_vsprIconB[iNewChoice]->PlayCommand( "GainFocus" );
}
}
else
{
if(m_bUsingTwoLists && m_iSelectedList == 1)
{
// this player is currently on a single press, which they are cancelling
if(m_bDoubleChoice[pn])
{
if( !bOldStillHasFocus )
m_vsprIcon[iOldChoice]->PlayCommand( "LostSelectedLoseFocus" );
if( !bNewAlreadyHadFocus )
m_vsprIcon[iNewChoice]->PlayCommand( "LostSelectedGainFocus" );
}
else
{
if( !bOldStillHasFocus )
m_vsprIcon[iOldChoice]->PlayCommand( "LoseFocus" );
if( !bNewAlreadyHadFocus )
m_vsprIcon[iNewChoice]->PlayCommand( "GainFocus" );
}
}
else
{
// this player is currently on a single press, which they are cancelling
if(m_bDoubleChoice[pn])
{
if( !bOldStillHasFocus )
m_vsprIcon[iOldChoice]->PlayCommand( "LostSelectedLoseFocus" );
if( !bNewAlreadyHadFocus )
m_vsprIcon[iNewChoice]->PlayCommand( "LostSelectedGainFocus" );
}
else
{
if( !bOldStillHasFocus )
m_vsprIcon[iOldChoice]->PlayCommand( "LoseFocus" );
if( !bNewAlreadyHadFocus )
m_vsprIcon[iNewChoice]->PlayCommand( "GainFocus" );
}
}
}
}
else // not using double selection
{
if(m_bUsingTwoLists && m_iSelectedList == 1)
{
if( !bOldStillHasFocus )
m_vsprIcon[iOldChoice]->PlayCommand( "LoseFocus" );
m_vsprIconB[iOldChoice]->PlayCommand( "LoseFocus" );
if( !bNewAlreadyHadFocus )
m_vsprIcon[iNewChoice]->PlayCommand( "GainFocus" );
m_vsprIconB[iNewChoice]->PlayCommand( "GainFocus" );
}
else
{
@@ -643,14 +915,6 @@ bool ScreenSelectMaster::ChangeSelection( PlayerNumber pn, MenuDir dir, int iNew
m_vsprIcon[iNewChoice]->PlayCommand( "GainFocus" );
}
}
else // not using double selection
{
if( !bOldStillHasFocus )
m_vsprIcon[iOldChoice]->PlayCommand( "LostSelectedLoseFocus" );
if( !bNewAlreadyHadFocus )
m_vsprIcon[iNewChoice]->PlayCommand( "LostSelectedGainFocus" );
}
}
if( SHOW_CURSOR )
@@ -661,26 +925,51 @@ bool ScreenSelectMaster::ChangeSelection( PlayerNumber pn, MenuDir dir, int iNew
if( SHOW_SCROLLER )
{
ActorScroller &scroller = SHARED_SELECTION ? m_Scroller[0] : m_Scroller[*p];
vector<AutoActor> &vScroll = SHARED_SELECTION ? m_vsprScroll[0] : m_vsprScroll[*p];
if( WRAP_SCROLLER )
ActorScroller &scroller = (m_bUsingTwoLists && m_iSelectedList == 1)?(SHARED_SELECTION ? m_ScrollerB[0] : m_ScrollerB[*p]):(SHARED_SELECTION ? m_Scroller[0] : m_Scroller[*p]);
vector<AutoActor> &vScroll = (m_bUsingTwoLists && m_iSelectedList == 1)?(SHARED_SELECTION ? m_vsprScrollB[0] : m_vsprScrollB[*p]):(SHARED_SELECTION ? m_vsprScroll[0] : m_vsprScroll[*p]);
// second list
if(m_bUsingTwoLists && m_iSelectedList == 1)
{
// HACK: We can't tell from the option orders whether or not we wrapped.
// For now, assume that the order is increasing left to right.
int iPressedDir = (dir == MenuDir_Left) ? -1 : +1;
int iActualDir = (iOldChoice < iNewChoice) ? +1 : -1;
if( iPressedDir != iActualDir ) // wrapped
if( WRAP_SCROLLER )
{
float fItem = scroller.GetCurrentItem();
int iNumChoices = m_aGameCommands.size();
fItem += iActualDir * iNumChoices;
scroller.SetCurrentAndDestinationItem( fItem );
}
}
// HACK: We can't tell from the option orders whether or not we wrapped.
// For now, assume that the order is increasing left to right.
int iPressedDir = (dir == MenuDir_Left) ? -1 : +1;
int iActualDir = (iOldChoice < iNewChoice) ? +1 : -1;
scroller.SetDestinationItem( (float)iNewChoice );
if( iPressedDir != iActualDir ) // wrapped
{
float fItem = scroller.GetCurrentItem();
int iNumChoices = m_aGameCommandsB.size();
fItem += iActualDir * iNumChoices;
scroller.SetCurrentAndDestinationItem( fItem );
}
}
scroller.SetDestinationItem( (float)iNewChoice );
}
else
{
if( WRAP_SCROLLER )
{
// HACK: We can't tell from the option orders whether or not we wrapped.
// For now, assume that the order is increasing left to right.
int iPressedDir = (dir == MenuDir_Left) ? -1 : +1;
int iActualDir = (iOldChoice < iNewChoice) ? +1 : -1;
if( iPressedDir != iActualDir ) // wrapped
{
float fItem = scroller.GetCurrentItem();
int iNumChoices = m_aGameCommands.size();
fItem += iActualDir * iNumChoices;
scroller.SetCurrentAndDestinationItem( fItem );
}
}
scroller.SetDestinationItem( (float)iNewChoice );
}
// using double selections
if(DOUBLE_PRESS_TO_SELECT)
{
@@ -783,15 +1072,23 @@ void ScreenSelectMaster::MenuStart( const InputEventPlus &input )
if(SHOW_SCROLLER)
{
vector<AutoActor> &vScroll = SHARED_SELECTION ? m_vsprScroll[0] : m_vsprScroll[pn];
vScroll[m_iChoice[pn]]->PlayCommand( "InitialSelection" );
if(m_bUsingTwoLists && m_iSelectedList == 1)
{
vector<AutoActor> &vScroll = SHARED_SELECTION ? m_vsprScrollB[0] : m_vsprScrollB[pn];
vScroll[m_iChoice[pn]]->PlayCommand( "InitialSelection" );
}
else
{
vector<AutoActor> &vScroll = SHARED_SELECTION ? m_vsprScroll[0] : m_vsprScroll[pn];
vScroll[m_iChoice[pn]]->PlayCommand( "InitialSelection" );
}
}
return;
}
const GameCommand &mc = m_aGameCommands[m_iChoice[pn]];
const GameCommand &mc = (m_bUsingTwoLists && m_iSelectedList == 1)?m_aGameCommandsB[m_iChoice[pn]]:m_aGameCommands[m_iChoice[pn]];
/* If no options are playable, then we're just waiting for one to become available.
* If any options are playable, then the selection must be playable. */
@@ -852,26 +1149,55 @@ void ScreenSelectMaster::TweenOnScreen()
if( SHOW_ICON )
{
for( unsigned c=0; c<m_aGameCommands.size(); c++ )
if(m_bUsingTwoLists && m_iSelectedList == 1)
{
m_vsprIcon[c]->PlayCommand( (int(c) == m_iChoice[0])? "GainFocus":"LoseFocus" );
m_vsprIcon[c]->FinishTweening();
for( unsigned c=0; c<m_aGameCommandsB.size(); c++ )
{
m_vsprIconB[c]->PlayCommand( (int(c) == m_iChoice[0])? "GainFocus":"LoseFocus" );
m_vsprIconB[c]->FinishTweening();
}
}
else
{
for( unsigned c=0; c<m_aGameCommands.size(); c++ )
{
m_vsprIcon[c]->PlayCommand( (int(c) == m_iChoice[0])? "GainFocus":"LoseFocus" );
m_vsprIcon[c]->FinishTweening();
}
}
}
if( SHOW_SCROLLER )
{
FOREACH( PlayerNumber, vpns, p )
if(m_bUsingTwoLists && m_iSelectedList == 1)
{
// Play Gain/LoseFocus before playing the on command. Gain/Lose will
// often stop tweening, which ruins the OnCommand.
for( unsigned c=0; c<m_aGameCommands.size(); c++ )
FOREACH( PlayerNumber, vpns, p )
{
m_vsprScroll[*p][c]->PlayCommand( int(c) == m_iChoice[*p]? "GainFocus":"LoseFocus" );
m_vsprScroll[*p][c]->FinishTweening();
}
// Play Gain/LoseFocus before playing the on command. Gain/Lose will
// often stop tweening, which ruins the OnCommand.
for( unsigned c=0; c<m_aGameCommands.size(); c++ )
{
m_vsprScrollB[*p][c]->PlayCommand( int(c) == m_iChoice[*p]? "GainFocus":"LoseFocus" );
m_vsprScrollB[*p][c]->FinishTweening();
}
m_Scroller[*p].SetCurrentAndDestinationItem( (float)m_iChoice[*p] );
m_ScrollerB[*p].SetCurrentAndDestinationItem( (float)m_iChoice[*p] );
}
}
else
{
FOREACH( PlayerNumber, vpns, p )
{
// Play Gain/LoseFocus before playing the on command. Gain/Lose will
// often stop tweening, which ruins the OnCommand.
for( unsigned c=0; c<m_aGameCommands.size(); c++ )
{
m_vsprScroll[*p][c]->PlayCommand( int(c) == m_iChoice[*p]? "GainFocus":"LoseFocus" );
m_vsprScroll[*p][c]->FinishTweening();
}
m_Scroller[*p].SetCurrentAndDestinationItem( (float)m_iChoice[*p] );
}
}
}
@@ -894,25 +1220,54 @@ void ScreenSelectMaster::TweenOffScreen()
vector<PlayerNumber> vpns;
GetActiveElementPlayerNumbers( vpns );
for( unsigned c=0; c<m_aGameCommands.size(); c++ )
// using two lists -- may need to consider throwing a wider range of commands
// for themers if tweening out with one/two lists/focussed/not focussed etc?
if(m_bUsingTwoLists && m_iSelectedList == 1)
{
if( GetPage(c) != GetCurrentPage() )
continue; // skip
bool bSelectedByEitherPlayer = false;
FOREACH( PlayerNumber, vpns, p )
for( unsigned c=0; c<m_aGameCommandsB.size(); c++ )
{
if( m_iChoice[*p] == (int)c )
bSelectedByEitherPlayer = true;
}
if( GetPage(c) != GetCurrentPage() )
continue; // skip
if( SHOW_ICON )
m_vsprIcon[c]->PlayCommand( bSelectedByEitherPlayer? "OffFocused":"OffUnfocused" );
if( SHOW_SCROLLER )
{
bool bSelectedByEitherPlayer = false;
FOREACH( PlayerNumber, vpns, p )
m_vsprScroll[*p][c]->PlayCommand( bSelectedByEitherPlayer? "OffFocused":"OffUnfocused" );
{
if( m_iChoice[*p] == (int)c )
bSelectedByEitherPlayer = true;
}
if( SHOW_ICON )
m_vsprIconB[c]->PlayCommand( bSelectedByEitherPlayer? "OffFocused":"OffUnfocused" );
if( SHOW_SCROLLER )
{
FOREACH( PlayerNumber, vpns, p )
m_vsprScrollB[*p][c]->PlayCommand( bSelectedByEitherPlayer? "OffFocused":"OffUnfocused" );
}
}
}
else
{
for( unsigned c=0; c<m_aGameCommands.size(); c++ )
{
if( GetPage(c) != GetCurrentPage() )
continue; // skip
bool bSelectedByEitherPlayer = false;
FOREACH( PlayerNumber, vpns, p )
{
if( m_iChoice[*p] == (int)c )
bSelectedByEitherPlayer = true;
}
if( SHOW_ICON )
m_vsprIcon[c]->PlayCommand( bSelectedByEitherPlayer? "OffFocused":"OffUnfocused" );
if( SHOW_SCROLLER )
{
FOREACH( PlayerNumber, vpns, p )
m_vsprScroll[*p][c]->PlayCommand( bSelectedByEitherPlayer? "OffFocused":"OffUnfocused" );
}
}
}
}
+13
View File
@@ -23,6 +23,7 @@ class ScreenSelectMaster : public ScreenSelect
{
public:
ScreenSelectMaster();
//~ScreenSelectMaster();
virtual void Init();
virtual RString GetDefaultChoice();
virtual void BeginScreen();
@@ -44,6 +45,7 @@ protected:
Page GetPage( int iChoiceIndex ) const;
Page GetCurrentPage() const;
ThemeMetric<bool> USE_TWO_SCROLLERS;
ThemeMetric<bool> DOUBLE_PRESS_TO_SELECT;
ThemeMetric<bool> SHOW_ICON;
ThemeMetric<bool> SHOW_SCROLLER;
@@ -57,6 +59,7 @@ protected:
ThemeMetric<float> PRE_SWITCH_PAGE_SECONDS;
ThemeMetric<float> POST_SWITCH_PAGE_SECONDS;
ThemeMetric1D<RString> OPTION_ORDER;
ThemeMetric1D<RString> OPTION_ORDER2;
ThemeMetric<bool> WRAP_CURSOR;
ThemeMetric<bool> WRAP_SCROLLER;
ThemeMetric<bool> LOOP_SCROLLER;
@@ -69,6 +72,8 @@ protected:
ThemeMetric<RString> DEFAULT_CHOICE;
map<int,int> m_mapCurrentChoiceToNextChoice[NUM_MenuDir];
map<int,int> m_mapCurrentChoiceToNextChoiceB[NUM_MenuDir]; // if using two lists
virtual int GetSelectionIndex( PlayerNumber pn );
virtual void UpdateSelectableChoices();
@@ -87,9 +92,17 @@ protected:
AutoActor m_sprMore[NUM_Page];
// icon is the shared, per-choice piece
vector<AutoActor> m_vsprIcon;
vector<AutoActor> m_vsprIconB; // used if the user wants two lists
// preview is per-player, per-choice piece
vector<AutoActor> m_vsprScroll[NUM_PLAYERS];
vector<AutoActor> m_vsprScrollB[NUM_PLAYERS]; // used if the user wants two lists
ActorScroller m_Scroller[NUM_PLAYERS];
ActorScroller m_ScrollerB[NUM_PLAYERS]; // used if the user wants two lists
// cursor is the per-player, shared by all choices
AutoActor m_sprCursor[NUM_PLAYERS];