Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[NO SQUASH] Add hypertext support to tooltips #14728

Draft
wants to merge 13 commits into
base: master
Choose a base branch
from
20 changes: 20 additions & 0 deletions doc/lua_api.md
Original file line number Diff line number Diff line change
Expand Up @@ -2849,6 +2849,18 @@ Elements
* `bgcolor` tooltip background color as `ColorString` (optional)
* `fontcolor` tooltip font color as `ColorString` (optional)

### `supertip[<X>,<Y>;<W>,<H>;<staticPos>;<width>;<name>;<text>]`

* Adds an advanced tooltip for an area. Displays a formatted text using
`Markup Language` in a tooltip.
* `X`, `Y`, `W` and `H` set the cursor hover area that allows the tooltip to pop-up.
* `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.

### `image[<X>,<Y>;<W>,<H>;<texture name>;<middle>]`

* Show an image.
Expand Down Expand Up @@ -3412,6 +3424,7 @@ Some types may inherit styles from parent types.
* model
* pwdfield, inherits from field
* scrollbar
* supertip
* tabheader
* table
* textarea
Expand Down Expand Up @@ -3512,6 +3525,13 @@ Some types may inherit styles from parent types.
* sound - a sound to be played when triggered.
* scrollbar
* noclip - boolean, set to true to allow the element to exceed formspec bounds.
* supertip
* noclip - boolean, set to true to allow the element to exceed formspec bounds.
* bgcolor - color, sets background color.
* border - boolean, draw border. Set to false to hide the bevelled tooltip pane. Default false.
* bgimg - standard background image. Defaults to none.
* bgimg_middle - Makes the bgimg textures render in 9-sliced mode and defines the middle rect.
See background9[] documentation for more details.
* tabheader
* noclip - boolean, set to true to allow the element to exceed formspec bounds.
* sound - a sound to be played when a different tab is selected.
Expand Down
39 changes: 38 additions & 1 deletion games/devtest/mods/testformspec/formspec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,43 @@ mouse control = true]
background9[0,0;0,0;testformspec_bg_9slice.png;true;4,6]
background[1,1;0,0;testformspec_bg.png;true]
]],

-- Tooltip
[[
formspec_version[7]
size[12,13]
label[1,0.5;Hover a red box for a tooltip.]

box[1,1;1,1;#ff000080]
tooltip[1,1;1,1;Normal tooltip]

box[1,3;1,1;#ff000080]
box[2.4,3.4;0.2,0.2;#ffffff80]
supertip[1,3;1,1;2.5,3.5;5;supertip_static;<big>Simple supertip (<i>static</i>)</big>
This one should always appear at the tiny white square.]
box[1,5;1,1;#ff000080]
supertip[1,5;1,1;;5;supertip_dynamic;<big>Simple supertip (<i>dynamic</i>)</big>
This should appear at the cursor.]

box[1,7;1,1;#ff000080]
supertip[1,7;1,1;;5;supertip_dynamic_complex;]]..minetest.formspec_escape([[<big>Complex supertip (<i>dynamic</i>)</big>
<img name=testformspec_node.png float=right width=64 height=64>
<left>Left align</left>
<center>Right align</center>
<right>Right align</right>
<b>Bold</b> <i>Italic</i> <u>Underline</u> <mono>Mono</mono>
Item:
<item name=testformspec:node>]])..[[]

box[1,9;1,1;#ff000080]
supertip[1,9;1,1;;5;supertip_stone;]]..minetest.formspec_escape([[<global color=#333 background=#aaa margin=20>
<item name=testformspec:node float=left width=64 height=64>
<big><b><center>Formspec Test Node</center></b></big>
The <b>Formspec Test Node</b> is a dummy node to display an item in the <mono>testformspec</mono> mod.

• <b>Max. stack size:</b> 99
• <b>Drops:</b> <i>itself</i> <item name=testformspec:node width=32 height=32>]])..
"]"
}

local page_id = 2
Expand All @@ -477,7 +514,7 @@ local function show_test_formspec(pname)
page = page()
end

local fs = page .. "tabheader[0,0;11,0.65;maintabs;Real Coord,Styles,Noclip,Hypertext,Tabs,Invs,Window,Anim,Model,ScrollC,Sound,Background,Unsized;" .. page_id .. ";false;false]"
local fs = page .. "tabheader[0,0;11,0.65;maintabs;Real Coord,Styles,Noclip,Hypertext,Tabs,Invs,Window,Anim,Model,ScrollC,Sound,Background,Unsized,Tooltip;" .. page_id .. ";false;false]"

minetest.show_formspec(pname, "testformspec:formspec", fs)
end
Expand Down
143 changes: 142 additions & 1 deletion src/gui/guiFormSpecMenu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "guiInventoryList.h"
#include "guiItemImage.h"
#include "guiScrollContainer.h"
#include "guiHyperText.h"
#include "guiScene.h"

#define MY_CHECKPOS(a,b) \
Expand Down Expand Up @@ -1755,6 +1754,81 @@ void GUIFormSpecMenu::parseHyperText(parserData *data, const std::string &elemen
m_fields.push_back(spec);
}

void GUIFormSpecMenu::parseSuperTip(parserData *data, const std::string &element)
{
std::vector<std::string> parts;

if (!precheckElement("supertip", element, 6, 6, parts))
return;

std::vector<std::string> v_pos = split(parts[0], ',');
std::vector<std::string> v_geom = split(parts[1], ',');

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;
}

s32 width = stof(parts[3]) * spacing.Y;
std::string name = parts[4];
std::string text = parts[5];

v2s32 pos;
v2s32 geom;
v2s32 stpos;

if (data->real_coordinates) {
pos = getRealCoordinateBasePos(v_pos);
geom = getRealCoordinateGeometry(v_geom);

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(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)
{
std::vector<std::string> parts;
Expand Down Expand Up @@ -2958,6 +3032,11 @@ void GUIFormSpecMenu::parseElement(parserData* data, const std::string &element)
return;
}

if (type == "supertip") {
parseSuperTip(data,description);
return;
}

if (type == "label") {
parseLabel(data,description);
return;
Expand Down Expand Up @@ -3110,6 +3189,7 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
m_scrollbars.clear();
m_fields.clear();
m_tooltips.clear();
m_supertips.clear();
m_tooltip_rects.clear();
m_inventory_rings.clear();
m_dropdowns.clear();
Expand Down Expand Up @@ -3639,6 +3719,17 @@ void GUIFormSpecMenu::drawMenu()
}
}

/*
Draw supertip
*/
for (const auto &pair : m_supertips) {
const auto &hover_rect = pair.second.hover_rect;
if (hover_rect.getArea() > 0 && hover_rect.isPointInside(m_pointer))
showSuperTip(pair.first, pair.second);
else
pair.first->setVisible(false);
}

// Some elements are only visible while being drawn
for (gui::IGUIElement *e : m_clickthrough_elements)
e->setVisible(true);
Expand Down Expand Up @@ -3797,6 +3888,56 @@ void GUIFormSpecMenu::showTooltip(const std::wstring &text,
bringToFront(m_tooltip_element);
}

void GUIFormSpecMenu::showSuperTip(GUIHyperText *e, const SuperTipSpec &spec)
{
// Supertip size and offset
s32 tooltip_width = spec.width;
s32 tooltip_height = e->getTextHeight() + 5;
s32 tooltip_x, tooltip_y;

v2u32 screenSize = Environment->getVideoDriver()->getScreenSize();

// Calculate and set the tooltip position
if (spec.floating) {
/* Dynamic tooltip position, relative to cursor */
int tooltip_offset_x = m_btn_height;
int tooltip_offset_y = m_btn_height;

if (m_pointer_type == PointerType::Touch) {
tooltip_offset_x *= 3;
tooltip_offset_y = 0;
if (m_pointer.X > (s32)screenSize.X / 2)
tooltip_offset_x = -(tooltip_offset_x + tooltip_width);
}

v2s32 basePos = getBasePos();

tooltip_x = (m_pointer.X - basePos.X) + tooltip_offset_x*2;
tooltip_y = (m_pointer.Y - basePos.Y) + tooltip_offset_y*2;
} else {
/* Static tooltip position, using formspec coordinates */
tooltip_x = spec.stpos[0];
tooltip_y = spec.stpos[1];
}

if (tooltip_x + tooltip_width > (s32)screenSize.X)
tooltip_x = (s32)screenSize.X - tooltip_width - m_btn_height;
if (tooltip_y + tooltip_height > (s32)screenSize.Y)
tooltip_y = (s32)screenSize.Y - tooltip_height - m_btn_height;

e->setRelativePosition(
core::rect<s32>(
core::position2d<s32>(tooltip_x, tooltip_y),
core::dimension2d<s32>(tooltip_width, tooltip_height)
)
);

// Display the supertip
e->setVisible(true);
bringToFront(e);
}


void GUIFormSpecMenu::updateSelectedItem()
{
// Don't update when dragging an item
Expand Down
22 changes: 22 additions & 0 deletions src/gui/guiFormSpecMenu.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "guiInventoryList.h"
#include "guiScrollBar.h"
#include "guiTable.h"
#include "guiHyperText.h"
#include "network/networkprotocol.h"
#include "client/joystick_controller.h"
#include "util/string.h"
Expand Down Expand Up @@ -165,6 +166,24 @@ class GUIFormSpecMenu : public GUIModalMenu
irr::video::SColor color;
};

struct SuperTipSpec
{
SuperTipSpec() = default;
SuperTipSpec(const core::rect<s32> &a_rect, v2s32 a_stpos, s32 a_width,
bool a_floating) :
hover_rect(a_rect),
stpos(a_stpos),
width(a_width),
floating(a_floating)
{
}

core::rect<s32> hover_rect;
v2s32 stpos;
s32 width;
bool floating;
};

public:
GUIFormSpecMenu(JoystickController *joystick,
gui::IGUIElement* parent, s32 id,
Expand Down Expand Up @@ -343,6 +362,7 @@ class GUIFormSpecMenu : public GUIModalMenu
std::vector<std::pair<FieldSpec, GUITable *>> m_tables;
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::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;
Expand Down Expand Up @@ -464,6 +484,7 @@ class GUIFormSpecMenu : public GUIModalMenu
void parseTextArea(parserData* data,std::vector<std::string>& parts,
const std::string &type);
void parseHyperText(parserData *data, const std::string &element);
void parseSuperTip(parserData *data, const std::string &element);
void parseLabel(parserData* data, const std::string &element);
void parseVertLabel(parserData* data, const std::string &element);
void parseImageButton(parserData* data, const std::string &element,
Expand Down Expand Up @@ -494,6 +515,7 @@ class GUIFormSpecMenu : public GUIModalMenu

void showTooltip(const std::wstring &text, const irr::video::SColor &color,
const irr::video::SColor &bgcolor);
void showSuperTip(GUIHyperText *e, const SuperTipSpec &spec);

/**
* In formspec version < 2 the elements were not ordered properly. Some element
Expand Down
Loading
Loading