Skip to content

Commit ec3795a

Browse files
committedAug 3, 2019
Add style[] tag with button support
1 parent d1a1c5c commit ec3795a

File tree

7 files changed

+240
-3
lines changed

7 files changed

+240
-3
lines changed
 

‎builtin/mainmenu/dlg_delete_content.lua

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ local function delete_content_formspec(dialogdata)
2222
"size[11.5,4.5,true]" ..
2323
"label[2,2;" ..
2424
fgettext("Are you sure you want to delete \"$1\"?", dialogdata.content.name) .. "]"..
25+
"style[dlg_delete_content_confirm;bgcolor;red]" ..
2526
"button[3.25,3.5;2.5,0.5;dlg_delete_content_confirm;" .. fgettext("Delete") .. "]" ..
2627
"button[5.75,3.5;2.5,0.5;dlg_delete_content_cancel;" .. fgettext("Cancel") .. "]"
2728

‎builtin/mainmenu/dlg_delete_world.lua

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ local function delete_world_formspec(dialogdata)
2121
"size[10,2.5,true]" ..
2222
"label[0.5,0.5;" ..
2323
fgettext("Delete World \"$1\"?", dialogdata.delete_name) .. "]" ..
24+
"style[world_delete_confirm;bgcolor;red]" ..
2425
"button[0.5,1.5;2.5,0.5;world_delete_confirm;" .. fgettext("Delete") .. "]" ..
2526
"button[7.0,1.5;2.5,0.5;world_delete_cancel;" .. fgettext("Cancel") .. "]"
2627
return retval

‎builtin/mainmenu/tab_local.lua

+3
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,9 @@ local function get_formspec(tabview, name, tabdata)
102102
)
103103

104104
retval = retval ..
105+
"style_type[button;bgcolor;#006699]" ..
106+
"style[world_delete;bgcolor;red]" ..
107+
"style[world_delete;textcolor;yellow]" ..
105108
"button[4,3.95;2.6,1;world_delete;".. fgettext("Delete") .. "]" ..
106109
"button[6.5,3.95;2.8,1;world_configure;".. fgettext("Configure") .. "]" ..
107110
"button[9.2,3.95;2.5,1;world_create;".. fgettext("New") .. "]" ..

‎doc/lua_api.txt

+38-1
Original file line numberDiff line numberDiff line change
@@ -1886,7 +1886,8 @@ For coloured text you can use `minetest.colorize`.
18861886

18871887
WARNING: Minetest allows you to add elements to every single formspec instance
18881888
using `player:set_formspec_prepend()`, which may be the reason backgrounds are
1889-
appearing when you don't expect them to. See [`no_prepend[]`].
1889+
appearing when you don't expect them to, or why things are styled differently
1890+
to normal. See [`no_prepend[]`] and [Styling Formspecs].
18901891

18911892
Examples
18921893
--------
@@ -2353,6 +2354,20 @@ Elements
23532354
**Note**: do _not_ use a element name starting with `key_`; those names are
23542355
reserved to pass key press events to formspec!
23552356

2357+
### `style[<name>;<propery>;<value]`
2358+
2359+
Set the style for the named element `name`.
2360+
Note: this **must** be before the element's tag.
2361+
2362+
See [Styling Formspecs].
2363+
2364+
2365+
### `style_type[<type>;<propery>;<value>]`
2366+
2367+
Sets the style for all elements of type `type` which appear after this tag.
2368+
2369+
See [Styling Formspecs].
2370+
23562371
Migrating to Real Coordinates
23572372
-----------------------------
23582373

@@ -2388,6 +2403,28 @@ offsets when migrating:
23882403
| list | | | Spacing is now 0.25 for both directions, meaning lists will be taller in height
23892404
| label | 0, +0.3 | | The first line of text is now positioned centered exactly at the position specified
23902405

