Browse Source

Make PlugWidget a child of PlugContainer instead of a child of CableWidget.

tags/v2.6.0
Andrew Belt 6 months ago
parent
commit
73d27e9df6
4 changed files with 193 additions and 133 deletions
  1. +14
    -1
      include/app/CableWidget.hpp
  2. +1
    -0
      include/app/RackWidget.hpp
  3. +149
    -127
      src/app/CableWidget.cpp
  4. +29
    -5
      src/app/RackWidget.cpp

+ 14
- 1
include/app/CableWidget.hpp View File

@@ -10,7 +10,18 @@ namespace rack {
namespace app {


struct PlugWidget;
struct PlugWidget : widget::Widget {
struct Internal;
Internal* internal;

PlugWidget();
~PlugWidget();
void step() override;
PRIVATE void setColor(NVGcolor color);
PRIVATE void setAngle(float angle);
PRIVATE void setPortWidget(PortWidget* portWidget);
PRIVATE void setTop(bool top);
};


struct CableWidget : widget::Widget {
@@ -47,6 +58,8 @@ struct CableWidget : widget::Widget {
void draw(const DrawArgs& args) override;
void drawLayer(const DrawArgs& args, int layer) override;
engine::Cable* releaseCable();
void onAdd(const AddEvent& e) override;
void onRemove(const RemoveEvent& e) override;
};




+ 1
- 0
include/app/RackWidget.hpp View File

@@ -41,6 +41,7 @@ struct RackWidget : widget::OpaqueWidget {
// Rack methods

widget::Widget* getModuleContainer();
widget::Widget* getPlugContainer();
widget::Widget* getCableContainer();
math::Vec getMousePos();



+ 149
- 127
src/app/CableWidget.cpp View File

@@ -33,7 +33,8 @@ struct PlugLight : componentlibrary::TRedGreenBlueLight<app::MultiLightWidget> {
};


struct PlugWidget : widget::Widget {
struct PlugWidget::Internal {
/** Initially pointing upward. */
float angle = 0.5f * M_PI;
PortWidget* portWidget = NULL;

@@ -45,75 +46,83 @@ struct PlugWidget : widget::Widget {
widget::SvgWidget* plugPort;

app::MultiLightWidget* plugLight;
};


PlugWidget() {
fb = new widget::FramebufferWidget;
addChild(fb);
PlugWidget::PlugWidget() {
internal = new Internal;

plugTransform = new widget::TransformWidget;
fb->addChild(plugTransform);
internal->fb = new widget::FramebufferWidget;
addChild(internal->fb);

plugTint = new TintWidget;
plugTransform->addChild(plugTint);
internal->plugTransform = new widget::TransformWidget;
internal->fb->addChild(internal->plugTransform);

plug = new widget::SvgWidget;
plug->setSvg(window::Svg::load(asset::system("res/ComponentLibrary/Plug.svg")));
plugTint->addChild(plug);
plugTransform->setSize(plug->getSize());
plugTransform->setPosition(plug->getSize().mult(-0.5));
plugTint->setSize(plug->getSize());
internal->plugTint = new TintWidget;
internal->plugTransform->addChild(internal->plugTint);

plugPort = new widget::SvgWidget;
plugPort->setSvg(window::Svg::load(asset::system("res/ComponentLibrary/PlugPort.svg")));
plugPort->setPosition(plugPort->getSize().mult(-0.5));
fb->addChild(plugPort);
internal->plug = new widget::SvgWidget;
internal->plug->setSvg(window::Svg::load(asset::system("res/ComponentLibrary/Plug.svg")));
internal->plugTint->addChild(internal->plug);
internal->plugTransform->setSize(internal->plug->getSize());
internal->plugTransform->setPosition(internal->plug->getSize().mult(-0.5));
internal->plugTint->setSize(internal->plug->getSize());

plugLight = new PlugLight;
plugLight->setPosition(plugLight->getSize().mult(-0.5));
addChild(plugLight);
internal->plugPort = new widget::SvgWidget;
internal->plugPort->setSvg(window::Svg::load(asset::system("res/ComponentLibrary/PlugPort.svg")));
internal->plugPort->setPosition(internal->plugPort->getSize().mult(-0.5));
internal->fb->addChild(internal->plugPort);

internal->plugLight = new PlugLight;
internal->plugLight->setPosition(internal->plugLight->getSize().mult(-0.5));
addChild(internal->plugLight);

setSize(internal->plug->getSize());
}

setSize(plug->getSize());
}

void step() override {
std::vector<float> values(3);
if (portWidget && plugLight->isVisible()) {
engine::Port* port = portWidget->getPort();
if (port) {
for (int i = 0; i < 3; i++) {
values[i] = port->plugLights[i].getBrightness();
}
PlugWidget::~PlugWidget() {
delete internal;
}

void PlugWidget::step() {
std::vector<float> values(3);
if (internal->portWidget && internal->plugLight->isVisible()) {
engine::Port* port = internal->portWidget->getPort();
if (port) {
for (int i = 0; i < 3; i++) {
values[i] = port->plugLights[i].getBrightness();
}
}
plugLight->setBrightnesses(values);

Widget::step();
}
internal->plugLight->setBrightnesses(values);

void setColor(NVGcolor color) {
if (color::isEqual(color, plugTint->color))
return;
plugTint->color = color;
fb->setDirty();
}
Widget::step();
}

void setAngle(float angle) {
if (angle == this->angle)
return;
this->angle = angle;
plugTransform->identity();
plugTransform->rotate(angle - 0.5f * M_PI, plug->getSize().div(2));
fb->setDirty();
}
void PlugWidget::setColor(NVGcolor color) {
if (color::isEqual(color, internal->plugTint->color))
return;
internal->plugTint->color = color;
internal->fb->setDirty();
}

void setPortWidget(PortWidget* portWidget) {
this->portWidget = portWidget;
}
void PlugWidget::setAngle(float angle) {
if (angle == internal->angle)
return;
internal->angle = angle;
internal->plugTransform->identity();
internal->plugTransform->rotate(angle - 0.5f * M_PI, internal->plug->getSize().div(2));
internal->fb->setDirty();
}

void setTop(bool top) {
plugLight->setVisible(top);
}
};
void PlugWidget::setPortWidget(PortWidget* portWidget) {
internal->portWidget = portWidget;
}

void PlugWidget::setTop(bool top) {
internal->plugLight->setVisible(top);
}


struct CableWidget::Internal {
@@ -124,15 +133,15 @@ CableWidget::CableWidget() {
internal = new Internal;
color = color::BLACK_TRANSPARENT;

inputPlug = new PlugWidget;
addChild(inputPlug);

outputPlug = new PlugWidget;
addChild(outputPlug);
inputPlug = new PlugWidget;
}


CableWidget::~CableWidget() {
delete outputPlug;
delete inputPlug;

setCable(NULL);
delete internal;
}
@@ -278,84 +287,81 @@ void CableWidget::step() {


void CableWidget::draw(const DrawArgs& args) {
// Draw plugs
Widget::draw(args);
CableWidget::drawLayer(args, 0);
}


void CableWidget::drawLayer(const DrawArgs& args, int layer) {
// Cable shadow and cable
if (layer == 2 || layer == 3) {
float opacity = settings::cableOpacity;
bool thick = false;

if (isComplete()) {
engine::Output* output = &cable->outputModule->outputs[cable->outputId];
// Increase thickness if output port is polyphonic
if (output->isPolyphonic()) {
thick = true;
}

// Draw opaque if mouse is hovering over a connected port
Widget* hoveredWidget = APP->event->hoveredWidget;
if (outputPort == hoveredWidget || inputPort == hoveredWidget) {
opacity = 1.0;
}
// Draw translucent cable if not active (i.e. 0 channels)
else if (output->getChannels() == 0) {
opacity *= 0.5;
}
}
else {
// Draw opaque if the cable is incomplete
opacity = 1.0;
float opacity = settings::cableOpacity;
bool thick = false;

if (isComplete()) {
engine::Output* output = &cable->outputModule->outputs[cable->outputId];
// Increase thickness if output port is polyphonic
if (output->isPolyphonic()) {
thick = true;
}

if (opacity <= 0.0)
return;
nvgAlpha(args.vg, std::pow(opacity, 1.5));

math::Vec outputPos = getOutputPos();
math::Vec inputPos = getInputPos();

float thickness = thick ? 9.0 : 6.0;

// The endpoints are off-center
math::Vec slump = getSlumpPos(outputPos, inputPos);
outputPos = outputPos.plus(slump.minus(outputPos).normalize().mult(13.0));
inputPos = inputPos.plus(slump.minus(inputPos).normalize().mult(13.0));

nvgLineCap(args.vg, NVG_ROUND);
// Avoids glitches when cable is bent
nvgLineJoin(args.vg, NVG_ROUND);

if (layer == 2) {
// Draw cable shadow
math::Vec shadowSlump = slump.plus(math::Vec(0, 30));
nvgBeginPath(args.vg);
nvgMoveTo(args.vg, VEC_ARGS(outputPos));
nvgQuadTo(args.vg, VEC_ARGS(shadowSlump), VEC_ARGS(inputPos));
NVGcolor shadowColor = nvgRGBAf(0, 0, 0, 0.10);
nvgStrokeColor(args.vg, shadowColor);
nvgStrokeWidth(args.vg, thickness - 1.0);
nvgStroke(args.vg);
// Draw opaque if mouse is hovering over a connected port
Widget* hoveredWidget = APP->event->hoveredWidget;
if (outputPort == hoveredWidget || inputPort == hoveredWidget) {
opacity = 1.0;
}
else if (layer == 3) {
// Draw cable outline
nvgBeginPath(args.vg);
nvgMoveTo(args.vg, VEC_ARGS(outputPos));
nvgQuadTo(args.vg, VEC_ARGS(slump), VEC_ARGS(inputPos));
// nvgStrokePaint(args.vg, nvgLinearGradient(args.vg, VEC_ARGS(outputPos), VEC_ARGS(inputPos), color::mult(color, 0.5), color));
nvgStrokeColor(args.vg, color::mult(color, 0.8));
nvgStrokeWidth(args.vg, thickness);
nvgStroke(args.vg);

// Draw cable
nvgStrokeColor(args.vg, color::mult(color, 0.95));
nvgStrokeWidth(args.vg, thickness - 1.0);
nvgStroke(args.vg);
// Draw translucent cable if not active (i.e. 0 channels)
else if (output->getChannels() == 0) {
opacity *= 0.5;
}
}
else {
// Draw opaque if the cable is incomplete
opacity = 1.0;
}

if (opacity <= 0.0)
return;
nvgAlpha(args.vg, std::pow(opacity, 1.5));

math::Vec outputPos = getOutputPos();
math::Vec inputPos = getInputPos();

float thickness = thick ? 9.0 : 6.0;

// The endpoints are off-center
math::Vec slump = getSlumpPos(outputPos, inputPos);
outputPos = outputPos.plus(slump.minus(outputPos).normalize().mult(13.0));
inputPos = inputPos.plus(slump.minus(inputPos).normalize().mult(13.0));

nvgLineCap(args.vg, NVG_ROUND);
// Avoids glitches when cable is bent
nvgLineJoin(args.vg, NVG_ROUND);

if (layer == -1) {
// Draw cable shadow
math::Vec shadowSlump = slump.plus(math::Vec(0, 30));
nvgBeginPath(args.vg);
nvgMoveTo(args.vg, VEC_ARGS(outputPos));
nvgQuadTo(args.vg, VEC_ARGS(shadowSlump), VEC_ARGS(inputPos));
NVGcolor shadowColor = nvgRGBAf(0, 0, 0, 0.10);
nvgStrokeColor(args.vg, shadowColor);
nvgStrokeWidth(args.vg, thickness - 1.0);
nvgStroke(args.vg);
}
else if (layer == 0) {
// Draw cable outline
nvgBeginPath(args.vg);
nvgMoveTo(args.vg, VEC_ARGS(outputPos));
nvgQuadTo(args.vg, VEC_ARGS(slump), VEC_ARGS(inputPos));
// nvgStrokePaint(args.vg, nvgLinearGradient(args.vg, VEC_ARGS(outputPos), VEC_ARGS(inputPos), color::mult(color, 0.5), color));
nvgStrokeColor(args.vg, color::mult(color, 0.8));
nvgStrokeWidth(args.vg, thickness);
nvgStroke(args.vg);

// Draw cable
nvgStrokeColor(args.vg, color::mult(color, 0.95));
nvgStrokeWidth(args.vg, thickness - 1.0);
nvgStroke(args.vg);
}

Widget::drawLayer(args, layer);
}
@@ -368,5 +374,21 @@ engine::Cable* CableWidget::releaseCable() {
}


void CableWidget::onAdd(const AddEvent& e) {
Widget* plugContainer = APP->scene->rack->getPlugContainer();
plugContainer->addChild(outputPlug);
plugContainer->addChild(inputPlug);
Widget::onAdd(e);
}


void CableWidget::onRemove(const RemoveEvent& e) {
Widget* plugContainer = APP->scene->rack->getPlugContainer();
plugContainer->removeChild(outputPlug);
plugContainer->removeChild(inputPlug);
Widget::onRemove(e);
}


} // namespace app
} // namespace rack

+ 29
- 5
src/app/RackWidget.cpp View File

@@ -26,6 +26,7 @@ namespace app {
struct RackWidget::Internal {
RailWidget* rail = NULL;
widget::Widget* moduleContainer = NULL;
widget::Widget* plugContainer = NULL;
widget::Widget* cableContainer = NULL;
CableWidget* incompleteCable = NULL;
int nextCableColorId = 0;
@@ -74,7 +75,8 @@ struct ModuleContainer : widget::Widget {
};


struct CableContainer : widget::TransparentWidget {
/** Children PlugWidgets are owned by CableWidgets. */
struct PlugContainer : widget::TransparentWidget {
void draw(const DrawArgs& args) override {
// Don't draw on layer 0
}
@@ -84,17 +86,28 @@ struct CableContainer : widget::TransparentWidget {
// Draw Plugs
Widget::draw(args);

// Draw cable lights
// Draw plug lights
nvgSave(args.vg);
nvgGlobalTint(args.vg, color::WHITE);
Widget::drawLayer(args, 1);
nvgRestore(args.vg);
}
}
};


struct CableContainer : widget::TransparentWidget {
void draw(const DrawArgs& args) override {
// Don't draw on layer 0
}

void drawLayer(const DrawArgs& args, int layer) override {
if (layer == 3) {
// Draw cable shadows
Widget::drawLayer(args, 2);
Widget::drawLayer(args, -1);

// Draw cables
Widget::drawLayer(args, 3);
Widget::draw(args);
}
}
};
@@ -109,6 +122,9 @@ RackWidget::RackWidget() {
internal->moduleContainer = new ModuleContainer;
addChild(internal->moduleContainer);

internal->plugContainer = new PlugContainer;
addChild(internal->plugContainer);

internal->cableContainer = new CableContainer;
addChild(internal->cableContainer);
}
@@ -149,9 +165,12 @@ void RackWidget::draw(const DrawArgs& args) {
// Tint all draws after this point
nvgGlobalTint(args.vg, nvgRGBAf(b, b, b, 1));

// Draw cables
// Draw plugs
Widget::drawLayer(args, 2);

// Draw cables
Widget::drawLayer(args, 3);

// Draw selection rectangle
if (internal->selecting) {
nvgBeginPath(args.vg);
@@ -221,6 +240,10 @@ widget::Widget* RackWidget::getModuleContainer() {
return internal->moduleContainer;
}

widget::Widget* RackWidget::getPlugContainer() {
return internal->plugContainer;
}

widget::Widget* RackWidget::getCableContainer() {
return internal->cableContainer;
}
@@ -1372,6 +1395,7 @@ void RackWidget::appendSelectionContextMenu(ui::Menu* menu) {

void RackWidget::clearCables() {
internal->incompleteCable = NULL;
// Since cables manage plugs, all plugs are removed from plugContainer
internal->cableContainer->clearChildren();
}



Loading…
Cancel
Save