From 9f87d1b9d5113801da843bea269d123892b23ba5 Mon Sep 17 00:00:00 2001 From: Glenn Maynard Date: Thu, 12 Aug 2004 22:10:48 +0000 Subject: [PATCH] rename NAV_FIRST_CHOICE_GOES_DOWN -> NAV_TOGGLE_THREE_KEY add NAV_TOGGLE_FIVE_KEY in NAV_FIVE_KEY, pressing start only moves to the "exit" row, instead of going directly to the next screen, so both players have opportunity to change options --- stepmania/src/ScreenOptions.cpp | 129 ++++++++++++++++++-------- stepmania/src/ScreenOptions.h | 4 +- stepmania/src/ScreenOptionsMaster.cpp | 10 +- 3 files changed, 97 insertions(+), 46 deletions(-) diff --git a/stepmania/src/ScreenOptions.cpp b/stepmania/src/ScreenOptions.cpp index 69c370e148..fe310422a5 100644 --- a/stepmania/src/ScreenOptions.cpp +++ b/stepmania/src/ScreenOptions.cpp @@ -49,11 +49,11 @@ const float ITEM_X[NUM_PLAYERS] = { 260, 420 }; #define CAPITALIZE_ALL_OPTION_NAMES THEME->GetMetricB(m_sName,"CapitalizeAllOptionNames") /* - * Three navigation types are provided: + * These navigation types are provided: * * NAV_THREE_KEY: * left, right -> change option - * up, down -> don't matter (change row) + * up, down -> change row * start -> move to next row * left+right+start -> move to prev row * (next screen via "exit" entry) @@ -65,6 +65,20 @@ const float ITEM_X[NUM_PLAYERS] = { 260, 420 }; * start -> next screen * This is a much more convenient navigation, requiring five keys. * + * NAV_TOGGLE_THREE_KEY: + * left, right -> change option + * up, down -> change row + * start -> on first choice, move down; otherewise toggle option and move to first choice + * + * NAV_TOGGLE_FIVE_KEY: + * left, right -> change option + * up, down -> change row + * start -> toggle option + * + * Regular modes and toggle modes must be enabled by the theme. We could simply + * automatically switch to toggle mode for multiselect rows, but that would be strange + * for non-multiselect rows (eg. scroll speed). + * * NAV_THREE_KEY_MENU: * left, right -> change row * up, down -> change row @@ -76,11 +90,6 @@ const float ITEM_X[NUM_PLAYERS] = { 260, 420 }; * We don't want to simply allow left/right to move up and down on single-entry * rows when in NAV_THREE_KEY, becasue left and right shouldn't exit the "exit" row * in player options menus, but it should in the options menu. - * - * NAV_FIRST_CHOICE_GOES_DOWN: - * left, right -> change option - * up, down -> change row - * start -> toggle option */ ScreenOptions::ScreenOptions( CString sClassName ) : ScreenWithMenuElements(sClassName) @@ -102,6 +111,7 @@ ScreenOptions::ScreenOptions( CString sClassName ) : ScreenWithMenuElements(sCla FOREACH_PlayerNumber( p ) { m_iCurrentRow[p] = 0; + m_iFocusX[p] = 0; m_bWasOnExit[p] = false; m_bGotAtLeastOneStartPressed[p] = false; } @@ -159,7 +169,7 @@ void ScreenOptions::Init( InputMode im, OptionRowData OptionRows[], int iNumOpti CHECKPOINT_M( ssprintf("row %i: %s", r, Row.m_RowDef.name.c_str()) ); FOREACH_PlayerNumber( p ) { - if( m_OptionsNavigation==NAV_FIRST_CHOICE_GOES_DOWN ) + if( m_OptionsNavigation==NAV_TOGGLE_THREE_KEY || m_OptionsNavigation==NAV_TOGGLE_FIVE_KEY ) Row.m_iChoiceWithFocus[p] = 0; // focus on the first row, which is "go down" else { @@ -1149,7 +1159,7 @@ void ScreenOptions::MenuStart( PlayerNumber pn, const InputEventType type ) switch( m_OptionsNavigation ) { case NAV_THREE_KEY: - case NAV_FIRST_CHOICE_GOES_DOWN: + case NAV_TOGGLE_THREE_KEY: { bool bHoldingLeftAndRight = INPUTMAPPER->IsButtonDown( MenuInput(pn, MENU_BUTTON_RIGHT) ) && @@ -1178,8 +1188,7 @@ void ScreenOptions::MenuStart( PlayerNumber pn, const InputEventType type ) } - - if( m_OptionsNavigation == NAV_FIRST_CHOICE_GOES_DOWN ) + if( m_OptionsNavigation == NAV_TOGGLE_THREE_KEY ) { int iChoiceInRow = row.m_iChoiceWithFocus[pn]; if( iChoiceInRow == 0 ) @@ -1190,7 +1199,6 @@ void ScreenOptions::MenuStart( PlayerNumber pn, const InputEventType type ) } // If this is a bFirstChoiceGoesDown, then if this is a multiselect row. - // Is this the right thing to do for five key navigation? if( data.bMultiSelect ) { int iChoiceInRow = row.m_iChoiceWithFocus[pn]; @@ -1202,7 +1210,7 @@ void ScreenOptions::MenuStart( PlayerNumber pn, const InputEventType type ) PositionUnderlines(); RefreshIcons(); - if( m_OptionsNavigation == NAV_FIRST_CHOICE_GOES_DOWN ) + if( m_OptionsNavigation == NAV_TOGGLE_THREE_KEY ) ChangeValueInRow( pn, -row.m_iChoiceWithFocus[pn], type != IET_FIRST_PRESS ); // move to the first choice } else @@ -1210,35 +1218,53 @@ void ScreenOptions::MenuStart( PlayerNumber pn, const InputEventType type ) switch( m_OptionsNavigation ) { case NAV_THREE_KEY: - case NAV_FIRST_CHOICE_GOES_DOWN: + MenuDown( pn, type ); + break; + case NAV_TOGGLE_THREE_KEY: + case NAV_TOGGLE_FIVE_KEY: + if( !data.bMultiSelect ) { - if( m_OptionsNavigation == NAV_FIRST_CHOICE_GOES_DOWN ) - { - if( !data.bMultiSelect ) - { - int iChoiceInRow = row.m_iChoiceWithFocus[pn]; - if( row.m_RowDef.bOneChoiceForAllPlayers ) - row.SetOneSharedSelection( iChoiceInRow ); - else - row.SetOneSelection( pn, iChoiceInRow ); - } - - ChangeValueInRow( pn, -row.m_iChoiceWithFocus[pn], type != IET_FIRST_PRESS ); // move to the first choice - } + int iChoiceInRow = row.m_iChoiceWithFocus[pn]; + if( row.m_RowDef.bOneChoiceForAllPlayers ) + row.SetOneSharedSelection( iChoiceInRow ); else - MenuDown( pn, type ); + row.SetOneSelection( pn, iChoiceInRow ); } + if( m_OptionsNavigation == NAV_TOGGLE_THREE_KEY ) + ChangeValueInRow( pn, -row.m_iChoiceWithFocus[pn], type != IET_FIRST_PRESS ); // move to the first choice + else + ChangeValueInRow( pn, 0, type != IET_FIRST_PRESS ); +// m_SoundChangeCol.Play(); break; case NAV_THREE_KEY_MENU: - case NAV_FIVE_KEY: /* Don't accept START to go to the next screen if we're still transitioning in. */ - if( type == IET_FIRST_PRESS && !IsTransitioning() ) // m_SMOptionsNavigation + if( type == IET_FIRST_PRESS && !IsTransitioning() ) StartGoToNextState(); break; + case NAV_FIVE_KEY: + /* Jump to the exit row. */ + MoveRow( pn, m_Rows.size()-m_iCurrentRow[pn]-1, type != IET_FIRST_PRESS ); + break; } } } +void ScreenOptions::StoreFocus( PlayerNumber pn ) +{ + if( m_OptionsNavigation != NAV_TOGGLE_FIVE_KEY ) + return; + + /* Long rows always put us in the center, so don't update the focus. */ + const Row &Row = *m_Rows[m_iCurrentRow[pn]]; + if( Row.m_bRowIsLong ) + return; + + int iWidth, iY; + GetWidthXY( pn, m_iCurrentRow[pn], m_Rows[m_iCurrentRow[pn]]->m_iChoiceWithFocus[pn], iWidth, m_iFocusX[pn], iY ); + LOG->Trace("cur selection %ix%i @ %i", m_iCurrentRow[pn], m_Rows[m_iCurrentRow[pn]]->m_iChoiceWithFocus[pn], + m_iFocusX[pn]); +} + /* Left/right */ void ScreenOptions::ChangeValueInRow( PlayerNumber pn, int iDelta, bool Repeat ) { @@ -1274,15 +1300,17 @@ void ScreenOptions::ChangeValueInRow( PlayerNumber pn, int iDelta, bool Repeat ) if( iCurrentChoiceWithFocus != iNewChoiceWithFocus ) bOneChanged = true; + row.m_iChoiceWithFocus[pn] = iNewChoiceWithFocus; + StoreFocus( pn ); + if( optrow.bOneChoiceForAllPlayers ) { - row.m_iChoiceWithFocus[pn] = iNewChoiceWithFocus; - /* If this row is bOneChoiceForAllPlayers, then lock the cursors together - * for this row. Don't do this in NAV_FIRST_CHOICE_GOES_DOWN, since the - * current selection and the current focus are detached in that mode. */ + * for this row. Don't do this in toggle modes, since the current selection + * and the current focus are detached. */ bool bForceFocusedChoiceTogether = false; - if( m_OptionsNavigation!=NAV_FIRST_CHOICE_GOES_DOWN && + if( m_OptionsNavigation!=NAV_TOGGLE_THREE_KEY && + m_OptionsNavigation!=NAV_TOGGLE_FIVE_KEY && optrow.bOneChoiceForAllPlayers ) bForceFocusedChoiceTogether = true; @@ -1294,12 +1322,15 @@ void ScreenOptions::ChangeValueInRow( PlayerNumber pn, int iDelta, bool Repeat ) { // lock focus together FOREACH_HumanPlayer( p ) + { row.m_iChoiceWithFocus[p] = iNewChoiceWithFocus; + StoreFocus( pn ); + } } FOREACH_PlayerNumber( p ) { - if( m_OptionsNavigation==NAV_FIRST_CHOICE_GOES_DOWN ) + if( m_OptionsNavigation==NAV_TOGGLE_THREE_KEY || m_OptionsNavigation==NAV_TOGGLE_FIVE_KEY ) { ; // do nothing } @@ -1314,9 +1345,7 @@ void ScreenOptions::ChangeValueInRow( PlayerNumber pn, int iDelta, bool Repeat ) } else { - row.m_iChoiceWithFocus[pn] = iNewChoiceWithFocus; - - if( m_OptionsNavigation==NAV_FIRST_CHOICE_GOES_DOWN ) + if( m_OptionsNavigation==NAV_TOGGLE_THREE_KEY || m_OptionsNavigation==NAV_TOGGLE_FIVE_KEY ) { ; // do nothing } @@ -1341,7 +1370,7 @@ void ScreenOptions::ChangeValueInRow( PlayerNumber pn, int iDelta, bool Repeat ) /* Up/down */ void ScreenOptions::MoveRow( PlayerNumber pn, int dir, bool Repeat ) { - if( m_OptionsNavigation==NAV_FIRST_CHOICE_GOES_DOWN ) + if( m_OptionsNavigation==NAV_TOGGLE_THREE_KEY ) { // If moving from a bFirstChoiceGoesDown row, put focus back on // the first choice before moving. @@ -1362,8 +1391,28 @@ void ScreenOptions::MoveRow( PlayerNumber pn, int dir, bool Repeat ) continue; // don't wrap while repeating wrap( row, m_Rows.size() ); + + const unsigned iOldSelection = m_Rows[m_iCurrentRow[p]]->m_iChoiceWithFocus[p]; + m_iCurrentRow[p] = row; + if( m_OptionsNavigation==NAV_TOGGLE_FIVE_KEY && !m_Rows[row]->m_bRowIsLong ) + { + int iSelectionDist = -1; + for( unsigned i = 0; i < m_Rows[row]->m_textItems.size(); ++i ) + { + int iWidth, iX, iY; + GetWidthXY( p, m_iCurrentRow[p], i, iWidth, iX, iY ); + const int iDist = abs( iX-m_iFocusX[p] ); + if( iSelectionDist == -1 || iDist < iSelectionDist ) + { + iSelectionDist = iDist; + m_Rows[row]->m_iChoiceWithFocus[p] = i; + } + } + m_Rows[row]->m_iChoiceWithFocus[p] = min( iOldSelection, m_Rows[row]->m_textItems.size()-1 ); + } + OnChange( (PlayerNumber)p ); changed = true; } diff --git a/stepmania/src/ScreenOptions.h b/stepmania/src/ScreenOptions.h index ef2e9ffedd..95804f7bfe 100644 --- a/stepmania/src/ScreenOptions.h +++ b/stepmania/src/ScreenOptions.h @@ -89,7 +89,7 @@ protected: protected: // derived classes need access to these void LoadOptionIcon( PlayerNumber pn, int iRow, CString sText ); - enum Navigation { NAV_THREE_KEY, NAV_THREE_KEY_MENU, NAV_FIVE_KEY, NAV_FIRST_CHOICE_GOES_DOWN }; + enum Navigation { NAV_THREE_KEY, NAV_THREE_KEY_MENU, NAV_FIVE_KEY, NAV_TOGGLE_THREE_KEY, NAV_TOGGLE_FIVE_KEY }; void SetNavigation( Navigation nav ) { m_OptionsNavigation = nav; } protected: @@ -143,6 +143,8 @@ protected: Navigation m_OptionsNavigation; int m_iCurrentRow[NUM_PLAYERS]; + int m_iFocusX[NUM_PLAYERS]; + void StoreFocus( PlayerNumber pn ); InputMode m_InputMode; diff --git a/stepmania/src/ScreenOptionsMaster.cpp b/stepmania/src/ScreenOptionsMaster.cpp index a92a1a66c0..9b48853995 100644 --- a/stepmania/src/ScreenOptionsMaster.cpp +++ b/stepmania/src/ScreenOptionsMaster.cpp @@ -234,8 +234,8 @@ ScreenOptionsMaster::ScreenOptionsMaster( CString sClassName ): } if( Flags[i] == "smnavigation" ) SetNavigation( NAV_THREE_KEY_MENU ); - if( Flags[i] == "firstchoicegoesdown" ) - SetNavigation( NAV_FIRST_CHOICE_GOES_DOWN ); + if( Flags[i] == "toggle" || Flags[i] == "firstchoicegoesdown" ) + SetNavigation( PREFSMAN->m_bArcadeOptionsNavigation? NAV_TOGGLE_THREE_KEY:NAV_TOGGLE_FIVE_KEY ); } m_OptionRowAlloc = new OptionRowData[asLineNames.size()]; @@ -287,7 +287,7 @@ ScreenOptionsMaster::ScreenOptionsMaster( CString sClassName ): } // TRICKY: Insert a down arrow as the first choice in the row. - if( m_OptionsNavigation == NAV_FIRST_CHOICE_GOES_DOWN ) + if( m_OptionsNavigation == NAV_TOGGLE_THREE_KEY ) { row.choices.insert( row.choices.begin(), ENTRY_NAME("NextRow") ); hand.ListEntries.insert( hand.ListEntries.begin(), ModeChoice() ); @@ -373,7 +373,7 @@ void ScreenOptionsMaster::ImportOption( const OptionRowData &row, const OptionRo case ROW_CONFIG: { int iSelection = hand.opt->Get( row.choices ); - SelectExactlyOne( iSelection+(m_OptionsNavigation==NAV_FIRST_CHOICE_GOES_DOWN?1:0), vbSelectedOut ); + SelectExactlyOne( iSelection+(m_OptionsNavigation==NAV_TOGGLE_THREE_KEY?1:0), vbSelectedOut ); return; } @@ -463,7 +463,7 @@ int ScreenOptionsMaster::ExportOption( const OptionRowData &row, const OptionRow case ROW_CONFIG: { - int sel = GetOneSelection(vbSelected) - (m_OptionsNavigation==NAV_FIRST_CHOICE_GOES_DOWN?1:0); + int sel = GetOneSelection(vbSelected) - (m_OptionsNavigation==NAV_TOGGLE_THREE_KEY?1:0); /* Get the original choice. */ int Original = hand.opt->Get( row.choices );