This commit is contained in:
y5nw 2024-04-19 09:43:01 +02:00 committed by GitHub
commit 297d2342ff
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 88 additions and 13 deletions

View File

@ -2681,6 +2681,8 @@ Version History
* Formspec version 7 (5.8.0): * Formspec version 7 (5.8.0):
* style[]: Add focused state for buttons * style[]: Add focused state for buttons
* Add field_enter_after_edit[] (experimental) * Add field_enter_after_edit[] (experimental)
* Formspec version 8 (5.9.0):
* hypertext[]: Allow `em` as a length unit
Elements Elements
-------- --------
@ -3535,6 +3537,10 @@ Some tags can enclose text, they open with `<tagname>` and close with `</tagname
Tags can have attributes, in that case, attributes are in the opening tag in Tags can have attributes, in that case, attributes are in the opening tag in
form of a key/value separated with equal signs. Attribute values should not be quoted. form of a key/value separated with equal signs. Attribute values should not be quoted.
Attributes that describe lengths (font size and image dimensions) can be a regular
number, which describes the size in pixels, or a number with the unit `em`, which
describes the size in relation to the font size of the enclosing element.
If you want to insert a literal greater-than sign or a backslash into the text, If you want to insert a literal greater-than sign or a backslash into the text,
you must escape it by preceding it with a backslash. you must escape it by preceding it with a backslash.

View File

@ -70,7 +70,9 @@ This is a normal text.
<bigger><mono>style</mono> test</bigger> <bigger><mono>style</mono> test</bigger>
<style color=#FFFF00>Yellow text.</style> <style color=#FF0000>Red text.</style> <style color=#FFFF00>Yellow text.</style> <style color=#FF0000>Red text.</style>
<style size=24>Size 24.</style> <style size=16>Size 16</style>. <style size=12>Size 12.</style> <style size=24>Size 24.</style> <style size=16>Size 16.</style> <style size=12>Size 12.</style>
<style size=2em>Size 2em.</style> <style size=1em>Size 1em.</style> <style size=0.5em>Size 0.5em.</style>
<style size=3em>Size 3em. <style size=0.5em>Half of 3em.</style></style>
<style font=normal>Normal font.</style> <style font=mono>Mono font.</style> <style font=normal>Normal font.</style> <style font=mono>Mono font.</style>
<bigger>Tag test</bigger> <bigger>Tag test</bigger>
@ -112,6 +114,10 @@ Normal:
<img name=testformspec_item.png float=left> <img name=testformspec_item.png float=left>
<mono>float=right</mono>: <mono>float=right</mono>:
<img name=testformspec_item.png float=right> <img name=testformspec_item.png float=right>
<mono>width=1em height=2em</mono>:
<img name=testformspec_item.png width=1em height=2em>
<mono>width=2em</mono> inside <mono>width=2em</mono> (should render at <mono>width=4em</mono>):
<style size=2em><img name=testformspec_item.png width=2em></style>
<bigger><mono>item</mono> test</bigger> <bigger><mono>item</mono> test</bigger>
Normal: Normal:

View File

@ -49,6 +49,49 @@ static bool check_integer(const std::string &str)
return *endptr == '\0'; return *endptr == '\0';
} }
static bool check_length(const std::string &str)
{
return ParsedText::LengthValue(str).isValid();
}
// -----------------------------------------------------------------------------
// LengthValue - A data structure representing a (possibly relative) length
ParsedText::LengthValue::LengthValue(const std::string &str)
{
char *unitptr = nullptr;
this->size = std::strtod(str.c_str(), &unitptr);
if (this->size <= 0)
this->size = 0;
this->unit = unitptr;
}
bool ParsedText::LengthValue::isValid()
{
return this->getAbsoluteValue(1) > 0;
}
double ParsedText::LengthValue::getAbsoluteValue(const double &em_size)
{
if (this->unit.empty())
return this->size;
else if (this->unit == "em")
return this->size * em_size;
else
return 0;
}
double ParsedText::LengthValue::getAbsoluteValue()
{
return getAbsoluteValue(0);
}
bool ParsedText::LengthValue::isAbsolute()
{
return getAbsoluteValue() > 0;
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// ParsedText - A text parser // ParsedText - A text parser
@ -63,7 +106,7 @@ void ParsedText::Element::setStyle(StyleList &style)
if (parseColorString(style["hovercolor"], color, false)) if (parseColorString(style["hovercolor"], color, false))
this->hovercolor = color; this->hovercolor = color;
unsigned int font_size = std::atoi(style["fontsize"].c_str()); this->font_size = std::atoi(style["fontsize"].c_str());
FontMode font_mode = FM_Standard; FontMode font_mode = FM_Standard;
if (style["fontstyle"] == "mono") if (style["fontstyle"] == "mono")
@ -72,9 +115,9 @@ void ParsedText::Element::setStyle(StyleList &style)
// hypertext[] only accepts absolute font size values and has a hardcoded // hypertext[] only accepts absolute font size values and has a hardcoded
// default font size of 16. This is the only way to make hypertext[] // default font size of 16. This is the only way to make hypertext[]
// respect font size settings that I can think of. // respect font size settings that I can think of.
font_size = myround(font_size / 16.0f * g_fontengine->getFontSize(font_mode)); this->font_size = myround(this->font_size / 16.0f * g_fontengine->getFontSize(font_mode));
FontSpec spec(font_size, font_mode, FontSpec spec(this->font_size, font_mode,
is_yes(style["bold"]), is_yes(style["italic"])); is_yes(style["bold"]), is_yes(style["italic"]));
// TODO: find a way to check font validity // TODO: find a way to check font validity
@ -83,7 +126,7 @@ void ParsedText::Element::setStyle(StyleList &style)
if (!this->font) if (!this->font)
printf("No font found ! Size=%d, mode=%d, bold=%s, italic=%s\n", printf("No font found ! Size=%d, mode=%d, bold=%s, italic=%s\n",
font_size, font_mode, style["bold"].c_str(), this->font_size, font_mode, style["bold"].c_str(),
style["italic"].c_str()); style["italic"].c_str());
} }
@ -341,9 +384,8 @@ void ParsedText::parseGenericStyleAttr(
style[name] = is_yes(value); style[name] = is_yes(value);
} else if (name == "size") { } else if (name == "size") {
if (check_integer(value)) if (check_length(value))
style["fontsize"] = value; style["fontsize"] = value;
} else if (name == "font") { } else if (name == "font") {
if (value == "mono" || value == "normal") if (value == "mono" || value == "normal")
style["fontstyle"] = value; style["fontstyle"] = value;
@ -512,13 +554,13 @@ u32 ParsedText::parseTag(const wchar_t *text, u32 cursor)
} }
if (attrs.count("width")) { if (attrs.count("width")) {
int width = stoi(attrs["width"]); int width = LengthValue(attrs["width"]).getAbsoluteValue(m_element->font_size);
if (width > 0) if (width > 0)
m_element->dim.Width = width; m_element->dim.Width = width;
} }
if (attrs.count("height")) { if (attrs.count("height")) {
int height = stoi(attrs["height"]); int height = LengthValue(attrs["height"]).getAbsoluteValue(m_element->font_size);
if (height > 0) if (height > 0)
m_element->dim.Height = height; m_element->dim.Height = height;
} }
@ -595,9 +637,18 @@ u32 ParsedText::parseTag(const wchar_t *text, u32 cursor)
// Update styles accordingly // Update styles accordingly
m_style.clear(); m_style.clear();
for (auto tag = m_active_tags.crbegin(); tag != m_active_tags.crend(); ++tag) unsigned int font_size = 0;
for (const auto &prop : (*tag)->style) for (auto tag = m_active_tags.crbegin(); tag != m_active_tags.crend(); ++tag) {
m_style[prop.first] = prop.second; for (const auto &prop : (*tag)->style) {
if (prop.first == "fontsize") {
// resolve font size
font_size = LengthValue(prop.second).getAbsoluteValue(font_size);
} else {
m_style[prop.first] = prop.second;
}
}
}
m_style["fontsize"] = std::to_string(font_size);
return cursor; return cursor;
} }

View File

@ -76,6 +76,17 @@ public:
typedef std::unordered_map<std::string, std::string> StyleList; typedef std::unordered_map<std::string, std::string> StyleList;
typedef std::unordered_map<std::string, std::string> AttrsList; typedef std::unordered_map<std::string, std::string> AttrsList;
struct LengthValue
{
double size;
std::string unit;
LengthValue(const std::string &str);
bool isValid();
bool isAbsolute();
double getAbsoluteValue();
double getAbsoluteValue(const double &em_size);
};
struct Tag struct Tag
{ {
std::string name; std::string name;
@ -98,6 +109,7 @@ public:
ValignType valign; ValignType valign;
gui::IGUIFont *font; gui::IGUIFont *font;
unsigned int font_size;
irr::video::SColor color; irr::video::SColor color;
irr::video::SColor hovercolor; irr::video::SColor hovercolor;

View File

@ -244,7 +244,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
// base64-encoded SHA-1 (27+\0). // base64-encoded SHA-1 (27+\0).
// See also formspec [Version History] in doc/lua_api.md // See also formspec [Version History] in doc/lua_api.md
#define FORMSPEC_API_VERSION 7 #define FORMSPEC_API_VERSION 8
#define TEXTURENAME_ALLOWED_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_.-" #define TEXTURENAME_ALLOWED_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_.-"