diff --git a/stepmania/src/OptionRow.cpp b/stepmania/src/OptionRow.cpp index 97ebb620ad..3402b34767 100644 --- a/stepmania/src/OptionRow.cpp +++ b/stepmania/src/OptionRow.cpp @@ -23,6 +23,9 @@ static const CString LayoutTypeNames[NUM_LAYOUT_TYPES] = { XToString( LayoutType ); StringToX( LayoutType ); +#define FOREACH_OptionsPlayer( pn ) \ + for( PlayerNumber pn=GetNextHumanPlayer((PlayerNumber)-1); pn!=PLAYER_INVALID && (!m_RowDef.bOneChoiceForAllPlayers || pn==0); pn=GetNextHumanPlayer(pn) ) + const CString NEXT_ROW_NAME = "NextRow"; @@ -455,18 +458,15 @@ void OptionRow::UpdateText() switch( m_RowDef.layoutType ) { case LAYOUT_SHOW_ONE_IN_ROW: - FOREACH_HumanPlayer( pn ) + FOREACH_HumanPlayer( p ) { + unsigned pn = m_RowDef.bOneChoiceForAllPlayers ? 0 : p; int iChoiceWithFocus = m_iChoiceInRowWithFocus[pn]; - unsigned item_no = m_RowDef.bOneChoiceForAllPlayers ? 0 : pn; - - /* If player_no is 2 and there is no player 1: */ - item_no = min( item_no, m_textItems.size()-1 ); CString sText = m_RowDef.choices[iChoiceWithFocus]; if( CAPITALIZE_ALL_OPTION_NAMES ) sText.MakeUpper(); - m_textItems[item_no]->SetText( sText ); + m_textItems[pn]->SetText( sText ); } break; } @@ -681,6 +681,23 @@ void OptionRow::Reload() ImportOptions(); + switch( m_RowDef.selectType ) + { + case SELECT_ONE: + FOREACH_OptionsPlayer( p ) + m_iChoiceInRowWithFocus[p] = GetOneSelection(p); + break; + case SELECT_MULTIPLE: + FOREACH_OptionsPlayer( p ) + CLAMP( m_iChoiceInRowWithFocus[p], 0, m_RowDef.choices.size()-1 ); + break; + default: + ASSERT(0); + } + + if( m_RowDef.m_bExportOnChange ) + ExportOptions(); + UpdateEnabledDisabled(); UpdateText(); PositionUnderlines(); @@ -720,63 +737,53 @@ static void VerifySelected( SelectType st, const vector vbSelected ) } } -void OptionRow::ImportOptions() +void OptionRow::ImportOptions( PlayerNumber pn ) { if( m_pHand == NULL ) return; - // clear selections - FOREACH_PlayerNumber( p ) - FOREACH( bool, m_vbSelected[p], b ) - *b = false; - ASSERT( m_RowDef.choices.size() > 0 ); - if( m_RowDef.bOneChoiceForAllPlayers ) - { - ASSERT( m_vbSelected[0].size() == m_RowDef.choices.size() ); - ERASE_ONE_BOOL_AT_FRONT_IF_NEEDED( m_vbSelected[0] ); - m_pHand->ImportOption( m_RowDef, PLAYER_1, m_vbSelected[0] ); - INSERT_ONE_BOOL_AT_FRONT_IF_NEEDED( m_vbSelected[0] ); - VerifySelected( m_RowDef.selectType, m_vbSelected[0] ); - } - else - { - FOREACH_HumanPlayer( p ) - { - ASSERT( m_vbSelected[p].size() == m_RowDef.choices.size() ); - ERASE_ONE_BOOL_AT_FRONT_IF_NEEDED( m_vbSelected[p] ); - m_pHand->ImportOption( m_RowDef, p, m_vbSelected[p] ); - INSERT_ONE_BOOL_AT_FRONT_IF_NEEDED( m_vbSelected[p] ); - VerifySelected( m_RowDef.selectType, m_vbSelected[p] ); - } - } + FOREACH( bool, m_vbSelected[pn], b ) + *b = false; + + ASSERT( m_vbSelected[pn].size() == m_RowDef.choices.size() ); + ERASE_ONE_BOOL_AT_FRONT_IF_NEEDED( m_vbSelected[pn] ); + m_pHand->ImportOption( m_RowDef, pn, m_vbSelected[pn] ); + INSERT_ONE_BOOL_AT_FRONT_IF_NEEDED( m_vbSelected[pn] ); + VerifySelected( m_RowDef.selectType, m_vbSelected[pn] ); } -int OptionRow::ExportOptions() +void OptionRow::ImportOptions() +{ + FOREACH_OptionsPlayer( p ) + ImportOptions( p ); +} + +int OptionRow::ExportOptions( PlayerNumber pn ) { if( m_pHand == NULL ) return 0; + ASSERT( m_RowDef.choices.size() > 0 ); + + int iChangeMask = 0; + + ASSERT( m_vbSelected[pn].size() == m_RowDef.choices.size() ); + ERASE_ONE_BOOL_AT_FRONT_IF_NEEDED( m_vbSelected[pn] ); + iChangeMask |= m_pHand->ExportOption( m_RowDef, pn, m_vbSelected[pn] ); + INSERT_ONE_BOOL_AT_FRONT_IF_NEEDED( m_vbSelected[pn] ); + + return iChangeMask; +} + +int OptionRow::ExportOptions() +{ int iChangeMask = 0; - if( m_RowDef.bOneChoiceForAllPlayers ) - { - ASSERT( m_vbSelected[0].size() == m_RowDef.choices.size() ); - ERASE_ONE_BOOL_AT_FRONT_IF_NEEDED( m_vbSelected[0] ); - iChangeMask |= m_pHand->ExportOption( m_RowDef, PLAYER_1, m_vbSelected[0] ); - INSERT_ONE_BOOL_AT_FRONT_IF_NEEDED( m_vbSelected[0] ); - } - else - { - FOREACH_HumanPlayer( p ) - { - ASSERT( m_vbSelected[p].size() == m_RowDef.choices.size() ); - ERASE_ONE_BOOL_AT_FRONT_IF_NEEDED( m_vbSelected[p] ); - iChangeMask |= m_pHand->ExportOption( m_RowDef, p, m_vbSelected[p] ); - INSERT_ONE_BOOL_AT_FRONT_IF_NEEDED( m_vbSelected[p] ); - } - } + FOREACH_OptionsPlayer( p ) + iChangeMask |= ExportOptions( p ); + return iChangeMask; } diff --git a/stepmania/src/OptionRow.h b/stepmania/src/OptionRow.h index a72082d59a..d3e41ffd23 100644 --- a/stepmania/src/OptionRow.h +++ b/stepmania/src/OptionRow.h @@ -88,7 +88,9 @@ public: void LoadExit(); void LoadOptionIcon( PlayerNumber pn, const CString &sText ); + void ImportOptions( PlayerNumber pn ); void ImportOptions(); + int ExportOptions( PlayerNumber pn ); int ExportOptions(); void AfterImportOptions( @@ -108,10 +110,33 @@ public: void SetOneSelection( PlayerNumber pn, int iChoice ); void SetOneSharedSelection( int iChoice ); - int m_iChoiceInRowWithFocus[NUM_PLAYERS]; // this choice has input focus - - // Only one will true at a time if m_RowDef.bMultiSelect - vector m_vbSelected[NUM_PLAYERS]; // size = m_RowDef.choices.size() + int GetChoiceInRowWithFocus( PlayerNumber pn ) const + { + if( m_RowDef.bOneChoiceForAllPlayers ) + pn = PLAYER_1; + int iChoice = m_iChoiceInRowWithFocus[pn]; + ASSERT(iChoice<(int)m_RowDef.choices.size()); + return iChoice; + } + void SetChoiceInRowWithFocus( PlayerNumber pn, int iChoice ) + { + if( m_RowDef.bOneChoiceForAllPlayers ) + pn = PLAYER_1; + ASSERT(iChoice<(int)m_RowDef.choices.size()); + m_iChoiceInRowWithFocus[pn] = iChoice; + } + bool GetSelected( PlayerNumber pn, int iChoice ) const + { + if( m_RowDef.bOneChoiceForAllPlayers ) + pn = PLAYER_1; + return m_vbSelected[pn][iChoice]; + } + void SetSelected( PlayerNumber pn, int iChoice, bool b ) + { + if( m_RowDef.bOneChoiceForAllPlayers ) + pn = PLAYER_1; + m_vbSelected[pn][iChoice] = b; + } enum RowType { @@ -155,6 +180,10 @@ protected: bool m_bFirstItemGoesDown; bool m_bRowHasFocus[NUM_PLAYERS]; + int m_iChoiceInRowWithFocus[NUM_PLAYERS]; // this choice has input focus + // Only one will true at a time if m_RowDef.bMultiSelect + vector m_vbSelected[NUM_PLAYERS]; // size = m_RowDef.choices.size() + float m_fY; bool m_bHidden; // currently off screen diff --git a/stepmania/src/ScreenOptions.cpp b/stepmania/src/ScreenOptions.cpp index 50f8e4717b..3fc2d1e3b5 100644 --- a/stepmania/src/ScreenOptions.cpp +++ b/stepmania/src/ScreenOptions.cpp @@ -191,13 +191,15 @@ void ScreenOptions::InitMenu( InputMode im, const vector &v m_framePage.AddChild( &row ); } - // TRICKY: Add one more item. This will be "EXIT" - m_Rows.push_back( new OptionRow() ); - OptionRow &row = *m_Rows.back(); - row.LoadMetrics( OPTION_ROW_TYPE ); - row.LoadExit(); - - m_framePage.AddChild( &row ); + if( SEPARATE_EXIT_ROW ) + { + // TRICKY: Add one more item. This will be "EXIT" + m_Rows.push_back( new OptionRow() ); + OptionRow &row = *m_Rows.back(); + row.LoadMetrics( OPTION_ROW_TYPE ); + row.LoadExit(); + m_framePage.AddChild( &row ); + } // add explanation here so it appears on top FOREACH_PlayerNumber( p ) @@ -406,7 +408,7 @@ void ScreenOptions::PositionCursors() OptionsCursor &highlight = m_Highlight[pn]; - const int iChoiceWithFocus = OptionRow.m_iChoiceInRowWithFocus[pn]; + const int iChoiceWithFocus = OptionRow.GetChoiceInRowWithFocus(pn); int iWidth, iX, iY; GetWidthXY( pn, iRow, iChoiceWithFocus, iWidth, iX, iY ); @@ -422,7 +424,7 @@ void ScreenOptions::TweenCursor( PlayerNumber pn ) ASSERT_M( iRow < (int)m_Rows.size(), ssprintf("%i < %i", iRow, (int)m_Rows.size() ) ); const OptionRow &row = *m_Rows[iRow]; - const int iChoiceWithFocus = row.m_iChoiceInRowWithFocus[pn]; + const int iChoiceWithFocus = row.GetChoiceInRowWithFocus(pn); int iWidth, iX, iY; GetWidthXY( pn, iRow, iChoiceWithFocus, iWidth, iX, iY ); @@ -686,10 +688,11 @@ void ScreenOptions::OnChange( PlayerNumber pn ) FOREACH_PlayerNumber( p ) { if( GAMESTATE->IsHumanPlayer(p) ) - TweenCursor( p ); + TweenCursor( p ); int iCurrentRow = m_iCurrentRow[pn]; - const bool ExitSelected = m_Rows[iCurrentRow]->GetRowType() == OptionRow::ROW_EXIT; + OptionRow &row = *m_Rows[iCurrentRow]; + const bool ExitSelected = row.GetRowType() == OptionRow::ROW_EXIT; if( p == pn || GAMESTATE->GetNumHumanPlayers() == 1 ) { if( m_bWasOnExit[p] != ExitSelected ) @@ -797,7 +800,7 @@ void ScreenOptions::MenuStart( PlayerNumber pn, const InputEventType selectType if( row.GetFirstItemGoesDown() ) { - int iChoiceInRow = row.m_iChoiceInRowWithFocus[pn]; + int iChoiceInRow = row.GetChoiceInRowWithFocus(pn); if( iChoiceInRow == 0 ) { MenuDown( pn, selectType ); @@ -807,9 +810,10 @@ void ScreenOptions::MenuStart( PlayerNumber pn, const InputEventType selectType if( row.GetRowDef().selectType == SELECT_MULTIPLE ) { - int iChoiceInRow = row.m_iChoiceInRowWithFocus[pn]; - row.m_vbSelected[pn][iChoiceInRow] = !row.m_vbSelected[pn][iChoiceInRow]; - if( row.m_vbSelected[pn][iChoiceInRow] ) + int iChoiceInRow = row.GetChoiceInRowWithFocus(pn); + bool bSelected = !row.GetSelected( pn, iChoiceInRow ); + row.SetSelected( pn, iChoiceInRow, bSelected ); + if( bSelected ) m_SoundToggleOn.Play(); else m_SoundToggleOff.Play(); @@ -819,7 +823,7 @@ void ScreenOptions::MenuStart( PlayerNumber pn, const InputEventType selectType if( row.GetFirstItemGoesDown() ) { // move to the first choice in the row - ChangeValueInRow( pn, -row.m_iChoiceInRowWithFocus[pn], selectType != IET_FIRST_PRESS ); + ChangeValueInRow( pn, -row.GetChoiceInRowWithFocus(pn), selectType != IET_FIRST_PRESS ); } } else // data.selectType != SELECT_MULTIPLE @@ -833,14 +837,14 @@ void ScreenOptions::MenuStart( PlayerNumber pn, const InputEventType selectType case NAV_TOGGLE_FIVE_KEY: if( row.GetRowDef().selectType != SELECT_MULTIPLE ) { - int iChoiceInRow = row.m_iChoiceInRowWithFocus[pn]; + int iChoiceInRow = row.GetChoiceInRowWithFocus(pn); if( row.GetRowDef().bOneChoiceForAllPlayers ) row.SetOneSharedSelection( iChoiceInRow ); else row.SetOneSelection( pn, iChoiceInRow ); } if( row.GetFirstItemGoesDown() ) - ChangeValueInRow( pn, -row.m_iChoiceInRowWithFocus[pn], selectType != IET_FIRST_PRESS ); // move to the first choice + ChangeValueInRow( pn, -row.GetChoiceInRowWithFocus(pn), selectType != IET_FIRST_PRESS ); // move to the first choice else ChangeValueInRow( pn, 0, selectType != IET_FIRST_PRESS ); break; @@ -867,9 +871,9 @@ void ScreenOptions::StoreFocus( PlayerNumber pn ) return; int iWidth, iY; - GetWidthXY( pn, m_iCurrentRow[pn], m_Rows[m_iCurrentRow[pn]]->m_iChoiceInRowWithFocus[pn], iWidth, m_iFocusX[pn], iY ); - LOG->Trace("cur selection %ix%i @ %i", m_iCurrentRow[pn], m_Rows[m_iCurrentRow[pn]]->m_iChoiceInRowWithFocus[pn], - m_iFocusX[pn]); + GetWidthXY( pn, m_iCurrentRow[pn], row.GetChoiceInRowWithFocus(pn), iWidth, m_iFocusX[pn], iY ); + LOG->Trace("cur selection %ix%i @ %i", + m_iCurrentRow[pn], row.GetChoiceInRowWithFocus(pn), m_iFocusX[pn]); } /* Left/right */ @@ -899,14 +903,14 @@ void ScreenOptions::ChangeValueInRow( PlayerNumber pn, int iDelta, bool Repeat ) bool bOneChanged = false; - int iCurrentChoiceWithFocus = row.m_iChoiceInRowWithFocus[pn]; + int iCurrentChoiceWithFocus = row.GetChoiceInRowWithFocus(pn); int iNewChoiceWithFocus = iCurrentChoiceWithFocus + iDelta; wrap( iNewChoiceWithFocus, iNumOptions ); if( iCurrentChoiceWithFocus != iNewChoiceWithFocus ) bOneChanged = true; - row.m_iChoiceInRowWithFocus[pn] = iNewChoiceWithFocus; + row.SetChoiceInRowWithFocus( pn, iNewChoiceWithFocus ); StoreFocus( pn ); if( row.GetRowDef().bOneChoiceForAllPlayers ) @@ -931,7 +935,7 @@ void ScreenOptions::ChangeValueInRow( PlayerNumber pn, int iDelta, bool Repeat ) // lock focus together FOREACH_HumanPlayer( p ) { - row.m_iChoiceInRowWithFocus[p] = iNewChoiceWithFocus; + row.SetChoiceInRowWithFocus( p, iNewChoiceWithFocus ); StoreFocus( p ); } } @@ -988,7 +992,7 @@ void ScreenOptions::MoveRow( PlayerNumber pn, int dir, bool Repeat ) { // If moving from a bFirstChoiceGoesDown row, put focus back on // the first choice before moving. - row.m_iChoiceInRowWithFocus[pn] = 0; + row.SetChoiceInRowWithFocus( pn, 0 ); } LOG->Trace("move pn %i, dir %i, rep %i", pn, dir, Repeat); @@ -1004,8 +1008,7 @@ void ScreenOptions::MoveRow( PlayerNumber pn, int dir, bool Repeat ) wrap( r, m_Rows.size() ); - int iCurrentRow = m_iCurrentRow[p]; - const unsigned iOldSelection = m_Rows[iCurrentRow]->m_iChoiceInRowWithFocus[p]; + const unsigned iOldSelection = row.GetChoiceInRowWithFocus(p); m_iCurrentRow[p] = r; @@ -1026,10 +1029,10 @@ void ScreenOptions::MoveRow( PlayerNumber pn, int dir, bool Repeat ) if( iSelectionDist == -1 || iDist < iSelectionDist ) { iSelectionDist = iDist; - row.m_iChoiceInRowWithFocus[p] = i; + row.SetChoiceInRowWithFocus( p, i ); } } - row.m_iChoiceInRowWithFocus[p] = min( iOldSelection, row.GetTextItemsSize()-1 ); + row.SetChoiceInRowWithFocus( p, min( iOldSelection, row.GetTextItemsSize()-1 ) ); } } diff --git a/stepmania/src/ScreenOptionsMaster.cpp b/stepmania/src/ScreenOptionsMaster.cpp index c568c3fcec..b19dde2771 100644 --- a/stepmania/src/ScreenOptionsMaster.cpp +++ b/stepmania/src/ScreenOptionsMaster.cpp @@ -136,13 +136,8 @@ void ScreenOptionsMaster::ImportOptionsForPlayer( PlayerNumber pn ) for( unsigned i = 0; i < OptionRowHandlers.size(); ++i ) { - const OptionRowHandler *pHand = OptionRowHandlers[i]; - const OptionRowDefinition &def = m_OptionRowAlloc[i]; OptionRow &row = *m_Rows[i]; - - if( def.bOneChoiceForAllPlayers ) - continue; - pHand->ImportOption( def, pn, row.m_vbSelected[pn] ); + row.ImportOptions( pn ); } } @@ -244,7 +239,7 @@ void ScreenOptionsMaster::HandleScreenMessage( const ScreenMessage SM ) OptionRowHandler *pHand = OptionRowHandlers[r]; - const int iChoice = row.m_iChoiceInRowWithFocus[GAMESTATE->m_MasterPlayerNumber]; + const int iChoice = row.GetChoiceInRowWithFocus(GAMESTATE->m_MasterPlayerNumber); CString sScreen = pHand->GetAndEraseScreen( iChoice ); if( !sScreen.empty() ) m_sNextScreen = sScreen;