diff --git a/include/app/LedDisplay.hpp b/include/app/LedDisplay.hpp index f8ec971e..2b850752 100644 --- a/include/app/LedDisplay.hpp +++ b/include/app/LedDisplay.hpp @@ -26,6 +26,7 @@ struct LedDisplayChoice : widget::OpaqueWidget { NVGcolor bgColor; LedDisplayChoice(); void draw(const DrawArgs& args) override; + void drawLayer(const DrawArgs& args, int layer) override; void onButton(const ButtonEvent& e) override; }; @@ -36,6 +37,7 @@ struct LedDisplayTextField : ui::TextField { NVGcolor bgColor; LedDisplayTextField(); void draw(const DrawArgs& args) override; + void drawLayer(const DrawArgs& args, int layer) override; int getTextPosition(math::Vec mousePos) override; }; diff --git a/src/app/CableWidget.cpp b/src/app/CableWidget.cpp index 8de89140..d629ac08 100644 --- a/src/app/CableWidget.cpp +++ b/src/app/CableWidget.cpp @@ -276,79 +276,83 @@ void CableWidget::step() { void CableWidget::draw(const DrawArgs& args) { + // Draw plugs Widget::draw(args); } void CableWidget::drawLayer(const DrawArgs& args, int layer) { - 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; - } + // 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 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; + } } - // 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; } - } - 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 == 2) { - // 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); + 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); + } + 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); + } } Widget::drawLayer(args, layer); diff --git a/src/app/LedDisplay.cpp b/src/app/LedDisplay.cpp index 734107ae..20efa1e0 100644 --- a/src/app/LedDisplay.cpp +++ b/src/app/LedDisplay.cpp @@ -45,7 +45,6 @@ LedDisplayChoice::LedDisplayChoice() { void LedDisplayChoice::draw(const DrawArgs& args) { - nvgScissor(args.vg, RECT_ARGS(args.clipBox)); if (bgColor.a > 0.0) { nvgBeginPath(args.vg); nvgRect(args.vg, 0, 0, box.size.x, box.size.y); @@ -53,16 +52,26 @@ void LedDisplayChoice::draw(const DrawArgs& args) { nvgFill(args.vg); } - std::shared_ptr font = APP->window->loadFont(fontPath); - nvgGlobalTint(args.vg, color::WHITE); - if (font && font->handle >= 0) { - nvgFillColor(args.vg, color); - nvgFontFaceId(args.vg, font->handle); - nvgTextLetterSpacing(args.vg, 0.0); - - nvgFontSize(args.vg, 12); - nvgText(args.vg, textOffset.x, textOffset.y, text.c_str(), NULL); + Widget::draw(args); +} + + +void LedDisplayChoice::drawLayer(const DrawArgs& args, int layer) { + nvgScissor(args.vg, RECT_ARGS(args.clipBox)); + + if (layer == 1) { + std::shared_ptr font = APP->window->loadFont(fontPath); + if (font && font->handle >= 0) { + nvgFillColor(args.vg, color); + nvgFontFaceId(args.vg, font->handle); + nvgTextLetterSpacing(args.vg, 0.0); + + nvgFontSize(args.vg, 12); + nvgText(args.vg, textOffset.x, textOffset.y, text.c_str(), NULL); + } } + + Widget::drawLayer(args, layer); nvgResetScissor(args.vg); } @@ -87,8 +96,6 @@ LedDisplayTextField::LedDisplayTextField() { void LedDisplayTextField::draw(const DrawArgs& args) { - nvgScissor(args.vg, RECT_ARGS(args.clipBox)); - // Background if (bgColor.a > 0.0) { nvgBeginPath(args.vg); @@ -97,24 +104,33 @@ void LedDisplayTextField::draw(const DrawArgs& args) { nvgFill(args.vg); } - // Text - std::shared_ptr font = APP->window->loadFont(fontPath); - nvgGlobalTint(args.vg, color::WHITE); - if (font && font->handle >= 0) { - bndSetFont(font->handle); - - NVGcolor highlightColor = color; - highlightColor.a = 0.5; - int begin = std::min(cursor, selection); - int end = (this == APP->event->selectedWidget) ? std::max(cursor, selection) : -1; - bndIconLabelCaret(args.vg, - textOffset.x, textOffset.y, - box.size.x - 2 * textOffset.x, box.size.y - 2 * textOffset.y, - -1, color, 12, text.c_str(), highlightColor, begin, end); - - bndSetFont(APP->window->uiFont->handle); + Widget::draw(args); +} + + +void LedDisplayTextField::drawLayer(const DrawArgs& args, int layer) { + nvgScissor(args.vg, RECT_ARGS(args.clipBox)); + + if (layer == 1) { + // Text + std::shared_ptr font = APP->window->loadFont(fontPath); + if (font && font->handle >= 0) { + bndSetFont(font->handle); + + NVGcolor highlightColor = color; + highlightColor.a = 0.5; + int begin = std::min(cursor, selection); + int end = (this == APP->event->selectedWidget) ? std::max(cursor, selection) : -1; + bndIconLabelCaret(args.vg, + textOffset.x, textOffset.y, + box.size.x - 2 * textOffset.x, box.size.y - 2 * textOffset.y, + -1, color, 12, text.c_str(), highlightColor, begin, end); + + bndSetFont(APP->window->uiFont->handle); + } } + Widget::drawLayer(args, layer); nvgResetScissor(args.vg); } diff --git a/src/app/RackWidget.cpp b/src/app/RackWidget.cpp index 26915cc0..02083992 100644 --- a/src/app/RackWidget.cpp +++ b/src/app/RackWidget.cpp @@ -44,24 +44,39 @@ struct ModuleContainer : widget::Widget { Widget::drawLayer(args, -1); Widget::draw(args); + } - // Draw lights and light halos - nvgGlobalTint(args.vg, color::WHITE); - Widget::drawLayer(args, 1); + void drawLayer(const DrawArgs& args, int layer) override { + // Draw lights after translucent rectangle + if (layer == 1) { + Widget::drawLayer(args, 1); + } } }; struct CableContainer : widget::TransparentWidget { void draw(const DrawArgs& args) override { - // Draw Plugs - Widget::draw(args); + // Don't draw on layer 0 + } - // Draw cable shadows - Widget::drawLayer(args, 1); + void drawLayer(const DrawArgs& args, int layer) override { + if (layer == 2) { + // Draw Plugs + Widget::draw(args); - // Draw cables - Widget::drawLayer(args, 2); + // Draw cable lights + nvgSave(args.vg); + nvgGlobalTint(args.vg, color::WHITE); + Widget::drawLayer(args, 1); + nvgRestore(args.vg); + + // Draw cable shadows + Widget::drawLayer(args, 2); + + // Draw cables + Widget::drawLayer(args, 3); + } } }; @@ -103,12 +118,28 @@ void RackWidget::step() { } void RackWidget::draw(const DrawArgs& args) { - // Darken all children by user setting float b = settings::rackBrightness; - nvgGlobalTint(args.vg, nvgRGBAf(b, b, b, 1)); + // Draw rack rails and modules Widget::draw(args); + // Draw translucent dark rectangle + if (b < 1.f) { + nvgBeginPath(args.vg); + nvgRect(args.vg, 0.0, 0.0, VEC_ARGS(box.size)); + nvgFillColor(args.vg, nvgRGBAf(0, 0, 0, 1.f - b)); + nvgFill(args.vg); + } + + // Draw lights and halos + Widget::drawLayer(args, 1); + + // Tint all draws after this point + nvgGlobalTint(args.vg, nvgRGBAf(b, b, b, 1)); + + // Draw cables + Widget::drawLayer(args, 2); + // Draw selection rectangle if (internal->selecting) { nvgBeginPath(args.vg);