ScreenOptions: row data structure allows multiple selections per row

This commit is contained in:
Chris Danford
2004-01-10 08:05:20 +00:00
parent 4f62f34ad9
commit 2cd7370442
4 changed files with 98 additions and 81 deletions
+42 -52
View File
@@ -125,25 +125,30 @@ void ScreenOptions::Init( InputMode im, OptionRowData OptionRows[], int iNumOpti
for( int r=0; r<iNumOptionLines; r++ ) // foreach row for( int r=0; r<iNumOptionLines; r++ ) // foreach row
{ {
m_Rows.push_back( new Row() ); m_Rows.push_back( new Row() );
m_Rows[r]->m_RowDef = OptionRows[r]; Row &Row = *m_Rows[r];
Row.m_RowDef = OptionRows[r];
for( int p=0; p<NUM_PLAYERS; p++ ) for( int p=0; p<NUM_PLAYERS; p++ )
m_Rows[r]->m_iSelection[p] = 0; {
vector<bool> &vbSelected = Row.m_vbSelected[p];
if( m_Rows[r]->m_RowDef.bOneChoiceForAllPlayers ) vbSelected.resize( Row.m_RowDef.choices.size() );
for( int p=1; p<NUM_PLAYERS; p++ ) for( int j=0; j<vbSelected.size(); j++ )
m_Rows[r]->m_iSelection[p] = m_Rows[r]->m_iSelection[0]; vbSelected[j] = false;
}
} }
} }
this->ImportOptions(); this->ImportOptions();
// Make all selections the same if bOneChoiceForAllPlayers
{ {
for( int r=0; r<iNumOptionLines; r++ ) // foreach row for( int r=0; r<iNumOptionLines; r++ ) // foreach row
{ {
Row &Row = *m_Rows[r];
if( m_Rows[r]->m_RowDef.bOneChoiceForAllPlayers ) if( m_Rows[r]->m_RowDef.bOneChoiceForAllPlayers )
for( int p=1; p<NUM_PLAYERS; p++ ) for( int p=1; p<NUM_PLAYERS; p++ )
m_Rows[r]->m_iSelection[p] = m_Rows[r]->m_iSelection[0]; Row.m_vbSelected[p] = m_Rows[r]->m_vbSelected[0];
} }
} }
@@ -261,7 +266,7 @@ void ScreenOptions::Init( InputMode im, OptionRowData OptionRows[], int iNumOpti
BitmapText *bt = new BitmapText; BitmapText *bt = new BitmapText;
textItems.push_back( bt ); textItems.push_back( bt );
const int iChoiceInRow = m_Rows[r]->m_iSelection[p]; const int iChoiceInRow = row.GetOneSelection( (PlayerNumber)p );
bt->LoadFromFont( THEME->GetPathToF("ScreenOptions item") ); bt->LoadFromFont( THEME->GetPathToF("ScreenOptions item") );
bt->SetText( optline.choices[iChoiceInRow] ); bt->SetText( optline.choices[iChoiceInRow] );
@@ -562,20 +567,25 @@ void ScreenOptions::PositionUnderlines()
vector<OptionsCursor*> &vpUnderlines = row.m_Underline[p]; vector<OptionsCursor*> &vpUnderlines = row.m_Underline[p];
if( row.m_bRowIsLong ) const int iNumUnderlines = row.m_bRowIsLong ? 1 : vpUnderlines.size();
for( int i=0; i<iNumUnderlines; i++ )
{ {
OptionsCursor& ul = *vpUnderlines[0]; OptionsCursor& ul = *vpUnderlines[i];
int iChoiceInRow = row.m_bRowIsLong ? row.GetOneSelection( (PlayerNumber)p ) : i;
/* Don't tween X movement and color changes. */ /* Don't tween X movement and color changes. */
int iWidth, iX, iY; int iWidth, iX, iY;
GetWidthXY( (PlayerNumber)p, r, row.m_iSelection[p], iWidth, iX, iY ); GetWidthXY( (PlayerNumber)p, r, iChoiceInRow, iWidth, iX, iY );
ul.SetGlobalX( (float)iX ); ul.SetGlobalX( (float)iX );
ul.SetGlobalDiffuseColor( RageColor(1,1,1, 1.0f) ); ul.SetGlobalDiffuseColor( RageColor(1,1,1, 1.0f) );
// If there's only one choice (ScreenOptionsMenu), don't show underlines. // If there's only one choice (ScreenOptionsMenu), don't show underlines.
// It looks silly. // It looks silly.
bool bOnlyOneChoice = row.m_RowDef.choices.size() == 1; bool bOnlyOneChoice = row.m_RowDef.choices.size() == 1;
bool hidden = bOnlyOneChoice || row.m_bHidden; bool bSelected = iChoiceInRow == row.GetOneSelection( (PlayerNumber)p );
bool bHidden = bOnlyOneChoice || !bSelected || row.m_bHidden;
if( ul.GetDestY() != row.m_fY ) if( ul.GetDestY() != row.m_fY )
{ {
@@ -584,39 +594,10 @@ void ScreenOptions::PositionUnderlines()
} }
/* XXX: diffuse doesn't work since underline is an ActorFrame */ /* XXX: diffuse doesn't work since underline is an ActorFrame */
ul.SetDiffuse( RageColor(1,1,1,hidden? 0.0f:1.0f) ); ul.SetDiffuse( RageColor(1,1,1,bHidden? 0.0f:1.0f) );
ul.SetBarWidth( iWidth ); ul.SetBarWidth( iWidth );
ul.SetY( (float)iY ); ul.SetY( (float)iY );
} }
else // !row.m_bRowIsLong
{
for( unsigned i=0; i<vpUnderlines.size(); i++ )
{
OptionsCursor& ul = *vpUnderlines[i];
/* Don't tween X movement and color changes. */
int iWidth, iX, iY;
GetWidthXY( (PlayerNumber)p, r, row.m_iSelection[p], iWidth, iX, iY );
ul.SetGlobalX( (float)iX );
ul.SetGlobalDiffuseColor( RageColor(1,1,1, 1.0f) );
// If there's only one choice (ScreenOptionsMenu), don't show underlines.
// It looks silly.
bool bOnlyOneChoice = row.m_RowDef.choices.size() == 1;
bool hidden = bOnlyOneChoice || row.m_bHidden;
if( ul.GetDestY() != row.m_fY )
{
ul.StopTweening();
ul.BeginTweening( 0.3f );
}
/* XXX: diffuse doesn't work since underline is an ActorFrame */
ul.SetDiffuse( RageColor(1,1,1,hidden? 0.0f:1.0f) );
ul.SetBarWidth( iWidth );
ul.SetY( (float)iY );
}
}
} }
} }
} }
@@ -636,8 +617,10 @@ void ScreenOptions::PositionIcons()
OptionIcon &icon = row.m_OptionIcons[p]; OptionIcon &icon = row.m_OptionIcons[p];
int iChoiceInRow = row.GetOneSelection( (PlayerNumber)p );
int iWidth, iX, iY; // We only use iY int iWidth, iX, iY; // We only use iY
GetWidthXY( (PlayerNumber)p, i, row.m_iSelection[p], iWidth, iX, iY ); GetWidthXY( (PlayerNumber)p, i, iChoiceInRow, iWidth, iX, iY );
icon.SetX( ICONS_X(p) ); icon.SetX( ICONS_X(p) );
if( icon.GetDestY() != row.m_fY ) if( icon.GetDestY() != row.m_fY )
@@ -673,8 +656,10 @@ void ScreenOptions::PositionCursors()
OptionsCursor &highlight = m_Highlight[p]; OptionsCursor &highlight = m_Highlight[p];
int iChoiceInRow = Row.GetOneSelection( (PlayerNumber)p );
int iWidth, iX, iY; int iWidth, iX, iY;
GetWidthXY( (PlayerNumber)p, row, Row.m_iSelection[p], iWidth, iX, iY ); GetWidthXY( (PlayerNumber)p, row, iChoiceInRow, iWidth, iX, iY );
highlight.SetBarWidth( iWidth ); highlight.SetBarWidth( iWidth );
highlight.SetXY( (float)iX, (float)iY ); highlight.SetXY( (float)iX, (float)iY );
} }
@@ -690,8 +675,10 @@ void ScreenOptions::TweenCursor( PlayerNumber pn )
int row = m_iCurrentRow[pn]; int row = m_iCurrentRow[pn];
Row &Row = *m_Rows[row]; Row &Row = *m_Rows[row];
int iChoiceInRow = Row.GetOneSelection( pn );
int iWidth, iX, iY; int iWidth, iX, iY;
GetWidthXY( pn, iCurRow, Row.m_iSelection[pn], iWidth, iX, iY ); GetWidthXY( pn, iCurRow, iChoiceInRow, iWidth, iX, iY );
highlight.StopTweening(); highlight.StopTweening();
highlight.BeginTweening( 0.2f ); highlight.BeginTweening( 0.2f );
@@ -707,18 +694,18 @@ void ScreenOptions::TweenCursor( PlayerNumber pn )
} }
} }
void ScreenOptions::UpdateText( PlayerNumber player_no, int iRow ) void ScreenOptions::UpdateText( PlayerNumber pn, int iRow )
{ {
Row &row = *m_Rows[iRow]; Row &row = *m_Rows[iRow];
if( !row.m_bRowIsLong ) if( !row.m_bRowIsLong )
return; return;
int iChoiceInRow = m_Rows[iRow]->m_iSelection[player_no]; int iChoiceInRow = row.GetOneSelection( pn );
const OptionRowData &optrow = m_Rows[iRow]->m_RowDef; const OptionRowData &optrow = m_Rows[iRow]->m_RowDef;
unsigned item_no = optrow.bOneChoiceForAllPlayers?0:player_no; unsigned item_no = optrow.bOneChoiceForAllPlayers ? 0 : pn;
/* If player_no is 2 and there is no player 1: */ /* If player_no is 2 and there is no player 1: */
item_no = min( item_no, m_Rows[iRow]->m_textItems.size()-1 ); item_no = min( item_no, m_Rows[iRow]->m_textItems.size()-1 );
@@ -1143,23 +1130,26 @@ void ScreenOptions::ChangeValue( PlayerNumber pn, int iDelta, bool Repeat )
if( p != pn ) if( p != pn )
continue; // skip continue; // skip
int iNewSel = m_Rows[iCurRow]->m_iSelection[p] + iDelta; Row &row = *m_Rows[iCurRow];
int iCurrentSel = row.GetOneSelection( (PlayerNumber)p );
int iNewSel = row.GetOneSelection( (PlayerNumber)p ) + iDelta;
wrap( iNewSel, iNumOptions ); wrap( iNewSel, iNumOptions );
if( iNewSel != m_Rows[iCurRow]->m_iSelection[p] ) if( iCurrentSel != iNewSel )
bOneChanged = true; bOneChanged = true;
if( optrow.bOneChoiceForAllPlayers ) if( optrow.bOneChoiceForAllPlayers )
{ {
for( int p2=0; p2<NUM_PLAYERS; p2++ ) for( int p2=0; p2<NUM_PLAYERS; p2++ )
{ {
m_Rows[iCurRow]->m_iSelection[p2] = iNewSel; row.SetOneSelection( (PlayerNumber)p2, iNewSel );
UpdateText( (PlayerNumber)p2, iCurRow ); UpdateText( (PlayerNumber)p2, iCurRow );
} }
} }
else else
{ {
m_Rows[iCurRow]->m_iSelection[p] = iNewSel; row.SetOneSelection( (PlayerNumber)p, iNewSel );
UpdateText( (PlayerNumber)p, iCurRow ); UpdateText( (PlayerNumber)p, iCurRow );
} }
OnChange( (PlayerNumber)p ); OnChange( (PlayerNumber)p );
+26 -3
View File
@@ -112,8 +112,8 @@ protected:
~Row(); ~Row();
OptionRowData m_RowDef; OptionRowData m_RowDef;
enum { ROW_NORMAL, ROW_EXIT } Type; enum { ROW_NORMAL, ROW_EXIT } Type;
vector<BitmapText *> m_textItems; vector<BitmapText *> m_textItems; // size depends on m_bRowIsLong and which players are joined
vector<OptionsCursor *> m_Underline[NUM_PLAYERS]; vector<OptionsCursor *> m_Underline[NUM_PLAYERS]; // size depends on m_bRowIsLong and which players are joined
Sprite m_sprBullet; Sprite m_sprBullet;
BitmapText m_textTitle; BitmapText m_textTitle;
OptionIcon m_OptionIcons[NUM_PLAYERS]; OptionIcon m_OptionIcons[NUM_PLAYERS];
@@ -121,7 +121,30 @@ protected:
float m_fY; float m_fY;
bool m_bRowIsLong; // goes off edge of screen bool m_bRowIsLong; // goes off edge of screen
bool m_bHidden; // currently off screen bool m_bHidden; // currently off screen
int m_iSelection[NUM_PLAYERS];
// Only one will true at a time if m_RowDef.bMultiSelect
vector<bool> m_vbSelected[NUM_PLAYERS]; // size = m_RowDef.choices.size().
int GetOneSelection( PlayerNumber pn )
{
for( int i=0; i<m_vbSelected[pn].size(); i++ )
if( m_vbSelected[pn][i] )
return i;
return -1;
}
int GetOneSharedSelection()
{
return GetOneSelection( (PlayerNumber)0 );
}
void SetOneSelection( PlayerNumber pn, int iChoice )
{
for( int i=0; i<m_vbSelected[pn].size(); i++ )
m_vbSelected[pn][i] = false;
m_vbSelected[pn][iChoice] = true;
}
void SetOneSharedSelection( int iChoice )
{
SetOneSelection( (PlayerNumber)0, iChoice );
}
}; };
vector<Row*> m_Rows; vector<Row*> m_Rows;
+20 -16
View File
@@ -362,24 +362,27 @@ void ScreenOptionsMaster::ImportOptions()
for( unsigned i = 0; i < OptionRowHandlers.size(); ++i ) for( unsigned i = 0; i < OptionRowHandlers.size(); ++i )
{ {
const OptionRowHandler &hand = OptionRowHandlers[i]; const OptionRowHandler &hand = OptionRowHandlers[i];
const OptionRowData &row = m_OptionRowAlloc[i]; const OptionRowData &data = m_OptionRowAlloc[i];
Row &row = *m_Rows[i];
if( row.bOneChoiceForAllPlayers ) if( data.bOneChoiceForAllPlayers )
{ {
int col = ImportOption( row, hand, 0, i ); int choice = ImportOption( data, hand, 0, i );
m_Rows[i]->m_iSelection[0] = col; row.SetOneSharedSelection( choice );
ASSERT( m_Rows[i]->m_iSelection[0] < (int)row.choices.size() ); ASSERT( row.GetOneSharedSelection() < (int)data.choices.size() );
} }
else else
for( int pn=0; pn<NUM_PLAYERS; pn++ ) {
for( int p=0; p<NUM_PLAYERS; p++ )
{ {
if( !GAMESTATE->IsHumanPlayer(pn) ) if( !GAMESTATE->IsHumanPlayer(p) )
continue; continue;
int col = ImportOption( row, hand, pn, i ); int choice = ImportOption( data, hand, p, i );
m_Rows[i]->m_iSelection[pn] = col; row.SetOneSelection( (PlayerNumber)p, choice );
ASSERT( m_Rows[i]->m_iSelection[pn] < (int)row.choices.size() ); ASSERT( row.GetOneSelection((PlayerNumber)p) < (int)data.choices.size() );
} }
}
} }
} }
@@ -485,14 +488,15 @@ void ScreenOptionsMaster::ExportOptions()
for( i = 0; i < OptionRowHandlers.size(); ++i ) for( i = 0; i < OptionRowHandlers.size(); ++i )
{ {
const OptionRowHandler &hand = OptionRowHandlers[i]; const OptionRowHandler &hand = OptionRowHandlers[i];
const OptionRowData &row = m_OptionRowAlloc[i]; const OptionRowData &data = m_OptionRowAlloc[i];
Row &row = *m_Rows[i];
for( int pn=0; pn<NUM_PLAYERS; pn++ ) for( int p=0; p<NUM_PLAYERS; p++ )
{ {
if( !GAMESTATE->IsHumanPlayer(pn) ) if( !GAMESTATE->IsHumanPlayer(p) )
continue; continue;
ChangeMask |= ExportOption( row, hand, pn, m_Rows[i]->m_iSelection[pn] ); ChangeMask |= ExportOption( data, hand, p, row.GetOneSelection((PlayerNumber)p) );
} }
} }
@@ -507,7 +511,7 @@ void ScreenOptionsMaster::ExportOptions()
const OptionRowHandler &hand = OptionRowHandlers[row]; const OptionRowHandler &hand = OptionRowHandlers[row];
if( hand.type == ROW_LIST ) if( hand.type == ROW_LIST )
{ {
const int sel = m_Rows[row]->m_iSelection[0]; const int sel = m_Rows[row]->GetOneSharedSelection();
const ModeChoice &mc = hand.ListEntries[sel]; const ModeChoice &mc = hand.ListEntries[sel];
if( mc.m_sScreen != "" ) if( mc.m_sScreen != "" )
m_NextScreen = mc.m_sScreen; m_NextScreen = mc.m_sScreen;
@@ -583,7 +587,7 @@ void ScreenOptionsMaster::RefreshIcons()
const OptionRowData &row = m_Rows[i]->m_RowDef; const OptionRowData &row = m_Rows[i]->m_RowDef;
int iSelection = m_Rows[i]->m_iSelection[p]; int iSelection = m_Rows[i]->GetOneSelection((PlayerNumber)p);
if( iSelection >= (int)row.choices.size() ) if( iSelection >= (int)row.choices.size() )
{ {
/* Invalid selection. Send debug output, to aid debugging. */ /* Invalid selection. Send debug output, to aid debugging. */
+10 -10
View File
@@ -97,14 +97,14 @@ void ScreenProfileOptions::ImportOptions()
vsProfiles.end(), vsProfiles.end(),
PREFSMAN->m_sDefaultLocalProfileID[PLAYER_1] ); PREFSMAN->m_sDefaultLocalProfileID[PLAYER_1] );
if( iter != vsProfiles.end() ) if( iter != vsProfiles.end() )
m_Rows[PO_PLAYER1]->m_iSelection[0] = iter - vsProfiles.begin() + 1; m_Rows[PO_PLAYER1]->SetOneSharedSelection( iter - vsProfiles.begin() + 1 );
iter = find( iter = find(
vsProfiles.begin(), vsProfiles.begin(),
vsProfiles.end(), vsProfiles.end(),
PREFSMAN->m_sDefaultLocalProfileID[PLAYER_2] ); PREFSMAN->m_sDefaultLocalProfileID[PLAYER_2] );
if( iter != vsProfiles.end() ) if( iter != vsProfiles.end() )
m_Rows[PO_PLAYER2]->m_iSelection[0] = iter - vsProfiles.begin() + 1; m_Rows[PO_PLAYER2]->SetOneSharedSelection( iter - vsProfiles.begin() + 1 );
} }
void ScreenProfileOptions::ExportOptions() void ScreenProfileOptions::ExportOptions()
@@ -112,13 +112,13 @@ void ScreenProfileOptions::ExportOptions()
vector<CString> vsProfiles; vector<CString> vsProfiles;
PROFILEMAN->GetLocalProfileIDs( vsProfiles ); PROFILEMAN->GetLocalProfileIDs( vsProfiles );
if( m_Rows[PO_PLAYER1]->m_iSelection[0] > 0 ) if( m_Rows[PO_PLAYER1]->GetOneSharedSelection() > 0 )
PREFSMAN->m_sDefaultLocalProfileID[PLAYER_1] = vsProfiles[m_Rows[PO_PLAYER1]->m_iSelection[0]-1]; PREFSMAN->m_sDefaultLocalProfileID[PLAYER_1] = vsProfiles[m_Rows[PO_PLAYER1]->GetOneSharedSelection()-1];
else else
PREFSMAN->m_sDefaultLocalProfileID[PLAYER_1] = ""; PREFSMAN->m_sDefaultLocalProfileID[PLAYER_1] = "";
if( m_Rows[PO_PLAYER2]->m_iSelection[0] > 0 ) if( m_Rows[PO_PLAYER2]->GetOneSharedSelection() > 0 )
PREFSMAN->m_sDefaultLocalProfileID[PLAYER_2] = vsProfiles[m_Rows[PO_PLAYER2]->m_iSelection[0]-1]; PREFSMAN->m_sDefaultLocalProfileID[PLAYER_2] = vsProfiles[m_Rows[PO_PLAYER2]->GetOneSharedSelection()-1];
else else
PREFSMAN->m_sDefaultLocalProfileID[PLAYER_2] = ""; PREFSMAN->m_sDefaultLocalProfileID[PLAYER_2] = "";
} }
@@ -212,17 +212,17 @@ CString ScreenProfileOptions::GetSelectedProfileID()
vector<CString> vsProfiles; vector<CString> vsProfiles;
PROFILEMAN->GetLocalProfileIDs( vsProfiles ); PROFILEMAN->GetLocalProfileIDs( vsProfiles );
if( m_Rows[GetCurrentRow()]->m_iSelection[0] ) if( m_Rows[GetCurrentRow()]->GetOneSharedSelection() )
return ""; return "";
else else
return vsProfiles[ m_Rows[GetCurrentRow()]->m_iSelection[0]-1]; return vsProfiles[ m_Rows[GetCurrentRow()]->GetOneSharedSelection()-1];
} }
CString ScreenProfileOptions::GetSelectedProfileName() CString ScreenProfileOptions::GetSelectedProfileName()
{ {
if( m_Rows[GetCurrentRow()]->m_iSelection[0] ) if( m_Rows[GetCurrentRow()]->GetOneSharedSelection() )
return ""; return "";
else else
return g_ProfileOptionsLines[PO_PLAYER1].choices[ m_Rows[GetCurrentRow()]->m_iSelection[0] ]; return g_ProfileOptionsLines[PO_PLAYER1].choices[ m_Rows[GetCurrentRow()]->GetOneSharedSelection() ];
} }