Browse Source

Move CableContainer methods into RackWidget

tags/v1.0.0
Andrew Belt 5 years ago
parent
commit
c4a33bedc3
11 changed files with 246 additions and 278 deletions
  1. +0
    -37
      include/app/CableContainer.hpp
  2. +38
    -14
      include/app/RackWidget.hpp
  3. +0
    -1
      include/rack.hpp
  4. +0
    -141
      src/app/CableContainer.cpp
  5. +2
    -2
      src/app/CableWidget.cpp
  6. +2
    -2
      src/app/ModuleWidget.cpp
  7. +14
    -14
      src/app/PortWidget.cpp
  8. +1
    -1
      src/app/RackScrollWidget.cpp
  9. +185
    -62
      src/app/RackWidget.cpp
  10. +3
    -3
      src/history.cpp
  11. +1
    -1
      src/patch.cpp

+ 0
- 37
include/app/CableContainer.hpp View File

@@ -1,37 +0,0 @@
#pragma once
#include "app/common.hpp"
#include "widgets/TransparentWidget.hpp"
#include "app/CableWidget.hpp"
#include "app/PortWidget.hpp"
#include <map>


namespace rack {


struct CableContainer : TransparentWidget {
CableWidget *incompleteCable = NULL;

~CableContainer();
void clear();
/** Removes all complete cables connected to the port */
void clearPort(PortWidget *port);
/** Adds a complete cable and adds it to the Engine.
Ownership rules work like add/removeChild()
*/
void addCable(CableWidget *w);
void removeCable(CableWidget *w);
/** Takes ownership of `w` and adds it as a child if it isn't already */
void setIncompleteCable(CableWidget *w);
CableWidget *releaseIncompleteCable();
/** Returns the most recently added complete cable connected to the given Port, i.e. the top of the stack */
CableWidget *getTopCable(PortWidget *port);
CableWidget *getCable(int cableId);

json_t *toJson();
void fromJson(json_t *rootJ, const std::map<int, ModuleWidget*> &moduleWidgets);
void draw(NVGcontext *vg) override;
};


} // namespace rack

+ 38
- 14
include/app/RackWidget.hpp View File

@@ -2,8 +2,9 @@
#include "app/common.hpp" #include "app/common.hpp"
#include "widgets/OpaqueWidget.hpp" #include "widgets/OpaqueWidget.hpp"
#include "widgets/FramebufferWidget.hpp" #include "widgets/FramebufferWidget.hpp"
#include "app/CableContainer.hpp"
#include "app/ModuleWidget.hpp" #include "app/ModuleWidget.hpp"
#include "app/CableWidget.hpp"
#include "app/PortWidget.hpp"




