From ba5699e109018d38fd1675c43aef2bab19a880c2 Mon Sep 17 00:00:00 2001 From: Christopher O'Neill Date: Fri, 8 May 2020 20:08:38 +0100 Subject: [PATCH 1/4] Remove unneccesary PPC assembly code --- src/ppui/fastfill.h | 79 +++------------------------------------------ 1 file changed, 5 insertions(+), 74 deletions(-) diff --git a/src/ppui/fastfill.h b/src/ppui/fastfill.h index 29f0614b..1517c5a6 100644 --- a/src/ppui/fastfill.h +++ b/src/ppui/fastfill.h @@ -28,88 +28,19 @@ * */ -#ifdef __GNUC__ -static __attribute__((noinline)) void fill_dword(pp_uint32* buff, pp_uint32 dw, pp_uint32 len) -#else +#include + static inline void fill_dword(pp_uint32* buff, pp_uint32 dw, pp_uint32 len) -#endif { -#if defined(__ppc__) && defined(__GNUC__) - // PPC assembly FTW!!1! - // r3 = buff - // r4 = dw - // r5 = len - asm volatile("li r9, 0\n" - "srawi r10, r5, 2\n" - "nop\n" // align loop start to 16 byte boundary - "cmpw cr7,r10,r9\n" - "nop\n" // see above - "beq cr7,$+36\n" - "2:\n" - "stw r4,0(r3)\n" - "stw r4,4(r3)\n" - "stw r4,8(r3)\n" - "stw r4,12(r3)\n" - "addi r10,r10,-1\n" - "addi r3,r3,16\n" // advance by 16 - "cmpw cr7,r10,r9\n" - "bne cr7,2b\n" - "clrlwi r11, r5, 30\n" - "nop\n" // align loop start to 16 byte boundary - "cmpw cr7,r11,r9\n" - "beq cr7,$+24\n" - "1:\n" - "stw r4,0(r3)\n" - "addi r11,r11,-1\n" - "addi r3,r3,4\n" // advance by 4 - "cmpw cr7,r11,r9\n" - "bne cr7,1b"); -#else - pp_uint32 newlen = len >> 2; - pp_uint32 remlen = len & 3; - if (newlen) - { - do - { - *buff = dw; - *(buff+1) = dw; - *(buff+2) = dw; - *(buff+3) = dw; - buff+=4; - } while (--newlen); - } - if (remlen) - { - do - { - *buff++ = dw; - } while (--remlen); - } -#endif + memset(buff, dw, len); } -#ifdef __GNUC__ -static __attribute__((noinline)) void fill_dword_vertical(pp_uint32* buff, pp_uint32 dw, pp_uint32 len, pp_uint32 pitch) -#else static inline void fill_dword_vertical(pp_uint32* buff, pp_uint32 dw, pp_uint32 len, pp_uint32 pitch) -#endif { -#if defined(__ppc__) && defined(__GNUC__) - asm volatile("nop\n" // align loop start to 16 byte boundary - "nop\n" // same - "nop\n" // same - "li r9,0\n" - "1:\n" - "stw r4,0(r3)\n" - "addi r5,r5,-1\n" - "add r3,r3,r6\n" - "cmpw cr7,r5,r9\n" - "bne cr7,1b"); -#else + pitch >>= 2; do { *buff = dw; - buff+=(pitch>>2); + buff += pitch; } while (--len); -#endif } From 65885c3e0ccacfa0a490247552c2757126cb83b9 Mon Sep 17 00:00:00 2001 From: Jeremy Clarke Date: Sat, 25 Apr 2020 19:37:42 +0100 Subject: [PATCH 2/4] Click and drag to move selection in pattern editor Click and drag a selection in the pattern editor to move the selected pattern data. Use the modifier key (alt) to clone instead of moving. --- .gitignore | 3 + src/ppui/GraphicsAbstract.h | 41 +++++ src/tracker/PatternEditor.cpp | 68 +++++++ src/tracker/PatternEditor.h | 8 + src/tracker/PatternEditorControl.cpp | 54 +++++- src/tracker/PatternEditorControl.h | 7 + .../PatternEditorControlEventListener.cpp | 137 ++++++++------ src/tracker/PatternEditorTools.cpp | 172 +++++++++++++++++- src/tracker/PatternEditorTools.h | 2 + 9 files changed, 437 insertions(+), 55 deletions(-) diff --git a/.gitignore b/.gitignore index a9dd3b9b..a2dbb0f4 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,6 @@ build/ # Resources generated with docerator on OSX resources/pictures/docicons/osx/MilkyTracker-*.icns resources/pictures/docicons/osx/docerator/ + +# Editor config files +.vscode/ diff --git a/src/ppui/GraphicsAbstract.h b/src/ppui/GraphicsAbstract.h index be9a77a3..d4923929 100644 --- a/src/ppui/GraphicsAbstract.h +++ b/src/ppui/GraphicsAbstract.h @@ -161,6 +161,10 @@ class PPGraphicsAbstract *a = *b; *b = h; } + static pp_int32 modulo(pp_int32 a, pp_int32 b) + { + return ((a % b + b) % b); + } pp_int32 width, height; @@ -331,6 +335,43 @@ class PPGraphicsAbstract { fillVerticalShaded(currentClipRect, colSrc, colDst, invertShading); } + + + void drawHLineDashed(pp_int32 x1, pp_int32 x2, pp_int32 y, pp_int32 dashLength, pp_int32 dashOffset = 0) + { + if (x2 < x1) + swap(&x1, &x2); + + pp_int32 tail = x1; + pp_int32 head = x1 + dashLength - modulo(dashOffset, dashLength); + + while (head-1 < x2) + { + drawHLine(tail, head-1, y); + tail = head; + head += dashLength; + } + if (tail < x2) + drawHLine(tail, x2, y); + } + + void drawVLineDashed(pp_int32 y1, pp_int32 y2, pp_int32 x, pp_int32 dashLength, pp_int32 dashOffset = 0) + { + if (y2 < y1) + swap(&y1, &y2); + + pp_int32 tail = y1; + pp_int32 head = y1 + dashLength - modulo(dashOffset, dashLength); + + while (head-1 < y2) + { + drawVLine(tail, head-1, x); + tail = head; + head += dashLength; + } + if (tail < y2) + drawVLine(tail, y2, x); + } }; #endif diff --git a/src/tracker/PatternEditor.cpp b/src/tracker/PatternEditor.cpp index 120c6568..41c3d7b2 100644 --- a/src/tracker/PatternEditor.cpp +++ b/src/tracker/PatternEditor.cpp @@ -211,6 +211,22 @@ bool PatternEditor::hasValidSelection() return PatternEditorTools::hasValidSelection(pattern, selection.start, selection.end, getNumChannels()); } +bool PatternEditor::selectionContains(const PatternEditorTools::Position& pos) +{ + return PatternEditorTools::selectionContains(pattern, selection.start, selection.end, pos); +} + +bool PatternEditor::canMoveSelection(pp_int32 channels, pp_int32 rows) +{ + PatternEditorTools::Position ss = selection.start; + PatternEditorTools::Position se = selection.end; + ss.channel += channels; + ss.row += rows; + se.channel += channels; + se.row += rows; + return PatternEditorTools::hasValidSelection(pattern, ss, se, getNumChannels()); +} + void PatternEditor::selectChannel(pp_int32 channel) { if (pattern == NULL) @@ -1815,3 +1831,55 @@ void PatternEditor::deleteLine(pp_int32 row) finishUndo(LastChangeDeleteLine); } + + +void PatternEditor::moveSelection(pp_int32 channels, pp_int32 rows) +{ + PatternEditorTools::Position targetStart = selection.start; + PatternEditorTools::Position targetEnd = selection.end; + targetStart.row += rows; + targetStart.channel += channels; + targetEnd.row += rows; + targetEnd.channel += channels; + + if (!PatternEditorTools::hasValidSelection(pattern, selection.start, selection.end)) + return; + if (!PatternEditorTools::hasValidSelection(pattern, targetStart, targetEnd)) + return; + + prepareUndo(); + + PatternEditorTools tools(pattern); + tools.moveSelection(selection.start, selection.end, channels, rows, true); + + selection.start = targetStart; + selection.end = targetEnd; + + finishUndo(LastChangeMoveSelection); +} + + +void PatternEditor::cloneSelection(pp_int32 channels, pp_int32 rows) +{ + PatternEditorTools::Position targetStart = selection.start; + PatternEditorTools::Position targetEnd = selection.end; + targetStart.row += rows; + targetStart.channel += channels; + targetEnd.row += rows; + targetEnd.channel += channels; + + if (!PatternEditorTools::hasValidSelection(pattern, selection.start, selection.end)) + return; + if (!PatternEditorTools::hasValidSelection(pattern, targetStart, targetEnd)) + return; + + prepareUndo(); + + PatternEditorTools tools(pattern); + tools.moveSelection(selection.start, selection.end, channels, rows, false); // don't erase source notes + + selection.start = targetStart; + selection.end = targetEnd; + + finishUndo(LastChangeCloneSelection); +} \ No newline at end of file diff --git a/src/tracker/PatternEditor.h b/src/tracker/PatternEditor.h index 9a4b662a..222ee1f2 100644 --- a/src/tracker/PatternEditor.h +++ b/src/tracker/PatternEditor.h @@ -155,6 +155,8 @@ class PatternEditor : public EditorBase LastChangeCut, LastChangePaste, LastChangeDeleteSelection, + LastChangeMoveSelection, + LastChangeCloneSelection, LastChangeExpandPattern, LastChangeShrinkPattern, @@ -263,6 +265,8 @@ class PatternEditor : public EditorBase void setSelectionEnd(const PatternEditorTools::Position& pos) { selection.end = pos; } void resetSelection() { selection.reset(); } bool hasValidSelection(); + bool canMoveSelection(pp_int32 channels, pp_int32 rows); + bool selectionContains(const PatternEditorTools::Position& pos); void selectChannel(pp_int32 channel); void selectAll(); @@ -414,6 +418,10 @@ class PatternEditor : public EditorBase void deleteNote(pp_int32 channel, pp_int32 row); void deleteLine(pp_int32 row); + // --- moving entire selection ------------------------------------------- + void moveSelection(pp_int32 channels, pp_int32 rows); + void cloneSelection(pp_int32 channels, pp_int32 rows); + }; #endif diff --git a/src/tracker/PatternEditorControl.cpp b/src/tracker/PatternEditorControl.cpp index 3a492719..d7cbd9ad 100644 --- a/src/tracker/PatternEditorControl.cpp +++ b/src/tracker/PatternEditorControl.cpp @@ -732,7 +732,7 @@ void PatternEditorControl::paint(PPGraphicsAbstract* g) g->drawString(name,px, py); } } - + for (j = startPos; j < numVisibleChannels; j++) { @@ -814,6 +814,58 @@ void PatternEditorControl::paint(PPGraphicsAbstract* g) } } + // --------------------- draw moved selection --------------------- + + if (hasValidSelection() && moveSelection) + { + pp_int32 moveSelectionRows = moveSelectionFinalPos.row - moveSelectionInitialPos.row; + pp_int32 moveSelectionChannels = moveSelectionFinalPos.channel - moveSelectionInitialPos.channel; + + pp_int32 i1 = selectionStart.row + moveSelectionRows; + pp_int32 j1 = selectionStart.channel + moveSelectionChannels; + pp_int32 i2 = selectionEnd.row + moveSelectionRows; + pp_int32 j2 = selectionEnd.channel + moveSelectionChannels; + + if (i2 >= 0 && j2 >= 0 && i1 < pattern->rows && j1 < numVisibleChannels) + { + #define CLAMP(a, min, max) ((a) < (min) ? (min) : ((a) >= (max) ? (max-1) : (a))) + + i1 = CLAMP(i1, 0, pattern->rows); + i2 = CLAMP(i2, 0, pattern->rows); + j1 = CLAMP(j1, 0, numVisibleChannels); + j2 = CLAMP(j2, 0, numVisibleChannels); + + #undef CLAMP + + pp_int32 x1 = (location.x + (j1-startPos) * slotSize + SCROLLBARWIDTH) + cursorPositions[selectionStart.inner] + (getRowCountWidth() + 4); + pp_int32 y1 = (location.y + (i1-startIndex) * font->getCharHeight() + SCROLLBARWIDTH) + (font->getCharHeight() + 4); + + pp_int32 x2 = (location.x + (j2-startPos) * slotSize + SCROLLBARWIDTH) + cursorPositions[selectionEnd.inner]+cursorSizes[selectionEnd.inner] + (getRowCountWidth() + 3); + pp_int32 y2 = (location.y + (i2-startIndex) * font->getCharHeight() + SCROLLBARWIDTH) + (font->getCharHeight()*2 + 2); + + // use a different color for cloning the selection instead of moving it + if (::getKeyModifier() & selectionKeyModifier) + g->setColor(hiLightPrimary); + else + g->setColor(textColor); + + const pp_int32 dashLen = 6; + + // inner dashed lines + g->drawHLineDashed(x1, x2, y1, dashLen, 3); + g->drawHLineDashed(x1, x2, y2, dashLen, 3+y2-y1); + g->drawVLineDashed(y1, y2, x1, dashLen, 3); + g->drawVLineDashed(y1, y2+2, x2, dashLen, 3+x2-x1); + + // outer dashed lines + g->drawHLineDashed(x1-1, x2+1, y1-1, dashLen, 1); + g->drawHLineDashed(x1-1, x2, y2+1, dashLen, 3+y2-y1); + g->drawVLineDashed(y1-1, y2+1, x1-1, dashLen, 1); + g->drawVLineDashed(y1-1, y2+2, x2+1, dashLen, 3+x2-x1); + } + + } + // draw scrollbars hTopScrollbar->paint(g); hBottomScrollbar->paint(g); diff --git a/src/tracker/PatternEditorControl.h b/src/tracker/PatternEditorControl.h index faf1a468..5ef1561f 100644 --- a/src/tracker/PatternEditorControl.h +++ b/src/tracker/PatternEditorControl.h @@ -170,6 +170,10 @@ class PatternEditorControl : pp_int32 selectionTicker; bool hasDragged; + + bool moveSelection; + PatternEditorTools::Position moveSelectionInitialPos; + PatternEditorTools::Position moveSelectionFinalPos; // edit menu pp_int32 menuPosX; @@ -377,6 +381,9 @@ class PatternEditorControl : void handleKeyChar(pp_uint8 character); void handleKeyDown(pp_uint16 keyCode, pp_uint16 scanCode, pp_uint16 character); + void selectionModifierKeyDown(); + void selectionModifierKeyUp(); + // mark channel void markChannel(pp_int32 channel, bool invert = true); diff --git a/src/tracker/PatternEditorControlEventListener.cpp b/src/tracker/PatternEditorControlEventListener.cpp index b62515f6..3bdcebb8 100644 --- a/src/tracker/PatternEditorControlEventListener.cpp +++ b/src/tracker/PatternEditorControlEventListener.cpp @@ -358,19 +358,9 @@ pp_int32 PatternEditorControl::dispatchEvent(PPEvent* event) pp_int32 visibleRows = (visibleHeight) / font->getCharHeight(); pp_int32 visibleChannels = (visibleWidth) / slotSize; - // copy of current selection + // backup selection, so that it may be restored when context menu is activated by long-press patternEditor->getSelection().backup(); - // If we're pressing the shift key start selection - // at current cursor position - if (::getKeyModifier() & selectionKeyModifier) - { - if (patternEditor->getSelection().start.isValid()) - patternEditor->getSelection().end = patternEditor->getCursor(); - else - patternEditor->getSelection().start = patternEditor->getCursor(); - } - preCursor = patternEditor->getCursor(); if (newStartIndex < visibleRows && newStartIndex >= 0) @@ -393,37 +383,44 @@ pp_int32 PatternEditorControl::dispatchEvent(PPEvent* event) if (preCursor.channel >= patternEditor->getNumChannels()) break; - - // start selecting row - if (!(::getKeyModifier() & selectionKeyModifier)) - { - patternEditor->getSelection().start.channel = patternEditor->getSelection().end.channel = preCursor.channel; - patternEditor->getSelection().start.row = patternEditor->getSelection().end.row = preCursor.row; - } - else - { - patternEditor->getSelection().end.channel = preCursor.channel; - patternEditor->getSelection().end.row = preCursor.row; - } - - pp_int32 innerPos = cp.x % slotSize; - + preCursor.inner = 0; - if (!(::getKeyModifier() & selectionKeyModifier)) - patternEditor->getSelection().start.inner = 0; - patternEditor->getSelection().end.inner = 0; + + pp_int32 innerPos = cp.x % slotSize; for (pp_uint32 i = 0; i < sizeof(cursorPositions) - 1; i++) { if (innerPos >= cursorPositions[i] && innerPos < cursorPositions[i+1]) { preCursor.inner = i; - if (!(::getKeyModifier() & selectionKeyModifier)) - patternEditor->getSelection().start.inner = i; - patternEditor->getSelection().end.inner = i; break; } } + + if (patternEditor->selectionContains(preCursor)) + { + startSelection = false; + moveSelection = true; + moveSelectionInitialPos = preCursor; + moveSelectionFinalPos = preCursor; + } + else + { + if (!(::getKeyModifier() & selectionKeyModifier)) + { + // start selection from mouse cursor position + patternEditor->getSelection().start = preCursor; + patternEditor->getSelection().end = preCursor; + } + else + { + // resume selection from mouse cursor position + if (!patternEditor->getSelection().start.isValid()) + patternEditor->getSelection().start = patternEditor->getCursor(); + patternEditor->getSelection().end = preCursor; + } + } + } ppreCursor = &preCursor; @@ -444,8 +441,21 @@ pp_int32 PatternEditorControl::dispatchEvent(PPEvent* event) } menuInvokeChannel = -1; - - if (!hasDragged && !(::getKeyModifier() & selectionKeyModifier) && ppreCursor) + + if (moveSelection && moveSelectionFinalPos != moveSelectionInitialPos) + { + pp_int32 moveSelectionRows = moveSelectionFinalPos.row - moveSelectionInitialPos.row; + pp_int32 moveSelectionChannels = moveSelectionFinalPos.channel - moveSelectionInitialPos.channel; + + if (patternEditor->canMoveSelection(moveSelectionChannels, moveSelectionRows)) + { + if (::getKeyModifier() & selectionKeyModifier) + patternEditor->cloneSelection(moveSelectionChannels, moveSelectionRows); + else + patternEditor->moveSelection(moveSelectionChannels, moveSelectionRows); + } + } + else if (!hasDragged && !(::getKeyModifier() & selectionKeyModifier) && ppreCursor) { if (properties.clickToCursor) { @@ -467,9 +477,12 @@ pp_int32 PatternEditorControl::dispatchEvent(PPEvent* event) patternEditor->resetSelection(); } - parentScreen->paintControl(this); startSelection = false; + moveSelection = false; + + parentScreen->paintControl(this); + ppreCursor = NULL; break; @@ -480,14 +493,13 @@ pp_int32 PatternEditorControl::dispatchEvent(PPEvent* event) { caughtControl->dispatchEvent(event); break; - } + } - if (!startSelection) + if (!moveSelection && !startSelection) break; hasDragged = true; - - goto markSelection; + goto markOrMoveSelection; //break; } @@ -569,7 +581,7 @@ pp_int32 PatternEditorControl::dispatchEvent(PPEvent* event) break; } -markSelection: +markOrMoveSelection: PPPoint cp = *((PPPoint*)event->getDataPtr()); PPPoint cp2 = cp; @@ -637,12 +649,16 @@ pp_int32 PatternEditorControl::dispatchEvent(PPEvent* event) pp_int32 visibleRows = (visibleHeight) / font->getCharHeight(); pp_int32 visibleChannels = (visibleWidth) / slotSize; - //if (newStartIndex < visibleRows && - // newStartPos < visibleChannels) - //{ - mp_sint32 cursorPositionRow = newStartIndex + startIndex; - mp_sint32 cursorPositionChannel = newStartPos + startPos; - + mp_sint32 cursorPositionRow = newStartIndex + startIndex; + mp_sint32 cursorPositionChannel = newStartPos + startPos; + + if (moveSelection) + { + moveSelectionFinalPos.channel = cursorPositionChannel; + moveSelectionFinalPos.row = cursorPositionRow; + } + else + { if (cursorPositionRow < 0) cursorPositionRow = 0; if (cursorPositionChannel < 0) cursorPositionChannel = 0; @@ -677,7 +693,7 @@ pp_int32 PatternEditorControl::dispatchEvent(PPEvent* event) setScrollbarPositions(startIndex, startPos); - //} + } parentScreen->paintControl(this); @@ -727,17 +743,17 @@ pp_int32 PatternEditorControl::dispatchEvent(PPEvent* event) case VK_ALT: assureCursor = false; if (selectionKeyModifier & KeyModifierALT) - keyboardStartSelection = true; + selectionModifierKeyDown(); break; case VK_SHIFT: assureCursor = false; if (selectionKeyModifier & KeyModifierSHIFT) - keyboardStartSelection = true; + selectionModifierKeyDown(); break; case VK_CONTROL: assureCursor = false; if (selectionKeyModifier & KeyModifierCTRL) - keyboardStartSelection = true; + selectionModifierKeyDown(); break; default: @@ -813,15 +829,15 @@ pp_int32 PatternEditorControl::dispatchEvent(PPEvent* event) { case VK_SHIFT: if (selectionKeyModifier & KeyModifierSHIFT) - keyboardStartSelection = false; + selectionModifierKeyUp(); break; case VK_ALT: if (selectionKeyModifier & KeyModifierALT) - keyboardStartSelection = false; + selectionModifierKeyUp(); break; case VK_CONTROL: if (selectionKeyModifier & KeyModifierCTRL) - keyboardStartSelection = false; + selectionModifierKeyUp(); break; } break; @@ -840,6 +856,21 @@ pp_int32 PatternEditorControl::dispatchEvent(PPEvent* event) return 0; } +void PatternEditorControl::selectionModifierKeyDown() +{ + keyboardStartSelection = true; + if (moveSelection) + parentScreen->paintControl(this); +} + +void PatternEditorControl::selectionModifierKeyUp() +{ + keyboardStartSelection = false; + if (moveSelection) + parentScreen->paintControl(this); +} + + pp_int32 PatternEditorControl::handleEvent(PPObject* sender, PPEvent* event) { PatternEditorTools::Position& cursor = patternEditor->getCursor(); diff --git a/src/tracker/PatternEditorTools.cpp b/src/tracker/PatternEditorTools.cpp index 153c3453..08a4a059 100644 --- a/src/tracker/PatternEditorTools.cpp +++ b/src/tracker/PatternEditorTools.cpp @@ -1718,6 +1718,40 @@ void PatternEditorTools::normalize() } +bool PatternEditorTools::selectionContains(const TXMPattern* pattern, const Position& ss, const Position& se, const Position& pos) +{ + pp_int32 selectionStartChannel; + pp_int32 selectionStartRow; + pp_int32 selectionStartInner; + pp_int32 selectionEndChannel; + pp_int32 selectionEndRow; + pp_int32 selectionEndInner; + + if (!normalizeSelection(pattern, ss, se, + selectionStartChannel, selectionStartRow, selectionStartInner, + selectionEndChannel, selectionEndRow,selectionEndInner)) + return false; + + // only entire instrument column is allowed + if (selectionStartInner >= 1 && selectionStartInner<=2) + selectionStartInner = 1; + if (selectionEndInner >= 1 && selectionEndInner<=2) + selectionEndInner = 2; + // only entire volume column can be selected + if (selectionStartInner >= 3 && selectionStartInner<=4) + selectionStartInner = 3; + if (selectionEndInner >= 3 && selectionEndInner<=4) + selectionEndInner = 4; + + bool outside = + pos.row < selectionStartRow || pos.row > selectionEndRow || + pos.channel < selectionStartChannel || pos.channel > selectionEndChannel || + (pos.channel == selectionStartChannel && pos.inner < selectionStartInner) || + (pos.channel == selectionEndChannel && pos.inner > selectionEndInner); + + return !outside; +} + bool PatternEditorTools::hasValidSelection(const TXMPattern* pattern, const Position& ss, const Position& se, pp_int32 numVisibleChannels/* = -1*/) { if (pattern == NULL || pattern->patternData == NULL) @@ -1888,4 +1922,140 @@ void PatternEditorTools::slotClear(mp_ubyte* dst, pp_int32 from, pp_int32 to) i++; } - +bool PatternEditorTools::moveSelection(const Position& ss, const Position& se, pp_int32 moveChannels, pp_int32 moveRows, bool clear) +{ + Position targetStart = ss; + Position targetEnd = se; + targetStart.channel += moveChannels; + targetStart.row += moveRows; + targetEnd.channel += moveChannels; + targetEnd.row += moveRows; + + if (!PatternEditorTools::hasValidSelection(pattern, ss, se)) + return false; + if (!PatternEditorTools::hasValidSelection(pattern, targetStart, targetEnd)) + return false; + + pp_int32 selectionStartChannel; + pp_int32 selectionStartRow; + pp_int32 selectionStartInner; + pp_int32 selectionEndChannel; + pp_int32 selectionEndRow; + pp_int32 selectionEndInner; + + if (!normalizeSelection(pattern, ss, se, + selectionStartChannel, selectionStartRow, selectionStartInner, + selectionEndChannel, selectionEndRow,selectionEndInner)) + return 0; + + // only entire instrument column is allowed + if (selectionStartInner >= 1 && selectionStartInner<=2) + selectionStartInner = 1; + if (selectionEndInner >= 1 && selectionEndInner<=2) + selectionEndInner = 2; + // only entire volume column can be selected + if (selectionStartInner >= 3 && selectionStartInner<=4) + selectionStartInner = 3; + if (selectionEndInner >= 3 && selectionEndInner<=4) + selectionEndInner = 4; + + pp_int32 selectionWidth = selectionEndChannel - selectionStartChannel + 1; + pp_int32 selectionHeight = selectionEndRow - selectionStartRow + 1; + + mp_sint32 slotSize = pattern->effnum * 2 + 2; + ASSERT(slotSize == 6); + + mp_sint32 rowSizeDst = slotSize*selectionWidth; + mp_sint32 rowSizeSrc = slotSize*pattern->channum; + mp_sint32 bufferSize = selectionHeight * rowSizeDst; + + mp_ubyte* buffer = new mp_ubyte[bufferSize]; + + if (buffer == NULL) + return false; + + memset(buffer, 0, bufferSize); + + // copy to temporary buffer, erase source if desired + + for (pp_int32 i = 0; i < selectionHeight; i++) + { + pp_int32 rowSrc = selectionStartRow + i; + + if (rowSrc < 0 || rowSrc >= pattern->rows) + continue; + + for (pp_int32 j = 0; j < selectionWidth; j++) + { + pp_int32 channelSrc = selectionStartChannel + j; + + if (channelSrc < 0 || channelSrc >= pattern->channum) + continue; + + mp_ubyte* src = pattern->patternData + rowSrc*rowSizeSrc + channelSrc*slotSize; + mp_ubyte* dst = buffer + i*rowSizeDst + j*slotSize; + + if (selectionWidth == 1) + { + PatternEditorTools::slotCopy(dst, src, selectionStartInner, selectionEndInner); + if (clear) + PatternEditorTools::slotClear(src, selectionStartInner, selectionEndInner); + } + else if (j == 0) + { + PatternEditorTools::slotCopy(dst, src, selectionStartInner, 7); + if (clear) + PatternEditorTools::slotClear(src, selectionStartInner, 7); + } + else if (j+selectionStartChannel == selectionEndChannel) + { + PatternEditorTools::slotCopy(dst, src, 0, selectionEndInner); + if (clear) + PatternEditorTools::slotClear(src, 0, selectionEndInner); + } + else + { + PatternEditorTools::slotCopy(dst, src, 0, 7); + if (clear) + PatternEditorTools::slotClear(src, 0, 7); + } + } + } + + // destination position + pp_int32 offsetStartChannel = selectionStartChannel + moveChannels; + pp_int32 offsetStartRow = selectionStartRow + moveRows; + + // paste from temporary buffer to target location + for (pp_int32 i = 0; i < selectionHeight; i++) + { + pp_int32 rowDst = offsetStartRow + i; + + if (rowDst < 0 || rowDst >= pattern->rows) + continue; + + for (pp_int32 j = 0; j < selectionWidth; j++) + { + pp_int32 channelDst = offsetStartChannel + j; + + if (channelDst < 0 || channelDst >= pattern->channum) + continue; + + mp_ubyte* src = buffer + i*rowSizeDst + j*slotSize; + mp_ubyte* dst = pattern->patternData + rowDst*rowSizeSrc + channelDst*slotSize; + + if (selectionWidth == 1) + PatternEditorTools::slotCopy(dst, src, selectionStartInner, selectionEndInner); + else if (j == 0) + PatternEditorTools::slotCopy(dst, src, selectionStartInner, 7); + else if (j+selectionStartChannel == selectionEndChannel) + PatternEditorTools::slotCopy(dst, src, 0, selectionEndInner); + else + PatternEditorTools::slotCopy(dst, src, 0, 7); + } + } + + delete[] buffer; + + return true; +} diff --git a/src/tracker/PatternEditorTools.h b/src/tracker/PatternEditorTools.h index dcd99c75..98188ce4 100644 --- a/src/tracker/PatternEditorTools.h +++ b/src/tracker/PatternEditorTools.h @@ -158,6 +158,7 @@ class PatternEditorTools void attachPattern(TXMPattern* pattern) { this->pattern = pattern; } void clearSelection(const Position& ss, const Position& se); + bool moveSelection(const Position& ss, const Position& se, pp_int32 moveChannels, pp_int32 moveRows, bool clear); bool expandPattern(); bool shrinkPattern(); @@ -200,6 +201,7 @@ class PatternEditorTools static void slotTransparentCopy(mp_ubyte* dst, mp_ubyte* src, pp_int32 from, pp_int32 to); static void slotClear(mp_ubyte* dst, pp_int32 from, pp_int32 to); + static bool selectionContains(const TXMPattern* pattern, const Position& ss, const Position& se, const Position& pos); static bool hasValidSelection(const TXMPattern* pattern, const Position& ss, const Position& se, pp_int32 numVisibleChannels = -1); static bool normalizeSelection(const TXMPattern* pattern, From 268da187db528fee43a961fe9b1f782427717bf3 Mon Sep 17 00:00:00 2001 From: Jeremy Clarke Date: Fri, 1 May 2020 01:43:08 +0100 Subject: [PATCH 3/4] More intuitive cutting/pasting of partial fx cmds This allows to you clear the effect type while leaving the effect parameter intact and also to paste only a parameter value into a slot with no effect (in both case the effect is set to arpeggio, which is rendered as 0 in the pattern editor). --- src/tracker/PatternEditor.cpp | 4 +- src/tracker/PatternEditorClipBoard.cpp | 9 +- src/tracker/PatternEditorTools.cpp | 113 +++++++++++++++++-------- 3 files changed, 84 insertions(+), 42 deletions(-) diff --git a/src/tracker/PatternEditor.cpp b/src/tracker/PatternEditor.cpp index 41c3d7b2..ac8a544e 100644 --- a/src/tracker/PatternEditor.cpp +++ b/src/tracker/PatternEditor.cpp @@ -1257,7 +1257,7 @@ bool PatternEditor::writeEffect(pp_int32 effNum, pp_uint8 eff, pp_uint8 op, patternTools.setPosition(pattern, cursor.channel, cursor.row); // only write effect, when valid effect - // (0 is not a valid effect in my internal format, arpeggio is mapped to 0x30) + // (0 is not a valid effect in my internal format, arpeggio is mapped to 0x20) if (eff) patternTools.setEffect(effNum, eff, op); else @@ -1290,7 +1290,7 @@ void PatternEditor::writeDirectEffect(pp_int32 effNum, pp_uint8 eff, pp_uint8 op patternTools.setPosition(pattern, track, row); // only write effect, when valid effect - // (0 is not a valid effect in my internal format, arpeggio is mapped to 0x30) + // (0 is not a valid effect in my internal format, arpeggio is mapped to 0x20) if (eff) patternTools.setEffect(effNum, eff, op); } diff --git a/src/tracker/PatternEditorClipBoard.cpp b/src/tracker/PatternEditorClipBoard.cpp index fef10679..b8529246 100644 --- a/src/tracker/PatternEditorClipBoard.cpp +++ b/src/tracker/PatternEditorClipBoard.cpp @@ -56,14 +56,14 @@ void PatternEditor::ClipBoard::makeCopy(TXMPattern& pattern, const PatternEditor return; // only entire instrument column is allowed - if (selectionStart.inner >= 1 && selectionStart.inner<=2) + if (selectionStart.inner >= 1 && selectionStart.inner <= 2) selectionStart.inner = 1; - if (selectionEnd.inner >= 1 && selectionEnd.inner<=2) + if (selectionEnd.inner >= 1 && selectionEnd.inner <= 2) selectionEnd.inner = 2; // only entire volume column can be selected - if (selectionStart.inner >= 3 && selectionStart.inner<=4) + if (selectionStart.inner >= 3 && selectionStart.inner <= 4) selectionStart.inner = 3; - if (selectionEnd.inner >= 3 && selectionEnd.inner<=4) + if (selectionEnd.inner >= 3 && selectionEnd.inner <= 4) selectionEnd.inner = 4; selectionWidth = selectionEnd.channel - selectionStart.channel + 1; @@ -71,6 +71,7 @@ void PatternEditor::ClipBoard::makeCopy(TXMPattern& pattern, const PatternEditor mp_sint32 slotSize = pattern.effnum * 2 + 2; + // sanity check: only operate on internal XM pattern data ASSERT(slotSize == 6); mp_sint32 rowSizeDst = slotSize*selectionWidth; diff --git a/src/tracker/PatternEditorTools.cpp b/src/tracker/PatternEditorTools.cpp index 08a4a059..886fe7b3 100644 --- a/src/tracker/PatternEditorTools.cpp +++ b/src/tracker/PatternEditorTools.cpp @@ -155,14 +155,14 @@ void PatternEditorTools::clearSelection(const PatternEditorTools::Position& ss, return; // only entire instrument column is allowed - if (selectionStartInner >= 1 && selectionStartInner<=2) + if (selectionStartInner >= 1 && selectionStartInner <= 2) selectionStartInner = 1; - if (selectionEndInner >= 1 && selectionEndInner<=2) + if (selectionEndInner >= 1 && selectionEndInner <= 2) selectionEndInner = 2; // only entire volume column can be selected - if (selectionStartInner >= 3 && selectionStartInner<=4) + if (selectionStartInner >= 3 && selectionStartInner <= 4) selectionStartInner = 3; - if (selectionEndInner >= 3 && selectionEndInner<=4) + if (selectionEndInner >= 3 && selectionEndInner <= 4) selectionEndInner = 4; pp_int32 selectionWidth = selectionEndChannel - selectionStartChannel + 1; @@ -393,14 +393,14 @@ pp_int32 PatternEditorTools::insRemapSelection(const Position& ss, const Positio return 0; // only entire instrument column is allowed - if (selectionStartInner >= 1 && selectionStartInner<=2) + if (selectionStartInner >= 1 && selectionStartInner <= 2) selectionStartInner = 1; - if (selectionEndInner >= 1 && selectionEndInner<=2) + if (selectionEndInner >= 1 && selectionEndInner <= 2) selectionEndInner = 2; // only entire volume column can be selected - if (selectionStartInner >= 3 && selectionStartInner<=4) + if (selectionStartInner >= 3 && selectionStartInner <= 4) selectionStartInner = 3; - if (selectionEndInner >= 3 && selectionEndInner<=4) + if (selectionEndInner >= 3 && selectionEndInner <= 4) selectionEndInner = 4; pp_int32 selectionWidth = selectionEndChannel - selectionStartChannel + 1; @@ -496,14 +496,14 @@ pp_int32 PatternEditorTools::noteTransposeSelection(const Position& ss, const Po return 0; // only entire instrument column is allowed - if (selectionStartInner >= 1 && selectionStartInner<=2) + if (selectionStartInner >= 1 && selectionStartInner <= 2) selectionStartInner = 1; - if (selectionEndInner >= 1 && selectionEndInner<=2) + if (selectionEndInner >= 1 && selectionEndInner <= 2) selectionEndInner = 2; // only entire volume column can be selected - if (selectionStartInner >= 3 && selectionStartInner<=4) + if (selectionStartInner >= 3 && selectionStartInner <= 4) selectionStartInner = 3; - if (selectionEndInner >= 3 && selectionEndInner<=4) + if (selectionEndInner >= 3 && selectionEndInner <= 4) selectionEndInner = 4; pp_int32 selectionWidth = selectionEndChannel - selectionStartChannel + 1; @@ -624,14 +624,14 @@ pp_int32 PatternEditorTools::interpolateValuesInSelection(const PatternEditorToo return 0; // only entire instrument column is allowed - if (selectionStartInner >= 1 && selectionStartInner<=2) + if (selectionStartInner >= 1 && selectionStartInner <= 2) selectionStartInner = 1; - if (selectionEndInner >= 1 && selectionEndInner<=2) + if (selectionEndInner >= 1 && selectionEndInner <= 2) selectionEndInner = 2; // only entire volume column can be selected - if (selectionStartInner >= 3 && selectionStartInner<=4) + if (selectionStartInner >= 3 && selectionStartInner <= 4) selectionStartInner = 3; - if (selectionEndInner >= 3 && selectionEndInner<=4) + if (selectionEndInner >= 3 && selectionEndInner <= 4) selectionEndInner = 4; // only entire effect operand column if (selectionStartInner >= 6 && selectionStartInner<=7) @@ -1733,14 +1733,14 @@ bool PatternEditorTools::selectionContains(const TXMPattern* pattern, const Posi return false; // only entire instrument column is allowed - if (selectionStartInner >= 1 && selectionStartInner<=2) + if (selectionStartInner >= 1 && selectionStartInner <= 2) selectionStartInner = 1; - if (selectionEndInner >= 1 && selectionEndInner<=2) + if (selectionEndInner >= 1 && selectionEndInner <= 2) selectionEndInner = 2; // only entire volume column can be selected - if (selectionStartInner >= 3 && selectionStartInner<=4) + if (selectionStartInner >= 3 && selectionStartInner <= 4) selectionStartInner = 3; - if (selectionEndInner >= 3 && selectionEndInner<=4) + if (selectionEndInner >= 3 && selectionEndInner <= 4) selectionEndInner = 4; bool outside = @@ -1774,12 +1774,14 @@ void PatternEditorTools::slotCopy(mp_ubyte* dst, mp_ubyte* src, pp_int32 from, p { pp_int32 i = 0; + // copy note if (i >= from && i <= to) { *dst = *src; } i++; - + + // copy instrument first digit if (i >= from && i <= to) { *(dst+1) &= 0x0F; @@ -1787,26 +1789,30 @@ void PatternEditorTools::slotCopy(mp_ubyte* dst, mp_ubyte* src, pp_int32 from, p } i++; + // copy instrument second digit if (i >= from && i <= to) { *(dst+1) &= 0xF0; *(dst+1) |= *(src+1)&0xF; } i++; - + + // copy volume if (i >= from && i <= to) { *(dst+2) = *(src+2); *(dst+3) = *(src+3); } i+=2; - + + // copy effect type if (i >= from && i <= to) { *(dst+4) = *(src+4); } i++; - + + // copy effect parameter first digit if (i >= from && i <= to) { *(dst+5) &= 0x0F; @@ -1814,24 +1820,33 @@ void PatternEditorTools::slotCopy(mp_ubyte* dst, mp_ubyte* src, pp_int32 from, p } i++; + // copy effect parameter second digit if (i >= from && i <= to) { *(dst+5) &= 0xF0; *(dst+5) |= *(src+5)&0xF; } i++; + + // special cases for arpeggio effect: + if (*(dst+4) == 0x20 && *(dst+5) == 0) + *(dst+4) = 0; + else if (*(dst+4) == 0 && *(dst+5) != 0) + *(dst+4) = 0x20; } void PatternEditorTools::slotTransparentCopy(mp_ubyte* dst, mp_ubyte* src, pp_int32 from, pp_int32 to) { pp_int32 i = 0; + // copy note if (i >= from && i <= to && *src) { *dst = *src; } i++; - + + // copy instrument first digit if (i >= from && i <= to && (*(src+1)&0xF0)) { *(dst+1) &= 0x0F; @@ -1839,26 +1854,30 @@ void PatternEditorTools::slotTransparentCopy(mp_ubyte* dst, mp_ubyte* src, pp_in } i++; + // copy instrument second digit if (i >= from && i <= to && (*(src+1)&0xF)) { *(dst+1) &= 0xF0; *(dst+1) |= *(src+1)&0xF; } i++; - + + // copy volume if (i >= from && i <= to && (*(src+2) || *(src+3))) { *(dst+2) = *(src+2); *(dst+3) = *(src+3); } i+=2; - + + // copy effect type if (i >= from && i <= to && (*(src+4))) { *(dst+4) = *(src+4); } i++; - + + // copy effect parameter first digit if (i >= from && i <= to && (*(src+5)&0xF0)) { *(dst+5) &= 0x0F; @@ -1866,60 +1885,80 @@ void PatternEditorTools::slotTransparentCopy(mp_ubyte* dst, mp_ubyte* src, pp_in } i++; + // copy effect parameter second digit if (i >= from && i <= to && (*(src+5)&0xF)) { *(dst+5) &= 0xF0; *(dst+5) |= *(src+5)&0xF; } i++; + + // special cases for arpeggio effect: + if (*(dst+4) == 0x20 && *(dst+5) == 0) + *(dst+4) = 0; + else if (*(dst+4) == 0 && *(dst+5) != 0) + *(dst+4) = 0x20; } void PatternEditorTools::slotClear(mp_ubyte* dst, pp_int32 from, pp_int32 to) { pp_int32 i = 0; + // clear note if (i >= from && i <= to) { *dst = 0; } i++; - + + // clear instrument first digit if (i >= from && i <= to) { *(dst+1) &= 0x0F; } i++; + // clear instrument second digit if (i >= from && i <= to) { *(dst+1) &= 0xF0; } i++; + // clear volume if (i >= from && i <= to) { *(dst+2) = 0; *(dst+3) = 0; } i+=2; - + + // clear effect type if (i >= from && i <= to) { *(dst+4) = 0; } i++; - + + // clear effect parameter first digit if (i >= from && i <= to) { *(dst+5) &= 0x0F; } i++; + // clear effect parameter second digit if (i >= from && i <= to) { *(dst+5) &= 0xF0; } i++; + + // special cases for arpeggio effect: + if (*(dst+4) == 0x20 && *(dst+5) == 0) + *(dst+4) = 0; + else if (*(dst+4) == 0 && *(dst+5) != 0) + *(dst+4) = 0x20; } bool PatternEditorTools::moveSelection(const Position& ss, const Position& se, pp_int32 moveChannels, pp_int32 moveRows, bool clear) @@ -1946,23 +1985,25 @@ bool PatternEditorTools::moveSelection(const Position& ss, const Position& se, p if (!normalizeSelection(pattern, ss, se, selectionStartChannel, selectionStartRow, selectionStartInner, selectionEndChannel, selectionEndRow,selectionEndInner)) - return 0; + return false; // only entire instrument column is allowed - if (selectionStartInner >= 1 && selectionStartInner<=2) + if (selectionStartInner >= 1 && selectionStartInner <= 2) selectionStartInner = 1; - if (selectionEndInner >= 1 && selectionEndInner<=2) + if (selectionEndInner >= 1 && selectionEndInner <= 2) selectionEndInner = 2; // only entire volume column can be selected - if (selectionStartInner >= 3 && selectionStartInner<=4) + if (selectionStartInner >= 3 && selectionStartInner <= 4) selectionStartInner = 3; - if (selectionEndInner >= 3 && selectionEndInner<=4) + if (selectionEndInner >= 3 && selectionEndInner <= 4) selectionEndInner = 4; pp_int32 selectionWidth = selectionEndChannel - selectionStartChannel + 1; pp_int32 selectionHeight = selectionEndRow - selectionStartRow + 1; mp_sint32 slotSize = pattern->effnum * 2 + 2; + + // sanity check: only operate on internal XM pattern data ASSERT(slotSize == 6); mp_sint32 rowSizeDst = slotSize*selectionWidth; From 4630751f99ce5980d0326ed216030613d92fc219 Mon Sep 17 00:00:00 2001 From: Jeremy Clarke Date: Sat, 2 May 2020 21:38:28 +0100 Subject: [PATCH 4/4] Allow selections by clicking outside the pattern bounds When clicking above the first row, or beyond the rightmost channel, instead of ignoring the input, selection will be properly clamped. Selections that would exceed the bottom of the pattern are now also clamped. --- src/ppui/Tools.cpp | 5 ++ src/ppui/Tools.h | 2 + src/tracker/PatternEditorControl.cpp | 13 ++-- .../PatternEditorControlEventListener.cpp | 77 ++++++++++++------- 4 files changed, 60 insertions(+), 37 deletions(-) diff --git a/src/ppui/Tools.cpp b/src/ppui/Tools.cpp index b9b644b2..674114ba 100644 --- a/src/ppui/Tools.cpp +++ b/src/ppui/Tools.cpp @@ -173,3 +173,8 @@ bool PPTools::decodeByteArray(pp_uint8* array, pp_uint32 size, const PPString& s return true; } +pp_int32 PPTools::clamp(pp_int32 a, pp_int32 min, pp_int32 max) +{ + return (a < min ? min : (a >= max ? max-1 : a)); +} + diff --git a/src/ppui/Tools.h b/src/ppui/Tools.h index bf353a48..67d41c7f 100644 --- a/src/ppui/Tools.h +++ b/src/ppui/Tools.h @@ -47,6 +47,8 @@ class PPTools static PPString encodeByteArray(const pp_uint8* array, pp_uint32 size); static bool decodeByteArray(pp_uint8* array, pp_uint32 size, const PPString& str); + + static pp_int32 clamp(pp_int32 a, pp_int32 min, pp_int32 max); }; #endif diff --git a/src/tracker/PatternEditorControl.cpp b/src/tracker/PatternEditorControl.cpp index d7cbd9ad..6ff63541 100644 --- a/src/tracker/PatternEditorControl.cpp +++ b/src/tracker/PatternEditorControl.cpp @@ -22,6 +22,7 @@ #include "PatternEditorControl.h" #include "GraphicsAbstract.h" +#include "Tools.h" #include "Screen.h" #include "Control.h" #include "Font.h" @@ -828,14 +829,10 @@ void PatternEditorControl::paint(PPGraphicsAbstract* g) if (i2 >= 0 && j2 >= 0 && i1 < pattern->rows && j1 < numVisibleChannels) { - #define CLAMP(a, min, max) ((a) < (min) ? (min) : ((a) >= (max) ? (max-1) : (a))) - - i1 = CLAMP(i1, 0, pattern->rows); - i2 = CLAMP(i2, 0, pattern->rows); - j1 = CLAMP(j1, 0, numVisibleChannels); - j2 = CLAMP(j2, 0, numVisibleChannels); - - #undef CLAMP + i1 = PPTools::clamp(i1, 0, pattern->rows); + i2 = PPTools::clamp(i2, 0, pattern->rows); + j1 = PPTools::clamp(j1, 0, numVisibleChannels); + j2 = PPTools::clamp(j2, 0, numVisibleChannels); pp_int32 x1 = (location.x + (j1-startPos) * slotSize + SCROLLBARWIDTH) + cursorPositions[selectionStart.inner] + (getRowCountWidth() + 4); pp_int32 y1 = (location.y + (i1-startIndex) * font->getCharHeight() + SCROLLBARWIDTH) + (font->getCharHeight() + 4); diff --git a/src/tracker/PatternEditorControlEventListener.cpp b/src/tracker/PatternEditorControlEventListener.cpp index 3bdcebb8..bfedace4 100644 --- a/src/tracker/PatternEditorControlEventListener.cpp +++ b/src/tracker/PatternEditorControlEventListener.cpp @@ -366,9 +366,18 @@ pp_int32 PatternEditorControl::dispatchEvent(PPEvent* event) if (newStartIndex < visibleRows && newStartIndex >= 0) { if (newStartIndex + startIndex < 0) - break; - - preCursor.row = newStartIndex + startIndex; + { + patternEditor->resetSelection(); + preCursor.row = 0; + } + else if (newStartIndex + startIndex >= patternEditor->getNumRows()) + { + preCursor.row = patternEditor->getNumRows()-1; + } + else + { + preCursor.row = newStartIndex + startIndex; + } } if (newStartPos < visibleHeight && newStartPos >= 0) @@ -380,20 +389,27 @@ pp_int32 PatternEditorControl::dispatchEvent(PPEvent* event) break; preCursor.channel = newStartPos + startPos; + preCursor.inner = 0; if (preCursor.channel >= patternEditor->getNumChannels()) - break; - - preCursor.inner = 0; - - pp_int32 innerPos = cp.x % slotSize; - for (pp_uint32 i = 0; i < sizeof(cursorPositions) - 1; i++) { - if (innerPos >= cursorPositions[i] && - innerPos < cursorPositions[i+1]) + // clicked beyond rightmost channel, start selection from the edge + patternEditor->resetSelection(); + preCursor.channel = patternEditor->getNumChannels() - 1; + preCursor.inner = 7; + } + else + { + // find which column in the channel was clicked + pp_int32 innerPos = cp.x % slotSize; + for (pp_uint32 i = 0; i < sizeof(cursorPositions) - 1; i++) { - preCursor.inner = i; - break; + if (innerPos >= cursorPositions[i] && + innerPos < cursorPositions[i+1]) + { + preCursor.inner = i; + break; + } } } @@ -651,6 +667,7 @@ pp_int32 PatternEditorControl::dispatchEvent(PPEvent* event) mp_sint32 cursorPositionRow = newStartIndex + startIndex; mp_sint32 cursorPositionChannel = newStartPos + startPos; + mp_sint32 cursorPositionInner; if (moveSelection) { @@ -659,38 +676,40 @@ pp_int32 PatternEditorControl::dispatchEvent(PPEvent* event) } else { - if (cursorPositionRow < 0) cursorPositionRow = 0; - if (cursorPositionChannel < 0) cursorPositionChannel = 0; - - //if (cursorPositionRow < 0 || cursorPositionChannel < 0) - // break; - - if (cursorPositionChannel >= patternEditor->getNumChannels()) + if (cursorPositionRow < 0) + cursorPositionRow = 0; + else if (cursorPositionRow >= patternEditor->getNumRows()) + cursorPositionRow = patternEditor->getNumRows()-1; + + if (cursorPositionChannel < 0) + { + cursorPositionChannel = 0; + cursorPositionInner = 0; + } + else if (cursorPositionChannel >= patternEditor->getNumChannels()) { - patternEditor->getSelection().end.channel = patternEditor->getNumChannels()-1; - patternEditor->getSelection().end.inner = 7; + cursorPositionChannel = patternEditor->getNumChannels()-1; + cursorPositionInner = 7; } else { - - // start selecting row - patternEditor->getSelection().end.channel = cursorPositionChannel; - patternEditor->getSelection().end.row = cursorPositionRow; - pp_int32 innerPos = cp.x % slotSize; - //selectionEnd.inner = 7; for (pp_uint32 i = 0; i < sizeof(cursorPositions) - 1; i++) { if (innerPos >= cursorPositions[i] && innerPos < cursorPositions[i+1]) { - patternEditor->getSelection().end.inner = i; + cursorPositionInner = i; break; } } } + patternEditor->getSelection().end.row = cursorPositionRow; + patternEditor->getSelection().end.channel = cursorPositionChannel; + patternEditor->getSelection().end.inner = cursorPositionInner; + setScrollbarPositions(startIndex, startPos); }