From 9be8e26434752026cf8dda56953458ededb1804a Mon Sep 17 00:00:00 2001
From: y5nw <37980625+y5nw@users.noreply.github.com>
Date: Sat, 10 Feb 2024 22:10:18 +0100
Subject: [PATCH 1/7] Hypertext: accept em as a length unit
---
games/devtest/mods/testformspec/formspec.lua | 5 +-
src/gui/guiHyperText.cpp | 48 ++++++++++++++++++--
src/gui/guiHyperText.h | 1 +
3 files changed, 49 insertions(+), 5 deletions(-)
diff --git a/games/devtest/mods/testformspec/formspec.lua b/games/devtest/mods/testformspec/formspec.lua
index 48c8763de..4bdf933d8 100644
--- a/games/devtest/mods/testformspec/formspec.lua
+++ b/games/devtest/mods/testformspec/formspec.lua
@@ -67,7 +67,8 @@ This is a normal text.
style test
- .
+
+
Tag test
@@ -108,6 +109,8 @@ Normal:
float=right:
+width=1em height=2em:
+
item test
Normal:
diff --git a/src/gui/guiHyperText.cpp b/src/gui/guiHyperText.cpp
index 8aba3083c..554982b49 100644
--- a/src/gui/guiHyperText.cpp
+++ b/src/gui/guiHyperText.cpp
@@ -48,6 +48,46 @@ static bool check_integer(const std::string &str)
return *endptr == '\0';
}
+struct size_with_unit {
+ double size;
+ std::string unit;
+};
+
+static size_with_unit parse_length(const std::string &str)
+{
+ char *unitptr = nullptr;
+ double size = strtod(str.c_str(), &unitptr);
+ size_with_unit length;
+
+ if (size <= 0)
+ size = 0;
+ length.size = size;
+ length.unit = unitptr;
+
+ return length;
+}
+
+static bool check_length(const std::string &str)
+{
+ return parse_length(str).size > 0;
+}
+
+static u32 get_length_value(const std::string &str, ParsedText::Element &parent)
+{
+ size_with_unit length = parse_length(str);
+ if (!length.unit.empty())
+ {
+ printf("%g %s\n", length.size, length.unit.c_str());
+ printf("%d\n", parent.font_size);
+ }
+ if (length.unit.empty())
+ return length.size;
+ else if (length.unit == "em")
+ return length.size * parent.font_size;
+ else
+ return 0;
+}
+
// -----------------------------------------------------------------------------
// ParsedText - A text parser
@@ -62,7 +102,7 @@ void ParsedText::Element::setStyle(StyleList &style)
if (parseColorString(style["hovercolor"], color, false))
this->hovercolor = color;
- unsigned int font_size = std::atoi(style["fontsize"].c_str());
+ font_size = get_length_value(style["fontsize"], *this);
FontMode font_mode = FM_Standard;
if (style["fontstyle"] == "mono")
@@ -340,7 +380,7 @@ void ParsedText::parseGenericStyleAttr(
style[name] = is_yes(value);
} else if (name == "size") {
- if (check_integer(value))
+ if (check_length(value))
style["fontsize"] = value;
} else if (name == "font") {
@@ -511,13 +551,13 @@ u32 ParsedText::parseTag(const wchar_t *text, u32 cursor)
}
if (attrs.count("width")) {
- int width = stoi(attrs["width"]);
+ int width = get_length_value(attrs["width"], *m_element);
if (width > 0)
m_element->dim.Width = width;
}
if (attrs.count("height")) {
- int height = stoi(attrs["height"]);
+ int height = get_length_value(attrs["height"], *m_element);
if (height > 0)
m_element->dim.Height = height;
}
diff --git a/src/gui/guiHyperText.h b/src/gui/guiHyperText.h
index 0616a37ce..4687d08a1 100644
--- a/src/gui/guiHyperText.h
+++ b/src/gui/guiHyperText.h
@@ -98,6 +98,7 @@ public:
ValignType valign;
gui::IGUIFont *font;
+ unsigned int font_size;
irr::video::SColor color;
irr::video::SColor hovercolor;
From 01b2a33156c010a5b0c6fba3f5d51f95996d1bd5 Mon Sep 17 00:00:00 2001
From: y5nw <37980625+y5nw@users.noreply.github.com>
Date: Mon, 12 Feb 2024 23:28:36 +0100
Subject: [PATCH 2/7] Scale text correctly
---
games/devtest/mods/testformspec/formspec.lua | 5 +-
src/gui/guiHyperText.cpp | 73 ++++++++++++--------
src/gui/guiHyperText.h | 10 +++
3 files changed, 58 insertions(+), 30 deletions(-)
diff --git a/games/devtest/mods/testformspec/formspec.lua b/games/devtest/mods/testformspec/formspec.lua
index 4bdf933d8..3e90b52ca 100644
--- a/games/devtest/mods/testformspec/formspec.lua
+++ b/games/devtest/mods/testformspec/formspec.lua
@@ -68,7 +68,8 @@ This is a normal text.
style test
-
+
+
Tag test
@@ -111,6 +112,8 @@ Normal:
width=1em height=2em:
+width=2em inside width=2em
+
item test
Normal:
diff --git a/src/gui/guiHyperText.cpp b/src/gui/guiHyperText.cpp
index 554982b49..1671a5e5b 100644
--- a/src/gui/guiHyperText.cpp
+++ b/src/gui/guiHyperText.cpp
@@ -48,16 +48,11 @@ static bool check_integer(const std::string &str)
return *endptr == '\0';
}
-struct size_with_unit {
- double size;
- std::string unit;
-};
-
-static size_with_unit parse_length(const std::string &str)
+static ParsedText::LengthValue parse_length(const std::string &str)
{
char *unitptr = nullptr;
double size = strtod(str.c_str(), &unitptr);
- size_with_unit length;
+ ParsedText::LengthValue length;
if (size <= 0)
size = 0;
@@ -69,25 +64,37 @@ static size_with_unit parse_length(const std::string &str)
static bool check_length(const std::string &str)
{
- return parse_length(str).size > 0;
+ return parse_length(str).isValid();
}
-static u32 get_length_value(const std::string &str, ParsedText::Element &parent)
+// -----------------------------------------------------------------------------
+// LengthValue - A data structure representing a (possibly relative) length
+
+bool ParsedText::LengthValue::isValid()
{
- size_with_unit length = parse_length(str);
- if (!length.unit.empty())
- {
- printf("%g %s\n", length.size, length.unit.c_str());
- printf("%d\n", parent.font_size);
- }
- if (length.unit.empty())
- return length.size;
- else if (length.unit == "em")
- return length.size * parent.font_size;
+ 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
@@ -102,7 +109,7 @@ void ParsedText::Element::setStyle(StyleList &style)
if (parseColorString(style["hovercolor"], color, false))
this->hovercolor = color;
- font_size = get_length_value(style["fontsize"], *this);
+ this->font_size = atoi(style["fontsize"].c_str());
FontMode font_mode = FM_Standard;
if (style["fontstyle"] == "mono")
@@ -111,9 +118,9 @@ void ParsedText::Element::setStyle(StyleList &style)
// hypertext[] only accepts absolute font size values and has a hardcoded
// default font size of 16. This is the only way to make hypertext[]
// 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"]));
// TODO: find a way to check font validity
@@ -122,7 +129,7 @@ void ParsedText::Element::setStyle(StyleList &style)
if (!this->font)
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());
}
@@ -382,7 +389,6 @@ void ParsedText::parseGenericStyleAttr(
} else if (name == "size") {
if (check_length(value))
style["fontsize"] = value;
-
} else if (name == "font") {
if (value == "mono" || value == "normal")
style["fontstyle"] = value;
@@ -551,13 +557,13 @@ u32 ParsedText::parseTag(const wchar_t *text, u32 cursor)
}
if (attrs.count("width")) {
- int width = get_length_value(attrs["width"], *m_element);
+ int width = parse_length(attrs["width"]).getAbsoluteValue(m_element->font_size);
if (width > 0)
m_element->dim.Width = width;
}
if (attrs.count("height")) {
- int height = get_length_value(attrs["height"], *m_element);
+ int height = parse_length(attrs["height"]).getAbsoluteValue(m_element->font_size);
if (height > 0)
m_element->dim.Height = height;
}
@@ -634,9 +640,18 @@ u32 ParsedText::parseTag(const wchar_t *text, u32 cursor)
// Update styles accordingly
m_style.clear();
- for (auto tag = m_active_tags.crbegin(); tag != m_active_tags.crend(); ++tag)
- for (const auto &prop : (*tag)->style)
- m_style[prop.first] = prop.second;
+ unsigned int font_size = 0;
+ for (auto tag = m_active_tags.crbegin(); tag != m_active_tags.crend(); ++tag) {
+ for (const auto &prop : (*tag)->style) {
+ if (prop.first == "fontsize") {
+ // resolve font size
+ font_size = parse_length(prop.second).getAbsoluteValue(font_size);
+ } else {
+ m_style[prop.first] = prop.second;
+ }
+ }
+ }
+ m_style["fontsize"] = std::to_string(font_size);
return cursor;
}
diff --git a/src/gui/guiHyperText.h b/src/gui/guiHyperText.h
index 4687d08a1..f11a3611b 100644
--- a/src/gui/guiHyperText.h
+++ b/src/gui/guiHyperText.h
@@ -76,6 +76,16 @@ public:
typedef std::unordered_map StyleList;
typedef std::unordered_map AttrsList;
+ struct LengthValue
+ {
+ double size;
+ std::string unit;
+ bool isValid();
+ bool isAbsolute();
+ double getAbsoluteValue();
+ double getAbsoluteValue(const double &em_size);
+ };
+
struct Tag
{
std::string name;
From 8ce75da24a8ca2b4ff7dbdbfa0de17ff1dd4c516 Mon Sep 17 00:00:00 2001
From: y5nw <37980625+y5nw@users.noreply.github.com>
Date: Mon, 12 Feb 2024 23:59:19 +0100
Subject: [PATCH 3/7] Fix erroneous testcase
---
games/devtest/mods/testformspec/formspec.lua | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/games/devtest/mods/testformspec/formspec.lua b/games/devtest/mods/testformspec/formspec.lua
index 3e90b52ca..b0b29efd1 100644
--- a/games/devtest/mods/testformspec/formspec.lua
+++ b/games/devtest/mods/testformspec/formspec.lua
@@ -112,8 +112,8 @@ Normal:
width=1em height=2em:
-width=2em inside width=2em
-
+width=2em inside width=2em (should render at width=4em):
+
item test
Normal:
From 14cad3dfb5277a3410431a67d84e7ced3d376745 Mon Sep 17 00:00:00 2001
From: y5nw <37980625+y5nw@users.noreply.github.com>
Date: Tue, 13 Feb 2024 00:07:25 +0100
Subject: [PATCH 4/7] Use C++ constructor for ParsedText::LengthValue
---
src/gui/guiHyperText.cpp | 32 ++++++++++++++------------------
src/gui/guiHyperText.h | 1 +
2 files changed, 15 insertions(+), 18 deletions(-)
diff --git a/src/gui/guiHyperText.cpp b/src/gui/guiHyperText.cpp
index 1671a5e5b..329b0a2c0 100644
--- a/src/gui/guiHyperText.cpp
+++ b/src/gui/guiHyperText.cpp
@@ -48,28 +48,24 @@ static bool check_integer(const std::string &str)
return *endptr == '\0';
}
-static ParsedText::LengthValue parse_length(const std::string &str)
-{
- char *unitptr = nullptr;
- double size = strtod(str.c_str(), &unitptr);
- ParsedText::LengthValue length;
-
- if (size <= 0)
- size = 0;
- length.size = size;
- length.unit = unitptr;
-
- return length;
-}
-
static bool check_length(const std::string &str)
{
- return parse_length(str).isValid();
+ 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 = strtod(str.c_str(), &unitptr);
+
+ if (this->size <= 0)
+ this->size = 0;
+ this->unit = unitptr;
+}
+
bool ParsedText::LengthValue::isValid()
{
return this->getAbsoluteValue(1) > 0;
@@ -557,13 +553,13 @@ u32 ParsedText::parseTag(const wchar_t *text, u32 cursor)
}
if (attrs.count("width")) {
- int width = parse_length(attrs["width"]).getAbsoluteValue(m_element->font_size);
+ int width = LengthValue(attrs["width"]).getAbsoluteValue(m_element->font_size);
if (width > 0)
m_element->dim.Width = width;
}
if (attrs.count("height")) {
- int height = parse_length(attrs["height"]).getAbsoluteValue(m_element->font_size);
+ int height = LengthValue(attrs["height"]).getAbsoluteValue(m_element->font_size);
if (height > 0)
m_element->dim.Height = height;
}
@@ -645,7 +641,7 @@ u32 ParsedText::parseTag(const wchar_t *text, u32 cursor)
for (const auto &prop : (*tag)->style) {
if (prop.first == "fontsize") {
// resolve font size
- font_size = parse_length(prop.second).getAbsoluteValue(font_size);
+ font_size = LengthValue(prop.second).getAbsoluteValue(font_size);
} else {
m_style[prop.first] = prop.second;
}
diff --git a/src/gui/guiHyperText.h b/src/gui/guiHyperText.h
index f11a3611b..bc0344b54 100644
--- a/src/gui/guiHyperText.h
+++ b/src/gui/guiHyperText.h
@@ -80,6 +80,7 @@ public:
{
double size;
std::string unit;
+ LengthValue(const std::string &str);
bool isValid();
bool isAbsolute();
double getAbsoluteValue();
From 6e57555d9ee3d241c86e17ac1b9eebd2d4d40f85 Mon Sep 17 00:00:00 2001
From: y5nw <37980625+y5nw@users.noreply.github.com>
Date: Tue, 13 Feb 2024 12:25:56 +0100
Subject: [PATCH 5/7] Document use of the `em` unit
---
doc/lua_api.md | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/doc/lua_api.md b/doc/lua_api.md
index 6f5bb8683..53ef2df59 100644
--- a/doc/lua_api.md
+++ b/doc/lua_api.md
@@ -3496,6 +3496,10 @@ Some tags can enclose text, they open with `` and close with `
Date: Tue, 13 Feb 2024 16:00:40 +0100
Subject: [PATCH 6/7] Bump formspec version
---
doc/lua_api.md | 2 ++
src/network/networkprotocol.h | 2 +-
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/doc/lua_api.md b/doc/lua_api.md
index 53ef2df59..ca7ef0e7d 100644
--- a/doc/lua_api.md
+++ b/doc/lua_api.md
@@ -2657,6 +2657,8 @@ Version History
* Formspec version 7 (5.8.0):
* style[]: Add focused state for buttons
* Add field_enter_after_edit[] (experimental)
+* Formspec version 8 (5.9.0):
+ * hypertext[]: Allow `em` as a length unit
Elements
--------
diff --git a/src/network/networkprotocol.h b/src/network/networkprotocol.h
index 6de00803e..aa5740d96 100644
--- a/src/network/networkprotocol.h
+++ b/src/network/networkprotocol.h
@@ -246,7 +246,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
// base64-encoded SHA-1 (27+\0).
// 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_.-"
From 177b52acb0316757da411c7315710275984f495a Mon Sep 17 00:00:00 2001
From: y5nw <37980625+y5nw@users.noreply.github.com>
Date: Wed, 14 Feb 2024 21:35:32 +0100
Subject: [PATCH 7/7] add std:: prepend where appropriate
---
src/gui/guiHyperText.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/gui/guiHyperText.cpp b/src/gui/guiHyperText.cpp
index 329b0a2c0..2250747db 100644
--- a/src/gui/guiHyperText.cpp
+++ b/src/gui/guiHyperText.cpp
@@ -59,7 +59,7 @@ static bool check_length(const std::string &str)
ParsedText::LengthValue::LengthValue(const std::string &str)
{
char *unitptr = nullptr;
- this->size = strtod(str.c_str(), &unitptr);
+ this->size = std::strtod(str.c_str(), &unitptr);
if (this->size <= 0)
this->size = 0;
@@ -105,7 +105,7 @@ void ParsedText::Element::setStyle(StyleList &style)
if (parseColorString(style["hovercolor"], color, false))
this->hovercolor = color;
- this->font_size = atoi(style["fontsize"].c_str());
+ this->font_size = std::atoi(style["fontsize"].c_str());
FontMode font_mode = FM_Standard;
if (style["fontstyle"] == "mono")