diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/client/game.cpp | 9 | ||||
-rw-r--r-- | src/gui/StyleSpec.h | 65 | ||||
-rw-r--r-- | src/gui/guiButton.cpp | 163 | ||||
-rw-r--r-- | src/gui/guiButton.h | 34 | ||||
-rw-r--r-- | src/gui/guiButtonImage.cpp | 102 | ||||
-rw-r--r-- | src/gui/guiButtonImage.h | 26 | ||||
-rw-r--r-- | src/gui/guiButtonItemImage.cpp | 15 | ||||
-rw-r--r-- | src/gui/guiButtonItemImage.h | 9 | ||||
-rw-r--r-- | src/gui/guiConfirmRegistration.cpp | 8 | ||||
-rw-r--r-- | src/gui/guiConfirmRegistration.h | 4 | ||||
-rw-r--r-- | src/gui/guiFormSpecMenu.cpp | 187 | ||||
-rw-r--r-- | src/gui/guiFormSpecMenu.h | 8 | ||||
-rw-r--r-- | src/gui/guiKeyChangeMenu.cpp | 12 | ||||
-rw-r--r-- | src/gui/guiKeyChangeMenu.h | 5 | ||||
-rw-r--r-- | src/gui/guiPasswordChange.cpp | 10 | ||||
-rw-r--r-- | src/gui/guiPasswordChange.h | 5 | ||||
-rw-r--r-- | src/gui/guiVolumeChange.cpp | 7 | ||||
-rw-r--r-- | src/gui/guiVolumeChange.h | 7 | ||||
-rw-r--r-- | src/script/lua_api/l_mainmenu.cpp | 19 | ||||
-rw-r--r-- | src/util/numeric.h | 10 |
20 files changed, 405 insertions, 300 deletions
diff --git a/src/client/game.cpp b/src/client/game.cpp index 505108caf..06e76d170 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -1556,7 +1556,8 @@ bool Game::connectToServer(const std::string &playername, } else { registration_confirmation_shown = true; (new GUIConfirmRegistration(guienv, guienv->getRootGUIElement(), -1, - &g_menumgr, client, playername, password, connection_aborted))->drop(); + &g_menumgr, client, playername, password, + connection_aborted, texture_src))->drop(); } } else { wait_time += dtime; @@ -1711,19 +1712,19 @@ inline bool Game::handleCallbacks() if (g_gamecallback->changepassword_requested) { (new GUIPasswordChange(guienv, guiroot, -1, - &g_menumgr, client))->drop(); + &g_menumgr, client, texture_src))->drop(); g_gamecallback->changepassword_requested = false; } if (g_gamecallback->changevolume_requested) { (new GUIVolumeChange(guienv, guiroot, -1, - &g_menumgr))->drop(); + &g_menumgr, texture_src))->drop(); g_gamecallback->changevolume_requested = false; } if (g_gamecallback->keyconfig_requested) { (new GUIKeyChangeMenu(guienv, guiroot, -1, - &g_menumgr))->drop(); + &g_menumgr, texture_src))->drop(); g_gamecallback->keyconfig_requested = false; } diff --git a/src/gui/StyleSpec.h b/src/gui/StyleSpec.h index 999c1d237..799fbf46d 100644 --- a/src/gui/StyleSpec.h +++ b/src/gui/StyleSpec.h @@ -18,6 +18,7 @@ with this program; if not, write to the Free Software Foundation, Inc., */ #include "client/tile.h" // ITextureSource +#include "debug.h" #include "irrlichttypes_extrabloated.h" #include "util/string.h" #include <array> @@ -31,25 +32,34 @@ public: { TEXTCOLOR, BGCOLOR, - BGCOLOR_HOVERED, - BGCOLOR_PRESSED, + BGCOLOR_HOVERED, // Note: Deprecated property + BGCOLOR_PRESSED, // Note: Deprecated property NOCLIP, BORDER, BGIMG, - BGIMG_HOVERED, + BGIMG_HOVERED, // Note: Deprecated property BGIMG_MIDDLE, - BGIMG_PRESSED, + BGIMG_PRESSED, // Note: Deprecated property FGIMG, - FGIMG_HOVERED, - FGIMG_PRESSED, + FGIMG_HOVERED, // Note: Deprecated property + FGIMG_PRESSED, // Note: Deprecated property ALPHA, NUM_PROPERTIES, NONE }; + enum State + { + STATE_DEFAULT = 0, + STATE_HOVERED = 1 << 0, + STATE_PRESSED = 1 << 1, + NUM_STATES = 1 << 2, + STATE_INVALID = 1 << 3, + }; private: std::array<bool, NUM_PROPERTIES> property_set{}; std::array<std::string, NUM_PROPERTIES> properties; + State state_map = STATE_DEFAULT; public: static Property GetPropertyByName(const std::string &name) @@ -99,6 +109,49 @@ public: property_set[prop] = true; } + //! Parses a name and returns the corresponding state enum + static State getStateByName(const std::string &name) + { + if (name == "default") { + return STATE_DEFAULT; + } else if (name == "hovered") { + return STATE_HOVERED; + } else if (name == "pressed") { + return STATE_PRESSED; + } else { + return STATE_INVALID; + } + } + + //! Gets the state that this style is intended for + State getState() const + { + return state_map; + } + + //! Set the given state on this style + void addState(State state) + { + FATAL_ERROR_IF(state >= NUM_STATES, "Out-of-bounds state received"); + + state_map = static_cast<State>(state_map | state); + } + + //! Using a list of styles mapped to state values, calculate the final + // combined style for a state by propagating values in its component states + static StyleSpec getStyleFromStatePropagation(const std::array<StyleSpec, NUM_STATES> &styles, State state) + { + StyleSpec temp = styles[StyleSpec::STATE_DEFAULT]; + temp.state_map = state; + for (int i = StyleSpec::STATE_DEFAULT + 1; i <= state; i++) { + if ((state & i) != 0) { + temp = temp | styles[i]; + } + } + + return temp; + } + video::SColor getColor(Property prop, video::SColor def) const { const auto &val = properties[prop]; diff --git a/src/gui/guiButton.cpp b/src/gui/guiButton.cpp index 4c16ee237..9dfe36bc4 100644 --- a/src/gui/guiButton.cpp +++ b/src/gui/guiButton.cpp @@ -14,6 +14,7 @@ #include "irrlicht_changes/static_text.h"
#include "porting.h"
#include "StyleSpec.h"
+#include "util/numeric.h"
using namespace irr;
using namespace gui;
@@ -26,14 +27,15 @@ using namespace gui; //! constructor
GUIButton::GUIButton(IGUIEnvironment* environment, IGUIElement* parent,
- s32 id, core::rect<s32> rectangle, bool noclip)
+ s32 id, core::rect<s32> rectangle, ISimpleTextureSource *tsrc,
+ bool noclip)
: IGUIButton(environment, parent, id, rectangle),
SpriteBank(0), OverrideFont(0),
OverrideColorEnabled(false), OverrideColor(video::SColor(101,255,255,255)),
ClickTime(0), HoverTime(0), FocusTime(0),
ClickShiftState(false), ClickControlState(false),
IsPushButton(false), Pressed(false),
- UseAlphaChannel(false), DrawBorder(true), ScaleImage(false)
+ UseAlphaChannel(false), DrawBorder(true), ScaleImage(false), TSrc(tsrc)
{
setNotClipped(noclip);
@@ -44,14 +46,6 @@ GUIButton::GUIButton(IGUIEnvironment* environment, IGUIElement* parent, // PATCH
for (size_t i = 0; i < 4; i++) {
Colors[i] = Environment->getSkin()->getColor((EGUI_DEFAULT_COLOR)i);
- HoveredColors[i] = irr::video::SColor(Colors[i].getAlpha(),
- core::clamp<u32>(Colors[i].getRed() * COLOR_HOVERED_MOD, 0, 255),
- core::clamp<u32>(Colors[i].getGreen() * COLOR_HOVERED_MOD, 0, 255),
- core::clamp<u32>(Colors[i].getBlue() * COLOR_HOVERED_MOD, 0, 255));
- PressedColors[i] = irr::video::SColor(Colors[i].getAlpha(),
- core::clamp<u32>(Colors[i].getRed() * COLOR_PRESSED_MOD, 0, 255),
- core::clamp<u32>(Colors[i].getGreen() * COLOR_PRESSED_MOD, 0, 255),
- core::clamp<u32>(Colors[i].getBlue() * COLOR_PRESSED_MOD, 0, 255));
}
StaticText = gui::StaticText::add(Environment, Text.c_str(), core::rect<s32>(0,0,rectangle.getWidth(),rectangle.getHeight()), false, false, this, id);
StaticText->setTextAlignment(EGUIA_CENTER, EGUIA_CENTER);
@@ -262,6 +256,13 @@ void GUIButton::draw() return;
// PATCH
+ // Track hovered state, if it has changed then we need to update the style.
+ bool hovered = isHovered();
+ if (hovered != WasHovered) {
+ WasHovered = hovered;
+ setFromState();
+ }
+
GUISkin* skin = dynamic_cast<GUISkin*>(Environment->getSkin());
video::IVideoDriver* driver = Environment->getVideoDriver();
// END PATCH
@@ -271,21 +272,24 @@ void GUIButton::draw() if (!Pressed)
{
// PATCH
- skin->drawColored3DButtonPaneStandard(this, AbsoluteRect, &AbsoluteClippingRect,
- isHovered() ? HoveredColors : Colors);
+ skin->drawColored3DButtonPaneStandard(this, AbsoluteRect,
+ &AbsoluteClippingRect, Colors);
// END PATCH
}
else
{
// PATCH
- skin->drawColored3DButtonPanePressed(this,
- AbsoluteRect, &AbsoluteClippingRect, PressedColors);
+ skin->drawColored3DButtonPanePressed(this, AbsoluteRect,
+ &AbsoluteClippingRect, Colors);
// END PATCH
}
}
const core::position2di buttonCenter(AbsoluteRect.getCenter());
- EGUI_BUTTON_IMAGE_STATE imageState = getImageState(Pressed);
+ // PATCH
+ // The image changes based on the state, so we use the default every time.
+ EGUI_BUTTON_IMAGE_STATE imageState = EGBIS_IMAGE_UP;
+ // END PATCH
if ( ButtonImages[(u32)imageState].Texture )
{
core::position2d<s32> pos(buttonCenter);
@@ -548,18 +552,6 @@ void GUIButton::setPressedImage(video::ITexture* image, const core::rect<s32>& p setImage(gui::EGBIS_IMAGE_DOWN, image, pos);
}
-void GUIButton::setHoveredImage(video::ITexture* image)
-{
- setImage(gui::EGBIS_IMAGE_UP_MOUSEOVER, image);
- setImage(gui::EGBIS_IMAGE_UP_FOCUSED_MOUSEOVER, image);
-}
-
-void GUIButton::setHoveredImage(video::ITexture* image, const core::rect<s32>& pos)
-{
- setImage(gui::EGBIS_IMAGE_UP_MOUSEOVER, image, pos);
- setImage(gui::EGBIS_IMAGE_UP_FOCUSED_MOUSEOVER, image, pos);
-}
-
//! Sets the text displayed by the button
void GUIButton::setText(const wchar_t* text)
{
@@ -618,6 +610,8 @@ void GUIButton::setPressed(bool pressed) skin->getSize(irr::gui::EGDS_BUTTON_PRESSED_IMAGE_OFFSET_Y)));
}
}
+
+ setFromState();
}
}
@@ -729,10 +723,12 @@ void GUIButton::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWri }
// PATCH
-GUIButton* GUIButton::addButton(IGUIEnvironment *environment, const core::rect<s32>& rectangle,
- IGUIElement* parent, s32 id, const wchar_t* text, const wchar_t *tooltiptext)
+GUIButton* GUIButton::addButton(IGUIEnvironment *environment,
+ const core::rect<s32>& rectangle, ISimpleTextureSource *tsrc,
+ IGUIElement* parent, s32 id, const wchar_t* text,
+ const wchar_t *tooltiptext)
{
- GUIButton* button = new GUIButton(environment, parent ? parent : environment->getRootGUIElement(), id, rectangle);
+ GUIButton* button = new GUIButton(environment, parent ? parent : environment->getRootGUIElement(), id, rectangle, tsrc);
if (text)
button->setText(text);
@@ -749,76 +745,87 @@ void GUIButton::setColor(video::SColor color) for (size_t i = 0; i < 4; i++) {
video::SColor base = Environment->getSkin()->getColor((gui::EGUI_DEFAULT_COLOR)i);
Colors[i] = base.getInterpolated(color, d);
- HoveredColors[i] = irr::video::SColor(Colors[i].getAlpha(),
- core::clamp<u32>(Colors[i].getRed() * COLOR_HOVERED_MOD, 0, 255),
- core::clamp<u32>(Colors[i].getGreen() * COLOR_HOVERED_MOD, 0, 255),
- core::clamp<u32>(Colors[i].getBlue() * COLOR_HOVERED_MOD, 0, 255));
- PressedColors[i] = irr::video::SColor(Colors[i].getAlpha(),
- core::clamp<u32>(Colors[i].getRed() * COLOR_PRESSED_MOD, 0, 255),
- core::clamp<u32>(Colors[i].getGreen() * COLOR_PRESSED_MOD, 0, 255),
- core::clamp<u32>(Colors[i].getBlue() * COLOR_PRESSED_MOD, 0, 255));
}
}
-void GUIButton::setHoveredColor(video::SColor color)
-{
- float d = 0.65f;
- for (size_t i = 0; i < 4; i++) {
- video::SColor base = Environment->getSkin()->getColor((gui::EGUI_DEFAULT_COLOR)i);
- HoveredColors[i] = base.getInterpolated(color, d);
- }
-}
-void GUIButton::setPressedColor(video::SColor color)
+
+//! Set element properties from a StyleSpec corresponding to the button state
+void GUIButton::setFromState()
{
- float d = 0.65f;
- for (size_t i = 0; i < 4; i++) {
- video::SColor base = Environment->getSkin()->getColor((gui::EGUI_DEFAULT_COLOR)i);
- PressedColors[i] = base.getInterpolated(color, d);
- }
+ StyleSpec::State state = StyleSpec::STATE_DEFAULT;
+
+ if (isPressed())
+ state = static_cast<StyleSpec::State>(state | StyleSpec::STATE_PRESSED);
+
+ if (isHovered())
+ state = static_cast<StyleSpec::State>(state | StyleSpec::STATE_HOVERED);
+
+ setFromStyle(StyleSpec::getStyleFromStatePropagation(Styles, state));
}
//! Set element properties from a StyleSpec
-void GUIButton::setFromStyle(const StyleSpec& style, ISimpleTextureSource *tsrc)
+void GUIButton::setFromStyle(const StyleSpec& style)
{
+ bool hovered = (style.getState() & StyleSpec::STATE_HOVERED) != 0;
+ bool pressed = (style.getState() & StyleSpec::STATE_PRESSED) != 0;
+
if (style.isNotDefault(StyleSpec::BGCOLOR)) {
+
setColor(style.getColor(StyleSpec::BGCOLOR));
- }
- if (style.isNotDefault(StyleSpec::BGCOLOR_HOVERED)) {
- setHoveredColor(style.getColor(StyleSpec::BGCOLOR_HOVERED));
- }
- if (style.isNotDefault(StyleSpec::BGCOLOR_PRESSED)) {
- setPressedColor(style.getColor(StyleSpec::BGCOLOR_PRESSED));
+
+ // If we have a propagated hover/press color, we need to automatically
+ // lighten/darken it
+ if (!Styles[style.getState()].isNotDefault(StyleSpec::BGCOLOR)) {
+ for (size_t i = 0; i < 4; i++) {
+ if (pressed) {
+ Colors[i] = multiplyColorValue(Colors[i], COLOR_PRESSED_MOD);
+ } else if (hovered) {
+ Colors[i] = multiplyColorValue(Colors[i], COLOR_HOVERED_MOD);
+ }
+ }
+ }
+
+ } else {
+ for (size_t i = 0; i < 4; i++) {
+ video::SColor base =
+ Environment->getSkin()->getColor((gui::EGUI_DEFAULT_COLOR)i);
+ if (pressed) {
+ Colors[i] = multiplyColorValue(base, COLOR_PRESSED_MOD);
+ } else if (hovered) {
+ Colors[i] = multiplyColorValue(base, COLOR_HOVERED_MOD);
+ } else {
+ Colors[i] = base;
+ }
+ }
}
if (style.isNotDefault(StyleSpec::TEXTCOLOR)) {
setOverrideColor(style.getColor(StyleSpec::TEXTCOLOR));
+ } else {
+ setOverrideColor(video::SColor(255,255,255,255));
+ OverrideColorEnabled = false;
}
- setNotClipped(style.getBool(StyleSpec::NOCLIP, isNotClipped()));
- setDrawBorder(style.getBool(StyleSpec::BORDER, DrawBorder));
+ setNotClipped(style.getBool(StyleSpec::NOCLIP, false));
+ setDrawBorder(style.getBool(StyleSpec::BORDER, true));
setUseAlphaChannel(style.getBool(StyleSpec::ALPHA, true));
const core::position2di buttonCenter(AbsoluteRect.getCenter());
core::position2d<s32> geom(buttonCenter);
if (style.isNotDefault(StyleSpec::BGIMG)) {
- video::ITexture *texture = style.getTexture(StyleSpec::BGIMG, tsrc);
-
+ video::ITexture *texture = style.getTexture(StyleSpec::BGIMG,
+ getTextureSource());
setImage(guiScalingImageButton(
- Environment->getVideoDriver(), texture, geom.X, geom.Y));
- setScaleImage(true);
- }
- if (style.isNotDefault(StyleSpec::BGIMG_HOVERED)) {
- video::ITexture *hovered_texture = style.getTexture(StyleSpec::BGIMG_HOVERED, tsrc);
-
- setHoveredImage(guiScalingImageButton(
- Environment->getVideoDriver(), hovered_texture, geom.X, geom.Y));
- setScaleImage(true);
- }
- if (style.isNotDefault(StyleSpec::BGIMG_PRESSED)) {
- video::ITexture *pressed_texture = style.getTexture(StyleSpec::BGIMG_PRESSED, tsrc);
-
- setPressedImage(guiScalingImageButton(
- Environment->getVideoDriver(), pressed_texture, geom.X, geom.Y));
+ Environment->getVideoDriver(), texture, geom.X, geom.Y));
setScaleImage(true);
+ } else {
+ setImage(nullptr);
}
BgMiddle = style.getRect(StyleSpec::BGIMG_MIDDLE, BgMiddle);
}
+
+//! Set the styles used for each state
+void GUIButton::setStyles(const std::array<StyleSpec, StyleSpec::NUM_STATES>& styles)
+{
+ Styles = styles;
+ setFromState();
+}
// END PATCH
diff --git a/src/gui/guiButton.h b/src/gui/guiButton.h index 3d1f98c32..ef10f926e 100644 --- a/src/gui/guiButton.h +++ b/src/gui/guiButton.h @@ -13,6 +13,7 @@ #include "ITexture.h"
#include "SColor.h"
#include "guiSkin.h"
+#include "StyleSpec.h"
using namespace irr;
@@ -67,7 +68,6 @@ using namespace irr; #endif
class ISimpleTextureSource;
-class StyleSpec;
class GUIButton : public gui::IGUIButton
{
@@ -75,7 +75,8 @@ public: //! constructor
GUIButton(gui::IGUIEnvironment* environment, gui::IGUIElement* parent,
- s32 id, core::rect<s32> rectangle, bool noclip=false);
+ s32 id, core::rect<s32> rectangle, ISimpleTextureSource *tsrc,
+ bool noclip=false);
//! destructor
virtual ~GUIButton();
@@ -125,16 +126,10 @@ public: //! Sets an image which should be displayed on the button when it is in pressed state.
virtual void setPressedImage(video::ITexture* image, const core::rect<s32>& pos) override;
- //! Sets an image which should be displayed on the button when it is in hovered state.
- virtual void setHoveredImage(video::ITexture* image=nullptr);
-
//! Sets the text displayed by the button
virtual void setText(const wchar_t* text) override;
// END PATCH
- //! Sets an image which should be displayed on the button when it is in hovered state.
- virtual void setHoveredImage(video::ITexture* image, const core::rect<s32>& pos);
-
//! Sets the sprite bank used by the button
virtual void setSpriteBank(gui::IGUISpriteBank* bank=0) override;
@@ -225,22 +220,29 @@ public: void setColor(video::SColor color);
// PATCH
- void setHoveredColor(video::SColor color);
- void setPressedColor(video::SColor color);
+ //! Set element properties from a StyleSpec corresponding to the button state
+ void setFromState();
//! Set element properties from a StyleSpec
- virtual void setFromStyle(const StyleSpec& style, ISimpleTextureSource *tsrc);
+ virtual void setFromStyle(const StyleSpec& style);
+
+ //! Set the styles used for each state
+ void setStyles(const std::array<StyleSpec, StyleSpec::NUM_STATES>& styles);
// END PATCH
//! Do not drop returned handle
- static GUIButton* addButton(gui::IGUIEnvironment *environment, const core::rect<s32>& rectangle,
- IGUIElement* parent, s32 id, const wchar_t* text, const wchar_t *tooltiptext=L"");
+ static GUIButton* addButton(gui::IGUIEnvironment *environment,
+ const core::rect<s32>& rectangle, ISimpleTextureSource *tsrc,
+ IGUIElement* parent, s32 id, const wchar_t* text,
+ const wchar_t *tooltiptext=L"");
protected:
void drawSprite(gui::EGUI_BUTTON_STATE state, u32 startTime, const core::position2di& center);
gui::EGUI_BUTTON_IMAGE_STATE getImageState(bool pressed) const;
+ ISimpleTextureSource *getTextureSource() { return TSrc; }
+
struct ButtonImage
{
ButtonImage() : Texture(0), SourceRect(core::rect<s32>(0,0,0,0))
@@ -308,6 +310,8 @@ private: ButtonImage ButtonImages[gui::EGBIS_COUNT];
+ std::array<StyleSpec, StyleSpec::NUM_STATES> Styles;
+
gui::IGUIFont* OverrideFont;
bool OverrideColorEnabled;
@@ -326,8 +330,8 @@ private: video::SColor Colors[4];
// PATCH
- video::SColor HoveredColors[4];
- video::SColor PressedColors[4];
+ bool WasHovered = false;
+ ISimpleTextureSource *TSrc;
gui::IGUIStaticText *StaticText;
diff --git a/src/gui/guiButtonImage.cpp b/src/gui/guiButtonImage.cpp index 02d920277..2658ad967 100644 --- a/src/gui/guiButtonImage.cpp +++ b/src/gui/guiButtonImage.cpp @@ -30,8 +30,9 @@ using namespace irr; using namespace gui; GUIButtonImage::GUIButtonImage(gui::IGUIEnvironment *environment, - gui::IGUIElement *parent, s32 id, core::rect<s32> rectangle, bool noclip) - : GUIButton (environment, parent, id, rectangle, noclip) + gui::IGUIElement *parent, s32 id, core::rect<s32> rectangle, + ISimpleTextureSource *tsrc, bool noclip) + : GUIButton (environment, parent, id, rectangle, tsrc, noclip) { m_image = Environment->addImage( core::rect<s32>(0,0,rectangle.getWidth(),rectangle.getHeight()), this); @@ -39,100 +40,38 @@ GUIButtonImage::GUIButtonImage(gui::IGUIEnvironment *environment, sendToBack(m_image); } -bool GUIButtonImage::OnEvent(const SEvent& event) -{ - bool result = GUIButton::OnEvent(event); - - EGUI_BUTTON_IMAGE_STATE imageState = getImageState(isPressed(), m_foreground_images); - video::ITexture *texture = m_foreground_images[(u32)imageState].Texture; - if (texture != nullptr) - { - m_image->setImage(texture); - } - - m_image->setVisible(texture != nullptr); - - return result; -} - -void GUIButtonImage::setForegroundImage(EGUI_BUTTON_IMAGE_STATE state, - video::ITexture *image, const core::rect<s32> &sourceRect) +void GUIButtonImage::setForegroundImage(video::ITexture *image) { - if (state >= EGBIS_COUNT) + if (image == m_foreground_image) return; - if (image) + if (image != nullptr) image->grab(); - u32 stateIdx = (u32)state; - if (m_foreground_images[stateIdx].Texture) - m_foreground_images[stateIdx].Texture->drop(); - - m_foreground_images[stateIdx].Texture = image; - m_foreground_images[stateIdx].SourceRect = sourceRect; - - EGUI_BUTTON_IMAGE_STATE imageState = getImageState(isPressed(), m_foreground_images); - if (imageState == stateIdx) - m_image->setImage(image); -} - -void GUIButtonImage::setForegroundImage(video::ITexture *image) -{ - setForegroundImage(gui::EGBIS_IMAGE_UP, image); -} - -void GUIButtonImage::setForegroundImage(video::ITexture *image, const core::rect<s32> &pos) -{ - setForegroundImage(gui::EGBIS_IMAGE_UP, image, pos); -} - -void GUIButtonImage::setPressedForegroundImage(video::ITexture *image) -{ - setForegroundImage(gui::EGBIS_IMAGE_DOWN, image); -} + if (m_foreground_image != nullptr) + m_foreground_image->drop(); -void GUIButtonImage::setPressedForegroundImage(video::ITexture *image, const core::rect<s32> &pos) -{ - setForegroundImage(gui::EGBIS_IMAGE_DOWN, image, pos); + m_foreground_image = image; + m_image->setImage(image); } -void GUIButtonImage::setHoveredForegroundImage(video::ITexture *image) +//! Set element properties from a StyleSpec +void GUIButtonImage::setFromStyle(const StyleSpec& style) { - setForegroundImage(gui::EGBIS_IMAGE_UP_MOUSEOVER, image); - setForegroundImage(gui::EGBIS_IMAGE_UP_FOCUSED_MOUSEOVER, image); -} - -void GUIButtonImage::setHoveredForegroundImage(video::ITexture *image, const core::rect<s32> &pos) -{ - setForegroundImage(gui::EGBIS_IMAGE_UP_MOUSEOVER, image, pos); - setForegroundImage(gui::EGBIS_IMAGE_UP_FOCUSED_MOUSEOVER, image, pos); -} - -void GUIButtonImage::setFromStyle(const StyleSpec &style, ISimpleTextureSource *tsrc) -{ - GUIButton::setFromStyle(style, tsrc); + GUIButton::setFromStyle(style); video::IVideoDriver *driver = Environment->getVideoDriver(); const core::position2di buttonCenter(AbsoluteRect.getCenter()); core::position2d<s32> geom(buttonCenter); if (style.isNotDefault(StyleSpec::FGIMG)) { - video::ITexture *texture = style.getTexture(StyleSpec::FGIMG, tsrc); + video::ITexture *texture = style.getTexture(StyleSpec::FGIMG, + getTextureSource()); setForegroundImage(guiScalingImageButton(driver, texture, geom.X, geom.Y)); setScaleImage(true); - } - if (style.isNotDefault(StyleSpec::FGIMG_HOVERED)) { - video::ITexture *hovered_texture = style.getTexture(StyleSpec::FGIMG_HOVERED, tsrc); - - setHoveredForegroundImage(guiScalingImageButton(driver, hovered_texture, geom.X, geom.Y)); - setScaleImage(true); - } - if (style.isNotDefault(StyleSpec::FGIMG_PRESSED)) { - video::ITexture *pressed_texture = style.getTexture(StyleSpec::FGIMG_PRESSED, tsrc); - - setPressedForegroundImage(guiScalingImageButton(driver, pressed_texture, geom.X, geom.Y)); - setScaleImage(true); + } else { + setForegroundImage(nullptr); } } @@ -143,11 +82,12 @@ void GUIButtonImage::setScaleImage(bool scaleImage) } GUIButtonImage *GUIButtonImage::addButton(IGUIEnvironment *environment, - const core::rect<s32> &rectangle, IGUIElement *parent, s32 id, - const wchar_t *text, const wchar_t *tooltiptext) + const core::rect<s32> &rectangle, ISimpleTextureSource *tsrc, + IGUIElement *parent, s32 id, const wchar_t *text, + const wchar_t *tooltiptext) { GUIButtonImage *button = new GUIButtonImage(environment, - parent ? parent : environment->getRootGUIElement(), id, rectangle); + parent ? parent : environment->getRootGUIElement(), id, rectangle, tsrc); if (text) button->setText(text); diff --git a/src/gui/guiButtonImage.h b/src/gui/guiButtonImage.h index 15901ee5d..a948d772b 100644 --- a/src/gui/guiButtonImage.h +++ b/src/gui/guiButtonImage.h @@ -27,33 +27,23 @@ class GUIButtonImage : public GUIButton public: //! constructor GUIButtonImage(gui::IGUIEnvironment *environment, gui::IGUIElement *parent, - s32 id, core::rect<s32> rectangle, bool noclip = false); - - virtual bool OnEvent(const SEvent& event) override; - - void setForegroundImage(gui::EGUI_BUTTON_IMAGE_STATE state, - video::ITexture *image = nullptr, - const core::rect<s32> &sourceRect = core::rect<s32>(0, 0, 0, 0)); + s32 id, core::rect<s32> rectangle, ISimpleTextureSource *tsrc, + bool noclip = false); void setForegroundImage(video::ITexture *image = nullptr); - void setForegroundImage(video::ITexture *image, const core::rect<s32> &pos); - - void setPressedForegroundImage(video::ITexture *image = nullptr); - void setPressedForegroundImage(video::ITexture *image, const core::rect<s32> &pos); - - void setHoveredForegroundImage(video::ITexture *image = nullptr); - void setHoveredForegroundImage(video::ITexture *image, const core::rect<s32> &pos); - virtual void setFromStyle(const StyleSpec &style, ISimpleTextureSource *tsrc) override; + //! Set element properties from a StyleSpec + virtual void setFromStyle(const StyleSpec& style) override; virtual void setScaleImage(bool scaleImage=true) override; //! Do not drop returned handle static GUIButtonImage *addButton(gui::IGUIEnvironment *environment, - const core::rect<s32> &rectangle, IGUIElement *parent, s32 id, - const wchar_t *text, const wchar_t *tooltiptext = L""); + const core::rect<s32> &rectangle, ISimpleTextureSource *tsrc, + IGUIElement *parent, s32 id, const wchar_t *text, + const wchar_t *tooltiptext = L""); private: - ButtonImage m_foreground_images[gui::EGBIS_COUNT]; + video::ITexture *m_foreground_image = nullptr; gui::IGUIImage *m_image; }; diff --git a/src/gui/guiButtonItemImage.cpp b/src/gui/guiButtonItemImage.cpp index 5c48b2acd..d8b9042ac 100644 --- a/src/gui/guiButtonItemImage.cpp +++ b/src/gui/guiButtonItemImage.cpp @@ -28,9 +28,11 @@ with this program; if not, write to the Free Software Foundation, Inc., using namespace irr; using namespace gui; -GUIButtonItemImage::GUIButtonItemImage(gui::IGUIEnvironment *environment, gui::IGUIElement *parent, - s32 id, core::rect<s32> rectangle, std::string item, Client *client, bool noclip) - : GUIButton (environment, parent, id, rectangle, noclip) +GUIButtonItemImage::GUIButtonItemImage(gui::IGUIEnvironment *environment, + gui::IGUIElement *parent, s32 id, core::rect<s32> rectangle, + ISimpleTextureSource *tsrc, std::string item, Client *client, + bool noclip) + : GUIButton (environment, parent, id, rectangle, tsrc, noclip) { m_image = new GUIItemImage(environment, this, id, core::rect<s32>(0,0,rectangle.getWidth(),rectangle.getHeight()), @@ -42,12 +44,13 @@ GUIButtonItemImage::GUIButtonItemImage(gui::IGUIEnvironment *environment, gui::I } GUIButtonItemImage *GUIButtonItemImage::addButton(IGUIEnvironment *environment, - const core::rect<s32> &rectangle, IGUIElement *parent, s32 id, - const wchar_t *text, std::string item, Client *client) + const core::rect<s32> &rectangle, ISimpleTextureSource *tsrc, + IGUIElement *parent, s32 id, const wchar_t *text, std::string item, + Client *client) { GUIButtonItemImage *button = new GUIButtonItemImage(environment, parent ? parent : environment->getRootGUIElement(), - id, rectangle, item, client); + id, rectangle, tsrc, item, client); if (text) button->setText(text); diff --git a/src/gui/guiButtonItemImage.h b/src/gui/guiButtonItemImage.h index 0a61874da..9cd0f6188 100644 --- a/src/gui/guiButtonItemImage.h +++ b/src/gui/guiButtonItemImage.h @@ -30,13 +30,14 @@ class GUIButtonItemImage : public GUIButton public: //! constructor GUIButtonItemImage(gui::IGUIEnvironment *environment, gui::IGUIElement *parent, - s32 id, core::rect<s32> rectangle, std::string item, - Client *client, bool noclip = false); + s32 id, core::rect<s32> rectangle, ISimpleTextureSource *tsrc, + std::string item, Client *client, bool noclip = false); //! Do not drop returned handle static GUIButtonItemImage *addButton(gui::IGUIEnvironment *environment, - const core::rect<s32> &rectangle, IGUIElement *parent, s32 id, - const wchar_t *text, std::string item, Client *client); + const core::rect<s32> &rectangle, ISimpleTextureSource *tsrc, + IGUIElement *parent, s32 id, const wchar_t *text, std::string item, + Client *client); private: std::string m_item_name; diff --git a/src/gui/guiConfirmRegistration.cpp b/src/gui/guiConfirmRegistration.cpp index 0d8bdf54e..58ac42740 100644 --- a/src/gui/guiConfirmRegistration.cpp +++ b/src/gui/guiConfirmRegistration.cpp @@ -40,10 +40,10 @@ const int ID_message = 266; GUIConfirmRegistration::GUIConfirmRegistration(gui::IGUIEnvironment *env, gui::IGUIElement *parent, s32 id, IMenuManager *menumgr, Client *client, const std::string &playername, const std::string &password, - bool *aborted) : + bool *aborted, ISimpleTextureSource *tsrc) : GUIModalMenu(env, parent, id, menumgr), m_client(client), m_playername(playername), m_password(password), - m_aborted(aborted) + m_aborted(aborted), m_tsrc(tsrc) { #ifdef __ANDROID__ m_touchscreen_visible = false; @@ -130,14 +130,14 @@ void GUIConfirmRegistration::regenerateGui(v2u32 screensize) core::rect<s32> rect2(0, 0, 230 * s, 35 * s); rect2 = rect2 + v2s32(size.X / 2 - 220 * s, ypos); text = wgettext("Register and Join"); - GUIButton::addButton(Environment, rect2, this, ID_confirm, text); + GUIButton::addButton(Environment, rect2, m_tsrc, this, ID_confirm, text); delete[] text; } { core::rect<s32> rect2(0, 0, 120 * s, 35 * s); rect2 = rect2 + v2s32(size.X / 2 + 70 * s, ypos); text = wgettext("Cancel"); - GUIButton::addButton(Environment, rect2, this, ID_cancel, text); + GUIButton::addButton(Environment, rect2, m_tsrc, this, ID_cancel, text); delete[] text; } { diff --git a/src/gui/guiConfirmRegistration.h b/src/gui/guiConfirmRegistration.h index 42c07e4ed..d8387201d 100644 --- a/src/gui/guiConfirmRegistration.h +++ b/src/gui/guiConfirmRegistration.h @@ -25,6 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include <string> class Client; +class ISimpleTextureSource; class GUIConfirmRegistration : public GUIModalMenu { @@ -32,7 +33,7 @@ public: GUIConfirmRegistration(gui::IGUIEnvironment *env, gui::IGUIElement *parent, s32 id, IMenuManager *menumgr, Client *client, const std::string &playername, const std::string &password, - bool *aborted); + bool *aborted, ISimpleTextureSource *tsrc); ~GUIConfirmRegistration(); void removeChildren(); @@ -63,4 +64,5 @@ private: const std::string &m_password; bool *m_aborted = nullptr; std::wstring m_pass_confirm = L""; + ISimpleTextureSource *m_tsrc; }; diff --git a/src/gui/guiFormSpecMenu.cpp b/src/gui/guiFormSpecMenu.cpp index acb153569..6a383a791 100644 --- a/src/gui/guiFormSpecMenu.cpp +++ b/src/gui/guiFormSpecMenu.cpp @@ -553,7 +553,7 @@ void GUIFormSpecMenu::parseCheckbox(parserData* data, const std::string &element gui::IGUICheckBox *e = Environment->addCheckBox(fselected, rect, this, spec.fid, spec.flabel.c_str()); - auto style = getStyleForElement("checkbox", name); + auto style = getDefaultStyleForElement("checkbox", name); e->setNotClipped(style.getBool(StyleSpec::NOCLIP, false)); if (spec.fname == data->focused_fieldname) { @@ -613,7 +613,7 @@ void GUIFormSpecMenu::parseScrollBar(parserData* data, const std::string &elemen GUIScrollBar *e = new GUIScrollBar(Environment, this, spec.fid, rect, is_horizontal, true); - auto style = getStyleForElement("scrollbar", name); + auto style = getDefaultStyleForElement("scrollbar", name); e->setNotClipped(style.getBool(StyleSpec::NOCLIP, false)); e->setArrowsVisible(data->scrollbar_options.arrow_visiblity); @@ -740,7 +740,7 @@ void GUIFormSpecMenu::parseImage(parserData* data, const std::string &element) gui::IGUIImage *e = Environment->addImage(rect, this, spec.fid, 0, true); e->setImage(texture); e->setScaleImage(true); - auto style = getStyleForElement("image", spec.fname); + auto style = getDefaultStyleForElement("image", spec.fname); e->setNotClipped(style.getBool(StyleSpec::NOCLIP, m_formspec_version < 3)); m_fields.push_back(spec); @@ -776,7 +776,7 @@ void GUIFormSpecMenu::parseImage(parserData* data, const std::string &element) ); gui::IGUIImage *e = Environment->addImage(texture, pos, true, this, spec.fid, 0); - auto style = getStyleForElement("image", spec.fname); + auto style = getDefaultStyleForElement("image", spec.fname); e->setNotClipped(style.getBool(StyleSpec::NOCLIP, m_formspec_version < 3)); m_fields.push_back(spec); @@ -841,7 +841,7 @@ void GUIFormSpecMenu::parseAnimatedImage(parserData *data, const std::string &el if (parts.size() >= 7) e->setFrameIndex(stoi(parts[6]) - 1); - auto style = getStyleForElement("animated_image", spec.fname, "image"); + auto style = getDefaultStyleForElement("animated_image", spec.fname, "image"); e->setNotClipped(style.getBool(StyleSpec::NOCLIP, false)); e->drop(); @@ -888,7 +888,7 @@ void GUIFormSpecMenu::parseItemImage(parserData* data, const std::string &elemen GUIItemImage *e = new GUIItemImage(Environment, this, spec.fid, core::rect<s32>(pos, pos + geom), name, m_font, m_client); - auto style = getStyleForElement("item_image", spec.fname); + auto style = getDefaultStyleForElement("item_image", spec.fname); e->setNotClipped(style.getBool(StyleSpec::NOCLIP, false)); // item images should let events through @@ -949,10 +949,11 @@ void GUIFormSpecMenu::parseButton(parserData* data, const std::string &element, if(type == "button_exit") spec.is_exit = true; - GUIButton *e = GUIButton::addButton(Environment, rect, this, spec.fid, spec.flabel.c_str()); + GUIButton *e = GUIButton::addButton(Environment, rect, m_tsrc, this, + spec.fid, spec.flabel.c_str()); auto style = getStyleForElement(type, name, (type != "button") ? "button" : ""); - e->setFromStyle(style, m_tsrc); + e->setStyles(style); if (spec.fname == data->focused_fieldname) { Environment->setFocus(e); @@ -1155,7 +1156,7 @@ void GUIFormSpecMenu::parseTable(parserData* data, const std::string &element) if (!str_initial_selection.empty() && str_initial_selection != "0") e->setSelected(stoi(str_initial_selection)); - auto style = getStyleForElement("table", name); + auto style = getDefaultStyleForElement("table", name); e->setNotClipped(style.getBool(StyleSpec::NOCLIP, false)); m_tables.emplace_back(spec, e); @@ -1231,7 +1232,7 @@ void GUIFormSpecMenu::parseTextList(parserData* data, const std::string &element if (!str_initial_selection.empty() && str_initial_selection != "0") e->setSelected(stoi(str_initial_selection)); - auto style = getStyleForElement("textlist", name); + auto style = getDefaultStyleForElement("textlist", name); e->setNotClipped(style.getBool(StyleSpec::NOCLIP, false)); m_tables.emplace_back(spec, e); @@ -1306,7 +1307,7 @@ void GUIFormSpecMenu::parseDropDown(parserData* data, const std::string &element if (!str_initial_selection.empty()) e->setSelected(stoi(str_initial_selection)-1); - auto style = getStyleForElement("dropdown", name); + auto style = getDefaultStyleForElement("dropdown", name); e->setNotClipped(style.getBool(StyleSpec::NOCLIP, false)); m_fields.push_back(spec); @@ -1394,7 +1395,7 @@ void GUIFormSpecMenu::parsePwdField(parserData* data, const std::string &element e->setPasswordBox(true,L'*'); - auto style = getStyleForElement("pwdfield", name, "field"); + auto style = getDefaultStyleForElement("pwdfield", name, "field"); e->setNotClipped(style.getBool(StyleSpec::NOCLIP, false)); e->setDrawBorder(style.getBool(StyleSpec::BORDER, true)); e->setOverrideColor(style.getColor(StyleSpec::TEXTCOLOR, video::SColor(0xFFFFFFFF))); @@ -1454,7 +1455,7 @@ void GUIFormSpecMenu::createTextField(parserData *data, FieldSpec &spec, } } - auto style = getStyleForElement(is_multiline ? "textarea" : "field", spec.fname); + auto style = getDefaultStyleForElement(is_multiline ? "textarea" : "field", spec.fname); if (e) { if (is_editable && spec.fname == data->focused_fieldname) @@ -1752,7 +1753,7 @@ void GUIFormSpecMenu::parseLabel(parserData* data, const std::string &element) spec.flabel.c_str(), rect, false, false, this, spec.fid); e->setTextAlignment(gui::EGUIA_UPPERLEFT, gui::EGUIA_CENTER); - auto style = getStyleForElement("label", spec.fname); + auto style = getDefaultStyleForElement("label", spec.fname); e->setNotClipped(style.getBool(StyleSpec::NOCLIP, false)); e->setOverrideColor(style.getColor(StyleSpec::TEXTCOLOR, video::SColor(0xFFFFFFFF))); @@ -1832,7 +1833,7 @@ void GUIFormSpecMenu::parseVertLabel(parserData* data, const std::string &elemen rect, false, false, this, spec.fid); e->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_CENTER); - auto style = getStyleForElement("vertlabel", spec.fname, "label"); + auto style = getDefaultStyleForElement("vertlabel", spec.fname, "label"); e->setNotClipped(style.getBool(StyleSpec::NOCLIP, false)); e->setOverrideColor(style.getColor(StyleSpec::TEXTCOLOR, video::SColor(0xFFFFFFFF))); @@ -1863,17 +1864,8 @@ void GUIFormSpecMenu::parseImageButton(parserData* data, const std::string &elem MY_CHECKPOS("imagebutton",0); MY_CHECKGEOM("imagebutton",1); - bool noclip = false; - bool drawborder = true; std::string pressed_image_name; - if (parts.size() >= 7) { - if (parts[5] == "true") - noclip = true; - if (parts[6] == "false") - drawborder = false; - } - if (parts.size() >= 8) { pressed_image_name = parts[7]; } @@ -1911,35 +1903,30 @@ void GUIFormSpecMenu::parseImageButton(parserData* data, const std::string &elem if (type == "image_button_exit") spec.is_exit = true; - GUIButtonImage *e = GUIButtonImage::addButton(Environment, rect, this, spec.fid, spec.flabel.c_str()); + GUIButtonImage *e = GUIButtonImage::addButton(Environment, rect, m_tsrc, + this, spec.fid, spec.flabel.c_str()); if (spec.fname == data->focused_fieldname) { Environment->setFocus(e); } auto style = getStyleForElement("image_button", spec.fname); - e->setFromStyle(style, m_tsrc); - // We explicitly handle these arguments *after* the style properties in - // order to override them if they are provided + // Override style properties with values specified directly in the element if (!image_name.empty()) - { - video::ITexture *texture = m_tsrc->getTexture(image_name); - e->setForegroundImage(guiScalingImageButton( - Environment->getVideoDriver(), texture, geom.X, geom.Y)); - } - if (!pressed_image_name.empty()) { - video::ITexture *pressed_texture = m_tsrc->getTexture(pressed_image_name); - e->setPressedForegroundImage(guiScalingImageButton( - Environment->getVideoDriver(), pressed_texture, geom.X, geom.Y)); - } - e->setScaleImage(true); + style[StyleSpec::STATE_DEFAULT].set(StyleSpec::FGIMG, image_name); + + if (!pressed_image_name.empty()) + style[StyleSpec::STATE_PRESSED].set(StyleSpec::FGIMG, pressed_image_name); if (parts.size() >= 7) { - e->setNotClipped(noclip); - e->setDrawBorder(drawborder); + style[StyleSpec::STATE_DEFAULT].set(StyleSpec::NOCLIP, parts[5]); + style[StyleSpec::STATE_DEFAULT].set(StyleSpec::BORDER, parts[6]); } + e->setStyles(style); + e->setScaleImage(true); + m_fields.push_back(spec); return; } @@ -2033,7 +2020,7 @@ void GUIFormSpecMenu::parseTabHeader(parserData* data, const std::string &elemen Environment->setFocus(e); } - auto style = getStyleForElement("tabheader", name); + auto style = getDefaultStyleForElement("tabheader", name); e->setNotClipped(style.getBool(StyleSpec::NOCLIP, true)); for (const std::string &button : buttons) { @@ -2118,10 +2105,12 @@ void GUIFormSpecMenu::parseItemImageButton(parserData* data, const std::string & 2 ); - GUIButtonItemImage *e_btn = GUIButtonItemImage::addButton(Environment, rect, this, spec_btn.fid, spec_btn.flabel.c_str(), item_name, m_client); + GUIButtonItemImage *e_btn = GUIButtonItemImage::addButton(Environment, + rect, m_tsrc, this, spec_btn.fid, spec_btn.flabel.c_str(), + item_name, m_client); auto style = getStyleForElement("item_image_button", spec_btn.fname, "image_button"); - e_btn->setFromStyle(style, m_tsrc); + e_btn->setStyles(style); if (spec_btn.fname == data->focused_fieldname) { Environment->setFocus(e_btn); @@ -2177,7 +2166,7 @@ void GUIFormSpecMenu::parseBox(parserData* data, const std::string &element) GUIBox *e = new GUIBox(Environment, this, spec.fid, rect, tmp_color); - auto style = getStyleForElement("box", spec.fname); + auto style = getDefaultStyleForElement("box", spec.fname); e->setNotClipped(style.getBool(StyleSpec::NOCLIP, m_formspec_version < 3)); e->drop(); @@ -2469,6 +2458,7 @@ bool GUIFormSpecMenu::parseStyle(parserData *data, const std::string &element, b StyleSpec spec; + // Parse properties for (size_t i = 1; i < parts.size(); i++) { size_t equal_pos = parts[i].find('='); if (equal_pos == std::string::npos) { @@ -2500,16 +2490,92 @@ bool GUIFormSpecMenu::parseStyle(parserData *data, const std::string &element, b for (size_t sel = 0; sel < selectors.size(); sel++) { std::string selector = trim(selectors[sel]); - if (selector.empty()) { - errorstream << "Invalid style element (Empty selector): '" << element - << "'" << std::endl; + // Copy the style properties to a new StyleSpec + // This allows a separate state mask per-selector + StyleSpec selector_spec = spec; + + // Parse state information, if it exists + bool state_valid = true; + size_t state_pos = selector.find(':'); + if (state_pos != std::string::npos) { + std::string state_str = selector.substr(state_pos + 1); + selector = selector.substr(0, state_pos); + + if (state_str.empty()) { + errorstream << "Invalid style element (Invalid state): '" << element + << "'" << std::endl; + state_valid = false; + } else { + std::vector<std::string> states = split(state_str, '+'); + for (std::string &state : states) { + StyleSpec::State converted = StyleSpec::getStateByName(state); + if (converted == StyleSpec::STATE_INVALID) { + infostream << "Unknown style state " << state << + " in element '" << element << "'" << std::endl; + state_valid = false; + break; + } + + selector_spec.addState(converted); + } + } + } + + if(!state_valid) { + // Skip this selector continue; } if (style_type) { - theme_by_type[selector] |= spec; + theme_by_type[selector].push_back(selector_spec); } else { - theme_by_name[selector] |= spec; + theme_by_name[selector].push_back(selector_spec); + } + + // Backwards-compatibility for existing _hovered/_pressed properties + if (selector_spec.hasProperty(StyleSpec::BGCOLOR_HOVERED) + || selector_spec.hasProperty(StyleSpec::BGIMG_HOVERED) + || selector_spec.hasProperty(StyleSpec::FGIMG_HOVERED)) { + StyleSpec hover_spec; + hover_spec.addState(StyleSpec::STATE_HOVERED); + + if (selector_spec.hasProperty(StyleSpec::BGCOLOR_HOVERED)) { + hover_spec.set(StyleSpec::BGCOLOR, selector_spec.get(StyleSpec::BGCOLOR_HOVERED, "")); + } + if (selector_spec.hasProperty(StyleSpec::BGIMG_HOVERED)) { + hover_spec.set(StyleSpec::BGIMG, selector_spec.get(StyleSpec::BGIMG_HOVERED, "")); + } + if (selector_spec.hasProperty(StyleSpec::FGIMG_HOVERED)) { + hover_spec.set(StyleSpec::FGIMG, selector_spec.get(StyleSpec::FGIMG_HOVERED, "")); + } + + if (style_type) { + theme_by_type[selector].push_back(hover_spec); + } else { + theme_by_name[selector].push_back(hover_spec); + } + } + if (selector_spec.hasProperty(StyleSpec::BGCOLOR_PRESSED) + || selector_spec.hasProperty(StyleSpec::BGIMG_PRESSED) + || selector_spec.hasProperty(StyleSpec::FGIMG_PRESSED)) { + StyleSpec press_spec; + press_spec.addState(StyleSpec::STATE_PRESSED); + + if (selector_spec.hasProperty(StyleSpec::BGCOLOR_PRESSED)) { + press_spec.set(StyleSpec::BGCOLOR, selector_spec.get(StyleSpec::BGCOLOR_PRESSED, "")); + } + if (selector_spec.hasProperty(StyleSpec::BGIMG_PRESSED)) { + press_spec.set(StyleSpec::BGIMG, selector_spec.get(StyleSpec::BGIMG_PRESSED, "")); + } + if (selector_spec.hasProperty(StyleSpec::FGIMG_PRESSED)) { + press_spec.set(StyleSpec::FGIMG, selector_spec.get(StyleSpec::FGIMG_PRESSED, "")); + } + + if (style_type) { + theme_by_type[selector].push_back(press_spec); + } else { + theme_by_name[selector].push_back(press_spec); + } } } @@ -3080,7 +3146,7 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize) size.X / 2 - 70 + 140, pos.Y + m_btn_height * 2 ); const wchar_t *text = wgettext("Proceed"); - GUIButton::addButton(Environment, mydata.rect, this, 257, text); + GUIButton::addButton(Environment, mydata.rect, m_tsrc, this, 257, text); delete[] text; } } @@ -4432,25 +4498,34 @@ std::wstring GUIFormSpecMenu::getLabelByID(s32 id) return L""; } -StyleSpec GUIFormSpecMenu::getStyleForElement(const std::string &type, +StyleSpec GUIFormSpecMenu::getDefaultStyleForElement(const std::string &type, const std::string &name, const std::string &parent_type) { - StyleSpec ret; + return getStyleForElement(type, name, parent_type)[StyleSpec::STATE_DEFAULT]; +} + +std::array<StyleSpec, StyleSpec::NUM_STATES> GUIFormSpecMenu::getStyleForElement(const std::string &type, + const std::string &name, const std::string &parent_type) +{ + std::array<StyleSpec, StyleSpec::NUM_STATES> ret; if (!parent_type.empty()) { auto it = theme_by_type.find(parent_type); if (it != theme_by_type.end()) { - ret |= it->second; + for (const StyleSpec &spec : it->second) + ret[(u32)spec.getState()] |= spec; } } auto it = theme_by_type.find(type); if (it != theme_by_type.end()) { - ret |= it->second; + for (const StyleSpec &spec : it->second) + ret[(u32)spec.getState()] |= spec; } it = theme_by_name.find(name); if (it != theme_by_name.end()) { - ret |= it->second; + for (const StyleSpec &spec : it->second) + ret[(u32)spec.getState()] |= spec; } return ret; diff --git a/src/gui/guiFormSpecMenu.h b/src/gui/guiFormSpecMenu.h index 17bfef205..b3bf67110 100644 --- a/src/gui/guiFormSpecMenu.h +++ b/src/gui/guiFormSpecMenu.h @@ -274,11 +274,13 @@ protected: v2s32 getRealCoordinateBasePos(const std::vector<std::string> &v_pos); v2s32 getRealCoordinateGeometry(const std::vector<std::string> &v_geom); - std::unordered_map<std::string, StyleSpec> theme_by_type; - std::unordered_map<std::string, StyleSpec> theme_by_name; + std::unordered_map<std::string, std::vector<StyleSpec>> theme_by_type; + std::unordered_map<std::string, std::vector<StyleSpec>> theme_by_name; std::unordered_set<std::string> property_warned; - StyleSpec getStyleForElement(const std::string &type, + StyleSpec getDefaultStyleForElement(const std::string &type, + const std::string &name="", const std::string &parent_type=""); + std::array<StyleSpec, StyleSpec::NUM_STATES> getStyleForElement(const std::string &type, const std::string &name="", const std::string &parent_type=""); v2s32 padding; diff --git a/src/gui/guiKeyChangeMenu.cpp b/src/gui/guiKeyChangeMenu.cpp index 3f270fc7a..da0e25c23 100644 --- a/src/gui/guiKeyChangeMenu.cpp +++ b/src/gui/guiKeyChangeMenu.cpp @@ -82,8 +82,10 @@ enum }; GUIKeyChangeMenu::GUIKeyChangeMenu(gui::IGUIEnvironment* env, - gui::IGUIElement* parent, s32 id, IMenuManager *menumgr) : -GUIModalMenu(env, parent, id, menumgr) + gui::IGUIElement* parent, s32 id, IMenuManager *menumgr, + ISimpleTextureSource *tsrc) : + GUIModalMenu(env, parent, id, menumgr), + m_tsrc(tsrc) { init_keys(); } @@ -157,7 +159,7 @@ void GUIKeyChangeMenu::regenerateGui(v2u32 screensize) core::rect<s32> rect(0, 0, 100 * s, 30 * s); rect += topleft + v2s32(offset.X + 150 * s, offset.Y - 5 * s); const wchar_t *text = wgettext(k->key.name()); - k->button = GUIButton::addButton(Environment, rect, this, k->id, text); + k->button = GUIButton::addButton(Environment, rect, m_tsrc, this, k->id, text); delete[] text; } if ((i + 1) % KMaxButtonPerColumns == 0) { @@ -217,14 +219,14 @@ void GUIKeyChangeMenu::regenerateGui(v2u32 screensize) core::rect<s32> rect(0, 0, 100 * s, 30 * s); rect += topleft + v2s32(size.X / 2 - 105 * s, size.Y - 40 * s); const wchar_t *text = wgettext("Save"); - GUIButton::addButton(Environment, rect, this, GUI_ID_BACK_BUTTON, text); + GUIButton::addButton(Environment, rect, m_tsrc, this, GUI_ID_BACK_BUTTON, text); delete[] text; } { core::rect<s32> rect(0, 0, 100 * s, 30 * s); rect += topleft + v2s32(size.X / 2 + 5 * s, size.Y - 40 * s); const wchar_t *text = wgettext("Cancel"); - GUIButton::addButton(Environment, rect, this, GUI_ID_ABORT_BUTTON, text); + GUIButton::addButton(Environment, rect, m_tsrc, this, GUI_ID_ABORT_BUTTON, text); delete[] text; } } diff --git a/src/gui/guiKeyChangeMenu.h b/src/gui/guiKeyChangeMenu.h index 528827fd9..1c0f40247 100644 --- a/src/gui/guiKeyChangeMenu.h +++ b/src/gui/guiKeyChangeMenu.h @@ -28,6 +28,8 @@ #include <string> #include <vector> +class ISimpleTextureSource; + struct key_setting { int id; @@ -41,7 +43,7 @@ class GUIKeyChangeMenu : public GUIModalMenu { public: GUIKeyChangeMenu(gui::IGUIEnvironment *env, gui::IGUIElement *parent, s32 id, - IMenuManager *menumgr); + IMenuManager *menumgr, ISimpleTextureSource *tsrc); ~GUIKeyChangeMenu(); void removeChildren(); @@ -74,4 +76,5 @@ private: key_setting *active_key = nullptr; gui::IGUIStaticText *key_used_text = nullptr; std::vector<key_setting *> key_settings; + ISimpleTextureSource *m_tsrc; }; diff --git a/src/gui/guiPasswordChange.cpp b/src/gui/guiPasswordChange.cpp index af91ce84c..965a2d6f7 100644 --- a/src/gui/guiPasswordChange.cpp +++ b/src/gui/guiPasswordChange.cpp @@ -38,10 +38,12 @@ const int ID_cancel = 261; GUIPasswordChange::GUIPasswordChange(gui::IGUIEnvironment* env, gui::IGUIElement* parent, s32 id, IMenuManager *menumgr, - Client* client + Client* client, + ISimpleTextureSource *tsrc ): GUIModalMenu(env, parent, id, menumgr), - m_client(client) + m_client(client), + m_tsrc(tsrc) { } @@ -146,14 +148,14 @@ void GUIPasswordChange::regenerateGui(v2u32 screensize) core::rect<s32> rect(0, 0, 100 * s, 30 * s); rect = rect + v2s32(size.X / 4 + 56 * s, ypos); text = wgettext("Change"); - GUIButton::addButton(Environment, rect, this, ID_change, text); + GUIButton::addButton(Environment, rect, m_tsrc, this, ID_change, text); delete[] text; } { core::rect<s32> rect(0, 0, 100 * s, 30 * s); rect = rect + v2s32(size.X / 4 + 185 * s, ypos); text = wgettext("Cancel"); - GUIButton::addButton(Environment, rect, this, ID_cancel, text); + GUIButton::addButton(Environment, rect, m_tsrc, this, ID_cancel, text); delete[] text; } diff --git a/src/gui/guiPasswordChange.h b/src/gui/guiPasswordChange.h index 58541a399..7141100c0 100644 --- a/src/gui/guiPasswordChange.h +++ b/src/gui/guiPasswordChange.h @@ -23,12 +23,14 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include <string> class Client; +class ISimpleTextureSource; class GUIPasswordChange : public GUIModalMenu { public: GUIPasswordChange(gui::IGUIEnvironment *env, gui::IGUIElement *parent, s32 id, - IMenuManager *menumgr, Client *client); + IMenuManager *menumgr, Client *client, + ISimpleTextureSource *tsrc); ~GUIPasswordChange(); void removeChildren(); @@ -57,4 +59,5 @@ private: std::wstring m_oldpass = L""; std::wstring m_newpass = L""; std::wstring m_newpass_confirm = L""; + ISimpleTextureSource *m_tsrc; }; diff --git a/src/gui/guiVolumeChange.cpp b/src/gui/guiVolumeChange.cpp index 9428cde83..07b11248c 100644 --- a/src/gui/guiVolumeChange.cpp +++ b/src/gui/guiVolumeChange.cpp @@ -38,9 +38,10 @@ const int ID_soundMuteButton = 266; GUIVolumeChange::GUIVolumeChange(gui::IGUIEnvironment* env, gui::IGUIElement* parent, s32 id, - IMenuManager *menumgr + IMenuManager *menumgr, ISimpleTextureSource *tsrc ): - GUIModalMenu(env, parent, id, menumgr) + GUIModalMenu(env, parent, id, menumgr), + m_tsrc(tsrc) { } @@ -104,7 +105,7 @@ void GUIVolumeChange::regenerateGui(v2u32 screensize) core::rect<s32> rect(0, 0, 80 * s, 30 * s); rect = rect + v2s32(size.X / 2 - 80 * s / 2, size.Y / 2 + 55 * s); const wchar_t *text = wgettext("Exit"); - GUIButton::addButton(Environment, rect, this, ID_soundExitButton, text); + GUIButton::addButton(Environment, rect, m_tsrc, this, ID_soundExitButton, text); delete[] text; } { diff --git a/src/gui/guiVolumeChange.h b/src/gui/guiVolumeChange.h index f4f4e9eea..466e17f9d 100644 --- a/src/gui/guiVolumeChange.h +++ b/src/gui/guiVolumeChange.h @@ -23,12 +23,14 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "modalMenu.h" #include <string> +class ISimpleTextureSource; + class GUIVolumeChange : public GUIModalMenu { public: GUIVolumeChange(gui::IGUIEnvironment* env, gui::IGUIElement* parent, s32 id, - IMenuManager *menumgr); + IMenuManager *menumgr, ISimpleTextureSource *tsrc); ~GUIVolumeChange(); void removeChildren(); @@ -46,4 +48,7 @@ public: protected: std::wstring getLabelByID(s32 id) { return L""; } std::string getNameByID(s32 id) { return ""; } + +private: + ISimpleTextureSource *m_tsrc; }; diff --git a/src/script/lua_api/l_mainmenu.cpp b/src/script/lua_api/l_mainmenu.cpp index 76db7ed13..867e84e13 100644 --- a/src/script/lua_api/l_mainmenu.cpp +++ b/src/script/lua_api/l_mainmenu.cpp @@ -571,9 +571,10 @@ int ModApiMainMenu::l_show_keys_menu(lua_State *L) sanity_check(engine != NULL); GUIKeyChangeMenu *kmenu = new GUIKeyChangeMenu(RenderingEngine::get_gui_env(), - engine->m_parent, - -1, - engine->m_menumanager); + engine->m_parent, + -1, + engine->m_menumanager, + engine->m_texture_source); kmenu->drop(); return 0; } @@ -904,12 +905,12 @@ int ModApiMainMenu::l_show_path_select_dialog(lua_State *L) GUIFileSelectMenu* fileOpenMenu = new GUIFileSelectMenu(RenderingEngine::get_gui_env(), - engine->m_parent, - -1, - engine->m_menumanager, - title, - formname, - is_file_select); + engine->m_parent, + -1, + engine->m_menumanager, + title, + formname, + is_file_select); fileOpenMenu->setTextDest(engine->m_buttonhandler); fileOpenMenu->drop(); return 0; diff --git a/src/util/numeric.h b/src/util/numeric.h index 6f82a18c1..864ab7543 100644 --- a/src/util/numeric.h +++ b/src/util/numeric.h @@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "irr_v2d.h" #include "irr_v3d.h" #include "irr_aabb3d.h" +#include "SColor.h" #include <matrix4.h> #define rangelim(d, min, max) ((d) < (min) ? (min) : ((d) > (max) ? (max) : (d))) @@ -432,3 +433,12 @@ inline v3f getPitchYawRoll(const core::matrix4 &m) { return getPitchYawRollRad(m) * core::RADTODEG64; } + +// Muliply the RGB value of a color linearly, and clamp to black/white +inline irr::video::SColor multiplyColorValue(const irr::video::SColor &color, float mod) +{ + return irr::video::SColor(color.getAlpha(), + core::clamp<u32>(color.getRed() * mod, 0, 255), + core::clamp<u32>(color.getGreen() * mod, 0, 255), + core::clamp<u32>(color.getBlue() * mod, 0, 255)); +} |