2406+
Styling Formspecs
2407+
-----------------
2408+
2409+
Formspec elements can be themed using the style tags:
2410+
2411+
style[ELEMENT_NAME;PROPERTY;VALUE]
2412+
style_type[ELEMENT_TYPE;PROPERTY;VALUE]
2413+
2414+
For example:
2415+
2416+
style_type[button;bgcolor;#006699]
2417+
style[world_delete;bgcolor;#ff0000]
2418+
button[4,3.95;2.6,1;world_delete;Delete]
2419+
2420+
### Valid Properties
2421+
2422+
* button and button_exit
2423+
* bgcolor - sets button tint
2424+
* textcolor
2425+
* tabheader
2426+
* bgcolor - tab background
2427+
* textcolor
23912428

23922429

23932430

‎src/gui/StyleSpec.h

+102
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/*
2+
Minetest
3+
Copyright (C) 2019 rubenwardy
4+
5+
This program is free software; you can redistribute it and/or modify
6+
it under the terms of the GNU Lesser General Public License as published by
7+
the Free Software Foundation; either version 2.1 of the License, or
8+
(at your option) any later version.
9+
10+
This program is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
GNU Lesser General Public License for more details.
14+
15+
You should have received a copy of the GNU Lesser General Public License along
16+
with this program; if not, write to the Free Software Foundation, Inc.,
17+
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*/
19+
20+
#include "irrlichttypes_extrabloated.h"
21+
22+
#pragma once
23+
24+
25+
class StyleSpec
26+
{
27+
public:
28+
enum Property {
29+
NONE = 0,
30+
TEXTCOLOR,
31+
BGCOLOR,
32+
NUM_PROPERTIES
33+
};
34+
35+
private:
36+
std::unordered_map<Property, std::string> properties;
37+
38+
public:
39+
static Property GetPropertyByName(const std::string &name) {
40+
if (name == "textcolor") {
41+
return TEXTCOLOR;
42+
} else if (name == "bgcolor") {
43+
return BGCOLOR;
44+
} else {
45+
return NONE;
46+
}
47+
}
48+
49+
std::string get(Property prop, std::string def) const {
50+
auto it = properties.find(prop);
51+
if (it == properties.end()) {
52+
return def;
53+
}
54+
55+
return it->second;
56+
}
57+
58+
void set(Property prop, std::string value) {
59+
properties[prop] = std::move(value);
60+
}
61+
62+
video::SColor getColor(Property prop, video::SColor def) const {
63+
auto it = properties.find(prop);
64+
if (it == properties.end()) {
65+
return def;
66+
}
67+
68+
parseColorString(it->second, def, false, 0xFF);
69+
return def;
70+
}
71+
72+
video::SColor getColor(Property prop) const {
73+
auto it = properties.find(prop);
74+
FATAL_ERROR_IF(it == properties.end(), "Unexpected missing property");
75+
76+
video::SColor color;
77+
parseColorString(it->second, color, false, 0xFF);
78+
return color;
79+
}
80+
81+
bool hasProperty(Property prop) const {
82+
return properties.find(prop) != properties.end();
83+
}
84+
85+
StyleSpec &operator|=(const StyleSpec &other) {
86+
for (size_t i = 1; i < NUM_PROPERTIES; i++) {
87+
auto prop = (Property)i;
88+
if (other.hasProperty(prop)) {
89+
properties[prop] = other.get(prop, "");
90+
}
91+
}
92+
93+
return *this;
94+
}
95+
96+
StyleSpec operator|(const StyleSpec &other) const {
97+
StyleSpec newspec = *this;
98+
newspec |= other;
99+
return newspec;
100+
}
101+
};
102+

‎src/gui/guiFormSpecMenu.cpp

+88-2
Original file line numberDiff line numberDiff line change
@@ -701,6 +701,17 @@ void GUIFormSpecMenu::parseButton(parserData* data, const std::string &element,
701701
spec.is_exit = true;
702702

703703
GUIButton *e = GUIButton::addButton(Environment, rect, this, spec.fid, spec.flabel.c_str());
704+
705+
auto style = getThemeForElement(type, name);
706+
if (style.hasProperty(StyleSpec::BGCOLOR)) {
707+
e->setColor(style.getColor(StyleSpec::BGCOLOR));
708+
}
709+
if (style.hasProperty(StyleSpec::TEXTCOLOR)) {
710+
e->setOverrideColor(style.getColor(StyleSpec::TEXTCOLOR));
711+
}
712+
713+
// e->setSprite();
714+
704715
if (spec.fname == data->focused_fieldname) {
705716
Environment->setFocus(e);
706717
}
@@ -1645,7 +1656,7 @@ void GUIFormSpecMenu::parseTabHeader(parserData* data, const std::string &elemen
16451656
pos.Y+geom.Y);
16461657

16471658
gui::IGUITabControl *e = Environment->addTabControl(rect, this,
1648-
show_background, show_border, spec.fid);
1659+
false, show_border, spec.fid);
16491660
e->setAlignment(irr::gui::EGUIA_UPPERLEFT, irr::gui::EGUIA_UPPERLEFT,
16501661
irr::gui::EGUIA_UPPERLEFT, irr::gui::EGUIA_LOWERRIGHT);
16511662
e->setTabHeight(geom.Y);
@@ -1656,9 +1667,17 @@ void GUIFormSpecMenu::parseTabHeader(parserData* data, const std::string &elemen
16561667

16571668
e->setNotClipped(true);
16581669

1670+
auto style = getThemeForElement("tabheader", name);
1671+
16591672
for (const std::string &button : buttons) {
1660-
e->addTab(unescape_translate(unescape_string(
1673+
auto tab = e->addTab(unescape_translate(unescape_string(
16611674
utf8_to_wide(button))).c_str(), -1);
1675+
tab->setDrawBackground(false);
1676+
tab->setBackgroundColor(video::SColor(0xFFFF0000));
1677+
if (style.hasProperty(StyleSpec::BGCOLOR))
1678+
tab->setBackgroundColor(style.getColor(StyleSpec::BGCOLOR));
1679+
1680+
tab->setTextColor(style.getColor(StyleSpec::TEXTCOLOR, video::SColor(0xFFFFFFFF)));
16621681
}
16631682

16641683
if ((tab_index >= 0) &&
@@ -2020,6 +2039,45 @@ void GUIFormSpecMenu::parseAnchor(parserData *data, const std::string &element)
20202039
<< "'" << std::endl;
20212040
}
20222041

2042+
bool GUIFormSpecMenu::parseStyle(parserData *data, const std::string &element, bool style_type)
2043+
{
2044+
std::vector<std::string> parts = split(element, ';');
2045+
2046+
if (parts.size() != 3) {
2047+
errorstream << "Invalid style element (" << parts.size() << "): '" << element
2048+
<< "'" << std::endl;
2049+
return false;
2050+
}
2051+
2052+
std::string selector = trim(parts[0]);
2053+
std::string propname = trim(parts[1]);
2054+
std::string value = trim(parts[2]);
2055+
2056+
StyleSpec::Property prop = StyleSpec::GetPropertyByName(propname);
2057+
if (prop == StyleSpec::NONE) {
2058+
errorstream << "Invalid style element (Unknown property " << prop << "): '" << element
2059+
<< "'" << std::endl;
2060+
return false;
2061+
}
2062+
2063+
StyleSpec spec;
2064+
spec.set(prop, value);
2065+
2066+
if (selector.empty()) {
2067+
errorstream << "Invalid style element (Selector required): '" << element
2068+
<< "'" << std::endl;
2069+
return false;
2070+
}
2071+
2072+
if (style_type) {
2073+
theme_by_type[selector] |= spec;
2074+
} else {
2075+
theme_by_name[selector] |= spec;
2076+
}
2077+
2078+
return true;
2079+
}
2080+
20232081
void GUIFormSpecMenu::parseElement(parserData* data, const std::string &element)
20242082
{
20252083
//some prechecks
@@ -2185,6 +2243,16 @@ void GUIFormSpecMenu::parseElement(parserData* data, const std::string &element)
21852243
return;
21862244
}
21872245

2246+
if (type == "style") {
2247+
parseStyle(data, description, false);
2248+
return;
2249+
}
2250+
2251+
if (type == "style_type") {
2252+
parseStyle(data, description, true);
2253+
return;
2254+
}
2255+
21882256
// Ignore others
21892257
infostream << "Unknown DrawSpec: type=" << type << ", data=\"" << description << "\""
21902258
<< std::endl;
@@ -2255,6 +2323,8 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
22552323
m_inventory_rings.clear();
22562324
m_static_texts.clear();
22572325
m_dropdowns.clear();
2326+
theme_by_name.clear();
2327+
theme_by_type.clear();
22582328

22592329
m_bgfullscreen = false;
22602330

@@ -4044,3 +4114,19 @@ std::wstring GUIFormSpecMenu::getLabelByID(s32 id)
40444114
}
40454115
return L"";
40464116
}
4117+
4118+
StyleSpec GUIFormSpecMenu::getThemeForElement(const std::string &type, const std::string &name) {
4119+
StyleSpec ret;
4120+
4121+
auto it = theme_by_type.find(type);
4122+
if (it != theme_by_type.end()) {
4123+
ret |= it->second;
4124+
}
4125+
4126+
it = theme_by_name.find(name);
4127+
if (it != theme_by_name.end()) {
4128+
ret |= it->second;
4129+
}
4130+
4131+
return ret;
4132+
}

‎src/gui/guiFormSpecMenu.h

+7
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
3030
#include "client/joystick_controller.h"
3131
#include "util/string.h"
3232
#include "util/enriched_string.h"
33+
#include "StyleSpec.h"
3334

3435
class InventoryManager;
3536
class ISimpleTextureSource;
@@ -401,6 +402,11 @@ class GUIFormSpecMenu : public GUIModalMenu
401402
const std::vector<std::string> &v_pos);
402403
v2s32 getRealCoordinateGeometry(const std::vector<std::string> &v_geom);
403404

405+
std::unordered_map<std::string, StyleSpec> theme_by_type;
406+
std::unordered_map<std::string, StyleSpec> theme_by_name;
407+
408+
StyleSpec getThemeForElement(const std::string &type, const std::string &name);
409+
404410
v2s32 padding;
405411
v2f32 spacing;
406412
v2s32 imgsize;
@@ -537,6 +543,7 @@ class GUIFormSpecMenu : public GUIModalMenu
537543
void parsePosition(parserData *data, const std::string &element);
538544
bool parseAnchorDirect(parserData *data, const std::string &element);
539545
void parseAnchor(parserData *data, const std::string &element);
546+
bool parseStyle(parserData *data, const std::string &element, bool style_type);
540547

541548
void tryClose();
542549

0 commit comments

Comments
 (0)
Please sign in to comment.