diff --git a/repos/gems/src/app/menu_view/button_widget.h b/repos/gems/src/app/menu_view/button_widget.h index f906a48f16..11c0eaae18 100644 --- a/repos/gems/src/app/menu_view/button_widget.h +++ b/repos/gems/src/app/menu_view/button_widget.h @@ -101,11 +101,6 @@ struct Menu_view::Button_widget : Widget, Animator::Item _selected = new_selected; _update_children(node); - - _children.for_each([&] (Widget &child) { - child.geometry(Rect(Point(margin.left + _padding.left, - margin.top + _padding.top), - child.min_size())); }); } Area min_size() const override @@ -176,9 +171,20 @@ struct Menu_view::Button_widget : Widget, Animator::Item void _layout() override { - _children.for_each([&] (Widget &w) { - w.size(Area(geometry().w() - _space().w(), - geometry().h() - _space().h())); }); + _children.for_each([&] (Widget &child) { + + child.position(Point(margin.left + _padding.left, + margin.top + _padding.top)); + + Area const avail = geometry().area(); + + unsigned const + w = avail.w() >= _space().w() ? avail.w() - _space().w() : 0, + h = avail.h() >= _space().h() ? avail.h() - _space().w() : 0; + + child.size(Area(max(w, child.min_size().w()), + max(h, child.min_size().h()))); + }); } diff --git a/repos/gems/src/app/menu_view/depgraph_widget.h b/repos/gems/src/app/menu_view/depgraph_widget.h index 647720f93d..da0f3724be 100644 --- a/repos/gems/src/app/menu_view/depgraph_widget.h +++ b/repos/gems/src/app/menu_view/depgraph_widget.h @@ -28,8 +28,6 @@ namespace Menu_view { struct Depgraph_widget; } struct Menu_view::Depgraph_widget : Widget { - Area _min_size { }; /* value cached from layout computation */ - struct Depth_direction { enum Value { EAST, WEST, NORTH, SOUTH }; @@ -78,6 +76,24 @@ struct Menu_view::Depgraph_widget : Widget Registry > _server_anchors { }; Registry > _client_anchors { }; + Rect _widget_geometry { Point(0, 0), Area(0, 0) }; + + /** + * Set cached widget geometry, calculated during 'update' + */ + void widget_geometry(Rect geometry) { _widget_geometry = geometry; } + + /** + * Propagate cached geometry to widget, called during '_layout' + * + * Calling this method may trigger the widget's geometry animation. + */ + void apply_layout_to_widget() + { + _widget.position(_widget_geometry.p1()); + _widget.size(_widget_geometry.area()); + } + struct Dependency : Animator::Item { Anchor::Type const _type; @@ -556,7 +572,8 @@ struct Menu_view::Depgraph_widget : Widget if (client && !server) { warning("node '", client_name, "' depends on " "non-existing node '", server_name, "'"); - client->_widget.geometry(Rect(Point(0, 0), Area(0, 0))); + client->_widget.position(Point(0, 0)); + client->_widget.size(Area(0, 0)); } }); @@ -588,9 +605,17 @@ struct Menu_view::Depgraph_widget : Widget }); /* - * Apply layout to the children, determine _min_size + * Calculate the bounding box and the designated geometries of all + * widgets. + * + * The bounding box dictates the 'min_size' of the depgraph widget. + * + * The computed widget geometries are stored in their corresponding + * 'Node' objects but are not immediately propagated to the widgets. + * The computed geometries are applied to the widgets in '_layout' + * phase. */ - Rect bounding_box(Point(0, 0), Area(0, 0)); + _bounding_box = Rect(Point(0, 0), Area(0, 0)); _children.for_each([&] (Widget &w) { _nodes.for_each([&] (Registered_node &node) { if (!node.belongs_to(w)) @@ -607,35 +632,16 @@ struct Menu_view::Depgraph_widget : Widget : Rect(Point(breadth_pos, depth_pos), Area(breadth_size, depth_size)); - w.geometry(Rect(node_rect.center(w.min_size()), w.min_size())); + Rect geometry(node_rect.center(w.min_size()), w.min_size()); - bounding_box = Rect::compound(bounding_box, w.geometry()); + node.widget_geometry(geometry); + + _bounding_box = Rect::compound(_bounding_box, geometry); }); }); - - /* - * Mirror coordinates if graph grows towards north or west - */ - if (_depth_direction.value == Depth_direction::NORTH - || _depth_direction.value == Depth_direction::WEST) { - - _children.for_each([&] (Widget &w) { - - int x = w.geometry().x1(), y = w.geometry().y1(); - - if (_depth_direction.value == Depth_direction::NORTH) - y = (int)bounding_box.h() - y - w.geometry().h(); - - if (_depth_direction.value == Depth_direction::WEST) - x = (int)bounding_box.w() - x - w.geometry().w(); - - w.geometry(Rect(Point(x, y), w.geometry().area())); - }); - } - _min_size = bounding_box.area(); } - Area min_size() const override { return _min_size; } + Area min_size() const override { return _bounding_box.area(); } void _draw_connect(Surface &pixel_surface, Surface &alpha_surface, @@ -720,6 +726,36 @@ struct Menu_view::Depgraph_widget : Widget void _layout() override { + /* + * Apply layout to the children + */ + _nodes.for_each([&] (Registered_node &node) { + if (&node != &_root_node) + node.apply_layout_to_widget(); }); + + /* + * Mirror coordinates if graph grows towards north or west + */ + if (_depth_direction.value == Depth_direction::NORTH + || _depth_direction.value == Depth_direction::WEST) { + + _children.for_each([&] (Widget &w) { + + int x = w.geometry().x1(), y = w.geometry().y1(); + + if (_depth_direction.value == Depth_direction::NORTH) + y = (int)_bounding_box.h() - y - w.geometry().h(); + + if (_depth_direction.value == Depth_direction::WEST) + x = (int)_bounding_box.w() - x - w.geometry().w(); + + w.position(Point(x, y)); + }); + } + + /* + * Prompt each child to update its layout + */ _children.for_each([&] (Widget &w) { w.size(w.geometry().area()); }); } diff --git a/repos/gems/src/app/menu_view/float_widget.h b/repos/gems/src/app/menu_view/float_widget.h index 8b6baa87d9..78bc79f4b0 100644 --- a/repos/gems/src/app/menu_view/float_widget.h +++ b/repos/gems/src/app/menu_view/float_widget.h @@ -43,7 +43,8 @@ struct Menu_view::Float_widget : Widget int const x = _west ? 0 : _east ? w_space : w_space / 2; int const y = _north ? 0 : _south ? h_space : h_space / 2; - child.geometry(Rect(Point(x, y), Area(w, h))); + child.position(Point(x, y)); + child.size(Area(w, h)); } void update(Xml_node node) override diff --git a/repos/gems/src/app/menu_view/frame_widget.h b/repos/gems/src/app/menu_view/frame_widget.h index bfc82b4df9..d6c0f9e0dd 100644 --- a/repos/gems/src/app/menu_view/frame_widget.h +++ b/repos/gems/src/app/menu_view/frame_widget.h @@ -44,13 +44,6 @@ struct Menu_view::Frame_widget : Widget _update_children(node); - /* - * layout - */ - _children.for_each([&] (Widget &child) { - child.geometry(Rect(Point(margin.left + padding.left, - margin.top + padding.top), - child.min_size())); }); } Area min_size() const override @@ -83,8 +76,19 @@ struct Menu_view::Frame_widget : Widget void _layout() override { _children.for_each([&] (Widget &child) { - child.size(Area(geometry().w() - _space().w(), - geometry().h() - _space().h())); }); + + child.position(Point(margin.left + padding.left, + margin.top + padding.top)); + + Area const avail = geometry().area(); + + unsigned const + w = avail.w() >= _space().w() ? avail.w() - _space().w() : 0, + h = avail.h() >= _space().h() ? avail.h() - _space().w() : 0; + + child.size(Area(max(w, child.min_size().w()), + max(h, child.min_size().h()))); + }); } private: diff --git a/repos/gems/src/app/menu_view/root_widget.h b/repos/gems/src/app/menu_view/root_widget.h index 729f766843..cb7e469979 100644 --- a/repos/gems/src/app/menu_view/root_widget.h +++ b/repos/gems/src/app/menu_view/root_widget.h @@ -74,8 +74,8 @@ struct Menu_view::Root_widget : Widget void _layout() override { _children.for_each([&] (Widget &child) { - child.size(geometry().area()); child.position(Point(0, 0)); + child.size(_geometry.area()); }); } }; diff --git a/repos/gems/src/app/menu_view/widget.h b/repos/gems/src/app/menu_view/widget.h index e647470b47..b08b5387aa 100644 --- a/repos/gems/src/app/menu_view/widget.h +++ b/repos/gems/src/app/menu_view/widget.h @@ -176,12 +176,6 @@ class Menu_view::Widget : List_model::Element Margin margin { 0, 0, 0, 0 }; - void geometry(Rect geometry) - { - _geometry = geometry; - _trigger_geometry_animation(); - } - Rect geometry() const { return _geometry; } Rect animated_geometry() const { return _animated_geometry.rect(); } @@ -220,6 +214,9 @@ class Menu_view::Widget : List_model::Element Surface &alpha_surface, Point at) const = 0; + /** + * Set widget size and update the widget tree's layout accordingly + */ void size(Area size) { _geometry = Rect(_geometry.p1(), size);