Browse Source

Merge branch 'master' of https://github.com/VCVRack/Rack into 2017-10-bontric-midiCC-fix

tags/v0.5.0
ben 7 years ago
parent
commit
320e40db7c
12 changed files with 110 additions and 160 deletions
  1. +1
    -0
      include/app.hpp
  2. +0
    -12
      include/components.hpp
  3. +19
    -1
      include/math.hpp
  4. +16
    -11
      include/widgets.hpp
  5. +0
    -108
      res/ComponentLibrary/Davies1900hSmallBlack.svg
  6. +1
    -1
      src/app/RackScene.cpp
  7. +30
    -14
      src/app/RackWidget.cpp
  8. +1
    -1
      src/app/Toolbar.cpp
  9. +8
    -11
      src/widgets/FramebufferWidget.cpp
  10. +1
    -1
      src/widgets/Menu.cpp
  11. +19
    -0
      src/widgets/Widget.cpp
  12. +14
    -0
      src/widgets/ZoomWidget.cpp

+ 1
- 0
include/app.hpp View File

@@ -141,6 +141,7 @@ struct RackWidget : OpaqueWidget {

Widget *onMouseMove(Vec pos, Vec mouseRel) override;
void onMouseDownOpaque(int button) override;
void onZoom() override;
};

struct RackRail : TransparentWidget {


+ 0
- 12
include/components.hpp View File

@@ -107,18 +107,6 @@ struct Davies1900hLargeRedKnob : Davies1900hKnob {
}
};

struct Davies1900hSmallBlackKnob : Davies1900hKnob {
Davies1900hSmallBlackKnob() {
setSVG(SVG::load(assetGlobal("res/ComponentLibrary/Davies1900hSmallBlack.svg")));
}
};

struct Davies1900hSmallBlackSnapKnob : Davies1900hSmallBlackKnob {
Davies1900hSmallBlackSnapKnob() {
snap = true;
}
};


struct Rogan : SVGKnob {
Rogan() {


+ 19
- 1
include/math.hpp View File

@@ -197,9 +197,15 @@ struct Vec {
Vec ceil() {
return Vec(ceilf(x), ceilf(y));
}
bool isEqual(Vec b) {
return x == b.x && y == b.y;
}
bool isZero() {
return x == 0.0 && y == 0.0;
}
bool isFinite() {
return isfinite(x) && isfinite(y);
}
Vec clamp(Rect bound);
};

@@ -229,6 +235,9 @@ struct Rect {
return (pos.x + size.x > r.pos.x && r.pos.x + r.size.x > pos.x)
&& (pos.y + size.y > r.pos.y && r.pos.y + r.size.y > pos.y);
}
bool isEqual(Rect r) {
return pos.isEqual(r.pos) && size.isEqual(r.size);
}
Vec getCenter() {
return pos.plus(size.mult(0.5));
}
@@ -241,8 +250,17 @@ struct Rect {
Vec getBottomRight() {
return pos.plus(size);
}
/** Clamps the position to fix inside a bounding box */
/** Clamps the edges of the rectangle to fit within a bound */
Rect clamp(Rect bound) {
Rect r;
r.pos.x = clampf(pos.x, bound.pos.x, bound.pos.x + bound.size.x);
r.pos.y = clampf(pos.y, bound.pos.y, bound.pos.y + bound.size.y);
r.size.x = clampf(pos.x + size.x, bound.pos.x, bound.pos.x + bound.size.x) - r.pos.x;
r.size.y = clampf(pos.y + size.y, bound.pos.y, bound.pos.y + bound.size.y) - r.pos.y;
return r;
}
/** Nudges the position to fix inside a bounding box */
Rect nudge(Rect bound) {
Rect r;
r.size = size;
r.pos.x = clampf(pos.x, bound.pos.x, bound.pos.x + bound.size.x - size.x);


+ 16
- 11
include/widgets.hpp View File

@@ -58,6 +58,8 @@ struct Widget {

Vec getAbsolutePos();
Rect getChildrenBoundingBox();
/** Returns a subset of the given Rect bounded by the box of this widget and all ancestors */
virtual Rect getViewport(Rect r);

template <class T>
T *getAncestorOfType() {
@@ -131,6 +133,7 @@ struct Widget {

virtual void onAction() {}
virtual void onChange() {}
virtual void onZoom();
};

struct TransformWidget : Widget {
@@ -144,6 +147,17 @@ struct TransformWidget : Widget {
void draw(NVGcontext *vg) override;
};

struct ZoomWidget : Widget {
float zoom = 1.0;
Rect getViewport(Rect r) override;
void setZoom(float zoom);
void draw(NVGcontext *vg) override;
Widget *onMouseDown(Vec pos, int button) override;
Widget *onMouseUp(Vec pos, int button) override;
Widget *onMouseMove(Vec pos, Vec mouseRel) override;
Widget *onHoverKey(Vec pos, int key) override;
Widget *onScroll(Vec pos, Vec scrollRel) override;
};

////////////////////
// Trait widgets
@@ -214,7 +228,7 @@ When `dirty` is true, its children will be re-rendered on the next call to step(
Events are not passed to the underlying scene.
*/
struct FramebufferWidget : virtual Widget {
/** Set this to true to re-render the children to the framebuffer in the next step() override */
/** Set this to true to re-render the children to the framebuffer the next time it is drawn */
bool dirty = true;
/** The root object in the framebuffer scene
The FramebufferWidget owns the pointer
@@ -226,6 +240,7 @@ struct FramebufferWidget : virtual Widget {
~FramebufferWidget();
void draw(NVGcontext *vg) override;
int getImageHandle();
void onZoom() override;
};

struct QuantityWidget : virtual Widget {
@@ -378,16 +393,6 @@ struct ScrollWidget : OpaqueWidget {
bool onScrollOpaque(Vec scrollRel) override;
};

struct ZoomWidget : Widget {
float zoom = 1.0;
void draw(NVGcontext *vg) override;
Widget *onMouseDown(Vec pos, int button) override;
Widget *onMouseUp(Vec pos, int button) override;
Widget *onMouseMove(Vec pos, Vec mouseRel) override;
Widget *onHoverKey(Vec pos, int key) override;
Widget *onScroll(Vec pos, Vec scrollRel) override;
};

struct TextField : OpaqueWidget {
std::string text;
std::string placeholder;


+ 0
- 108
res/ComponentLibrary/Davies1900hSmallBlack.svg View File

@@ -1,108 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->

<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="7.0462589mm"
height="7.1788893mm"
viewBox="0 0 7.0462589 7.1788893"
version="1.1"
id="svg6414"
inkscape:version="0.92.1 r"
sodipodi:docname="Davies1900hSmallBlack.svg">
<defs
id="defs6408">
<clipPath
id="clip82">
<path
d="m 979.55859,272.09375 h 26.63281 v 27.13281 h -26.63281 z m 0,0"
id="path22604"
inkscape:connector-curvature="0" />
</clipPath>
<clipPath
id="clip83">
<path
d="m 992,272.09375 h 2 V 287 h -2 z m 0,0"
id="path22607"
inkscape:connector-curvature="0" />
</clipPath>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.98994949"
inkscape:cx="101.21858"
inkscape:cy="-36.897917"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:window-width="1600"
inkscape:window-height="882"
inkscape:window-x="0"
inkscape:window-y="18"
inkscape:window-maximized="0" />
<metadata
id="metadata6411">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-36.542344,-107.44627)">
<g
id="g6344"
transform="matrix(0.35277777,0,0,-0.35277777,-474.41126,963.93894)">
<g
style="clip-rule:nonzero"
id="g28551"
clip-path="url(#clip82)"
transform="matrix(0.75000002,0,0,-0.75000002,713.70253,2631.9236)">
<path
inkscape:connector-curvature="0"
id="path28547"
d="m 1005.8555,288.88281 c -1.6407,7.16406 -8.78128,11.64844 -15.94925,10.00781 -7.16797,-1.64062 -11.64844,-8.78125 -10.00781,-15.94921 1.64062,-7.16797 8.78125,-11.64844 15.94922,-10.00782 7.16794,1.64063 11.64454,8.78125 10.00784,15.94922"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none" />
<path
inkscape:connector-curvature="0"
id="path28549"
d="m 1005.8555,288.88281 c -1.6407,7.16406 -8.78128,11.64844 -15.94925,10.00781 -7.16797,-1.64062 -11.64844,-8.78125 -10.00781,-15.94921 1.64062,-7.16797 8.78125,-11.64844 15.94922,-10.00782 7.16794,1.64063 11.64454,8.78125 10.00784,15.94922"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none" />
</g>
<g
style="clip-rule:nonzero"
id="g28555"
clip-path="url(#clip83)"
transform="matrix(0.75000002,0,0,-0.75000002,713.70253,2631.9236)">
<path
inkscape:connector-curvature="0"
id="path28553"
transform="translate(992.87612,272.59527)"
d="M -0.0011146,-0.0015175 V 13.314889"
style="fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1" />
</g>
</g>
</g>
</svg>

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

@@ -63,7 +63,7 @@ void RackScene::step() {
.div(zoomWidget->zoom);

// Set zoom from the toolbar's zoom slider
zoomWidget->zoom = gToolbar->zoomSlider->value / 100.0;
zoomWidget->setZoom(gToolbar->zoomSlider->value / 100.0);

Scene::step();



+ 30
- 14
src/app/RackWidget.cpp View File

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

RackWidget::RackWidget() {
rails = new FramebufferWidget();
RackRail *rail = new RackRail();
rail->box.size = Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT);
rails->addChild(rail);
rails->box.size = rail->box.size;
rails->box.size = Vec();
{
RackRail *rail = new RackRail();
rail->box.size = Vec();
rails->addChild(rail);
}
addChild(rails);

moduleContainer = new Widget();
addChild(moduleContainer);
@@ -29,7 +32,6 @@ RackWidget::RackWidget() {
}

RackWidget::~RackWidget() {
delete rails;
}

void RackWidget::clear() {
@@ -333,13 +335,29 @@ bool RackWidget::requestModuleBoxNearest(ModuleWidget *m, Rect box) {
}

void RackWidget::step() {
rails->step();

// Expand size to fit modules
Vec moduleSize = moduleContainer->getChildrenBoundingBox().getBottomRight();
// We assume that the size is reset by a parent before calling step(). Otherwise it will grow unbounded.
box.size = box.size.max(moduleSize);

// Adjust size and position of rails
Widget *rail = rails->children.front();
Rect bound = getViewport(Rect(Vec(), box.size));
if (!rails->box.contains(bound)) {
// Add a margin around the otherwise tight bound, so that scrolling slightly will not require a re-render of rails.
Vec margin = Vec(100, 100);
bound.pos = bound.pos.minus(margin);
bound.size = bound.size.plus(margin.mult(2));
rails->box = bound;
// Compute offset of rail within rails framebuffer
Vec grid = Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT);
Vec gridPos = bound.pos.div(grid).floor().mult(grid);
bound.pos = gridPos.minus(bound.pos);
bound.size = bound.size.minus(bound.pos);
rail->box = bound;
rails->dirty = true;
}

// Autosave every 15 seconds
if (gGuiFrame % (60*15) == 0) {
savePatch(assetLocal("autosave.vcv"));
@@ -350,13 +368,6 @@ void RackWidget::step() {
}

void RackWidget::draw(NVGcontext *vg) {
// Draw rails
nvgBeginPath(vg);
nvgRect(vg, 0.0, 0.0, box.size.x, box.size.y);
NVGpaint paint = nvgImagePattern(vg, rails->box.pos.x, rails->box.pos.y, rails->box.size.x, rails->box.size.y, 0.0, rails->getImageHandle(), 1.0);
nvgFillPaint(vg, paint);
nvgFill(vg);

Widget::draw(vg);
}

@@ -513,5 +524,10 @@ void RackWidget::onMouseDownOpaque(int button) {
}
}

void RackWidget::onZoom() {
rails->box.size = Vec();
Widget::onZoom();
}


} // namespace rack

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

@@ -153,7 +153,7 @@ Toolbar::Toolbar() {
zoomSlider->box.size.x = 150;
zoomSlider->label = "Zoom";
zoomSlider->unit = "%";
zoomSlider->setLimits(25.0, 200.0);
zoomSlider->setLimits(33.33, 200.0);
zoomSlider->setDefaultValue(100.0);
addChild(zoomSlider);
xPos += zoomSlider->box.size.x;


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

@@ -18,7 +18,6 @@ static const float oversample = 2.0;
struct FramebufferWidget::Internal {
NVGLUframebuffer *fb = NULL;
Rect box;
Vec lastS;

~Internal() {
setFramebuffer(NULL);
@@ -47,20 +46,16 @@ void FramebufferWidget::draw(NVGcontext *vg) {
// Get world transform
float xform[6];
nvgCurrentTransform(vg, xform);
// Skew is not supported
// Skew and rotate is not supported
assert(fabsf(xform[1]) < 1e-6);
assert(fabsf(xform[2]) < 1e-6);
Vec s = Vec(xform[0], xform[3]);
Vec b = Vec(xform[4], xform[5]);

// Check if scale has changed
if (s.x != internal->lastS.x || s.y != internal->lastS.y) {
dirty = true;
}
internal->lastS = s;

// Render to framebuffer
if (dirty) {
dirty = false;

internal->box.pos = Vec(0, 0);
internal->box.size = box.size.mult(s).ceil().plus(Vec(1, 1));
Vec fbSize = internal->box.size.mult(gPixelRatio * oversample);
@@ -73,7 +68,7 @@ void FramebufferWidget::draw(NVGcontext *vg) {
// Delete old one first to free up GPU memory
internal->setFramebuffer(NULL);
// Create a framebuffer from the main nanovg context. We will draw to this in the secondary nanovg context.
NVGLUframebuffer *fb = nvgluCreateFramebuffer(gVg, fbSize.x, fbSize.y, NVG_IMAGE_REPEATX | NVG_IMAGE_REPEATY);
NVGLUframebuffer *fb = nvgluCreateFramebuffer(gVg, fbSize.x, fbSize.y, 0);
if (!fb)
return;
internal->setFramebuffer(fb);
@@ -94,8 +89,6 @@ void FramebufferWidget::draw(NVGcontext *vg) {

nvgEndFrame(gFramebufferVg);
nvgluBindFramebuffer(NULL);

dirty = false;
}

if (!internal->fb) {
@@ -128,5 +121,9 @@ int FramebufferWidget::getImageHandle() {
return internal->fb->image;
}

void FramebufferWidget::onZoom() {
dirty = true;
}


} // namespace rack

+ 1
- 1
src/widgets/Menu.cpp View File

@@ -30,7 +30,7 @@ void Menu::setChildMenu(Menu *menu) {
void Menu::step() {
// Try to fit into the parent's box
if (parent)
box = box.clamp(Rect(Vec(0, 0), parent->box.size));
box = box.nudge(Rect(Vec(0, 0), parent->box.size));

Widget::step();



+ 19
- 0
src/widgets/Widget.cpp View File

@@ -40,6 +40,18 @@ Rect Widget::getChildrenBoundingBox() {
return Rect(topLeft, bottomRight.minus(topLeft));
}

Rect Widget::getViewport(Rect r) {
Rect bound;
if (parent) {
bound = parent->getViewport(box);
}
else {
bound = box;
}
bound.pos = bound.pos.minus(box.pos);
return r.clamp(bound);
}

void Widget::addChild(Widget *widget) {
assert(!widget->parent);
widget->parent = this;
@@ -172,4 +184,11 @@ Widget *Widget::onScroll(Vec pos, Vec scrollRel) {
return NULL;
}

void Widget::onZoom() {
for (auto it = children.rbegin(); it != children.rend(); it++) {
Widget *child = *it;
child->onZoom();
}
}

} // namespace rack

+ 14
- 0
src/widgets/ZoomWidget.cpp View File

@@ -3,6 +3,20 @@

namespace rack {

Rect ZoomWidget::getViewport(Rect r) {
r.pos = r.pos.mult(zoom);
r.size = r.size.mult(zoom);
r = Widget::getViewport(r);
r.pos = r.pos.div(zoom);
r.size = r.size.div(zoom);
return r;
}

void ZoomWidget::setZoom(float zoom) {
if (zoom != this->zoom)
onZoom();
this->zoom = zoom;
}

void ZoomWidget::draw(NVGcontext *vg) {
nvgScale(vg, zoom, zoom);


Loading…
Cancel
Save