From c9938e424bfdae63ef5b45299d94a62d72dbdae7 Mon Sep 17 00:00:00 2001 From: Norman Feske Date: Fri, 27 Oct 2023 15:23:36 +0200 Subject: [PATCH] menu_view: use modern list-model interface Issue #4317 --- repos/gems/src/app/menu_view/cursor.h | 39 ++---- .../gems/src/app/menu_view/depgraph_widget.h | 113 +++++++----------- repos/gems/src/app/menu_view/label_widget.h | 46 +++++-- repos/gems/src/app/menu_view/main.cc | 43 ++++--- repos/gems/src/app/menu_view/text_selection.h | 41 ++----- repos/gems/src/app/menu_view/widget.h | 62 +++++----- repos/gems/src/app/menu_view/widget_factory.h | 4 +- 7 files changed, 163 insertions(+), 185 deletions(-) diff --git a/repos/gems/src/app/menu_view/cursor.h b/repos/gems/src/app/menu_view/cursor.h index e856ac1ab9..052d3b2d21 100644 --- a/repos/gems/src/app/menu_view/cursor.h +++ b/repos/gems/src/app/menu_view/cursor.h @@ -92,7 +92,6 @@ class Menu_view::Cursor : List_model::Element _move_to(_position_from_xml_node(node), Steps{0}); } - void draw(Surface &pixel_surface, Surface &alpha_surface, Point at, unsigned height) const @@ -111,36 +110,20 @@ class Menu_view::Cursor : List_model::Element } } - struct Model_update_policy : List_model::Update_policy + bool matches(Xml_node const &node) const { - Widget_factory &_factory; - Glyph_position &_glyph_position; + return _node_name(node) == _name; + } - Model_update_policy(Widget_factory &factory, Glyph_position &glyph_position) - : - _factory(factory), _glyph_position(glyph_position) - { } + static bool type_matches(Xml_node const &node) + { + return node.has_type("cursor"); + } - void destroy_element(Cursor &c) { destroy(_factory.alloc, &c); } - - Cursor &create_element(Xml_node node) - { - return *new (_factory.alloc) - Cursor(node, _factory.animator, _glyph_position, _factory.styles); - } - - void update_element(Cursor &c, Xml_node node) - { - c._move_to(c._position_from_xml_node(node), Steps{12}); - } - - static bool element_matches_xml_node(Cursor const &c, Xml_node node) - { - return node.has_type("cursor") && _node_name(node) == c._name; - } - - static bool node_is_element(Xml_node node) { return node.has_type("cursor"); } - }; + void update(Xml_node const &node) + { + _move_to(_position_from_xml_node(node), Steps{12}); + } }; #endif /* _CURSOR_H_ */ diff --git a/repos/gems/src/app/menu_view/depgraph_widget.h b/repos/gems/src/app/menu_view/depgraph_widget.h index 41013b097c..5f3e2dd3e6 100644 --- a/repos/gems/src/app/menu_view/depgraph_widget.h +++ b/repos/gems/src/app/menu_view/depgraph_widget.h @@ -442,79 +442,12 @@ struct Menu_view::Depgraph_widget : Widget fn(_root_node); } - /** - * Customized model-update policy that augments the list of child widgets - * with their graph-node topology - */ - struct Model_update_policy : List_model::Update_policy - { - Widget::Model_update_policy &_generic_model_update_policy; - Allocator &_alloc; - Animator &_animator; - Node_registry &_nodes; - - Model_update_policy(Widget::Model_update_policy &policy, - Allocator &alloc, Animator &animator, - Node_registry &nodes) - : - _generic_model_update_policy(policy), - _alloc(alloc), _animator(animator), _nodes(nodes) - { } - - void _destroy_node(Registered_node &node) - { - /* - * If a server node vanishes, disconnect all client nodes. The - * nodes will be reconnected - if possible - after the model - * update. - */ - node.for_each_dependent_node([&] (Node &dependent) { - dependent.cut_dependencies(); }); - - Widget &w = node._widget; - destroy(_alloc, &node); - _generic_model_update_policy.destroy_element(w); - } - - void destroy_element(Widget &w) - { - _nodes.for_each([&] (Registered_node &node) { - if (node.belongs_to(w)) - _destroy_node(node); }); - } - - /* do not import nodes as widgets */ - bool node_is_element(Xml_node node) { return !node.has_type("dep"); } - - Widget &create_element(Xml_node elem_node) - { - Widget &w = _generic_model_update_policy.create_element(elem_node); - new (_alloc) Registered_node(_nodes, _alloc, w, _animator); - return w; - } - - void update_element(Widget &w, Xml_node elem_node) - { - _generic_model_update_policy.update_element(w, elem_node); - } - - static bool element_matches_xml_node(Widget const &w, Xml_node node) - { - return Widget::Model_update_policy::element_matches_xml_node(w, node); - } - - } _model_update_policy { Widget::_model_update_policy, - _factory.alloc, _factory.animator, _nodes }; - Depgraph_widget(Widget_factory &factory, Xml_node node, Unique_id unique_id) : Widget(factory, node, unique_id) { } - ~Depgraph_widget() - { - _children.destroy_all_elements(_model_update_policy); - } + ~Depgraph_widget() { _update_children(Xml_node("")); } void update(Xml_node node) override { @@ -529,7 +462,49 @@ struct Menu_view::Depgraph_widget : Widget if (dir_name == "west") _depth_direction = { Depth_direction::WEST }; } - _children.update_from_xml(_model_update_policy, node); + _update_children(node); + } + + void _update_children(Xml_node const &node) + { + Allocator &alloc = _factory.alloc; + + update_list_model_from_xml(_children, node, + + /* create */ + [&] (Xml_node const &node) -> Widget & + { + Widget &w = _factory.create(node); + new (alloc) Registered_node(_nodes, alloc, w, _factory.animator); + return w; + }, + + /* destroy */ + [&] (Widget &w) + { + auto destroy_node = [&] (Registered_node &node) + { + /* + * If a server node vanishes, disconnect all client nodes. The + * nodes will be reconnected - if possible - after the model + * update. + */ + node.for_each_dependent_node([&] (Node &dependent) { + dependent.cut_dependencies(); }); + + Widget &w = node._widget; + destroy(alloc, &node); + _factory.destroy(&w); + }; + + _nodes.for_each([&] (Registered_node &node) { + if (node.belongs_to(w)) + destroy_node(node); }); + }, + + /* update */ + [&] (Widget &w, Xml_node const &node) { w.update(node); } + ); /* * Import dependencies diff --git a/repos/gems/src/app/menu_view/label_widget.h b/repos/gems/src/app/menu_view/label_widget.h index bf66721e52..fbc437a72a 100644 --- a/repos/gems/src/app/menu_view/label_widget.h +++ b/repos/gems/src/app/menu_view/label_widget.h @@ -37,24 +37,47 @@ struct Menu_view::Label_widget : Widget, Cursor::Glyph_position int _min_width = 0; int _min_height = 0; - Cursor::Model_update_policy _cursor_update_policy; - Text_selection::Model_update_policy _selection_update_policy; - List_model _cursors { }; List_model _selections { }; Label_widget(Widget_factory &factory, Xml_node node, Unique_id unique_id) : - Widget(factory, node, unique_id), - _color(factory.animator), - _cursor_update_policy(factory, *this), - _selection_update_policy(factory.alloc, *this) + Widget(factory, node, unique_id), _color(factory.animator) { } - ~Label_widget() + ~Label_widget() { _update_children(Xml_node("")); } + + void _update_children(Xml_node const &node) { - _cursors .destroy_all_elements(_cursor_update_policy); - _selections.destroy_all_elements(_selection_update_policy); + update_list_model_from_xml(_cursors, node, + + /* create */ + [&] (Xml_node const &node) -> Cursor & { + return *new (_factory.alloc) + Cursor(node, _factory.animator, *this, _factory.styles); }, + + /* destroy */ + [&] (Cursor &cursor) { destroy(_factory.alloc, &cursor); }, + + /* update */ + [&] (Cursor &cursor, Xml_node const &node) { + cursor.update(node); } + ); + + update_list_model_from_xml(_selections, node, + + /* create */ + [&] (Xml_node const &node) -> Text_selection & { + return *new (_factory.alloc) + Text_selection(node, *this); }, + + /* destroy */ + [&] (Text_selection &t) { destroy(_factory.alloc, &t); }, + + /* update */ + [&] (Text_selection &t, Xml_node const &node) { + t.update(node); } + ); } void update(Xml_node node) override @@ -81,8 +104,7 @@ struct Menu_view::Label_widget : Widget, Cursor::Glyph_position _min_width = min_w_px.decimal(); } - _cursors .update_from_xml(_cursor_update_policy, node); - _selections.update_from_xml(_selection_update_policy, node); + _update_children(node); } Area min_size() const override diff --git a/repos/gems/src/app/menu_view/main.cc b/repos/gems/src/app/menu_view/main.cc index b15679546e..94c38d7054 100644 --- a/repos/gems/src/app/menu_view/main.cc +++ b/repos/gems/src/app/menu_view/main.cc @@ -22,6 +22,7 @@ #include "depgraph_widget.h" /* Genode includes */ +#include #include #include #include @@ -419,27 +420,37 @@ void Menu_view::Main::_handle_frame_timer() } -Menu_view::Widget * -Menu_view::Widget_factory::create(Xml_node node) +Menu_view::Widget & +Menu_view::Widget_factory::create(Xml_node const &node) { - Widget *w = nullptr; - Widget::Unique_id const unique_id(++_unique_id_cnt); - if (node.has_type("label")) w = new (alloc) Label_widget (*this, node, unique_id); - if (node.has_type("button")) w = new (alloc) Button_widget (*this, node, unique_id); - if (node.has_type("vbox")) w = new (alloc) Box_layout_widget (*this, node, unique_id); - if (node.has_type("hbox")) w = new (alloc) Box_layout_widget (*this, node, unique_id); - if (node.has_type("frame")) w = new (alloc) Frame_widget (*this, node, unique_id); - if (node.has_type("float")) w = new (alloc) Float_widget (*this, node, unique_id); - if (node.has_type("depgraph")) w = new (alloc) Depgraph_widget (*this, node, unique_id); + if (node.has_type("label")) return *new (alloc) Label_widget (*this, node, unique_id); + if (node.has_type("button")) return *new (alloc) Button_widget (*this, node, unique_id); + if (node.has_type("vbox")) return *new (alloc) Box_layout_widget (*this, node, unique_id); + if (node.has_type("hbox")) return *new (alloc) Box_layout_widget (*this, node, unique_id); + if (node.has_type("frame")) return *new (alloc) Frame_widget (*this, node, unique_id); + if (node.has_type("float")) return *new (alloc) Float_widget (*this, node, unique_id); + if (node.has_type("depgraph")) return *new (alloc) Depgraph_widget (*this, node, unique_id); - if (!w) { - Genode::error("unknown widget type '", node.type(), "'"); - return 0; - } + /* + * This cannot occur because the 'List_model' ensures that 'create' is only + * called for nodes that passed 'node_type_known'. + */ + error("unknown widget type '", node.type(), "'"); + sleep_forever(); +} - return w; + +bool Menu_view::Widget_factory::node_type_known(Xml_node const &node) +{ + return node.has_type("label") + || node.has_type("button") + || node.has_type("vbox") + || node.has_type("hbox") + || node.has_type("frame") + || node.has_type("float") + || node.has_type("depgraph"); } diff --git a/repos/gems/src/app/menu_view/text_selection.h b/repos/gems/src/app/menu_view/text_selection.h index 9e29e9ff51..b866a4ffa9 100644 --- a/repos/gems/src/app/menu_view/text_selection.h +++ b/repos/gems/src/app/menu_view/text_selection.h @@ -87,39 +87,20 @@ class Menu_view::Text_selection : List_model::Element color); } - struct Model_update_policy : List_model::Update_policy + bool matches(Xml_node const &node) const { - Allocator &_alloc; - Glyph_position &_glyph_position; + return _node_name(node) == _name; + } - Model_update_policy(Allocator &alloc, Glyph_position &glyph_position) - : - _alloc(alloc), _glyph_position(glyph_position) - { } + static bool type_matches(Xml_node const &node) + { + return node.has_type("selection"); + } - void destroy_element(Text_selection &t) { destroy(_alloc, &t); } - - Text_selection &create_element(Xml_node node) - { - return *new (_alloc) - Text_selection(node, _glyph_position); - } - - void update_element(Text_selection &t, Xml_node node) - { - t._range = t._range_from_xml_node(node); - } - - static bool element_matches_xml_node(Text_selection const &t, Xml_node node) - { - return node.has_type("selection") && _node_name(node) == t._name; - } - - static bool node_is_element(Xml_node node) - { - return node.has_type("selection"); - } - }; + void update(Xml_node const &node) + { + _range = _range_from_xml_node(node); + } }; #endif /* _TEXT_SELECTION_ */ diff --git a/repos/gems/src/app/menu_view/widget.h b/repos/gems/src/app/menu_view/widget.h index 35a2d135f7..90a9ff7c9d 100644 --- a/repos/gems/src/app/menu_view/widget.h +++ b/repos/gems/src/app/menu_view/widget.h @@ -126,36 +126,22 @@ class Menu_view::Widget : List_model::Element List_model _children { }; - struct Model_update_policy : List_model::Update_policy - { - Widget_factory &_factory; - - Model_update_policy(Widget_factory &factory) : _factory(factory) { } - - void destroy_element(Widget &w) { _factory.destroy(&w); } - - Widget &create_element(Xml_node elem_node) - { - if (Widget *w = _factory.create(elem_node)) - return *w; - - throw Unknown_element_type(); - } - - void update_element(Widget &w, Xml_node node) { w.update(node); } - - static bool element_matches_xml_node(Widget const &w, Xml_node node) - { - return node.has_type(w._type_name.string()) - && Widget::node_name(node) == w._name - && node_version(node) == w._version; - } - - } _model_update_policy { _factory }; - inline void _update_children(Xml_node node) { - _children.update_from_xml(_model_update_policy, node); + update_list_model_from_xml(_children, node, + + /* create */ + [&] (Xml_node const &node) -> Widget & { + return _factory.create(node); }, + + /* destroy */ + [&] (Widget &w) { + _factory.destroy(&w); }, + + /* update */ + [&] (Widget &w, Xml_node const &node) { + w.update(node); } + ); } void _draw_children(Surface &pixel_surface, @@ -230,7 +216,7 @@ class Menu_view::Widget : List_model::Element virtual ~Widget() { - _children.destroy_all_elements(_model_update_policy); + _update_children(Xml_node("")); } bool has_name(Name const &name) const { return name == _name; } @@ -320,6 +306,24 @@ class Menu_view::Widget : List_model::Element { Genode::print(out, _name); } + + /** + * List_model::Element + */ + bool matches(Xml_node const &node) const + { + return node.has_type(_type_name.string()) + && Widget::node_name(node) == _name + && node_version(node) == _version; + } + + /** + * List_model::Element + */ + static bool type_matches(Xml_node const &node) + { + return Widget_factory::node_type_known(node); + } }; #endif /* _WIDGET_H_ */ diff --git a/repos/gems/src/app/menu_view/widget_factory.h b/repos/gems/src/app/menu_view/widget_factory.h index a15d7db8ba..a4f189b340 100644 --- a/repos/gems/src/app/menu_view/widget_factory.h +++ b/repos/gems/src/app/menu_view/widget_factory.h @@ -44,9 +44,11 @@ class Menu_view::Widget_factory alloc(alloc), styles(styles), animator(animator) { } - Widget *create(Xml_node node); + Widget &create(Xml_node const &); void destroy(Widget *widget) { Genode::destroy(alloc, widget); } + + static bool node_type_known(Xml_node const &); }; #endif /* _WIDGET_FACTORY_H_ */