@@ -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 |
@@ -2,8 +2,9 @@ | |||
#include "app/common.hpp" | |||
#include "widgets/OpaqueWidget.hpp" | |||
#include "widgets/FramebufferWidget.hpp" | |||
#include "app/CableContainer.hpp" | |||
#include "app/ModuleWidget.hpp" | |||
#include "app/CableWidget.hpp" | |||
#include "app/PortWidget.hpp" | |||
namespace rack { | |||
@@ -12,13 +13,33 @@ namespace rack { | |||
struct RackWidget : OpaqueWidget { | |||
FramebufferWidget *rails; | |||
Widget *moduleContainer; | |||
CableContainer *cableContainer; | |||
Widget *cableContainer; | |||
CableWidget *incompleteCable = NULL; | |||
/** The last mouse position in the RackWidget */ | |||
math::Vec mousePos; | |||
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 addModuleAtMouse(ModuleWidget *mw); | |||
/** Removes the module and transfers ownership to the caller */ | |||
@@ -29,19 +50,22 @@ struct RackWidget : OpaqueWidget { | |||
bool requestModuleBoxNearest(ModuleWidget *mw, math::Rect requestedBox); | |||
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); | |||
}; | |||
@@ -64,7 +64,6 @@ | |||
#include "app/SVGSlider.hpp" | |||
#include "app/SVGSwitch.hpp" | |||
#include "app/Toolbar.hpp" | |||
#include "app/CableContainer.hpp" | |||
#include "app/CableWidget.hpp" | |||
#include "engine/Engine.hpp" | |||
@@ -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 |
@@ -240,7 +240,7 @@ void CableWidget::drawPlugs(NVGcontext *vg) { | |||
math::Vec inputPos = getInputPos(); | |||
// 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); | |||
if (outputPort) { | |||
// 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); | |||
if (inputPort) { | |||
nvgSave(vg); | |||
@@ -529,10 +529,10 @@ void ModuleWidget::saveDialog() { | |||
void ModuleWidget::disconnect() { | |||
for (PortWidget *input : inputs) { | |||
app()->scene->rackWidget->cableContainer->clearPort(input); | |||
app()->scene->rackWidget->clearCablesOnPort(input); | |||
} | |||
for (PortWidget *output : outputs) { | |||
app()->scene->rackWidget->cableContainer->clearPort(output); | |||
app()->scene->rackWidget->clearCablesOnPort(output); | |||
} | |||
} | |||
@@ -28,7 +28,7 @@ PortWidget::~PortWidget() { | |||
delete plugLight; | |||
// HACK | |||
if (module) | |||
app()->scene->rackWidget->cableContainer->clearPort(this); | |||
app()->scene->rackWidget->clearCablesOnPort(this); | |||
} | |||
void PortWidget::step() { | |||
@@ -48,7 +48,7 @@ void PortWidget::step() { | |||
} | |||
void PortWidget::draw(NVGcontext *vg) { | |||
CableWidget *cw = app()->scene->rackWidget->cableContainer->incompleteCable; | |||
CableWidget *cw = app()->scene->rackWidget->incompleteCable; | |||
if (cw) { | |||
// Dim the PortWidget if the active cable cannot plug into this PortWidget | |||
if (type == OUTPUT ? cw->outputPort : cw->inputPort) | |||
@@ -59,14 +59,14 @@ void PortWidget::draw(NVGcontext *vg) { | |||
void PortWidget::onButton(const event::Button &e) { | |||
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) { | |||
// history::CableRemove | |||
history::CableRemove *h = new history::CableRemove; | |||
h->setCable(cw); | |||
app()->history->push(h); | |||
app()->scene->rackWidget->cableContainer->removeCable(cw); | |||
app()->scene->rackWidget->removeCable(cw); | |||
delete cw; | |||
} | |||
} | |||
@@ -80,7 +80,7 @@ void PortWidget::onDragStart(const event::DragStart &e) { | |||
} | |||
else { | |||
// Grab cable on top of stack | |||
cw = app()->scene->rackWidget->cableContainer->getTopCable(this); | |||
cw = app()->scene->rackWidget->getTopCable(this); | |||
} | |||
if (cw) { | |||
@@ -90,7 +90,7 @@ void PortWidget::onDragStart(const event::DragStart &e) { | |||
app()->history->push(h); | |||
// Disconnect and reuse existing cable | |||
app()->scene->rackWidget->cableContainer->removeCable(cw); | |||
app()->scene->rackWidget->removeCable(cw); | |||
if (type == OUTPUT) | |||
cw->setOutput(NULL); | |||
else | |||
@@ -104,15 +104,15 @@ void PortWidget::onDragStart(const event::DragStart &e) { | |||
else | |||
cw->setInput(this); | |||
} | |||
app()->scene->rackWidget->cableContainer->setIncompleteCable(cw); | |||
app()->scene->rackWidget->setIncompleteCable(cw); | |||
} | |||
void PortWidget::onDragEnd(const event::DragEnd &e) { | |||
// FIXME | |||
// 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()) { | |||
app()->scene->rackWidget->cableContainer->addCable(cw); | |||
app()->scene->rackWidget->addCable(cw); | |||
// 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) { | |||
// Reject ports if this is an input port and something is already plugged into it | |||
if (type == INPUT) { | |||
if (app()->scene->rackWidget->cableContainer->getTopCable(this)) | |||
if (app()->scene->rackWidget->getTopCable(this)) | |||
return; | |||
} | |||
CableWidget *cw = app()->scene->rackWidget->cableContainer->incompleteCable; | |||
CableWidget *cw = app()->scene->rackWidget->incompleteCable; | |||
if (cw) { | |||
cw->hoveredOutputPort = cw->hoveredInputPort = NULL; | |||
if (type == OUTPUT) | |||
@@ -144,11 +144,11 @@ void PortWidget::onDragDrop(const event::DragDrop &e) { | |||
void PortWidget::onDragEnter(const event::DragEnter &e) { | |||
// Reject ports if this is an input port and something is already plugged into it | |||
if (type == INPUT) { | |||
if (app()->scene->rackWidget->cableContainer->getTopCable(this)) | |||
if (app()->scene->rackWidget->getTopCable(this)) | |||
return; | |||
} | |||
CableWidget *cw = app()->scene->rackWidget->cableContainer->incompleteCable; | |||
CableWidget *cw = app()->scene->rackWidget->incompleteCable; | |||
if (cw) { | |||
if (type == OUTPUT) | |||
cw->hoveredOutputPort = this; | |||
@@ -162,7 +162,7 @@ void PortWidget::onDragLeave(const event::DragLeave &e) { | |||
if (!originPort) | |||
return; | |||
CableWidget *cw = app()->scene->rackWidget->cableContainer->incompleteCable; | |||
CableWidget *cw = app()->scene->rackWidget->incompleteCable; | |||
if (cw) { | |||
if (type == OUTPUT) | |||
cw->hoveredOutputPort = NULL; | |||
@@ -11,7 +11,7 @@ void RackScrollWidget::step() { | |||
math::Vec pos = app()->window->mousePos; | |||
math::Rect viewport = getViewport(box.zeroPos()); | |||
// 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 speed = 15.0; | |||
if (pos.x <= viewport.pos.x + margin) | |||
@@ -1,4 +1,5 @@ | |||
#include "app/RackWidget.hpp" | |||
#include "widgets/TransparentWidget.hpp" | |||
#include "app/RackRail.hpp" | |||
#include "app/Scene.hpp" | |||
#include "app/ModuleBrowser.hpp" | |||
@@ -44,12 +45,11 @@ struct ModuleContainer : Widget { | |||
void draw(NVGcontext *vg) override { | |||
// Draw shadows behind each ModuleWidget first, so the shadow doesn't overlap the front of other ModuleWidgets. | |||
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); | |||
assert(w); | |||
nvgSave(vg); | |||
nvgTranslate(vg, child->box.pos.x, child->box.pos.y); | |||
w->drawShadow(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() { | |||
rails = new FramebufferWidget; | |||
rails->box.size = math::Vec(); | |||
@@ -81,7 +95,81 @@ RackWidget::~RackWidget() { | |||
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() { | |||
// This isn't required because removing all ModuleWidgets should remove all cables, but do it just in case. | |||
clearCables(); | |||
// Remove ModuleWidgets | |||
std::list<Widget*> widgets = moduleContainer->children; | |||
for (Widget *w : widgets) { | |||
@@ -89,7 +177,6 @@ void RackWidget::clear() { | |||
assert(moduleWidget); | |||
removeModule(moduleWidget); | |||
} | |||
assert(cableContainer->children.empty()); | |||
} | |||
json_t *RackWidget::toJson() { | |||
@@ -116,7 +203,18 @@ json_t *RackWidget::toJson() { | |||
json_object_set_new(rootJ, "modules", modulesJ); | |||
// 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; | |||
} | |||
@@ -174,8 +272,19 @@ void RackWidget::fromJson(json_t *rootJ) { | |||
// Before 1.0, cables were called wires | |||
if (!cablesJ) | |||
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() { | |||
@@ -288,76 +397,90 @@ ModuleWidget *RackWidget::getModule(int moduleId) { | |||
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; | |||
} | |||
@@ -124,8 +124,8 @@ void CableAdd::setCable(CableWidget *cw) { | |||
} | |||
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; | |||
} | |||
@@ -147,7 +147,7 @@ void CableAdd::redo() { | |||
cw->color = color; | |||
app()->scene->rackWidget->cableContainer->addCable(cw); | |||
app()->scene->rackWidget->addCable(cw); | |||
} | |||
@@ -167,7 +167,7 @@ void PatchManager::disconnectDialog() { | |||
if (!osdialog_message(OSDIALOG_WARNING, OSDIALOG_OK_CANCEL, "Remove all patch cables?")) | |||
return; | |||
app()->scene->rackWidget->cableContainer->clear(); | |||
app()->scene->rackWidget->clear(); | |||
} | |||
json_t *PatchManager::toJson() { | |||