Browse Source

Add SVGSlider, SVGSwitch, attempt SVG gradients

tags/v0.3.0
Andrew Belt 8 years ago
parent
commit
6e4cddc4e1
14 changed files with 233 additions and 109 deletions
  1. +55
    -21
      include/app.hpp
  2. +46
    -51
      include/components.hpp
  3. +3
    -0
      include/math.hpp
  4. +2
    -2
      include/rack.hpp
  5. +1
    -1
      include/widgets.hpp
  6. +1
    -1
      src/app/Knob.cpp
  7. +1
    -0
      src/app/Port.cpp
  8. +3
    -2
      src/app/SVGKnob.cpp
  9. +3
    -6
      src/app/SVGPort.cpp
  10. +15
    -0
      src/app/SVGScrew.cpp
  11. +30
    -0
      src/app/SVGSlider.cpp
  12. +33
    -0
      src/app/SVGSwitch.cpp
  13. +8
    -15
      src/widgets/FramebufferWidget.cpp
  14. +32
    -10
      src/widgets/SVGWidget.cpp

+ 55
- 21
include/app.hpp View File

@@ -124,6 +124,7 @@ struct ParamWidget : OpaqueWidget, QuantityWidget {
void onChange(); void onChange();
}; };


/** Implements vertical dragging behavior for ParamWidgets */
struct Knob : ParamWidget { struct Knob : ParamWidget {
void onDragStart(); void onDragStart();
void onDragMove(Vec mouseRel); void onDragMove(Vec mouseRel);
@@ -150,42 +151,76 @@ struct SVGKnob : Knob, FramebufferWidget {
void onChange(); void onChange();
}; };


struct Switch : ParamWidget, SpriteWidget {
struct SVGSlider : Knob, FramebufferWidget {
/** Intermediate positions will be interpolated between these positions */
Vec minHandlePos, maxHandlePos;
/** Not owned */
SVGWidget *background;
SVGWidget *handle;

SVGSlider();
void step();
void onChange();
}; };


struct SVGSwitch : ParamWidget, FramebufferWidget {
struct Switch : ParamWidget {
virtual void setIndex(int index) {}
};

struct SVGSwitch : virtual Switch, FramebufferWidget {
std::vector<std::shared_ptr<SVG>> frames;
/** Not owned */ /** Not owned */
TransformWidget *tw;
SVGWidget *swPressed;
SVGWidget *swReleased;
SVGWidget *sw;

SVGSwitch();
/** Adds an SVG file to represent the next switch position */
void addFrame(std::shared_ptr<SVG> svg);
void setIndex(int index);
void step();
}; };


/** A switch that cycles through each mechanical position */
struct ToggleSwitch : virtual Switch { struct ToggleSwitch : virtual Switch {
void onDragStart() { void onDragStart() {
index = 1;
// Cycle through values
// e.g. a range of [0.0, 3.0] would have modes 0, 1, 2, and 3.
float v = value + 1.0;
setValue(v <= maxValue ? v : minValue);
}
void onChange() {
int index = (int)roundf(value);
setIndex(index);
ParamWidget::onChange();
}
};

/** FIXME I don't think this should exist. The audio engine should read from a MomentarySwitch and increment its internal state, instead of relying on the knob to do that logic. */
struct ModeSwitch : virtual Switch {
void onDragStart() {
setIndex(1);
} }
void onDragEnd() { void onDragEnd() {
index = 0;
setIndex(0);
} }
void onDragDrop(Widget *origin) { void onDragDrop(Widget *origin) {
if (origin != this) if (origin != this)
return; return;

// Cycle through modes
// Cycle through values
// e.g. a range of [0.0, 3.0] would have modes 0, 1, 2, and 3. // e.g. a range of [0.0, 3.0] would have modes 0, 1, 2, and 3.
float v = value + 1.0; float v = value + 1.0;
setValue(v > maxValue ? minValue : v);
setValue(v <= maxValue ? v : minValue);
} }
}; };


/** A switch that is turned on when held */
struct MomentarySwitch : virtual Switch { struct MomentarySwitch : virtual Switch {
void onDragStart() { void onDragStart() {
setValue(maxValue); setValue(maxValue);
index = 1;
setIndex(1);
} }
void onDragEnd() { void onDragEnd() {
setValue(minValue); setValue(minValue);
index = 0;
setIndex(0);
} }
}; };


@@ -218,21 +253,20 @@ struct Port : OpaqueWidget {
void onDragLeave(Widget *origin); void onDragLeave(Widget *origin);
}; };


