Formspecs: Add state-selection to style elements (#9378)
authorHugues Ross <hugues.ross@gmail.com>
Sat, 11 Apr 2020 20:39:30 +0000 (16:39 -0400)
committerGitHub <noreply@github.com>
Sat, 11 Apr 2020 20:39:30 +0000 (21:39 +0100)
22 files changed:
doc/lua_api.txt
games/minimal/mods/test/formspec.lua
src/client/game.cpp
src/gui/StyleSpec.h
src/gui/guiButton.cpp
src/gui/guiButton.h
src/gui/guiButtonImage.cpp
src/gui/guiButtonImage.h
src/gui/guiButtonItemImage.cpp
src/gui/guiButtonItemImage.h
src/gui/guiConfirmRegistration.cpp
src/gui/guiConfirmRegistration.h
src/gui/guiFormSpecMenu.cpp
src/gui/guiFormSpecMenu.h
src/gui/guiKeyChangeMenu.cpp
src/gui/guiKeyChangeMenu.h
src/gui/guiPasswordChange.cpp
src/gui/guiPasswordChange.h
src/gui/guiVolumeChange.cpp
src/gui/guiVolumeChange.h
src/script/lua_api/l_mainmenu.cpp
src/util/numeric.h

index 6ba87d61922e7815c43d8f0ee6cc16b5206972ce..b083b290770709d1647516fd39c00952e2f0bc26 100644 (file)
@@ -2188,12 +2188,12 @@ Elements
 
 * 9-sliced background. See https://en.wikipedia.org/wiki/9-slice_scaling
 * Middle is a rect which defines the middle of the 9-slice.
-       * `x` - The middle will be x pixels from all sides.
-       * `x,y` - The middle will be x pixels from the horizontal and y from the vertical.
-       * `x,y,x2,y2` - The middle will start at x,y, and end at x2, y2. Negative x2 and y2 values
-               will be added to the width and height of the texture, allowing it to be used as the
-               distance from the far end.
-       * All numbers in middle are integers.
+    * `x` - The middle will be x pixels from all sides.
+    * `x,y` - The middle will be x pixels from the horizontal and y from the vertical.
+    * `x,y,x2,y2` - The middle will start at x,y, and end at x2, y2. Negative x2 and y2 values
+        will be added to the width and height of the texture, allowing it to be used as the
+        distance from the far end.
+    * All numbers in middle are integers.
 * Example for formspec 8x4 in 16x resolution:
   image shall be sized 8 times 16px  times  4 times 16px
 * If `auto_clip` is `true`, the background is clipped to the formspec size
@@ -2508,16 +2508,28 @@ Elements
         * `span=<value>`: number of following columns to affect
           (default: infinite).
 
-### `style[<name 1>,<name 2>,...;<prop1>;<prop2>;...]`
+### `style[<selector 1>,<selector 2>;<prop1>;<prop2>;...]`
 
-* Set the style for the named element(s) `name`.
+* Set the style for the element(s) matching `selector` by name.
+* `selector` can be one of:
+    * `<name>` - An element name.
+    * `<name>:<state>` - An element name, a colon, and one or more states.
+* `state` is a list of states separated by the `+` character.
+    * If a state is provided, the style will only take effect when the element is in that state.
+    * All provided states must be active for the style to apply.
 * Note: this **must** be before the element is defined.
 * See [Styling Formspecs].
 
 
-### `style_type[<type 1>,<type 2>,...;<prop1>;<prop2>;...]`
+### `style_type[<selector 1>,<selector 2>;<prop1>;<prop2>;...]`
 
-* Sets the style for all elements of type(s) `type` which appear after this element.
+* Set the style for the element(s) matching `selector` by type.
+* `selector` can be one of:
+    * `<type>` - An element type.
+    * `<type>:<state>` - An element type, a colon, and one or more states.
+* `state` is a list of states separated by the `+` character.
+    * If a state is provided, the style will only take effect when the element is in that state.
+    * All provided states must be active for the style to apply.
 * See [Styling Formspecs].
 
 Migrating to Real Coordinates
@@ -2560,23 +2572,32 @@ Styling Formspecs
 
 Formspec elements can be themed using the style elements:
 
-    style[<name 1>,<name 2>,...;<prop1>;<prop2>;...]
-    style_type[<type 1>,<type 2>,...;<prop1>;<prop2>;...]
+    style[<name 1>,<name 2>;<prop1>;<prop2>;...]
+    style[<name 1>:<state>,<name 2>:<state>;<prop1>;<prop2>;...]
+    style_type[<type 1>,<type 2>;<prop1>;<prop2>;...]
+    style_type[<type 1>:<state>,<type 2>:<state>;<prop1>;<prop2>;...]
 
 Where a prop is:
 
     property_name=property_value
 
+For example:
+
+    style_type[button;bgcolor=#006699]
+    style[world_delete;bgcolor=red;textcolor=yellow]
+    button[4,3.95;2.6,1;world_delete;Delete]
+
 A name/type can optionally be a comma separated list of names/types, like so:
 
     world_delete,world_create,world_configure
     button,image_button
 
-For example:
+Any name/type in the list can also be accompanied by a `+`-separated list of states, like so:
 
-    style_type[button;bgcolor=#006699]
-    style[world_delete;bgcolor=red;textcolor=yellow]
-    button[4,3.95;2.6,1;world_delete;Delete]
+    world_delete:hovered+pressed
+    button:pressed
+
+States allow you to apply styles in response to changes in the element, instead of applying at all times.
 
 Setting a property to nothing will reset it to the default value. For example:
 
@@ -2654,6 +2675,14 @@ Some types may inherit styles from parent types.
     * noclip - boolean, set to true to allow the element to exceed formspec bounds.
     * textcolor - color. Default white.
 
+### Valid States
+
+* *all elements*
+    * default - Equivalent to providing no states
+* button, button_exit, image_button, item_image_button
+    * hovered - Active when the mouse is hovering over the element
+    * pressed - Active when the button is pressed
+
 Markup Language
 ---------------
 
index d2123b4afcf7291b9dd7a8e4012953b6e6a0b436..14886aad2e8c1bb76bbd5f4bbfb4a5da7c9b7c6f 100644 (file)
@@ -65,7 +65,10 @@ local style_fs = [[
        style[one_btn13;border=false]\r
        item_image_button[1.25,8.35;1,1;default:sword_steel;one_btn13;NoBor]\r
 \r
-       style[one_btn14;border=false;bgimg=test_bg.png;bgimg_hovered=test_bg_hovered.png;bgimg_pressed=test_bg_pressed.png;fgimg=bubble.png;fgimg_hovered=default_apple.png;fgimg_pressed=heart.png]\r
+       style[one_btn14;border=false;bgimg=test_bg.png;fgimg=bubble.png]\r
+       style[one_btn14:hovered;bgimg=test_bg_hovered.png;fgimg=default_apple.png;textcolor=red]\r
+       style[one_btn14:pressed;bgimg=test_bg_pressed.png;fgimg=heart.png;textcolor=green]\r
+       style[one_btn14:hovered+pressed;textcolor=blue]\r
        image_button[0,9.6;1,1;bubble.png;one_btn14;Bg]\r
 \r
        style[one_btn15;border=false;bgimg=test_bg.png;bgimg_hovered=test_bg_hovered.png;bgimg_pressed=test_bg_pressed.png]\r
index 505108caf472a457562a1e990a5bf813888705d8..06e76d1705142ce193eec563d76eed306c4c913c 100644 (file)
@@ -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;
        }
 
index 999c1d2379d6b196de6643dd3d8317cb7e6a00b2..799fbf46d5a8141696ad802d35c61fceac64e6e4 100644 (file)
@@ -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];
index 4c16ee2376a79a189b81b3e9aa8571c666c8dcd6..9dfe36bc4b94d544637b753f711887824d3719a4 100644 (file)
@@ -14,6 +14,7 @@
 #include "irrlicht_changes/static_text.h"\r
 #include "porting.h"\r
 #include "StyleSpec.h"\r
+#include "util/numeric.h"\r
 \r
 using namespace irr;\r
 using namespace gui;\r
@@ -26,14 +27,15 @@ using namespace gui;
 \r
 //! constructor\r
 GUIButton::GUIButton(IGUIEnvironment* environment, IGUIElement* parent,\r
-                       s32 id, core::rect<s32> rectangle, bool noclip)\r
+                       s32 id, core::rect<s32> rectangle, ISimpleTextureSource *tsrc,\r
+                       bool noclip)\r
 : IGUIButton(environment, parent, id, rectangle),\r
        SpriteBank(0), OverrideFont(0),\r
        OverrideColorEnabled(false), OverrideColor(video::SColor(101,255,255,255)),\r
        ClickTime(0), HoverTime(0), FocusTime(0),\r
        ClickShiftState(false), ClickControlState(false),\r
        IsPushButton(false), Pressed(false),\r
-       UseAlphaChannel(false), DrawBorder(true), ScaleImage(false)\r
+       UseAlphaChannel(false), DrawBorder(true), ScaleImage(false), TSrc(tsrc)\r
 {\r
        setNotClipped(noclip);\r
 \r
@@ -44,14 +46,6 @@ GUIButton::GUIButton(IGUIEnvironment* environment, IGUIElement* parent,
        // PATCH\r
        for (size_t i = 0; i < 4; i++) {\r
                Colors[i] = Environment->getSkin()->getColor((EGUI_DEFAULT_COLOR)i);\r
-               HoveredColors[i] = irr::video::SColor(Colors[i].getAlpha(),\r
-                       core::clamp<u32>(Colors[i].getRed() * COLOR_HOVERED_MOD, 0, 255),\r
-                       core::clamp<u32>(Colors[i].getGreen() * COLOR_HOVERED_MOD, 0, 255),\r
-                       core::clamp<u32>(Colors[i].getBlue() * COLOR_HOVERED_MOD, 0, 255));\r
-               PressedColors[i] = irr::video::SColor(Colors[i].getAlpha(),\r
-                       core::clamp<u32>(Colors[i].getRed() * COLOR_PRESSED_MOD, 0, 255),\r
-                       core::clamp<u32>(Colors[i].getGreen() * COLOR_PRESSED_MOD, 0, 255),\r
-                       core::clamp<u32>(Colors[i].getBlue() * COLOR_PRESSED_MOD, 0, 255));\r
        }\r
        StaticText = gui::StaticText::add(Environment, Text.c_str(), core::rect<s32>(0,0,rectangle.getWidth(),rectangle.getHeight()), false, false, this, id);\r
        StaticText->setTextAlignment(EGUIA_CENTER, EGUIA_CENTER);\r
@@ -262,6 +256,13 @@ void GUIButton::draw()
                return;\r
 \r
        // PATCH\r
+       // Track hovered state, if it has changed then we need to update the style.\r
+       bool hovered = isHovered();\r
+       if (hovered != WasHovered) {\r
+               WasHovered = hovered;\r
+               setFromState();\r
+       }\r
+\r
        GUISkin* skin = dynamic_cast<GUISkin*>(Environment->getSkin());\r
        video::IVideoDriver* driver = Environment->getVideoDriver();\r
        // END PATCH\r
@@ -271,21 +272,24 @@ void GUIButton::draw()
                if (!Pressed)\r
                {\r
                        // PATCH\r
-                       skin->drawColored3DButtonPaneStandard(this, AbsoluteRect, &AbsoluteClippingRect,\r
-                               isHovered() ? HoveredColors : Colors);\r
+                       skin->drawColored3DButtonPaneStandard(this, AbsoluteRect,\r
+                                       &AbsoluteClippingRect, Colors);\r
                        // END PATCH\r
                }\r
                else\r
                {\r
                        // PATCH\r
-                       skin->drawColored3DButtonPanePressed(this,\r
-                                       AbsoluteRect, &AbsoluteClippingRect, PressedColors);\r
+                       skin->drawColored3DButtonPanePressed(this, AbsoluteRect,\r
+                                       &AbsoluteClippingRect, Colors);\r
                        // END PATCH\r
                }\r
        }\r
 \r
        const core::position2di buttonCenter(AbsoluteRect.getCenter());\r
-       EGUI_BUTTON_IMAGE_STATE imageState = getImageState(Pressed);\r
+       // PATCH\r
+       // The image changes based on the state, so we use the default every time.\r
+       EGUI_BUTTON_IMAGE_STATE imageState = EGBIS_IMAGE_UP;\r
+       // END PATCH\r
        if ( ButtonImages[(u32)imageState].Texture )\r
        {\r
                core::position2d<s32> pos(buttonCenter);\r
@@ -548,18 +552,6 @@ void GUIButton::setPressedImage(video::ITexture* image, const core::rect<s32>& p
        setImage(gui::EGBIS_IMAGE_DOWN, image, pos);\r
 }\r
 \r
-void GUIButton::setHoveredImage(video::ITexture* image)\r
-{\r
-       setImage(gui::EGBIS_IMAGE_UP_MOUSEOVER, image);\r
-       setImage(gui::EGBIS_IMAGE_UP_FOCUSED_MOUSEOVER, image);\r
-}\r
-\r
-void GUIButton::setHoveredImage(video::ITexture* image, const core::rect<s32>& pos)\r
-{\r
-       setImage(gui::EGBIS_IMAGE_UP_MOUSEOVER, image, pos);\r
-       setImage(gui::EGBIS_IMAGE_UP_FOCUSED_MOUSEOVER, image, pos);\r
-}\r
-\r
 //! Sets the text displayed by the button\r
 void GUIButton::setText(const wchar_t* text)\r
 {\r
@@ -618,6 +610,8 @@ void GUIButton::setPressed(bool pressed)
                                                        skin->getSize(irr::gui::EGDS_BUTTON_PRESSED_IMAGE_OFFSET_Y)));\r
                        }\r
                }\r
+\r
+               setFromState();\r
        }\r
 }\r
 \r
