]> git.lizzy.rs Git - dragonfireclient.git/blobdiff - src/gui/guiButton.cpp
Android: Fix ConfirmRegistration and PasswordChange input and scale size (#10182)
[dragonfireclient.git] / src / gui / guiButton.cpp
index 60d330f4ab61579ec5a8f5de05bc1063fdb8c4f7..e0d6337cdadca382224e41b09e6edaa7128b74b5 100644 (file)
@@ -5,25 +5,37 @@
 #include "guiButton.h"\r
 \r
 \r
+#include "client/guiscalingfilter.h"\r
+#include "client/tile.h"\r
 #include "IGUISkin.h"\r
 #include "IGUIEnvironment.h"\r
 #include "IVideoDriver.h"\r
 #include "IGUIFont.h"\r
+#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
 \r
+// Multiply with a color to get the default corresponding hovered color\r
+#define COLOR_HOVERED_MOD 1.25f\r
+\r
+// Multiply with a color to get the default corresponding pressed color\r
+#define COLOR_PRESSED_MOD 0.85f\r
+\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
@@ -35,6 +47,8 @@ GUIButton::GUIButton(IGUIEnvironment* environment, IGUIElement* parent,
        for (size_t i = 0; i < 4; i++) {\r
                Colors[i] = Environment->getSkin()->getColor((EGUI_DEFAULT_COLOR)i);\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
        // END PATCH\r
 }\r
 \r
@@ -182,8 +196,12 @@ bool GUIButton::OnEvent(const SEvent& event)
        case EET_MOUSE_INPUT_EVENT:\r
                if (event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN)\r
                {\r
-                       if (!IsPushButton)\r
+                       // Sometimes formspec elements can receive mouse events when the\r
+                       // mouse is outside of the formspec. Thus, we test the position here.\r
+                       if ( !IsPushButton && AbsoluteClippingRect.isPointInside(\r
+                                               core::position2d<s32>(event.MouseInput.X, event.MouseInput.Y ))) {\r
                                setPressed(true);\r
+                       }\r
 \r
                        return true;\r
                }\r
@@ -238,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
@@ -247,19 +272,24 @@ void GUIButton::draw()
                if (!Pressed)\r
                {\r
                        // PATCH\r
-                       skin->drawColored3DButtonPaneStandard(this, AbsoluteRect, &AbsoluteClippingRect, Colors);\r
+                       skin->drawColored3DButtonPaneStandard(this, AbsoluteRect,\r
+                                       &AbsoluteClippingRect, Colors);\r
                        // END PATCH\r
                }\r
                else\r
                {\r
                        // PATCH\r
-                       skin->drawColored3DButtonPanePressed(this, AbsoluteRect, &AbsoluteClippingRect, Colors);\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
@@ -281,10 +311,25 @@ void GUIButton::draw()
                        }\r
                }\r
 \r
-               driver->draw2DImage(ButtonImages[(u32)imageState].Texture,\r
-                               ScaleImage? AbsoluteRect : core::rect<s32>(pos, sourceRect.getSize()),\r
-                               sourceRect, &AbsoluteClippingRect,\r
-                               0, UseAlphaChannel);\r
+               // PATCH\r
+               video::ITexture* texture = ButtonImages[(u32)imageState].Texture;\r
+               if (BgMiddle.getArea() == 0) {\r
+                       driver->draw2DImage(texture,\r
+                                       ScaleImage? AbsoluteRect : core::rect<s32>(pos, sourceRect.getSize()),\r
+                                       sourceRect, &AbsoluteClippingRect,\r
+                                       0, UseAlphaChannel);\r
+               } else {\r
+                       core::rect<s32> middle = BgMiddle;\r
+                       // `-x` is interpreted as `w - x`\r
+                       if (middle.LowerRightCorner.X < 0)\r
+                               middle.LowerRightCorner.X += texture->getOriginalSize().Width;\r
+                       if (middle.LowerRightCorner.Y < 0)\r
+                               middle.LowerRightCorner.Y += texture->getOriginalSize().Height;\r
+                       draw2DImage9Slice(driver, texture,\r
+                                       ScaleImage ? AbsoluteRect : core::rect<s32>(pos, sourceRect.getSize()),\r
+                                       middle, &AbsoluteClippingRect);\r
+               }\r
+               // END PATCH\r
        }\r
 \r
        if (SpriteBank)\r
@@ -302,7 +347,7 @@ void GUIButton::draw()
                        drawSprite(state, FocusTime, pos);\r
 \r
                        // mouse over / off animation\r
-                       state = Environment->getHovered() == this ? EGBS_BUTTON_MOUSE_OVER : EGBS_BUTTON_MOUSE_OFF;\r
+                       state = isHovered() ? EGBS_BUTTON_MOUSE_OVER : EGBS_BUTTON_MOUSE_OFF;\r
                        drawSprite(state, HoverTime, pos);\r
                }\r
                else\r