struct SpritePort : Port, SpriteWidget {
void draw(NVGcontext *vg) {
Port::draw(vg);
SpriteWidget::draw(vg);
}
};

struct SVGPort : Port, FramebufferWidget { struct SVGPort : Port, FramebufferWidget {
SVGWidget *sw;
SVGWidget *background;


SVGPort(); SVGPort();
void setSVG(std::shared_ptr<SVG> svg);
void draw(NVGcontext *vg); void draw(NVGcontext *vg);
}; };


/** If you don't add these to your ModuleWidget, they will fall out of the rack... */
struct SVGScrew : FramebufferWidget {
SVGWidget *sw;

SVGScrew();
};

//////////////////// ////////////////////
// scene // scene
//////////////////// ////////////////////


+ 46
- 51
include/components.hpp View File

@@ -313,15 +313,17 @@ struct BefacoTinyKnob : SVGKnob {
} }
}; };


struct BefacoSlidePot : SpriteKnob {
struct BefacoSlidePot : SVGSlider {
BefacoSlidePot() { BefacoSlidePot() {
box.size = Vec(12, 122);
spriteOffset = Vec(-2, -6);
spriteSize = Vec(18, 134);
minIndex = 97;
maxIndex = 0;
spriteCount = 98;
spriteImage = Image::load("res/ComponentLibrary/BefacoSlidePot.png");
Vec margin = Vec(3.5, 3.5);
maxHandlePos = Vec(-1, -2).plus(margin);
minHandlePos = Vec(-1, 87).plus(margin);
background->svg = SVG::load("res/ComponentLibrary/BefacoSlidePot.svg");
background->wrap();
background->box.pos = margin;
box.size = background->box.size.plus(margin.mult(2));
handle->svg = SVG::load("res/ComponentLibrary/BefacoSlidePotHandle.svg");
handle->wrap();
} }
}; };