@@ -729,10 +723,12 @@ void GUIButton::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWri
 }\r
 \r
 // PATCH\r
-GUIButton* GUIButton::addButton(IGUIEnvironment *environment, const core::rect<s32>& rectangle,\r
-                                                               IGUIElement* parent, s32 id, const wchar_t* text, const wchar_t *tooltiptext)\r
+GUIButton* GUIButton::addButton(IGUIEnvironment *environment,\r
+               const core::rect<s32>& rectangle, ISimpleTextureSource *tsrc,\r
+               IGUIElement* parent, s32 id, const wchar_t* text,\r
+               const wchar_t *tooltiptext)\r
 {\r
-       GUIButton* button = new GUIButton(environment, parent ? parent : environment->getRootGUIElement(), id, rectangle);\r
+       GUIButton* button = new GUIButton(environment, parent ? parent : environment->getRootGUIElement(), id, rectangle, tsrc);\r
        if (text)\r
                button->setText(text);\r
 \r
@@ -749,76 +745,87 @@ void GUIButton::setColor(video::SColor color)
        for (size_t i = 0; i < 4; i++) {\r
                video::SColor base = Environment->getSkin()->getColor((gui::EGUI_DEFAULT_COLOR)i);\r
                Colors[i] = base.getInterpolated(color, d);\r
-               HoveredColors[i] = irr::video::SColor(Colors[i].getAlpha(),\r
-                       core::clamp<u32>(Colors[i].getRed() * COLOR_HOVERED_MOD, 0, 255),\r
-                       core::clamp<u32>(Colors[i].getGreen() * COLOR_HOVERED_MOD, 0, 255),\r
-                       core::clamp<u32>(Colors[i].getBlue() * COLOR_HOVERED_MOD, 0, 255));\r
-               PressedColors[i] = irr::video::SColor(Colors[i].getAlpha(),\r
-                       core::clamp<u32>(Colors[i].getRed() * COLOR_PRESSED_MOD, 0, 255),\r
-                       core::clamp<u32>(Colors[i].getGreen() * COLOR_PRESSED_MOD, 0, 255),\r
-                       core::clamp<u32>(Colors[i].getBlue() * COLOR_PRESSED_MOD, 0, 255));\r
        }\r
 }\r