@@ -312,23 +357,6 @@ void GUIButton::draw()
                }\r
        }\r
 \r
-       if (Text.size())\r
-       {\r
-               IGUIFont* font = getActiveFont();\r
-\r
-               core::rect<s32> rect = AbsoluteRect;\r
-               if (Pressed)\r
-               {\r
-                       rect.UpperLeftCorner.X += skin->getSize(EGDS_BUTTON_PRESSED_TEXT_OFFSET_X);\r
-                       rect.UpperLeftCorner.Y += skin->getSize(EGDS_BUTTON_PRESSED_TEXT_OFFSET_Y);\r
-               }\r
-\r
-               if (font)\r
-                       font->draw(Text.c_str(), rect,\r
-                               OverrideColorEnabled ? OverrideColor : skin->getColor(isEnabled() ? EGDC_BUTTON_TEXT : EGDC_GRAY_TEXT),\r
-                               true, true, &AbsoluteClippingRect);\r
-       }\r
-\r
        IGUIElement::draw();\r
 }\r
 \r
@@ -355,11 +383,18 @@ void GUIButton::drawSprite(EGUI_BUTTON_STATE state, u32 startTime, const core::p
 }\r
 \r
 EGUI_BUTTON_IMAGE_STATE GUIButton::getImageState(bool pressed) const\r
+{\r
+       // PATCH\r
+       return getImageState(pressed, ButtonImages);\r
+       // END PATCH\r
+}\r
+\r
+EGUI_BUTTON_IMAGE_STATE GUIButton::getImageState(bool pressed, const ButtonImage* images) const\r
 {\r
        // figure state we should have\r
        EGUI_BUTTON_IMAGE_STATE state = EGBIS_IMAGE_DISABLED;\r
        bool focused = Environment->hasFocus((IGUIElement*)this);\r
-       bool mouseOver = static_cast<const IGUIElement*>(Environment->getHovered()) == this;    // (static cast for Borland)\r
+       bool mouseOver = isHovered();\r
        if (isEnabled())\r
        {\r
                if ( pressed )\r
@@ -387,12 +422,13 @@ EGUI_BUTTON_IMAGE_STATE GUIButton::getImageState(bool pressed) const
        }\r
 \r
        // find a compatible state that has images\r
-       while ( state != EGBIS_IMAGE_UP && !ButtonImages[(u32)state].Texture )\r
+       while ( state != EGBIS_IMAGE_UP && !images[(u32)state].Texture )\r
        {\r
+               // PATCH\r
                switch ( state )\r
                {\r
                        case EGBIS_IMAGE_UP_FOCUSED:\r
-                               state = EGBIS_IMAGE_UP_MOUSEOVER;\r
+                               state = EGBIS_IMAGE_UP;\r
                                break;\r
                        case EGBIS_IMAGE_UP_FOCUSED_MOUSEOVER:\r
                                state = EGBIS_IMAGE_UP_FOCUSED;\r
@@ -401,7 +437,7 @@ EGUI_BUTTON_IMAGE_STATE GUIButton::getImageState(bool pressed) const
                                state = EGBIS_IMAGE_DOWN;\r
                                break;\r
                        case EGBIS_IMAGE_DOWN_FOCUSED:\r
-                               state = EGBIS_IMAGE_DOWN_MOUSEOVER;\r
+                               state = EGBIS_IMAGE_DOWN;\r
                                break;\r
                        case EGBIS_IMAGE_DOWN_FOCUSED_MOUSEOVER:\r
                                state = EGBIS_IMAGE_DOWN_FOCUSED;\r
@@ -415,6 +451,7 @@ EGUI_BUTTON_IMAGE_STATE GUIButton::getImageState(bool pressed) const
                        default:\r
                                state = EGBIS_IMAGE_UP;\r
                }\r
+               // END PATCH\r
        }\r
 \r
        return state;\r
@@ -433,6 +470,8 @@ void GUIButton::setOverrideFont(IGUIFont* font)
 \r
        if (OverrideFont)\r
                OverrideFont->grab();\r
+\r
+       StaticText->setOverrideFont(font);\r
 }\r
 \r
 //! Gets the override font (if any)\r
@@ -457,6 +496,8 @@ void GUIButton::setOverrideColor(video::SColor color)
 {\r
        OverrideColor = color;\r
        OverrideColorEnabled = true;\r
+\r
+       StaticText->setOverrideColor(color);\r
 }\r
 \r
 video::SColor GUIButton::getOverrideColor() const\r
@@ -490,6 +531,36 @@ void GUIButton::setImage(EGUI_BUTTON_IMAGE_STATE state, video::ITexture* image,
        ButtonImages[stateIdx].SourceRect = sourceRect;\r
 }\r
 \r
