From 19f806dbada99ba8305b53937e86fa5b1a708a35 Mon Sep 17 00:00:00 2001 From: Andrew Belt Date: Sun, 7 Nov 2021 13:24:06 -0500 Subject: [PATCH] Implement PortCreateCableItem and PortCableItem. --- include/app/CableWidget.hpp | 1 - include/app/RackWidget.hpp | 2 +- src/app/CableWidget.cpp | 9 ---- src/app/PortWidget.cpp | 104 +++++++++++++++++++++++++++++------- src/app/RackWidget.cpp | 14 ++++- 5 files changed, 100 insertions(+), 30 deletions(-) diff --git a/include/app/CableWidget.hpp b/include/app/CableWidget.hpp index dcaa8303..6c86438f 100644 --- a/include/app/CableWidget.hpp +++ b/include/app/CableWidget.hpp @@ -30,7 +30,6 @@ struct CableWidget : widget::Widget { CableWidget(); ~CableWidget(); - void setNextCableColor(); bool isComplete(); /** Based on the input/output ports, re-creates the cable and removes/adds it to the Engine. */ void updateCable(); diff --git a/include/app/RackWidget.hpp b/include/app/RackWidget.hpp index d8a6fe42..cb95319b 100644 --- a/include/app/RackWidget.hpp +++ b/include/app/RackWidget.hpp @@ -24,7 +24,6 @@ struct RackWidget : widget::OpaqueWidget { CableWidget* incompleteCable = NULL; ParamWidget* touchedParam = NULL; - int nextCableColorId = 0; PRIVATE RackWidget(); PRIVATE ~RackWidget(); @@ -120,6 +119,7 @@ struct RackWidget : widget::OpaqueWidget { std::vector getCompleteCables(); /** Returns all cables attached to port, complete or not. */ std::vector getCablesOnPort(PortWidget* port); + NVGcolor getNextCableColor(); }; diff --git a/src/app/CableWidget.cpp b/src/app/CableWidget.cpp index d629ac08..8342fb84 100644 --- a/src/app/CableWidget.cpp +++ b/src/app/CableWidget.cpp @@ -138,15 +138,6 @@ CableWidget::~CableWidget() { } -void CableWidget::setNextCableColor() { - if (!settings::cableColors.empty()) { - int id = APP->scene->rack->nextCableColorId++; - APP->scene->rack->nextCableColorId %= settings::cableColors.size(); - color = settings::cableColors[id]; - } -} - - bool CableWidget::isComplete() { return outputPort && inputPort; } diff --git a/src/app/PortWidget.cpp b/src/app/PortWidget.cpp index 12abb379..085d8732 100644 --- a/src/app/PortWidget.cpp +++ b/src/app/PortWidget.cpp @@ -14,6 +14,15 @@ namespace rack { namespace app { +struct PortWidget::Internal { + ui::Tooltip* tooltip = NULL; + /** For overriding onDragStart behavior by menu items. */ + CableWidget* overrideCw = NULL; + bool overrideCreateCable = false; + NVGcolor overrideColor = color::BLACK_TRANSPARENT; +}; + + struct PortTooltip : ui::Tooltip { PortWidget* portWidget; @@ -83,15 +92,44 @@ struct ColorMenuItem : ui::MenuItem { struct PortCableItem : ColorMenuItem { + PortWidget* pw; + CableWidget* cw; + + void onButton(const ButtonEvent& e) override { + OpaqueWidget::onButton(e); + if (disabled) + return; + if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_LEFT && (e.mods & RACK_MOD_MASK) == 0) { + // Set PortWidget::onDragStart overrides + pw->internal->overrideCw = cw; + + // Pretend the PortWidget was clicked + e.consume(pw); + // Deletes `this` + doAction(); + } + } }; struct PortCreateCableItem : ColorMenuItem { -}; + PortWidget* pw; - -struct PortWidget::Internal { - ui::Tooltip* tooltip = NULL; + void onButton(const ButtonEvent& e) override { + OpaqueWidget::onButton(e); + if (disabled) + return; + if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_LEFT && (e.mods & RACK_MOD_MASK) == 0) { + // Set PortWidget::onDragStart overrides + pw->internal->overrideCreateCable = true; + pw->internal->overrideColor = color; + + // Pretend the PortWidget was clicked + e.consume(pw); + // Deletes `this` + doAction(); + } + } }; @@ -182,29 +220,32 @@ void PortWidget::createContextMenu() { menu->addChild(new ui::MenuSeparator); - // Create cable items + // New cable items bool createCableDisabled = (type == engine::Port::INPUT) && topCw; for (NVGcolor color : settings::cableColors) { // Include extra leading spaces for the color circle PortCreateCableItem* item = createMenuItem(" New cable", "Click+drag"); item->disabled = createCableDisabled; + item->pw = this; item->color = color; menu->addChild(item); } - // Cable items if (!cws.empty()) { menu->addChild(new ui::MenuSeparator); + } - for (auto it = cws.rbegin(); it != cws.rend(); it++) { - CableWidget* cw = *it; - PortWidget* pw = (type == engine::Port::INPUT) ? cw->outputPort : cw->inputPort; - engine::PortInfo* portInfo = pw->getPortInfo(); - - PortCableItem* item = createMenuItem(" " + portInfo->module->model->name + ": " + portInfo->getName()); - item->color = cw->color; - menu->addChild(item); - } + // Cable items + for (auto it = cws.rbegin(); it != cws.rend(); it++) { + CableWidget* cw = *it; + PortWidget* pw = (type == engine::Port::INPUT) ? cw->outputPort : cw->inputPort; + engine::PortInfo* portInfo = pw->getPortInfo(); + + PortCableItem* item = createMenuItem(" " + portInfo->module->model->name + ": " + portInfo->getName()); + item->color = cw->color; + item->pw = this; + item->cw = cw; + menu->addChild(item); } } @@ -273,8 +314,18 @@ void PortWidget::onDragStart(const DragStartEvent& e) { if (e.button != GLFW_MOUSE_BUTTON_LEFT) return; + DEFER({ + // Reset overrides + internal->overrideCw = NULL; + internal->overrideCreateCable = false; + internal->overrideColor = color::BLACK_TRANSPARENT; + }); + CableWidget* cw = NULL; - if ((APP->window->getMods() & RACK_MOD_MASK) == RACK_MOD_CTRL) { + if (internal->overrideCreateCable) { + // Keep cable NULL. Will be created below + } + else if ((APP->window->getMods() & RACK_MOD_MASK) == RACK_MOD_CTRL) { if (type == engine::Port::OUTPUT) { // Ctrl-clicking an output creates a new cable. // Keep cable NULL. Will be created below @@ -292,7 +343,10 @@ void PortWidget::onDragStart(const DragStartEvent& e) { } else { // Grab cable on top of stack - cw = APP->scene->rack->getTopCable(this); + if (internal->overrideCw) + cw = internal->overrideCw; + else + cw = APP->scene->rack->getTopCable(this); if (cw) { // history::CableRemove @@ -311,9 +365,23 @@ void PortWidget::onDragStart(const DragStartEvent& e) { } if (!cw) { + // Check that inputs don't already have a cable + if (type == engine::Port::INPUT) { + CableWidget* topCw = APP->scene->rack->getTopCable(this); + if (topCw) + return; + } + // Create a new cable cw = new CableWidget; - cw->setNextCableColor(); + + // Set color + if (internal->overrideColor.a > 0.f) + cw->color = internal->overrideColor; + else + cw->color = APP->scene->rack->getNextCableColor(); + + // Set port if (type == engine::Port::OUTPUT) cw->outputPort = this; else diff --git a/src/app/RackWidget.cpp b/src/app/RackWidget.cpp index 2cedf016..78442063 100644 --- a/src/app/RackWidget.cpp +++ b/src/app/RackWidget.cpp @@ -85,6 +85,7 @@ struct RackWidget::Internal { RailWidget* rail = NULL; widget::Widget* moduleContainer = NULL; widget::Widget* cableContainer = NULL; + int nextCableColorId = 0; /** The last mouse position in the RackWidget */ math::Vec mousePos; @@ -411,7 +412,7 @@ void RackWidget::fromJson(json_t* rootJ) { cw->fromJson(cableJ); // In <=v1, cable colors were not serialized, so choose one from the available colors. if (cw->color.a == 0.f) { - cw->setNextCableColor(); + cw->color = getNextCableColor(); } addCable(cw); } @@ -1393,5 +1394,16 @@ std::vector RackWidget::getCablesOnPort(PortWidget* port) { } +NVGcolor RackWidget::getNextCableColor() { + if (settings::cableColors.empty()) + return color::WHITE; + + int id = internal->nextCableColorId++; + internal->nextCableColorId %= settings::cableColors.size(); + return settings::cableColors[id]; +} + + + } // namespace app } // namespace rack