diff --git a/include/app/RackRail.hpp b/include/app/RackRail.hpp index 6ff2863d..4e7e2a2d 100644 --- a/include/app/RackRail.hpp +++ b/include/app/RackRail.hpp @@ -8,6 +8,9 @@ namespace app { struct RackRail : widget::TransparentWidget { + std::shared_ptr busBoardSvg; + + RackRail(); void draw(const DrawArgs &args) override; }; diff --git a/include/app/common.hpp b/include/app/common.hpp index 0dbd70a9..433271f0 100644 --- a/include/app/common.hpp +++ b/include/app/common.hpp @@ -44,6 +44,7 @@ static const float RACK_GRID_WIDTH = 15; static const float RACK_GRID_HEIGHT = 380; static const math::Vec RACK_GRID_SIZE = math::Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT); static const math::Vec RACK_OFFSET = RACK_GRID_SIZE.mult(math::Vec(2000, 100)); +static const math::Vec BUS_BOARD_GRID_SIZE = math::Vec(RACK_GRID_WIDTH * 20, RACK_GRID_HEIGHT); } // namespace app diff --git a/res/ComponentLibrary/RackBusboard.svg b/res/ComponentLibrary/RackBusboard.svg new file mode 100644 index 00000000..fba58a81 --- /dev/null +++ b/res/ComponentLibrary/RackBusboard.svg @@ -0,0 +1,865 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/app/RackRail.cpp b/src/app/RackRail.cpp index e2dd0602..617ec364 100644 --- a/src/app/RackRail.cpp +++ b/src/app/RackRail.cpp @@ -1,9 +1,18 @@ #include "app/RackRail.hpp" +#include "app.hpp" +#include "asset.hpp" +#include "svg.hpp" namespace rack { namespace app { + +RackRail::RackRail() { + busBoardSvg = APP->window->loadSvg(asset::system("res/ComponentLibrary/RackBusboard.svg")); +} + + void RackRail::draw(const DrawArgs &args) { const float railHeight = 15; @@ -14,38 +23,59 @@ void RackRail::draw(const DrawArgs &args) { nvgFill(args.vg); // Rails - nvgFillColor(args.vg, nvgRGB(0xc9, 0xc9, 0xc9)); - nvgStrokeWidth(args.vg, 1.0); - nvgStrokeColor(args.vg, nvgRGB(0x9d, 0x9f, 0xa2)); float holeRadius = 4.0; - for (float railY = 0; railY < box.size.y; railY += RACK_GRID_HEIGHT) { + for (float y = 0; y < box.size.y; y += RACK_GRID_HEIGHT) { + nvgFillColor(args.vg, nvgRGB(0xc9, 0xc9, 0xc9)); + nvgStrokeWidth(args.vg, 1.0); + nvgStrokeColor(args.vg, nvgRGB(0x9d, 0x9f, 0xa2)); // Top rail nvgBeginPath(args.vg); - nvgRect(args.vg, 0, railY, box.size.x, railHeight); - for (float railX = 0; railX < box.size.x; railX += RACK_GRID_WIDTH) { - nvgCircle(args.vg, railX + RACK_GRID_WIDTH / 2, railY + railHeight / 2, holeRadius); + nvgRect(args.vg, 0, y, box.size.x, railHeight); + for (float x = 0; x < box.size.x; x += RACK_GRID_WIDTH) { + nvgCircle(args.vg, x + RACK_GRID_WIDTH / 2, y + railHeight / 2, holeRadius); nvgPathWinding(args.vg, NVG_HOLE); } nvgFill(args.vg); nvgBeginPath(args.vg); - nvgMoveTo(args.vg, 0, railY + railHeight - 0.5); - nvgLineTo(args.vg, box.size.x, railY + railHeight - 0.5); + nvgMoveTo(args.vg, 0, y + railHeight - 0.5); + nvgLineTo(args.vg, box.size.x, y + railHeight - 0.5); nvgStroke(args.vg); // Bottom rail nvgBeginPath(args.vg); - nvgRect(args.vg, 0, railY + RACK_GRID_HEIGHT - railHeight, box.size.x, railHeight); - for (float railX = 0; railX < box.size.x; railX += RACK_GRID_WIDTH) { - nvgCircle(args.vg, railX + RACK_GRID_WIDTH / 2, railY + RACK_GRID_HEIGHT - railHeight + railHeight / 2, holeRadius); + nvgRect(args.vg, 0, y + RACK_GRID_HEIGHT - railHeight, box.size.x, railHeight); + for (float x = 0; x < box.size.x; x += RACK_GRID_WIDTH) { + nvgCircle(args.vg, x + RACK_GRID_WIDTH / 2, y + RACK_GRID_HEIGHT - railHeight + railHeight / 2, holeRadius); nvgPathWinding(args.vg, NVG_HOLE); } nvgFill(args.vg); nvgBeginPath(args.vg); - nvgMoveTo(args.vg, 0, railY + RACK_GRID_HEIGHT - 0.5); - nvgLineTo(args.vg, box.size.x, railY + RACK_GRID_HEIGHT - 0.5); + nvgMoveTo(args.vg, 0, y + RACK_GRID_HEIGHT - 0.5); + nvgLineTo(args.vg, box.size.x, y + RACK_GRID_HEIGHT - 0.5); nvgStroke(args.vg); + + // Bus board + const float busBoardWidth = RACK_GRID_WIDTH * 20; + const float busBoardHeight = mm2px(38.27639); + const float busBoardY = y + (RACK_GRID_HEIGHT - busBoardHeight) / 2; + for (float x = 0; x < box.size.x; x += busBoardWidth) { + nvgSave(args.vg); + nvgTranslate(args.vg, x, busBoardY); + svgDraw(args.vg, busBoardSvg->handle); + nvgRestore(args.vg); + } + + // Bus board shadow + nvgBeginPath(args.vg); + const float shadowY = busBoardY + busBoardHeight; + const float shadowHeight = 10; + nvgRect(args.vg, 0, shadowY, box.size.x, shadowHeight); + NVGcolor shadowColor = nvgRGBA(0, 0, 0, 0x20); + NVGcolor transparentColor = nvgRGBAf(0, 0, 0, 0); + nvgFillPaint(args.vg, nvgLinearGradient(args.vg, 0, shadowY, 0, shadowY + shadowHeight, shadowColor, transparentColor)); + nvgFill(args.vg); } } diff --git a/src/app/RackWidget.cpp b/src/app/RackWidget.cpp index e0eceadc..7ef33760 100644 --- a/src/app/RackWidget.cpp +++ b/src/app/RackWidget.cpp @@ -103,8 +103,8 @@ void RackWidget::step() { void RackWidget::draw(const DrawArgs &args) { // Resize and reposition the RackRail to align on the grid. math::Rect railBox; - railBox.pos = args.clipBox.pos.div(RACK_GRID_SIZE).floor().mult(RACK_GRID_SIZE); - railBox.size = args.clipBox.size.div(RACK_GRID_SIZE).floor().plus(math::Vec(25, 2)).mult(RACK_GRID_SIZE); + railBox.pos = args.clipBox.pos.div(BUS_BOARD_GRID_SIZE).floor().mult(BUS_BOARD_GRID_SIZE); + railBox.size = args.clipBox.size.div(BUS_BOARD_GRID_SIZE).floor().plus(math::Vec(5, 2)).mult(BUS_BOARD_GRID_SIZE); railFb->box = railBox; RackRail *rail = railFb->getFirstDescendantOfType();