-void GUIButton::setHoveredColor(video::SColor color)\r
-{\r
-       float d = 0.65f;\r
-       for (size_t i = 0; i < 4; i++) {\r
-               video::SColor base = Environment->getSkin()->getColor((gui::EGUI_DEFAULT_COLOR)i);\r
-               HoveredColors[i] = base.getInterpolated(color, d);\r
-       }\r
-}\r
-void GUIButton::setPressedColor(video::SColor color)\r
+\r
+//! Set element properties from a StyleSpec corresponding to the button state\r
+void GUIButton::setFromState()\r
 {\r
-       float d = 0.65f;\r
-       for (size_t i = 0; i < 4; i++) {\r
-               video::SColor base = Environment->getSkin()->getColor((gui::EGUI_DEFAULT_COLOR)i);\r
-               PressedColors[i] = base.getInterpolated(color, d);\r
-       }\r
+       StyleSpec::State state = StyleSpec::STATE_DEFAULT;\r
+\r
+       if (isPressed())\r
+               state = static_cast<StyleSpec::State>(state | StyleSpec::STATE_PRESSED);\r
+\r
+       if (isHovered())\r
+               state = static_cast<StyleSpec::State>(state | StyleSpec::STATE_HOVERED);\r
+\r
+       setFromStyle(StyleSpec::getStyleFromStatePropagation(Styles, state));\r
 }\r
 \r
 //! Set element properties from a StyleSpec\r
