Allow to bind supertip to a formspec element

This commit is contained in:
Jean-Patrick Guerrero 2024-06-08 11:06:31 +02:00 committed by Wuzzy
parent 7c25907675
commit 3638d93b77
3 changed files with 169 additions and 62 deletions

@ -2849,6 +2849,18 @@ Elements
* `bgcolor` tooltip background color as `ColorString` (optional)
* `fontcolor` tooltip font color as `ColorString` (optional)
### `supertip[<gui_element_name>;<staticPos>;<width>;<name>;<text>]`
* Adds an advanced tooltip for an element. Displays a formatted text using
`Markup Language` in a tooltip.
This supertip have to be declared *after* its parent element that is bound to.
* `staticPos` is an optional position of the form `posX,posY` in formspec coordinates.
If specified, the tooltip will always appear at these given formspec coordinates.
If this field is empty, the tooltip will follow the cursor.
* `width` sets the tooltip width (in formspec units).
* `name` is the name of the field.
* `text` is the formatted text using `Markup Language` described below.
### `supertip[<X>,<Y>;<W>,<H>;<staticPos>;<width>;<name>;<text>]`
* Adds an advanced tooltip for an area. Displays a formatted text using

@ -1758,75 +1758,135 @@ void GUIFormSpecMenu::parseSuperTip(parserData *data, const std::string &element
{
std::vector<std::string> parts;
if (!precheckElement("supertip", element, 6, 6, parts))
if (!precheckElement("supertip", element, 5, 6, parts))
return;
std::vector<std::string> v_pos = split(parts[0], ',');
std::vector<std::string> v_geom = split(parts[1], ',');
// Get mode and check size
bool rect_mode = parts[0].find(',') != std::string::npos;
size_t base_size = rect_mode ? 6 : 5;
if (parts.size() != base_size && parts.size() != base_size + 2) {
errorstream << "Invalid supertip element(" << parts.size() << "): '"
<< element << "'" << std::endl;
return;
}
MY_CHECKPOS("supertip", 0);
MY_CHECKGEOM("supertip", 1);
if (rect_mode) {
std::vector<std::string> v_pos = split(parts[0], ',');
std::vector<std::string> v_geom = split(parts[1], ',');
std::vector<std::string> v_stpos;
bool floating = true;
if(parts[2] != "") {
v_stpos = split(parts[2], ',');
if (v_stpos.size() != 2) {
errorstream << "Invalid staticPos in supertip element(" << parts.size() <<
"): \"" << parts[2] << "\"" << std::endl;
return;
MY_CHECKPOS("supertip", 0);
MY_CHECKGEOM("supertip", 1);
std::vector<std::string> v_stpos;
bool floating = true;
if(parts[2] != "") {
v_stpos = split(parts[2], ',');
if (v_stpos.size() != 2) {
errorstream << "Invalid staticPos in supertip element(" << parts.size() <<
"): \"" << parts[2] << "\"" << std::endl;
return;
}
floating = false;
}
floating = false;
}
s32 width = stof(parts[3]) * spacing.Y;
std::string name = parts[4];
std::string text = parts[5];
s32 width = stof(parts[3]) * spacing.Y;
std::string name = parts[4];
std::string text = parts[5];
v2s32 pos;
v2s32 geom;
v2s32 stpos;
v2s32 pos;
v2s32 geom;
v2s32 stpos;
if (data->real_coordinates) {
pos = getRealCoordinateBasePos(v_pos);
geom = getRealCoordinateGeometry(v_geom);
if (data->real_coordinates) {
pos = getRealCoordinateBasePos(v_pos);
geom = getRealCoordinateGeometry(v_geom);
if (!floating)
stpos = getRealCoordinateBasePos(v_stpos);
if (!floating)
stpos = getRealCoordinateBasePos(v_stpos);
} else {
pos = getElementBasePos(&v_pos);
geom.X = stof(v_geom[0]) * spacing.X;
geom.Y = stof(v_geom[1]) * spacing.Y;
if (!floating)
stpos = getElementBasePos(&v_stpos);
}
core::rect<s32> rect(pos, pos + geom);
if (m_form_src)
text = m_form_src->resolveText(text);
FieldSpec spec(
name,
translate_string(utf8_to_wide(unescape_string(text))),
L"",
258 + m_fields.size()
);
GUIHyperText *e = new GUIHyperText(spec.flabel.c_str(), Environment,
data->current_parent, spec.fid, rect, m_client, m_tsrc);
auto style = getStyleForElement("supertip", spec.fname);
e->setStyles(style);
SuperTipSpec geospec(name, text, e->getAbsoluteClippingRect(), stpos, width, floating);
m_fields.push_back(spec);
m_supertips.emplace_back(e, geospec);
e->setVisible(false);
e->drop();
} else {
pos = getElementBasePos(&v_pos);
geom.X = stof(v_geom[0]) * spacing.X;
geom.Y = stof(v_geom[1]) * spacing.Y;
std::string fieldname = parts[0];
core::rect<s32> rect;
if (!floating)
stpos = getElementBasePos(&v_stpos);
for (const auto &f : m_fields) {
if (f.fname == fieldname) {
auto *e = getElementFromId(f.fid, true);
rect = e->getAbsoluteClippingRect();
break;
}
}
std::vector<std::string> v_stpos;
bool floating = true;
if(parts[1] != "") {
v_stpos = split(parts[1], ',');
if (v_stpos.size() != 2) {
errorstream << "Invalid staticPos in supertip element(" << parts.size() <<
"): \"" << parts[2] << "\"" << std::endl;
return;
}
floating = false;
}
s32 width = stof(parts[2]) * spacing.Y;
v2s32 stpos;
if (!floating) {
if (data->real_coordinates)
stpos = getRealCoordinateBasePos(v_stpos);
else
stpos = getElementBasePos(&v_stpos);
}
std::string name = parts[3];
std::string text = parts[4];
if (m_form_src)
text = m_form_src->resolveText(text);
FieldSpec spec(
name,
translate_string(utf8_to_wide(unescape_string(text))),
L"",
258 + m_fields.size()
);
m_fields.push_back(spec);
m_supertip_map[fieldname] = SuperTipSpec(name, text, rect, stpos, width, floating);
}
core::rect<s32> rect(pos, pos + geom);
if (m_form_src)
text = m_form_src->resolveText(text);
FieldSpec spec(
name,
translate_string(utf8_to_wide(unescape_string(text))),
L"",
258 + m_fields.size()
);
GUIHyperText *e = new GUIHyperText(spec.flabel.c_str(), Environment,
data->current_parent, spec.fid, rect, m_client, m_tsrc);
auto style = getStyleForElement("supertip", spec.fname);
e->setStyles(style);
SuperTipSpec geospec(e->getAbsoluteClippingRect(), stpos, width, floating);
m_fields.push_back(spec);
m_supertips.emplace_back(e, geospec);
e->setVisible(false);
e->drop();
}
void GUIFormSpecMenu::parseLabel(parserData* data, const std::string &element)
@ -3190,6 +3250,7 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
m_fields.clear();
m_tooltips.clear();
m_supertips.clear();
m_supertip_map.clear();
m_tooltip_rects.clear();
m_inventory_rings.clear();
m_dropdowns.clear();
@ -3722,12 +3783,16 @@ void GUIFormSpecMenu::drawMenu()
/*
Draw supertip
*/
for (const auto &pair : m_supertips) {
const auto &hover_rect = pair.second.hover_rect;
for (auto &pair : m_supertips) {
auto &spec = pair.second;
const auto &hover_rect = spec.hover_rect;
if (hover_rect.getArea() > 0 && hover_rect.isPointInside(m_pointer))
showSuperTip(pair.first, pair.second);
else
showSuperTip(pair.first, spec);
else {
pair.first->setVisible(false);
spec.bound = false;
}
}
// Some elements are only visible while being drawn
@ -3812,6 +3877,29 @@ void GUIFormSpecMenu::drawMenu()
if (!text.empty())
showTooltip(text, m_tooltips[field.fname].color,
m_tooltips[field.fname].bgcolor);
if (m_supertip_map.count(field.fname) != 0) {
auto &spec = m_supertip_map[field.fname];
if (!spec.bound) {
spec.bound = true;
auto *parent_element = getElementFromId(field.fid, true);
auto txt = translate_string(utf8_to_wide(unescape_string(spec.text)));
GUIHyperText *e = new GUIHyperText(
txt.c_str(), Environment,
parent_element->getParent(), field.fid,
spec.hover_rect, m_client, m_tsrc);
auto style = getStyleForElement("supertip", spec.name);
e->setStyles(style);
m_supertips.emplace_back(e, spec);
e->setVisible(false);
e->drop();
}
}
}
if (cursor_control &&

@ -169,8 +169,11 @@ class GUIFormSpecMenu : public GUIModalMenu
struct SuperTipSpec
{
SuperTipSpec() = default;
SuperTipSpec(const core::rect<s32> &a_rect, v2s32 a_stpos, s32 a_width,
SuperTipSpec(const std::string &a_name, const std::string &a_text,
const core::rect<s32> &a_rect, v2s32 a_stpos, s32 a_width,
bool a_floating) :
name(a_name),
text(a_text),
hover_rect(a_rect),
stpos(a_stpos),
width(a_width),
@ -178,10 +181,13 @@ class GUIFormSpecMenu : public GUIModalMenu
{
}
std::string name;
std::string text;
core::rect<s32> hover_rect;
v2s32 stpos;
s32 width;
bool floating;
bool bound = false;
};
public:
@ -363,6 +369,7 @@ class GUIFormSpecMenu : public GUIModalMenu
std::vector<std::pair<FieldSpec, gui::IGUICheckBox *>> m_checkboxes;
std::map<std::string, TooltipSpec> m_tooltips;
std::vector<std::pair<GUIHyperText *, SuperTipSpec>> m_supertips;
std::map<std::string, SuperTipSpec> m_supertip_map;
std::vector<std::pair<gui::IGUIElement *, TooltipSpec>> m_tooltip_rects;
std::vector<std::pair<FieldSpec, GUIScrollBar *>> m_scrollbars;
std::vector<std::pair<FieldSpec, std::vector<std::string>>> m_dropdowns;