@@ -70,10 +70,12 @@ struct WireWidget : OpaqueWidget { | |||||
WireWidget(); | WireWidget(); | ||||
~WireWidget(); | ~WireWidget(); | ||||
/** Synchronizes the plugged state of the widget to the owned wire */ | |||||
void updateWire(); | void updateWire(); | ||||
Vec getOutputPos(); | |||||
Vec getInputPos(); | |||||
void draw(NVGcontext *vg); | void draw(NVGcontext *vg); | ||||
void drawOutputPlug(NVGcontext *vg); | |||||
void drawInputPlug(NVGcontext *vg); | |||||
void drawPlugs(NVGcontext *vg); | |||||
}; | }; | ||||
struct RackWidget : OpaqueWidget { | struct RackWidget : OpaqueWidget { | ||||
@@ -82,7 +84,6 @@ struct RackWidget : OpaqueWidget { | |||||
// Only put WireWidgets in here | // Only put WireWidgets in here | ||||
Widget *wireContainer; | Widget *wireContainer; | ||||
WireWidget *activeWire = NULL; | WireWidget *activeWire = NULL; | ||||
std::shared_ptr<Image> railsImage; | |||||
RackWidget(); | RackWidget(); | ||||
~RackWidget(); | ~RackWidget(); | ||||
@@ -124,7 +124,6 @@ void ModuleWidget::draw(NVGcontext *vg) { | |||||
nvgScissor(vg, 0, 0, box.size.x, box.size.y); | nvgScissor(vg, 0, 0, box.size.x, box.size.y); | ||||
Widget::draw(vg); | Widget::draw(vg); | ||||
bndBevel(vg, 0.0, 0.0, box.size.x, box.size.y); | |||||
// CPU usage text | // CPU usage text | ||||
if (dynamic_cast<RackScene*>(gScene)->toolbar->cpuUsageButton->value > 0.0) { | if (dynamic_cast<RackScene*>(gScene)->toolbar->cpuUsageButton->value > 0.0) { | ||||
@@ -20,9 +20,11 @@ void Panel::draw(NVGcontext *vg) { | |||||
nvgFill(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); | nvgStrokeColor(vg, borderColor); | ||||
nvgStrokeWidth(vg, 0.5); | |||||
nvgStrokeWidth(vg, 1.0); | |||||
nvgStroke(vg); | nvgStroke(vg); | ||||
} | } | ||||
@@ -8,14 +8,28 @@ | |||||
namespace rack { | 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<WireWidget*>(child); | |||||
assert(wire); | |||||
wire->drawPlugs(vg); | |||||
} | |||||
Widget::draw(vg); | |||||
} | |||||
}; | |||||
RackWidget::RackWidget() { | RackWidget::RackWidget() { | ||||
moduleContainer = new Widget(); | moduleContainer = new Widget(); | ||||
addChild(moduleContainer); | addChild(moduleContainer); | ||||
wireContainer = new TransparentWidget(); | |||||
wireContainer = new WireContainer(); | |||||
addChild(wireContainer); | addChild(wireContainer); | ||||
railsImage = Image::load("res/rails.png"); | |||||
} | } | ||||
RackWidget::~RackWidget() { | RackWidget::~RackWidget() { | ||||
@@ -227,12 +241,12 @@ void RackWidget::fromJson(json_t *rootJ) { | |||||
void RackWidget::repositionModule(ModuleWidget *module) { | void RackWidget::repositionModule(ModuleWidget *module) { | ||||
// Create possible positions | // 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<Vec> positions; | std::vector<Vec> positions; | ||||
for (int y = maxi(0, y0 - 2); y < y0 + 2; y++) { | for (int y = maxi(0, y0 - 2); y < y0 + 2; y++) { | ||||
for (int x = maxi(0, x0 - 40); x < x0 + 40; x++) { | 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 | // Autosave every 15 seconds | ||||
// (This is alpha software, expect crashes!) | |||||
if (gGuiFrame % (60*15) == 0) { | if (gGuiFrame % (60*15) == 0) { | ||||
savePatch("autosave.json"); | savePatch("autosave.json"); | ||||
} | } | ||||
@@ -295,13 +308,41 @@ void RackWidget::draw(NVGcontext *vg) { | |||||
nvgFillColor(vg, nvgRGBf(0.2, 0.2, 0.2)); | nvgFillColor(vg, nvgRGBf(0.2, 0.2, 0.2)); | ||||
nvgFill(vg); | 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); | 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); | Widget::draw(vg); | ||||
@@ -118,46 +118,49 @@ void WireWidget::updateWire() { | |||||
} | } | ||||
} | } | ||||
void WireWidget::draw(NVGcontext *vg) { | |||||
Vec absolutePos = getAbsolutePos().minus(box.pos); | |||||
float opacity = dynamic_cast<RackScene*>(gScene)->toolbar->wireOpacitySlider->value / 100.0; | |||||
float tension = dynamic_cast<RackScene*>(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) { | if (outputPort) { | ||||
outputPos = Rect(outputPort->getAbsolutePos(), outputPort->box.size).getCenter(); | |||||
pos = Rect(outputPort->getAbsolutePos(), outputPort->box.size).getCenter(); | |||||
} | } | ||||
else if (hoveredOutputPort) { | else if (hoveredOutputPort) { | ||||
outputPos = Rect(hoveredOutputPort->getAbsolutePos(), hoveredOutputPort->box.size).getCenter(); | |||||
pos = Rect(hoveredOutputPort->getAbsolutePos(), hoveredOutputPort->box.size).getCenter(); | |||||
} | } | ||||
else { | else { | ||||
outputPos = gMousePos; | |||||
pos = gMousePos; | |||||
} | } | ||||
return pos.minus(getAbsolutePos().minus(box.pos)); | |||||
} | |||||
Vec inputPos; | |||||
Vec WireWidget::getInputPos() { | |||||
Vec pos; | |||||
if (inputPort) { | if (inputPort) { | ||||
inputPos = Rect(inputPort->getAbsolutePos(), inputPort->box.size).getCenter(); | |||||
pos = Rect(inputPort->getAbsolutePos(), inputPort->box.size).getCenter(); | |||||
} | } | ||||
else if (hoveredInputPort) { | else if (hoveredInputPort) { | ||||
inputPos = Rect(hoveredInputPort->getAbsolutePos(), hoveredInputPort->box.size).getCenter(); | |||||
pos = Rect(hoveredInputPort->getAbsolutePos(), hoveredInputPort->box.size).getCenter(); | |||||
} | } | ||||
else { | 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<RackScene*>(gScene)->toolbar->wireOpacitySlider->value / 100.0; | |||||
float tension = dynamic_cast<RackScene*>(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 | } // namespace rack |