#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
//! 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
// 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
- \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
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
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
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
}\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
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
{\r
ClickTime = porting::getTimeMs();\r
Pressed = pressed;\r
-\r
- GUISkin* skin = dynamic_cast<GUISkin*>(Environment->getSkin());\r
-\r
- for(IGUIElement *child : getChildren())\r
- {\r
- core::rect<s32> originalRect = child->getRelativePosition();\r
- if (Pressed) {\r
- child->setRelativePosition(originalRect +\r
- core::dimension2d<s32>(\r
- skin->getSize(irr::gui::EGDS_BUTTON_PRESSED_IMAGE_OFFSET_X),\r
- skin->getSize(irr::gui::EGDS_BUTTON_PRESSED_IMAGE_OFFSET_Y)));\r
- } else {\r
- child->setRelativePosition(originalRect -\r
- core::dimension2d<s32>(\r
- skin->getSize(irr::gui::EGDS_BUTTON_PRESSED_IMAGE_OFFSET_X),\r
- skin->getSize(irr::gui::EGDS_BUTTON_PRESSED_IMAGE_OFFSET_Y)));\r
- }\r
- }\r
+ setFromState();\r
}\r
}\r
\r
}\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
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
+ setOverrideFont(style.getFont());\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
+ Environment->getVideoDriver(), texture,\r
+ AbsoluteRect.getWidth(), AbsoluteRect.getHeight()));\r
setScaleImage(true);\r
+ } else {\r
+ setImage(nullptr);\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
+ BgMiddle = style.getRect(StyleSpec::BGIMG_MIDDLE, BgMiddle);\r
\r
- setPressedImage(guiScalingImageButton(\r
- Environment->getVideoDriver(), pressed_texture, geom.X, geom.Y));\r
- setScaleImage(true);\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