From 9505e09f581e70874f61e839da38aa6851258605 Mon Sep 17 00:00:00 2001 From: Jason Felds Date: Tue, 26 Jul 2011 16:05:14 -0400 Subject: [PATCH] Add the copy/paste selected timing data feature. Not perfect at this stage, but...well, everyone wanted it. --- Docs/Changelog_sm5.txt | 6 +++ Themes/_fallback/Languages/en.ini | 1 + src/ScreenEdit.cpp | 83 ++++++++++++++++++++++++++++++- src/ScreenEdit.h | 11 ++-- src/TimingData.cpp | 76 +++++++++++++++++++++++++--- 5 files changed, 162 insertions(+), 15 deletions(-) diff --git a/Docs/Changelog_sm5.txt b/Docs/Changelog_sm5.txt index 63a8649366..adc2ddb5fa 100644 --- a/Docs/Changelog_sm5.txt +++ b/Docs/Changelog_sm5.txt @@ -8,6 +8,12 @@ ________________________________________________________________________________ StepMania 5.0 ????????? | 20110??? -------------------------------------------------------------------------------- +2011/07/26 +---------- +* [ScreenEdit] Add a semi working implementation of the often requested + copy/paste selected timing data feature. This should make it easier for + some charters. [Wolfman2000] + 2011/07/21 ---------- * [BeginnerHelper] Removed DancePadAngle metric in favor of DancePadOnCommand. diff --git a/Themes/_fallback/Languages/en.ini b/Themes/_fallback/Languages/en.ini index 7c634f71cc..8e1223cc1b 100644 --- a/Themes/_fallback/Languages/en.ini +++ b/Themes/_fallback/Languages/en.ini @@ -975,6 +975,7 @@ OsMountPlayer2=OS Mount Player2 Paste at begin marker=Paste at begin marker Paste at current beat=Paste at current beat Paste timing data=Paste timing data +Paste Partial Timing at current beat=Paste Partial Timing at current beat Persp=Persp Play current beat to end=Play current beat to end Play preview music=Play preview music diff --git a/src/ScreenEdit.cpp b/src/ScreenEdit.cpp index 2ecf2fc9c3..356bd909fd 100644 --- a/src/ScreenEdit.cpp +++ b/src/ScreenEdit.cpp @@ -588,7 +588,8 @@ static MenuDef g_AreaMenu( "ScreenMiniMenuAreaMenu", MenuRowDef( ScreenEdit::paste_at_current_beat, "Paste at current beat", true, EditMode_Practice, true, true, 0, NULL ), MenuRowDef( ScreenEdit::paste_at_begin_marker, "Paste at begin marker", true, EditMode_Practice, true, true, 0, NULL ), - MenuRowDef( ScreenEdit::insert_and_shift, "Insert beat and shift down", true, EditMode_Practice, true, true, 0, NULL ), + MenuRowDef( ScreenEdit::paste_partial_timing_at_beat, "Paste Partial Timing at current beat", true, EditMode_Practice, true, true, 0, NULL ), + MenuRowDef( ScreenEdit::insert_and_shift, "Insert beat and shift down", true, EditMode_Practice, true, true, 0, NULL ), MenuRowDef( ScreenEdit::delete_and_shift, "Delete beat and shift up", true, EditMode_Practice, true, true, 0, NULL ), MenuRowDef( ScreenEdit::shift_pauses_forward, "Shift all timing changes down", true, EditMode_Full, true, true, 0, NULL ), MenuRowDef( ScreenEdit::shift_pauses_backward, "Shift all timing changes up", true, EditMode_Full, true, true, 0, NULL ), @@ -1742,6 +1743,7 @@ void ScreenEdit::InputEdit( const InputEventPlus &input, EditButton EditB ) // update enabled/disabled in g_AreaMenu g_AreaMenu.rows[paste_at_current_beat].bEnabled = !m_Clipboard.IsEmpty(); g_AreaMenu.rows[paste_at_begin_marker].bEnabled = !m_Clipboard.IsEmpty() != 0 && m_NoteFieldEdit.m_iBeginMarker!=-1; + g_AreaMenu.rows[paste_partial_timing_at_beat].bEnabled = !this->clipboardTiming.empty(); g_AreaMenu.rows[undo].bEnabled = m_bHasUndo; EditMiniMenu( &g_AreaMenu, SM_BackFromAreaMenu ); } @@ -2926,7 +2928,9 @@ void ScreenEdit::HandleScreenMessage( const ScreenMessage SM ) } else if( SM == SM_BackFromAreaMenu ) { - HandleAreaMenuChoice( (AreaMenuChoice)ScreenMiniMenu::s_iLastRowCode, ScreenMiniMenu::s_viLastAnswers ); + AreaMenuChoice amc = static_cast(ScreenMiniMenu::s_iLastRowCode); + const vector &answers = ScreenMiniMenu::s_viLastAnswers; + HandleAreaMenuChoice( amc, answers ); } else if( SM == SM_BackFromAlterMenu ) { @@ -4305,6 +4309,81 @@ void ScreenEdit::HandleAreaMenuChoice( AreaMenuChoice c, const vector &iAns m_NoteDataEdit.CopyRange( m_Clipboard, 0, iRowsToCopy, iDestFirstRow ); } break; + case paste_partial_timing_at_beat: + { + int firstRow = BeatToNoteRow(GetAppropriatePosition().m_fSongBeat); + FOREACH_ENUM(TimingSegmentType, tst) + { + /* TODO: Maybe wipe out the already there timing data first? + * We need to identify the max row within the timing data first. */ + for (unsigned i = 0; i < this->clipboardTiming.allTimingSegments[tst].size(); i++) + { + // TODO: This REALLY needs improving. + TimingSegment * org = this->clipboardTiming.allTimingSegments[tst][i]; + TimingSegment * cpy; + + switch (tst) + { + case SEGMENT_BPM: + { + cpy = new BPMSegment(*(static_cast(org))); + break; + } + case SEGMENT_STOP_DELAY: + { + cpy = new StopSegment(*(static_cast(org))); + break; + } + case SEGMENT_TIME_SIG: + { + cpy = new TimeSignatureSegment(*(static_cast(org))); + break; + } + case SEGMENT_WARP: + { + cpy = new WarpSegment(*(static_cast(org))); + break; + } + case SEGMENT_LABEL: + { + cpy = new LabelSegment(*(static_cast(org))); + break; + } + case SEGMENT_TICKCOUNT: + { + cpy = new TickcountSegment(*(static_cast(org))); + break; + } + case SEGMENT_COMBO: + { + cpy = new ComboSegment(*(static_cast(org))); + break; + } + case SEGMENT_SPEED: + { + cpy = new SpeedSegment(*(static_cast(org))); + break; + } + case SEGMENT_SCROLL: + { + cpy = new ScrollSegment(*(static_cast(org))); + break; + } + case SEGMENT_FAKE: + { + cpy = new FakeSegment(*(static_cast(org))); + break; + } + default: FAIL_M(ssprintf("An unknown timing segment type %d can't be copied over!", tst)); + } + int oldRow = cpy->GetRow(); + int newRow = oldRow + firstRow; + cpy->SetRow(newRow); + GetAppropriateTiming().AddSegment(tst, cpy); + } + } + break; + } case insert_and_shift: NoteDataUtil::InsertRows( m_NoteDataEdit, BeatToNoteRow( GetBeat() ), BeatToNoteRow(1) ); break; diff --git a/src/ScreenEdit.h b/src/ScreenEdit.h index a2a4add92b..0749344f05 100644 --- a/src/ScreenEdit.h +++ b/src/ScreenEdit.h @@ -423,17 +423,18 @@ public: enum AreaMenuChoice { - paste_at_current_beat, - paste_at_begin_marker, + paste_at_current_beat, /**< Paste note data starting at the current beat. */ + paste_at_begin_marker, /**< Paste note data starting at the first market. */ + paste_partial_timing_at_beat, /**< Paste TimingData starting at the current beat. */ insert_and_shift, delete_and_shift, - shift_pauses_forward, - shift_pauses_backward, + shift_pauses_forward, /**< Shift all timing changes forward one beat. */ + shift_pauses_backward, /**< Shift all timing changes backward one beat. */ convert_pause_to_beat, convert_delay_to_beat, last_second_at_beat, undo, - clear_clipboard, + clear_clipboard, /**< Clear the clipboards. */ NUM_AREA_MENU_CHOICES }; void HandleAlterMenuChoice(AlterMenuChoice c, diff --git a/src/TimingData.cpp b/src/TimingData.cpp index d087616b2c..f15e564934 100644 --- a/src/TimingData.cpp +++ b/src/TimingData.cpp @@ -29,22 +29,83 @@ bool TimingData::empty() const TimingData TimingData::CopyRange(int startRow, int endRow) const { - TimingData tmp; + TimingData ret; - for (unsigned i = 0; i < NUM_TimingSegmentType; i++) + FOREACH_ENUM(TimingSegmentType, tst) { - for (unsigned j = 0; j < this->allTimingSegments[i].size(); j++) + unsigned cnt = 0; + for (unsigned j = 0; j < this->allTimingSegments[tst].size(); j++) { - int row = this->allTimingSegments[i][j]->GetRow(); + int row = this->allTimingSegments[tst][j]->GetRow(); if (row >= startRow && row < endRow) { - tmp.AddSegment(static_cast(i), - this->allTimingSegments[i][j]); + // TODO: This REALLY needs improving. + TimingSegment * org = this->allTimingSegments[tst][j]; + TimingSegment * cpy; + + switch (tst) + { + case SEGMENT_BPM: + { + cpy = new BPMSegment(*(static_cast(org))); + break; + } + case SEGMENT_STOP_DELAY: + { + cpy = new StopSegment(*(static_cast(org))); + break; + } + case SEGMENT_TIME_SIG: + { + cpy = new TimeSignatureSegment(*(static_cast(org))); + break; + } + case SEGMENT_WARP: + { + cpy = new WarpSegment(*(static_cast(org))); + break; + } + case SEGMENT_LABEL: + { + cpy = new LabelSegment(*(static_cast(org))); + break; + } + case SEGMENT_TICKCOUNT: + { + cpy = new TickcountSegment(*(static_cast(org))); + break; + } + case SEGMENT_COMBO: + { + cpy = new ComboSegment(*(static_cast(org))); + break; + } + case SEGMENT_SPEED: + { + cpy = new SpeedSegment(*(static_cast(org))); + break; + } + case SEGMENT_SCROLL: + { + cpy = new ScrollSegment(*(static_cast(org))); + break; + } + case SEGMENT_FAKE: + { + cpy = new FakeSegment(*(static_cast(org))); + break; + } + default: FAIL_M(ssprintf("An unknown timing segment type %d can't be copied over!", tst)); + } + // reset the rows as if startRow was beat 0. + cpy->SetRow(org->GetRow() - startRow); + ret.AddSegment(tst, cpy); + cnt++; } } } - return tmp; + return ret; } void TimingData::GetActualBPM( float &fMinBPMOut, float &fMaxBPMOut, float highest ) const @@ -655,7 +716,6 @@ bool TimingData::IsFakeAtRow( int iNoteRow ) const BPMSegment* TimingData::GetBPMSegmentAtRow( int iNoteRow ) { vector &bpms = this->allTimingSegments[SEGMENT_BPM]; - static BPMSegment empty; if( bpms.empty() ) return new BPMSegment();