From e612f7cd7d6810d4ae83f5cb88cbfe5aa722cdf7 Mon Sep 17 00:00:00 2001 From: Norman Feske Date: Tue, 14 Jan 2020 18:47:18 +0100 Subject: [PATCH] menu_view: add character position to hover report When setting the attribute 'hover_details' to "yes", the hover report features the character position of a hovered label. Issue #3607 Issue #3629 --- repos/gems/src/app/menu_view/label_widget.h | 37 +++++++++++++-- repos/gems/src/app/menu_view/main.cc | 4 +- repos/gems/src/app/menu_view/widget.h | 52 +++++++++++++++------ 3 files changed, 71 insertions(+), 22 deletions(-) diff --git a/repos/gems/src/app/menu_view/label_widget.h b/repos/gems/src/app/menu_view/label_widget.h index 7041e4d3f..d493df9e4 100644 --- a/repos/gems/src/app/menu_view/label_widget.h +++ b/repos/gems/src/app/menu_view/label_widget.h @@ -88,12 +88,39 @@ struct Menu_view::Label_widget : Widget, Cursor::Glyph_position /** * Cursor::Glyph_position interface */ - int xpos_of_glyph(unsigned at) const override - { - Text const truncated_at(Cstring(_text.string(), at)); + int xpos_of_glyph(unsigned at) const override + { + return _font->string_width(_text.string(), at).decimal(); + } - return _font->string_width(truncated_at.string()).decimal(); - } + unsigned _char_index_at_xpos(unsigned xpos) const + { + return _font->index_at_xpos(_text.string(), xpos); + } + + Hovered hovered(Point at) const override + { + Unique_id const hovered_id = Widget::hovered(at).unique_id; + + if (!hovered_id.valid()) + return Hovered { .unique_id = hovered_id, .detail = { } }; + + return { .unique_id = hovered_id, + .detail = { _char_index_at_xpos(at.x()) } }; + } + + void gen_hover_model(Xml_generator &xml, Point at) const override + { + if (_inner_geometry().contains(at)) { + + xml.node(_type_name.string(), [&]() { + + _gen_common_hover_attr(xml); + + xml.attribute("at", _char_index_at_xpos(at.x())); + }); + } + } private: diff --git a/repos/gems/src/app/menu_view/main.cc b/repos/gems/src/app/menu_view/main.cc index 9f085d3bb..7ea820551 100644 --- a/repos/gems/src/app/menu_view/main.cc +++ b/repos/gems/src/app/menu_view/main.cc @@ -126,7 +126,7 @@ struct Menu_view::Main Attached_dataspace _input_ds { _env.rm(), _nitpicker.input()->dataspace() }; - Widget::Unique_id _last_reported_hovered { }; + Widget::Hovered _last_reported_hovered { }; void _handle_config(); @@ -208,7 +208,7 @@ void Menu_view::Main::_update_hover_report() return; } - Widget::Unique_id const new_hovered = _root_widget.hovered(_hovered_position); + Widget::Hovered const new_hovered = _root_widget.hovered(_hovered_position); if (_last_reported_hovered != new_hovered) { diff --git a/repos/gems/src/app/menu_view/widget.h b/repos/gems/src/app/menu_view/widget.h index 5f78d66be..8feb463cc 100644 --- a/repos/gems/src/app/menu_view/widget.h +++ b/repos/gems/src/app/menu_view/widget.h @@ -78,11 +78,30 @@ class Menu_view::Widget : List_model::Element */ Unique_id() { } - bool operator != (Unique_id const &other) { return other.value != value; } + bool operator != (Unique_id const &other) const + { + return other.value != value; + } bool valid() const { return value != 0; } }; + struct Hovered + { + /* widget */ + Unique_id unique_id; + + /* widget-local detail */ + using Detail = String<16>; + + Detail detail; + + bool operator != (Hovered const &other) const + { + return (unique_id != other.unique_id) || (detail != other.detail); + } + }; + static Name node_name(Xml_node node) { return node.attribute_value("name", Name(node.type())); @@ -90,7 +109,7 @@ class Menu_view::Widget : List_model::Element static Animated_rect::Steps motion_steps() { return { 60 }; }; - private: + protected: Type_name const _type_name; Name const _name; @@ -98,8 +117,6 @@ class Menu_view::Widget : List_model::Element Unique_id const _unique_id; - protected: - Widget_factory &_factory; List_model _children { }; @@ -169,6 +186,15 @@ class Menu_view::Widget : List_model::Element _animated_geometry.move_to(_geometry, motion_steps()); } + void _gen_common_hover_attr(Xml_generator &xml) const + { + xml.attribute("name", _name.string()); + xml.attribute("xpos", geometry().x1()); + xml.attribute("ypos", geometry().y1()); + xml.attribute("width", geometry().w()); + xml.attribute("height", geometry().h()); + } + public: Margin margin { 0, 0, 0, 0 }; @@ -233,16 +259,16 @@ class Menu_view::Widget : List_model::Element * * This function is used to track changes of the hover model. */ - virtual Unique_id hovered(Point at) const + virtual Hovered hovered(Point at) const { if (!_inner_geometry().contains(at)) - return Unique_id(); + return { }; - Unique_id result = _unique_id; + Hovered result { .unique_id = _unique_id, .detail = { } }; _children.for_each([&] (Widget const &w) { - Unique_id const id = w.hovered(at - w.geometry().p1()); - if (id.valid()) - result = id; + Hovered const hovered = w.hovered(at - w.geometry().p1()); + if (hovered.unique_id.valid()) + result = hovered; }); return result; @@ -259,11 +285,7 @@ class Menu_view::Widget : List_model::Element xml.node(_type_name.string(), [&]() { - xml.attribute("name", _name.string()); - xml.attribute("xpos", geometry().x1()); - xml.attribute("ypos", geometry().y1()); - xml.attribute("width", geometry().w()); - xml.attribute("height", geometry().h()); + _gen_common_hover_attr(xml); _children.for_each([&] (Widget const &w) { w.gen_hover_model(xml, at - w.geometry().p1()); });