menu_view: add character position to hover report

When setting the <dialog> attribute 'hover_details' to "yes", the hover
report features the character position of a hovered label.

Issue #3607
Issue #3629
This commit is contained in:
Norman Feske 2020-01-14 18:47:18 +01:00 committed by Christian Helmuth
parent 7cc4aa2a28
commit e612f7cd7d
3 changed files with 71 additions and 22 deletions

View File

@ -90,9 +90,36 @@ struct Menu_view::Label_widget : Widget, Cursor::Glyph_position
*/ */
int xpos_of_glyph(unsigned at) const override int xpos_of_glyph(unsigned at) const override
{ {
Text const truncated_at(Cstring(_text.string(), at)); 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: private:

View File

@ -126,7 +126,7 @@ struct Menu_view::Main
Attached_dataspace _input_ds { _env.rm(), _nitpicker.input()->dataspace() }; Attached_dataspace _input_ds { _env.rm(), _nitpicker.input()->dataspace() };
Widget::Unique_id _last_reported_hovered { }; Widget::Hovered _last_reported_hovered { };
void _handle_config(); void _handle_config();
@ -208,7 +208,7 @@ void Menu_view::Main::_update_hover_report()
return; 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) { if (_last_reported_hovered != new_hovered) {

View File

@ -78,11 +78,30 @@ class Menu_view::Widget : List_model<Widget>::Element
*/ */
Unique_id() { } 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; } 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) static Name node_name(Xml_node node)
{ {
return node.attribute_value("name", Name(node.type())); return node.attribute_value("name", Name(node.type()));
@ -90,7 +109,7 @@ class Menu_view::Widget : List_model<Widget>::Element
static Animated_rect::Steps motion_steps() { return { 60 }; }; static Animated_rect::Steps motion_steps() { return { 60 }; };
private: protected:
Type_name const _type_name; Type_name const _type_name;
Name const _name; Name const _name;
@ -98,8 +117,6 @@ class Menu_view::Widget : List_model<Widget>::Element
Unique_id const _unique_id; Unique_id const _unique_id;
protected:
Widget_factory &_factory; Widget_factory &_factory;
List_model<Widget> _children { }; List_model<Widget> _children { };
@ -169,6 +186,15 @@ class Menu_view::Widget : List_model<Widget>::Element
_animated_geometry.move_to(_geometry, motion_steps()); _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: public:
Margin margin { 0, 0, 0, 0 }; Margin margin { 0, 0, 0, 0 };
@ -233,16 +259,16 @@ class Menu_view::Widget : List_model<Widget>::Element
* *
* This function is used to track changes of the hover model. * 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)) 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) { _children.for_each([&] (Widget const &w) {
Unique_id const id = w.hovered(at - w.geometry().p1()); Hovered const hovered = w.hovered(at - w.geometry().p1());
if (id.valid()) if (hovered.unique_id.valid())
result = id; result = hovered;
}); });
return result; return result;
@ -259,11 +285,7 @@ class Menu_view::Widget : List_model<Widget>::Element
xml.node(_type_name.string(), [&]() { xml.node(_type_name.string(), [&]() {
xml.attribute("name", _name.string()); _gen_common_hover_attr(xml);
xml.attribute("xpos", geometry().x1());
xml.attribute("ypos", geometry().y1());
xml.attribute("width", geometry().w());
xml.attribute("height", geometry().h());
_children.for_each([&] (Widget const &w) { _children.for_each([&] (Widget const &w) {
w.gen_hover_model(xml, at - w.geometry().p1()); }); w.gen_hover_model(xml, at - w.geometry().p1()); });