From fd4479f992ab8e52f8c3bdcbf5046e75c41eef21 Mon Sep 17 00:00:00 2001 From: Andrew Belt Date: Wed, 30 Dec 2020 19:26:09 -0500 Subject: [PATCH] Use a ~15px dragging threshold when dragging a Module from the Module Browser, so that clicking it makes it stay in the last right-clicked position. Make event framework trigger DragHover before DragMove. --- include/app/ModuleWidget.hpp | 2 +- src/app/ModuleBrowser.cpp | 2 +- src/app/ModuleWidget.cpp | 44 ++++++++++++++++++++++++++++-------- src/event.cpp | 21 ++++++++++------- 4 files changed, 49 insertions(+), 20 deletions(-) diff --git a/include/app/ModuleWidget.hpp b/include/app/ModuleWidget.hpp index 9bf7d479..c0a4465f 100644 --- a/include/app/ModuleWidget.hpp +++ b/include/app/ModuleWidget.hpp @@ -95,7 +95,7 @@ struct ModuleWidget : widget::OpaqueWidget { */ virtual void appendContextMenu(ui::Menu* menu) {} - PRIVATE math::Vec& dragPos(); + PRIVATE math::Vec& dragOffset(); PRIVATE math::Vec& oldPos(); PRIVATE engine::Module* releaseModule(); }; diff --git a/src/app/ModuleBrowser.cpp b/src/app/ModuleBrowser.cpp index 87f99999..e90ad9e7 100644 --- a/src/app/ModuleBrowser.cpp +++ b/src/app/ModuleBrowser.cpp @@ -230,7 +230,7 @@ struct ModelBox : widget::OpaqueWidget { // Set the drag position at the center of the module // TODO This doesn't work because ModuleWidget::onDragStart, which is called afterwards, overwrites this. - mw->dragPos() = mw->box.size.div(2); + mw->dragOffset() = mw->box.size.div(2); } } diff --git a/src/app/ModuleWidget.cpp b/src/app/ModuleWidget.cpp index e784eebd..528d5c27 100644 --- a/src/app/ModuleWidget.cpp +++ b/src/app/ModuleWidget.cpp @@ -361,9 +361,15 @@ struct ModuleDeleteItem : ui::MenuItem { struct ModuleWidget::Internal { - /** The position the user clicked on the module to start dragging in the RackWidget. + /** The module position clicked on to start dragging in the rack. */ - math::Vec dragPos; + math::Vec dragOffset; + + /** Global rack position the user clicked on. + */ + math::Vec dragRackPos; + bool dragRackEnabled; + /** The position in the RackWidget when dragging began. Used for history::ModuleMove. Set by RackWidget::updateModuleOldPositions() when *any* module begins dragging, since force-dragging can move other modules around. @@ -487,7 +493,7 @@ void ModuleWidget::onButton(const event::Button& e) { // Set starting drag position even if we don't consume it if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_LEFT) { - internal->dragPos = e.pos; + internal->dragOffset = e.pos; } if (e.isConsumed()) @@ -545,6 +551,11 @@ void ModuleWidget::onHoverKey(const event::HoverKey& e) { void ModuleWidget::onDragStart(const event::DragStart& e) { if (e.button == GLFW_MOUSE_BUTTON_LEFT) { + // Clear dragRack so dragging in not enabled until mouse is moved a bit. + internal->dragRackPos = math::Vec(NAN, NAN); + internal->dragRackEnabled = false; + + // Prepare initial position of modules for history. APP->scene->rack->updateModuleOldPositions(); } } @@ -561,11 +572,24 @@ void ModuleWidget::onDragEnd(const event::DragEnd& e) { void ModuleWidget::onDragMove(const event::DragMove& e) { if (e.button == GLFW_MOUSE_BUTTON_LEFT) { if (!settings::lockModules) { - math::Vec pos = APP->scene->rack->mousePos.minus(internal->dragPos); - if ((APP->window->getMods() & RACK_MOD_MASK) == RACK_MOD_CTRL) - APP->scene->rack->setModulePosForce(this, pos); - else - APP->scene->rack->setModulePosNearest(this, pos); + // Set dragRackPos on the first time after dragging + math::Vec mousePos = APP->scene->rack->mousePos; + if (!internal->dragRackPos.isFinite()) + internal->dragRackPos = mousePos; + + // Check if the mouse has moved enough to start dragging the module. + const float dist = RACK_GRID_WIDTH; + if (!internal->dragRackEnabled && internal->dragRackPos.minus(mousePos).square() >= std::pow(dist, 2)) + internal->dragRackEnabled = true; + + // Move module + if (internal->dragRackEnabled) { + math::Vec pos = mousePos.minus(internal->dragOffset); + if ((APP->window->getMods() & RACK_MOD_MASK) == RACK_MOD_CTRL) + APP->scene->rack->setModulePosForce(this, pos); + else + APP->scene->rack->setModulePosNearest(this, pos); + } } } } @@ -1062,8 +1086,8 @@ void ModuleWidget::createContextMenu() { } -math::Vec& ModuleWidget::dragPos() { - return internal->dragPos; +math::Vec& ModuleWidget::dragOffset() { + return internal->dragOffset; } math::Vec& ModuleWidget::oldPos() { diff --git a/src/event.cpp b/src/event.cpp index b6beb07f..4fb4d87d 100644 --- a/src/event.cpp +++ b/src/event.cpp @@ -193,12 +193,7 @@ bool State::handleHover(math::Vec pos, math::Vec mouseDelta) { } if (draggedWidget) { - // Trigger DragMove event - DragMove eDragMove; - eDragMove.button = dragButton; - eDragMove.mouseDelta = mouseDelta; - draggedWidget->onDragMove(eDragMove); - + bool dragHovered = false; if (!cursorLocked) { // Trigger DragHover event Context cDragHover; @@ -211,9 +206,18 @@ bool State::handleHover(math::Vec pos, math::Vec mouseDelta) { rootWidget->onDragHover(eDragHover); setDragHovered(cDragHover.target); + // If consumed, don't continue after DragMove so Hover is not triggered. if (cDragHover.target) - return true; + dragHovered = true; } + + // Trigger DragMove event + DragMove eDragMove; + eDragMove.button = dragButton; + eDragMove.mouseDelta = mouseDelta; + draggedWidget->onDragMove(eDragMove); + if (dragHovered) + return true; } if (!cursorLocked) { @@ -226,7 +230,8 @@ bool State::handleHover(math::Vec pos, math::Vec mouseDelta) { rootWidget->onHover(eHover); setHovered(cHover.target); - return !!cHover.target; + if (cHover.target) + return true; } return false; }