Browse Source

Rework widgets to support cable stacking

tags/v0.4.0
Andrew Belt 7 years ago
parent
commit
7ee43d337d
6 changed files with 185 additions and 113 deletions
  1. +15
    -8
      include/app.hpp
  2. +2
    -2
      src/app/ModuleWidget.cpp
  3. +38
    -64
      src/app/Port.cpp
  4. +1
    -16
      src/app/RackWidget.cpp
  5. +108
    -0
      src/app/WireContainer.cpp
  6. +21
    -23
      src/app/WireWidget.cpp

+ 15
- 8
include/app.hpp View File

@@ -83,13 +83,25 @@ struct WireWidget : OpaqueWidget {
void drawPlugs(NVGcontext *vg);
};

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(Port *port);
void removeAllWires(Port *port);
/** Returns the most recently added wire connected to the given Port, i.e. the top of the stack */
WireWidget *getTopWire(Port *port);
void draw(NVGcontext *vg);
};

struct RackWidget : OpaqueWidget {
FramebufferWidget *rails;
// Only put ModuleWidgets in here
Widget *moduleContainer;
// Only put WireWidgets in here
Widget *wireContainer;
WireWidget *activeWire = NULL;
WireContainer *wireContainer;
std::string lastPath;

RackWidget();
@@ -249,20 +261,15 @@ struct MomentarySwitch : virtual Switch {

struct Port : OpaqueWidget {
enum PortType {
DEFAULT,
INPUT,
OUTPUT
};

Module *module = NULL;
WireWidget *connectedWire = NULL;
PortType type = DEFAULT;
PortType type = INPUT;
int portId;

Port();
~Port();
void disconnect();

void draw(NVGcontext *vg);
void onMouseDownOpaque(int button);
void onDragEnd();


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

@@ -97,10 +97,10 @@ void ModuleWidget::fromJson(json_t *rootJ) {

void ModuleWidget::disconnect() {
for (Port *input : inputs) {
input->disconnect();
gRackWidget->wireContainer->removeAllWires(input);
}
for (Port *output : outputs) {
output->disconnect();
gRackWidget->wireContainer->removeAllWires(output);
}
}



+ 38
- 64
src/app/Port.cpp View File

@@ -3,109 +3,83 @@

namespace rack {

Port::Port() {
box.size = Vec(20, 20);
}

Port::~Port() {
disconnect();

if (gRackWidget->activeWire) {
if (gRackWidget->activeWire->hoveredInputPort == this)
gRackWidget->activeWire->hoveredInputPort = NULL;
if (gRackWidget->activeWire->hoveredOutputPort == this)
gRackWidget->activeWire->hoveredOutputPort = NULL;
}
}

void Port::disconnect() {
if (connectedWire) {
gRackWidget->wireContainer->removeChild(connectedWire);
// On destruction, Wire automatically sets connectedWire to NULL
delete connectedWire;
}
gRackWidget->wireContainer->removeAllWires(this);
}

void Port::draw(NVGcontext *vg) {
if (gRackWidget->activeWire) {
WireWidget *activeWire = gRackWidget->wireContainer->activeWire;
if (activeWire) {
// Dim the Port if the active wire cannot plug into this Port
if (type == INPUT ? gRackWidget->activeWire->inputPort : gRackWidget->activeWire->outputPort)
if (type == INPUT ? activeWire->inputPort : activeWire->outputPort)
nvgGlobalAlpha(vg, 0.5);
}
}

void Port::onMouseDownOpaque(int button) {
if (button == 1) {
disconnect();
gRackWidget->wireContainer->removeTopWire(this);

// HACK
// Update hovered*Port of active wire if applicable
onDragEnter(NULL);
}
}

void Port::onDragEnd() {
WireWidget *w = gRackWidget->activeWire;
assert(w);
w->updateWire();
if (!w->wire) {
gRackWidget->wireContainer->removeChild(w);
delete w;
}
gRackWidget->activeWire = NULL;
gRackWidget->wireContainer->commitActiveWire();
}

void Port::onDragStart() {
if (connectedWire) {
// Disconnect wire from this port, but set it as the active wire
// Try to grab wire on top of stack
WireWidget *wire = gRackWidget->wireContainer->getTopWire(this);

if (wire) {
// Disconnect existing wire
if (type == INPUT)
connectedWire->inputPort = NULL;
wire->inputPort = NULL;
else
connectedWire->outputPort = NULL;
connectedWire->updateWire();
gRackWidget->activeWire = connectedWire;
connectedWire = NULL;
wire->outputPort = NULL;
wire->updateWire();
}
else {
connectedWire = new WireWidget();
// Create a new wire
wire = new WireWidget();
if (type == INPUT)
connectedWire->inputPort = this;
wire->inputPort = this;
else
connectedWire->outputPort = this;
gRackWidget->wireContainer->addChild(connectedWire);
gRackWidget->activeWire = connectedWire;
wire->outputPort = this;
}
gRackWidget->wireContainer->setActiveWire(wire);
}

void Port::onDragDrop(Widget *origin) {
if (connectedWire) return;
if (gRackWidget->activeWire) {
if (type == INPUT) {
gRackWidget->activeWire->hoveredInputPort = NULL;
if (gRackWidget->activeWire->inputPort) return;
gRackWidget->activeWire->inputPort = this;
}
else {
gRackWidget->activeWire->hoveredOutputPort = NULL;
if (gRackWidget->activeWire->outputPort) return;
gRackWidget->activeWire->outputPort = this;
}
connectedWire = gRackWidget->activeWire;
}
}

void Port::onDragEnter(Widget *origin) {
if (connectedWire) return;
if (gRackWidget->activeWire) {
// Reject ports if this is an input port and something is already plugged into it
if (type == INPUT) {
WireWidget *topWire = gRackWidget->wireContainer->getTopWire(this);
if (topWire)
return;
}

WireWidget *activeWire = gRackWidget->wireContainer->activeWire;
if (activeWire) {
if (type == INPUT)
gRackWidget->activeWire->hoveredInputPort = this;
activeWire->hoveredInputPort = this;
else
gRackWidget->activeWire->hoveredOutputPort = this;
activeWire->hoveredOutputPort = this;
}
}

void Port::onDragLeave(Widget *origin) {
if (gRackWidget->activeWire) {
WireWidget *activeWire = gRackWidget->wireContainer->activeWire;
if (activeWire) {
if (type == INPUT)
gRackWidget->activeWire->hoveredInputPort = NULL;
activeWire->hoveredInputPort = NULL;
else
gRackWidget->activeWire->hoveredOutputPort = NULL;
activeWire->hoveredOutputPort = NULL;
}
}



+ 1
- 16
src/app/RackWidget.cpp View File

@@ -13,19 +13,6 @@
namespace rack {


struct WireContainer : TransparentWidget {
void draw(NVGcontext *vg) {
// Wire plugs
for (Widget *child : children) {
WireWidget *wire = dynamic_cast<WireWidget*>(child);
assert(wire);
wire->drawPlugs(vg);
}

Widget::draw(vg);
}
};

RackWidget::RackWidget() {
rails = new FramebufferWidget();
RackRail *rail = new RackRail();
@@ -45,7 +32,7 @@ RackWidget::~RackWidget() {
}

void RackWidget::clear() {
activeWire = NULL;
wireContainer->activeWire = NULL;
wireContainer->clearChildren();
moduleContainer->clearChildren();
lastPath = "";
@@ -253,8 +240,6 @@ void RackWidget::fromJson(json_t *rootJ) {
WireWidget *wireWidget = new WireWidget();
wireWidget->outputPort = outputPort;
wireWidget->inputPort = inputPort;
outputPort->connectedWire = wireWidget;
inputPort->connectedWire = wireWidget;
wireWidget->updateWire();
// Add wire to rack
wireContainer->addChild(wireWidget);


+ 108
- 0
src/app/WireContainer.cpp View File

@@ -0,0 +1,108 @@
#include "app.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->hoveredInputPort) {
activeWire->inputPort = activeWire->hoveredInputPort;
activeWire->hoveredInputPort = NULL;
}
if (activeWire->hoveredOutputPort) {
activeWire->outputPort = activeWire->hoveredOutputPort;
activeWire->hoveredOutputPort = NULL;
}
activeWire->updateWire();

// Did it successfully connect?
if (activeWire->wire) {
// Make it permanent
activeWire = NULL;
}
else {
// Remove it
setActiveWire(NULL);
}
}

void WireContainer::removeTopWire(Port *port) {
WireWidget *wire = getTopWire(port);
if (wire) {
removeChild(wire);
delete wire;
}
}

void WireContainer::removeAllWires(Port *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->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(Port *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

+ 21
- 23
src/app/WireWidget.cpp View File

@@ -87,34 +87,32 @@ WireWidget::WireWidget() {
}

WireWidget::~WireWidget() {
if (outputPort) {
outputPort->connectedWire = NULL;
outputPort = NULL;
}
if (inputPort) {
inputPort->connectedWire = NULL;
inputPort = NULL;
}
outputPort = NULL;
inputPort = NULL;
updateWire();
}

void WireWidget::updateWire() {
if (wire) {
engineRemoveWire(wire);
delete wire;
wire = NULL;
}
if (inputPort && outputPort) {
// Check correct types
assert(inputPort->type == Port::INPUT);
assert(outputPort->type == Port::OUTPUT);

wire = new Wire();
wire->outputModule = outputPort->module;
wire->outputId = outputPort->portId;
wire->inputModule = inputPort->module;
wire->inputId = inputPort->portId;
engineAddWire(wire);
if (!wire) {
wire = new Wire();
wire->outputModule = outputPort->module;
wire->outputId = outputPort->portId;
wire->inputModule = inputPort->module;
wire->inputId = inputPort->portId;
engineAddWire(wire);
}
}
else {
if (wire) {
engineRemoveWire(wire);
delete wire;
wire = NULL;
}
}
}

@@ -150,17 +148,17 @@ void WireWidget::draw(NVGcontext *vg) {
float opacity = dynamic_cast<RackScene*>(gScene)->toolbar->wireOpacitySlider->value / 100.0;
float tension = dynamic_cast<RackScene*>(gScene)->toolbar->wireTensionSlider->value;

// Display the actively dragged wire as opaque
if (gRackWidget->activeWire == this)
// Draw as opaque if an "incomplete" wire
if (!(inputPort && outputPort))
opacity = 1.0;

drawWire(vg, getOutputPos(), getInputPos(), color, tension, opacity);
drawPlug(vg, getOutputPos(), color);
drawPlug(vg, getInputPos(), color);
}

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.
drawPlug(vg, getOutputPos(), color);
drawPlug(vg, getInputPos(), color);
}




Loading…
Cancel
Save