* 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
* `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
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:
* 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
---------------
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
} 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;
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;
}
*/
#include "client/tile.h" // ITextureSource
+#include "debug.h"
#include "irrlichttypes_extrabloated.h"
#include "util/string.h"
#include <array>
{
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)
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];
#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
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
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
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
skin->getSize(irr::gui::EGDS_BUTTON_PRESSED_IMAGE_OFFSET_Y)));\r
}\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
\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
#include "ITexture.h"\r
#include "SColor.h"\r
#include "guiSkin.h"\r
+#include "StyleSpec.h"\r
\r
using namespace irr;\r
\r
#endif\r
\r
class ISimpleTextureSource;\r
-class StyleSpec;\r
\r
class GUIButton : public gui::IGUIButton\r
{\r
\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
//! 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
\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
\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
\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
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);
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);
}
}
}
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);
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;
};
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()),
}
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);
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;
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;
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;
}
{
#include <string>
class Client;
+class ISimpleTextureSource;
class GUIConfirmRegistration : public GUIModalMenu
{
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();
const std::string &m_password;
bool *m_aborted = nullptr;
std::wstring m_pass_confirm = L"";
+ ISimpleTextureSource *m_tsrc;
};
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) {
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);
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);
);
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);
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();
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
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);
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);
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);
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);
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)));
}
}
- 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)
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)));
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)));
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];
}
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;
}
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) {
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);
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();
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) {
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);
+ }
}
}
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;
}
}
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;
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;
};
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();
}
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) {
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;
}
}
#include <string>
#include <vector>
+class ISimpleTextureSource;
+
struct key_setting
{
int id;
{
public:
GUIKeyChangeMenu(gui::IGUIEnvironment *env, gui::IGUIElement *parent, s32 id,
- IMenuManager *menumgr);
+ IMenuManager *menumgr, ISimpleTextureSource *tsrc);
~GUIKeyChangeMenu();
void removeChildren();
key_setting *active_key = nullptr;
gui::IGUIStaticText *key_used_text = nullptr;
std::vector<key_setting *> key_settings;
+ ISimpleTextureSource *m_tsrc;
};
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)
{
}
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;
}
#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();
std::wstring m_oldpass = L"";
std::wstring m_newpass = L"";
std::wstring m_newpass_confirm = L"";
+ ISimpleTextureSource *m_tsrc;
};
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)
{
}
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;
}
{
#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();
protected:
std::wstring getLabelByID(s32 id) { return L""; }
std::string getNameByID(s32 id) { return ""; }
+
+private:
+ ISimpleTextureSource *m_tsrc;
};
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;
}
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;
#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)))
{
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));
+}