-void GUIButton::setFromStyle(const StyleSpec& style, ISimpleTextureSource *tsrc)\r
+void GUIButton::setFromStyle(const StyleSpec& style)\r
 {\r
+       bool hovered = (style.getState() & StyleSpec::STATE_HOVERED) != 0;\r
+       bool pressed = (style.getState() & StyleSpec::STATE_PRESSED) != 0;\r
+\r
        if (style.isNotDefault(StyleSpec::BGCOLOR)) {\r
+\r
                setColor(style.getColor(StyleSpec::BGCOLOR));\r
-       }\r
-       if (style.isNotDefault(StyleSpec::BGCOLOR_HOVERED)) {\r
-               setHoveredColor(style.getColor(StyleSpec::BGCOLOR_HOVERED));\r
-       }\r
-       if (style.isNotDefault(StyleSpec::BGCOLOR_PRESSED)) {\r
-               setPressedColor(style.getColor(StyleSpec::BGCOLOR_PRESSED));\r
+\r
+               // If we have a propagated hover/press color, we need to automatically\r
+               // lighten/darken it\r
+               if (!Styles[style.getState()].isNotDefault(StyleSpec::BGCOLOR)) {\r
+                       for (size_t i = 0; i < 4; i++) {\r
+                               if (pressed) {\r
+                                       Colors[i] = multiplyColorValue(Colors[i], COLOR_PRESSED_MOD);\r
+                               } else if (hovered) {\r
+                                       Colors[i] = multiplyColorValue(Colors[i], COLOR_HOVERED_MOD);\r
+                               }\r
+                       }\r
+               }\r
+\r
+       } else {\r
+               for (size_t i = 0; i < 4; i++) {\r
+                       video::SColor base =\r
+                                       Environment->getSkin()->getColor((gui::EGUI_DEFAULT_COLOR)i);\r
+                       if (pressed) {\r
+                               Colors[i] = multiplyColorValue(base, COLOR_PRESSED_MOD);\r
+                       } else if (hovered) {\r
+                               Colors[i] = multiplyColorValue(base, COLOR_HOVERED_MOD);\r
+                       } else {\r
+                               Colors[i] = base;\r
+                       }\r
+               }\r
        }\r
 \r
        if (style.isNotDefault(StyleSpec::TEXTCOLOR)) {\r
                setOverrideColor(style.getColor(StyleSpec::TEXTCOLOR));\r
+       } else {\r
+               setOverrideColor(video::SColor(255,255,255,255));\r
+               OverrideColorEnabled = false;\r
        }\r
-       setNotClipped(style.getBool(StyleSpec::NOCLIP, isNotClipped()));\r
-       setDrawBorder(style.getBool(StyleSpec::BORDER, DrawBorder));\r
+       setNotClipped(style.getBool(StyleSpec::NOCLIP, false));\r
+       setDrawBorder(style.getBool(StyleSpec::BORDER, true));\r
        setUseAlphaChannel(style.getBool(StyleSpec::ALPHA, true));\r
 \r
        const core::position2di buttonCenter(AbsoluteRect.getCenter());\r
        core::position2d<s32> geom(buttonCenter);\r
        if (style.isNotDefault(StyleSpec::BGIMG)) {\r
-               video::ITexture *texture = style.getTexture(StyleSpec::BGIMG, tsrc);\r
-\r
+               video::ITexture *texture = style.getTexture(StyleSpec::BGIMG,\r
+                               getTextureSource());\r
                setImage(guiScalingImageButton(\r
-                                       Environment->getVideoDriver(), texture, geom.X, geom.Y));\r
-               setScaleImage(true);\r
-       }\r
-       if (style.isNotDefault(StyleSpec::BGIMG_HOVERED)) {\r
-               video::ITexture *hovered_texture = style.getTexture(StyleSpec::BGIMG_HOVERED, tsrc);\r
-\r
-               setHoveredImage(guiScalingImageButton(\r
-                                       Environment->getVideoDriver(), hovered_texture, geom.X, geom.Y));\r
-               setScaleImage(true);\r
-       }\r
-       if (style.isNotDefault(StyleSpec::BGIMG_PRESSED)) {\r
-               video::ITexture *pressed_texture = style.getTexture(StyleSpec::BGIMG_PRESSED, tsrc);\r
-\r
-               setPressedImage(guiScalingImageButton(\r
-                                       Environment->getVideoDriver(), pressed_texture, geom.X, geom.Y));\r
+                               Environment->getVideoDriver(), texture, geom.X, geom.Y));\r
                setScaleImage(true);\r
