void CPActionReverse::Redo(CMainFrame &MainFrm) { CSongView *pSongView = GET_SONG_VIEW(); auto [b, e] = GetIterators(*pSongView); const CSelection &Sel = m_pUndoState->Selection; const column_t ColStart = GetSelectColumn(Sel.m_cpStart.Xpos.Column); const column_t ColEnd = GetSelectColumn(Sel.m_cpEnd.Xpos.Column); while (b < e) { for (int c = Sel.m_cpStart.Xpos.Track; c <= Sel.m_cpEnd.Xpos.Track; ++c) { auto NoteBegin = b.Get(c); auto NoteEnd = e.Get(c); if (c == Sel.m_cpStart.Xpos.Track && ColStart > column_t::Note) { // // // auto Temp = NoteEnd; CopyNoteSection(NoteEnd, NoteBegin, column_t::Note, static_cast<column_t>(value_cast(ColStart) - 1)); CopyNoteSection(NoteBegin, Temp, column_t::Note, static_cast<column_t>(value_cast(ColStart) - 1)); } if (c == Sel.m_cpEnd.Xpos.Track && ColEnd < column_t::Effect4) { auto Temp = NoteEnd; CopyNoteSection(NoteEnd, NoteBegin, static_cast<column_t>(value_cast(ColEnd) + 1), column_t::Effect4); CopyNoteSection(NoteBegin, Temp, static_cast<column_t>(value_cast(ColEnd) + 1), column_t::Effect4); } b.Set(c, NoteEnd); e.Set(c, NoteBegin); } ++b; --e; } }
void CPActionStretch::Redo(CMainFrame &MainFrm) { CSongView *pSongView = GET_SONG_VIEW(); auto [b, e] = GetIterators(*pSongView); const CSelection &Sel = m_pUndoState->Selection; CPatternIterator s {b}; const column_t ColStart = GetSelectColumn(Sel.m_cpStart.Xpos.Column); const column_t ColEnd = GetSelectColumn(Sel.m_cpEnd.Xpos.Column); int Pos = 0; int Offset = 0; int oldRow = -1; do { stChanNote BLANK; for (int i = Sel.m_cpStart.Xpos.Track; i <= Sel.m_cpEnd.Xpos.Track; ++i) { const auto &Source = (Offset < m_UndoClipData.ClipInfo.Rows && m_iStretchMap[Pos] > 0) ? *(m_UndoClipData.GetPattern(i - Sel.m_cpStart.Xpos.Track, Offset)) : BLANK; // // // auto Target = b.Get(i); CopyNoteSection(Target, Source, i == Sel.m_cpStart.Xpos.Track ? ColStart : column_t::Note, i == Sel.m_cpEnd.Xpos.Track ? ColEnd : column_t::Effect4); b.Set(i, Target); } int dist = m_iStretchMap[Pos++]; for (int i = 0; i < dist; ++i) { ++Offset; oldRow = s.m_iRow; ++s; if (s.m_iRow <= oldRow) Offset += pSongView->GetSong().GetPatternLength() + s.m_iRow - oldRow - 1; } Pos %= m_iStretchMap.size(); } while (++b <= e); }
bool CSelection::IsColumnSelected(column_t Column, int Channel) const { column_t SelStart = GetSelectColumn(GetColStart()); // // // column_t SelEnd = GetSelectColumn(GetColEnd()); return (Channel > GetChanStart() || (Channel == GetChanStart() && Column >= SelStart)) // // // && (Channel < GetChanEnd() || (Channel == GetChanEnd() && Column <= SelEnd)); }
void CPatternAction::DeleteSelection(CSongView &view, const CSelection &Sel) const // // // { auto [b, e] = CPatternIterator::FromSelection(Sel, view); const column_t ColStart = GetSelectColumn(b.m_iColumn); const column_t ColEnd = GetSelectColumn(e.m_iColumn); stChanNote BLANK; do for (int i = b.m_iChannel; i <= e.m_iChannel; ++i) { auto NoteData = b.Get(i); CopyNoteSection(NoteData, BLANK, i == b.m_iChannel ? ColStart : column_t::Note, i == e.m_iChannel ? ColEnd : column_t::Effect4); b.Set(i, NoteData); } while (++b <= e); }
void CPActionScrollValues::Redo(CMainFrame &MainFrm) { CPatternEditor *pPatternEditor = GET_PATTERN_EDITOR(); CSongView *pSongView = GET_SONG_VIEW(); auto [b, e] = GetIterators(*pSongView); int ChanStart = (m_pUndoState->IsSelecting ? m_pUndoState->Selection.m_cpStart : m_pUndoState->Cursor).Xpos.Track; int ChanEnd = (m_pUndoState->IsSelecting ? m_pUndoState->Selection.m_cpEnd : m_pUndoState->Cursor).Xpos.Track; column_t ColStart = GetSelectColumn( (m_pUndoState->IsSelecting ? m_pUndoState->Selection.m_cpStart : m_pUndoState->Cursor).Xpos.Column); column_t ColEnd = GetSelectColumn( (m_pUndoState->IsSelecting ? m_pUndoState->Selection.m_cpEnd : m_pUndoState->Cursor).Xpos.Column); const bool bSingular = b == e && !m_pUndoState->IsSelecting; const unsigned Length = pSongView->GetSong().GetPatternLength(); const auto WarpFunc = [this] (unsigned char &x, int Lim) { int Val = x + m_iAmount; if (FTEnv.GetSettings()->General.bWrapPatternValue) { Val %= Lim; if (Val < 0) Val += Lim; } else { if (Val >= Lim) Val = Lim - 1; if (Val < 0) Val = 0; } x = static_cast<unsigned char>(Val); }; int Row = 0; int oldRow = -1; do { if (b.m_iRow <= oldRow) Row += Length + b.m_iRow - oldRow - 1; for (int i = ChanStart; i <= ChanEnd; ++i) { auto Note = *(m_UndoClipData.GetPattern(i - ChanStart, Row)); // // // for (column_t k = column_t::Instrument; k <= column_t::Effect4; k = static_cast<column_t>(value_cast(k) + 1)) { if (i == ChanStart && k < ColStart) continue; if (i == ChanEnd && k > ColEnd) continue; switch (k) { case column_t::Instrument: if (Note.Instrument == MAX_INSTRUMENTS || Note.Instrument == HOLD_INSTRUMENT) break; // // // 050B WarpFunc(Note.Instrument, MAX_INSTRUMENTS); break; case column_t::Volume: if (Note.Vol == MAX_VOLUME) break; WarpFunc(Note.Vol, MAX_VOLUME); break; case column_t::Effect1: case column_t::Effect2: case column_t::Effect3: case column_t::Effect4: { unsigned fx = value_cast(k) - value_cast(column_t::Effect1); if (Note.Effects[fx].fx == effect_t::none) break; if (bSingular) switch (Note.Effects[fx].fx) { case effect_t::SWEEPUP: case effect_t::SWEEPDOWN: case effect_t::ARPEGGIO: case effect_t::VIBRATO: case effect_t::TREMOLO: case effect_t::SLIDE_UP: case effect_t::SLIDE_DOWN: case effect_t::VOLUME_SLIDE: case effect_t::DELAYED_VOLUME: case effect_t::TRANSPOSE: unsigned char Hi = Note.Effects[fx].param >> 4; unsigned char Lo = Note.Effects[fx].param & 0x0F; WarpFunc(value_cast(pPatternEditor->GetColumn()) % 3 == 2 ? Hi : Lo, 0x10); Note.Effects[fx].param = (Hi << 4) | Lo; continue; } WarpFunc(Note.Effects[fx].param, 0x100); break; } } } b.Set(i, Note); } ++Row; oldRow = b.m_iRow; } while (++b <= e); }
bool CPatternAction::SetTargetSelection(const CMainFrame &MainFrm, CSelection &Sel) // // // { CPatternEditor *pPatternEditor = GET_PATTERN_EDITOR(); CCursorPos Start; if ((m_iPastePos == paste_pos_t::SELECTION || m_iPastePos == paste_pos_t::FILL) && !m_bSelecting) m_iPastePos = paste_pos_t::CURSOR; switch (m_iPastePos) { // Xpos.Column will be written later case paste_pos_t::CURSOR: Start = m_pUndoState->Cursor; break; case paste_pos_t::DRAG: Start.Ypos.Frame = m_dragTarget.GetFrameStart(); Start.Ypos.Row = m_dragTarget.GetRowStart(); Start.Xpos.Track = m_dragTarget.GetChanStart(); break; case paste_pos_t::SELECTION: case paste_pos_t::FILL: Start.Ypos.Frame = m_selection.GetFrameStart(); Start.Ypos.Row = m_selection.GetRowStart(); Start.Xpos.Track = m_selection.GetChanStart(); break; } auto pSongView = GET_SONG_VIEW(); CPatternIterator End(*pSongView, Start); if (m_iPasteMode == paste_mode_t::INSERT) { End.m_iFrame = Start.Ypos.Frame; End.m_iRow = pPatternEditor->GetCurrentPatternLength(End.m_iFrame) - 1; } else End += m_ClipData.ClipInfo.Rows - 1; switch (m_iPastePos) { case paste_pos_t::FILL: End.m_iFrame = m_selection.GetFrameEnd(); End.m_iRow = m_selection.GetRowEnd(); End.m_iChannel = m_selection.GetChanEnd(); Start.Xpos.Column = GetCursorStartColumn(m_ClipData.ClipInfo.StartColumn); End.m_iColumn = GetCursorEndColumn( !((End.m_iChannel - Start.Xpos.Track + 1) % m_ClipData.ClipInfo.Channels) ? m_ClipData.ClipInfo.EndColumn : static_cast<column_t>(value_cast(column_t::Effect1) + pSongView->GetEffectColumnCount(End.m_iChannel))); break; case paste_pos_t::DRAG: End.m_iChannel += m_ClipData.ClipInfo.Channels - 1; Start.Xpos.Column = m_dragTarget.GetColStart(); End.m_iColumn = m_dragTarget.GetColEnd(); break; default: End.m_iChannel += m_ClipData.ClipInfo.Channels - 1; Start.Xpos.Column = GetCursorStartColumn(m_ClipData.ClipInfo.StartColumn); End.m_iColumn = GetCursorEndColumn(m_ClipData.ClipInfo.EndColumn); } const bool bOverflow = FTEnv.GetSettings()->General.bOverflowPaste; if (!bOverflow && End.m_iFrame > Start.Ypos.Frame) { End.m_iFrame = Start.Ypos.Frame; End.m_iRow = pPatternEditor->GetCurrentPatternLength(End.m_iFrame) - 1; } const cursor_column_t EFBEGIN = GetCursorStartColumn(column_t::Effect1); int OFFS = 3 * (value_cast(GetSelectColumn(m_pUndoState->Cursor.Xpos.Column)) - value_cast(m_ClipData.ClipInfo.StartColumn)); if (OFFS < static_cast<int>(value_cast(EFBEGIN) - value_cast(Start.Xpos.Column))) OFFS = value_cast(EFBEGIN) - value_cast(Start.Xpos.Column); if (Start.Xpos.Track == End.m_iChannel && Start.Xpos.Column >= EFBEGIN && End.m_iColumn >= EFBEGIN) { if (m_iPastePos != paste_pos_t::DRAG) { End.m_iColumn = static_cast<cursor_column_t>(value_cast(End.m_iColumn) + OFFS); Start.Xpos.Column = static_cast<cursor_column_t>(value_cast(Start.Xpos.Column) + OFFS); if (End.m_iColumn > cursor_column_t::EFF4_PARAM2) End.m_iColumn = cursor_column_t::EFF4_PARAM2; } } CSelection New; New.m_cpStart = Start; New.m_cpEnd = End.GetCursor(); pPatternEditor->SetSelection(New); sel_condition_t Cond = pPatternEditor->GetSelectionCondition(); if (Cond == sel_condition_t::CLEAN) { Sel = New; return true; } else { pPatternEditor->SetSelection(m_selection); if (!m_bSelecting) pPatternEditor->CancelSelection(); int Confirm = IDYES; switch (Cond) { case sel_condition_t::REPEATED_ROW: Confirm = AfxMessageBox(IDS_PASTE_REPEATED_ROW, MB_YESNO | MB_ICONEXCLAMATION | MB_DEFBUTTON2); break; case sel_condition_t::NONTERMINAL_SKIP: case sel_condition_t::TERMINAL_SKIP: if (!bOverflow) break; Confirm = AfxMessageBox(IDS_PASTE_NONTERMINAL, MB_YESNO | MB_ICONEXCLAMATION | MB_DEFBUTTON2); break; } if (Confirm == IDYES) { pPatternEditor->SetSelection(Sel = New); return true; } else { return false; } } }