From e5ad462cd2f8034dcc643833cc44e879d80d6f7e Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 18 Jul 2025 05:05:56 -0500 Subject: [PATCH] GUI: new pattern cursor logic, part 20 oh yes --- src/gui/debugWindow.cpp | 4 ++++ src/gui/doAction.cpp | 26 +++++++++++++++++++++----- src/gui/editControls.cpp | 11 +++++++---- src/gui/editing.cpp | 19 +++++++++++++++---- src/gui/gui.cpp | 6 ++++++ src/gui/gui.h | 6 +++++- src/gui/pattern.cpp | 2 ++ 7 files changed, 60 insertions(+), 14 deletions(-) diff --git a/src/gui/debugWindow.cpp b/src/gui/debugWindow.cpp index b1b5e0a04..d08b89370 100644 --- a/src/gui/debugWindow.cpp +++ b/src/gui/debugWindow.cpp @@ -196,6 +196,10 @@ void FurnaceGUI::drawDebug() { ImGui::TextWrapped("%s",pdi.c_str()); ImGui::TreePop(); } + if (ImGui::TreeNode("GUI Status")) { + ImGui::Text("patScroll: %f",patScroll); + ImGui::TreePop(); + } if (ImGui::TreeNode("Sample Debug")) { for (int i=0; isong.sampleLen; i++) { DivSample* sample=e->getSample(i); diff --git a/src/gui/doAction.cpp b/src/gui/doAction.cpp index b223bf80e..4d8daed18 100644 --- a/src/gui/doAction.cpp +++ b/src/gui/doAction.cpp @@ -172,14 +172,30 @@ void FurnaceGUI::doAction(int what) { break; case GUI_ACTION_ORDER_LOCK: orderLock=!orderLock; + // move selection within bounds of current order if necessary if (selStart.order!=curOrder || selEnd.order!=curOrder) { - finishSelection(); // selection confinement logic - if (selStart.ordercurOrder) { - - } else if (selStart.order=curOrder && selEnd.order>curOrder) { + if (selStart.order==selEnd.order) { + // selection within one order - move it to the current one + } else if (selStart.ordercurOrder) { + // current order is inside selection - confine it to this order + selStart.y=0; + selEnd.y=e->curSubSong->patLen; + } else if (selStart.ordercurOrder) { + // current order intersects selection - clamp the bottom + selEnd.y=e->curSubSong->patLen; + } else { + // something else - reset selection... + selStart=cursor; + selEnd=cursor; } + selStart.order=curOrder; + selEnd.order=curOrder; + cursor.order=curOrder; + finishSelection(); } break; case GUI_ACTION_REPEAT_PATTERN: diff --git a/src/gui/editControls.cpp b/src/gui/editControls.cpp index ea363b5d9..97d840bcb 100644 --- a/src/gui/editControls.cpp +++ b/src/gui/editControls.cpp @@ -723,7 +723,10 @@ void FurnaceGUI::drawEditControls() { ImGui::SameLine(); ImGui::Checkbox(_("Edit"),&edit); ImGui::SameLine(); - ImGui::Checkbox(_("Lock"),&orderLock); + bool ol=orderLock; + if (ImGui::Checkbox(_("Lock"),&ol)) { + doAction(GUI_ACTION_ORDER_LOCK); + } ImGui::SameLine(); bool metro=e->getMetronome(); if (ImGui::Checkbox(_("Metronome"),&metro)) { @@ -813,7 +816,7 @@ void FurnaceGUI::drawEditControls() { pushToggleColors(orderLock); if (ImGui::Button(ICON_FA_LOCK "##OrderLock")) { - orderLock=!orderLock; + doAction(GUI_ACTION_ORDER_LOCK); } if (ImGui::IsItemHovered()) { ImGui::SetTooltip(_("Lock cursor/selection to this order")); @@ -939,7 +942,7 @@ void FurnaceGUI::drawEditControls() { pushToggleColors(orderLock); if (ImGui::Button(ICON_FA_LOCK "##OrderLock",buttonSize)) { - orderLock=!orderLock; + doAction(GUI_ACTION_ORDER_LOCK); } if (ImGui::IsItemHovered()) { ImGui::SetTooltip(_("Lock cursor/selection to this order")); @@ -1088,7 +1091,7 @@ void FurnaceGUI::drawEditControls() { ImGui::SameLine(); pushToggleColors(orderLock); if (ImGui::Button(ICON_FA_LOCK "##OrderLock")) { - orderLock=!orderLock; + doAction(GUI_ACTION_ORDER_LOCK); } if (ImGui::IsItemHovered()) { ImGui::SetTooltip(_("Lock cursor/selection to this order")); diff --git a/src/gui/editing.cpp b/src/gui/editing.cpp index e41c399f2..ece8acead 100644 --- a/src/gui/editing.cpp +++ b/src/gui/editing.cpp @@ -53,6 +53,8 @@ const char* FurnaceGUI::noteNameNormal(short note, short octave) { } void FurnaceGUI::prepareUndo(ActionType action, UndoRegion region) { + prevCursor=cursor; + if (region.begin.ord==-1) { region.begin.ord=selStart.order; region.end.ord=selEnd.order; @@ -126,9 +128,10 @@ void FurnaceGUI::makeUndo(ActionType action, UndoRegion region) { bool shallWalk=false; UndoStep s; s.type=action; - s.cursor=cursor; + s.cursor=prevCursor; s.selStart=selStart; s.selEnd=selEnd; + s.scroll=patScroll; s.order=curOrder; s.oldOrdersLen=oldOrdersLen; s.newOrdersLen=e->curSubSong->ordersLen; @@ -2131,7 +2134,6 @@ void FurnaceGUI::moveSelected(int x, int y) { void FurnaceGUI::doUndo() { if (undoHist.empty()) return; UndoStep& us=undoHist.back(); - redoHist.push_back(us); MARK_MODIFIED; switch (us.type) { @@ -2172,8 +2174,10 @@ void FurnaceGUI::doUndo() { selStart=us.selStart; selEnd=us.selEnd; curNibble=us.nibble; - updateScroll(cursor.y); setOrder(us.order); + if (us.scroll>=0.0f) { + updateScrollRaw(us.scroll); + } } } e->walkSong(loopOrder,loopRow,loopEnd); @@ -2205,6 +2209,11 @@ void FurnaceGUI::doUndo() { e->setOrder(curOrder); } + // reverse state for redo + us.cursor=cursor; + us.scroll=patScroll; + redoHist.push_back(us); + undoHist.pop_back(); } @@ -2252,8 +2261,10 @@ void FurnaceGUI::doRedo() { selStart=us.selStart; selEnd=us.selEnd; curNibble=us.nibble; - updateScroll(cursor.y); setOrder(us.order); + if (us.scroll>=0.0f) { + updateScrollRaw(us.scroll); + } } } e->walkSong(loopOrder,loopRow,loopEnd); diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 36ac8b87c..f0b76f46c 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -563,6 +563,11 @@ void FurnaceGUI::updateScroll(int amount) { haveHitBounds=false; } +void FurnaceGUI::updateScrollRaw(float amount) { + nextScroll=amount; + haveHitBounds=false; +} + void FurnaceGUI::addScroll(int amount) { float lineHeight=(patFont->FontSize+2*dpiScale); nextAddScroll=lineHeight*amount; @@ -8836,6 +8841,7 @@ FurnaceGUI::FurnaceGUI(): nextAddScroll(0.0f), orderScroll(0.0f), orderScrollSlideOrigin(0.0f), + patScroll(-1.0f), orderScrollRealOrigin(0.0f,0.0f), dragMobileMenuOrigin(0.0f,0.0f), layoutTimeBegin(0), diff --git a/src/gui/gui.h b/src/gui/gui.h index 8b15f60ad..ab5fa65b1 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1098,6 +1098,7 @@ struct UndoOtherData { struct UndoStep { ActionType type; SelectionPoint cursor, selStart, selEnd; + float scroll; int order; bool nibble; int oldOrdersLen, newOrdersLen; @@ -1111,6 +1112,7 @@ struct UndoStep { cursor(), selStart(), selEnd(), + scroll(-1.0f), order(0), nibble(false), oldOrdersLen(0), @@ -2371,7 +2373,7 @@ class FurnaceGUI { bool clockShowReal, clockShowRow, clockShowBeat, clockShowMetro, clockShowTime; float clockMetroTick[16]; - SelectionPoint selStart, selEnd, cursor, cursorDrag, dragStart, dragEnd; + SelectionPoint selStart, selEnd, cursor, cursorDrag, dragStart, dragEnd, prevCursor; bool selecting, selectingFull, dragging, curNibble, orderNibble, followOrders, followPattern, wasFollowing, changeAllOrders, mobileUI; bool collapseWindow, demandScrollX, fancyPattern, firstFrame, tempoView, waveHex, waveSigned, waveGenVisible, lockLayout, editOptsVisible, latchNibble, nonLatchNibble; bool keepLoopAlive, keepGrooveAlive, orderScrollLocked, orderScrollTolerance, dragMobileMenu, dragMobileEditButton, wantGrooveListFocus; @@ -2531,6 +2533,7 @@ class FurnaceGUI { bool bindSetActive, bindSetPending; float nextScroll, nextAddScroll, nextAddScrollX, orderScroll, orderScrollSlideOrigin; + float patScroll; ImVec2 orderScrollRealOrigin; ImVec2 dragMobileMenuOrigin; @@ -3114,6 +3117,7 @@ class FurnaceGUI { void bindEngine(DivEngine* eng); void enableSafeMode(); void updateScroll(int amount); + void updateScrollRaw(float amount); void addScroll(int amount); void addScrollX(int amount); void setFileName(String name); diff --git a/src/gui/pattern.cpp b/src/gui/pattern.cpp index 84d029b8c..c0003b01f 100644 --- a/src/gui/pattern.cpp +++ b/src/gui/pattern.cpp @@ -1401,6 +1401,8 @@ void FurnaceGUI::drawPattern() { } } } + // HACK: we need to capture the last scroll position in order to restore it during undo/redo + patScroll=ImGui::GetScrollY(); // HACK: rendering here would cause the pairs to be drawn behind the pattern for some reason... // ...so we capture the table's window draw list... tdl=ImGui::GetWindowDrawList();