mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-31 08:25:38 +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;
|
_selected = new_selected;
|
||||||
|
|
||||||
_update_children(node);
|
_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
|
Area min_size() const override
|
||||||
@ -176,9 +171,20 @@ struct Menu_view::Button_widget : Widget, Animator::Item
|
|||||||
|
|
||||||
void _layout() override
|
void _layout() override
|
||||||
{
|
{
|
||||||
_children.for_each([&] (Widget &w) {
|
_children.for_each([&] (Widget &child) {
|
||||||
w.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())));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -28,8 +28,6 @@ namespace Menu_view { struct Depgraph_widget; }
|
|||||||
|
|
||||||
struct Menu_view::Depgraph_widget : Widget
|
struct Menu_view::Depgraph_widget : Widget
|
||||||
{
|
{
|
||||||
Area _min_size { }; /* value cached from layout computation */
|
|
||||||
|
|
||||||
struct Depth_direction
|
struct Depth_direction
|
||||||
{
|
{
|
||||||
enum Value { EAST, WEST, NORTH, SOUTH };
|
enum Value { EAST, WEST, NORTH, SOUTH };
|
||||||
@ -78,6 +76,24 @@ struct Menu_view::Depgraph_widget : Widget
|
|||||||
Registry<Registered<Anchor> > _server_anchors { };
|
Registry<Registered<Anchor> > _server_anchors { };
|
||||||
Registry<Registered<Anchor> > _client_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
|
struct Dependency : Animator::Item
|
||||||
{
|
{
|
||||||
Anchor::Type const _type;
|
Anchor::Type const _type;
|
||||||
@ -556,7 +572,8 @@ struct Menu_view::Depgraph_widget : Widget
|
|||||||
if (client && !server) {
|
if (client && !server) {
|
||||||
warning("node '", client_name, "' depends on "
|
warning("node '", client_name, "' depends on "
|
||||||
"non-existing node '", server_name, "'");
|
"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) {
|
_children.for_each([&] (Widget &w) {
|
||||||
_nodes.for_each([&] (Registered_node &node) {
|
_nodes.for_each([&] (Registered_node &node) {
|
||||||
if (!node.belongs_to(w))
|
if (!node.belongs_to(w))
|
||||||
@ -607,35 +632,16 @@ struct Menu_view::Depgraph_widget : Widget
|
|||||||
: Rect(Point(breadth_pos, depth_pos),
|
: Rect(Point(breadth_pos, depth_pos),
|
||||||
Area(breadth_size, depth_size));
|
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,
|
void _draw_connect(Surface<Pixel_rgb888> &pixel_surface,
|
||||||
Surface<Pixel_alpha8> &alpha_surface,
|
Surface<Pixel_alpha8> &alpha_surface,
|
||||||
@ -720,6 +726,36 @@ struct Menu_view::Depgraph_widget : Widget
|
|||||||
|
|
||||||
void _layout() override
|
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) {
|
_children.for_each([&] (Widget &w) {
|
||||||
w.size(w.geometry().area()); });
|
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 x = _west ? 0 : _east ? w_space : w_space / 2;
|
||||||
int const y = _north ? 0 : _south ? h_space : h_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
|
void update(Xml_node node) override
|
||||||
|
@ -44,13 +44,6 @@ struct Menu_view::Frame_widget : Widget
|
|||||||
|
|
||||||
_update_children(node);
|
_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
|
Area min_size() const override
|
||||||
@ -83,8 +76,19 @@ struct Menu_view::Frame_widget : Widget
|
|||||||
void _layout() override
|
void _layout() override
|
||||||
{
|
{
|
||||||
_children.for_each([&] (Widget &child) {
|
_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:
|
private:
|
||||||
|
@ -74,8 +74,8 @@ struct Menu_view::Root_widget : Widget
|
|||||||
void _layout() override
|
void _layout() override
|
||||||
{
|
{
|
||||||
_children.for_each([&] (Widget &child) {
|
_children.for_each([&] (Widget &child) {
|
||||||
child.size(geometry().area());
|
|
||||||
child.position(Point(0, 0));
|
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 };
|
Margin margin { 0, 0, 0, 0 };
|
||||||
|
|
||||||
void geometry(Rect geometry)
|
|
||||||
{
|
|
||||||
_geometry = geometry;
|
|
||||||
_trigger_geometry_animation();
|
|
||||||
}
|
|
||||||
|
|
||||||
Rect geometry() const { return _geometry; }
|
Rect geometry() const { return _geometry; }
|
||||||
|
|
||||||
Rect animated_geometry() const { return _animated_geometry.rect(); }
|
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,
|
Surface<Pixel_alpha8> &alpha_surface,
|
||||||
Point at) const = 0;
|
Point at) const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set widget size and update the widget tree's layout accordingly
|
||||||
|
*/
|
||||||
void size(Area size)
|
void size(Area size)
|
||||||
{
|
{
|
||||||
_geometry = Rect(_geometry.p1(), size);
|
_geometry = Rect(_geometry.p1(), size);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user