mirror of
https://github.com/luanti-org/luanti.git
synced 2025-06-27 16:36:03 +00:00
Merge bd0d9a7f95
into 2d36d32da8
This commit is contained in:
commit
23aba644cd
14 changed files with 286 additions and 48 deletions
|
@ -3653,6 +3653,8 @@ Some types may inherit styles from parent types.
|
||||||
* `+<number>`/`-<number>`: Offsets default font size by `number` points.
|
* `+<number>`/`-<number>`: Offsets default font size by `number` points.
|
||||||
* `*<number>`: Multiplies default font size by `number`, similar to CSS `em`.
|
* `*<number>`: Multiplies default font size by `number`, similar to CSS `em`.
|
||||||
* border - boolean, draw border. Set to false to hide the bevelled button pane. Default true.
|
* border - boolean, draw border. Set to false to hide the bevelled button pane. Default true.
|
||||||
|
* border_img - string, a texture that overrides the border style.
|
||||||
|
* border_img_middle - rect, to render `border_img` in 9-sliced mode. Refer to `background9[...]`.
|
||||||
* content_offset - 2d vector, shifts the position of the button's content without resizing it.
|
* content_offset - 2d vector, shifts the position of the button's content without resizing it.
|
||||||
* noclip - boolean, set to true to allow the element to exceed formspec bounds.
|
* noclip - boolean, set to true to allow the element to exceed formspec bounds.
|
||||||
* padding - rect, adds space between the edges of the button and the content. This value is
|
* padding - rect, adds space between the edges of the button and the content. This value is
|
||||||
|
|
|
@ -38,6 +38,10 @@ A key-value config file with the following keys:
|
||||||
* `textdomain`: Textdomain used to translate title and description.
|
* `textdomain`: Textdomain used to translate title and description.
|
||||||
Defaults to the texture pack name.
|
Defaults to the texture pack name.
|
||||||
See [Translating content meta](lua_api.md#translating-content-meta).
|
See [Translating content meta](lua_api.md#translating-content-meta).
|
||||||
|
* `formspec_theme`: optional. Formspec elements that define the defaut style.
|
||||||
|
* Allowed elements: `bgcolor`, `style_type`
|
||||||
|
* `formspec_version_theme`: optional. Indicates the minimal [formspec version](lua_api.md)
|
||||||
|
needed to properly display `formspec_theme`. On older clients, this suppresses warnings.
|
||||||
|
|
||||||
### `description.txt`
|
### `description.txt`
|
||||||
**Deprecated**, you should use texture_pack.conf instead.
|
**Deprecated**, you should use texture_pack.conf instead.
|
||||||
|
|
|
@ -28,6 +28,8 @@
|
||||||
#endif
|
#endif
|
||||||
#include "os.h"
|
#include "os.h"
|
||||||
|
|
||||||
|
irr::gui::IGUISkin *impl_create_irr_guiskin(irr::video::IVideoDriver *driver);
|
||||||
|
|
||||||
namespace irr
|
namespace irr
|
||||||
{
|
{
|
||||||
namespace gui
|
namespace gui
|
||||||
|
@ -590,7 +592,7 @@ If you no longer need the skin, you should call IGUISkin::drop().
|
||||||
See IReferenceCounted::drop() for more information. */
|
See IReferenceCounted::drop() for more information. */
|
||||||
IGUISkin *CGUIEnvironment::createSkin()
|
IGUISkin *CGUIEnvironment::createSkin()
|
||||||
{
|
{
|
||||||
IGUISkin *skin = new CGUISkin(Driver);
|
IGUISkin *skin = impl_create_irr_guiskin(Driver);
|
||||||
|
|
||||||
IGUIFont *builtinfont = getBuiltInFont();
|
IGUIFont *builtinfont = getBuiltInFont();
|
||||||
IGUIFontBitmap *bitfont = 0;
|
IGUIFontBitmap *bitfont = 0;
|
||||||
|
|
|
@ -291,7 +291,7 @@ namespace gui
|
||||||
//! gets the colors
|
//! gets the colors
|
||||||
virtual void getColors(video::SColor* colors); // ::PATCH:
|
virtual void getColors(video::SColor* colors); // ::PATCH:
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
|
|
||||||
float Scale = 1.0f;
|
float Scale = 1.0f;
|
||||||
video::SColor Colors[EGDC_COUNT];
|
video::SColor Colors[EGDC_COUNT];
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "inputhandler.h"
|
#include "inputhandler.h"
|
||||||
#include "profiler.h"
|
#include "profiler.h"
|
||||||
#include "gui/guiEngine.h"
|
#include "gui/guiEngine.h"
|
||||||
|
#include "gui/guiSkin.h"
|
||||||
#include "fontengine.h"
|
#include "fontengine.h"
|
||||||
#include "clientlauncher.h"
|
#include "clientlauncher.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
@ -338,6 +339,11 @@ static video::ITexture *loadTexture(video::IVideoDriver *driver, const char *pat
|
||||||
return texture;
|
return texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gui::IGUISkin *impl_create_irr_guiskin(video::IVideoDriver *driver)
|
||||||
|
{
|
||||||
|
return new GUISkin(driver);
|
||||||
|
}
|
||||||
|
|
||||||
void ClientLauncher::config_guienv()
|
void ClientLauncher::config_guienv()
|
||||||
{
|
{
|
||||||
gui::IGUISkin *skin = guienv->getSkin();
|
gui::IGUISkin *skin = guienv->getSkin();
|
||||||
|
|
|
@ -19,6 +19,7 @@ set(gui_SRCS
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/guiScene.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/guiScene.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/guiScrollBar.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/guiScrollBar.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/guiScrollContainer.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/guiScrollContainer.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/guiSkin.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/guiTable.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/guiTable.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/guiHyperText.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/guiHyperText.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/guiVolumeChange.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/guiVolumeChange.cpp
|
||||||
|
|
|
@ -13,6 +13,9 @@
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
class StyleSpec;
|
||||||
|
|
||||||
|
using StyleSpecMap = std::unordered_map<std::string, std::vector<StyleSpec>>;
|
||||||
|
|
||||||
class StyleSpec
|
class StyleSpec
|
||||||
{
|
{
|
||||||
|
@ -59,6 +62,8 @@ public:
|
||||||
STATE_INVALID = 1 << 4,
|
STATE_INVALID = 1 << 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using StateMap = std::array<StyleSpec, NUM_STATES>;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::array<bool, NUM_PROPERTIES> property_set{};
|
std::array<bool, NUM_PROPERTIES> property_set{};
|
||||||
std::array<std::string, NUM_PROPERTIES> properties;
|
std::array<std::string, NUM_PROPERTIES> properties;
|
||||||
|
@ -380,12 +385,24 @@ public:
|
||||||
|
|
||||||
StyleSpec &operator|=(const StyleSpec &other)
|
StyleSpec &operator|=(const StyleSpec &other)
|
||||||
{
|
{
|
||||||
|
u32 props_set = 0;
|
||||||
|
static_assert(sizeof(props_set) * 8 > NUM_PROPERTIES);
|
||||||
|
|
||||||
for (size_t i = 0; i < NUM_PROPERTIES; i++) {
|
for (size_t i = 0; i < NUM_PROPERTIES; i++) {
|
||||||
auto prop = (Property)i;
|
auto prop = (Property)i;
|
||||||
if (other.hasProperty(prop)) {
|
if (other.hasProperty(prop)) {
|
||||||
|
props_set |= (1 << i);
|
||||||
set(prop, other.get(prop, ""));
|
set(prop, other.get(prop, ""));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if ((props_set & (1 << FGIMG | 1 << FGIMG_MIDDLE)) == (1 << FGIMG)) {
|
||||||
|
// Image was specified without 9-slice. Reset to non-9-slice.
|
||||||
|
set(FGIMG_MIDDLE, "");
|
||||||
|
}
|
||||||
|
if ((props_set & (1 << BGIMG | 1 << BGIMG_MIDDLE)) == (1 << BGIMG)) {
|
||||||
|
// Image was specified without 9-slice. Reset to non-9-slice.
|
||||||
|
set(BGIMG_MIDDLE, "");
|
||||||
|
}
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
|
@ -303,13 +303,17 @@ void GUIButton::draw()
|
||||||
|
|
||||||
// PATCH
|
// PATCH
|
||||||
video::ITexture* texture = ButtonImages[(u32)imageState].Texture;
|
video::ITexture* texture = ButtonImages[(u32)imageState].Texture;
|
||||||
|
// FIXME: Vertices can only be darkened because [0, 255] is normalized to [0, 1]
|
||||||
|
// For reference: irr/src/OpenGL/Driver.cpp -> `vt2DImage`
|
||||||
video::SColor image_colors[] = { BgColor, BgColor, BgColor, BgColor };
|
video::SColor image_colors[] = { BgColor, BgColor, BgColor, BgColor };
|
||||||
if (BgMiddle.getArea() == 0) {
|
if (BgMiddle.getArea() == 0) {
|
||||||
|
// Regular image button
|
||||||
driver->draw2DImage(texture,
|
driver->draw2DImage(texture,
|
||||||
ScaleImage? AbsoluteRect : core::rect<s32>(pos, sourceRect.getSize()),
|
ScaleImage? AbsoluteRect : core::rect<s32>(pos, sourceRect.getSize()),
|
||||||
sourceRect, &AbsoluteClippingRect,
|
sourceRect, &AbsoluteClippingRect,
|
||||||
image_colors, UseAlphaChannel);
|
image_colors, UseAlphaChannel);
|
||||||
} else {
|
} else {
|
||||||
|
// This is generally used to replace the default border style
|
||||||
draw2DImage9Slice(driver, texture,
|
draw2DImage9Slice(driver, texture,
|
||||||
ScaleImage ? AbsoluteRect : core::rect<s32>(pos, sourceRect.getSize()),
|
ScaleImage ? AbsoluteRect : core::rect<s32>(pos, sourceRect.getSize()),
|
||||||
sourceRect, BgMiddle, &AbsoluteClippingRect, image_colors);
|
sourceRect, BgMiddle, &AbsoluteClippingRect, image_colors);
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include "client/guiscalingfilter.h"
|
#include "client/guiscalingfilter.h"
|
||||||
#include "client/renderingengine.h"
|
#include "client/renderingengine.h"
|
||||||
#include "client/shader.h"
|
#include "client/shader.h"
|
||||||
|
#include "client/texturepaths.h"
|
||||||
#include "client/tile.h"
|
#include "client/tile.h"
|
||||||
#include "clientdynamicinfo.h"
|
#include "clientdynamicinfo.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
@ -43,14 +44,18 @@ void TextDestGuiEngine::gotText(const StringMap &fields)
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
MenuTextureSource::MenuTextureSource(video::IVideoDriver* driver) :
|
||||||
|
m_driver(driver)
|
||||||
|
{
|
||||||
|
g_settings->registerChangedCallback("texture_path", onTxpSettingChanged, this);
|
||||||
|
}
|
||||||
|
|
||||||
MenuTextureSource::~MenuTextureSource()
|
MenuTextureSource::~MenuTextureSource()
|
||||||
{
|
{
|
||||||
u32 before = m_driver->getTextureCount();
|
g_settings->deregisterAllChangedCallbacks(this);
|
||||||
|
|
||||||
for (const auto &it: m_to_delete) {
|
u32 before = m_driver->getTextureCount();
|
||||||
m_driver->removeTexture(it);
|
cleanupTextures();
|
||||||
}
|
|
||||||
m_to_delete.clear();
|
|
||||||
|
|
||||||
infostream << "~MenuTextureSource() before cleanup: "<< before
|
infostream << "~MenuTextureSource() before cleanup: "<< before
|
||||||
<< " after: " << m_driver->getTextureCount() << std::endl;
|
<< " after: " << m_driver->getTextureCount() << std::endl;
|
||||||
|
@ -70,8 +75,14 @@ video::ITexture *MenuTextureSource::getTexture(const std::string &name, u32 *id)
|
||||||
if (retval)
|
if (retval)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
verbosestream << "MenuTextureSource: loading " << name << std::endl;
|
// Try to find the texture in the active texture pack
|
||||||
video::IImage *image = m_driver->createImageFromFile(name.c_str());
|
std::string path;
|
||||||
|
if (!fs::IsPathAbsolute(name))
|
||||||
|
path = getTexturePath(name, nullptr);
|
||||||
|
|
||||||
|
const char *filepath = path.empty() ? name.c_str() : path.c_str();
|
||||||
|
verbosestream << "MenuTextureSource: loading " << filepath << std::endl;
|
||||||
|
video::IImage *image = m_driver->createImageFromFile(filepath);
|
||||||
if (!image)
|
if (!image)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -83,6 +94,20 @@ video::ITexture *MenuTextureSource::getTexture(const std::string &name, u32 *id)
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MenuTextureSource::cleanupTextures()
|
||||||
|
{
|
||||||
|
for (const auto &it: m_to_delete) {
|
||||||
|
m_driver->removeTexture(it);
|
||||||
|
}
|
||||||
|
m_to_delete.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MenuTextureSource::onTxpSettingChanged(const std::string &name, void *data)
|
||||||
|
{
|
||||||
|
((MenuTextureSource *)data)->cleanupTextures();
|
||||||
|
clearTextureNameCache();
|
||||||
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
/** MenuMusicFetcher */
|
/** MenuMusicFetcher */
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
|
@ -76,7 +76,7 @@ public:
|
||||||
* default constructor
|
* default constructor
|
||||||
* @param driver the video driver to load textures from
|
* @param driver the video driver to load textures from
|
||||||
*/
|
*/
|
||||||
MenuTextureSource(video::IVideoDriver *driver) : m_driver(driver) {};
|
MenuTextureSource(video::IVideoDriver *driver);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* destructor, removes all loaded textures
|
* destructor, removes all loaded textures
|
||||||
|
@ -91,6 +91,12 @@ public:
|
||||||
video::ITexture *getTexture(const std::string &name, u32 *id = NULL);
|
video::ITexture *getTexture(const std::string &name, u32 *id = NULL);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
/** Unloads all textures in `m_to_delete` */
|
||||||
|
void cleanupTextures();
|
||||||
|
|
||||||
|
/** Update the texture cache */
|
||||||
|
static void onTxpSettingChanged(const std::string &name, void *data);
|
||||||
|
|
||||||
/** driver to get textures from */
|
/** driver to get textures from */
|
||||||
video::IVideoDriver *m_driver = nullptr;
|
video::IVideoDriver *m_driver = nullptr;
|
||||||
/** set of textures to delete */
|
/** set of textures to delete */
|
||||||
|
|
|
@ -56,6 +56,7 @@
|
||||||
#include "guiScrollContainer.h"
|
#include "guiScrollContainer.h"
|
||||||
#include "guiHyperText.h"
|
#include "guiHyperText.h"
|
||||||
#include "guiScene.h"
|
#include "guiScene.h"
|
||||||
|
#include "guiSkin.h"
|
||||||
|
|
||||||
#define MY_CHECKPOS(a,b) \
|
#define MY_CHECKPOS(a,b) \
|
||||||
if (v_pos.size() != 2) { \
|
if (v_pos.size() != 2) { \
|
||||||
|
@ -114,10 +115,15 @@ GUIFormSpecMenu::GUIFormSpecMenu(JoystickController *joystick,
|
||||||
|
|
||||||
m_tooltip_show_delay = (u32)g_settings->getS32("tooltip_show_delay");
|
m_tooltip_show_delay = (u32)g_settings->getS32("tooltip_show_delay");
|
||||||
m_tooltip_append_itemname = g_settings->getBool("tooltip_append_itemname");
|
m_tooltip_append_itemname = g_settings->getBool("tooltip_append_itemname");
|
||||||
|
|
||||||
|
g_settings->registerChangedCallback("texture_path", onTxpSettingChanged, this);
|
||||||
|
setThemeFromSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
GUIFormSpecMenu::~GUIFormSpecMenu()
|
GUIFormSpecMenu::~GUIFormSpecMenu()
|
||||||
{
|
{
|
||||||
|
g_settings->deregisterAllChangedCallbacks(this);
|
||||||
|
|
||||||
removeAll();
|
removeAll();
|
||||||
|
|
||||||
delete m_selected_item;
|
delete m_selected_item;
|
||||||
|
@ -2618,15 +2624,9 @@ void GUIFormSpecMenu::parsePadding(parserData *data, const std::string &element)
|
||||||
<< "'" << std::endl;
|
<< "'" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GUIFormSpecMenu::parseStyle(parserData *data, const std::string &element)
|
void GUIFormSpecMenu::parse_style_to_map(StyleSpecMap &out, const std::string &element,
|
||||||
|
std::unordered_set<std::string> *prop_warned)
|
||||||
{
|
{
|
||||||
if (data->type != "style" && data->type != "style_type") {
|
|
||||||
errorstream << "Invalid style element type: '" << data->type << "'" << std::endl;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool style_type = (data->type == "style_type");
|
|
||||||
|
|
||||||
std::vector<std::string> parts = split(element, ';');
|
std::vector<std::string> parts = split(element, ';');
|
||||||
|
|
||||||
if (parts.size() < 2) {
|
if (parts.size() < 2) {
|
||||||
|
@ -2653,11 +2653,11 @@ void GUIFormSpecMenu::parseStyle(parserData *data, const std::string &element)
|
||||||
|
|
||||||
StyleSpec::Property prop = StyleSpec::GetPropertyByName(propname);
|
StyleSpec::Property prop = StyleSpec::GetPropertyByName(propname);
|
||||||
if (prop == StyleSpec::NONE) {
|
if (prop == StyleSpec::NONE) {
|
||||||
if (property_warned.find(propname) != property_warned.end()) {
|
if (prop_warned && prop_warned->find(propname) != prop_warned->end()) {
|
||||||
warningstream << "Invalid style element (Unknown property " << propname << "): '"
|
warningstream << "Invalid style element (Unknown property " << propname << "): '"
|
||||||
<< element
|
<< element
|
||||||
<< "'" << std::endl;
|
<< "'" << std::endl;
|
||||||
property_warned.insert(propname);
|
prop_warned->insert(propname);
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -2705,11 +2705,7 @@ void GUIFormSpecMenu::parseStyle(parserData *data, const std::string &element)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (style_type) {
|
out[selector].push_back(selector_spec);
|
||||||
theme_by_type[selector].push_back(selector_spec);
|
|
||||||
} else {
|
|
||||||
theme_by_name[selector].push_back(selector_spec);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Backwards-compatibility for existing _hovered/_pressed properties
|
// Backwards-compatibility for existing _hovered/_pressed properties
|
||||||
if (selector_spec.hasProperty(StyleSpec::BGCOLOR_HOVERED)
|
if (selector_spec.hasProperty(StyleSpec::BGCOLOR_HOVERED)
|
||||||
|
@ -2728,11 +2724,7 @@ void GUIFormSpecMenu::parseStyle(parserData *data, const std::string &element)
|
||||||
hover_spec.set(StyleSpec::FGIMG, selector_spec.get(StyleSpec::FGIMG_HOVERED, ""));
|
hover_spec.set(StyleSpec::FGIMG, selector_spec.get(StyleSpec::FGIMG_HOVERED, ""));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (style_type) {
|
out[selector].push_back(hover_spec);
|
||||||
theme_by_type[selector].push_back(hover_spec);
|
|
||||||
} else {
|
|
||||||
theme_by_name[selector].push_back(hover_spec);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (selector_spec.hasProperty(StyleSpec::BGCOLOR_PRESSED)
|
if (selector_spec.hasProperty(StyleSpec::BGCOLOR_PRESSED)
|
||||||
|| selector_spec.hasProperty(StyleSpec::BGIMG_PRESSED)
|
|| selector_spec.hasProperty(StyleSpec::BGIMG_PRESSED)
|
||||||
|
@ -2750,15 +2742,31 @@ void GUIFormSpecMenu::parseStyle(parserData *data, const std::string &element)
|
||||||
press_spec.set(StyleSpec::FGIMG, selector_spec.get(StyleSpec::FGIMG_PRESSED, ""));
|
press_spec.set(StyleSpec::FGIMG, selector_spec.get(StyleSpec::FGIMG_PRESSED, ""));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (style_type) {
|
out[selector].push_back(press_spec);
|
||||||
theme_by_type[selector].push_back(press_spec);
|
|
||||||
} else {
|
|
||||||
theme_by_name[selector].push_back(press_spec);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
void GUIFormSpecMenu::parseStyle(parserData *data, const std::string &element)
|
||||||
|
{
|
||||||
|
if (data->type != "style" && data->type != "style_type") {
|
||||||
|
errorstream << "Invalid style element type: '" << data->type << "'" << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool style_type = (data->type == "style_type");
|
||||||
|
bool do_warn = m_formspec_version <= FORMSPEC_API_VERSION;
|
||||||
|
|
||||||
|
StyleSpecMap *map = style_type ? &theme_by_type : &theme_by_name;
|
||||||
|
if (data->reading_theme) {
|
||||||
|
GUISkin *skin = (GUISkin *)Environment->getSkin();
|
||||||
|
map = &skin->getThemeRef();
|
||||||
|
}
|
||||||
|
parse_style_to_map(
|
||||||
|
*map,
|
||||||
|
element,
|
||||||
|
do_warn ? &property_warned : nullptr
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GUIFormSpecMenu::parseSetFocus(parserData*, const std::string &element)
|
void GUIFormSpecMenu::parseSetFocus(parserData*, const std::string &element)
|
||||||
|
@ -2898,8 +2906,8 @@ void GUIFormSpecMenu::removeAll()
|
||||||
scroll_container_it.second->drop();
|
scroll_container_it.second->drop();
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::unordered_map<std::string, std::function<void(GUIFormSpecMenu*, GUIFormSpecMenu::parserData *data,
|
const std::unordered_map<std::string, GUIFormSpecMenu::parser_function_t>
|
||||||
const std::string &description)>> GUIFormSpecMenu::element_parsers = {
|
GUIFormSpecMenu::element_parsers = {
|
||||||
{"container", &GUIFormSpecMenu::parseContainer},
|
{"container", &GUIFormSpecMenu::parseContainer},
|
||||||
{"container_end", &GUIFormSpecMenu::parseContainerEnd},
|
{"container_end", &GUIFormSpecMenu::parseContainerEnd},
|
||||||
{"list", &GUIFormSpecMenu::parseList},
|
{"list", &GUIFormSpecMenu::parseList},
|
||||||
|
@ -2948,14 +2956,20 @@ const std::unordered_map<std::string, std::function<void(GUIFormSpecMenu*, GUIFo
|
||||||
{"allow_close", &GUIFormSpecMenu::parseAllowClose},
|
{"allow_close", &GUIFormSpecMenu::parseAllowClose},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Formspec elements allowed for themes
|
||||||
|
const std::unordered_map<std::string, GUIFormSpecMenu::parser_function_t>
|
||||||
|
GUIFormSpecMenu::element_parsers_theme = {
|
||||||
|
{"bgcolor", &GUIFormSpecMenu::parseBackgroundColor},
|
||||||
|
{"style_type", &GUIFormSpecMenu::parseStyle},
|
||||||
|
};
|
||||||
|
|
||||||
void GUIFormSpecMenu::parseElement(parserData* data, const std::string &element)
|
void GUIFormSpecMenu::parseElement(parserData *data, const std::string &element, bool is_theme)
|
||||||
{
|
{
|
||||||
//some prechecks
|
//some prechecks
|
||||||
if (element.empty())
|
if (element.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (parseVersionDirect(element))
|
if (!is_theme && parseVersionDirect(element))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
size_t pos = element.find('[');
|
size_t pos = element.find('[');
|
||||||
|
@ -2968,8 +2982,9 @@ void GUIFormSpecMenu::parseElement(parserData* data, const std::string &element)
|
||||||
// They remain here due to bool flags, for now
|
// They remain here due to bool flags, for now
|
||||||
data->type = type;
|
data->type = type;
|
||||||
|
|
||||||
auto it = element_parsers.find(type);
|
auto &parser_lut = is_theme ? element_parsers_theme : element_parsers;
|
||||||
if (it != element_parsers.end()) {
|
auto it = parser_lut.find(type);
|
||||||
|
if (it != parser_lut.end()) {
|
||||||
it->second(this, data, description);
|
it->second(this, data, description);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -5054,6 +5069,40 @@ std::wstring GUIFormSpecMenu::getLabelByID(s32 id)
|
||||||
return L"";
|
return L"";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void GUIFormSpecMenu::setThemeFromSettings()
|
||||||
|
{
|
||||||
|
GUISkin *skin = (GUISkin *)Environment->getSkin();
|
||||||
|
skin->getThemeRef().clear();
|
||||||
|
skin->setTextureSource(m_tsrc);
|
||||||
|
|
||||||
|
const std::string settingspath = g_settings->get("texture_path") + DIR_DELIM + "texture_pack.conf";
|
||||||
|
Settings settings;
|
||||||
|
if (!settings.readConfigFile(settingspath.c_str()))
|
||||||
|
return;
|
||||||
|
if (!settings.exists("formspec_theme"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
settings.getU16NoEx("formspec_version_theme", m_theme_formspec_version);
|
||||||
|
auto theme_elements = split(settings.get("formspec_theme"), ']');
|
||||||
|
|
||||||
|
parserData mydata;
|
||||||
|
mydata.reading_theme = true;
|
||||||
|
|
||||||
|
const u16 version_backup = m_formspec_version;
|
||||||
|
m_formspec_version = m_theme_formspec_version;
|
||||||
|
for (const std::string &element : theme_elements)
|
||||||
|
parseElement(&mydata, element, true);
|
||||||
|
m_formspec_version = version_backup;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GUIFormSpecMenu::onTxpSettingChanged(const std::string &name, void *data)
|
||||||
|
{
|
||||||
|
GUIFormSpecMenu *me = (GUIFormSpecMenu *)data;
|
||||||
|
me->setThemeFromSettings();
|
||||||
|
me->regenerateGui(me->m_screensize_old);
|
||||||
|
}
|
||||||
|
|
||||||
StyleSpec GUIFormSpecMenu::getDefaultStyleForElement(const std::string &type,
|
StyleSpec GUIFormSpecMenu::getDefaultStyleForElement(const std::string &type,
|
||||||
const std::string &name, const std::string &parent_type) {
|
const std::string &name, const std::string &parent_type) {
|
||||||
return getStyleForElement(type, name, parent_type)[StyleSpec::STATE_DEFAULT];
|
return getStyleForElement(type, name, parent_type)[StyleSpec::STATE_DEFAULT];
|
||||||
|
|
|
@ -302,10 +302,14 @@ protected:
|
||||||
bool precheckElement(const std::string &name, const std::string &element,
|
bool precheckElement(const std::string &name, const std::string &element,
|
||||||
size_t args_min, size_t args_max, std::vector<std::string> &parts);
|
size_t args_min, size_t args_max, std::vector<std::string> &parts);
|
||||||
|
|
||||||
std::unordered_map<std::string, std::vector<StyleSpec>> theme_by_type;
|
StyleSpecMap theme_by_type, theme_by_name;
|
||||||
std::unordered_map<std::string, std::vector<StyleSpec>> theme_by_name;
|
|
||||||
std::unordered_set<std::string> property_warned;
|
std::unordered_set<std::string> property_warned;
|
||||||
|
|
||||||
|
// Texturepack-definied formspec theming support
|
||||||
|
u16 m_theme_formspec_version;
|
||||||
|
void setThemeFromSettings();
|
||||||
|
static void onTxpSettingChanged(const std::string &name, void *data);
|
||||||
|
|
||||||
StyleSpec getDefaultStyleForElement(const std::string &type,
|
StyleSpec getDefaultStyleForElement(const std::string &type,
|
||||||
const std::string &name="", const std::string &parent_type="");
|
const std::string &name="", const std::string &parent_type="");
|
||||||
std::array<StyleSpec, StyleSpec::NUM_STATES> getStyleForElement(const std::string &type,
|
std::array<StyleSpec, StyleSpec::NUM_STATES> getStyleForElement(const std::string &type,
|
||||||
|
@ -387,8 +391,9 @@ private:
|
||||||
bool m_show_debug = false;
|
bool m_show_debug = false;
|
||||||
|
|
||||||
struct parserData {
|
struct parserData {
|
||||||
bool explicit_size;
|
bool explicit_size = false;
|
||||||
bool real_coordinates;
|
bool real_coordinates = false;
|
||||||
|
bool reading_theme = false;
|
||||||
u8 simple_field_count;
|
u8 simple_field_count;
|
||||||
v2f invsize;
|
v2f invsize;
|
||||||
v2s32 size;
|
v2s32 size;
|
||||||
|
@ -419,7 +424,9 @@ private:
|
||||||
std::string type;
|
std::string type;
|
||||||
};
|
};
|
||||||
|
|
||||||
static const std::unordered_map<std::string, std::function<void(GUIFormSpecMenu*, GUIFormSpecMenu::parserData *data, const std::string &description)>> element_parsers;
|
using parser_function_t = std::function<void(GUIFormSpecMenu*, parserData *, const std::string &)>;
|
||||||
|
static const std::unordered_map<std::string, parser_function_t>
|
||||||
|
element_parsers, element_parsers_theme;
|
||||||
|
|
||||||
struct fs_key_pending {
|
struct fs_key_pending {
|
||||||
bool key_up;
|
bool key_up;
|
||||||
|
@ -433,7 +440,7 @@ private:
|
||||||
|
|
||||||
void removeAll();
|
void removeAll();
|
||||||
|
|
||||||
void parseElement(parserData* data, const std::string &element);
|
void parseElement(parserData* data, const std::string &element, bool is_theme = false);
|
||||||
|
|
||||||
void parseSize(parserData* data, const std::string &element);
|
void parseSize(parserData* data, const std::string &element);
|
||||||
void parseContainer(parserData* data, const std::string &element);
|
void parseContainer(parserData* data, const std::string &element);
|
||||||
|
@ -483,6 +490,8 @@ private:
|
||||||
void parseAnchor(parserData *data, const std::string &element);
|
void parseAnchor(parserData *data, const std::string &element);
|
||||||
bool parsePaddingDirect(parserData *data, const std::string &element);
|
bool parsePaddingDirect(parserData *data, const std::string &element);
|
||||||
void parsePadding(parserData *data, const std::string &element);
|
void parsePadding(parserData *data, const std::string &element);
|
||||||
|
static void parse_style_to_map(StyleSpecMap &out, const std::string &element,
|
||||||
|
std::unordered_set<std::string> *prop_warned);
|
||||||
void parseStyle(parserData *data, const std::string &element);
|
void parseStyle(parserData *data, const std::string &element);
|
||||||
void parseSetFocus(parserData *, const std::string &element);
|
void parseSetFocus(parserData *, const std::string &element);
|
||||||
void parseModel(parserData *data, const std::string &element);
|
void parseModel(parserData *data, const std::string &element);
|
||||||
|
|
76
src/gui/guiSkin.cpp
Normal file
76
src/gui/guiSkin.cpp
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
// Luanti
|
||||||
|
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
// Copyright (C) 2025 Krock/SmallJoker <mk939@ymail.com>
|
||||||
|
|
||||||
|
#include "guiSkin.h"
|
||||||
|
#include "client/guiscalingfilter.h"
|
||||||
|
|
||||||
|
|
||||||
|
GUISkin::GUISkin(video::IVideoDriver *driver) : gui::CGUISkin(driver)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
GUISkin::~GUISkin()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void GUISkin::drawColored3DButtonPanePressed(gui::IGUIElement *element,
|
||||||
|
const core::rect<s32> &rect,
|
||||||
|
const core::rect<s32> *clip,
|
||||||
|
const video::SColor *colors)
|
||||||
|
{
|
||||||
|
if (!Driver)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (tryDrawPane("_skin_button", StyleSpec::STATE_PRESSED, rect, clip))
|
||||||
|
return;
|
||||||
|
|
||||||
|
gui::CGUISkin::drawColored3DButtonPanePressed(element, rect, clip, colors);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GUISkin::drawColored3DButtonPaneStandard(gui::IGUIElement *element,
|
||||||
|
const core::rect<s32> &rect,
|
||||||
|
const core::rect<s32> *clip,
|
||||||
|
const video::SColor *colors)
|
||||||
|
{
|
||||||
|
if (!Driver)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (tryDrawPane("_skin_button", StyleSpec::STATE_DEFAULT, rect, clip))
|
||||||
|
return;
|
||||||
|
|
||||||
|
gui::CGUISkin::drawColored3DButtonPaneStandard(element, rect, clip, colors);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GUISkin::tryDrawPane(const char *type, StyleSpec::State state,
|
||||||
|
const core::rect<s32> &rect,
|
||||||
|
const core::rect<s32> *clip)
|
||||||
|
{
|
||||||
|
auto it = m_theme.find(type);
|
||||||
|
if (it == m_theme.end())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
video::SColor c = 0xFFFFFFFF;
|
||||||
|
video::SColor image_colors[] = { c, c, c, c };
|
||||||
|
|
||||||
|
// Similar to GUIFormSpecMenu::getStyleForElement
|
||||||
|
StyleSpec::StateMap states;
|
||||||
|
for (const StyleSpec &spec : it->second)
|
||||||
|
states[(u32)spec.getState()] |= spec;
|
||||||
|
|
||||||
|
StyleSpec style = StyleSpec::getStyleFromStatePropagation(states, state);
|
||||||
|
video::ITexture *texture = style.getTexture(StyleSpec::BGIMG, m_texture_source);
|
||||||
|
core::recti source_rect = core::rect<s32>(core::position2di(0,0), texture->getOriginalSize());
|
||||||
|
|
||||||
|
core::recti bg_middle = style.getRect(StyleSpec::BGIMG_MIDDLE, core::recti());
|
||||||
|
if (bg_middle.getArea() == 0) {
|
||||||
|
Driver->draw2DImage(texture, rect, source_rect, clip, image_colors, true);
|
||||||
|
} else {
|
||||||
|
draw2DImage9Slice(Driver, texture, rect, source_rect, bg_middle, clip, image_colors);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
37
src/gui/guiSkin.h
Normal file
37
src/gui/guiSkin.h
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
// Luanti
|
||||||
|
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
// Copyright (C) 2025 Krock/SmallJoker <mk939@ymail.com>
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "StyleSpec.h" // StyleSpecMap
|
||||||
|
#include "../../irr/src/CGUISkin.h"
|
||||||
|
|
||||||
|
class GUISkin : public gui::CGUISkin {
|
||||||
|
public:
|
||||||
|
GUISkin(video::IVideoDriver *driver);
|
||||||
|
virtual ~GUISkin();
|
||||||
|
|
||||||
|
void setTextureSource(ISimpleTextureSource *src) { m_texture_source = src; }
|
||||||
|
|
||||||
|
virtual void drawColored3DButtonPaneStandard(gui::IGUIElement *element,
|
||||||
|
const core::rect<s32> &rect,
|
||||||
|
const core::rect<s32> *clip = 0,
|
||||||
|
const video::SColor *colors = 0) override;
|
||||||
|
|
||||||
|
virtual void drawColored3DButtonPanePressed(gui::IGUIElement *element,
|
||||||
|
const core::rect<s32> &rect,
|
||||||
|
const core::rect<s32> *clip = 0,
|
||||||
|
const video::SColor *colors = 0) override;
|
||||||
|
|
||||||
|
StyleSpecMap &getThemeRef() { return m_theme; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool tryDrawPane(const char *type, StyleSpec::State state,
|
||||||
|
const core::rect<s32> &rect,
|
||||||
|
const core::rect<s32> *clip = 0);
|
||||||
|
|
||||||
|
ISimpleTextureSource *m_texture_source = nullptr;
|
||||||
|
StyleSpecMap m_theme;
|
||||||
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue