#include "global.h" #include "EditMenu.h" #include "RageLog.h" #include "SongManager.h" #include "GameState.h" #include "ThemeManager.h" #include "GameManager.h" #include "Steps.h" #include "song.h" #include "StepsUtil.h" #include "Foreach.h" #include "CommonMetrics.h" #include "BannerCache.h" #include "UnlockManager.h" #include "SongUtil.h" static const CString EditMenuRowNames[] = { "Group", "Song", "StepsType", "Steps", "SourceStepsType", "SourceSteps", "Action" }; XToString( EditMenuRow, NUM_EDIT_MENU_ROWS ); XToThemedString( EditMenuRow, NUM_EDIT_MENU_ROWS ); static const CString EditMenuActionNames[] = { "Edit", "Delete", "Create", "Practice", }; XToString( EditMenuAction, NUM_EditMenuAction ); XToThemedString( EditMenuAction, NUM_EditMenuAction ); StringToX( EditMenuAction ); static CString ARROWS_X_NAME( size_t i ) { return ssprintf("Arrows%dX",int(i+1)); } static CString ROW_VALUE_X_NAME( size_t i ) { return ssprintf("RowValue%dX",int(i+1)); } static CString ROW_Y_NAME( size_t i ) { return ssprintf("Row%dY",int(i+1)); } void EditMenu::GetSongsToShowForGroup( const CString &sGroup, vector &vpSongsOut ) { vpSongsOut.clear(); if( !SHOW_GROUPS.GetValue() ) SONGMAN->GetSongs( vpSongsOut ); else SONGMAN->GetSongs( vpSongsOut, sGroup ); switch( EDIT_MODE.GetValue() ) { case EditMode_Practice: case EditMode_Home: for( int i=vpSongsOut.size()-1; i>=0; i-- ) { const Song* pSong = vpSongsOut[i]; if( UNLOCKMAN->SongIsLocked(pSong) || pSong->IsTutorial() ) vpSongsOut.erase( vpSongsOut.begin()+i ); } break; case EditMode_Full: break; default: ASSERT(0); } SongUtil::SortSongPointerArrayByTitle( vpSongsOut ); } void EditMenu::GetGroupsToShow( vector &vsGroupsOut ) { vsGroupsOut.clear(); if( !SHOW_GROUPS.GetValue() ) return; SONGMAN->GetSongGroupNames( vsGroupsOut ); for( int i = vsGroupsOut.size()-1; i>=0; i-- ) { const CString &sGroup = vsGroupsOut[i]; vector vpSongs; GetSongsToShowForGroup( sGroup, vpSongs ); // strip groups that have no unlocked songs if( vpSongs.empty() ) vsGroupsOut.erase( vsGroupsOut.begin()+i ); } } EditMenu::EditMenu() { } EditMenu::~EditMenu() { BANNERCACHE->Undemand(); } void EditMenu::Load( const CString &sType ) { LOG->Trace( "EditMenu::Load" ); SHOW_GROUPS.Load(sType,"ShowGroups"); ARROWS_X.Load(sType,ARROWS_X_NAME,NUM_ARROWS); ARROWS_ENABLED_COLOR.Load(sType,"ArrowsEnabledColor"); ARROWS_DISABLED_COLOR.Load(sType,"ArrowsDisabledColor"); SONG_BANNER_WIDTH.Load(sType,"SongBannerWidth"); SONG_BANNER_HEIGHT.Load(sType,"SongBannerHeight"); GROUP_BANNER_WIDTH.Load(sType,"GroupBannerWidth"); GROUP_BANNER_HEIGHT.Load(sType,"GroupBannerHeight"); ROW_LABELS_X.Load(sType,"RowLabelsX"); ROW_LABEL_ON_COMMAND.Load(sType,"RowLabelOnCommand"); ROW_VALUE_X.Load(sType,ROW_VALUE_X_NAME,NUM_EDIT_MENU_ROWS); ROW_VALUE_ON_COMMAND.Load(sType,"RowValueOnCommand"); ROW_Y.Load(sType,ROW_Y_NAME,NUM_EDIT_MENU_ROWS); EDIT_MODE.Load(sType,"EditMode"); for( int i=0; i<2; i++ ) { m_sprArrows[i].Load( THEME->GetPathG(sType,i==0?"left":"right") ); m_sprArrows[i].SetX( ARROWS_X.GetValue(i) ); this->AddChild( &m_sprArrows[i] ); } m_SelectedRow = GetFirstRow(); ZERO( m_iSelection ); FOREACH_EditMenuRow( r ) { m_textLabel[r].LoadFromFont( THEME->GetPathF(sType,"title") ); m_textLabel[r].SetXY( ROW_LABELS_X, ROW_Y.GetValue(r) ); m_textLabel[r].SetText( EditMenuRowToThemedString(r) ); m_textLabel[r].RunCommands( ROW_LABEL_ON_COMMAND ); m_textLabel[r].SetHorizAlign( Actor::align_left ); this->AddChild( &m_textLabel[r] ); m_textValue[r].LoadFromFont( THEME->GetPathF(sType,"value") ); m_textValue[r].SetXY( ROW_VALUE_X.GetValue(r), ROW_Y.GetValue(r) ); m_textValue[r].SetText( "blah" ); m_textValue[r].RunCommands( ROW_VALUE_ON_COMMAND ); this->AddChild( &m_textValue[r] ); } m_textLabel[ROW_GROUP].SetHidden( !SHOW_GROUPS.GetValue() ); m_textValue[ROW_GROUP].SetHidden( !SHOW_GROUPS.GetValue() ); /* Load low-res banners, if needed. */ BANNERCACHE->Demand(); if( SHOW_GROUPS.GetValue() ) { m_GroupBanner.SetName( "GroupBanner" ); ActorUtil::SetXY( m_GroupBanner, sType ); this->AddChild( &m_GroupBanner ); } m_SongBanner.SetName( "SongBanner" ); ActorUtil::SetXY( m_SongBanner, sType ); this->AddChild( &m_SongBanner ); m_SongTextBanner.SetName( "SongTextBanner" ); m_SongTextBanner.Load( "TextBanner" ); ActorUtil::SetXY( m_SongTextBanner, sType ); this->AddChild( &m_SongTextBanner ); m_Meter.SetName( "Meter" ); m_Meter.Load( "DifficultyMeterEdit" ); ActorUtil::SetXY( m_Meter, sType ); this->AddChild( &m_Meter ); m_SourceMeter.SetName( "SourceMeter" ); m_SourceMeter.Load( "DifficultyMeterEdit" ); ActorUtil::SetXY( m_SourceMeter, sType ); this->AddChild( &m_SourceMeter ); m_soundChangeRow.Load( THEME->GetPathS(sType,"row"), true ); m_soundChangeValue.Load( THEME->GetPathS(sType,"value"), true ); // // fill in data structures // GetGroupsToShow( m_sGroups ); m_StepsTypes = CommonMetrics::STEPS_TYPES_TO_SHOW.GetValue(); RefreshAll(); } void EditMenu::RefreshAll() { ChangeToRow( GetFirstRow() ); OnRowValueChanged( (EditMenuRow)0 ); // Select the current song if any if( GAMESTATE->m_pCurSong ) { for( unsigned i=0; im_pCurSong->m_sGroupName == m_sGroups[i] ) m_iSelection[ROW_GROUP] = i; OnRowValueChanged( ROW_GROUP ); for( unsigned i=0; im_pCurSong == m_pSongs[i] ) m_iSelection[ROW_SONG] = i; OnRowValueChanged( ROW_SONG ); // Select the current StepsType and difficulty if any if( GAMESTATE->m_pCurSteps[PLAYER_1] ) { for( unsigned i=0; im_pCurSteps[PLAYER_1]->m_StepsType ) { m_iSelection[ROW_STEPS_TYPE] = i; OnRowValueChanged( ROW_STEPS_TYPE ); } } for( unsigned i=0; im_pCurSteps[PLAYER_1] ) { m_iSelection[ROW_STEPS] = i; OnRowValueChanged( ROW_STEPS ); } } } } } bool EditMenu::CanGoUp() { return m_SelectedRow != GetFirstRow(); } bool EditMenu::CanGoDown() { return m_SelectedRow != NUM_EDIT_MENU_ROWS-1; } bool EditMenu::CanGoLeft() { if( m_SelectedRow == ROW_SONG ) return true; /* wraps */ return m_iSelection[m_SelectedRow] != 0; } int EditMenu::GetRowSize( EditMenuRow er ) const { switch( er ) { case ROW_GROUP: return m_sGroups.size(); case ROW_SONG: return m_pSongs.size(); case ROW_STEPS_TYPE: return m_StepsTypes.size(); case ROW_STEPS: return m_vpSteps.size(); case ROW_SOURCE_STEPS_TYPE: return m_StepsTypes.size(); case ROW_SOURCE_STEPS: return m_vpSourceSteps.size(); case ROW_ACTION: return m_Actions.size(); default: FAIL_M( ssprintf("%i", er) ); } } bool EditMenu::CanGoRight() { if( m_SelectedRow == ROW_SONG ) return true; /* wraps */ return m_iSelection[m_SelectedRow] != GetRowSize(m_SelectedRow)-1; } void EditMenu::Up() { if( CanGoUp() ) { if( GetSelectedSteps() && m_SelectedRow==ROW_ACTION ) ChangeToRow( ROW_STEPS ); else ChangeToRow( EditMenuRow(m_SelectedRow-1) ); m_soundChangeRow.Play(); } } void EditMenu::Down() { if( CanGoDown() ) { if( GetSelectedSteps() && m_SelectedRow==ROW_STEPS ) ChangeToRow( ROW_ACTION ); else ChangeToRow( EditMenuRow(m_SelectedRow+1) ); m_soundChangeRow.Play(); } } void EditMenu::Left() { if( CanGoLeft() ) { m_iSelection[m_SelectedRow]--; wrap( m_iSelection[m_SelectedRow], GetRowSize(m_SelectedRow) ); OnRowValueChanged( m_SelectedRow ); m_soundChangeValue.Play(); } } void EditMenu::Right() { if( CanGoRight() ) { m_iSelection[m_SelectedRow]++; wrap( m_iSelection[m_SelectedRow], GetRowSize(m_SelectedRow) ); OnRowValueChanged( m_SelectedRow ); m_soundChangeValue.Play(); } } void EditMenu::ChangeToRow( EditMenuRow newRow ) { m_SelectedRow = newRow; for( int i=0; i<2; i++ ) m_sprArrows[i].SetY( ROW_Y.GetValue(newRow) ); UpdateArrows(); } void EditMenu::UpdateArrows() { m_sprArrows[0].SetDiffuse( CanGoLeft() ? ARROWS_ENABLED_COLOR : ARROWS_DISABLED_COLOR ); m_sprArrows[1].SetDiffuse( CanGoRight()? ARROWS_ENABLED_COLOR : ARROWS_DISABLED_COLOR ); m_sprArrows[0].EnableAnimation( CanGoLeft() ); m_sprArrows[1].EnableAnimation( CanGoRight() ); } void EditMenu::OnRowValueChanged( EditMenuRow row ) { UpdateArrows(); switch( row ) { case ROW_GROUP: m_textValue[ROW_GROUP].SetText( SONGMAN->ShortenGroupName(GetSelectedGroup()) ); if( SHOW_GROUPS.GetValue() ) { m_GroupBanner.LoadFromSongGroup( GetSelectedGroup() ); m_GroupBanner.ScaleToClipped( GROUP_BANNER_WIDTH, GROUP_BANNER_HEIGHT ); } m_pSongs.clear(); GetSongsToShowForGroup( GetSelectedGroup(), m_pSongs ); m_iSelection[ROW_SONG] = 0; // fall through case ROW_SONG: m_textValue[ROW_SONG].SetText( "" ); m_SongBanner.LoadFromSong( GetSelectedSong() ); m_SongBanner.ScaleToClipped( SONG_BANNER_WIDTH, SONG_BANNER_HEIGHT ); m_SongTextBanner.LoadFromSong( GetSelectedSong() ); // fall through case ROW_STEPS_TYPE: m_textValue[ROW_STEPS_TYPE].SetText( GAMEMAN->StepsTypeToThemedString(GetSelectedStepsType()) ); m_vpSteps.clear(); FOREACH_Difficulty( dc ) { if( dc == DIFFICULTY_EDIT ) { switch( EDIT_MODE.GetValue() ) { case EditMode_Full: case EditMode_Practice: { vector v; GetSelectedSong()->GetSteps( v, GetSelectedStepsType(), DIFFICULTY_EDIT ); StepsUtil::SortStepsByDescription( v ); FOREACH_CONST( Steps*, v, p ) m_vpSteps.push_back( StepsAndDifficulty(*p,dc) ); } break; case EditMode_Home: // have only "New Edit" break; default: ASSERT(0); } switch( EDIT_MODE.GetValue() ) { case EditMode_Practice: break; case EditMode_Home: case EditMode_Full: m_vpSteps.push_back( StepsAndDifficulty(NULL,dc) ); // "New Edit" break; default: ASSERT(0); } } else { Steps *pSteps = GetSelectedSong()->GetStepsByDifficulty( GetSelectedStepsType(), dc ); if( pSteps && UNLOCKMAN->StepsIsLocked( GetSelectedSong(), pSteps ) ) pSteps = NULL; switch( EDIT_MODE.GetValue() ) { case EditMode_Home: // don't allow selecting of non-edits in HomeMode break; case EditMode_Practice: // only show this difficulty if steps exist if( pSteps ) m_vpSteps.push_back( StepsAndDifficulty(pSteps,dc) ); break; case EditMode_Full: // show this difficulty whether or not steps exist. m_vpSteps.push_back( StepsAndDifficulty(pSteps,dc) ); break; default: ASSERT(0); } } } CLAMP( m_iSelection[ROW_STEPS], 0, m_vpSteps.size()-1 ); // fall through case ROW_STEPS: { CString s; Steps *pSteps = GetSelectedSteps(); if( pSteps && GetSelectedDifficulty() == DIFFICULTY_EDIT ) { if( pSteps->GetDescription().empty() ) s += "-no name-"; else s += pSteps->GetDescription(); s += " (" + DifficultyToThemedString(DIFFICULTY_EDIT) + ")"; } else { s = DifficultyToThemedString(GetSelectedDifficulty()); // UGLY. "Edit" -> "New Edit" switch( EDIT_MODE.GetValue() ) { case EditMode_Home: s = "New " + s; break; case EditMode_Practice: case EditMode_Full: break; default: ASSERT(0); } } m_textValue[ROW_STEPS].SetText( s ); } if( GetSelectedSteps() ) m_Meter.SetFromSteps( GetSelectedSteps() ); else m_Meter.SetFromMeterAndDifficulty( 0, GetSelectedDifficulty() ); // fall through case ROW_SOURCE_STEPS_TYPE: m_textLabel[ROW_SOURCE_STEPS_TYPE].SetHidden( GetSelectedSteps() ? true : false ); m_textValue[ROW_SOURCE_STEPS_TYPE].SetHidden( GetSelectedSteps() ? true : false ); m_textValue[ROW_SOURCE_STEPS_TYPE].SetText( GAMEMAN->StepsTypeToThemedString(GetSelectedSourceStepsType()) ); m_vpSourceSteps.clear(); m_vpSourceSteps.push_back( StepsAndDifficulty(NULL,DIFFICULTY_INVALID) ); // "blank" FOREACH_Difficulty( dc ) { // fill in pSteps if( dc != DIFFICULTY_EDIT ) { Steps *pSteps = GetSelectedSong()->GetStepsByDifficulty( GetSelectedSourceStepsType(), dc ); m_vpSourceSteps.push_back( StepsAndDifficulty(pSteps,dc) ); } else { vector v; GetSelectedSong()->GetSteps( v, GetSelectedSourceStepsType(), dc ); StepsUtil::SortStepsByDescription( v ); FOREACH_CONST( Steps*, v, pSteps ) m_vpSourceSteps.push_back( StepsAndDifficulty(*pSteps,dc) ); if( v.empty() ) m_vpSourceSteps.push_back( StepsAndDifficulty(NULL,dc) ); } } CLAMP( m_iSelection[ROW_SOURCE_STEPS], 0, m_vpSourceSteps.size()-1 ); // fall through case ROW_SOURCE_STEPS: { m_textLabel[ROW_SOURCE_STEPS].SetHidden( GetSelectedSteps() ? true : false ); m_textValue[ROW_SOURCE_STEPS].SetHidden( GetSelectedSteps() ? true : false ); { CString s; Steps *pSourceSteps = GetSelectedSourceSteps(); if( GetSelectedSourceDifficulty() == DIFFICULTY_INVALID ) s = "Blank"; else if( pSourceSteps && GetSelectedSourceDifficulty() == DIFFICULTY_EDIT ) s = pSourceSteps->GetDescription() + " (" + DifficultyToThemedString(DIFFICULTY_EDIT) + ")"; else s = DifficultyToThemedString(GetSelectedSourceDifficulty()); m_textValue[ROW_SOURCE_STEPS].SetText( s ); } bool bHideMeter = false; if( GetSelectedSourceDifficulty() == DIFFICULTY_INVALID ) bHideMeter = true; else if( GetSelectedSourceSteps() ) m_SourceMeter.SetFromSteps( GetSelectedSourceSteps() ); else m_SourceMeter.SetFromMeterAndDifficulty( 0, GetSelectedSourceDifficulty() ); m_SourceMeter.SetHidden( (bHideMeter || GetSelectedSteps()) ); m_Actions.clear(); if( GetSelectedSteps() ) { switch( EDIT_MODE.GetValue() ) { case EditMode_Practice: m_Actions.push_back( EditMenuAction_Practice ); break; case EditMode_Home: case EditMode_Full: m_Actions.push_back( EditMenuAction_Edit ); m_Actions.push_back( EditMenuAction_Delete ); break; default: ASSERT(0); } } else { m_Actions.push_back( EditMenuAction_Create ); } m_iSelection[ROW_ACTION] = 0; } // fall through case ROW_ACTION: m_textValue[ROW_ACTION].SetText( EditMenuActionToThemedString(GetSelectedAction()) ); break; default: ASSERT(0); // invalid row } } /* * (c) 2001-2004 Chris Danford * 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. */