+       } else {\r
+               setImage(nullptr);\r
        }\r
        BgMiddle = style.getRect(StyleSpec::BGIMG_MIDDLE, BgMiddle);\r
 }\r
+\r
+//! Set the styles used for each state\r
+void GUIButton::setStyles(const std::array<StyleSpec, StyleSpec::NUM_STATES>& styles)\r
+{\r
+       Styles = styles;\r
+       setFromState();\r
+}\r
 // END PATCH\r
index 3d1f98c32bed77fc8648995b087932f166b4df8a..ef10f926ef5d73bd551f69bc775881417c9a93df 100644 (file)
@@ -13,6 +13,7 @@
 #include "ITexture.h"\r
 #include "SColor.h"\r
 #include "guiSkin.h"\r
+#include "StyleSpec.h"\r
 \r
 using namespace irr;\r
 \r
@@ -67,7 +68,6 @@ using namespace irr;
 #endif\r
 \r
 class ISimpleTextureSource;\r
-class StyleSpec;\r
 \r
 class GUIButton : public gui::IGUIButton\r
 {\r
@@ -75,7 +75,8 @@ public:
 \r
        //! constructor\r
        GUIButton(gui::IGUIEnvironment* environment, gui::IGUIElement* parent,\r
-                          s32 id, core::rect<s32> rectangle, bool noclip=false);\r
+                          s32 id, core::rect<s32> rectangle, ISimpleTextureSource *tsrc,\r
+                          bool noclip=false);\r
 \r
        //! destructor\r
        virtual ~GUIButton();\r
