| @@ -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); | ||||