Added timing menu options to Edit Mode that allow shifting and copying timing segments of a chosen type in the selected region or everywhere below the cursor.

This commit is contained in:
Kyzentun
2015-04-04 09:10:00 -06:00
parent 2f1a348565
commit 9e5081476f
9 changed files with 321 additions and 18 deletions
+158 -9
View File
@@ -94,6 +94,7 @@ AutoScreenMessage( SM_DoRevertToLastSave );
AutoScreenMessage( SM_DoRevertFromDisk );
AutoScreenMessage( SM_ConfirmClearArea );
AutoScreenMessage( SM_BackFromTimingDataInformation );
AutoScreenMessage(SM_BackFromTimingDataChangeInformation);
AutoScreenMessage( SM_BackFromDifficultyMeterChange );
AutoScreenMessage( SM_BackFromBeat0Change );
AutoScreenMessage( SM_BackFromBPMChange );
@@ -1033,6 +1034,18 @@ static MenuDef g_TimingDataInformation(
MenuRowDef(ScreenEdit::fake,
"Edit fake",
true, EditMode_Full, true, true, 0, NULL ),
MenuRowDef(ScreenEdit::shift_timing_in_region_down,
"Shift timing in region down",
true, EditMode_Full, true, true, 0, "4th","8th","12th","16th","24th","32nd","48th","64th","192nd"),
MenuRowDef(ScreenEdit::shift_timing_in_region_up,
"Shift timing in region up",
true, EditMode_Full, true, true, 0, "4th","8th","12th","16th","24th","32nd","48th","64th","192nd"),
MenuRowDef(ScreenEdit::copy_timing_in_region,
"Copy timing in region",
true, EditMode_Full, true, true, 0, NULL),
MenuRowDef(ScreenEdit::paste_timing_from_clip,
"Paste timing from clipboard",
true, EditMode_Full, true, true, 0, NULL),
MenuRowDef(ScreenEdit::copy_full_timing,
"Copy timing data",
true, EditMode_Full, true, true, 0, NULL ),
@@ -1044,6 +1057,47 @@ static MenuDef g_TimingDataInformation(
true, EditMode_Full, true, true, 0, NULL )
);
static MenuDef g_TimingDataChangeInformation(
"ScreenMiniMenuTimingDataChangeInformation",
MenuRowDef(ScreenEdit::timing_all,
"All timing",
true, EditMode_Full, true, true, 0, NULL),
MenuRowDef(ScreenEdit::timing_bpm,
"BPM changes",
true, EditMode_Full, true, true, 0, NULL),
MenuRowDef(ScreenEdit::timing_stop,
"Stops",
true, EditMode_Full, true, true, 0, NULL),
MenuRowDef(ScreenEdit::timing_delay,
"Delays",
true, EditMode_Full, true, true, 0, NULL),
// Time signatures disabled because they don't fully work. -Kyz
// MenuRowDef(ScreenEdit::timing_time_sig,
// "Time Signatures",
// true, EditMode_Full, true, true, 0, NULL),
MenuRowDef(ScreenEdit::timing_warp,
"Warps",
true, EditMode_Full, true, true, 0, NULL),
MenuRowDef(ScreenEdit::timing_label,
"Labels",
true, EditMode_Full, true, true, 0, NULL),
MenuRowDef(ScreenEdit::timing_tickcount,
"Tickcount",
true, EditMode_Full, true, true, 0, NULL),
MenuRowDef(ScreenEdit::timing_combo,
"Combo segments",
true, EditMode_Full, true, true, 0, NULL),
MenuRowDef(ScreenEdit::timing_speed,
"Speed segments",
true, EditMode_Full, true, true, 0, NULL),
MenuRowDef(ScreenEdit::timing_scroll,
"Scroll segments",
true, EditMode_Full, true, true, 0, NULL),
MenuRowDef(ScreenEdit::timing_fake,
"Fakes",
true, EditMode_Full, true, true, 0, NULL)
);
// XXX: What are these enums used for?
enum
{
@@ -3541,6 +3595,10 @@ void ScreenEdit::HandleScreenMessage( const ScreenMessage SM )
{
HandleTimingDataInformationChoice( (TimingDataInformationChoice)ScreenMiniMenu::s_iLastRowCode, ScreenMiniMenu::s_viLastAnswers );
}
else if(SM == SM_BackFromTimingDataChangeInformation)
{
HandleTimingDataChangeChoice((TimingDataChangeChoice)ScreenMiniMenu::s_iLastRowCode, ScreenMiniMenu::s_viLastAnswers);
}
else if( SM == SM_BackFromDifficultyMeterChange )
{
int i = StringToInt( ScreenTextEntry::s_sLastAnswer );
@@ -4628,6 +4686,12 @@ void ScreenEdit::DisplayTimingMenu()
EditMiniMenu( &g_TimingDataInformation, SM_BackFromTimingDataInformation );
}
void ScreenEdit::DisplayTimingChangeMenu()
{
int row= GetRow();
EditMiniMenu(&g_TimingDataChangeInformation, SM_BackFromTimingDataChangeInformation);
}
// End helper functions
static LocalizedString REVERT_LAST_SAVE ( "ScreenEdit", "Do you want to revert to your last save?" );
@@ -5303,6 +5367,13 @@ void ScreenEdit::HandleAlterMenuChoice(AlterMenuChoice c, const vector<int> &iAn
}
int GetRowsFromAnswers(int choice, const vector<int>& answers);
int GetRowsFromAnswers(int choice, const vector<int>& answers)
{
// Logic courtesy of someone else, not me. Just deduplicating it. -Kyz
return answers.size() > 0 ? NoteTypeToRow((NoteType)answers[choice]) : 48;
}
void ScreenEdit::HandleAreaMenuChoice( AreaMenuChoice c, const vector<int> &iAnswers, bool bAllowUndo )
{
bool bSaveUndo = true;
@@ -5355,23 +5426,19 @@ void ScreenEdit::HandleAreaMenuChoice( AreaMenuChoice c, const vector<int> &iAns
case insert_and_shift:
NoteDataUtil::InsertRows( m_NoteDataEdit, GetRow(),
iAnswers.size() > 0 ?
NoteTypeToRow((NoteType)iAnswers[c]) : 48);
GetRowsFromAnswers(c, iAnswers));
break;
case delete_and_shift:
NoteDataUtil::DeleteRows( m_NoteDataEdit, GetRow(),
iAnswers.size() > 0 ?
NoteTypeToRow((NoteType)iAnswers[c]) : 48);
GetRowsFromAnswers(c, iAnswers));
break;
case shift_pauses_forward:
GetAppropriateTimingForUpdate().InsertRows( GetRow(),
iAnswers.size() > 0 ?
NoteTypeToRow((NoteType)iAnswers[c]) : 48);
GetRowsFromAnswers(c, iAnswers));
break;
case shift_pauses_backward:
GetAppropriateTimingForUpdate().DeleteRows( GetRow(),
iAnswers.size() > 0 ?
NoteTypeToRow((NoteType)iAnswers[c]) : 48);
GetRowsFromAnswers(c, iAnswers));
break;
case convert_pause_to_beat:
@@ -5501,7 +5568,7 @@ void ScreenEdit::HandleStepsInformationChoice( StepsInformationChoice c, const v
ENTER_NEW_METER,
ssprintf("%d", m_pSteps->GetMeter()),
4,
NULL,
ScreenTextEntry::IntValidate,
ChangeStepMeter,
NULL);
break;
@@ -5747,6 +5814,23 @@ void ScreenEdit::HandleTimingDataInformationChoice( TimingDataInformationChoice
);
break;
}
case shift_timing_in_region_down:
m_timing_is_being_copied= false;
m_timing_rows_being_shitted= GetRowsFromAnswers(c, iAnswers);
DisplayTimingChangeMenu();
break;
case shift_timing_in_region_up:
m_timing_is_being_copied= false;
m_timing_rows_being_shitted= -GetRowsFromAnswers(c, iAnswers);
DisplayTimingChangeMenu();
break;
case copy_timing_in_region:
m_timing_is_being_copied= true;
DisplayTimingChangeMenu();
break;
case paste_timing_from_clip:
clipboardFullTiming.CopyRange(0, MAX_NOTE_ROW, TimingSegmentType_Invalid, GetRow(), GetAppropriateTimingForUpdate());
break;
case copy_full_timing:
{
clipboardFullTiming = GetAppropriateTiming();
@@ -5772,6 +5856,71 @@ void ScreenEdit::HandleTimingDataInformationChoice( TimingDataInformationChoice
}
}
void ScreenEdit::HandleTimingDataChangeChoice(TimingDataChangeChoice choice,
const vector<int>& answers)
{
TimingSegmentType change_type= TimingSegmentType_Invalid;
switch(choice)
{
case timing_all:
change_type= TimingSegmentType_Invalid;
break;
case timing_bpm:
change_type= SEGMENT_BPM;
break;
case timing_stop:
change_type= SEGMENT_STOP;
break;
case timing_delay:
change_type= SEGMENT_DELAY;
break;
case timing_time_sig:
change_type= SEGMENT_TIME_SIG;
break;
case timing_warp:
change_type= SEGMENT_WARP;
break;
case timing_label:
change_type= SEGMENT_LABEL;
break;
case timing_tickcount:
change_type= SEGMENT_TICKCOUNT;
break;
case timing_combo:
change_type= SEGMENT_COMBO;
break;
case timing_speed:
change_type= SEGMENT_SPEED;
break;
case timing_scroll:
change_type= SEGMENT_SCROLL;
break;
case timing_fake:
change_type= SEGMENT_FAKE;
break;
default: break;
}
int begin= m_NoteFieldEdit.m_iBeginMarker;
int end= m_NoteFieldEdit.m_iEndMarker;
if(begin < 0)
{
begin= GetRow();
}
if(end < 0)
{
end= MAX_NOTE_ROW;
}
if(m_timing_is_being_copied)
{
clipboardFullTiming.Clear();
GetAppropriateTiming().CopyRange(begin, end, change_type, 0, clipboardFullTiming);
}
else
{
GetAppropriateTimingForUpdate().ShiftRange(begin, end, change_type, m_timing_rows_being_shitted);
}
}
void ScreenEdit::HandleBGChangeChoice( BGChangeChoice c, const vector<int> &iAnswers )
{
BackgroundChange newChange;
+28 -2
View File
@@ -268,6 +268,10 @@ protected:
/** @brief Display the TimingData menu for editing song and step timing. */
void DisplayTimingMenu();
bool m_timing_is_being_copied; // Instead of being shifted.
int m_timing_rows_being_shitted; // How far the timing is being shitted.
void DisplayTimingChangeMenu();
EditState m_EditState;
Song* m_pSong;
@@ -603,15 +607,37 @@ public:
speed_mode,
scroll,
fake,
shift_timing_in_region_down,
shift_timing_in_region_up,
copy_timing_in_region,
paste_timing_from_clip,
copy_full_timing,
paste_full_timing,
erase_step_timing,
NUM_TIMING_DATA_INFORMATION_CHOICES
};
void HandleTimingDataInformationChoice (TimingDataInformationChoice c,
void HandleTimingDataInformationChoice (TimingDataInformationChoice c,
const vector<int> &iAnswers );
enum TimingDataChangeChoice
{
timing_all,
timing_bpm,
timing_stop,
timing_delay,
timing_time_sig,
timing_warp,
timing_label,
timing_tickcount,
timing_combo,
timing_speed,
timing_scroll,
timing_fake,
NUM_TimingDataChangeChoices
};
void HandleTimingDataChangeChoice(TimingDataChangeChoice choice,
const vector<int>& answers);
enum BGChangeChoice
{
layer,
+10
View File
@@ -108,6 +108,16 @@ bool ScreenTextEntry::FloatValidate( const RString &sAnswer, RString &sErrorOut
return false;
}
static LocalizedString INVALID_INT( "ScreenTextEntry", "\"%s\" is an invalid integer value." );
bool ScreenTextEntry::IntValidate( const RString &sAnswer, RString &sErrorOut )
{
int f;
if(sAnswer >> f)
return true;
sErrorOut = ssprintf( INVALID_INT.GetValue(), sAnswer.c_str() );
return false;
}
bool ScreenTextEntry::s_bCancelledLast = false;
/* Handle UTF-8. Right now, we need to at least be able to backspace a whole
+1
View File
@@ -97,6 +97,7 @@ public:
void LoadFromTextEntrySettings( const TextEntrySettings &settings );
static bool FloatValidate( const RString &sAnswer, RString &sErrorOut );
static bool IntValidate( const RString &sAnswer, RString &sErrorOut );
virtual void Init();
virtual void BeginScreen();
+69 -2
View File
@@ -8,6 +8,9 @@
#include "Foreach.h"
#include <float.h>
static void EraseSegment(vector<TimingSegment*> &vSegs, int index, TimingSegment *cur);
static const int INVALID_INDEX = -1;
TimingSegment* GetSegmentAtRow( int iNoteRow, TimingSegmentType tst );
TimingData::TimingData(float fOffset) : m_fBeat0OffsetInSeconds(fOffset)
@@ -189,6 +192,72 @@ void TimingData::CopyRange(int start_row, int end_row,
}
}
void TimingData::ShiftRange(int start_row, int end_row,
TimingSegmentType shift_type, int shift_amount)
{
FOREACH_TimingSegmentType(seg_type)
{
if(seg_type == shift_type || shift_type == TimingSegmentType_Invalid)
{
vector<TimingSegment*>& segs= GetTimingSegments(seg_type);
int first_row= min(start_row, start_row + shift_amount);
int last_row= max(end_row, end_row + shift_amount);
int first_affected= GetSegmentIndexAtRow(seg_type, first_row);
int last_affected= GetSegmentIndexAtRow(seg_type, last_row);
if(first_affected == INVALID_INDEX)
{
continue;
}
// Prance through the affected area twice. The first time, changing
// the rows of the segments, the second time removing segments that
// have been run over by a segment being moved. Attempts to combine
// both operations into a single loop were error prone. -Kyz
for(size_t i= first_affected; i <= last_affected && i < segs.size(); ++i)
{
int seg_row= segs[i]->GetRow();
if(seg_row > 0 && seg_row >= start_row && seg_row <= end_row)
{
int dest_row= max(seg_row + shift_amount, 0);
segs[i]->SetRow(dest_row);
}
}
#define ERASE_SEG(s) if(segs.size() > 1) { EraseSegment(segs, s, segs[s]); --i; --last_affected; erased= true; }
for(size_t i= first_affected; i <= last_affected && i < segs.size(); ++i)
{
bool erased= false;
int seg_row= segs[i]->GetRow();
if(i < segs.size() - 1)
{
int next_row= segs[i+1]->GetRow();
// This is a loop so that it will go back through and remove all
// segments that were run over. -Kyz
while(seg_row >= next_row && seg_row < start_row)
{
ERASE_SEG(i);
if(i < segs.size())
{
seg_row= segs[i]->GetRow();
}
else
{
seg_row= -1;
}
}
}
if(!erased && i > 0)
{
int prev_row= segs[i-1]->GetRow();
if(prev_row >= seg_row)
{
ERASE_SEG(i);
}
}
}
#undef ERASE_SEG
}
}
}
void TimingData::GetActualBPM( float &fMinBPMOut, float &fMaxBPMOut, float highest ) const
{
fMinBPMOut = FLT_MAX;
@@ -232,8 +301,6 @@ float TimingData::GetPreviousSegmentBeatAtRow(TimingSegmentType tst, int row) co
return (backup > -1) ? backup : NoteRowToBeat(row);
}
static const int INVALID_INDEX = -1;
int TimingData::GetSegmentIndexAtRow(TimingSegmentType tst, int iRow ) const
{
const vector<TimingSegment*> &vSegs = GetTimingSegments(tst);
+1
View File
@@ -150,6 +150,7 @@ public:
bool empty() const;
void CopyRange(int start_row, int end_row, TimingSegmentType copy_type, int dest_row, TimingData& dest) const;
void ShiftRange(int start_row, int end_row, TimingSegmentType shift_type, int shift_amount);
/**
* @brief Gets the actual BPM of the song,
* while respecting a limit.