diff --git a/repos/gems/run/menu_view.run b/repos/gems/run/menu_view.run index 2eedcc16d4..ddb504e037 100644 --- a/repos/gems/run/menu_view.run +++ b/repos/gems/run/menu_view.run @@ -158,23 +158,44 @@ install_config { - - - - - - + + + + + + + + + + + + + + + + + + + + diff --git a/repos/gems/src/app/menu_view/box_layout_widget.h b/repos/gems/src/app/menu_view/box_layout_widget.h index dd04d37ab1..4df7f346c1 100644 --- a/repos/gems/src/app/menu_view/box_layout_widget.h +++ b/repos/gems/src/app/menu_view/box_layout_widget.h @@ -28,20 +28,18 @@ struct Menu_view::Box_layout_widget : Widget Direction const _direction; - Box_layout_widget(Widget_factory &factory, Xml_node node, Unique_id unique_id) - : - Widget(factory, node, unique_id), - _direction(node.has_type("vbox") ? VERTICAL : HORIZONTAL) - { } + bool _vertical() const { return _direction == VERTICAL; } - void update(Xml_node node) override + unsigned _count = 0; + + /** + * Stack and count children, and update min_size for the whole compound + * + * This method performs the part of the layout calculation that can be + * done without knowing the final size of the box layout. + */ + void _stack_and_count_child_widgets() { - _update_children(node); - - /* - * Apply layout to the children - */ - /* determine largest size among our children */ unsigned largest_size = 0; _children.for_each([&] (Widget const &w) { @@ -51,6 +49,7 @@ struct Menu_view::Box_layout_widget : Widget /* position children on one row/column */ Point position(0, 0); + _count = 0; _children.for_each([&] (Widget &w) { Area const child_min_size = w.min_size(); @@ -66,6 +65,7 @@ struct Menu_view::Box_layout_widget : Widget unsigned const dx = child_min_size.w() - min(w.margin.right, next_left_margin); position = position + Point(dx, 0); } + _count++; }); _min_size = (_direction == VERTICAL) @@ -73,6 +73,54 @@ struct Menu_view::Box_layout_widget : Widget : Area(position.x(), largest_size); } + /** + * Adjust layout to actual size of the entire box layout widget + */ + void _stretch_child_widgets_to_available_size() + { + using Genode::max; + unsigned const unused_pixels = + _vertical() ? max(_geometry.h(), _min_size.h()) - _min_size.h() + : max(_geometry.w(), _min_size.w()) - _min_size.w(); + + /* number of excess pixels at the end of the stack (fixpoint) */ + unsigned const step_fp = (_count > 0) ? (unused_pixels << 8) / _count : 0; + + unsigned consumed_fp = 0; + _children.for_each([&] (Widget &w) { + + unsigned const next_consumed_fp = consumed_fp + step_fp; + unsigned const padding_pixels = (next_consumed_fp >> 8) + - (consumed_fp >> 8); + if (_direction == VERTICAL) { + w.position(w.geometry().p1() + Point(0, consumed_fp >> 8)); + w.size(Area(geometry().w(), w.min_size().h() + padding_pixels)); + } else { + w.position(w.geometry().p1() + Point(consumed_fp >> 8, 0)); + w.size(Area(w.min_size().w() + padding_pixels, geometry().h())); + } + consumed_fp = next_consumed_fp; + }); + } + + Box_layout_widget(Widget_factory &factory, Xml_node node, Unique_id unique_id) + : + Widget(factory, node, unique_id), + _direction(node.has_type("vbox") ? VERTICAL : HORIZONTAL) + { } + + void update(Xml_node node) override + { + _update_children(node); + + /* + * Apply layout to the children + */ + + _stack_and_count_child_widgets(); + + } + Area min_size() const override { return _min_size; @@ -87,12 +135,8 @@ struct Menu_view::Box_layout_widget : Widget void _layout() override { - _children.for_each([&] (Widget &w) { - if (_direction == VERTICAL) - w.size(Area(geometry().w(), w.min_size().h())); - else - w.size(Area(w.min_size().w(), geometry().h())); - }); + _stack_and_count_child_widgets(); + _stretch_child_widgets_to_available_size(); } }; diff --git a/repos/gems/src/app/menu_view/float_widget.h b/repos/gems/src/app/menu_view/float_widget.h index 80cf1bec52..793ebc65cd 100644 --- a/repos/gems/src/app/menu_view/float_widget.h +++ b/repos/gems/src/app/menu_view/float_widget.h @@ -40,7 +40,7 @@ struct Menu_view::Float_widget : Widget int const h = (_north && _south) ? geometry().h() : child_min.h(); /* align / center child position */ - int const x = _east ? 0 : _west ? 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; child.geometry(Rect(Point(x, y), Area(w, h)));