mirror of
https://github.com/minetest/minetest.git
synced 2024-07-04 15:05:27 +02:00
Add "supertip" formspec element
This commit is contained in:
parent
87232358d3
commit
46bc0d5ca0
@ -2849,6 +2849,16 @@ Elements
|
||||
* `bgcolor` tooltip background color as `ColorString` (optional)
|
||||
* `fontcolor` tooltip font color as `ColorString` (optional)
|
||||
|
||||
### `supertip[<X>,<Y>;<W>,<H>;<posX>,<posY>;<width>;<name>;<text>]`
|
||||
|
||||
* Displays a formatted text using `Markup Language` in a tooltip.
|
||||
* `x`, `y`, `w` and `h` set the mouse hover area that allows the tooltip to pop-up.
|
||||
* `posX` and `posY` set the static positioning of the tooltip (optional).
|
||||
If not set, the tooltip is floating (moving with the pointer).
|
||||
* `width` sets the tooltip width.
|
||||
* `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.
|
||||
@ -3412,6 +3422,7 @@ Some types may inherit styles from parent types.
|
||||
* model
|
||||
* pwdfield, inherits from field
|
||||
* scrollbar
|
||||
* supertip
|
||||
* tabheader
|
||||
* table
|
||||
* textarea
|
||||
@ -3512,6 +3523,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.
|
||||
|
@ -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) \
|
||||
@ -1755,6 +1754,77 @@ void GUIFormSpecMenu::parseHyperText(parserData *data, const std::string &elemen
|
||||
m_fields.push_back(spec);
|
||||
}
|
||||
|
||||
void GUIFormSpecMenu::parseSuperTip(parserData *data, const std::string &element)
|
||||
{
|
||||
constexpr char max_parts = 6;
|
||||
std::vector<std::string> parts;
|
||||
|
||||
if (!precheckElement("supertip", element, 5, max_parts, parts))
|
||||
return;
|
||||
|
||||
std::vector<std::string> v_stpos;
|
||||
std::vector<std::string> v_pos = split(parts[0], ',');
|
||||
std::vector<std::string> v_geom = split(parts[1], ',');
|
||||
bool floating = parts.size() == max_parts - 1;
|
||||
|
||||
if (!floating)
|
||||
v_stpos = split(parts[2], ',');
|
||||
|
||||
const char i = max_parts - parts.size();
|
||||
s32 width = stof(parts[3-i]) * spacing.Y;
|
||||
std::string name = parts[4-i];
|
||||
std::string text = parts[5-i];
|
||||
|
||||
MY_CHECKPOS("supertip", 0);
|
||||
MY_CHECKGEOM("supertip", 1);
|
||||
MY_CHECKPOS("supertip", 2);
|
||||
|
||||
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;
|
||||
@ -2958,6 +3028,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;
|
||||
@ -3110,6 +3185,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();
|
||||
@ -3639,6 +3715,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);
|
||||
@ -3797,6 +3884,39 @@ void GUIFormSpecMenu::showTooltip(const std::wstring &text,
|
||||
bringToFront(m_tooltip_element);
|
||||
}
|
||||
|
||||
void GUIFormSpecMenu::showSuperTip(GUIHyperText *e, const SuperTipSpec &spec)
|
||||
{
|
||||
// Supertip size and offset
|
||||
s32 W = spec.width;
|
||||
s32 H = e->getTextHeight();
|
||||
s32 X,Y;
|
||||
|
||||
if (spec.floating) {
|
||||
/* Issue with floating tooltips' positioning here.
|
||||
Set hardcoded values that only works on 16:10/4K displays. */
|
||||
X = m_pointer.X - 1120;
|
||||
Y = m_pointer.Y - 400;
|
||||
} else {
|
||||
/* Static tooltips */
|
||||
X = spec.stpos[0];
|
||||
Y = spec.stpos[1];
|
||||
}
|
||||
|
||||
v2u32 screenSize = Environment->getVideoDriver()->getScreenSize();
|
||||
|
||||
if (X + W > (s32)screenSize.X)
|
||||
X = (s32)screenSize.X - W - m_btn_height;
|
||||
if (Y + H > (s32)screenSize.Y)
|
||||
Y = (s32)screenSize.Y - H - m_btn_height;
|
||||
|
||||
e->setRelativePosition(core::rect<s32>(core::position2d(X,Y), core::dimension2d(W,H)));
|
||||
|
||||
// Display the supertip
|
||||
e->setVisible(true);
|
||||
bringToFront(e);
|
||||
}
|
||||
|
||||
|
||||
void GUIFormSpecMenu::updateSelectedItem()
|
||||
{
|
||||
// Don't update when dragging an item
|
||||
|
@ -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"
|
||||
@ -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,
|
||||
@ -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;
|
||||
@ -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,
|
||||
@ -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
|
||||
|
@ -29,12 +29,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "irrlicht_changes/CGUITTFont.h"
|
||||
#include "mainmenumanager.h"
|
||||
#include "porting.h"
|
||||
|
||||
using namespace irr::gui;
|
||||
#include "client/guiscalingfilter.h"
|
||||
|
||||
static bool check_color(const std::string &str)
|
||||
{
|
||||
irr::video::SColor color;
|
||||
video::SColor color;
|
||||
return parseColorString(str, color, false);
|
||||
}
|
||||
|
||||
@ -372,7 +371,7 @@ void ParsedText::globalTag(const AttrsList &attrs)
|
||||
else if (attr.second == "middle")
|
||||
valign = ParsedText::VALIGN_MIDDLE;
|
||||
} else if (attr.first == "background") {
|
||||
irr::video::SColor color;
|
||||
video::SColor color;
|
||||
if (attr.second == "none") {
|
||||
background_type = BACKGROUND_NONE;
|
||||
} else if (parseColorString(attr.second, color, false)) {
|
||||
@ -643,7 +642,7 @@ TextDrawer::TextDrawer(const wchar_t *text, Client *client,
|
||||
if (e.font) {
|
||||
e.dim.Width = e.font->getDimension(e.text.c_str()).Width;
|
||||
e.dim.Height = e.font->getDimension(L"Yy").Height;
|
||||
if (e.font->getType() == irr::gui::EGFT_CUSTOM) {
|
||||
if (e.font->getType() == gui::EGFT_CUSTOM) {
|
||||
CGUITTFont *tmp = static_cast<CGUITTFont*>(e.font);
|
||||
e.baseline = e.dim.Height - 1 - tmp->getAscender() / 64;
|
||||
}
|
||||
@ -940,18 +939,49 @@ void TextDrawer::place(const core::rect<s32> &dest_rect)
|
||||
m_voffset = 0;
|
||||
}
|
||||
|
||||
void TextDrawer::drawBackgroundImage(
|
||||
video::IVideoDriver *driver, const ParsedText &m_text, const core::rect<s32> &clip_rect)
|
||||
{
|
||||
auto size = m_text.background_image->getOriginalSize();
|
||||
|
||||
if (m_text.background_middle.getArea() > 0) {
|
||||
draw2DImage9Slice(driver, m_text.background_image, clip_rect,
|
||||
core::rect<s32>(0, 0, size.Width, size.Height), m_text.background_middle);
|
||||
} else {
|
||||
const video::SColor color(255, 255, 255, 255);
|
||||
const video::SColor colors[] = {color, color, color, color};
|
||||
|
||||
draw2DImageFilterScaled(driver, m_text.background_image, clip_rect,
|
||||
core::rect<s32>(0, 0, size.Width, size.Height), nullptr, colors, true);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw text in a rectangle with a given offset. Items are actually placed in
|
||||
// relative (to upper left corner) coordinates.
|
||||
void TextDrawer::draw(const core::rect<s32> &clip_rect,
|
||||
const core::position2d<s32> &dest_offset)
|
||||
{
|
||||
irr::video::IVideoDriver *driver = m_guienv->getVideoDriver();
|
||||
video::IVideoDriver *driver = m_guienv->getVideoDriver();
|
||||
core::position2d<s32> offset = dest_offset;
|
||||
offset.Y += m_voffset;
|
||||
|
||||
if (m_text.background_type == ParsedText::BACKGROUND_COLOR)
|
||||
driver->draw2DRectangle(m_text.background_color, clip_rect);
|
||||
|
||||
if (m_text.border) {
|
||||
const video::SColor color(255,0,0,0);
|
||||
const auto &UpperLeft = clip_rect.UpperLeftCorner;
|
||||
const auto &LowerRight = clip_rect.LowerRightCorner;
|
||||
|
||||
driver->draw2DLine(UpperLeft, core::position2di(LowerRight.X, UpperLeft.Y), color);
|
||||
driver->draw2DLine(core::position2di(LowerRight.X, UpperLeft.Y), LowerRight, color);
|
||||
driver->draw2DLine(LowerRight, core::position2di(UpperLeft.X, LowerRight.Y), color);
|
||||
driver->draw2DLine(core::position2di(UpperLeft.X, LowerRight.Y), UpperLeft, color);
|
||||
}
|
||||
|
||||
if (m_text.background_image)
|
||||
drawBackgroundImage(driver, m_text, clip_rect);
|
||||
|
||||
for (auto &p : m_text.m_paragraphs) {
|
||||
for (auto &el : p.elements) {
|
||||
core::rect<s32> rect(el.pos + offset, el.dim);
|
||||
@ -961,7 +991,7 @@ void TextDrawer::draw(const core::rect<s32> &clip_rect,
|
||||
switch (el.type) {
|
||||
case ParsedText::ELEMENT_SEPARATOR:
|
||||
case ParsedText::ELEMENT_TEXT: {
|
||||
irr::video::SColor color = el.color;
|
||||
video::SColor color = el.color;
|
||||
|
||||
for (auto tag : el.tags)
|
||||
if (&(*tag) == m_hovertag)
|
||||
@ -992,9 +1022,9 @@ void TextDrawer::draw(const core::rect<s32> &clip_rect,
|
||||
m_tsrc->getTexture(
|
||||
stringw_to_utf8(el.text));
|
||||
if (texture != 0)
|
||||
m_guienv->getVideoDriver()->draw2DImage(
|
||||
driver->draw2DImage(
|
||||
texture, rect,
|
||||
irr::core::rect<s32>(
|
||||
core::rect<s32>(
|
||||
core::position2d<s32>(0, 0),
|
||||
texture->getOriginalSize()),
|
||||
&clip_rect, 0, true);
|
||||
@ -1006,7 +1036,7 @@ void TextDrawer::draw(const core::rect<s32> &clip_rect,
|
||||
ItemStack item;
|
||||
item.deSerialize(stringw_to_utf8(el.text), idef);
|
||||
|
||||
drawItemStack(m_guienv->getVideoDriver(),
|
||||
drawItemStack(driver,
|
||||
g_fontengine->getFont(), item, rect, &clip_rect, m_client,
|
||||
IT_ROT_OTHER, el.angle, el.rotation);
|
||||
}
|
||||
@ -1032,13 +1062,13 @@ GUIHyperText::GUIHyperText(const wchar_t *text, IGUIEnvironment *environment,
|
||||
setDebugName("GUIHyperText");
|
||||
#endif
|
||||
|
||||
IGUISkin *skin = 0;
|
||||
IGUISkin *skin = nullptr;
|
||||
if (Environment)
|
||||
skin = Environment->getSkin();
|
||||
|
||||
m_scrollbar_width = skin ? skin->getSize(gui::EGDS_SCROLLBAR_SIZE) : 16;
|
||||
|
||||
core::rect<s32> rect = irr::core::rect<s32>(
|
||||
core::rect<s32> rect = core::rect<s32>(
|
||||
RelativeRect.getWidth() - m_scrollbar_width, 0,
|
||||
RelativeRect.getWidth(), RelativeRect.getHeight());
|
||||
|
||||
@ -1084,6 +1114,25 @@ void GUIHyperText::checkHover(s32 X, s32 Y)
|
||||
cursor_control->setActiveIcon(m_drawer.m_hovertag ? gui::ECI_HAND : gui::ECI_NORMAL);
|
||||
}
|
||||
|
||||
void GUIHyperText::setStyles(const std::array<StyleSpec, StyleSpec::NUM_STATES> &styles)
|
||||
{
|
||||
StyleSpec::State state = StyleSpec::STATE_DEFAULT;
|
||||
StyleSpec style = StyleSpec::getStyleFromStatePropagation(styles, state);
|
||||
|
||||
ParsedText &text = m_drawer.getText();
|
||||
text.background_middle = style.getRect(StyleSpec::BGIMG_MIDDLE, core::rect<s32>());
|
||||
text.border = style.getBool(StyleSpec::BORDER, false);
|
||||
setNotClipped(style.getBool(StyleSpec::NOCLIP, true));
|
||||
|
||||
if (text.background_type != text.BackgroundType::BACKGROUND_COLOR) {
|
||||
text.background_type = text.BackgroundType::BACKGROUND_COLOR;
|
||||
text.background_color = style.getColor(StyleSpec::BGCOLOR, video::SColor(255,110,130,60));
|
||||
}
|
||||
|
||||
if (style.isNotDefault(StyleSpec::BGIMG))
|
||||
text.background_image = style.getTexture(StyleSpec::BGIMG, m_tsrc);
|
||||
}
|
||||
|
||||
bool GUIHyperText::OnEvent(const SEvent &event)
|
||||
{
|
||||
// Scroll bar
|
||||
|
@ -24,8 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include "irrlichttypes_extrabloated.h"
|
||||
|
||||
using namespace irr;
|
||||
#include "StyleSpec.h"
|
||||
|
||||
class ISimpleTextureSource;
|
||||
class Client;
|
||||
@ -99,8 +98,8 @@ class ParsedText
|
||||
|
||||
gui::IGUIFont *font;
|
||||
|
||||
irr::video::SColor color;
|
||||
irr::video::SColor hovercolor;
|
||||
video::SColor color;
|
||||
video::SColor hovercolor;
|
||||
bool underline;
|
||||
|
||||
s32 baseline = 0;
|
||||
@ -130,7 +129,10 @@ class ParsedText
|
||||
s32 margin = 3;
|
||||
ValignType valign = VALIGN_TOP;
|
||||
BackgroundType background_type = BACKGROUND_NONE;
|
||||
irr::video::SColor background_color;
|
||||
video::SColor background_color;
|
||||
video::ITexture *background_image = nullptr;
|
||||
core::rect<s32> background_middle;
|
||||
bool border = false;
|
||||
|
||||
Tag m_root_tag;
|
||||
|
||||
@ -177,6 +179,8 @@ class TextDrawer
|
||||
inline s32 getHeight() { return m_height; };
|
||||
void draw(const core::rect<s32> &clip_rect,
|
||||
const core::position2d<s32> &dest_offset);
|
||||
void drawBackgroundImage(video::IVideoDriver *driver, const ParsedText &m_text, const core::rect<s32> &clip_rect);
|
||||
ParsedText &getText() { return m_text; }
|
||||
ParsedText::Element *getElementAt(core::position2d<s32> pos);
|
||||
ParsedText::Tag *m_hovertag;
|
||||
|
||||
@ -211,10 +215,13 @@ class GUIHyperText : public gui::IGUIElement
|
||||
//! draws the element and its children
|
||||
virtual void draw();
|
||||
|
||||
core::dimension2du getTextDimension();
|
||||
//! Returns the height of the text in pixels when it is drawn.
|
||||
s32 getTextHeight() { return m_drawer.getHeight(); }
|
||||
|
||||
bool OnEvent(const SEvent &event);
|
||||
|
||||
void setStyles(const std::array<StyleSpec, StyleSpec::NUM_STATES> &styles);
|
||||
|
||||
protected:
|
||||
// GUI members
|
||||
ISimpleTextureSource *m_tsrc;
|
||||
|
Loading…
Reference in New Issue
Block a user