@@ -50,14 +50,27 @@ struct Widget { | |||||
void requestDelete(); | void requestDelete(); | ||||
/** Returns the smallest rectangle containing this widget's children (visible and invisible) in its local coordinates. | |||||
Returns `Rect(Vec(inf, inf), Vec(-inf, -inf))` if there are no children. | |||||
*/ | |||||
virtual math::Rect getChildrenBoundingBox(); | virtual math::Rect getChildrenBoundingBox(); | ||||
/** Returns `v` transformed into the coordinate system of `relative` */ | |||||
/** Returns `v` (given in local coordinates) transformed into the coordinate system of `relative`. | |||||
*/ | |||||
virtual math::Vec getRelativeOffset(math::Vec v, Widget* relative); | virtual math::Vec getRelativeOffset(math::Vec v, Widget* relative); | ||||
/** Returns `v` transformed into world coordinates */ | |||||
/** Returns `v` transformed into world/root/global/absolute coordinates. | |||||
*/ | |||||
math::Vec getAbsoluteOffset(math::Vec v) { | math::Vec getAbsoluteOffset(math::Vec v) { | ||||
return getRelativeOffset(v, NULL); | return getRelativeOffset(v, NULL); | ||||
} | } | ||||
/** Returns a subset of the given math::Rect bounded by the box of this widget and all ancestors */ | |||||
/** Returns the zoom level in the coordinate system of `relative`. | |||||
Only `ZoomWidget` should override this to return value other than 1. | |||||
*/ | |||||
virtual float getRelativeZoom(Widget* relative); | |||||
float getAbsoluteZoom() { | |||||
return getRelativeZoom(NULL); | |||||
} | |||||
/** Returns a subset of the given Rect bounded by the box of this widget and all ancestors. | |||||
*/ | |||||
virtual math::Rect getViewport(math::Rect r); | virtual math::Rect getViewport(math::Rect r); | ||||
template <class T> | template <class T> | ||||
@@ -11,6 +11,7 @@ struct ZoomWidget : Widget { | |||||
float zoom = 1.f; | float zoom = 1.f; | ||||
math::Vec getRelativeOffset(math::Vec v, Widget* relative) override; | math::Vec getRelativeOffset(math::Vec v, Widget* relative) override; | ||||
float getRelativeZoom(Widget* relative) override; | |||||
math::Rect getViewport(math::Rect r) override; | math::Rect getViewport(math::Rect r) override; | ||||
void setZoom(float zoom); | void setZoom(float zoom); | ||||
float getZoom() { | float getZoom() { | ||||
@@ -87,8 +87,6 @@ math::Rect Widget::getChildrenBoundingBox() { | |||||
math::Vec min = math::Vec(INFINITY, INFINITY); | math::Vec min = math::Vec(INFINITY, INFINITY); | ||||
math::Vec max = math::Vec(-INFINITY, -INFINITY); | math::Vec max = math::Vec(-INFINITY, -INFINITY); | ||||
for (Widget* child : children) { | for (Widget* child : children) { | ||||
if (!child->visible) | |||||
continue; | |||||
min = min.min(child->box.getTopLeft()); | min = min.min(child->box.getTopLeft()); | ||||
max = max.max(child->box.getBottomRight()); | max = max.max(child->box.getBottomRight()); | ||||
} | } | ||||
@@ -97,14 +95,22 @@ math::Rect Widget::getChildrenBoundingBox() { | |||||
math::Vec Widget::getRelativeOffset(math::Vec v, Widget* relative) { | math::Vec Widget::getRelativeOffset(math::Vec v, Widget* relative) { | ||||
if (this == relative) { | |||||
if (this == relative) | |||||
return v; | return v; | ||||
} | |||||
// Translate offset | |||||
v = v.plus(box.pos); | v = v.plus(box.pos); | ||||
if (parent) { | |||||
v = parent->getRelativeOffset(v, relative); | |||||
} | |||||
return v; | |||||
if (!parent) | |||||
return v; | |||||
return parent->getRelativeOffset(v, relative); | |||||
} | |||||
float Widget::getRelativeZoom(Widget* relative) { | |||||
if (this == relative) | |||||
return 1.f; | |||||
if (!parent) | |||||
return 1.f; | |||||
return parent->getRelativeZoom(relative); | |||||
} | } | ||||
@@ -6,9 +6,17 @@ namespace widget { | |||||
math::Vec ZoomWidget::getRelativeOffset(math::Vec v, Widget* relative) { | math::Vec ZoomWidget::getRelativeOffset(math::Vec v, Widget* relative) { | ||||
return Widget::getRelativeOffset(v.mult(zoom), relative); | |||||
// Transform `v` (which is in child coordinates) to local coordinates. | |||||
v = v.mult(zoom); | |||||
return Widget::getRelativeOffset(v, relative); | |||||
} | } | ||||
float ZoomWidget::getRelativeZoom(Widget* relative) { | |||||
return zoom * Widget::getRelativeZoom(relative); | |||||
} | |||||
math::Rect ZoomWidget::getViewport(math::Rect r) { | math::Rect ZoomWidget::getViewport(math::Rect r) { | ||||
r.pos = r.pos.mult(zoom); | r.pos = r.pos.mult(zoom); | ||||
r.size = r.size.mult(zoom); | r.size = r.size.mult(zoom); | ||||
@@ -18,6 +26,7 @@ math::Rect ZoomWidget::getViewport(math::Rect r) { | |||||
return r; | return r; | ||||
} | } | ||||
void ZoomWidget::setZoom(float zoom) { | void ZoomWidget::setZoom(float zoom) { | ||||
if (zoom == this->zoom) | if (zoom == this->zoom) | ||||
return; | return; | ||||
@@ -30,6 +39,7 @@ void ZoomWidget::setZoom(float zoom) { | |||||
Widget::onDirty(eDirty); | Widget::onDirty(eDirty); | ||||
} | } | ||||
void ZoomWidget::draw(const DrawArgs& args) { | void ZoomWidget::draw(const DrawArgs& args) { | ||||
DrawArgs zoomCtx = args; | DrawArgs zoomCtx = args; | ||||
zoomCtx.clipBox.pos = zoomCtx.clipBox.pos.div(zoom); | zoomCtx.clipBox.pos = zoomCtx.clipBox.pos.div(zoom); | ||||