@@ -125,16 +126,10 @@ public:
        //! Sets an image which should be displayed on the button when it is in pressed state.\r
        virtual void setPressedImage(video::ITexture* image, const core::rect<s32>& pos) override;\r
 \r
-       //! Sets an image which should be displayed on the button when it is in hovered state.\r
-       virtual void setHoveredImage(video::ITexture* image=nullptr);\r
-\r
        //! Sets the text displayed by the button\r
        virtual void setText(const wchar_t* text) override;\r
        // END PATCH\r
 \r
-       //! Sets an image which should be displayed on the button when it is in hovered state.\r
-       virtual void setHoveredImage(video::ITexture* image, const core::rect<s32>& pos);\r
-\r
        //! Sets the sprite bank used by the button\r
        virtual void setSpriteBank(gui::IGUISpriteBank* bank=0) override;\r
 \r
@@ -225,22 +220,29 @@ public:
 \r
        void setColor(video::SColor color);\r
        // PATCH\r
-       void setHoveredColor(video::SColor color);\r
-       void setPressedColor(video::SColor color);\r
+       //! Set element properties from a StyleSpec corresponding to the button state\r
+       void setFromState();\r
 \r
        //! Set element properties from a StyleSpec\r
-       virtual void setFromStyle(const StyleSpec& style, ISimpleTextureSource *tsrc);\r
+       virtual void setFromStyle(const StyleSpec& style);\r
+\r
+       //! Set the styles used for each state\r
+       void setStyles(const std::array<StyleSpec, StyleSpec::NUM_STATES>& styles);\r
        // END PATCH\r
 \r
 \r
        //! Do not drop returned handle\r