+// PATCH\r
+void GUIButton::setImage(video::ITexture* image)\r
+{\r
+       setImage(gui::EGBIS_IMAGE_UP, image);\r
+}\r
+\r
+void GUIButton::setImage(video::ITexture* image, const core::rect<s32>& pos)\r
+{\r
+       setImage(gui::EGBIS_IMAGE_UP, image, pos);\r
+}\r
+\r
+void GUIButton::setPressedImage(video::ITexture* image)\r
+{\r
+       setImage(gui::EGBIS_IMAGE_DOWN, image);\r
+}\r
+\r
+void GUIButton::setPressedImage(video::ITexture* image, const core::rect<s32>& pos)\r
+{\r
+       setImage(gui::EGBIS_IMAGE_DOWN, image, pos);\r
+}\r
+\r
+//! Sets the text displayed by the button\r
+void GUIButton::setText(const wchar_t* text)\r
+{\r
+       StaticText->setText(text);\r
+\r
+       IGUIButton::setText(text);\r
+}\r
+// END PATCH\r
+\r
 //! Sets if the button should behave like a push button. Which means it\r
 //! can be in two states: Normal or Pressed. With a click on the button,\r
 //! the user can change the state of the button.\r
@@ -505,6 +576,14 @@ bool GUIButton::isPressed() const
        return Pressed;\r
 }\r
 \r
+// PATCH\r
+//! Returns if this element (or one of its direct children) is hovered\r
+bool GUIButton::isHovered() const\r
+{\r
+       IGUIElement *hovered = Environment->getHovered();\r
+       return  hovered == this || (hovered != nullptr && hovered->getParent() == this);\r
+}\r
+// END PATCH\r
 \r
 //! Sets the pressed state of the button if this is a pushbutton\r
 void GUIButton::setPressed(bool pressed)\r
@@ -513,6 +592,7 @@ void GUIButton::setPressed(bool pressed)
        {\r
                ClickTime = porting::getTimeMs();\r
                Pressed = pressed;\r
+               setFromState();\r
        }\r
 }\r
 \r
@@ -624,10 +704,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
@@ -646,4 +728,110 @@ void GUIButton::setColor(video::SColor color)
                Colors[i] = base.getInterpolated(color, d);\r
        }\r
 }\r
+\r
+//! Set element properties from a StyleSpec corresponding to the button state\r
+void GUIButton::setFromState()\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)\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 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, false));\r
+       setDrawBorder(style.getBool(StyleSpec::BORDER, true));\r
+       setUseAlphaChannel(style.getBool(StyleSpec::ALPHA, true));\r
+       setOverrideFont(style.getFont());\r
+\r
+       if (style.isNotDefault(StyleSpec::BGIMG)) {\r
+               video::ITexture *texture = style.getTexture(StyleSpec::BGIMG,\r
+                               getTextureSource());\r
+               setImage(guiScalingImageButton(\r
+                               Environment->getVideoDriver(), texture,\r
+                                               AbsoluteRect.getWidth(), AbsoluteRect.getHeight()));\r
+               setScaleImage(true);\r
+       } else {\r
+               setImage(nullptr);\r
+       }\r
+\r
+       BgMiddle = style.getRect(StyleSpec::BGIMG_MIDDLE, BgMiddle);\r
+\r
+       // Child padding and offset\r
+       Padding = style.getRect(StyleSpec::PADDING, core::rect<s32>());\r
+       Padding = core::rect<s32>(\r
+                       Padding.UpperLeftCorner + BgMiddle.UpperLeftCorner,\r
+                       Padding.LowerRightCorner + BgMiddle.LowerRightCorner);\r
+\r
+       GUISkin* skin = dynamic_cast<GUISkin*>(Environment->getSkin());\r
+       core::vector2d<s32> defaultPressOffset(\r
+                       skin->getSize(irr::gui::EGDS_BUTTON_PRESSED_IMAGE_OFFSET_X),\r
+                       skin->getSize(irr::gui::EGDS_BUTTON_PRESSED_IMAGE_OFFSET_Y));\r
+       ContentOffset = style.getVector2i(StyleSpec::CONTENT_OFFSET, isPressed()\r
+                       ? defaultPressOffset\r
+                       : core::vector2d<s32>(0));\r
+\r
+       core::rect<s32> childBounds(\r
+                               Padding.UpperLeftCorner.X + ContentOffset.X,\r
+                               Padding.UpperLeftCorner.Y + ContentOffset.Y,\r
+                               AbsoluteRect.getWidth() + Padding.LowerRightCorner.X + ContentOffset.X,\r
+                               AbsoluteRect.getHeight() + Padding.LowerRightCorner.Y + ContentOffset.Y);\r
+\r
+       for (IGUIElement *child : getChildren()) {\r
+               child->setRelativePosition(childBounds);\r
+       }\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