diff --git a/irr/src/CGUIEnvironment.cpp b/irr/src/CGUIEnvironment.cpp index abfa0aab9..1a4560eab 100644 --- a/irr/src/CGUIEnvironment.cpp +++ b/irr/src/CGUIEnvironment.cpp @@ -28,6 +28,8 @@ #endif #include "os.h" +irr::gui::IGUISkin *impl_create_irr_guiskin(irr::video::IVideoDriver *driver); + namespace irr { namespace gui @@ -590,7 +592,7 @@ If you no longer need the skin, you should call IGUISkin::drop(). See IReferenceCounted::drop() for more information. */ IGUISkin *CGUIEnvironment::createSkin() { - IGUISkin *skin = new CGUISkin(Driver); + IGUISkin *skin = impl_create_irr_guiskin(Driver); IGUIFont *builtinfont = getBuiltInFont(); IGUIFontBitmap *bitfont = 0; diff --git a/irr/src/CGUISkin.h b/irr/src/CGUISkin.h index 704a09745..e3bb6f380 100644 --- a/irr/src/CGUISkin.h +++ b/irr/src/CGUISkin.h @@ -291,7 +291,7 @@ namespace gui //! gets the colors virtual void getColors(video::SColor* colors); // ::PATCH: - private: + protected: float Scale = 1.0f; video::SColor Colors[EGDC_COUNT]; diff --git a/src/client/clientlauncher.cpp b/src/client/clientlauncher.cpp index 64f2e8f51..8a0484824 100644 --- a/src/client/clientlauncher.cpp +++ b/src/client/clientlauncher.cpp @@ -14,6 +14,7 @@ #include "inputhandler.h" #include "profiler.h" #include "gui/guiEngine.h" +#include "gui/guiSkin.h" #include "fontengine.h" #include "clientlauncher.h" #include "version.h" @@ -338,6 +339,11 @@ static video::ITexture *loadTexture(video::IVideoDriver *driver, const char *pat return texture; } +gui::IGUISkin *impl_create_irr_guiskin(video::IVideoDriver *driver) +{ + return new GUISkin(driver); +} + void ClientLauncher::config_guienv() { gui::IGUISkin *skin = guienv->getSkin(); diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 0c1db2ae0..9b9216be1 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -19,6 +19,7 @@ set(gui_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/guiScene.cpp ${CMAKE_CURRENT_SOURCE_DIR}/guiScrollBar.cpp ${CMAKE_CURRENT_SOURCE_DIR}/guiScrollContainer.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/guiSkin.cpp ${CMAKE_CURRENT_SOURCE_DIR}/guiTable.cpp ${CMAKE_CURRENT_SOURCE_DIR}/guiHyperText.cpp ${CMAKE_CURRENT_SOURCE_DIR}/guiVolumeChange.cpp diff --git a/src/gui/StyleSpec.h b/src/gui/StyleSpec.h index 1003c5865..a7d389cea 100644 --- a/src/gui/StyleSpec.h +++ b/src/gui/StyleSpec.h @@ -62,6 +62,8 @@ public: STATE_INVALID = 1 << 4, }; + using StateMap = std::array; + private: std::array property_set{}; std::array properties; diff --git a/src/gui/guiFormSpecMenu.cpp b/src/gui/guiFormSpecMenu.cpp index 34ddcea0a..b86df13e2 100644 --- a/src/gui/guiFormSpecMenu.cpp +++ b/src/gui/guiFormSpecMenu.cpp @@ -56,6 +56,7 @@ #include "guiScrollContainer.h" #include "guiHyperText.h" #include "guiScene.h" +#include "guiSkin.h" #define MY_CHECKPOS(a,b) \ if (v_pos.size() != 2) { \ @@ -2756,8 +2757,13 @@ void GUIFormSpecMenu::parseStyle(parserData *data, const std::string &element) 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( - style_type ? theme_by_type : theme_by_name, + *map, element, do_warn ? &property_warned : nullptr ); @@ -3248,16 +3254,6 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize) pos_offset = v2f32(); - if (!m_theme_elements.empty()) { - // Formspec theming - - const u16 version_backup = m_formspec_version; - m_formspec_version = m_theme_formspec_version; - for (const std::string &element : m_theme_elements) - parseElement(&mydata, element, true); - m_formspec_version = version_backup; - } - // used for formspec versions < 3 auto legacy_sort_start = std::prev(Children.end()); // last element @@ -5050,7 +5046,9 @@ std::wstring GUIFormSpecMenu::getLabelByID(s32 id) void GUIFormSpecMenu::setThemeFromSettings() { - m_theme_elements.clear(); + 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; @@ -5060,7 +5058,16 @@ void GUIFormSpecMenu::setThemeFromSettings() return; settings.getU16NoEx("formspec_version_theme", m_theme_formspec_version); - m_theme_elements = split(settings.get("formspec_theme"), ']'); + 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) diff --git a/src/gui/guiFormSpecMenu.h b/src/gui/guiFormSpecMenu.h index b732fe0f4..d7a18cf4b 100644 --- a/src/gui/guiFormSpecMenu.h +++ b/src/gui/guiFormSpecMenu.h @@ -306,7 +306,6 @@ protected: std::unordered_set property_warned; // Texturepack-definied formspec theming support - std::vector m_theme_elements; u16 m_theme_formspec_version; void setThemeFromSettings(); static void onTxpSettingChanged(const std::string &name, void *data); @@ -392,8 +391,9 @@ private: bool m_show_debug = false; struct parserData { - bool explicit_size; - bool real_coordinates; + bool explicit_size = false; + bool real_coordinates = false; + bool reading_theme = false; u8 simple_field_count; v2f invsize; v2s32 size; diff --git a/src/gui/guiSkin.cpp b/src/gui/guiSkin.cpp new file mode 100644 index 000000000..b4aef156b --- /dev/null +++ b/src/gui/guiSkin.cpp @@ -0,0 +1,76 @@ +// Luanti +// SPDX-License-Identifier: LGPL-2.1-or-later +// Copyright (C) 2025 Krock/SmallJoker + +#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 &rect, + const core::rect *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 &rect, + const core::rect *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 &rect, + const core::rect *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(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; +} + + diff --git a/src/gui/guiSkin.h b/src/gui/guiSkin.h new file mode 100644 index 000000000..4c46a79d5 --- /dev/null +++ b/src/gui/guiSkin.h @@ -0,0 +1,37 @@ +// Luanti +// SPDX-License-Identifier: LGPL-2.1-or-later +// Copyright (C) 2025 Krock/SmallJoker + +#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 &rect, + const core::rect *clip = 0, + const video::SColor *colors = 0) override; + + virtual void drawColored3DButtonPanePressed(gui::IGUIElement *element, + const core::rect &rect, + const core::rect *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 &rect, + const core::rect *clip = 0); + + ISimpleTextureSource *m_texture_source = nullptr; + StyleSpecMap m_theme; +}; +