Browse Source

Add DrawContext::clipBox for drawing children widgets only when they intersect with the clipBox.

tags/v1.0.0
Andrew Belt 5 years ago
parent
commit
fd3937794e
7 changed files with 59 additions and 23 deletions
  1. +22
    -9
      include/math.hpp
  2. +3
    -2
      include/widgets/Widget.hpp
  3. +16
    -3
      src/app/ModuleBrowser.cpp
  4. +2
    -2
      src/app/RackWidget.cpp
  5. +1
    -1
      src/ui/Menu.cpp
  6. +11
    -5
      src/widgets/Widget.cpp
  7. +4
    -1
      src/widgets/ZoomWidget.cpp

+ 22
- 9
include/math.hpp View File

@@ -258,17 +258,17 @@ struct Rect {
}

/** Returns whether this Rect contains an entire point, inclusive on the top/left, non-inclusive on the bottom/right */
bool contains(Vec v) const {
bool isContaining(Vec v) const {
return pos.x <= v.x && v.x < pos.x + size.x
&& pos.y <= v.y && v.y < pos.y + size.y;
}
/** Returns whether this Rect contains an entire Rect */
bool contains(Rect r) const {
bool isContaining(Rect r) const {
return pos.x <= r.pos.x && r.pos.x + r.size.x <= pos.x + size.x
&& pos.y <= r.pos.y && r.pos.y + r.size.y <= pos.y + size.y;
}
/** Returns whether this Rect overlaps with another Rect */
bool intersects(Rect r) const {
bool isIntersecting(Rect r) const {
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);
}
@@ -313,13 +313,22 @@ struct Rect {
r.pos.y = math::clampSafe(pos.y, bound.pos.y, bound.pos.y + bound.size.y - size.y);
return r;
}
/** Expands this Rect to contain `other` */
Rect expand(Rect other) const {
/** Expands this Rect to contain `b` */
Rect expand(Rect b) const {
Rect r;
r.pos.x = std::min(pos.x, other.pos.x);
r.pos.y = std::min(pos.y, other.pos.y);
r.size.x = std::max(pos.x + size.x, other.pos.x + other.size.x) - r.pos.x;
r.size.y = std::max(pos.y + size.y, other.pos.y + other.size.y) - r.pos.y;
r.pos.x = std::min(pos.x, b.pos.x);
r.pos.y = std::min(pos.y, b.pos.y);
r.size.x = std::max(pos.x + size.x, b.pos.x + b.size.x) - r.pos.x;
r.size.y = std::max(pos.y + size.y, b.pos.y + b.size.y) - r.pos.y;
return r;
}
/** Returns the intersection of `this` and `b` */
Rect intersect(Rect b) const {
Rect r;
r.pos.x = std::max(pos.x, b.pos.x);
r.pos.y = std::max(pos.y, b.pos.y);
r.size.x = std::min(pos.x + size.x, b.pos.x + b.size.x) - r.pos.x;
r.size.y = std::min(pos.y + size.y, b.pos.y + b.size.y) - r.pos.y;
return r;
}
/** Returns a Rect with its position set to zero */
@@ -335,6 +344,10 @@ struct Rect {
r.size = size.plus(delta.mult(2.f));
return r;
}

DEPRECATED bool contains(Vec v) const {return isContaining(v);}
DEPRECATED bool contains(Rect r) const {return isContaining(r);}
DEPRECATED bool intersects(Rect r) const {return isIntersecting(r);}
};




+ 3
- 2
include/widgets/Widget.hpp View File

@@ -11,7 +11,8 @@ namespace rack {


struct DrawContext {
mutable NVGcontext *vg;
NVGcontext *vg;
math::Rect clipBox = math::Rect(math::Vec(), math::Vec(INFINITY, INFINITY));
};


@@ -101,7 +102,7 @@ struct Widget {
// Filter child by visibility and position
if (!child->visible)
continue;
if (!child->box.contains(e.pos))
if (!child->box.isContaining(e.pos))
continue;

// Clone event and adjust its position


+ 16
- 3
src/app/ModuleBrowser.cpp View File

@@ -22,7 +22,10 @@ static std::set<Model*> sFavoriteModels;

struct ModuleBox : OpaqueWidget {
Model *model;
bool initialized = false;
/** Lazily created */
Widget *previewWidget = NULL;
/** Number of frames since draw() has been called */
int visibleFrames = 0;

void setModel(Model *model) {
this->model = model;
@@ -47,9 +50,17 @@ struct ModuleBox : OpaqueWidget {
addChild(pluginLabel);
}

void step() override {
if (previewWidget && ++visibleFrames >= 60) {
removeChild(previewWidget);
delete previewWidget;
previewWidget = NULL;
}
}

void draw(const DrawContext &ctx) override {
// Lazily create ModuleWidget when drawn
if (!initialized) {
if (!previewWidget) {
Widget *transparentWidget = new TransparentWidget;
addChild(transparentWidget);

@@ -71,7 +82,8 @@ struct ModuleBox : OpaqueWidget {
zoomWidget->box.size.y = RACK_GRID_HEIGHT;
float width = std::ceil(zoomWidget->box.size.x);
box.size.x = std::max(box.size.x, width);
initialized = true;

previewWidget = transparentWidget;
}

OpaqueWidget::draw(ctx);
@@ -113,6 +125,7 @@ ModuleBrowser::ModuleBrowser() {
moduleLayout->spacing = math::Vec(10, 10);
moduleScroll->container->addChild(moduleLayout);

for (int i = 0; i < 100; i++)
for (Plugin *plugin : plugin::plugins) {
for (Model *model : plugin->models) {
ModuleBox *moduleBox = new ModuleBox;


+ 2
- 2
src/app/RackWidget.cpp View File

@@ -104,7 +104,7 @@ void RackWidget::step() {
// Adjust size and position of rails
Widget *rail = rails->children.front();
math::Rect bound = getViewport(math::Rect(math::Vec(), box.size));
if (!rails->box.contains(bound)) {
if (!rails->box.isContaining(bound)) {
math::Vec cellMargin = math::Vec(20, 1);
rails->box.pos = bound.pos.div(RACK_GRID_SIZE).floor().minus(cellMargin).mult(RACK_GRID_SIZE);
rails->box.size = bound.size.plus(cellMargin.mult(RACK_GRID_SIZE).mult(2));
@@ -369,7 +369,7 @@ bool RackWidget::requestModuleBox(ModuleWidget *m, math::Rect requestedBox) {
// Don't intersect with self
if (m == m2)
continue;
if (requestedBox.intersects(m2->box)) {
if (requestedBox.isIntersecting(m2->box)) {
return false;
}
}


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

@@ -54,7 +54,7 @@ void Menu::draw(const DrawContext &ctx) {
}

void Menu::onHoverScroll(const event::HoverScroll &e) {
if (parent && !parent->box.contains(box))
if (parent && !parent->box.isContaining(box))
box.pos.y += e.scrollDelta.y;
}



+ 11
- 5
src/widgets/Widget.cpp View File

@@ -94,25 +94,31 @@ void Widget::step() {
}

void Widget::draw(const DrawContext &ctx) {
// Iterate children
for (Widget *child : children) {
// Don't draw if invisible
if (!child->visible)
continue;
// Don't draw if child is outside bounding box
if (!box.zeroPos().intersects(child->box))
// Don't draw if child is outside clip box
if (!ctx.clipBox.isIntersecting(child->box))
continue;

DrawContext childCtx = ctx;
// Intersect child clip box with self
childCtx.clipBox = childCtx.clipBox.intersect(child->box);
childCtx.clipBox.pos = childCtx.clipBox.pos.minus(child->box.pos);

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"
// Call deprecated draw function, which does nothing by default
child->draw(ctx.vg);
#pragma GCC diagnostic pop

child->draw(childCtx);

// Draw red hitboxes
// if (app()->event->hoveredWidget == child) {
// nvgBeginPath(ctx.vg);


+ 4
- 1
src/widgets/ZoomWidget.cpp View File

@@ -29,9 +29,12 @@ void ZoomWidget::setZoom(float zoom) {
}

void ZoomWidget::draw(const DrawContext &ctx) {
DrawContext zoomCtx = ctx;
zoomCtx.clipBox.pos = zoomCtx.clipBox.pos.div(zoom);
zoomCtx.clipBox.size = zoomCtx.clipBox.size.div(zoom);
// No need to save the state because that is done in the parent
nvgScale(ctx.vg, zoom, zoom);
Widget::draw(ctx);
Widget::draw(zoomCtx);
}




Loading…
Cancel
Save