mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-18 18:56:29 +00:00
menu view: cleanly separate update, layout phases
This patch improves the separation of the update and layout phases to avoid superfluous geometry animations of its child widgets. Prior this patch, 'Widget::geometry' was called in both phases, potentially triggering geometry animations with intermediate values at the update phase. Related to issue #3221
This commit is contained in:
parent
ba5de21db4
commit
122c404883
@ -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())));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
@ -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<Registered<Anchor> > _server_anchors { };
|
||||
Registry<Registered<Anchor> > _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_rgb888> &pixel_surface,
|
||||
Surface<Pixel_alpha8> &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()); });
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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());
|
||||
});
|
||||
}
|
||||
};
|
||||
|
@ -176,12 +176,6 @@ class Menu_view::Widget : List_model<Widget>::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<Widget>::Element
|
||||
Surface<Pixel_alpha8> &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);
|
||||
|
Loading…
Reference in New Issue
Block a user