menu_view: defer geometry animation to layout step

The box-layout widget used to trigger the geometry animation of its
children immediately when updating the widget from the XML model (by
calling 'child->Widget::geometry'). This caused layout inconsistencies
in situations where the box layout is defined not by the constraints of
the child widgets but from the outside (the parent calls Widget::size).
Since the final layout is not known before the parent defines the actual
size, this patch moves the trigger point for the geometry animation to
'Widget::size'.
This commit is contained in:
Norman Feske 2018-05-06 20:49:58 +02:00 committed by Christian Helmuth
parent 05b0010281
commit 3065cceb73
4 changed files with 22 additions and 9 deletions

View File

@ -75,7 +75,7 @@ class Menu_view::Animated_rect : public Rect, Animator::Item, Noncopyable
Point(_p2.x(), _p2.y()));
/* schedule / de-schedule animation */
animated(_p1.animated() || _p2.animated());
Animator::Item::animated(_p1.animated() || _p2.animated());
}
/**
@ -91,6 +91,8 @@ class Menu_view::Animated_rect : public Rect, Animator::Item, Noncopyable
_p2.move_to(rect.p2(), steps);
animate();
}
bool animated() const { return Animator::Item::animated(); }
};
#endif /* _ANIMATED_GEOMETRY_H_ */

View File

@ -55,20 +55,22 @@ struct Menu_view::Box_layout_widget : Widget
Area const child_min_size = w.min_size();
w.position(position);
if (_direction == VERTICAL) {
w.geometry(Rect(position, Area(largest_size, child_min_size.h())));
unsigned const next_top_margin = w.next() ? w.next()->margin.top : 0;
unsigned const dy = child_min_size.h() - min(w.margin.bottom, next_top_margin);
position = position + Point(0, dy);
} else {
w.geometry(Rect(position, Area(child_min_size.w(), largest_size)));
unsigned const next_left_margin = w.next() ? w.next()->margin.left : 0;
unsigned const dx = child_min_size.w() - min(w.margin.right, next_left_margin);
position = position + Point(dx, 0);
}
_min_size = Area(w.geometry().x2() + 1, w.geometry().y2() + 1);
});
_min_size = (_direction == VERTICAL)
? Area(largest_size, position.y())
: Area(position.x(), largest_size);
}
Area min_size() const override

View File

@ -52,9 +52,6 @@ struct Menu_view::Root_widget : Widget
}
_update_children(node);
_children.for_each([&] (Widget &child) {
child.geometry(Rect(Point(0, 0), child.min_size())); });
}
Area min_size() const override

View File

@ -160,6 +160,16 @@ class Menu_view::Widget : public List_model<Widget>::Element
Animated_rect _animated_geometry { _factory.animator };
void _trigger_geometry_animation()
{
if (_animated_geometry.animated())
return;
if (_geometry.p1() != _animated_geometry.p1()
|| _geometry.p2() != _animated_geometry.p2())
_animated_geometry.move_to(_geometry, Animated_rect::Steps{60});
}
public:
Margin margin { 0, 0, 0, 0 };
@ -167,7 +177,7 @@ class Menu_view::Widget : public List_model<Widget>::Element
void geometry(Rect geometry)
{
_geometry = geometry;
_animated_geometry.move_to(_geometry, Animated_rect::Steps{60});
_trigger_geometry_animation();
}
Rect geometry() const { return _geometry; }
@ -213,6 +223,8 @@ class Menu_view::Widget : public List_model<Widget>::Element
_geometry = Rect(_geometry.p1(), size);
_layout();
_trigger_geometry_animation();
}
void position(Point position)