-       static GUIButton* addButton(gui::IGUIEnvironment *environment, const core::rect<s32>& rectangle,\r
-                                                                       IGUIElement* parent, s32 id, const wchar_t* text, const wchar_t *tooltiptext=L"");\r
+       static GUIButton* addButton(gui::IGUIEnvironment *environment,\r
+                       const core::rect<s32>& rectangle, ISimpleTextureSource *tsrc,\r
+                       IGUIElement* parent, s32 id, const wchar_t* text,\r
+                       const wchar_t *tooltiptext=L"");\r
 \r
 protected:\r
        void drawSprite(gui::EGUI_BUTTON_STATE state, u32 startTime, const core::position2di& center);\r
        gui::EGUI_BUTTON_IMAGE_STATE getImageState(bool pressed) const;\r
 \r
+       ISimpleTextureSource *getTextureSource() { return TSrc; }\r
+\r
        struct ButtonImage\r
        {\r
                ButtonImage() : Texture(0), SourceRect(core::rect<s32>(0,0,0,0))\r
@@ -308,6 +310,8 @@ private:
 \r
        ButtonImage ButtonImages[gui::EGBIS_COUNT];\r
 \r
+       std::array<StyleSpec, StyleSpec::NUM_STATES> Styles;\r
+\r
        gui::IGUIFont* OverrideFont;\r
 \r
        bool OverrideColorEnabled;\r
@@ -326,8 +330,8 @@ private:
 \r
        video::SColor Colors[4];\r
        // PATCH\r
-       video::SColor HoveredColors[4];\r
-       video::SColor PressedColors[4];\r
+       bool WasHovered = false;\r
+       ISimpleTextureSource *TSrc;\r
 \r
        gui::IGUIStaticText *StaticText;\r
 \r
index 02d920277ca70f6885bfd25d658373679f82166d..2658ad967126f4641112ee321c2abe52802ff5cd 100644 (file)
@@ -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);
index 15901ee5de474c5ae391adeec0644f11f49a78fa..a948d772b1e884a5588ba04a0d581ca6cfcf5bcd 100644 (file)
@@ -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;
 };
index 5c48b2acd54a4ef517896e1f6eb94c235a76331f..d8b9042ac9881387ff5be491dd4b3ba275cff92b 100644 (file)
@@ -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);
index 0a61874dac8ad84a2a6580d1fc8d62e1add19282..9cd0f61887c9c7efe517480265025ea2cd6bc99a 100644 (file)
@@ -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;
index 0d8bdf54e7be61f99a995fdd7ce2813f1849cceb..58ac427406d210cebb86e17176caeceaddacda5b 100644 (file)
@@ -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;
        }
        {
index 42c07e4edf03f3953c60c03311fdedbd6c7284a9..d8387201d46d88d2a0aa7e97997873c4603611e6 100644 (file)
@@ -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;
 };
index acb153569e1b3a13ba5ff6de2db23c8f90df4bdf..6a383a7919263e8694a0d5ae9b28860e553c53af 100644 (file)
@@ -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;
index 17bfef205b470f2285d0a8da379f58a3ea940bd8..b3bf67110ad2585c7b9a76df56dc35abbf3f2ce0 100644 (file)
@@ -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;
index 3f270fc7adbcc11c0f3d074d5dbf8b9bcaa0dd08..da0e25c239b986afcaccd5e0e954cf9697d2da52 100644 (file)
@@ -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;
        }
 }
index 528827fd9c56ad45c133eef9f58dcd9430a8f431..1c0f40247fee1f008cf7b85428259469d476a125 100644 (file)
@@ -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;
 };
index af91ce84c44950cb0cd96c884e608f849873976d..965a2d6f75a418a7fada73511830076d1595c7f7 100644 (file)
@@ -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;
        }
 
index 58541a3990e0503fff395b2a19b00e82ab31a6fe..7141100c08593a6eaf305c1fcc8f26bec4c72a55 100644 (file)
@@ -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;
 };
index 9428cde83cffcb05544cd26a0cdde7ab86bbbafd..07b11248ca2c5c636e7424a61b4011863c38d239 100644 (file)
@@ -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;
        }
        {
index f4f4e9eea28d02f770c4bdc52a10e087e7f2fd40..466e17f9d90a29c27f3633471c763dbfc732f5e0 100644 (file)
@@ -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;
 };
index 76db7ed13be24ccd2be4b5b0347d8359f1eda834..867e84e1348c9d262c6c798c9fd3018ac1aa9811 100644 (file)
@@ -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;
index 6f82a18c1b4d858019e29d8f5a9c0da064b6a3a1..864ab754369be02c5c524de2b1e5ab687eb60e9e 100644 (file)
@@ -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));
+}