diff --git a/include/app.hpp b/include/app.hpp index 4e875105..4b72a8d7 100644 --- a/include/app.hpp +++ b/include/app.hpp @@ -70,10 +70,12 @@ struct WireWidget : OpaqueWidget { WireWidget(); ~WireWidget(); + /** Synchronizes the plugged state of the widget to the owned wire */ void updateWire(); + Vec getOutputPos(); + Vec getInputPos(); void draw(NVGcontext *vg); - void drawOutputPlug(NVGcontext *vg); - void drawInputPlug(NVGcontext *vg); + void drawPlugs(NVGcontext *vg); }; struct RackWidget : OpaqueWidget { @@ -82,7 +84,6 @@ struct RackWidget : OpaqueWidget { // Only put WireWidgets in here Widget *wireContainer; WireWidget *activeWire = NULL; - std::shared_ptr railsImage; RackWidget(); ~RackWidget(); diff --git a/res/rails.png b/res/rails.png deleted file mode 100644 index 4cc97f71..00000000 Binary files a/res/rails.png and /dev/null differ diff --git a/src/app/ModuleWidget.cpp b/src/app/ModuleWidget.cpp index 08af4a9d..dfd64bd9 100644 --- a/src/app/ModuleWidget.cpp +++ b/src/app/ModuleWidget.cpp @@ -124,7 +124,6 @@ void ModuleWidget::draw(NVGcontext *vg) { nvgScissor(vg, 0, 0, box.size.x, box.size.y); Widget::draw(vg); - bndBevel(vg, 0.0, 0.0, box.size.x, box.size.y); // CPU usage text if (dynamic_cast(gScene)->toolbar->cpuUsageButton->value > 0.0) { diff --git a/src/app/Panel.cpp b/src/app/Panel.cpp index 665cda9c..72a2498c 100644 --- a/src/app/Panel.cpp +++ b/src/app/Panel.cpp @@ -20,9 +20,11 @@ void Panel::draw(NVGcontext *vg) { nvgFill(vg); } - // Border color + // Border + nvgBeginPath(vg); + nvgRect(vg, 0.5, 0.5, box.size.x - 1, box.size.y - 1); nvgStrokeColor(vg, borderColor); - nvgStrokeWidth(vg, 0.5); + nvgStrokeWidth(vg, 1.0); nvgStroke(vg); } diff --git a/src/app/RackWidget.cpp b/src/app/RackWidget.cpp index db3eac18..a7a89b42 100644 --- a/src/app/RackWidget.cpp +++ b/src/app/RackWidget.cpp @@ -8,14 +8,28 @@ namespace rack { +static Vec rackGridSize = Vec(15, 380); + + +struct WireContainer : TransparentWidget { + void draw(NVGcontext *vg) { + // Wire plugs + for (Widget *child : children) { + WireWidget *wire = dynamic_cast(child); + assert(wire); + wire->drawPlugs(vg); + } + + Widget::draw(vg); + } +}; + RackWidget::RackWidget() { moduleContainer = new Widget(); addChild(moduleContainer); - wireContainer = new TransparentWidget(); + wireContainer = new WireContainer(); addChild(wireContainer); - - railsImage = Image::load("res/rails.png"); } RackWidget::~RackWidget() { @@ -227,12 +241,12 @@ void RackWidget::fromJson(json_t *rootJ) { void RackWidget::repositionModule(ModuleWidget *module) { // Create possible positions - int x0 = roundf(module->requestedPos.x / 15); - int y0 = roundf(module->requestedPos.y / 380); + int x0 = roundf(module->requestedPos.x / rackGridSize.x); + int y0 = roundf(module->requestedPos.y / rackGridSize.y); std::vector positions; for (int y = maxi(0, y0 - 2); y < y0 + 2; y++) { for (int x = maxi(0, x0 - 40); x < x0 + 40; x++) { - positions.push_back(Vec(x*15, y*380)); + positions.push_back(Vec(x * rackGridSize.x, y * rackGridSize.y)); } } @@ -279,7 +293,6 @@ void RackWidget::step() { } // Autosave every 15 seconds - // (This is alpha software, expect crashes!) if (gGuiFrame % (60*15) == 0) { savePatch("autosave.json"); } @@ -295,13 +308,41 @@ void RackWidget::draw(NVGcontext *vg) { nvgFillColor(vg, nvgRGBf(0.2, 0.2, 0.2)); nvgFill(vg); - // Rails image - { - int imageWidth, imageHeight; - nvgImageSize(vg, railsImage->handle, &imageWidth, &imageHeight); - NVGpaint paint = nvgImagePattern(vg, 0.0, 0.0, imageWidth, imageHeight, 0.0, railsImage->handle, 1.0); - nvgFillPaint(vg, paint); + // Rails + // TODO Put this in a framebuffer cache and tile + const float railHeight = 15; + nvgFillColor(vg, nvgRGBf(0.8, 0.8, 0.8)); + nvgStrokeWidth(vg, 1.0); + nvgStrokeColor(vg, nvgRGBf(0.6, 0.6, 0.6)); + float holeRadius = 3.5; + for (float railY = 0; railY < box.size.y; railY += rackGridSize.y) { + // Top rail + nvgBeginPath(vg); + nvgRect(vg, 0, railY, box.size.x, railHeight); + for (float railX = 0; railX < box.size.x; railX += rackGridSize.x) { + nvgCircle(vg, railX + rackGridSize.x / 2, railY + railHeight / 2, holeRadius); + nvgPathWinding(vg, NVG_HOLE); + } + nvgFill(vg); + + nvgBeginPath(vg); + nvgMoveTo(vg, 0, railY + railHeight - 0.5); + nvgLineTo(vg, box.size.x, railY + railHeight - 0.5); + nvgStroke(vg); + + // Bottom rail + nvgBeginPath(vg); + nvgRect(vg, 0, railY + rackGridSize.y - railHeight, box.size.x, railHeight); + for (float railX = 0; railX < box.size.x; railX += rackGridSize.x) { + nvgCircle(vg, railX + rackGridSize.x / 2, railY + rackGridSize.y - railHeight + railHeight / 2, holeRadius); + nvgPathWinding(vg, NVG_HOLE); + } nvgFill(vg); + + nvgBeginPath(vg); + nvgMoveTo(vg, 0, railY + rackGridSize.y - 0.5); + nvgLineTo(vg, box.size.x, railY + rackGridSize.y - 0.5); + nvgStroke(vg); } Widget::draw(vg); diff --git a/src/app/WireWidget.cpp b/src/app/WireWidget.cpp index 4eff3deb..20a23657 100644 --- a/src/app/WireWidget.cpp +++ b/src/app/WireWidget.cpp @@ -118,46 +118,49 @@ void WireWidget::updateWire() { } } -void WireWidget::draw(NVGcontext *vg) { - Vec absolutePos = getAbsolutePos().minus(box.pos); - float opacity = dynamic_cast(gScene)->toolbar->wireOpacitySlider->value / 100.0; - float tension = dynamic_cast(gScene)->toolbar->wireTensionSlider->value; - - // Display the actively dragged wire as opaque - if (gRackWidget->activeWire == this) - opacity = 1.0; - - // Compute location of outputPos and inputPos - Vec outputPos; +Vec WireWidget::getOutputPos() { + Vec pos; if (outputPort) { - outputPos = Rect(outputPort->getAbsolutePos(), outputPort->box.size).getCenter(); + pos = Rect(outputPort->getAbsolutePos(), outputPort->box.size).getCenter(); } else if (hoveredOutputPort) { - outputPos = Rect(hoveredOutputPort->getAbsolutePos(), hoveredOutputPort->box.size).getCenter(); + pos = Rect(hoveredOutputPort->getAbsolutePos(), hoveredOutputPort->box.size).getCenter(); } else { - outputPos = gMousePos; + pos = gMousePos; } + return pos.minus(getAbsolutePos().minus(box.pos)); +} - Vec inputPos; +Vec WireWidget::getInputPos() { + Vec pos; if (inputPort) { - inputPos = Rect(inputPort->getAbsolutePos(), inputPort->box.size).getCenter(); + pos = Rect(inputPort->getAbsolutePos(), inputPort->box.size).getCenter(); } else if (hoveredInputPort) { - inputPos = Rect(hoveredInputPort->getAbsolutePos(), hoveredInputPort->box.size).getCenter(); + pos = Rect(hoveredInputPort->getAbsolutePos(), hoveredInputPort->box.size).getCenter(); } else { - inputPos = gMousePos; + pos = gMousePos; } + return pos.minus(getAbsolutePos().minus(box.pos)); +} - outputPos = outputPos.minus(absolutePos); - inputPos = inputPos.minus(absolutePos); +void WireWidget::draw(NVGcontext *vg) { + float opacity = dynamic_cast(gScene)->toolbar->wireOpacitySlider->value / 100.0; + float tension = dynamic_cast(gScene)->toolbar->wireTensionSlider->value; - drawWire(vg, outputPos, inputPos, color, tension, opacity); - drawPlug(vg, outputPos, color); - drawPlug(vg, inputPos, color); + // Display the actively dragged wire as opaque + if (gRackWidget->activeWire == this) + opacity = 1.0; + + drawWire(vg, getOutputPos(), getInputPos(), color, tension, opacity); + drawPlug(vg, getOutputPos(), color); + drawPlug(vg, getInputPos(), color); } +void WireWidget::drawPlugs(NVGcontext *vg) { +} } // namespace rack