@@ -329,33 +331,30 @@ struct BefacoSlidePot : SpriteKnob {
// Jacks // Jacks
//////////////////// ////////////////////


struct PJ301MPort : SpritePort {
struct PJ301MPort : SVGPort {
PJ301MPort() { PJ301MPort() {
box.size = Vec(24, 24);
spriteOffset = Vec(-2, -2);
spriteSize = Vec(30, 30);
spriteImage = Image::load("res/ComponentLibrary/PJ301M.png");
// setSVG(SVG::load("res/ComponentLibrary/PJ301M.svg"));
padding = Vec(1, 1);
background->svg = SVG::load("res/ComponentLibrary/PJ301M.svg");
background->wrap();
box.size = background->box.size;
} }
}; };


struct PJ3410Port : SpritePort {
struct PJ3410Port : SVGPort {
PJ3410Port() { PJ3410Port() {
box.size = Vec(32, 31);
spriteOffset = Vec(-1, -1);
spriteSize = Vec(36, 36);
spriteImage = Image::load("res/ComponentLibrary/PJ3410.png");
// setSVG(SVG::load("res/ComponentLibrary/PJ3410.svg"));
padding = Vec(1, 1);
background->svg = SVG::load("res/ComponentLibrary/PJ3410.svg");
background->wrap();
box.size = background->box.size;
} }
}; };


struct CL1362Port : SpritePort {
struct CL1362Port : SVGPort {
CL1362Port() { CL1362Port() {
box.size = Vec(33, 29);
spriteOffset = Vec(-2, -2);
spriteSize = Vec(39, 36);
spriteImage = Image::load("res/ComponentLibrary/CL1362.png");
// setSVG(SVG::load("res/ComponentLibrary/CL1362.svg"));
padding = Vec(1, 1);
background->svg = SVG::load("res/ComponentLibrary/CL1362.svg");
background->wrap();
box.size = background->box.size;
} }
}; };


@@ -417,45 +416,41 @@ struct SmallLight : BASE {
// Switches // Switches
//////////////////// ////////////////////


// struct BefacoBigKnob : {
// BefacoBigKnob() {
// box.size = Vec(75, 75);
// minAngle = -0.75*M_PI;
// maxAngle = 0.75*M_PI;
// setSVG(SVG::load("res/ComponentLibrary/BefacoBigKnob.svg"));
// }
// };
struct NKK : SVGSwitch, ToggleSwitch {
NKK() {
addFrame(SVG::load("res/ComponentLibrary/NKK0.svg"));
addFrame(SVG::load("res/ComponentLibrary/NKK1.svg"));
addFrame(SVG::load("res/ComponentLibrary/NKK2.svg"));
sw->wrap();
box.size = sw->box.size;
}
};




//////////////////// ////////////////////
// Misc // Misc
//////////////////// ////////////////////


/** If you don't add these to your ModuleWidget, it will fall out of the rack... */
struct Screw : SpriteWidget {
Screw() {
box.size = Vec(15, 14);
spriteOffset = Vec(0, 0);
spriteSize = Vec(15, 14);
}
};

struct BlackScrew : Screw {
BlackScrew() {
spriteImage = Image::load("res/ComponentLibrary/ScrewBlack.png");
struct ScrewSilver : SVGScrew {
ScrewSilver() {
sw->svg = SVG::load("res/ComponentLibrary/ScrewSilver.svg");
sw->wrap();
box.size = sw->box.size;
} }
}; };


struct SilverScrew : Screw {
SilverScrew() {
spriteImage = Image::load("res/ComponentLibrary/ScrewSilver.png");
struct ScrewBlack : SVGScrew {
ScrewBlack() {
sw->svg = SVG::load("res/ComponentLibrary/ScrewBlack.svg");
sw->wrap();
box.size = sw->box.size;
} }
}; };


struct LightPanel : Panel { struct LightPanel : Panel {
LightPanel() { LightPanel() {
backgroundColor = nvgRGB(0xf2, 0xf2, 0xf2);
borderColor = nvgRGB(0xb8, 0xb8, 0xb8);
backgroundColor = nvgRGB(0xe8, 0xe8, 0xe8);
borderColor = nvgRGB(0xac, 0xac, 0xac);
} }
}; };




+ 3
- 0
include/math.hpp View File

@@ -191,6 +191,9 @@ struct Rect {


Rect() {} Rect() {}
Rect(Vec pos, Vec size) : pos(pos), size(size) {} Rect(Vec pos, Vec size) : pos(pos), size(size) {}
static Rect fromMinMax(Vec min, Vec max) {
return Rect(min, max.minus(min));
}


/** Returns whether this Rect contains another Rect, inclusive on the top/left, non-inclusive on the bottom/right */ /** Returns whether this Rect contains another Rect, inclusive on the top/left, non-inclusive on the bottom/right */
bool contains(Vec v) { bool contains(Vec v) {


+ 2
- 2
include/rack.hpp View File

@@ -69,8 +69,8 @@ Port *createOutput(Vec pos, Module *module, int outputId) {
} }


template <class TScrew> template <class TScrew>
Screw *createScrew(Vec pos) {
Screw *screw = new TScrew();
Widget *createScrew(Vec pos) {
Widget *screw = new TScrew();
screw->box.pos = pos; screw->box.pos = pos;
return screw; return screw;
} }


+ 1
- 1
include/widgets.hpp View File

@@ -195,7 +195,7 @@ struct FramebufferWidget : virtual Widget {
/** A margin in pixels around the children in the framebuffer /** A margin in pixels around the children in the framebuffer
This prevents cutting the rendered SVG off on the box edges. This prevents cutting the rendered SVG off on the box edges.
*/ */
int margin = 0;
Vec padding;
/** The root object in the framebuffer scene /** The root object in the framebuffer scene
The FramebufferWidget owns the pointer The FramebufferWidget owns the pointer
*/ */


+ 1
- 1
src/app/Knob.cpp View File

@@ -6,7 +6,7 @@


namespace rack { namespace rack {


#define KNOB_SENSITIVITY 0.001
#define KNOB_SENSITIVITY 0.0015




void Knob::onDragStart() { void Knob::onDragStart() {


+ 1
- 0
src/app/Port.cpp View File

@@ -21,6 +21,7 @@ void Port::disconnect() {


void Port::draw(NVGcontext *vg) { void Port::draw(NVGcontext *vg) {
if (gRackWidget->activeWire) { if (gRackWidget->activeWire) {
// Dim the Port if the active wire cannot plug into this Port
if (type == INPUT ? gRackWidget->activeWire->inputPort : gRackWidget->activeWire->outputPort) if (type == INPUT ? gRackWidget->activeWire->inputPort : gRackWidget->activeWire->outputPort)
nvgGlobalAlpha(vg, 0.5); nvgGlobalAlpha(vg, 0.5);
} }


+ 3
- 2
src/app/SVGKnob.cpp View File

@@ -5,12 +5,13 @@ namespace rack {




SVGKnob::SVGKnob() { SVGKnob::SVGKnob() {
margin = 4;
padding = Vec(1, 1);


shadow = new CircularShadow(); shadow = new CircularShadow();
shadow->blur = 5.0; shadow->blur = 5.0;
shadow->box.pos = Vec(0, 1); shadow->box.pos = Vec(0, 1);
addChild(shadow);
// TODO Remove shadow entirely
// addChild(shadow);


tw = new TransformWidget(); tw = new TransformWidget();
addChild(tw); addChild(tw);


+ 3
- 6
src/app/SVGPort.cpp View File

@@ -5,13 +5,10 @@ namespace rack {




SVGPort::SVGPort() { SVGPort::SVGPort() {
sw = new SVGWidget();
addChild(sw);
}
padding = Vec(1, 1);


void SVGPort::setSVG(std::shared_ptr<SVG> svg) {
sw->svg = svg;
sw->wrap();
background = new SVGWidget();
addChild(background);
} }


void SVGPort::draw(NVGcontext *vg) { void SVGPort::draw(NVGcontext *vg) {


+ 15
- 0
src/app/SVGScrew.cpp View File

@@ -0,0 +1,15 @@
#include "app.hpp"


namespace rack {


SVGScrew::SVGScrew() {
padding = Vec(1, 1);

sw = new SVGWidget();
addChild(sw);
}


} // namespace rack

+ 30
- 0
src/app/SVGSlider.cpp View File

@@ -0,0 +1,30 @@
#include "app.hpp"


namespace rack {


SVGSlider::SVGSlider() {
background = new SVGWidget();
addChild(background);

handle = new SVGWidget();
addChild(handle);
}

void SVGSlider::step() {
if (dirty) {
// Update handle position
Vec handlePos = Vec(mapf(value, minValue, maxValue, minHandlePos.x, maxHandlePos.x), mapf(value, minValue, maxValue, minHandlePos.y, maxHandlePos.y));
handle->box.pos = handlePos;
}
FramebufferWidget::step();
}

void SVGSlider::onChange() {
dirty = true;
ParamWidget::onChange();
}


} // namespace rack

+ 33
- 0
src/app/SVGSwitch.cpp View File

@@ -0,0 +1,33 @@
#include "app.hpp"


namespace rack {


SVGSwitch::SVGSwitch() {
padding = Vec(1, 1);

sw = new SVGWidget();
addChild(sw);
}

void SVGSwitch::addFrame(std::shared_ptr<SVG> svg) {
frames.push_back(svg);
// Automatically set the frame as this SVG file.
// This allows us to wrap() the widget after calling
if (!sw->svg)
sw->svg = svg;
}

void SVGSwitch::setIndex(int index) {
if (0 <= index && index < (int)frames.size())
sw->svg = frames[index];
dirty = true;
}

void SVGSwitch::step() {
FramebufferWidget::step();
}


} // namespace rack

+ 8
- 15
src/widgets/FramebufferWidget.cpp View File

@@ -10,7 +10,6 @@ namespace rack {


struct FramebufferWidget::Internal { struct FramebufferWidget::Internal {
NVGLUframebuffer *fb = NULL; NVGLUframebuffer *fb = NULL;
Vec offset;


~Internal() { ~Internal() {
setFramebuffer(NULL); setFramebuffer(NULL);
@@ -31,22 +30,16 @@ FramebufferWidget::~FramebufferWidget() {
} }


void FramebufferWidget::step() { void FramebufferWidget::step() {
if (children.empty())
return;

// Step children before rendering // Step children before rendering
Widget::step(); Widget::step();


// Render the scene to the framebuffer if dirty // Render the scene to the framebuffer if dirty
if (dirty) { if (dirty) {
Rect childrenBox = getChildrenBoundingBox();
assert(childrenBox.size.isFinite());
int width = ceilf(childrenBox.size.x) + 2*margin;
int height = ceilf(childrenBox.size.y) + 2*margin;
internal->offset = childrenBox.pos.minus(Vec(margin, margin));
Vec fbSize = box.size.plus(padding.mult(2));
assert(fbSize.isFinite());


internal->setFramebuffer(NULL); internal->setFramebuffer(NULL);
NVGLUframebuffer *fb = nvgluCreateFramebuffer(gVg, width, height, NVG_IMAGE_REPEATX | NVG_IMAGE_REPEATY);
NVGLUframebuffer *fb = nvgluCreateFramebuffer(gVg, fbSize.x, fbSize.y, NVG_IMAGE_REPEATX | NVG_IMAGE_REPEATY);
if (!fb) if (!fb)
return; return;
internal->setFramebuffer(fb); internal->setFramebuffer(fb);
@@ -54,12 +47,12 @@ void FramebufferWidget::step() {
// TODO Support screens with pixelRatio != 1.0 (e.g. Retina) by using the actual size of the framebuffer, etc. // TODO Support screens with pixelRatio != 1.0 (e.g. Retina) by using the actual size of the framebuffer, etc.
const float pixelRatio = 1.0; const float pixelRatio = 1.0;
nvgluBindFramebuffer(fb); nvgluBindFramebuffer(fb);
glViewport(0.0, 0.0, width, height);
glViewport(0.0, 0.0, fbSize.x, fbSize.y);
glClearColor(0.0, 0.0, 0.0, 0.0); glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
nvgBeginFrame(gVg, width, height, pixelRatio);
nvgBeginFrame(gVg, fbSize.x, fbSize.y, pixelRatio);


nvgTranslate(gVg, -internal->offset.x, -internal->offset.y);
nvgTranslate(gVg, padding.x, padding.y);
Widget::draw(gVg); Widget::draw(gVg);


nvgEndFrame(gVg); nvgEndFrame(gVg);
@@ -77,8 +70,8 @@ void FramebufferWidget::draw(NVGcontext *vg) {
int width, height; int width, height;
nvgImageSize(vg, internal->fb->image, &width, &height); nvgImageSize(vg, internal->fb->image, &width, &height);
nvgBeginPath(vg); nvgBeginPath(vg);
nvgRect(vg, internal->offset.x, internal->offset.y, width, height);
NVGpaint paint = nvgImagePattern(vg, internal->offset.x, internal->offset.y, width, height, 0.0, internal->fb->image, 1.0);
nvgRect(vg, -padding.x, -padding.y, width, height);
NVGpaint paint = nvgImagePattern(vg, -padding.x, -padding.y, width, height, 0.0, internal->fb->image, 1.0);
nvgFillPaint(vg, paint); nvgFillPaint(vg, paint);
nvgFill(vg); nvgFill(vg);




+ 32
- 10
src/widgets/SVGWidget.cpp View File

@@ -19,7 +19,7 @@ static void drawSVG(NVGcontext *vg, NSVGimage *svg) {
DEBUG_ONLY(printf("new image: %g x %g px\n", svg->width, svg->height);) DEBUG_ONLY(printf("new image: %g x %g px\n", svg->width, svg->height);)
int shapeIndex = 0; int shapeIndex = 0;
for (NSVGshape *shape = svg->shapes; shape; shape = shape->next, shapeIndex++) { for (NSVGshape *shape = svg->shapes; shape; shape = shape->next, shapeIndex++) {
DEBUG_ONLY(printf(" new shape: %d id \"%s\", fillrule %d\n", shapeIndex, shape->id, shape->fillRule);)
DEBUG_ONLY(printf(" new shape: %d id \"%s\", fillrule %d, from (%f, %f) to (%f, %f)\n", shapeIndex, shape->id, shape->fillRule, shape->bounds[0], shape->bounds[1], shape->bounds[2], shape->bounds[3]);)


if (!(shape->flags & NSVG_FLAGS_VISIBLE)) if (!(shape->flags & NSVG_FLAGS_VISIBLE))
continue; continue;
@@ -29,14 +29,10 @@ static void drawSVG(NVGcontext *vg, NSVGimage *svg) {
if (shape->opacity < 1.0) if (shape->opacity < 1.0)
nvgGlobalAlpha(vg, shape->opacity); nvgGlobalAlpha(vg, shape->opacity);


nvgStrokeWidth(vg, shape->strokeWidth);
// strokeDashOffset, strokeDashArray, strokeDashCount not yet supported
// strokeLineJoin, strokeLineCap not yet supported

// Build path // Build path
nvgBeginPath(vg); nvgBeginPath(vg);
for (NSVGpath *path = shape->paths; path; path = path->next) { for (NSVGpath *path = shape->paths; path; path = path->next) {
DEBUG_ONLY(printf(" new path: %d points, %s\n", path->npts, path->closed ? "closed" : "open");)
DEBUG_ONLY(printf(" new path: %d points, %s, from (%f, %f) to (%f, %f)\n", path->npts, path->closed ? "closed" : "open", path->bounds[0], path->bounds[1], path->bounds[2], path->bounds[3]);)


nvgMoveTo(vg, path->pts[0], path->pts[1]); nvgMoveTo(vg, path->pts[0], path->pts[1]);
for (int i = 1; i < path->npts; i += 3) { for (int i = 1; i < path->npts; i += 3) {
@@ -61,14 +57,38 @@ static void drawSVG(NVGcontext *vg, NSVGimage *svg) {
DEBUG_ONLY(printf(" fill color (%g, %g, %g, %g)\n", color.r, color.g, color.b, color.a);) DEBUG_ONLY(printf(" fill color (%g, %g, %g, %g)\n", color.r, color.g, color.b, color.a);)
} break; } break;
case NSVG_PAINT_LINEAR_GRADIENT: { case NSVG_PAINT_LINEAR_GRADIENT: {
// NSVGgradient *g = shape->fill.gradient;
// printf(" lin grad: %f\t%f\n", g->fx, g->fy);
NSVGgradient *g = shape->fill.gradient;
DEBUG_ONLY(printf(" linear gradient: %f\t%f\n", g->fx, g->fy);)
} break;
case NSVG_PAINT_RADIAL_GRADIENT: {
NSVGgradient *g = shape->fill.gradient;
DEBUG_ONLY(printf(" radial gradient: %f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\n", g->fx, g->fy, g->xform[0], g->xform[1], g->xform[2], g->xform[3], g->xform[4], g->xform[5]);)
for (int i = 0; i < g->nstops; i++) {
DEBUG_ONLY(printf(" stop: #%08x\t%f\n", g->stops[i].color, g->stops[i].offset);)
}
assert(g->nstops >= 1);
NVGcolor color0 = getNVGColor(g->stops[0].color);
NVGcolor color1 = getNVGColor(g->stops[g->nstops - 1].color);

float inverse[6];
Rect shapeBox = Rect::fromMinMax(Vec(shape->bounds[0], shape->bounds[1]), Vec(shape->bounds[2], shape->bounds[3]));
nvgTransformInverse(inverse, g->xform);
Vec c;
nvgTransformPoint(&c.x, &c.y, inverse, 5, 5);
printf("%f %f\n", c.x, c.y);

NVGpaint paint = nvgRadialGradient(vg, c.x, c.y, 0.0, 160, color0, color1);
nvgFillPaint(vg, paint);
} break; } break;
} }
nvgFill(vg); nvgFill(vg);
} }


// Stroke shape // Stroke shape
nvgStrokeWidth(vg, shape->strokeWidth);
// strokeDashOffset, strokeDashArray, strokeDashCount not yet supported
// strokeLineJoin, strokeLineCap not yet supported

if (shape->stroke.type) { if (shape->stroke.type) {
switch (shape->stroke.type) { switch (shape->stroke.type) {
case NSVG_PAINT_COLOR: { case NSVG_PAINT_COLOR: {
@@ -92,10 +112,12 @@ static void drawSVG(NVGcontext *vg, NSVGimage *svg) {




void SVGWidget::wrap() { void SVGWidget::wrap() {
if (svg)
if (svg) {
box.size = Vec(svg->handle->width, svg->handle->height); box.size = Vec(svg->handle->width, svg->handle->height);
else
}
else {
box.size = Vec(); box.size = Vec();
}
} }


void SVGWidget::draw(NVGcontext *vg) { void SVGWidget::draw(NVGcontext *vg) {


Loading…
Cancel
Save