@@ -0,0 +1,25 @@ | |||
#pragma once | |||
#include "app/common.hpp" | |||
#include "widgets/TransparentWidget.hpp" | |||
#include "app/CableWidget.hpp" | |||
#include "app/PortWidget.hpp" | |||
namespace rack { | |||
struct CableContainer : TransparentWidget { | |||
CableWidget *activeCable = NULL; | |||
/** Takes ownership of `w` and adds it as a child if it isn't already */ | |||
void setActiveCable(CableWidget *w); | |||
/** "Drops" the cable onto the port, making an engine connection if successful */ | |||
void commitActiveCable(); | |||
void removeTopCable(PortWidget *port); | |||
void removeAllCables(PortWidget *port); | |||
/** Returns the most recently added cable connected to the given Port, i.e. the top of the stack */ | |||
CableWidget *getTopCable(PortWidget *port); | |||
void draw(NVGcontext *vg) override; | |||
}; | |||
} // namespace rack |
@@ -2,24 +2,24 @@ | |||
#include "app/common.hpp" | |||
#include "widgets/OpaqueWidget.hpp" | |||
#include "app/PortWidget.hpp" | |||
#include "engine/Wire.hpp" | |||
#include "engine/Cable.hpp" | |||
namespace rack { | |||
struct WireWidget : OpaqueWidget { | |||
struct CableWidget : OpaqueWidget { | |||
PortWidget *outputPort = NULL; | |||
PortWidget *inputPort = NULL; | |||
PortWidget *hoveredOutputPort = NULL; | |||
PortWidget *hoveredInputPort = NULL; | |||
Wire *wire = NULL; | |||
Cable *cable = NULL; | |||
NVGcolor color; | |||
WireWidget(); | |||
~WireWidget(); | |||
/** Synchronizes the plugged state of the widget to the owned wire */ | |||
void updateWire(); | |||
CableWidget(); | |||
~CableWidget(); | |||
/** Synchronizes the plugged state of the widget to the owned cable */ | |||
void updateCable(); | |||
math::Vec getOutputPos(); | |||
math::Vec getInputPos(); | |||
json_t *toJson(); |
@@ -2,7 +2,7 @@ | |||
#include "app/common.hpp" | |||
#include "widgets/OpaqueWidget.hpp" | |||
#include "widgets/FramebufferWidget.hpp" | |||
#include "app/WireContainer.hpp" | |||
#include "app/CableContainer.hpp" | |||
#include "app/ModuleWidget.hpp" | |||
@@ -13,15 +13,15 @@ struct RackWidget : OpaqueWidget { | |||
FramebufferWidget *rails; | |||
// Only put ModuleWidgets in here | |||
Widget *moduleContainer; | |||
// Only put WireWidgets in here | |||
WireContainer *wireContainer; | |||
// Only put CableWidgets in here | |||
CableContainer *cableContainer; | |||
std::string lastPath; | |||
math::Vec lastMousePos; | |||
RackWidget(); | |||
~RackWidget(); | |||
/** Completely clear the rack's modules and wires */ | |||
/** Completely clear the rack's modules and cables */ | |||
void clear(); | |||
/** Clears the rack and loads the template patch */ | |||
void reset(); | |||
@@ -31,7 +31,7 @@ struct RackWidget : OpaqueWidget { | |||
void saveTemplate(); | |||
/** If `lastPath` is defined, ask the user to reload it */ | |||
void revert(); | |||
/** Disconnects all wires */ | |||
/** Disconnects all cables */ | |||
void disconnect(); | |||
void save(std::string filename); | |||
void load(std::string filename); | |||
@@ -8,8 +8,8 @@ namespace rack { | |||
struct Toolbar : OpaqueWidget { | |||
// TODO Move these to future Rack app state | |||
float wireOpacity = 0.5; | |||
float wireTension = 0.5; | |||
float cableOpacity = 0.5; | |||
float cableTension = 0.5; | |||
Toolbar(); | |||
void draw(NVGcontext *vg) override; | |||
@@ -1,25 +0,0 @@ | |||
#pragma once | |||
#include "app/common.hpp" | |||
#include "widgets/TransparentWidget.hpp" | |||
#include "app/WireWidget.hpp" | |||
#include "app/PortWidget.hpp" | |||
namespace rack { | |||
struct WireContainer : TransparentWidget { | |||
WireWidget *activeWire = NULL; | |||
/** Takes ownership of `w` and adds it as a child if it isn't already */ | |||
void setActiveWire(WireWidget *w); | |||
/** "Drops" the wire onto the port, making an engine connection if successful */ | |||
void commitActiveWire(); | |||
void removeTopWire(PortWidget *port); | |||
void removeAllWires(PortWidget *port); | |||
/** Returns the most recently added wire connected to the given Port, i.e. the top of the stack */ | |||
WireWidget *getTopWire(PortWidget *port); | |||
void draw(NVGcontext *vg) override; | |||
}; | |||
} // namespace rack |
@@ -6,7 +6,7 @@ | |||
namespace rack { | |||
struct Wire { | |||
struct Cable { | |||
int id = 0; | |||
Module *outputModule = NULL; | |||
int outputId; |
@@ -1,7 +1,7 @@ | |||
#pragma once | |||
#include "common.hpp" | |||
#include "engine/Module.hpp" | |||
#include "engine/Wire.hpp" | |||
#include "engine/Cable.hpp" | |||
#include <vector> | |||
@@ -9,11 +9,11 @@ namespace rack { | |||
struct Engine { | |||
/** Plugins should not manipulate other modules or wires unless that is the entire purpose of the module. | |||
Your plugin needs to have a clear purpose for manipulating other modules and wires and must be done with a good UX. | |||
/** Plugins should not manipulate other modules or cables unless that is the entire purpose of the module. | |||
Your plugin needs to have a clear purpose for manipulating other modules and cables and must be done with a good UX. | |||
*/ | |||
std::vector<Module*> modules; | |||
std::vector<Wire*> wires; | |||
std::vector<Cable*> cables; | |||
bool paused = false; | |||
struct Internal; | |||
@@ -31,8 +31,8 @@ struct Engine { | |||
void resetModule(Module *module); | |||
void randomizeModule(Module *module); | |||
/** Does not transfer pointer ownership */ | |||
void addWire(Wire *wire); | |||
void removeWire(Wire *wire); | |||
void addCable(Cable *cable); | |||
void removeCable(Cable *cable); | |||
void setParam(Module *module, int paramId, float value); | |||
void setParamSmooth(Module *module, int paramId, float value); | |||
int getNextModuleId(); | |||
@@ -7,7 +7,7 @@ namespace rack { | |||
struct Input : Port { | |||
/** Returns the value if a wire is plugged in, otherwise returns the given default value */ | |||
/** Returns the value if a cable is plugged in, otherwise returns the given default value */ | |||
float normalize(float normalVoltage, int index = 0) { | |||
return active ? getVoltage(index) : normalVoltage; | |||
} | |||
@@ -20,7 +20,7 @@ struct Port { | |||
}; | |||
/** Number of polyphonic channels */ | |||
int numChannels = 1; | |||
/** Whether a wire is plugged in */ | |||
/** Whether a cable is plugged in */ | |||
bool active = false; | |||
Light plugLights[2]; | |||
@@ -38,14 +38,14 @@ struct ModuleRemove : ModuleAction { | |||
math::Vec pos; | |||
json_t *moduleJ; | |||
struct WireInfo { | |||
int wireId; | |||
struct CableInfo { | |||
int cableId; | |||
int outputModuleId; | |||
int outputId; | |||
int inputModuleId; | |||
int inputId; | |||
}; | |||
std::vector<WireInfo> wireInfos; | |||
std::vector<CableInfo> cableInfos; | |||
~ModuleRemove(); | |||
void undo() override; | |||
@@ -70,8 +70,8 @@ struct ParamChange : ModuleAction { | |||
}; | |||
struct WireAdd : Action { | |||
int wireId; | |||
struct CableAdd : Action { | |||
int cableId; | |||
int outputModuleId; | |||
int outputId; | |||
int inputModuleId; | |||
@@ -81,8 +81,8 @@ struct WireAdd : Action { | |||
}; | |||
struct WireRemove : Action { | |||
int wireId; | |||
struct CableRemove : Action { | |||
int cableId; | |||
int outputModuleId; | |||
int outputId; | |||
int inputModuleId; | |||
@@ -92,8 +92,8 @@ struct WireRemove : Action { | |||
}; | |||
struct WireMove : Action { | |||
int wireId; | |||
struct CableMove : Action { | |||
int cableId; | |||
int oldOutputModuleId; | |||
int oldOutputId; | |||
int oldInputModuleId; | |||
@@ -65,8 +65,8 @@ | |||
#include "app/SVGSwitch.hpp" | |||
#include "app/ToggleSwitch.hpp" | |||
#include "app/Toolbar.hpp" | |||
#include "app/WireContainer.hpp" | |||
#include "app/WireWidget.hpp" | |||
#include "app/CableContainer.hpp" | |||
#include "app/CableWidget.hpp" | |||
#include "engine/Engine.hpp" | |||
#include "engine/Input.hpp" | |||
@@ -74,7 +74,7 @@ | |||
#include "engine/Module.hpp" | |||
#include "engine/Output.hpp" | |||
#include "engine/Param.hpp" | |||
#include "engine/Wire.hpp" | |||
#include "engine/Cable.hpp" | |||
#include "plugin/Plugin.hpp" | |||
#include "plugin/Model.hpp" | |||
@@ -11,8 +11,8 @@ void load(std::string filename); | |||
extern float zoom; | |||
extern float wireOpacity; | |||
extern float wireTension; | |||
extern float cableOpacity; | |||
extern float cableTension; | |||
extern bool paramTooltip; | |||
extern bool powerMeter; | |||
extern bool lockModules; | |||
@@ -0,0 +1,108 @@ | |||
#include "app/CableContainer.hpp" | |||
namespace rack { | |||
void CableContainer::setActiveCable(CableWidget *w) { | |||
if (activeCable) { | |||
removeChild(activeCable); | |||
delete activeCable; | |||
activeCable = NULL; | |||
} | |||
if (w) { | |||
if (w->parent == NULL) | |||
addChild(w); | |||
activeCable = w; | |||
} | |||
} | |||
void CableContainer::commitActiveCable() { | |||
if (!activeCable) | |||
return; | |||
if (activeCable->hoveredOutputPort) { | |||
activeCable->outputPort = activeCable->hoveredOutputPort; | |||
activeCable->hoveredOutputPort = NULL; | |||
} | |||
if (activeCable->hoveredInputPort) { | |||
activeCable->inputPort = activeCable->hoveredInputPort; | |||
activeCable->hoveredInputPort = NULL; | |||
} | |||
activeCable->updateCable(); | |||
// Did it successfully connect? | |||
if (activeCable->cable) { | |||
// Make it permanent | |||
activeCable = NULL; | |||
} | |||
else { | |||
// Remove it | |||
setActiveCable(NULL); | |||
} | |||
} | |||
void CableContainer::removeTopCable(PortWidget *port) { | |||
CableWidget *cable = getTopCable(port); | |||
if (cable) { | |||
removeChild(cable); | |||
delete cable; | |||
} | |||
} | |||
void CableContainer::removeAllCables(PortWidget *port) { | |||
// As a convenience, de-hover the active cable so we don't attach them once it is dropped. | |||
if (activeCable) { | |||
if (activeCable->hoveredInputPort == port) | |||
activeCable->hoveredInputPort = NULL; | |||
if (activeCable->hoveredOutputPort == port) | |||
activeCable->hoveredOutputPort = NULL; | |||
} | |||
// Build a list of CableWidgets to delete | |||
std::list<CableWidget*> cables; | |||
for (Widget *child : children) { | |||
CableWidget *cable = dynamic_cast<CableWidget*>(child); | |||
assert(cable); | |||
if (!cable || cable->inputPort == port || cable->outputPort == port) { | |||
if (activeCable == cable) { | |||
activeCable = NULL; | |||
} | |||
// We can't delete from this list while we're iterating it, so add it to the deletion list. | |||
cables.push_back(cable); | |||
} | |||
} | |||
// Once we're done building the list, actually delete them | |||
for (CableWidget *cable : cables) { | |||
removeChild(cable); | |||
delete cable; | |||
} | |||
} | |||
CableWidget *CableContainer::getTopCable(PortWidget *port) { | |||
for (auto it = children.rbegin(); it != children.rend(); it++) { | |||
CableWidget *cable = dynamic_cast<CableWidget*>(*it); | |||
assert(cable); | |||
// Ignore incomplete cables | |||
if (!(cable->inputPort && cable->outputPort)) | |||
continue; | |||
if (cable->inputPort == port || cable->outputPort == port) | |||
return cable; | |||
} | |||
return NULL; | |||
} | |||
void CableContainer::draw(NVGcontext *vg) { | |||
Widget::draw(vg); | |||
// Cable plugs | |||
for (Widget *child : children) { | |||
CableWidget *cable = dynamic_cast<CableWidget*>(child); | |||
assert(cable); | |||
cable->drawPlugs(vg); | |||
} | |||
} | |||
} // namespace rack |
@@ -1,4 +1,4 @@ | |||
#include "app/WireWidget.hpp" | |||
#include "app/CableWidget.hpp" | |||
#include "app/Scene.hpp" | |||
#include "engine/Engine.hpp" | |||
#include "componentlibrary.hpp" | |||
@@ -31,11 +31,11 @@ static void drawPlug(NVGcontext *vg, math::Vec pos, NVGcolor color) { | |||
nvgFill(vg); | |||
} | |||
static void drawWire(NVGcontext *vg, math::Vec pos1, math::Vec pos2, NVGcolor color, float thickness, float tension, float opacity) { | |||
static void drawCable(NVGcontext *vg, math::Vec pos1, math::Vec pos2, NVGcolor color, float thickness, float tension, float opacity) { | |||
NVGcolor colorShadow = nvgRGBAf(0, 0, 0, 0.10); | |||
NVGcolor colorOutline = nvgLerpRGBA(color, nvgRGBf(0.0, 0.0, 0.0), 0.5); | |||
// Wire | |||
// Cable | |||
if (opacity > 0.0) { | |||
nvgSave(vg); | |||
// This power scaling looks more linear than actual linear scaling | |||
@@ -57,7 +57,7 @@ static void drawWire(NVGcontext *vg, math::Vec pos1, math::Vec pos2, NVGcolor co | |||
nvgStrokeWidth(vg, thickness); | |||
nvgStroke(vg); | |||
// Wire outline | |||
// Cable outline | |||
nvgBeginPath(vg); | |||
nvgMoveTo(vg, pos1.x, pos1.y); | |||
nvgQuadTo(vg, pos3.x, pos3.y, pos2.x, pos2.y); | |||
@@ -65,7 +65,7 @@ static void drawWire(NVGcontext *vg, math::Vec pos1, math::Vec pos2, NVGcolor co | |||
nvgStrokeWidth(vg, thickness); | |||
nvgStroke(vg); | |||
// Wire solid | |||
// Cable solid | |||
nvgStrokeColor(vg, color); | |||
nvgStrokeWidth(vg, thickness - 2); | |||
nvgStroke(vg); | |||
@@ -75,7 +75,7 @@ static void drawWire(NVGcontext *vg, math::Vec pos1, math::Vec pos2, NVGcolor co | |||
} | |||
static const NVGcolor wireColors[] = { | |||
static const NVGcolor cableColors[] = { | |||
nvgRGB(0xc9, 0xb7, 0x0e), // yellow | |||
nvgRGB(0xc9, 0x18, 0x47), // red | |||
nvgRGB(0x0c, 0x8e, 0x15), // green | |||
@@ -85,45 +85,45 @@ static const NVGcolor wireColors[] = { | |||
// nvgRGB(0x88, 0x88, 0x88), // light gray | |||
// nvgRGB(0xaa, 0xaa, 0xaa), // white | |||
}; | |||
static int lastWireColorId = -1; | |||
static int lastCableColorId = -1; | |||
WireWidget::WireWidget() { | |||
lastWireColorId = (lastWireColorId + 1) % LENGTHOF(wireColors); | |||
color = wireColors[lastWireColorId]; | |||
CableWidget::CableWidget() { | |||
lastCableColorId = (lastCableColorId + 1) % LENGTHOF(cableColors); | |||
color = cableColors[lastCableColorId]; | |||
} | |||
WireWidget::~WireWidget() { | |||
CableWidget::~CableWidget() { | |||
outputPort = NULL; | |||
inputPort = NULL; | |||
updateWire(); | |||
updateCable(); | |||
} | |||
void WireWidget::updateWire() { | |||
void CableWidget::updateCable() { | |||
if (inputPort && outputPort) { | |||
// Check correct types | |||
assert(inputPort->type == PortWidget::INPUT); | |||
assert(outputPort->type == PortWidget::OUTPUT); | |||
if (!wire) { | |||
wire = new Wire; | |||
wire->outputModule = outputPort->module; | |||
wire->outputId = outputPort->portId; | |||
wire->inputModule = inputPort->module; | |||
wire->inputId = inputPort->portId; | |||
app()->engine->addWire(wire); | |||
if (!cable) { | |||
cable = new Cable; | |||
cable->outputModule = outputPort->module; | |||
cable->outputId = outputPort->portId; | |||
cable->inputModule = inputPort->module; | |||
cable->inputId = inputPort->portId; | |||
app()->engine->addCable(cable); | |||
} | |||
} | |||
else { | |||
if (wire) { | |||
app()->engine->removeWire(wire); | |||
delete wire; | |||
wire = NULL; | |||
if (cable) { | |||
app()->engine->removeCable(cable); | |||
delete cable; | |||
cable = NULL; | |||
} | |||
} | |||
} | |||
math::Vec WireWidget::getOutputPos() { | |||
math::Vec CableWidget::getOutputPos() { | |||
if (outputPort) { | |||
return outputPort->getRelativeOffset(outputPort->box.zeroPos().getCenter(), app()->scene->rackWidget); | |||
} | |||
@@ -135,7 +135,7 @@ math::Vec WireWidget::getOutputPos() { | |||
} | |||
} | |||
math::Vec WireWidget::getInputPos() { | |||
math::Vec CableWidget::getInputPos() { | |||
if (inputPort) { | |||
return inputPort->getRelativeOffset(inputPort->box.zeroPos().getCenter(), app()->scene->rackWidget); | |||
} | |||
@@ -147,30 +147,30 @@ math::Vec WireWidget::getInputPos() { | |||
} | |||
} | |||
json_t *WireWidget::toJson() { | |||
json_t *CableWidget::toJson() { | |||
json_t *rootJ = json_object(); | |||
std::string s = color::toHexString(color); | |||
json_object_set_new(rootJ, "color", json_string(s.c_str())); | |||
return rootJ; | |||
} | |||
void WireWidget::fromJson(json_t *rootJ) { | |||
void CableWidget::fromJson(json_t *rootJ) { | |||
json_t *colorJ = json_object_get(rootJ, "color"); | |||
if (colorJ) { | |||
// v0.6.0 and earlier patches use JSON objects. Just ignore them if so and use the existing wire color. | |||
// v0.6.0 and earlier patches use JSON objects. Just ignore them if so and use the existing cable color. | |||
if (json_is_string(colorJ)) | |||
color = color::fromHexString(json_string_value(colorJ)); | |||
} | |||
} | |||
void WireWidget::draw(NVGcontext *vg) { | |||
float opacity = settings::wireOpacity; | |||
float tension = settings::wireTension; | |||
void CableWidget::draw(NVGcontext *vg) { | |||
float opacity = settings::cableOpacity; | |||
float tension = settings::cableTension; | |||
WireWidget *activeWire = app()->scene->rackWidget->wireContainer->activeWire; | |||
if (activeWire) { | |||
// Draw as opaque if the wire is active | |||
if (activeWire == this) | |||
CableWidget *activeCable = app()->scene->rackWidget->cableContainer->activeCable; | |||
if (activeCable) { | |||
// Draw as opaque if the cable is active | |||
if (activeCable == this) | |||
opacity = 1.0; | |||
} | |||
else { | |||
@@ -180,8 +180,8 @@ void WireWidget::draw(NVGcontext *vg) { | |||
} | |||
float thickness = 5; | |||
if (wire && wire->outputModule) { | |||
Output *output = &wire->outputModule->outputs[wire->outputId]; | |||
if (cable && cable->outputModule) { | |||
Output *output = &cable->outputModule->outputs[cable->outputId]; | |||
if (output->numChannels != 1) { | |||
thickness = 9; | |||
} | |||
@@ -189,11 +189,11 @@ void WireWidget::draw(NVGcontext *vg) { | |||
math::Vec outputPos = getOutputPos(); | |||
math::Vec inputPos = getInputPos(); | |||
drawWire(vg, outputPos, inputPos, color, thickness, tension, opacity); | |||
drawCable(vg, outputPos, inputPos, color, thickness, tension, opacity); | |||
} | |||
void WireWidget::drawPlugs(NVGcontext *vg) { | |||
// TODO Figure out a way to draw plugs first and wires last, and cut the plug portion of the wire off. | |||
void CableWidget::drawPlugs(NVGcontext *vg) { | |||
// TODO Figure out a way to draw plugs first and cables last, and cut the plug portion of the cable off. | |||
math::Vec outputPos = getOutputPos(); | |||
math::Vec inputPos = getInputPos(); | |||
drawPlug(vg, outputPos, color); |
@@ -251,10 +251,10 @@ void ModuleWidget::toggleBypass() { | |||
void ModuleWidget::disconnect() { | |||
for (PortWidget *input : inputs) { | |||
app()->scene->rackWidget->wireContainer->removeAllWires(input); | |||
app()->scene->rackWidget->cableContainer->removeAllCables(input); | |||
} | |||
for (PortWidget *output : outputs) { | |||
app()->scene->rackWidget->wireContainer->removeAllWires(output); | |||
app()->scene->rackWidget->cableContainer->removeAllCables(output); | |||
} | |||
} | |||
@@ -28,7 +28,7 @@ PortWidget::~PortWidget() { | |||
// HACK | |||
// See ModuleWidget::~ModuleWidget for description | |||
if (module) | |||
app()->scene->rackWidget->wireContainer->removeAllWires(this); | |||
app()->scene->rackWidget->cableContainer->removeAllCables(this); | |||
} | |||
void PortWidget::step() { | |||
@@ -48,20 +48,20 @@ void PortWidget::step() { | |||
} | |||
void PortWidget::draw(NVGcontext *vg) { | |||
WireWidget *activeWire = app()->scene->rackWidget->wireContainer->activeWire; | |||
if (activeWire) { | |||
// Dim the PortWidget if the active wire cannot plug into this PortWidget | |||
if (type == INPUT ? activeWire->inputPort : activeWire->outputPort) | |||
CableWidget *activeCable = app()->scene->rackWidget->cableContainer->activeCable; | |||
if (activeCable) { | |||
// Dim the PortWidget if the active cable cannot plug into this PortWidget | |||
if (type == INPUT ? activeCable->inputPort : activeCable->outputPort) | |||
nvgGlobalAlpha(vg, 0.5); | |||
} | |||
} | |||
void PortWidget::onButton(const event::Button &e) { | |||
if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_RIGHT) { | |||
app()->scene->rackWidget->wireContainer->removeTopWire(this); | |||
app()->scene->rackWidget->cableContainer->removeTopCable(this); | |||
// HACK | |||
// Update hovered*PortWidget of active wire if applicable | |||
// Update hovered*PortWidget of active cable if applicable | |||
// event::DragEnter eDragEnter; | |||
// onDragEnter(eDragEnter); | |||
} | |||
@@ -69,29 +69,29 @@ void PortWidget::onButton(const event::Button &e) { | |||
} | |||
void PortWidget::onDragStart(const event::DragStart &e) { | |||
// Try to grab wire on top of stack | |||
WireWidget *wire = NULL; | |||
// Try to grab cable on top of stack | |||
CableWidget *cable = NULL; | |||
if (type == INPUT || !app()->window->isModPressed()) { | |||
wire = app()->scene->rackWidget->wireContainer->getTopWire(this); | |||
cable = app()->scene->rackWidget->cableContainer->getTopCable(this); | |||
} | |||
if (wire) { | |||
// Disconnect existing wire | |||
(type == INPUT ? wire->inputPort : wire->outputPort) = NULL; | |||
wire->updateWire(); | |||
if (cable) { | |||
// Disconnect existing cable | |||
(type == INPUT ? cable->inputPort : cable->outputPort) = NULL; | |||
cable->updateCable(); | |||
} | |||
else { | |||
// Create a new wire | |||
wire = new WireWidget; | |||
(type == INPUT ? wire->inputPort : wire->outputPort) = this; | |||
// Create a new cable | |||
cable = new CableWidget; | |||
(type == INPUT ? cable->inputPort : cable->outputPort) = this; | |||
} | |||
app()->scene->rackWidget->wireContainer->setActiveWire(wire); | |||
app()->scene->rackWidget->cableContainer->setActiveCable(cable); | |||
} | |||
void PortWidget::onDragEnd(const event::DragEnd &e) { | |||
// FIXME | |||
// If the source PortWidget is deleted, this will be called, removing the cable | |||
app()->scene->rackWidget->wireContainer->commitActiveWire(); | |||
app()->scene->rackWidget->cableContainer->commitActiveCable(); | |||
} | |||
void PortWidget::onDragDrop(const event::DragDrop &e) { | |||
@@ -112,14 +112,14 @@ 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) { | |||
WireWidget *topWire = app()->scene->rackWidget->wireContainer->getTopWire(this); | |||
if (topWire) | |||
CableWidget *topCable = app()->scene->rackWidget->cableContainer->getTopCable(this); | |||
if (topCable) | |||
return; | |||
} | |||
WireWidget *activeWire = app()->scene->rackWidget->wireContainer->activeWire; | |||
if (activeWire) { | |||
(type == INPUT ? activeWire->hoveredInputPort : activeWire->hoveredOutputPort) = this; | |||
CableWidget *activeCable = app()->scene->rackWidget->cableContainer->activeCable; | |||
if (activeCable) { | |||
(type == INPUT ? activeCable->hoveredInputPort : activeCable->hoveredOutputPort) = this; | |||
} | |||
} | |||
@@ -128,9 +128,9 @@ void PortWidget::onDragLeave(const event::DragLeave &e) { | |||
if (!originPort) | |||
return; | |||
WireWidget *activeWire = app()->scene->rackWidget->wireContainer->activeWire; | |||
if (activeWire) { | |||
(type == INPUT ? activeWire->hoveredInputPort : activeWire->hoveredOutputPort) = NULL; | |||
CableWidget *activeCable = app()->scene->rackWidget->cableContainer->activeCable; | |||
if (activeCable) { | |||
(type == INPUT ? activeCable->hoveredInputPort : activeCable->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->wireContainer->activeWire) { | |||
if (app()->scene->rackWidget->cableContainer->activeCable) { | |||
float margin = 20.0; | |||
float speed = 15.0; | |||
if (pos.x <= viewport.pos.x + margin) | |||
@@ -49,8 +49,8 @@ RackWidget::RackWidget() { | |||
moduleContainer = new ModuleContainer; | |||
addChild(moduleContainer); | |||
wireContainer = new WireContainer; | |||
addChild(wireContainer); | |||
cableContainer = new CableContainer; | |||
addChild(cableContainer); | |||
} | |||
RackWidget::~RackWidget() { | |||
@@ -58,8 +58,8 @@ RackWidget::~RackWidget() { | |||
} | |||
void RackWidget::clear() { | |||
wireContainer->activeWire = NULL; | |||
wireContainer->clearChildren(); | |||
cableContainer->activeCable = NULL; | |||
cableContainer->clearChildren(); | |||
// Remove ModuleWidgets | |||
std::list<Widget*> widgets = moduleContainer->children; | |||
for (Widget *w : widgets) { | |||
@@ -218,7 +218,7 @@ void RackWidget::disconnect() { | |||
if (!osdialog_message(OSDIALOG_WARNING, OSDIALOG_OK_CANCEL, "Remove all patch cables?")) | |||
return; | |||
wireContainer->removeAllWires(NULL); | |||
cableContainer->removeAllCables(NULL); | |||
} | |||
json_t *RackWidget::toJson() { | |||
@@ -248,35 +248,35 @@ json_t *RackWidget::toJson() { | |||
} | |||
json_object_set_new(rootJ, "modules", modulesJ); | |||
// wires | |||
json_t *wiresJ = json_array(); | |||
for (Widget *w : wireContainer->children) { | |||
WireWidget *wireWidget = dynamic_cast<WireWidget*>(w); | |||
assert(wireWidget); | |||
// cables | |||
json_t *cablesJ = json_array(); | |||
for (Widget *w : cableContainer->children) { | |||
CableWidget *cableWidget = dynamic_cast<CableWidget*>(w); | |||
assert(cableWidget); | |||
PortWidget *outputPort = wireWidget->outputPort; | |||
PortWidget *inputPort = wireWidget->inputPort; | |||
// Only serialize WireWidgets connected on both ends | |||
PortWidget *outputPort = cableWidget->outputPort; | |||
PortWidget *inputPort = cableWidget->inputPort; | |||
// Only serialize CableWidgets connected on both ends | |||
if (!(outputPort && inputPort)) | |||
continue; | |||
Wire *wire = wireWidget->wire; | |||
assert(wire); | |||
// wire | |||
json_t *wireJ = wireWidget->toJson(); | |||
Cable *cable = cableWidget->cable; | |||
assert(cable); | |||
// cable | |||
json_t *cableJ = cableWidget->toJson(); | |||
assert(outputPort->module); | |||
assert(inputPort->module); | |||
json_object_set_new(wireJ, "id", json_integer(wire->id)); | |||
json_object_set_new(wireJ, "outputModuleId", json_integer(outputPort->module->id)); | |||
json_object_set_new(wireJ, "outputId", json_integer(outputPort->portId)); | |||
json_object_set_new(wireJ, "inputModuleId", json_integer(inputPort->module->id)); | |||
json_object_set_new(wireJ, "inputId", json_integer(inputPort->portId)); | |||
json_object_set_new(cableJ, "id", json_integer(cable->id)); | |||
json_object_set_new(cableJ, "outputModuleId", json_integer(outputPort->module->id)); | |||
json_object_set_new(cableJ, "outputId", json_integer(outputPort->portId)); | |||
json_object_set_new(cableJ, "inputModuleId", json_integer(inputPort->module->id)); | |||
json_object_set_new(cableJ, "inputId", json_integer(inputPort->portId)); | |||
json_array_append_new(wiresJ, wireJ); | |||
json_array_append_new(cablesJ, cableJ); | |||
} | |||
json_object_set_new(rootJ, "wires", wiresJ); | |||
json_object_set_new(rootJ, "cables", cablesJ); | |||
return rootJ; | |||
} | |||
@@ -358,16 +358,19 @@ void RackWidget::fromJson(json_t *rootJ) { | |||
} | |||
} | |||
// wires | |||
json_t *wiresJ = json_object_get(rootJ, "wires"); | |||
assert(wiresJ); | |||
size_t wireIndex; | |||
json_t *wireJ; | |||
json_array_foreach(wiresJ, wireIndex, wireJ) { | |||
int outputModuleId = json_integer_value(json_object_get(wireJ, "outputModuleId")); | |||
int outputId = json_integer_value(json_object_get(wireJ, "outputId")); | |||
int inputModuleId = json_integer_value(json_object_get(wireJ, "inputModuleId")); | |||
int inputId = json_integer_value(json_object_get(wireJ, "inputId")); | |||
// cables | |||
json_t *cablesJ = json_object_get(rootJ, "cables"); | |||
// Before 1.0, cables were called wires | |||
if (!cablesJ) | |||
cablesJ = json_object_get(rootJ, "wires"); | |||
assert(cablesJ); | |||
size_t cableIndex; | |||
json_t *cableJ; | |||
json_array_foreach(cablesJ, cableIndex, cableJ) { | |||
int outputModuleId = json_integer_value(json_object_get(cableJ, "outputModuleId")); | |||
int outputId = json_integer_value(json_object_get(cableJ, "outputId")); | |||
int inputModuleId = json_integer_value(json_object_get(cableJ, "inputModuleId")); | |||
int inputId = json_integer_value(json_object_get(cableJ, "inputId")); | |||
// Get module widgets | |||
ModuleWidget *outputModuleWidget = moduleWidgets[outputModuleId]; | |||
@@ -400,14 +403,14 @@ void RackWidget::fromJson(json_t *rootJ) { | |||
if (!outputPort || !inputPort) | |||
continue; | |||
// Create WireWidget | |||
WireWidget *wireWidget = new WireWidget; | |||
wireWidget->fromJson(wireJ); | |||
wireWidget->outputPort = outputPort; | |||
wireWidget->inputPort = inputPort; | |||
wireWidget->updateWire(); | |||
// Add wire to rack | |||
wireContainer->addChild(wireWidget); | |||
// Create CableWidget | |||
CableWidget *cableWidget = new CableWidget; | |||
cableWidget->fromJson(cableJ); | |||
cableWidget->outputPort = outputPort; | |||
cableWidget->inputPort = inputPort; | |||
cableWidget->updateCable(); | |||
// Add cable to rack | |||
cableContainer->addChild(cableWidget); | |||
} | |||
// Display a message if we have something to say | |||
@@ -481,7 +484,7 @@ void RackWidget::addModuleAtMouse(ModuleWidget *m) { | |||
} | |||
void RackWidget::removeModule(ModuleWidget *m) { | |||
// Disconnect wires | |||
// Disconnect cables | |||
m->disconnect(); | |||
// Remove module from Engine | |||
@@ -156,12 +156,12 @@ struct ZoomQuantity : Quantity { | |||
}; | |||
struct WireOpacityQuantity : Quantity { | |||
struct CableOpacityQuantity : Quantity { | |||
void setValue(float value) override { | |||
settings::wireOpacity = math::clamp(value, getMinValue(), getMaxValue()); | |||
settings::cableOpacity = math::clamp(value, getMinValue(), getMaxValue()); | |||
} | |||
float getValue() override { | |||
return settings::wireOpacity; | |||
return settings::cableOpacity; | |||
} | |||
float getDefaultValue() override {return 0.5;} | |||
float getDisplayValue() override {return getValue() * 100.0;} | |||
@@ -173,12 +173,12 @@ struct WireOpacityQuantity : Quantity { | |||
struct WireTensionQuantity : Quantity { | |||
struct CableTensionQuantity : Quantity { | |||
void setValue(float value) override { | |||
settings::wireTension = math::clamp(value, getMinValue(), getMaxValue()); | |||
settings::cableTension = math::clamp(value, getMinValue(), getMaxValue()); | |||
} | |||
float getValue() override { | |||
return settings::wireTension; | |||
return settings::cableTension; | |||
} | |||
float getDefaultValue() override {return 0.5;} | |||
std::string getLabel() override {return "Cable tension";} | |||
@@ -281,15 +281,15 @@ struct SettingsButton : MenuButton { | |||
zoomSlider->quantity = new ZoomQuantity; | |||
menu->addChild(zoomSlider); | |||
Slider *wireOpacitySlider = new Slider; | |||
wireOpacitySlider->box.size.x = 200.0; | |||
wireOpacitySlider->quantity = new WireOpacityQuantity; | |||
menu->addChild(wireOpacitySlider); | |||
Slider *cableOpacitySlider = new Slider; | |||
cableOpacitySlider->box.size.x = 200.0; | |||
cableOpacitySlider->quantity = new CableOpacityQuantity; | |||
menu->addChild(cableOpacitySlider); | |||
Slider *wireTensionSlider = new Slider; | |||
wireTensionSlider->box.size.x = 200.0; | |||
wireTensionSlider->quantity = new WireTensionQuantity; | |||
menu->addChild(wireTensionSlider); | |||
Slider *cableTensionSlider = new Slider; | |||
cableTensionSlider->box.size.x = 200.0; | |||
cableTensionSlider->quantity = new CableTensionQuantity; | |||
menu->addChild(cableTensionSlider); | |||
} | |||
}; | |||
@@ -1,108 +0,0 @@ | |||
#include "app/WireContainer.hpp" | |||
namespace rack { | |||
void WireContainer::setActiveWire(WireWidget *w) { | |||
if (activeWire) { | |||
removeChild(activeWire); | |||
delete activeWire; | |||
activeWire = NULL; | |||
} | |||
if (w) { | |||
if (w->parent == NULL) | |||
addChild(w); | |||
activeWire = w; | |||
} | |||
} | |||
void WireContainer::commitActiveWire() { | |||
if (!activeWire) | |||
return; | |||
if (activeWire->hoveredOutputPort) { | |||
activeWire->outputPort = activeWire->hoveredOutputPort; | |||
activeWire->hoveredOutputPort = NULL; | |||
} | |||
if (activeWire->hoveredInputPort) { | |||
activeWire->inputPort = activeWire->hoveredInputPort; | |||
activeWire->hoveredInputPort = NULL; | |||
} | |||
activeWire->updateWire(); | |||
// Did it successfully connect? | |||
if (activeWire->wire) { | |||
// Make it permanent | |||
activeWire = NULL; | |||
} | |||
else { | |||
// Remove it | |||
setActiveWire(NULL); | |||
} | |||
} | |||
void WireContainer::removeTopWire(PortWidget *port) { | |||
WireWidget *wire = getTopWire(port); | |||
if (wire) { | |||
removeChild(wire); | |||
delete wire; | |||
} | |||
} | |||
void WireContainer::removeAllWires(PortWidget *port) { | |||
// As a convenience, de-hover the active wire so we don't attach them once it is dropped. | |||
if (activeWire) { | |||
if (activeWire->hoveredInputPort == port) | |||
activeWire->hoveredInputPort = NULL; | |||
if (activeWire->hoveredOutputPort == port) | |||
activeWire->hoveredOutputPort = NULL; | |||
} | |||
// Build a list of WireWidgets to delete | |||
std::list<WireWidget*> wires; | |||
for (Widget *child : children) { | |||
WireWidget *wire = dynamic_cast<WireWidget*>(child); | |||
assert(wire); | |||
if (!wire || wire->inputPort == port || wire->outputPort == port) { | |||
if (activeWire == wire) { | |||
activeWire = NULL; | |||
} | |||
// We can't delete from this list while we're iterating it, so add it to the deletion list. | |||
wires.push_back(wire); | |||
} | |||
} | |||
// Once we're done building the list, actually delete them | |||
for (WireWidget *wire : wires) { | |||
removeChild(wire); | |||
delete wire; | |||
} | |||
} | |||
WireWidget *WireContainer::getTopWire(PortWidget *port) { | |||
for (auto it = children.rbegin(); it != children.rend(); it++) { | |||
WireWidget *wire = dynamic_cast<WireWidget*>(*it); | |||
assert(wire); | |||
// Ignore incomplete wires | |||
if (!(wire->inputPort && wire->outputPort)) | |||
continue; | |||
if (wire->inputPort == port || wire->outputPort == port) | |||
return wire; | |||
} | |||
return NULL; | |||
} | |||
void WireContainer::draw(NVGcontext *vg) { | |||
Widget::draw(vg); | |||
// Wire plugs | |||
for (Widget *child : children) { | |||
WireWidget *wire = dynamic_cast<WireWidget*>(child); | |||
assert(wire); | |||
wire->drawPlugs(vg); | |||
} | |||
} | |||
} // namespace rack |
@@ -1,10 +1,10 @@ | |||
#include "engine/Wire.hpp" | |||
#include "engine/Cable.hpp" | |||
namespace rack { | |||
void Wire::step() { | |||
void Cable::step() { | |||
Output *output = &outputModule->outputs[outputId]; | |||
Input *input = &inputModule->inputs[inputId]; | |||
// Match number of polyphonic channels to output port |
@@ -53,7 +53,7 @@ struct Engine::Internal { | |||
Module *resetModule = NULL; | |||
Module *randomizeModule = NULL; | |||
int nextModuleId = 1; | |||
int nextWireId = 1; | |||
int nextCableId = 1; | |||
// Parameter smoothing | |||
Module *smoothModule = NULL; | |||
@@ -76,8 +76,8 @@ Engine::Engine() { | |||
} | |||
Engine::~Engine() { | |||
// Make sure there are no wires or modules in the rack on destruction. This suggests that a module failed to remove itself before the RackWidget was destroyed. | |||
assert(wires.empty()); | |||
// Make sure there are no cables or modules in the rack on destruction. This suggests that a module failed to remove itself before the RackWidget was destroyed. | |||
assert(cables.empty()); | |||
assert(modules.empty()); | |||
delete internal; | |||
@@ -172,8 +172,8 @@ static void Engine_step(Engine *engine) { | |||
} | |||
// Step cables | |||
for (Wire *wire : engine->wires) { | |||
wire->step(); | |||
for (Cable *cable : engine->cables) { | |||
cable->step(); | |||
} | |||
} | |||
@@ -257,10 +257,10 @@ void Engine::removeModule(Module *module) { | |||
if (module == internal->smoothModule) { | |||
internal->smoothModule = NULL; | |||
} | |||
// Check that all wires are disconnected | |||
for (Wire *wire : wires) { | |||
assert(wire->outputModule != module); | |||
assert(wire->inputModule != module); | |||
// Check that all cables are disconnected | |||
for (Cable *cable : cables) { | |||
assert(cable->outputModule != module); | |||
assert(cable->inputModule != module); | |||
} | |||
// Check that the module actually exists | |||
auto it = std::find(modules.begin(), modules.end(), module); | |||
@@ -290,55 +290,55 @@ static void Engine_updateActive(Engine *engine) { | |||
} | |||
} | |||
// Set inputs/outputs to active | |||
for (Wire *wire : engine->wires) { | |||
wire->outputModule->outputs[wire->outputId].active = true; | |||
wire->inputModule->inputs[wire->inputId].active = true; | |||
for (Cable *cable : engine->cables) { | |||
cable->outputModule->outputs[cable->outputId].active = true; | |||
cable->inputModule->inputs[cable->inputId].active = true; | |||
} | |||
} | |||
void Engine::addWire(Wire *wire) { | |||
assert(wire); | |||
void Engine::addCable(Cable *cable) { | |||
assert(cable); | |||
VIPLock vipLock(internal->vipMutex); | |||
std::lock_guard<std::mutex> lock(internal->mutex); | |||
// Check wire properties | |||
assert(wire->outputModule); | |||
assert(wire->inputModule); | |||
// Check that the wire is not already added, and that the input is not already used by another cable | |||
for (Wire *wire2 : wires) { | |||
assert(wire2 != wire); | |||
assert(!(wire2->inputModule == wire->inputModule && wire2->inputId == wire->inputId)); | |||
// Check cable properties | |||
assert(cable->outputModule); | |||
assert(cable->inputModule); | |||
// Check that the cable is not already added, and that the input is not already used by another cable | |||
for (Cable *cable2 : cables) { | |||
assert(cable2 != cable); | |||
assert(!(cable2->inputModule == cable->inputModule && cable2->inputId == cable->inputId)); | |||
} | |||
// Set ID | |||
if (wire->id == 0) { | |||
if (cable->id == 0) { | |||
// Automatically assign ID | |||
wire->id = internal->nextWireId++; | |||
cable->id = internal->nextCableId++; | |||
} | |||
else { | |||
// Manual ID | |||
// Check that the ID is not already taken | |||
for (Wire *w : wires) { | |||
assert(wire->id != w->id); | |||
for (Cable *w : cables) { | |||
assert(cable->id != w->id); | |||
} | |||
} | |||
// Add the wire | |||
wires.push_back(wire); | |||
// Add the cable | |||
cables.push_back(cable); | |||
Engine_updateActive(this); | |||
} | |||
void Engine::removeWire(Wire *wire) { | |||
assert(wire); | |||
void Engine::removeCable(Cable *cable) { | |||
assert(cable); | |||
VIPLock vipLock(internal->vipMutex); | |||
std::lock_guard<std::mutex> lock(internal->mutex); | |||
// Check that the wire is already added | |||
auto it = std::find(wires.begin(), wires.end(), wire); | |||
assert(it != wires.end()); | |||
// Check that the cable is already added | |||
auto it = std::find(cables.begin(), cables.end(), cable); | |||
assert(it != cables.end()); | |||
// Set input to 0V | |||
wire->inputModule->inputs[wire->inputId].value = 0.f; | |||
// Remove the wire | |||
wires.erase(it); | |||
cable->inputModule->inputs[cable->inputId].value = 0.f; | |||
// Remove the cable | |||
cables.erase(it); | |||
Engine_updateActive(this); | |||
// Remove ID | |||
wire->id = 0; | |||
cable->id = 0; | |||
} | |||
void Engine::setParam(Module *module, int paramId, float value) { | |||
@@ -37,9 +37,9 @@ void ModuleRemove::undo() { | |||
moduleWidget->fromJson(moduleJ); | |||
app()->scene->rackWidget->addModule(moduleWidget); | |||
// Add wires | |||
for (WireInfo &wireInfo : wireInfos) { | |||
// TODO Add wire | |||
// Add cables | |||
for (CableInfo &cableInfo : cableInfos) { | |||
// TODO Add cable | |||
} | |||
} | |||
@@ -32,13 +32,13 @@ static json_t *settingsToJson() { | |||
json_object_set_new(rootJ, "windowPos", windowPosJ); | |||
} | |||
// wireOpacity | |||
json_t *wireOpacityJ = json_real(wireOpacity); | |||
json_object_set_new(rootJ, "wireOpacity", wireOpacityJ); | |||
// cableOpacity | |||
json_t *cableOpacityJ = json_real(cableOpacity); | |||
json_object_set_new(rootJ, "cableOpacity", cableOpacityJ); | |||
// wireTension | |||
json_t *wireTensionJ = json_real(wireTension); | |||
json_object_set_new(rootJ, "wireTension", wireTensionJ); | |||
// cableTension | |||
json_t *cableTensionJ = json_real(cableTension); | |||
json_object_set_new(rootJ, "cableTension", cableTensionJ); | |||
// zoom | |||
json_t *zoomJ = json_real(zoom); | |||
@@ -98,15 +98,15 @@ static void settingsFromJson(json_t *rootJ) { | |||
app()->window->setWindowPos(math::Vec(x, y)); | |||
} | |||
// wireOpacity | |||
json_t *wireOpacityJ = json_object_get(rootJ, "wireOpacity"); | |||
if (wireOpacityJ) | |||
wireOpacity = json_number_value(wireOpacityJ); | |||
// cableOpacity | |||
json_t *cableOpacityJ = json_object_get(rootJ, "cableOpacity"); | |||
if (cableOpacityJ) | |||
cableOpacity = json_number_value(cableOpacityJ); | |||
// tension | |||
json_t *tensionJ = json_object_get(rootJ, "wireTension"); | |||
json_t *tensionJ = json_object_get(rootJ, "cableTension"); | |||
if (tensionJ) | |||
wireTension = json_number_value(tensionJ); | |||
cableTension = json_number_value(tensionJ); | |||
// zoom | |||
json_t *zoomJ = json_object_get(rootJ, "zoom"); | |||
@@ -192,8 +192,8 @@ void load(std::string filename) { | |||
float zoom = 1.0; | |||
float wireOpacity = 0.5; | |||
float wireTension = 0.5; | |||
float cableOpacity = 0.5; | |||
float cableTension = 0.5; | |||
bool paramTooltip = false; | |||
bool powerMeter = false; | |||
bool lockModules = false; | |||