diff --git a/include/app/CableWidget.hpp b/include/app/CableWidget.hpp index e688af0d..dcaa8303 100644 --- a/include/app/CableWidget.hpp +++ b/include/app/CableWidget.hpp @@ -46,6 +46,7 @@ struct CableWidget : widget::Widget { void fromJson(json_t* rootJ); void step() override; void draw(const DrawArgs& args) override; + void drawLayer(const DrawArgs& args, int layer) override; engine::Cable* releaseCable(); }; diff --git a/include/widget/Widget.hpp b/include/widget/Widget.hpp index f72d0695..36d14198 100644 --- a/include/widget/Widget.hpp +++ b/include/widget/Widget.hpp @@ -126,8 +126,6 @@ struct Widget : WeakBase { /** Local box representing the visible viewport. */ math::Rect clipBox; NVGLUframebuffer* fb = NULL; - /** Custom widgets may draw children multiple times, passing a different layer number each time. */ - int layer = 0; }; /** Draws the widget to the NanoVG context */ @@ -135,8 +133,16 @@ struct Widget : WeakBase { /** Override draw(const DrawArgs &args) instead */ DEPRECATED virtual void draw(NVGcontext* vg) {} + /** Draw additional layers. + + Custom widgets may draw its children multiple times on different layers, passing an arbitrary layer number each time. + Layer 0 calls children's draw(). + When overriding, always wrap draw commands in `if (layer == ...) {}` to avoid drawing on all layers. + */ + virtual void drawLayer(const DrawArgs& args, int layer); + /** Draws a particular child. */ - void drawChild(Widget* child, const DrawArgs& args); + void drawChild(Widget* child, const DrawArgs& args, int layer = 0); // Events diff --git a/src/app/CableWidget.cpp b/src/app/CableWidget.cpp index c6fba0c2..a0913d86 100644 --- a/src/app/CableWidget.cpp +++ b/src/app/CableWidget.cpp @@ -131,11 +131,13 @@ CableWidget::CableWidget() { addChild(outputPlug); } + CableWidget::~CableWidget() { setCable(NULL); delete internal; } + void CableWidget::setNextCableColor() { if (!settings::cableColors.empty()) { int id = APP->scene->rack->nextCableColorId++; @@ -144,10 +146,12 @@ void CableWidget::setNextCableColor() { } } + bool CableWidget::isComplete() { return outputPort && inputPort; } + void CableWidget::updateCable() { if (cable) { APP->engine->removeCable(cable); @@ -164,6 +168,7 @@ void CableWidget::updateCable() { } } + void CableWidget::setCable(engine::Cable* cable) { if (this->cable) { APP->engine->removeCable(this->cable); @@ -188,10 +193,12 @@ void CableWidget::setCable(engine::Cable* cable) { } } + engine::Cable* CableWidget::getCable() { return cable; } + math::Vec CableWidget::getInputPos() { if (inputPort) { return inputPort->getRelativeOffset(inputPort->box.zeroPos().getCenter(), APP->scene->rack); @@ -204,6 +211,7 @@ math::Vec CableWidget::getInputPos() { } } + math::Vec CableWidget::getOutputPos() { if (outputPort) { return outputPort->getRelativeOffset(outputPort->box.zeroPos().getCenter(), APP->scene->rack); @@ -216,11 +224,13 @@ math::Vec CableWidget::getOutputPos() { } } + void CableWidget::mergeJson(json_t* rootJ) { std::string s = color::toHexString(color); json_object_set_new(rootJ, "color", json_string(s.c_str())); } + void CableWidget::fromJson(json_t* rootJ) { json_t* colorJ = json_object_get(rootJ, "color"); if (colorJ) { @@ -230,6 +240,7 @@ void CableWidget::fromJson(json_t* rootJ) { } } + static math::Vec getSlumpPos(math::Vec pos1, math::Vec pos2) { float dist = pos1.minus(pos2).norm(); math::Vec avg = pos1.plus(pos2).div(2); @@ -238,6 +249,7 @@ static math::Vec getSlumpPos(math::Vec pos1, math::Vec pos2) { return avg; } + void CableWidget::step() { math::Vec outputPos = getOutputPos(); math::Vec inputPos = getInputPos(); @@ -262,13 +274,13 @@ void CableWidget::step() { Widget::step(); } + void CableWidget::draw(const DrawArgs& args) { - if (args.layer == 0) { - // Draw PlugWidgets - Widget::draw(args); - return; - } + Widget::draw(args); +} + +void CableWidget::drawLayer(const DrawArgs& args, int layer) { float opacity = settings::cableOpacity; bool thick = false; @@ -312,7 +324,7 @@ void CableWidget::draw(const DrawArgs& args) { // Avoids glitches when cable is bent nvgLineJoin(args.vg, NVG_ROUND); - if (args.layer == 1) { + if (layer == 1) { // Draw cable shadow math::Vec shadowSlump = slump.plus(math::Vec(0, 30)); nvgBeginPath(args.vg); @@ -323,7 +335,7 @@ void CableWidget::draw(const DrawArgs& args) { nvgStrokeWidth(args.vg, thickness - 1.0); nvgStroke(args.vg); } - else if (args.layer == 2) { + else if (layer == 2) { // Draw cable outline nvgBeginPath(args.vg); nvgMoveTo(args.vg, VEC_ARGS(outputPos)); @@ -340,6 +352,7 @@ void CableWidget::draw(const DrawArgs& args) { } } + engine::Cable* CableWidget::releaseCable() { engine::Cable* cable = this->cable; this->cable = NULL; diff --git a/src/app/RackWidget.cpp b/src/app/RackWidget.cpp index 2f8e6700..626a7860 100644 --- a/src/app/RackWidget.cpp +++ b/src/app/RackWidget.cpp @@ -62,14 +62,10 @@ struct CableContainer : widget::TransparentWidget { Widget::draw(args); // Draw cable shadows - DrawArgs args1 = args; - args1.layer = 1; - Widget::draw(args1); + Widget::drawLayer(args, 1); // Draw cables - DrawArgs args2 = args; - args2.layer = 2; - Widget::draw(args2); + Widget::drawLayer(args, 2); } }; diff --git a/src/widget/Widget.cpp b/src/widget/Widget.cpp index 7e187ad2..84b74705 100644 --- a/src/widget/Widget.cpp +++ b/src/widget/Widget.cpp @@ -273,7 +273,22 @@ void Widget::draw(const DrawArgs& args) { } -void Widget::drawChild(Widget* child, const DrawArgs& args) { +void Widget::drawLayer(const DrawArgs& args, int layer) { + // Iterate children + for (Widget* child : children) { + // Don't draw if invisible + if (!child->isVisible()) + continue; + // Don't draw if child is outside clip box + if (!args.clipBox.intersects(child->box)) + continue; + + drawChild(child, args, layer); + } +} + + +void Widget::drawChild(Widget* child, const DrawArgs& args, int layer) { DrawArgs childArgs = args; // Intersect child clip box with self childArgs.clipBox = childArgs.clipBox.intersect(child->box); @@ -283,13 +298,17 @@ void Widget::drawChild(Widget* child, const DrawArgs& args) { nvgSave(args.vg); nvgTranslate(args.vg, child->box.pos.x, child->box.pos.y); - child->draw(childArgs); - + if (layer == 0) { + child->draw(childArgs); #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" - // Call deprecated draw function, which does nothing by default - child->draw(args.vg); + // Call deprecated draw function, which does nothing by default + child->draw(args.vg); #pragma GCC diagnostic pop + } + else { + child->drawLayer(childArgs, layer); + } nvgRestore(args.vg); }