namespace rack { namespace rack {
@@ -12,13 +13,33 @@ namespace rack {
struct RackWidget : OpaqueWidget { struct RackWidget : OpaqueWidget {
FramebufferWidget *rails; FramebufferWidget *rails;
Widget *moduleContainer; Widget *moduleContainer;
CableContainer *cableContainer;
Widget *cableContainer;
CableWidget *incompleteCable = NULL;
/** The last mouse position in the RackWidget */ /** The last mouse position in the RackWidget */
math::Vec mousePos; math::Vec mousePos;


RackWidget(); RackWidget();
~RackWidget(); ~RackWidget();


void step() override;
void draw(NVGcontext *vg) override;

void onHover(const event::Hover &e) override;
void onDragHover(const event::DragHover &e) override;
void onButton(const event::Button &e) override;
void onZoom(const event::Zoom &e) override;

/** Completely clear the rack's modules and cables */
void clear();
json_t *toJson();
void fromJson(json_t *rootJ);
void pastePresetClipboard();

// Module methods

/** Adds a module and adds it to the Engine
Ownership rules work like add/removeChild()
*/
void addModule(ModuleWidget *mw); void addModule(ModuleWidget *mw);
void addModuleAtMouse(ModuleWidget *mw); void addModuleAtMouse(ModuleWidget *mw);
/** Removes the module and transfers ownership to the caller */ /** Removes the module and transfers ownership to the caller */
@@ -29,19 +50,22 @@ struct RackWidget : OpaqueWidget {
bool requestModuleBoxNearest(ModuleWidget *mw, math::Rect requestedBox); bool requestModuleBoxNearest(ModuleWidget *mw, math::Rect requestedBox);
ModuleWidget *getModule(int moduleId); ModuleWidget *getModule(int moduleId);


/** Completely clear the rack's modules and cables */
void clear();
json_t *toJson();
void fromJson(json_t *rootJ);
void pastePresetClipboard();
// Cable methods


void step() override;
void draw(NVGcontext *vg) override;

void onHover(const event::Hover &e) override;
void onDragHover(const event::DragHover &e) override;
void onButton(const event::Button &e) override;
void onZoom(const event::Zoom &e) override;
void clearCables();
/** Removes all complete cables connected to the port */
void clearCablesOnPort(PortWidget *port);
/** Adds a complete cable and adds it to the Engine.
Ownership rules work like add/removeChild()
*/
void addCable(CableWidget *w);
void removeCable(CableWidget *w);
/** Takes ownership of `w` and adds it as a child if it isn't already */
void setIncompleteCable(CableWidget *w);
CableWidget *releaseIncompleteCable();
/** Returns the most recently added complete cable connected to the given Port, i.e. the top of the stack */
CableWidget *getTopCable(PortWidget *port);
CableWidget *getCable(int cableId);
}; };






+ 0
- 1
include/rack.hpp View File

@@ -64,7 +64,6 @@
#include "app/SVGSlider.hpp" #include "app/SVGSlider.hpp"
#include "app/SVGSwitch.hpp" #include "app/SVGSwitch.hpp"
#include "app/Toolbar.hpp" #include "app/Toolbar.hpp"
#include "app/CableContainer.hpp"
#include "app/CableWidget.hpp" #include "app/CableWidget.hpp"


#include "engine/Engine.hpp" #include "engine/Engine.hpp"


+ 0
- 141
src/app/CableContainer.cpp View File

@@ -1,141 +0,0 @@
#include "app/CableContainer.hpp"
#include "app.hpp"
#include "engine/Engine.hpp"


namespace rack {


CableContainer::~CableContainer() {
clear();
}

void CableContainer::clear() {
for (Widget *w : children) {
CableWidget *cw = dynamic_cast<CableWidget*>(w);
assert(cw);
if (cw != incompleteCable)
app()->engine->removeCable(cw->cable);
}
incompleteCable = NULL;
clearChildren();
}

void CableContainer::clearPort(PortWidget *port) {
assert(port);
std::list<Widget*> childrenCopy = children;
for (Widget *w : childrenCopy) {
CableWidget *cw = dynamic_cast<CableWidget*>(w);
assert(cw);

// Check if cable is connected to port
if (cw->inputPort == port || cw->outputPort == port) {
if (cw == incompleteCable) {
incompleteCable = NULL;
removeChild(cw);
}
else {
removeCable(cw);
}
delete cw;
}
}
}

void CableContainer::addCable(CableWidget *w) {
assert(w->isComplete());
app()->engine->addCable(w->cable);
addChild(w);
}

void CableContainer::removeCable(CableWidget *w) {
assert(w->isComplete());
app()->engine->removeCable(w->cable);
removeChild(w);
}

void CableContainer::setIncompleteCable(CableWidget *w) {
if (incompleteCable) {
removeChild(incompleteCable);
delete incompleteCable;
incompleteCable = NULL;
}
if (w) {
addChild(w);
incompleteCable = w;
}
}

CableWidget *CableContainer::releaseIncompleteCable() {
CableWidget *cw = incompleteCable;
removeChild(incompleteCable);
incompleteCable = NULL;
return cw;
}

CableWidget *CableContainer::getTopCable(PortWidget *port) {
for (auto it = children.rbegin(); it != children.rend(); it++) {
CableWidget *cw = dynamic_cast<CableWidget*>(*it);
assert(cw);
// Ignore incomplete cables
if (!cw->isComplete())
continue;
if (cw->inputPort == port || cw->outputPort == port)
return cw;
}
return NULL;
}

CableWidget *CableContainer::getCable(int cableId) {
for (Widget *w : children) {
CableWidget *cw = dynamic_cast<CableWidget*>(w);
assert(cw);
if (cw->cable->id == cableId)
return cw;
}
return NULL;
}

json_t *CableContainer::toJson() {
json_t *rootJ = json_array();
for (Widget *w : children) {
CableWidget *cw = dynamic_cast<CableWidget*>(w);
assert(cw);

// Only serialize complete cables
if (!cw->isComplete())
continue;

json_array_append_new(rootJ, cw->toJson());
}
return rootJ;
}

void CableContainer::fromJson(json_t *rootJ, const std::map<int, ModuleWidget*> &moduleWidgets) {
size_t cableIndex;
json_t *cableJ;
json_array_foreach(rootJ, cableIndex, cableJ) {
// Create a unserialize cable
CableWidget *cw = new CableWidget;
cw->fromJson(cableJ, moduleWidgets);
if (!cw->isComplete()) {
delete cw;
continue;
}
addCable(cw);
}
}

void CableContainer::draw(NVGcontext *vg) {
Widget::draw(vg);

// Cable plugs
for (Widget *w : children) {
CableWidget *cw = dynamic_cast<CableWidget*>(w);
assert(cw);
cw->drawPlugs(vg);
}
}


} // namespace rack

+ 2
- 2
src/app/CableWidget.cpp View File

@@ -240,7 +240,7 @@ void CableWidget::drawPlugs(NVGcontext *vg) {
math::Vec inputPos = getInputPos(); math::Vec inputPos = getInputPos();


// Draw plug if the cable is on top, or if the cable is incomplete // Draw plug if the cable is on top, or if the cable is incomplete
if (!isComplete() || app()->scene->rackWidget->cableContainer->getTopCable(outputPort) == this) {
if (!isComplete() || app()->scene->rackWidget->getTopCable(outputPort) == this) {
drawPlug(vg, outputPos, color); drawPlug(vg, outputPos, color);
if (outputPort) { if (outputPort) {
// Draw plug light // Draw plug light
@@ -251,7 +251,7 @@ void CableWidget::drawPlugs(NVGcontext *vg) {
} }
} }


if (!isComplete() || app()->scene->rackWidget->cableContainer->getTopCable(inputPort) == this) {
if (!isComplete() || app()->scene->rackWidget->getTopCable(inputPort) == this) {
drawPlug(vg, inputPos, color); drawPlug(vg, inputPos, color);
if (inputPort) { if (inputPort) {
nvgSave(vg); nvgSave(vg);


+ 2
- 2
src/app/ModuleWidget.cpp View File

@@ -529,10 +529,10 @@ void ModuleWidget::saveDialog() {


void ModuleWidget::disconnect() { void ModuleWidget::disconnect() {
for (PortWidget *input : inputs) { for (PortWidget *input : inputs) {
app()->scene->rackWidget->cableContainer->clearPort(input);
app()->scene->rackWidget->clearCablesOnPort(input);
} }
for (PortWidget *output : outputs) { for (PortWidget *output : outputs) {
app()->scene->rackWidget->cableContainer->clearPort(output);
app()->scene->rackWidget->clearCablesOnPort(output);
} }
} }




+ 14
- 14
src/app/PortWidget.cpp View File

@@ -28,7 +28,7 @@ PortWidget::~PortWidget() {
delete plugLight; delete plugLight;
// HACK // HACK
if (module) if (module)
app()->scene->rackWidget->cableContainer->clearPort(this);
app()->scene->rackWidget->clearCablesOnPort(this);
} }


void PortWidget::step() { void PortWidget::step() {
@@ -48,7 +48,7 @@ void PortWidget::step() {
} }


void PortWidget::draw(NVGcontext *vg) { void PortWidget::draw(NVGcontext *vg) {
CableWidget *cw = app()->scene->rackWidget->cableContainer->incompleteCable;
CableWidget *cw = app()->scene->rackWidget->incompleteCable;
if (cw) { if (cw) {
// Dim the PortWidget if the active cable cannot plug into this PortWidget // Dim the PortWidget if the active cable cannot plug into this PortWidget
if (type == OUTPUT ? cw->outputPort : cw->inputPort) if (type == OUTPUT ? cw->outputPort : cw->inputPort)
@@ -59,14 +59,14 @@ void PortWidget::draw(NVGcontext *vg) {


void PortWidget::onButton(const event::Button &e) { void PortWidget::onButton(const event::Button &e) {
if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_RIGHT) { if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_RIGHT) {
CableWidget *cw = app()->scene->rackWidget->cableContainer->getTopCable(this);
CableWidget *cw = app()->scene->rackWidget->getTopCable(this);
if (cw) { if (cw) {
// history::CableRemove // history::CableRemove
history::CableRemove *h = new history::CableRemove; history::CableRemove *h = new history::CableRemove;
h->setCable(cw); h->setCable(cw);
app()->history->push(h); app()->history->push(h);


app()->scene->rackWidget->cableContainer->removeCable(cw);
app()->scene->rackWidget->removeCable(cw);
delete cw; delete cw;
} }
} }
@@ -80,7 +80,7 @@ void PortWidget::onDragStart(const event::DragStart &e) {
} }
else { else {
// Grab cable on top of stack // Grab cable on top of stack
cw = app()->scene->rackWidget->cableContainer->getTopCable(this);
cw = app()->scene->rackWidget->getTopCable(this);
} }


if (cw) { if (cw) {
@@ -90,7 +90,7 @@ void PortWidget::onDragStart(const event::DragStart &e) {
app()->history->push(h); app()->history->push(h);


// Disconnect and reuse existing cable // Disconnect and reuse existing cable
app()->scene->rackWidget->cableContainer->removeCable(cw);
app()->scene->rackWidget->removeCable(cw);
if (type == OUTPUT) if (type == OUTPUT)
cw->setOutput(NULL); cw->setOutput(NULL);
else else
@@ -104,15 +104,15 @@ void PortWidget::onDragStart(const event::DragStart &e) {
else else
cw->setInput(this); cw->setInput(this);
} }
app()->scene->rackWidget->cableContainer->setIncompleteCable(cw);
app()->scene->rackWidget->setIncompleteCable(cw);
} }


void PortWidget::onDragEnd(const event::DragEnd &e) { void PortWidget::onDragEnd(const event::DragEnd &e) {
// FIXME // FIXME
// If the source PortWidget is deleted, this will be called, removing the cable // If the source PortWidget is deleted, this will be called, removing the cable
CableWidget *cw = app()->scene->rackWidget->cableContainer->releaseIncompleteCable();
CableWidget *cw = app()->scene->rackWidget->releaseIncompleteCable();
if (cw->isComplete()) { if (cw->isComplete()) {
app()->scene->rackWidget->cableContainer->addCable(cw);
app()->scene->rackWidget->addCable(cw);


// history::CableAdd // history::CableAdd
history::CableAdd *h = new history::CableAdd; history::CableAdd *h = new history::CableAdd;
@@ -127,11 +127,11 @@ void PortWidget::onDragEnd(const event::DragEnd &e) {
void PortWidget::onDragDrop(const event::DragDrop &e) { void PortWidget::onDragDrop(const event::DragDrop &e) {
// Reject ports if this is an input port and something is already plugged into it // Reject ports if this is an input port and something is already plugged into it
if (type == INPUT) { if (type == INPUT) {
if (app()->scene->rackWidget->cableContainer->getTopCable(this))
if (app()->scene->rackWidget->getTopCable(this))
return; return;
} }


CableWidget *cw = app()->scene->rackWidget->cableContainer->incompleteCable;
CableWidget *cw = app()->scene->rackWidget->incompleteCable;
if (cw) { if (cw) {
cw->hoveredOutputPort = cw->hoveredInputPort = NULL; cw->hoveredOutputPort = cw->hoveredInputPort = NULL;
if (type == OUTPUT) if (type == OUTPUT)
@@ -144,11 +144,11 @@ void PortWidget::onDragDrop(const event::DragDrop &e) {
void PortWidget::onDragEnter(const event::DragEnter &e) { void PortWidget::onDragEnter(const event::DragEnter &e) {
// Reject ports if this is an input port and something is already plugged into it // Reject ports if this is an input port and something is already plugged into it
if (type == INPUT) { if (type == INPUT) {
if (app()->scene->rackWidget->cableContainer->getTopCable(this))
if (app()->scene->rackWidget->getTopCable(this))
return; return;
} }


CableWidget *cw = app()->scene->rackWidget->cableContainer->incompleteCable;
CableWidget *cw = app()->scene->rackWidget->incompleteCable;
if (cw) { if (cw) {
if (type == OUTPUT) if (type == OUTPUT)
cw->hoveredOutputPort = this; cw->hoveredOutputPort = this;
@@ -162,7 +162,7 @@ void PortWidget::onDragLeave(const event::DragLeave &e) {
if (!originPort) if (!originPort)
return; return;


CableWidget *cw = app()->scene->rackWidget->cableContainer->incompleteCable;
CableWidget *cw = app()->scene->rackWidget->incompleteCable;
if (cw) { if (cw) {
if (type == OUTPUT) if (type == OUTPUT)
cw->hoveredOutputPort = NULL; cw->hoveredOutputPort = NULL;


+ 1
- 1
src/app/RackScrollWidget.cpp View File

@@ -11,7 +11,7 @@ void RackScrollWidget::step() {
math::Vec pos = app()->window->mousePos; math::Vec pos = app()->window->mousePos;
math::Rect viewport = getViewport(box.zeroPos()); math::Rect viewport = getViewport(box.zeroPos());
// Scroll rack if dragging cable near the edge of the screen // Scroll rack if dragging cable near the edge of the screen
if (app()->scene->rackWidget->cableContainer->incompleteCable) {
if (app()->scene->rackWidget->incompleteCable) {
float margin = 20.0; float margin = 20.0;
float speed = 15.0; float speed = 15.0;
if (pos.x <= viewport.pos.x + margin) if (pos.x <= viewport.pos.x + margin)


+ 185
- 62
src/app/RackWidget.cpp View File

@@ -1,4 +1,5 @@
#include "app/RackWidget.hpp" #include "app/RackWidget.hpp"
#include "widgets/TransparentWidget.hpp"
#include "app/RackRail.hpp" #include "app/RackRail.hpp"
#include "app/Scene.hpp" #include "app/Scene.hpp"
#include "app/ModuleBrowser.hpp" #include "app/ModuleBrowser.hpp"
@@ -44,12 +45,11 @@ struct ModuleContainer : Widget {
void draw(NVGcontext *vg) override { void draw(NVGcontext *vg) override {
// Draw shadows behind each ModuleWidget first, so the shadow doesn't overlap the front of other ModuleWidgets. // Draw shadows behind each ModuleWidget first, so the shadow doesn't overlap the front of other ModuleWidgets.
for (Widget *child : children) { for (Widget *child : children) {
if (!child->visible)
continue;
nvgSave(vg);
nvgTranslate(vg, child->box.pos.x, child->box.pos.y);
ModuleWidget *w = dynamic_cast<ModuleWidget*>(child); ModuleWidget *w = dynamic_cast<ModuleWidget*>(child);
assert(w); assert(w);

nvgSave(vg);
nvgTranslate(vg, child->box.pos.x, child->box.pos.y);
w->drawShadow(vg); w->drawShadow(vg);
nvgRestore(vg); nvgRestore(vg);
} }
@@ -59,6 +59,20 @@ struct ModuleContainer : Widget {
}; };




struct CableContainer : TransparentWidget {
void draw(NVGcontext *vg) override {
Widget::draw(vg);

// Draw cable plugs
for (Widget *w : children) {
CableWidget *cw = dynamic_cast<CableWidget*>(w);
assert(cw);
cw->drawPlugs(vg);
}
}
};


RackWidget::RackWidget() { RackWidget::RackWidget() {
rails = new FramebufferWidget; rails = new FramebufferWidget;
rails->box.size = math::Vec(); rails->box.size = math::Vec();
@@ -81,7 +95,81 @@ RackWidget::~RackWidget() {
clear(); clear();
} }


void RackWidget::step() {
// Expand size to fit modules
math::Vec moduleSize = moduleContainer->getChildrenBoundingBox().getBottomRight();
// We assume that the size is reset by a parent before calling step(). Otherwise it will grow unbounded.
box.size = box.size.max(moduleSize);

// Adjust size and position of rails
Widget *rail = rails->children.front();
math::Rect bound = getViewport(math::Rect(math::Vec(), box.size));
if (!rails->box.contains(bound)) {
math::Vec cellMargin = math::Vec(20, 1);
rails->box.pos = bound.pos.div(RACK_GRID_SIZE).floor().minus(cellMargin).mult(RACK_GRID_SIZE);
rails->box.size = bound.size.plus(cellMargin.mult(RACK_GRID_SIZE).mult(2));
rails->dirty = true;

rail->box.size = rails->box.size;
}

Widget::step();
}

void RackWidget::draw(NVGcontext *vg) {
Widget::draw(vg);
}

void RackWidget::onHover(const event::Hover &e) {
// Scroll with arrow keys
float arrowSpeed = 30.0;
if ((app()->window->getMods() & WINDOW_MOD_MASK) == (WINDOW_MOD_CTRL |GLFW_MOD_SHIFT))
arrowSpeed /= 16.0;
else if ((app()->window->getMods() & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL)
arrowSpeed *= 4.0;
else if ((app()->window->getMods() & WINDOW_MOD_MASK) == GLFW_MOD_SHIFT)
arrowSpeed /= 4.0;

ScrollWidget *scrollWidget = app()->scene->scrollWidget;
if (glfwGetKey(app()->window->win, GLFW_KEY_LEFT) == GLFW_PRESS) {
scrollWidget->offset.x -= arrowSpeed;
}
if (glfwGetKey(app()->window->win, GLFW_KEY_RIGHT) == GLFW_PRESS) {
scrollWidget->offset.x += arrowSpeed;
}
if (glfwGetKey(app()->window->win, GLFW_KEY_UP) == GLFW_PRESS) {
scrollWidget->offset.y -= arrowSpeed;
}
if (glfwGetKey(app()->window->win, GLFW_KEY_DOWN) == GLFW_PRESS) {
scrollWidget->offset.y += arrowSpeed;
}

OpaqueWidget::onHover(e);
mousePos = e.pos;
}

void RackWidget::onDragHover(const event::DragHover &e) {
OpaqueWidget::onDragHover(e);
mousePos = e.pos;
}

void RackWidget::onButton(const event::Button &e) {
OpaqueWidget::onButton(e);
if (e.getConsumed() == this) {
if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_RIGHT) {
app()->scene->moduleBrowser->visible = true;
}
}
}

void RackWidget::onZoom(const event::Zoom &e) {
rails->box.size = math::Vec();
OpaqueWidget::onZoom(e);
}

void RackWidget::clear() { void RackWidget::clear() {
// This isn't required because removing all ModuleWidgets should remove all cables, but do it just in case.
clearCables();
// Remove ModuleWidgets // Remove ModuleWidgets
std::list<Widget*> widgets = moduleContainer->children; std::list<Widget*> widgets = moduleContainer->children;
for (Widget *w : widgets) { for (Widget *w : widgets) {
@@ -89,7 +177,6 @@ void RackWidget::clear() {
assert(moduleWidget); assert(moduleWidget);
removeModule(moduleWidget); removeModule(moduleWidget);
} }
assert(cableContainer->children.empty());
} }


json_t *RackWidget::toJson() { json_t *RackWidget::toJson() {
@@ -116,7 +203,18 @@ json_t *RackWidget::toJson() {
json_object_set_new(rootJ, "modules", modulesJ); json_object_set_new(rootJ, "modules", modulesJ);


// cables // cables
json_object_set_new(rootJ, "cables", cableContainer->toJson());
json_t *cablesJ = json_array();
for (Widget *w : cableContainer->children) {
CableWidget *cw = dynamic_cast<CableWidget*>(w);
assert(cw);

// Only serialize complete cables
if (!cw->isComplete())
continue;

json_array_append_new(cablesJ, cw->toJson());
}
json_object_set_new(rootJ, "cables", cablesJ);


return rootJ; return rootJ;
} }
@@ -174,8 +272,19 @@ void RackWidget::fromJson(json_t *rootJ) {
// Before 1.0, cables were called wires // Before 1.0, cables were called wires
if (!cablesJ) if (!cablesJ)
cablesJ = json_object_get(rootJ, "wires"); cablesJ = json_object_get(rootJ, "wires");
if (cablesJ)
cableContainer->fromJson(cablesJ, moduleWidgets);
assert(cablesJ);
size_t cableIndex;
json_t *cableJ;
json_array_foreach(cablesJ, cableIndex, cableJ) {
// Create a unserialize cable
CableWidget *cw = new CableWidget;
cw->fromJson(cableJ, moduleWidgets);
if (!cw->isComplete()) {
delete cw;
continue;
}
addCable(cw);
}
} }


void RackWidget::pastePresetClipboard() { void RackWidget::pastePresetClipboard() {
@@ -288,76 +397,90 @@ ModuleWidget *RackWidget::getModule(int moduleId) {
return NULL; return NULL;
} }


void RackWidget::step() {
// Expand size to fit modules
math::Vec moduleSize = moduleContainer->getChildrenBoundingBox().getBottomRight();
// We assume that the size is reset by a parent before calling step(). Otherwise it will grow unbounded.
box.size = box.size.max(moduleSize);

// Adjust size and position of rails
Widget *rail = rails->children.front();
math::Rect bound = getViewport(math::Rect(math::Vec(), box.size));
if (!rails->box.contains(bound)) {
math::Vec cellMargin = math::Vec(20, 1);
rails->box.pos = bound.pos.div(RACK_GRID_SIZE).floor().minus(cellMargin).mult(RACK_GRID_SIZE);
rails->box.size = bound.size.plus(cellMargin.mult(RACK_GRID_SIZE).mult(2));
rails->dirty = true;

rail->box.size = rails->box.size;
void RackWidget::clearCables() {
for (Widget *w : cableContainer->children) {
CableWidget *cw = dynamic_cast<CableWidget*>(w);
assert(cw);
if (cw != incompleteCable)
app()->engine->removeCable(cw->cable);
} }
incompleteCable = NULL;
cableContainer->clearChildren();
}


Widget::step();
void RackWidget::clearCablesOnPort(PortWidget *port) {
assert(port);
std::list<Widget*> childrenCopy = cableContainer->children;
for (Widget *w : childrenCopy) {
CableWidget *cw = dynamic_cast<CableWidget*>(w);
assert(cw);

// Check if cable is connected to port
if (cw->inputPort == port || cw->outputPort == port) {
if (cw == incompleteCable) {
incompleteCable = NULL;
cableContainer->removeChild(cw);
}
else {
removeCable(cw);
}
delete cw;
}
}
} }


void RackWidget::draw(NVGcontext *vg) {
Widget::draw(vg);
void RackWidget::addCable(CableWidget *w) {
assert(w->isComplete());
app()->engine->addCable(w->cable);
cableContainer->addChild(w);
} }


void RackWidget::onHover(const event::Hover &e) {
// Scroll with arrow keys
float arrowSpeed = 30.0;
if ((app()->window->getMods() & WINDOW_MOD_MASK) == (WINDOW_MOD_CTRL |GLFW_MOD_SHIFT))
arrowSpeed /= 16.0;
else if ((app()->window->getMods() & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL)
arrowSpeed *= 4.0;
else if ((app()->window->getMods() & WINDOW_MOD_MASK) == GLFW_MOD_SHIFT)
arrowSpeed /= 4.0;
void RackWidget::removeCable(CableWidget *w) {
assert(w->isComplete());
app()->engine->removeCable(w->cable);
cableContainer->removeChild(w);
}


ScrollWidget *scrollWidget = app()->scene->scrollWidget;
if (glfwGetKey(app()->window->win, GLFW_KEY_LEFT) == GLFW_PRESS) {
scrollWidget->offset.x -= arrowSpeed;
}
if (glfwGetKey(app()->window->win, GLFW_KEY_RIGHT) == GLFW_PRESS) {
scrollWidget->offset.x += arrowSpeed;
void RackWidget::setIncompleteCable(CableWidget *w) {
if (incompleteCable) {
cableContainer->removeChild(incompleteCable);
delete incompleteCable;
incompleteCable = NULL;
} }
if (glfwGetKey(app()->window->win, GLFW_KEY_UP) == GLFW_PRESS) {
scrollWidget->offset.y -= arrowSpeed;
}
if (glfwGetKey(app()->window->win, GLFW_KEY_DOWN) == GLFW_PRESS) {
scrollWidget->offset.y += arrowSpeed;
if (w) {
cableContainer->addChild(w);
incompleteCable = w;
} }

OpaqueWidget::onHover(e);
mousePos = e.pos;
} }


void RackWidget::onDragHover(const event::DragHover &e) {
OpaqueWidget::onDragHover(e);
mousePos = e.pos;
CableWidget *RackWidget::releaseIncompleteCable() {
CableWidget *cw = incompleteCable;
cableContainer->removeChild(incompleteCable);
incompleteCable = NULL;
return cw;
} }


void RackWidget::onButton(const event::Button &e) {
OpaqueWidget::onButton(e);
if (e.getConsumed() == this) {
if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_RIGHT) {
app()->scene->moduleBrowser->visible = true;
}
CableWidget *RackWidget::getTopCable(PortWidget *port) {
for (auto it = cableContainer->children.rbegin(); it != cableContainer->children.rend(); it++) {
CableWidget *cw = dynamic_cast<CableWidget*>(*it);
assert(cw);
// Ignore incomplete cables
if (!cw->isComplete())
continue;
if (cw->inputPort == port || cw->outputPort == port)
return cw;
} }
return NULL;
} }


void RackWidget::onZoom(const event::Zoom &e) {
rails->box.size = math::Vec();
OpaqueWidget::onZoom(e);
CableWidget *RackWidget::getCable(int cableId) {
for (Widget *w : cableContainer->children) {
CableWidget *cw = dynamic_cast<CableWidget*>(w);
assert(cw);
if (cw->cable->id == cableId)
return cw;
}
return NULL;
} }






+ 3
- 3
src/history.cpp View File

@@ -124,8 +124,8 @@ void CableAdd::setCable(CableWidget *cw) {
} }


void CableAdd::undo() { void CableAdd::undo() {
CableWidget *cw = app()->scene->rackWidget->cableContainer->getCable(cableId);
app()->scene->rackWidget->cableContainer->removeCable(cw);
CableWidget *cw = app()->scene->rackWidget->getCable(cableId);
app()->scene->rackWidget->removeCable(cw);
delete cw; delete cw;
} }


@@ -147,7 +147,7 @@ void CableAdd::redo() {


cw->color = color; cw->color = color;


app()->scene->rackWidget->cableContainer->addCable(cw);
app()->scene->rackWidget->addCable(cw);
} }






+ 1
- 1
src/patch.cpp View File

@@ -167,7 +167,7 @@ void PatchManager::disconnectDialog() {
if (!osdialog_message(OSDIALOG_WARNING, OSDIALOG_OK_CANCEL, "Remove all patch cables?")) if (!osdialog_message(OSDIALOG_WARNING, OSDIALOG_OK_CANCEL, "Remove all patch cables?"))
return; return;


app()->scene->rackWidget->cableContainer->clear();
app()->scene->rackWidget->clear();
} }


json_t *PatchManager::toJson() { json_t *PatchManager::toJson() {


Loading…
Cancel
Save