@@ -27,8 +27,8 @@ struct CableWidget : OpaqueWidget { | |||
math::Vec getInputPos(); | |||
json_t *toJson(); | |||
void fromJson(json_t *rootJ, const std::map<int, ModuleWidget*> &moduleWidgets); | |||
void draw(NVGcontext *vg) override; | |||
void drawPlugs(NVGcontext *vg); | |||
void draw(const DrawContext &ctx) override; | |||
void drawPlugs(const DrawContext &ctx); | |||
}; | |||
@@ -10,7 +10,7 @@ struct CircularShadow : TransparentWidget { | |||
float blurRadius; | |||
float opacity; | |||
CircularShadow(); | |||
void draw(NVGcontext *vg) override; | |||
void draw(const DrawContext &ctx) override; | |||
}; | |||
@@ -9,12 +9,12 @@ namespace rack { | |||
struct LedDisplay : Widget { | |||
void draw(NVGcontext *vg) override; | |||
void draw(const DrawContext &ctx) override; | |||
}; | |||
struct LedDisplaySeparator : TransparentWidget { | |||
LedDisplaySeparator(); | |||
void draw(NVGcontext *vg) override; | |||
void draw(const DrawContext &ctx) override; | |||
}; | |||
struct LedDisplayChoice : TransparentWidget { | |||
@@ -23,7 +23,7 @@ struct LedDisplayChoice : TransparentWidget { | |||
math::Vec textOffset; | |||
NVGcolor color; | |||
LedDisplayChoice(); | |||
void draw(NVGcontext *vg) override; | |||
void draw(const DrawContext &ctx) override; | |||
void onButton(const event::Button &e) override; | |||
}; | |||
@@ -32,7 +32,7 @@ struct LedDisplayTextField : TextField { | |||
math::Vec textOffset; | |||
NVGcolor color; | |||
LedDisplayTextField(); | |||
void draw(NVGcontext *vg) override; | |||
void draw(const DrawContext &ctx) override; | |||
int getTextPosition(math::Vec mousePos) override; | |||
}; | |||
@@ -10,9 +10,9 @@ struct LightWidget : TransparentWidget { | |||
NVGcolor bgColor = nvgRGBA(0, 0, 0, 0); | |||
NVGcolor color = nvgRGBA(0, 0, 0, 0); | |||
NVGcolor borderColor = nvgRGBA(0, 0, 0, 0); | |||
void draw(NVGcontext *vg) override; | |||
virtual void drawLight(NVGcontext *vg); | |||
virtual void drawHalo(NVGcontext *vg); | |||
void draw(const DrawContext &ctx) override; | |||
virtual void drawLight(const DrawContext &ctx); | |||
virtual void drawHalo(const DrawContext &ctx); | |||
}; | |||
@@ -13,7 +13,7 @@ struct ModuleBrowser : OpaqueWidget { | |||
ModuleBrowser(); | |||
void step() override; | |||
void draw(NVGcontext *vg) override; | |||
void draw(const DrawContext &ctx) override; | |||
void onHoverKey(const event::HoverKey &e) override; | |||
}; | |||
@@ -30,8 +30,8 @@ struct ModuleWidget : OpaqueWidget { | |||
} | |||
~ModuleWidget(); | |||
void draw(NVGcontext *vg) override; | |||
void drawShadow(NVGcontext *vg); | |||
void draw(const DrawContext &ctx) override; | |||
void drawShadow(const DrawContext &ctx); | |||
void onHover(const event::Hover &e) override; | |||
void onButton(const event::Button &e) override; | |||
@@ -16,7 +16,7 @@ struct ParamWidget : OpaqueWidget { | |||
~ParamWidget(); | |||
void step() override; | |||
void draw(NVGcontext *vg) override; | |||
void draw(const DrawContext &ctx) override; | |||
void onButton(const event::Button &e) override; | |||
void onEnter(const event::Enter &e) override; | |||
void onLeave(const event::Leave &e) override; | |||
@@ -23,7 +23,7 @@ struct PortWidget : OpaqueWidget { | |||
~PortWidget(); | |||
void step() override; | |||
void draw(NVGcontext *vg) override; | |||
void draw(const DrawContext &ctx) override; | |||
void onButton(const event::Button &e) override; | |||
void onDragStart(const event::DragStart &e) override; | |||
@@ -7,7 +7,7 @@ namespace rack { | |||
struct RackRail : TransparentWidget { | |||
void draw(NVGcontext *vg) override; | |||
void draw(const DrawContext &ctx) override; | |||
}; | |||
@@ -8,7 +8,7 @@ namespace rack { | |||
struct RackScrollWidget : ScrollWidget { | |||
void step() override; | |||
void draw(NVGcontext *vg) override; | |||
void draw(const DrawContext &ctx) override; | |||
}; | |||
@@ -22,7 +22,7 @@ struct RackWidget : OpaqueWidget { | |||
~RackWidget(); | |||
void step() override; | |||
void draw(NVGcontext *vg) override; | |||
void draw(const DrawContext &ctx) override; | |||
void onHover(const event::Hover &e) override; | |||
void onHoverKey(const event::HoverKey &e) override; | |||
@@ -10,7 +10,7 @@ namespace rack { | |||
struct PanelBorder : TransparentWidget { | |||
void draw(NVGcontext *vg) override; | |||
void draw(const DrawContext &ctx) override; | |||
}; | |||
@@ -28,7 +28,7 @@ struct Scene : OpaqueWidget { | |||
Scene(); | |||
~Scene(); | |||
void step() override; | |||
void draw(NVGcontext *vg) override; | |||
void draw(const DrawContext &ctx) override; | |||
void onHoverKey(const event::HoverKey &e) override; | |||
void onPathDrop(const event::PathDrop &e) override; | |||
@@ -12,7 +12,7 @@ struct Toolbar : OpaqueWidget { | |||
float cableTension = 0.5; | |||
Toolbar(); | |||
void draw(NVGcontext *vg) override; | |||
void draw(const DrawContext &ctx) override; | |||
}; | |||
@@ -15,7 +15,7 @@ struct Button : OpaqueWidget { | |||
Button(); | |||
~Button(); | |||
void draw(NVGcontext *vg) override; | |||
void draw(const DrawContext &ctx) override; | |||
void onEnter(const event::Enter &e) override; | |||
void onLeave(const event::Leave &e) override; | |||
void onDragStart(const event::DragStart &e) override; | |||
@@ -7,7 +7,7 @@ namespace rack { | |||
struct ChoiceButton : Button { | |||
void draw(NVGcontext *vg) override; | |||
void draw(const DrawContext &ctx) override; | |||
}; | |||
@@ -19,7 +19,7 @@ struct Label : Widget { | |||
Alignment alignment = LEFT_ALIGNMENT; | |||
Label(); | |||
void draw(NVGcontext *vg) override; | |||
void draw(const DrawContext &ctx) override; | |||
}; | |||
@@ -17,7 +17,7 @@ struct Menu : OpaqueWidget { | |||
~Menu(); | |||
void setChildMenu(Menu *menu); | |||
void step() override; | |||
void draw(NVGcontext *vg) override; | |||
void draw(const DrawContext &ctx) override; | |||
void onHoverScroll(const event::HoverScroll &e) override; | |||
}; | |||
@@ -17,7 +17,7 @@ struct MenuItem : MenuEntry { | |||
std::string rightText; | |||
bool disabled = false; | |||
void draw(NVGcontext *vg) override; | |||
void draw(const DrawContext &ctx) override; | |||
void step() override; | |||
void onEnter(const event::Enter &e) override; | |||
void onDragDrop(const event::DragDrop &e) override; | |||
@@ -9,7 +9,7 @@ namespace rack { | |||
struct MenuLabel : MenuEntry { | |||
std::string text; | |||
void draw(NVGcontext *vg) override; | |||
void draw(const DrawContext &ctx) override; | |||
void step() override; | |||
}; | |||
@@ -8,7 +8,7 @@ namespace rack { | |||
struct MenuSeparator : MenuEntry { | |||
MenuSeparator(); | |||
void draw(NVGcontext *vg) override; | |||
void draw(const DrawContext &ctx) override; | |||
}; | |||
@@ -7,7 +7,7 @@ namespace rack { | |||
struct PasswordField : TextField { | |||
void draw(NVGcontext *vg) override; | |||
void draw(const DrawContext &ctx) override; | |||
}; | |||
@@ -12,7 +12,7 @@ struct ProgressBar : Widget { | |||
ProgressBar(); | |||
~ProgressBar(); | |||
void draw(NVGcontext *vg) override; | |||
void draw(const DrawContext &ctx) override; | |||
}; | |||
@@ -13,7 +13,7 @@ struct RadioButton : OpaqueWidget { | |||
RadioButton(); | |||
~RadioButton(); | |||
void draw(NVGcontext *vg) override; | |||
void draw(const DrawContext &ctx) override; | |||
void onEnter(const event::Enter &e) override; | |||
void onLeave(const event::Leave &e) override; | |||
void onDragDrop(const event::DragDrop &e) override; | |||
@@ -18,7 +18,7 @@ struct ScrollBar : OpaqueWidget { | |||
float size = 0.0; | |||
ScrollBar(); | |||
void draw(NVGcontext *vg) override; | |||
void draw(const DrawContext &ctx) override; | |||
void onDragStart(const event::DragStart &e) override; | |||
void onDragMove(const event::DragMove &e) override; | |||
void onDragEnd(const event::DragEnd &e) override; | |||
@@ -16,7 +16,7 @@ struct ScrollWidget : OpaqueWidget { | |||
ScrollWidget(); | |||
void scrollTo(math::Rect r); | |||
void draw(NVGcontext *vg) override; | |||
void draw(const DrawContext &ctx) override; | |||
void step() override; | |||
void onHover(const event::Hover &e) override; | |||
void onHoverScroll(const event::HoverScroll &e) override; | |||
@@ -14,7 +14,7 @@ struct Slider : OpaqueWidget { | |||
Slider(); | |||
~Slider(); | |||
void draw(NVGcontext *vg) override; | |||
void draw(const DrawContext &ctx) override; | |||
void onDragStart(const event::DragStart &e) override; | |||
void onDragMove(const event::DragMove &e) override; | |||
void onDragEnd(const event::DragEnd &e) override; | |||
@@ -20,7 +20,7 @@ struct TextField : OpaqueWidget { | |||
int selection = 0; | |||
TextField(); | |||
void draw(NVGcontext *vg) override; | |||
void draw(const DrawContext &ctx) override; | |||
void onButton(const event::Button &e) override; | |||
void onHover(const event::Hover &e) override; | |||
void onEnter(const event::Enter &e) override; | |||
@@ -10,7 +10,7 @@ struct Tooltip : Widget { | |||
std::string text; | |||
void step() override; | |||
void draw(NVGcontext *vg) override; | |||
void draw(const DrawContext &ctx) override; | |||
}; | |||
@@ -27,7 +27,7 @@ struct FramebufferWidget : Widget { | |||
FramebufferWidget(); | |||
~FramebufferWidget(); | |||
void draw(NVGcontext *vg) override; | |||
void draw(const DrawContext &ctx) override; | |||
virtual void drawFramebuffer(); | |||
int getImageHandle(); | |||
@@ -26,9 +26,9 @@ struct SVGWidget : Widget { | |||
wrap(); | |||
} | |||
void draw(NVGcontext *vg) override { | |||
void draw(const DrawContext &ctx) override { | |||
if (svg && svg->handle) { | |||
svgDraw(vg, svg->handle); | |||
svgDraw(ctx.vg, svg->handle); | |||
} | |||
} | |||
}; | |||
@@ -36,10 +36,10 @@ struct TransformWidget : Widget { | |||
nvgTransformPremultiply(transform, t); | |||
} | |||
void draw(NVGcontext *vg) override { | |||
void draw(const DrawContext &ctx) override { | |||
// No need to save the state because that is done in the parent | |||
nvgTransform(vg, transform[0], transform[1], transform[2], transform[3], transform[4], transform[5]); | |||
Widget::draw(vg); | |||
nvgTransform(ctx.vg, transform[0], transform[1], transform[2], transform[3], transform[4], transform[5]); | |||
Widget::draw(ctx); | |||
} | |||
}; | |||
@@ -10,6 +10,11 @@ | |||
namespace rack { | |||
struct DrawContext { | |||
mutable NVGcontext *vg; | |||
}; | |||
/** A node in the 2D scene graph | |||
*/ | |||
struct Widget { | |||
@@ -67,8 +72,10 @@ struct Widget { | |||
/** Advances the module by one frame */ | |||
virtual void step(); | |||
/** Draws to NanoVG context */ | |||
virtual void draw(NVGcontext *vg); | |||
/** Draws the widget to the NanoVG context */ | |||
virtual void draw(const DrawContext &ctx); | |||
/** Override `draw(const DrawContext &ctx)` instead */ | |||
DEPRECATED virtual void draw(NVGcontext *vg) {} | |||
// Events | |||
@@ -11,7 +11,7 @@ struct ZoomWidget : Widget { | |||
math::Vec getRelativeOffset(math::Vec v, Widget *relative) override; | |||
math::Rect getViewport(math::Rect r) override; | |||
void setZoom(float zoom); | |||
void draw(NVGcontext *vg) override; | |||
void draw(const DrawContext &ctx) override; | |||
void onHover(const event::Hover &e) override { | |||
event::Hover e2 = e; | |||
@@ -16,12 +16,12 @@ struct BlankPanel : Widget { | |||
panelBorder->box.size = box.size; | |||
} | |||
void draw(NVGcontext *vg) override { | |||
nvgBeginPath(vg); | |||
nvgRect(vg, 0.0, 0.0, box.size.x, box.size.y); | |||
nvgFillColor(vg, nvgRGB(0xe6, 0xe6, 0xe6)); | |||
nvgFill(vg); | |||
Widget::draw(vg); | |||
void draw(const DrawContext &ctx) override { | |||
nvgBeginPath(ctx.vg); | |||
nvgRect(ctx.vg, 0.0, 0.0, box.size.x, box.size.y); | |||
nvgFillColor(ctx.vg, nvgRGB(0xe6, 0xe6, 0xe6)); | |||
nvgFill(ctx.vg); | |||
Widget::draw(ctx); | |||
} | |||
}; | |||
@@ -64,15 +64,15 @@ struct ModuleResizeHandle : Widget { | |||
} | |||
app()->scene->rackWidget->requestModuleBox(m, newBox); | |||
} | |||
void draw(NVGcontext *vg) override { | |||
void draw(const DrawContext &ctx) override { | |||
for (float x = 5.0; x <= 10.0; x += 5.0) { | |||
nvgBeginPath(vg); | |||
nvgBeginPath(ctx.vg); | |||
const float margin = 5.0; | |||
nvgMoveTo(vg, x + 0.5, margin + 0.5); | |||
nvgLineTo(vg, x + 0.5, box.size.y - margin + 0.5); | |||
nvgStrokeWidth(vg, 1.0); | |||
nvgStrokeColor(vg, nvgRGBAf(0.5, 0.5, 0.5, 0.5)); | |||
nvgStroke(vg); | |||
nvgMoveTo(ctx.vg, x + 0.5, margin + 0.5); | |||
nvgLineTo(ctx.vg, x + 0.5, box.size.y - margin + 0.5); | |||
nvgStrokeWidth(ctx.vg, 1.0); | |||
nvgStrokeColor(ctx.vg, nvgRGBAf(0.5, 0.5, 0.5, 0.5)); | |||
nvgStroke(ctx.vg); | |||
} | |||
} | |||
}; | |||
@@ -10,67 +10,67 @@ | |||
namespace rack { | |||
static void drawPlug(NVGcontext *vg, math::Vec pos, NVGcolor color) { | |||
static void drawPlug(const DrawContext &ctx, math::Vec pos, NVGcolor color) { | |||
NVGcolor colorOutline = nvgLerpRGBA(color, nvgRGBf(0.0, 0.0, 0.0), 0.5); | |||
// Plug solid | |||
nvgBeginPath(vg); | |||
nvgCircle(vg, pos.x, pos.y, 9); | |||
nvgFillColor(vg, color); | |||
nvgFill(vg); | |||
nvgBeginPath(ctx.vg); | |||
nvgCircle(ctx.vg, pos.x, pos.y, 9); | |||
nvgFillColor(ctx.vg, color); | |||
nvgFill(ctx.vg); | |||
// Border | |||
nvgStrokeWidth(vg, 1.0); | |||
nvgStrokeColor(vg, colorOutline); | |||
nvgStroke(vg); | |||
nvgStrokeWidth(ctx.vg, 1.0); | |||
nvgStrokeColor(ctx.vg, colorOutline); | |||
nvgStroke(ctx.vg); | |||
// Hole | |||
nvgBeginPath(vg); | |||
nvgCircle(vg, pos.x, pos.y, 5); | |||
nvgFillColor(vg, nvgRGBf(0.0, 0.0, 0.0)); | |||
nvgFill(vg); | |||
nvgBeginPath(ctx.vg); | |||
nvgCircle(ctx.vg, pos.x, pos.y, 5); | |||
nvgFillColor(ctx.vg, nvgRGBf(0.0, 0.0, 0.0)); | |||
nvgFill(ctx.vg); | |||
} | |||
static void drawCable(NVGcontext *vg, math::Vec pos1, math::Vec pos2, NVGcolor color, float thickness, float tension, float opacity) { | |||
static void drawCable(const DrawContext &ctx, math::Vec pos1, math::Vec pos2, NVGcolor color, float thickness, float tension, float opacity) { | |||
NVGcolor colorShadow = nvgRGBAf(0, 0, 0, 0.10); | |||
NVGcolor colorOutline = nvgLerpRGBA(color, nvgRGBf(0.0, 0.0, 0.0), 0.5); | |||
// Cable | |||
if (opacity > 0.0) { | |||
nvgSave(vg); | |||
nvgSave(ctx.vg); | |||
// This power scaling looks more linear than actual linear scaling | |||
nvgGlobalAlpha(vg, std::pow(opacity, 1.5)); | |||
nvgGlobalAlpha(ctx.vg, std::pow(opacity, 1.5)); | |||
float dist = pos1.minus(pos2).norm(); | |||
math::Vec slump; | |||
slump.y = (1.0 - tension) * (150.0 + 1.0*dist); | |||
math::Vec pos3 = pos1.plus(pos2).div(2).plus(slump); | |||
nvgLineJoin(vg, NVG_ROUND); | |||
nvgLineJoin(ctx.vg, NVG_ROUND); | |||
// Shadow | |||
math::Vec pos4 = pos3.plus(slump.mult(0.08)); | |||
nvgBeginPath(vg); | |||
nvgMoveTo(vg, pos1.x, pos1.y); | |||
nvgQuadTo(vg, pos4.x, pos4.y, pos2.x, pos2.y); | |||
nvgStrokeColor(vg, colorShadow); | |||
nvgStrokeWidth(vg, thickness); | |||
nvgStroke(vg); | |||
nvgBeginPath(ctx.vg); | |||
nvgMoveTo(ctx.vg, pos1.x, pos1.y); | |||
nvgQuadTo(ctx.vg, pos4.x, pos4.y, pos2.x, pos2.y); | |||
nvgStrokeColor(ctx.vg, colorShadow); | |||
nvgStrokeWidth(ctx.vg, thickness); | |||
nvgStroke(ctx.vg); | |||
// Cable outline | |||
nvgBeginPath(vg); | |||
nvgMoveTo(vg, pos1.x, pos1.y); | |||
nvgQuadTo(vg, pos3.x, pos3.y, pos2.x, pos2.y); | |||
nvgStrokeColor(vg, colorOutline); | |||
nvgStrokeWidth(vg, thickness); | |||
nvgStroke(vg); | |||
nvgBeginPath(ctx.vg); | |||
nvgMoveTo(ctx.vg, pos1.x, pos1.y); | |||
nvgQuadTo(ctx.vg, pos3.x, pos3.y, pos2.x, pos2.y); | |||
nvgStrokeColor(ctx.vg, colorOutline); | |||
nvgStrokeWidth(ctx.vg, thickness); | |||
nvgStroke(ctx.vg); | |||
// Cable solid | |||
nvgStrokeColor(vg, color); | |||
nvgStrokeWidth(vg, thickness - 2); | |||
nvgStroke(vg); | |||
nvgStrokeColor(ctx.vg, color); | |||
nvgStrokeWidth(ctx.vg, thickness - 2); | |||
nvgStroke(ctx.vg); | |||
nvgRestore(vg); | |||
nvgRestore(ctx.vg); | |||
} | |||
} | |||
@@ -205,7 +205,7 @@ void CableWidget::fromJson(json_t *rootJ, const std::map<int, ModuleWidget*> &mo | |||
} | |||
} | |||
void CableWidget::draw(NVGcontext *vg) { | |||
void CableWidget::draw(const DrawContext &ctx) { | |||
float opacity = settings::cableOpacity; | |||
float tension = settings::cableTension; | |||
@@ -235,33 +235,33 @@ void CableWidget::draw(NVGcontext *vg) { | |||
math::Vec outputPos = getOutputPos(); | |||
math::Vec inputPos = getInputPos(); | |||
drawCable(vg, outputPos, inputPos, color, thickness, tension, opacity); | |||
drawCable(ctx, outputPos, inputPos, color, thickness, tension, opacity); | |||
} | |||
void CableWidget::drawPlugs(NVGcontext *vg) { | |||
void CableWidget::drawPlugs(const DrawContext &ctx) { | |||
// TODO Figure out a way to draw plugs first and cables last, and cut the plug portion of the cable off. | |||
math::Vec outputPos = getOutputPos(); | |||
math::Vec inputPos = getInputPos(); | |||
// Draw plug if the cable is on top, or if the cable is incomplete | |||
if (!isComplete() || app()->scene->rackWidget->getTopCable(outputPort) == this) { | |||
drawPlug(vg, outputPos, color); | |||
drawPlug(ctx, outputPos, color); | |||
if (isComplete()) { | |||
// Draw plug light | |||
nvgSave(vg); | |||
nvgTranslate(vg, outputPos.x - 4, outputPos.y - 4); | |||
outputPort->plugLight->draw(vg); | |||
nvgRestore(vg); | |||
nvgSave(ctx.vg); | |||
nvgTranslate(ctx.vg, outputPos.x - 4, outputPos.y - 4); | |||
outputPort->plugLight->draw(ctx); | |||
nvgRestore(ctx.vg); | |||
} | |||
} | |||
if (!isComplete() || app()->scene->rackWidget->getTopCable(inputPort) == this) { | |||
drawPlug(vg, inputPos, color); | |||
drawPlug(ctx, inputPos, color); | |||
if (isComplete()) { | |||
nvgSave(vg); | |||
nvgTranslate(vg, inputPos.x - 4, inputPos.y - 4); | |||
inputPort->plugLight->draw(vg); | |||
nvgRestore(vg); | |||
nvgSave(ctx.vg); | |||
nvgTranslate(ctx.vg, inputPos.x - 4, inputPos.y - 4); | |||
inputPort->plugLight->draw(ctx); | |||
nvgRestore(ctx.vg); | |||
} | |||
} | |||
} | |||
@@ -9,19 +9,19 @@ CircularShadow::CircularShadow() { | |||
opacity = 0.15; | |||
} | |||
void CircularShadow::draw(NVGcontext *vg) { | |||
void CircularShadow::draw(const DrawContext &ctx) { | |||
if (opacity <= 0.0) | |||
return; | |||
nvgBeginPath(vg); | |||
nvgRect(vg, -blurRadius, -blurRadius, box.size.x + 2*blurRadius, box.size.y + 2*blurRadius); | |||
nvgBeginPath(ctx.vg); | |||
nvgRect(ctx.vg, -blurRadius, -blurRadius, box.size.x + 2*blurRadius, box.size.y + 2*blurRadius); | |||
math::Vec center = box.size.div(2.0); | |||
float radius = center.x; | |||
NVGcolor icol = nvgRGBAf(0.0, 0.0, 0.0, opacity); | |||
NVGcolor ocol = nvgRGBAf(0.0, 0.0, 0.0, 0.0); | |||
NVGpaint paint = nvgRadialGradient(vg, center.x, center.y, radius - blurRadius, radius, icol, ocol); | |||
nvgFillPaint(vg, paint); | |||
nvgFill(vg); | |||
NVGpaint paint = nvgRadialGradient(ctx.vg, center.x, center.y, radius - blurRadius, radius, icol, ocol); | |||
nvgFillPaint(ctx.vg, paint); | |||
nvgFill(ctx.vg); | |||
} | |||
@@ -8,13 +8,13 @@ | |||
namespace rack { | |||
void LedDisplay::draw(NVGcontext *vg) { | |||
nvgBeginPath(vg); | |||
nvgRoundedRect(vg, 0, 0, box.size.x, box.size.y, 5.0); | |||
nvgFillColor(vg, nvgRGB(0x00, 0x00, 0x00)); | |||
nvgFill(vg); | |||
void LedDisplay::draw(const DrawContext &ctx) { | |||
nvgBeginPath(ctx.vg); | |||
nvgRoundedRect(ctx.vg, 0, 0, box.size.x, box.size.y, 5.0); | |||
nvgFillColor(ctx.vg, nvgRGB(0x00, 0x00, 0x00)); | |||
nvgFill(ctx.vg); | |||
Widget::draw(vg); | |||
Widget::draw(ctx); | |||
} | |||
@@ -22,13 +22,13 @@ LedDisplaySeparator::LedDisplaySeparator() { | |||
box.size = math::Vec(); | |||
} | |||
void LedDisplaySeparator::draw(NVGcontext *vg) { | |||
nvgBeginPath(vg); | |||
nvgMoveTo(vg, 0, 0); | |||
nvgLineTo(vg, box.size.x, box.size.y); | |||
nvgStrokeWidth(vg, 1.0); | |||
nvgStrokeColor(vg, nvgRGB(0x33, 0x33, 0x33)); | |||
nvgStroke(vg); | |||
void LedDisplaySeparator::draw(const DrawContext &ctx) { | |||
nvgBeginPath(ctx.vg); | |||
nvgMoveTo(ctx.vg, 0, 0); | |||
nvgLineTo(ctx.vg, box.size.x, box.size.y); | |||
nvgStrokeWidth(ctx.vg, 1.0); | |||
nvgStrokeColor(ctx.vg, nvgRGB(0x33, 0x33, 0x33)); | |||
nvgStroke(ctx.vg); | |||
} | |||
@@ -39,19 +39,19 @@ LedDisplayChoice::LedDisplayChoice() { | |||
textOffset = math::Vec(10, 18); | |||
} | |||
void LedDisplayChoice::draw(NVGcontext *vg) { | |||
nvgScissor(vg, 0, 0, box.size.x, box.size.y); | |||
void LedDisplayChoice::draw(const DrawContext &ctx) { | |||
nvgScissor(ctx.vg, 0, 0, box.size.x, box.size.y); | |||
if (font->handle >= 0) { | |||
nvgFillColor(vg, color); | |||
nvgFontFaceId(vg, font->handle); | |||
nvgTextLetterSpacing(vg, 0.0); | |||
nvgFillColor(ctx.vg, color); | |||
nvgFontFaceId(ctx.vg, font->handle); | |||
nvgTextLetterSpacing(ctx.vg, 0.0); | |||
nvgFontSize(vg, 12); | |||
nvgText(vg, textOffset.x, textOffset.y, text.c_str(), NULL); | |||
nvgFontSize(ctx.vg, 12); | |||
nvgText(ctx.vg, textOffset.x, textOffset.y, text.c_str(), NULL); | |||
} | |||
nvgResetScissor(vg); | |||
nvgResetScissor(ctx.vg); | |||
} | |||
void LedDisplayChoice::onButton(const event::Button &e) { | |||
@@ -70,14 +70,14 @@ LedDisplayTextField::LedDisplayTextField() { | |||
} | |||
void LedDisplayTextField::draw(NVGcontext *vg) { | |||
nvgScissor(vg, 0, 0, box.size.x, box.size.y); | |||
void LedDisplayTextField::draw(const DrawContext &ctx) { | |||
nvgScissor(ctx.vg, 0, 0, box.size.x, box.size.y); | |||
// Background | |||
nvgBeginPath(vg); | |||
nvgRoundedRect(vg, 0, 0, box.size.x, box.size.y, 5.0); | |||
nvgFillColor(vg, nvgRGB(0x00, 0x00, 0x00)); | |||
nvgFill(vg); | |||
nvgBeginPath(ctx.vg); | |||
nvgRoundedRect(ctx.vg, 0, 0, box.size.x, box.size.y, 5.0); | |||
nvgFillColor(ctx.vg, nvgRGB(0x00, 0x00, 0x00)); | |||
nvgFill(ctx.vg); | |||
// Text | |||
if (font->handle >= 0) { | |||
@@ -87,14 +87,14 @@ void LedDisplayTextField::draw(NVGcontext *vg) { | |||
highlightColor.a = 0.5; | |||
int begin = std::min(cursor, selection); | |||
int end = (this == app()->event->selectedWidget) ? std::max(cursor, selection) : -1; | |||
bndIconLabelCaret(vg, textOffset.x, textOffset.y, | |||
bndIconLabelCaret(ctx.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); | |||
} | |||
nvgResetScissor(vg); | |||
nvgResetScissor(ctx.vg); | |||
} | |||
int LedDisplayTextField::getTextPosition(math::Vec mousePos) { | |||
@@ -5,45 +5,45 @@ | |||
namespace rack { | |||
void LightWidget::draw(NVGcontext *vg) { | |||
drawLight(vg); | |||
drawHalo(vg); | |||
void LightWidget::draw(const DrawContext &ctx) { | |||
drawLight(ctx); | |||
drawHalo(ctx); | |||
} | |||
void LightWidget::drawLight(NVGcontext *vg) { | |||
void LightWidget::drawLight(const DrawContext &ctx) { | |||
float radius = box.size.x / 2.0; | |||
nvgBeginPath(vg); | |||
nvgCircle(vg, radius, radius, radius); | |||
nvgBeginPath(ctx.vg); | |||
nvgCircle(ctx.vg, radius, radius, radius); | |||
// Background | |||
nvgFillColor(vg, bgColor); | |||
nvgFill(vg); | |||
nvgFillColor(ctx.vg, bgColor); | |||
nvgFill(ctx.vg); | |||
// Foreground | |||
nvgFillColor(vg, color); | |||
nvgFill(vg); | |||
nvgFillColor(ctx.vg, color); | |||
nvgFill(ctx.vg); | |||
// Border | |||
nvgStrokeWidth(vg, 0.5); | |||
nvgStrokeColor(vg, borderColor); | |||
nvgStroke(vg); | |||
nvgStrokeWidth(ctx.vg, 0.5); | |||
nvgStrokeColor(ctx.vg, borderColor); | |||
nvgStroke(ctx.vg); | |||
} | |||
void LightWidget::drawHalo(NVGcontext *vg) { | |||
void LightWidget::drawHalo(const DrawContext &ctx) { | |||
float radius = box.size.x / 2.0; | |||
float oradius = radius + 15.0; | |||
nvgBeginPath(vg); | |||
nvgRect(vg, radius - oradius, radius - oradius, 2*oradius, 2*oradius); | |||
nvgBeginPath(ctx.vg); | |||
nvgRect(ctx.vg, radius - oradius, radius - oradius, 2*oradius, 2*oradius); | |||
NVGpaint paint; | |||
NVGcolor icol = color::mult(color, 0.08); | |||
NVGcolor ocol = nvgRGB(0, 0, 0); | |||
paint = nvgRadialGradient(vg, radius, radius, radius, oradius, icol, ocol); | |||
nvgFillPaint(vg, paint); | |||
nvgGlobalCompositeOperation(vg, NVG_LIGHTER); | |||
nvgFill(vg); | |||
paint = nvgRadialGradient(ctx.vg, radius, radius, radius, oradius, icol, ocol); | |||
nvgFillPaint(ctx.vg, paint); | |||
nvgGlobalCompositeOperation(ctx.vg, NVG_LIGHTER); | |||
nvgFill(ctx.vg); | |||
} | |||
@@ -47,9 +47,7 @@ struct ModuleBox : OpaqueWidget { | |||
addChild(pluginLabel); | |||
} | |||
void draw(NVGcontext *vg) override { | |||
DEBUG("%p model", model); | |||
void draw(const DrawContext &ctx) override { | |||
// Lazily create ModuleWidget when drawn | |||
if (!initialized) { | |||
Widget *transparentWidget = new TransparentWidget; | |||
@@ -76,12 +74,12 @@ struct ModuleBox : OpaqueWidget { | |||
initialized = true; | |||
} | |||
OpaqueWidget::draw(vg); | |||
OpaqueWidget::draw(ctx); | |||
if (app()->event->hoveredWidget == this) { | |||
nvgBeginPath(vg); | |||
nvgRect(vg, 0.0, 0.0, box.size.x, box.size.y); | |||
nvgFillColor(vg, nvgRGBAf(1, 1, 1, 0.25)); | |||
nvgFill(vg); | |||
nvgBeginPath(ctx.vg); | |||
nvgRect(ctx.vg, 0.0, 0.0, box.size.x, box.size.y); | |||
nvgFillColor(ctx.vg, nvgRGBAf(1, 1, 1, 0.25)); | |||
nvgFill(ctx.vg); | |||
} | |||
} | |||
@@ -137,9 +135,9 @@ void ModuleBrowser::step() { | |||
OpaqueWidget::step(); | |||
} | |||
void ModuleBrowser::draw(NVGcontext *vg) { | |||
bndMenuBackground(vg, 0.0, 0.0, box.size.x, box.size.y, 0); | |||
Widget::draw(vg); | |||
void ModuleBrowser::draw(const DrawContext &ctx) { | |||
bndMenuBackground(ctx.vg, 0.0, 0.0, box.size.x, box.size.y, 0); | |||
Widget::draw(ctx); | |||
} | |||
void ModuleBrowser::onHoverKey(const event::HoverKey &e) { | |||
@@ -136,57 +136,57 @@ ModuleWidget::~ModuleWidget() { | |||
setModule(NULL); | |||
} | |||
void ModuleWidget::draw(NVGcontext *vg) { | |||
void ModuleWidget::draw(const DrawContext &ctx) { | |||
if (module && module->bypass) { | |||
nvgGlobalAlpha(vg, 0.5); | |||
nvgGlobalAlpha(ctx.vg, 0.5); | |||
} | |||
// nvgScissor(vg, 0, 0, box.size.x, box.size.y); | |||
Widget::draw(vg); | |||
// nvgScissor(ctx.vg, 0, 0, box.size.x, box.size.y); | |||
Widget::draw(ctx); | |||
// Power meter | |||
if (module && settings::powerMeter) { | |||
nvgBeginPath(vg); | |||
nvgRect(vg, | |||
nvgBeginPath(ctx.vg); | |||
nvgRect(ctx.vg, | |||
0, box.size.y - 20, | |||
65, 20); | |||
nvgFillColor(vg, nvgRGBAf(0, 0, 0, 0.75)); | |||
nvgFill(vg); | |||
nvgFillColor(ctx.vg, nvgRGBAf(0, 0, 0, 0.75)); | |||
nvgFill(ctx.vg); | |||
std::string cpuText = string::f("%.2f ÎĽs", module->cpuTime * 1e6f); | |||
bndLabel(vg, 2.0, box.size.y - 20.0, INFINITY, INFINITY, -1, cpuText.c_str()); | |||
bndLabel(ctx.vg, 2.0, box.size.y - 20.0, INFINITY, INFINITY, -1, cpuText.c_str()); | |||
float p = math::clamp(module->cpuTime / app()->engine->getSampleTime(), 0.f, 1.f); | |||
nvgBeginPath(vg); | |||
nvgRect(vg, | |||
nvgBeginPath(ctx.vg); | |||
nvgRect(ctx.vg, | |||
0, (1.f - p) * box.size.y, | |||
5, p * box.size.y); | |||
nvgFillColor(vg, nvgRGBAf(1, 0, 0, 1.0)); | |||
nvgFill(vg); | |||
nvgFillColor(ctx.vg, nvgRGBAf(1, 0, 0, 1.0)); | |||
nvgFill(ctx.vg); | |||
} | |||
// if (module) { | |||
// nvgBeginPath(vg); | |||
// nvgRect(vg, 0, 0, 20, 20); | |||
// nvgFillColor(vg, nvgRGBAf(0, 0, 0, 0.75)); | |||
// nvgFill(vg); | |||
// nvgBeginPath(ctx.vg); | |||
// nvgRect(ctx.vg, 0, 0, 20, 20); | |||
// nvgFillColor(ctx.vg, nvgRGBAf(0, 0, 0, 0.75)); | |||
// nvgFill(ctx.vg); | |||
// std::string debugText = string::f("%d", module->id); | |||
// bndLabel(vg, 0, 0, INFINITY, INFINITY, -1, debugText.c_str()); | |||
// bndLabel(ctx.vg, 0, 0, INFINITY, INFINITY, -1, debugText.c_str()); | |||
// } | |||
// nvgResetScissor(vg); | |||
// nvgResetScissor(ctx.vg); | |||
} | |||
void ModuleWidget::drawShadow(NVGcontext *vg) { | |||
nvgBeginPath(vg); | |||
void ModuleWidget::drawShadow(const DrawContext &ctx) { | |||
nvgBeginPath(ctx.vg); | |||
float r = 20; // Blur radius | |||
float c = 20; // Corner radius | |||
math::Vec b = math::Vec(-10, 30); // Offset from each corner | |||
nvgRect(vg, b.x - r, b.y - r, box.size.x - 2*b.x + 2*r, box.size.y - 2*b.y + 2*r); | |||
nvgRect(ctx.vg, b.x - r, b.y - r, box.size.x - 2*b.x + 2*r, box.size.y - 2*b.y + 2*r); | |||
NVGcolor shadowColor = nvgRGBAf(0, 0, 0, 0.2); | |||
NVGcolor transparentColor = nvgRGBAf(0, 0, 0, 0); | |||
nvgFillPaint(vg, nvgBoxGradient(vg, b.x, b.y, box.size.x - 2*b.x, box.size.y - 2*b.y, c, r, shadowColor, transparentColor)); | |||
nvgFill(vg); | |||
nvgFillPaint(ctx.vg, nvgBoxGradient(ctx.vg, b.x, b.y, box.size.x - 2*b.x, box.size.y - 2*b.y, c, r, shadowColor, transparentColor)); | |||
nvgFill(ctx.vg); | |||
} | |||
void ModuleWidget::onHover(const event::Hover &e) { | |||
@@ -125,19 +125,19 @@ void ParamWidget::step() { | |||
OpaqueWidget::step(); | |||
} | |||
void ParamWidget::draw(NVGcontext *vg) { | |||
Widget::draw(vg); | |||
void ParamWidget::draw(const DrawContext &ctx) { | |||
Widget::draw(ctx); | |||
// if (paramQuantity) { | |||
// nvgBeginPath(vg); | |||
// nvgRect(vg, | |||
// nvgBeginPath(ctx.vg); | |||
// nvgRect(ctx.vg, | |||
// box.size.x - 12, box.size.y - 12, | |||
// 12, 12); | |||
// nvgFillColor(vg, nvgRGBAf(1, 0, 1, 0.9)); | |||
// nvgFill(vg); | |||
// nvgFillColor(ctx.vg, nvgRGBAf(1, 0, 1, 0.9)); | |||
// nvgFill(ctx.vg); | |||
// std::string mapText = string::f("%d", paramQuantity->paramId); | |||
// bndLabel(vg, box.size.x - 17.0, box.size.y - 16.0, INFINITY, INFINITY, -1, mapText.c_str()); | |||
// bndLabel(ctx.vg, box.size.x - 17.0, box.size.y - 16.0, INFINITY, INFINITY, -1, mapText.c_str()); | |||
// } | |||
} | |||
@@ -51,14 +51,14 @@ void PortWidget::step() { | |||
plugLight->setBrightnesses(values); | |||
} | |||
void PortWidget::draw(NVGcontext *vg) { | |||
void PortWidget::draw(const DrawContext &ctx) { | |||
CableWidget *cw = app()->scene->rackWidget->incompleteCable; | |||
if (cw) { | |||
// Dim the PortWidget if the active cable cannot plug into this PortWidget | |||
if (type == OUTPUT ? cw->outputPort : cw->inputPort) | |||
nvgGlobalAlpha(vg, 0.5); | |||
nvgGlobalAlpha(ctx.vg, 0.5); | |||
} | |||
Widget::draw(vg); | |||
Widget::draw(ctx); | |||
} | |||
void PortWidget::onButton(const event::Button &e) { | |||
@@ -3,57 +3,57 @@ | |||
namespace rack { | |||
void RackRail::draw(NVGcontext *vg) { | |||
void RackRail::draw(const DrawContext &ctx) { | |||
const float railHeight = RACK_GRID_WIDTH; | |||
// Background color | |||
nvgBeginPath(vg); | |||
nvgRect(vg, 0.0, 0.0, box.size.x, box.size.y); | |||
nvgFillColor(vg, nvgRGBf(0.2, 0.2, 0.2)); | |||
nvgFill(vg); | |||
nvgBeginPath(ctx.vg); | |||
nvgRect(ctx.vg, 0.0, 0.0, box.size.x, box.size.y); | |||
nvgFillColor(ctx.vg, nvgRGBf(0.2, 0.2, 0.2)); | |||
nvgFill(ctx.vg); | |||
// Rails | |||
nvgFillColor(vg, nvgRGBf(0.85, 0.85, 0.85)); | |||
nvgStrokeWidth(vg, 1.0); | |||
nvgStrokeColor(vg, nvgRGBf(0.7, 0.7, 0.7)); | |||
nvgFillColor(ctx.vg, nvgRGBf(0.85, 0.85, 0.85)); | |||
nvgStrokeWidth(ctx.vg, 1.0); | |||
nvgStrokeColor(ctx.vg, nvgRGBf(0.7, 0.7, 0.7)); | |||
float holeRadius = 3.5; | |||
for (float railY = 0; railY < box.size.y; railY += RACK_GRID_HEIGHT) { | |||
// Top rail | |||
nvgBeginPath(vg); | |||
nvgRect(vg, 0, railY, box.size.x, railHeight); | |||
nvgBeginPath(ctx.vg); | |||
nvgRect(ctx.vg, 0, railY, box.size.x, railHeight); | |||
for (float railX = 0; railX < box.size.x; railX += RACK_GRID_WIDTH) { | |||
nvgCircle(vg, railX + RACK_GRID_WIDTH / 2, railY + railHeight / 2, holeRadius); | |||
nvgPathWinding(vg, NVG_HOLE); | |||
nvgCircle(ctx.vg, railX + RACK_GRID_WIDTH / 2, railY + railHeight / 2, holeRadius); | |||
nvgPathWinding(ctx.vg, NVG_HOLE); | |||
} | |||
nvgFill(vg); | |||
nvgFill(ctx.vg); | |||
nvgBeginPath(vg); | |||
nvgMoveTo(vg, 0, railY + railHeight - 0.5); | |||
nvgLineTo(vg, box.size.x, railY + railHeight - 0.5); | |||
nvgStroke(vg); | |||
nvgBeginPath(ctx.vg); | |||
nvgMoveTo(ctx.vg, 0, railY + railHeight - 0.5); | |||
nvgLineTo(ctx.vg, box.size.x, railY + railHeight - 0.5); | |||
nvgStroke(ctx.vg); | |||
// Bottom rail | |||
nvgBeginPath(vg); | |||
nvgRect(vg, 0, railY + RACK_GRID_HEIGHT - railHeight, box.size.x, railHeight); | |||
nvgBeginPath(ctx.vg); | |||
nvgRect(ctx.vg, 0, railY + RACK_GRID_HEIGHT - railHeight, box.size.x, railHeight); | |||
for (float railX = 0; railX < box.size.x; railX += RACK_GRID_WIDTH) { | |||
nvgCircle(vg, railX + RACK_GRID_WIDTH / 2, railY + RACK_GRID_HEIGHT - railHeight + railHeight / 2, holeRadius); | |||
nvgPathWinding(vg, NVG_HOLE); | |||
nvgCircle(ctx.vg, railX + RACK_GRID_WIDTH / 2, railY + RACK_GRID_HEIGHT - railHeight + railHeight / 2, holeRadius); | |||
nvgPathWinding(ctx.vg, NVG_HOLE); | |||
} | |||
nvgFill(vg); | |||
nvgFill(ctx.vg); | |||
nvgBeginPath(vg); | |||
nvgMoveTo(vg, 0, railY + RACK_GRID_HEIGHT - 0.5); | |||
nvgLineTo(vg, box.size.x, railY + RACK_GRID_HEIGHT - 0.5); | |||
nvgStroke(vg); | |||
nvgBeginPath(ctx.vg); | |||
nvgMoveTo(ctx.vg, 0, railY + RACK_GRID_HEIGHT - 0.5); | |||
nvgLineTo(ctx.vg, box.size.x, railY + RACK_GRID_HEIGHT - 0.5); | |||
nvgStroke(ctx.vg); | |||
} | |||
// Useful for screenshots | |||
if (0) { | |||
nvgBeginPath(vg); | |||
nvgRect(vg, 0.0, 0.0, box.size.x, box.size.y); | |||
nvgFillColor(vg, nvgRGBf(1.0, 1.0, 1.0)); | |||
nvgFill(vg); | |||
nvgBeginPath(ctx.vg); | |||
nvgRect(ctx.vg, 0.0, 0.0, box.size.x, box.size.y); | |||
nvgFillColor(ctx.vg, nvgRGBf(1.0, 1.0, 1.0)); | |||
nvgFill(ctx.vg); | |||
} | |||
} | |||
@@ -27,20 +27,20 @@ void RackScrollWidget::step() { | |||
} | |||
void RackScrollWidget::draw(NVGcontext *vg) { | |||
ScrollWidget::draw(vg); | |||
void RackScrollWidget::draw(const DrawContext &ctx) { | |||
ScrollWidget::draw(ctx); | |||
if (app()->scene->rackWidget->isEmpty()) { | |||
math::Rect b; | |||
b.size = math::Vec(600, 300); | |||
b.pos = box.size.minus(b.size).div(2); | |||
NVGcolor bg = nvgRGBAf(0, 0, 0, 0.4); | |||
bndInnerBox(vg, b.pos.x, b.pos.y, b.size.x, b.size.y, | |||
bndInnerBox(ctx.vg, b.pos.x, b.pos.y, b.size.x, b.size.y, | |||
0, 0, 0, 0, bg, bg); | |||
NVGcolor fg = nvgRGBAf(1, 1, 1, 0.25); | |||
std::string text = "Right-click or press Enter to add modules"; | |||
bndIconLabelValue(vg, b.pos.x, b.pos.y + 80, b.size.x, b.size.y, -1, fg, BND_CENTER, 80, text.c_str(), NULL); | |||
bndIconLabelValue(ctx.vg, b.pos.x, b.pos.y + 80, b.size.x, b.size.y, -1, fg, BND_CENTER, 80, text.c_str(), NULL); | |||
} | |||
} | |||
@@ -42,32 +42,32 @@ static ModuleWidget *moduleFromJson(json_t *moduleJ) { | |||
struct ModuleContainer : Widget { | |||
void draw(NVGcontext *vg) override { | |||
void draw(const DrawContext &ctx) override { | |||
// Draw shadows behind each ModuleWidget first, so the shadow doesn't overlap the front of other ModuleWidgets. | |||
for (Widget *child : children) { | |||
ModuleWidget *w = dynamic_cast<ModuleWidget*>(child); | |||
assert(w); | |||
nvgSave(vg); | |||
nvgTranslate(vg, child->box.pos.x, child->box.pos.y); | |||
w->drawShadow(vg); | |||
nvgRestore(vg); | |||
nvgSave(ctx.vg); | |||
nvgTranslate(ctx.vg, child->box.pos.x, child->box.pos.y); | |||
w->drawShadow(ctx); | |||
nvgRestore(ctx.vg); | |||
} | |||
Widget::draw(vg); | |||
Widget::draw(ctx); | |||
} | |||
}; | |||
struct CableContainer : TransparentWidget { | |||
void draw(NVGcontext *vg) override { | |||
Widget::draw(vg); | |||
void draw(const DrawContext &ctx) override { | |||
Widget::draw(ctx); | |||
// Draw cable plugs | |||
for (Widget *w : children) { | |||
CableWidget *cw = dynamic_cast<CableWidget*>(w); | |||
assert(cw); | |||
cw->drawPlugs(vg); | |||
cw->drawPlugs(ctx); | |||
} | |||
} | |||
}; | |||
@@ -116,8 +116,8 @@ void RackWidget::step() { | |||
Widget::step(); | |||
} | |||
void RackWidget::draw(NVGcontext *vg) { | |||
Widget::draw(vg); | |||
void RackWidget::draw(const DrawContext &ctx) { | |||
Widget::draw(ctx); | |||
} | |||
void RackWidget::onHover(const event::Hover &e) { | |||
@@ -4,13 +4,13 @@ | |||
namespace rack { | |||
void PanelBorder::draw(NVGcontext *vg) { | |||
void PanelBorder::draw(const DrawContext &ctx) { | |||
NVGcolor borderColor = nvgRGBAf(0.5, 0.5, 0.5, 0.5); | |||
nvgBeginPath(vg); | |||
nvgRect(vg, 0.5, 0.5, box.size.x - 1.0, box.size.y - 1.0); | |||
nvgStrokeColor(vg, borderColor); | |||
nvgStrokeWidth(vg, 1.0); | |||
nvgStroke(vg); | |||
nvgBeginPath(ctx.vg); | |||
nvgRect(ctx.vg, 0.5, 0.5, box.size.x - 1.0, box.size.y - 1.0); | |||
nvgStrokeColor(ctx.vg, borderColor); | |||
nvgStrokeWidth(ctx.vg, 1.0); | |||
nvgStroke(ctx.vg); | |||
} | |||
@@ -85,8 +85,8 @@ void Scene::step() { | |||
} | |||
} | |||
void Scene::draw(NVGcontext *vg) { | |||
OpaqueWidget::draw(vg); | |||
void Scene::draw(const DrawContext &ctx) { | |||
OpaqueWidget::draw(ctx); | |||
} | |||
void Scene::onHoverKey(const event::HoverKey &e) { | |||
@@ -26,8 +26,8 @@ struct MenuButton : Button { | |||
box.size.x = bndLabelWidth(app()->window->vg, -1, text.c_str()); | |||
Widget::step(); | |||
} | |||
void draw(NVGcontext *vg) override { | |||
bndMenuItem(vg, 0.0, 0.0, box.size.x, box.size.y, state, -1, text.c_str()); | |||
void draw(const DrawContext &ctx) override { | |||
bndMenuItem(ctx.vg, 0.0, 0.0, box.size.x, box.size.y, state, -1, text.c_str()); | |||
} | |||
}; | |||
@@ -570,16 +570,16 @@ struct PluginsButton : MenuButton { | |||
} | |||
} | |||
void draw(NVGcontext *vg) override { | |||
MenuButton::draw(vg); | |||
void draw(const DrawContext &ctx) override { | |||
MenuButton::draw(ctx); | |||
// if (1) { | |||
// // Notification circle | |||
// nvgBeginPath(vg); | |||
// nvgCircle(vg, box.size.x - 3, 3, 4.0); | |||
// nvgFillColor(vg, nvgRGBf(1.0, 0.0, 0.0)); | |||
// nvgFill(vg); | |||
// nvgStrokeColor(vg, nvgRGBf(0.5, 0.0, 0.0)); | |||
// nvgStroke(vg); | |||
// nvgBeginPath(ctx.vg); | |||
// nvgCircle(ctx.vg, box.size.x - 3, 3, 4.0); | |||
// nvgFillColor(ctx.vg, nvgRGBf(1.0, 0.0, 0.0)); | |||
// nvgFill(ctx.vg); | |||
// nvgStrokeColor(ctx.vg, nvgRGBf(0.5, 0.0, 0.0)); | |||
// nvgStroke(ctx.vg); | |||
// } | |||
} | |||
}; | |||
@@ -664,11 +664,11 @@ Toolbar::Toolbar() { | |||
layout->addChild(helpButton); | |||
} | |||
void Toolbar::draw(NVGcontext *vg) { | |||
bndMenuBackground(vg, 0.0, 0.0, box.size.x, box.size.y, BND_CORNER_ALL); | |||
bndBevel(vg, 0.0, 0.0, box.size.x, box.size.y); | |||
void Toolbar::draw(const DrawContext &ctx) { | |||
bndMenuBackground(ctx.vg, 0.0, 0.0, box.size.x, box.size.y, BND_CORNER_ALL); | |||
bndBevel(ctx.vg, 0.0, 0.0, box.size.x, box.size.y); | |||
Widget::draw(vg); | |||
Widget::draw(ctx); | |||
} | |||
@@ -13,8 +13,8 @@ Button::~Button() { | |||
delete quantity; | |||
} | |||
void Button::draw(NVGcontext *vg) { | |||
bndToolButton(vg, 0.0, 0.0, box.size.x, box.size.y, BND_CORNER_NONE, state, -1, text.c_str()); | |||
void Button::draw(const DrawContext &ctx) { | |||
bndToolButton(ctx.vg, 0.0, 0.0, box.size.x, box.size.y, BND_CORNER_NONE, state, -1, text.c_str()); | |||
} | |||
void Button::onEnter(const event::Enter &e) { | |||
@@ -4,8 +4,8 @@ | |||
namespace rack { | |||
void ChoiceButton::draw(NVGcontext *vg) { | |||
bndChoiceButton(vg, 0.0, 0.0, box.size.x, box.size.y, BND_CORNER_NONE, state, -1, text.c_str()); | |||
void ChoiceButton::draw(const DrawContext &ctx) { | |||
bndChoiceButton(ctx.vg, 0.0, 0.0, box.size.x, box.size.y, BND_CORNER_NONE, state, -1, text.c_str()); | |||
} | |||
@@ -10,7 +10,7 @@ Label::Label() { | |||
color = bndGetTheme()->regularTheme.textColor; | |||
} | |||
void Label::draw(NVGcontext *vg) { | |||
void Label::draw(const DrawContext &ctx) { | |||
// TODO | |||
// Custom font sizes do not work with right or center alignment | |||
float x; | |||
@@ -20,14 +20,14 @@ void Label::draw(NVGcontext *vg) { | |||
x = 0.0; | |||
} break; | |||
case RIGHT_ALIGNMENT: { | |||
x = box.size.x - bndLabelWidth(vg, -1, text.c_str()); | |||
x = box.size.x - bndLabelWidth(ctx.vg, -1, text.c_str()); | |||
} break; | |||
case CENTER_ALIGNMENT: { | |||
x = (box.size.x - bndLabelWidth(vg, -1, text.c_str())) / 2.0; | |||
x = (box.size.x - bndLabelWidth(ctx.vg, -1, text.c_str())) / 2.0; | |||
} break; | |||
} | |||
bndIconLabelValue(vg, x, 0.0, box.size.x, box.size.y, -1, color, BND_LEFT, fontSize, text.c_str(), NULL); | |||
bndIconLabelValue(ctx.vg, x, 0.0, box.size.x, box.size.y, -1, color, BND_LEFT, fontSize, text.c_str(), NULL); | |||
} | |||
@@ -48,9 +48,9 @@ void Menu::step() { | |||
} | |||
} | |||
void Menu::draw(NVGcontext *vg) { | |||
bndMenuBackground(vg, 0.0, 0.0, box.size.x, box.size.y, BND_CORNER_NONE); | |||
Widget::draw(vg); | |||
void Menu::draw(const DrawContext &ctx) { | |||
bndMenuBackground(ctx.vg, 0.0, 0.0, box.size.x, box.size.y, BND_CORNER_NONE); | |||
Widget::draw(ctx); | |||
} | |||
void Menu::onHoverScroll(const event::HoverScroll &e) { | |||
@@ -4,7 +4,7 @@ | |||
namespace rack { | |||
void MenuItem::draw(NVGcontext *vg) { | |||
void MenuItem::draw(const DrawContext &ctx) { | |||
BNDwidgetState state = BND_DEFAULT; | |||
if (app()->event->hoveredWidget == this) | |||
@@ -17,14 +17,14 @@ void MenuItem::draw(NVGcontext *vg) { | |||
// Main text and background | |||
if (!disabled) | |||
bndMenuItem(vg, 0.0, 0.0, box.size.x, box.size.y, state, -1, text.c_str()); | |||
bndMenuItem(ctx.vg, 0.0, 0.0, box.size.x, box.size.y, state, -1, text.c_str()); | |||
else | |||
bndMenuLabel(vg, 0.0, 0.0, box.size.x, box.size.y, -1, text.c_str()); | |||
bndMenuLabel(ctx.vg, 0.0, 0.0, box.size.x, box.size.y, -1, text.c_str()); | |||
// Right text | |||
float x = box.size.x - bndLabelWidth(vg, -1, rightText.c_str()); | |||
float x = box.size.x - bndLabelWidth(ctx.vg, -1, rightText.c_str()); | |||
NVGcolor rightColor = (state == BND_DEFAULT && !disabled) ? bndGetTheme()->menuTheme.textColor : bndGetTheme()->menuTheme.textSelectedColor; | |||
bndIconLabelValue(vg, x, 0.0, box.size.x, box.size.y, -1, rightColor, BND_LEFT, BND_LABEL_FONT_SIZE, rightText.c_str(), NULL); | |||
bndIconLabelValue(ctx.vg, x, 0.0, box.size.x, box.size.y, -1, rightColor, BND_LEFT, BND_LABEL_FONT_SIZE, rightText.c_str(), NULL); | |||
} | |||
void MenuItem::step() { | |||
@@ -5,8 +5,8 @@ | |||
namespace rack { | |||
void MenuLabel::draw(NVGcontext *vg) { | |||
bndMenuLabel(vg, 0.0, 0.0, box.size.x, box.size.y, -1, text.c_str()); | |||
void MenuLabel::draw(const DrawContext &ctx) { | |||
bndMenuLabel(ctx.vg, 0.0, 0.0, box.size.x, box.size.y, -1, text.c_str()); | |||
} | |||
void MenuLabel::step() { | |||
@@ -8,14 +8,14 @@ MenuSeparator::MenuSeparator() { | |||
box.size.y = BND_WIDGET_HEIGHT / 2; | |||
} | |||
void MenuSeparator::draw(NVGcontext *vg) { | |||
nvgBeginPath(vg); | |||
void MenuSeparator::draw(const DrawContext &ctx) { | |||
nvgBeginPath(ctx.vg); | |||
const float margin = 8.0; | |||
nvgMoveTo(vg, margin, box.size.y / 2.0); | |||
nvgLineTo(vg, box.size.x - margin, box.size.y / 2.0); | |||
nvgStrokeWidth(vg, 1.0); | |||
nvgStrokeColor(vg, color::alpha(bndGetTheme()->menuTheme.textColor, 0.25)); | |||
nvgStroke(vg); | |||
nvgMoveTo(ctx.vg, margin, box.size.y / 2.0); | |||
nvgLineTo(ctx.vg, box.size.x - margin, box.size.y / 2.0); | |||
nvgStrokeWidth(ctx.vg, 1.0); | |||
nvgStrokeColor(ctx.vg, color::alpha(bndGetTheme()->menuTheme.textColor, 0.25)); | |||
nvgStroke(ctx.vg); | |||
} | |||
@@ -4,10 +4,10 @@ | |||
namespace rack { | |||
void PasswordField::draw(NVGcontext *vg) { | |||
void PasswordField::draw(const DrawContext &ctx) { | |||
std::string textTmp = text; | |||
text = std::string(textTmp.size(), '*'); | |||
TextField::draw(vg); | |||
TextField::draw(ctx); | |||
text = textTmp; | |||
} | |||
@@ -13,10 +13,10 @@ ProgressBar::~ProgressBar() { | |||
delete quantity; | |||
} | |||
void ProgressBar::draw(NVGcontext *vg) { | |||
void ProgressBar::draw(const DrawContext &ctx) { | |||
float progress = quantity ? quantity->getScaledValue() : 0.f; | |||
std::string text = quantity ? quantity->getString() : ""; | |||
bndSlider(vg, 0.0, 0.0, box.size.x, box.size.y, BND_CORNER_ALL, BND_DEFAULT, progress, text.c_str(), NULL); | |||
bndSlider(ctx.vg, 0.0, 0.0, box.size.x, box.size.y, BND_CORNER_ALL, BND_DEFAULT, progress, text.c_str(), NULL); | |||
} | |||
@@ -13,11 +13,11 @@ RadioButton::~RadioButton() { | |||
delete quantity; | |||
} | |||
void RadioButton::draw(NVGcontext *vg) { | |||
void RadioButton::draw(const DrawContext &ctx) { | |||
std::string label; | |||
if (quantity) | |||
label = quantity->getLabel(); | |||
bndRadioButton(vg, 0.0, 0.0, box.size.x, box.size.y, BND_CORNER_NONE, state, -1, label.c_str()); | |||
bndRadioButton(ctx.vg, 0.0, 0.0, box.size.x, box.size.y, BND_CORNER_NONE, state, -1, label.c_str()); | |||
} | |||
void RadioButton::onEnter(const event::Enter &e) { | |||
@@ -14,8 +14,8 @@ ScrollBar::ScrollBar() { | |||
box.size = math::Vec(BND_SCROLLBAR_WIDTH, BND_SCROLLBAR_HEIGHT); | |||
} | |||
void ScrollBar::draw(NVGcontext *vg) { | |||
bndScrollBar(vg, 0.0, 0.0, box.size.x, box.size.y, state, offset, size); | |||
void ScrollBar::draw(const DrawContext &ctx) { | |||
bndScrollBar(ctx.vg, 0.0, 0.0, box.size.x, box.size.y, state, offset, size); | |||
} | |||
void ScrollBar::onDragStart(const event::DragStart &e) { | |||
@@ -26,10 +26,10 @@ void ScrollWidget::scrollTo(math::Rect r) { | |||
offset = offset.clampSafe(bound); | |||
} | |||
void ScrollWidget::draw(NVGcontext *vg) { | |||
nvgScissor(vg, 0, 0, box.size.x, box.size.y); | |||
Widget::draw(vg); | |||
nvgResetScissor(vg); | |||
void ScrollWidget::draw(const DrawContext &ctx) { | |||
nvgScissor(ctx.vg, 0, 0, box.size.x, box.size.y); | |||
Widget::draw(ctx); | |||
nvgResetScissor(ctx.vg); | |||
} | |||
void ScrollWidget::step() { | |||
@@ -16,10 +16,10 @@ Slider::~Slider() { | |||
delete quantity; | |||
} | |||
void Slider::draw(NVGcontext *vg) { | |||
void Slider::draw(const DrawContext &ctx) { | |||
float progress = quantity ? quantity->getScaledValue() : 0.f; | |||
std::string text = quantity ? quantity->getString() : ""; | |||
bndSlider(vg, 0.0, 0.0, box.size.x, box.size.y, BND_CORNER_NONE, state, progress, text.c_str(), NULL); | |||
bndSlider(ctx.vg, 0.0, 0.0, box.size.x, box.size.y, BND_CORNER_NONE, state, progress, text.c_str(), NULL); | |||
} | |||
void Slider::onDragStart(const event::DragStart &e) { | |||
@@ -7,8 +7,8 @@ TextField::TextField() { | |||
box.size.y = BND_WIDGET_HEIGHT; | |||
} | |||
void TextField::draw(NVGcontext *vg) { | |||
nvgScissor(vg, 0, 0, box.size.x, box.size.y); | |||
void TextField::draw(const DrawContext &ctx) { | |||
nvgScissor(ctx.vg, 0, 0, box.size.x, box.size.y); | |||
BNDwidgetState state; | |||
if (this == app()->event->selectedWidget) | |||
@@ -20,13 +20,13 @@ void TextField::draw(NVGcontext *vg) { | |||
int begin = std::min(cursor, selection); | |||
int end = std::max(cursor, selection); | |||
bndTextField(vg, 0.0, 0.0, box.size.x, box.size.y, BND_CORNER_NONE, state, -1, text.c_str(), begin, end); | |||
bndTextField(ctx.vg, 0.0, 0.0, box.size.x, box.size.y, BND_CORNER_NONE, state, -1, text.c_str(), begin, end); | |||
// Draw placeholder text | |||
if (text.empty() && state != BND_ACTIVE) { | |||
bndIconLabelCaret(vg, 0.0, 0.0, box.size.x, box.size.y, -1, bndGetTheme()->textFieldTheme.itemColor, 13, placeholder.c_str(), bndGetTheme()->textFieldTheme.itemColor, 0, -1); | |||
bndIconLabelCaret(ctx.vg, 0.0, 0.0, box.size.x, box.size.y, -1, bndGetTheme()->textFieldTheme.itemColor, 13, placeholder.c_str(), bndGetTheme()->textFieldTheme.itemColor, 0, -1); | |||
} | |||
nvgResetScissor(vg); | |||
nvgResetScissor(ctx.vg); | |||
} | |||
void TextField::onButton(const event::Button &e) { | |||
@@ -13,10 +13,10 @@ void Tooltip::step() { | |||
Widget::step(); | |||
} | |||
void Tooltip::draw(NVGcontext *vg) { | |||
bndTooltipBackground(vg, 0.0, 0.0, box.size.x, box.size.y); | |||
bndMenuLabel(vg, 0.0, 0.0, box.size.x, box.size.y, -1, text.c_str()); | |||
Widget::draw(vg); | |||
void Tooltip::draw(const DrawContext &ctx) { | |||
bndTooltipBackground(ctx.vg, 0.0, 0.0, box.size.x, box.size.y); | |||
bndMenuLabel(ctx.vg, 0.0, 0.0, box.size.x, box.size.y, -1, text.c_str()); | |||
Widget::draw(ctx); | |||
} | |||
@@ -14,17 +14,17 @@ FramebufferWidget::~FramebufferWidget() { | |||
nvgluDeleteFramebuffer(fb); | |||
} | |||
void FramebufferWidget::draw(NVGcontext *vg) { | |||
void FramebufferWidget::draw(const DrawContext &ctx) { | |||
// Bypass framebuffer rendering if we're already drawing in a framebuffer | |||
// In other words, disallow nested framebuffers. They look bad. | |||
if (vg == app()->window->fbVg) { | |||
Widget::draw(vg); | |||
if (ctx.vg == app()->window->fbVg) { | |||
Widget::draw(ctx); | |||
return; | |||
} | |||
// Get world transform | |||
float xform[6]; | |||
nvgCurrentTransform(vg, xform); | |||
nvgCurrentTransform(ctx.vg, xform); | |||
// Skew and rotate is not supported | |||
assert(math::isNear(xform[1], 0.f)); | |||
assert(math::isNear(xform[2], 0.f)); | |||
@@ -65,7 +65,7 @@ void FramebufferWidget::draw(NVGcontext *vg) { | |||
nvgluDeleteFramebuffer(fb); | |||
// Create a framebuffer from the main nanovg context. We will draw to this in the secondary nanovg context. | |||
if (fbSize.isFinite() && !fbSize.isZero()) | |||
fb = nvgluCreateFramebuffer(vg, fbSize.x, fbSize.y, 0); | |||
fb = nvgluCreateFramebuffer(ctx.vg, fbSize.x, fbSize.y, 0); | |||
} | |||
if (!fb) | |||
@@ -80,28 +80,28 @@ void FramebufferWidget::draw(NVGcontext *vg) { | |||
return; | |||
// Draw framebuffer image, using world coordinates | |||
nvgSave(vg); | |||
nvgResetTransform(vg); | |||
nvgSave(ctx.vg); | |||
nvgResetTransform(ctx.vg); | |||
nvgBeginPath(vg); | |||
nvgRect(vg, | |||
nvgBeginPath(ctx.vg); | |||
nvgRect(ctx.vg, | |||
offsetI.x + fbBox.pos.x, | |||
offsetI.y + fbBox.pos.y, | |||
fbBox.size.x, fbBox.size.y); | |||
NVGpaint paint = nvgImagePattern(vg, | |||
NVGpaint paint = nvgImagePattern(ctx.vg, | |||
offsetI.x + fbBox.pos.x, | |||
offsetI.y + fbBox.pos.y, | |||
fbBox.size.x, fbBox.size.y, | |||
0.0, fb->image, 1.0); | |||
nvgFillPaint(vg, paint); | |||
nvgFill(vg); | |||
nvgFillPaint(ctx.vg, paint); | |||
nvgFill(ctx.vg); | |||
// For debugging the bounding box of the framebuffer | |||
// nvgStrokeWidth(vg, 2.0); | |||
// nvgStrokeColor(vg, nvgRGBAf(1, 1, 0, 0.5)); | |||
// nvgStroke(vg); | |||
// nvgStrokeWidth(ctx.vg, 2.0); | |||
// nvgStrokeColor(ctx.vg, nvgRGBAf(1, 1, 0, 0.5)); | |||
// nvgStroke(ctx.vg); | |||
nvgRestore(vg); | |||
nvgRestore(ctx.vg); | |||
} | |||
void FramebufferWidget::drawFramebuffer() { | |||
@@ -115,7 +115,9 @@ void FramebufferWidget::drawFramebuffer() { | |||
nvgTranslate(vg, fbOffset.x, fbOffset.y); | |||
nvgScale(vg, fbScale.x, fbScale.y); | |||
Widget::draw(vg); | |||
DrawContext ctx; | |||
ctx.vg = vg; | |||
Widget::draw(ctx); | |||
glViewport(0.0, 0.0, fbSize.x, fbSize.y); | |||
glClearColor(0.0, 0.0, 0.0, 0.0); | |||
@@ -93,7 +93,7 @@ void Widget::step() { | |||
} | |||
} | |||
void Widget::draw(NVGcontext *vg) { | |||
void Widget::draw(const DrawContext &ctx) { | |||
for (Widget *child : children) { | |||
// Don't draw if invisible | |||
if (!child->visible) | |||
@@ -102,19 +102,26 @@ void Widget::draw(NVGcontext *vg) { | |||
if (!box.zeroPos().intersects(child->box)) | |||
continue; | |||
nvgSave(vg); | |||
nvgTranslate(vg, child->box.pos.x, child->box.pos.y); | |||
child->draw(vg); | |||
nvgSave(ctx.vg); | |||
nvgTranslate(ctx.vg, child->box.pos.x, child->box.pos.y); | |||
DrawContext childCtx = ctx; | |||
child->draw(childCtx); | |||
#pragma GCC diagnostic push | |||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations" | |||
child->draw(ctx.vg); | |||
#pragma GCC diagnostic pop | |||
// Draw red hitboxes | |||
// if (app()->event->hoveredWidget == child) { | |||
// nvgBeginPath(vg); | |||
// nvgRect(vg, 0, 0, child->box.size.x, child->box.size.y); | |||
// nvgFillColor(vg, nvgRGBAf(1, 0, 0, 0.5)); | |||
// nvgFill(vg); | |||
// nvgBeginPath(ctx.vg); | |||
// nvgRect(ctx.vg, 0, 0, child->box.size.x, child->box.size.y); | |||
// nvgFillColor(ctx.vg, nvgRGBAf(1, 0, 0, 0.5)); | |||
// nvgFill(ctx.vg); | |||
// } | |||
nvgRestore(vg); | |||
nvgRestore(ctx.vg); | |||
} | |||
} | |||
@@ -28,10 +28,10 @@ void ZoomWidget::setZoom(float zoom) { | |||
Widget::onZoom(eZoom); | |||
} | |||
void ZoomWidget::draw(NVGcontext *vg) { | |||
void ZoomWidget::draw(const DrawContext &ctx) { | |||
// No need to save the state because that is done in the parent | |||
nvgScale(vg, zoom, zoom); | |||
Widget::draw(vg); | |||
nvgScale(ctx.vg, zoom, zoom); | |||
Widget::draw(ctx); | |||
} | |||
@@ -359,7 +359,9 @@ void Window::run() { | |||
// nvgReset(vg); | |||
// nvgScale(vg, pixelRatio, pixelRatio); | |||
app()->event->rootWidget->draw(vg); | |||
DrawContext ctx; | |||
ctx.vg = vg; | |||
app()->event->rootWidget->draw(ctx); | |||
glViewport(0, 0, fbWidth, fbHeight); | |||
glClearColor(0.0, 0.0, 0.0, 1.0); | |||