Formspecs: Add state-selection to style elements (#9378)

This commit is contained in:
Hugues Ross 2020-04-11 16:39:30 -04:00 committed by GitHub
parent ba3587e776
commit f780bae05c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 462 additions and 325 deletions

@ -2188,12 +2188,12 @@ Elements
* 9-sliced background. See https://en.wikipedia.org/wiki/9-slice_scaling * 9-sliced background. See https://en.wikipedia.org/wiki/9-slice_scaling
* Middle is a rect which defines the middle of the 9-slice. * Middle is a rect which defines the middle of the 9-slice.
* `x` - The middle will be x pixels from all sides. * `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` - 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 * `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 will be added to the width and height of the texture, allowing it to be used as the
distance from the far end. distance from the far end.
* All numbers in middle are integers. * All numbers in middle are integers.
* Example for formspec 8x4 in 16x resolution: * Example for formspec 8x4 in 16x resolution:
image shall be sized 8 times 16px times 4 times 16px image shall be sized 8 times 16px times 4 times 16px
* If `auto_clip` is `true`, the background is clipped to the formspec size * 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 * `span=<value>`: number of following columns to affect
(default: infinite). (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. * Note: this **must** be before the element is defined.
* See [Styling Formspecs]. * 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]. * See [Styling Formspecs].
Migrating to Real Coordinates Migrating to Real Coordinates
@ -2560,24 +2572,33 @@ Styling Formspecs
Formspec elements can be themed using the style elements: Formspec elements can be themed using the style elements:
style[<name 1>,<name 2>,...;<prop1>;<prop2>;...] style[<name 1>,<name 2>;<prop1>;<prop2>;...]
style_type[<type 1>,<type 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: Where a prop is:
property_name=property_value property_name=property_value
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: For example:
style_type[button;bgcolor=#006699] style_type[button;bgcolor=#006699]
style[world_delete;bgcolor=red;textcolor=yellow] style[world_delete;bgcolor=red;textcolor=yellow]
button[4,3.95;2.6,1;world_delete;Delete] 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
Any name/type in the list can also be accompanied by a `+`-separated list of states, like so:
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: Setting a property to nothing will reset it to the default value. For example:
style_type[button;bgimg=button.png;bgimg_pressed=button_pressed.png;border=false] style_type[button;bgimg=button.png;bgimg_pressed=button_pressed.png;border=false]
@ -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. * noclip - boolean, set to true to allow the element to exceed formspec bounds.
* textcolor - color. Default white. * 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 Markup Language
--------------- ---------------

@ -65,7 +65,10 @@ local style_fs = [[
style[one_btn13;border=false] style[one_btn13;border=false]
item_image_button[1.25,8.35;1,1;default:sword_steel;one_btn13;NoBor] item_image_button[1.25,8.35;1,1;default:sword_steel;one_btn13;NoBor]
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] style[one_btn14;border=false;bgimg=test_bg.png;fgimg=bubble.png]
style[one_btn14:hovered;bgimg=test_bg_hovered.png;fgimg=default_apple.png;textcolor=red]
style[one_btn14:pressed;bgimg=test_bg_pressed.png;fgimg=heart.png;textcolor=green]
style[one_btn14:hovered+pressed;textcolor=blue]
image_button[0,9.6;1,1;bubble.png;one_btn14;Bg] image_button[0,9.6;1,1;bubble.png;one_btn14;Bg]
style[one_btn15;border=false;bgimg=test_bg.png;bgimg_hovered=test_bg_hovered.png;bgimg_pressed=test_bg_pressed.png] style[one_btn15;border=false;bgimg=test_bg.png;bgimg_hovered=test_bg_hovered.png;bgimg_pressed=test_bg_pressed.png]

@ -1556,7 +1556,8 @@ bool Game::connectToServer(const std::string &playername,
} else { } else {
registration_confirmation_shown = true; registration_confirmation_shown = true;
(new GUIConfirmRegistration(guienv, guienv->getRootGUIElement(), -1, (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 { } else {
wait_time += dtime; wait_time += dtime;
@ -1711,19 +1712,19 @@ inline bool Game::handleCallbacks()
if (g_gamecallback->changepassword_requested) { if (g_gamecallback->changepassword_requested) {
(new GUIPasswordChange(guienv, guiroot, -1, (new GUIPasswordChange(guienv, guiroot, -1,
&g_menumgr, client))->drop(); &g_menumgr, client, texture_src))->drop();
g_gamecallback->changepassword_requested = false; g_gamecallback->changepassword_requested = false;
} }
if (g_gamecallback->changevolume_requested) { if (g_gamecallback->changevolume_requested) {
(new GUIVolumeChange(guienv, guiroot, -1, (new GUIVolumeChange(guienv, guiroot, -1,
&g_menumgr))->drop(); &g_menumgr, texture_src))->drop();
g_gamecallback->changevolume_requested = false; g_gamecallback->changevolume_requested = false;
} }
if (g_gamecallback->keyconfig_requested) { if (g_gamecallback->keyconfig_requested) {
(new GUIKeyChangeMenu(guienv, guiroot, -1, (new GUIKeyChangeMenu(guienv, guiroot, -1,
&g_menumgr))->drop(); &g_menumgr, texture_src))->drop();
g_gamecallback->keyconfig_requested = false; g_gamecallback->keyconfig_requested = false;
} }

@ -18,6 +18,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
*/ */
#include "client/tile.h" // ITextureSource #include "client/tile.h" // ITextureSource
#include "debug.h"
#include "irrlichttypes_extrabloated.h" #include "irrlichttypes_extrabloated.h"
#include "util/string.h" #include "util/string.h"
#include <array> #include <array>
@ -31,25 +32,34 @@ public:
{ {
TEXTCOLOR, TEXTCOLOR,
BGCOLOR, BGCOLOR,
BGCOLOR_HOVERED, BGCOLOR_HOVERED, // Note: Deprecated property
BGCOLOR_PRESSED, BGCOLOR_PRESSED, // Note: Deprecated property
NOCLIP, NOCLIP,
BORDER, BORDER,
BGIMG, BGIMG,
BGIMG_HOVERED, BGIMG_HOVERED, // Note: Deprecated property
BGIMG_MIDDLE, BGIMG_MIDDLE,
BGIMG_PRESSED, BGIMG_PRESSED, // Note: Deprecated property
FGIMG, FGIMG,
FGIMG_HOVERED, FGIMG_HOVERED, // Note: Deprecated property
FGIMG_PRESSED, FGIMG_PRESSED, // Note: Deprecated property
ALPHA, ALPHA,
NUM_PROPERTIES, NUM_PROPERTIES,
NONE NONE
}; };
enum State
{
STATE_DEFAULT = 0,
STATE_HOVERED = 1 << 0,
STATE_PRESSED = 1 << 1,
NUM_STATES = 1 << 2,
STATE_INVALID = 1 << 3,
};
private: private:
std::array<bool, NUM_PROPERTIES> property_set{}; std::array<bool, NUM_PROPERTIES> property_set{};
std::array<std::string, NUM_PROPERTIES> properties; std::array<std::string, NUM_PROPERTIES> properties;
State state_map = STATE_DEFAULT;
public: public:
static Property GetPropertyByName(const std::string &name) static Property GetPropertyByName(const std::string &name)
@ -99,6 +109,49 @@ public:
property_set[prop] = true; 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 video::SColor getColor(Property prop, video::SColor def) const
{ {
const auto &val = properties[prop]; const auto &val = properties[prop];

@ -14,6 +14,7 @@
#include "irrlicht_changes/static_text.h" #include "irrlicht_changes/static_text.h"
#include "porting.h" #include "porting.h"
#include "StyleSpec.h" #include "StyleSpec.h"
#include "util/numeric.h"
using namespace irr; using namespace irr;
using namespace gui; using namespace gui;
@ -26,14 +27,15 @@ using namespace gui;
//! constructor //! constructor
GUIButton::GUIButton(IGUIEnvironment* environment, IGUIElement* parent, GUIButton::GUIButton(IGUIEnvironment* environment, IGUIElement* parent,
s32 id, core::rect<s32> rectangle, bool noclip) s32 id, core::rect<s32> rectangle, ISimpleTextureSource *tsrc,
bool noclip)
: IGUIButton(environment, parent, id, rectangle), : IGUIButton(environment, parent, id, rectangle),
SpriteBank(0), OverrideFont(0), SpriteBank(0), OverrideFont(0),
OverrideColorEnabled(false), OverrideColor(video::SColor(101,255,255,255)), OverrideColorEnabled(false), OverrideColor(video::SColor(101,255,255,255)),
ClickTime(0), HoverTime(0), FocusTime(0), ClickTime(0), HoverTime(0), FocusTime(0),
ClickShiftState(false), ClickControlState(false), ClickShiftState(false), ClickControlState(false),
IsPushButton(false), Pressed(false), IsPushButton(false), Pressed(false),
UseAlphaChannel(false), DrawBorder(true), ScaleImage(false) UseAlphaChannel(false), DrawBorder(true), ScaleImage(false), TSrc(tsrc)
{ {
setNotClipped(noclip); setNotClipped(noclip);
@ -44,14 +46,6 @@ GUIButton::GUIButton(IGUIEnvironment* environment, IGUIElement* parent,
// PATCH // PATCH
for (size_t i = 0; i < 4; i++) { for (size_t i = 0; i < 4; i++) {
Colors[i] = Environment->getSkin()->getColor((EGUI_DEFAULT_COLOR)i); Colors[i] = Environment->getSkin()->getColor((EGUI_DEFAULT_COLOR)i);
HoveredColors[i] = irr::video::SColor(Colors[i].getAlpha(),
core::clamp<u32>(Colors[i].getRed() * COLOR_HOVERED_MOD, 0, 255),
core::clamp<u32>(Colors[i].getGreen() * COLOR_HOVERED_MOD, 0, 255),
core::clamp<u32>(Colors[i].getBlue() * COLOR_HOVERED_MOD, 0, 255));
PressedColors[i] = irr::video::SColor(Colors[i].getAlpha(),
core::clamp<u32>(Colors[i].getRed() * COLOR_PRESSED_MOD, 0, 255),
core::clamp<u32>(Colors[i].getGreen() * COLOR_PRESSED_MOD, 0, 255),
core::clamp<u32>(Colors[i].getBlue() * COLOR_PRESSED_MOD, 0, 255));
} }
StaticText = gui::StaticText::add(Environment, Text.c_str(), core::rect<s32>(0,0,rectangle.getWidth(),rectangle.getHeight()), false, false, this, id); StaticText = gui::StaticText::add(Environment, Text.c_str(), core::rect<s32>(0,0,rectangle.getWidth(),rectangle.getHeight()), false, false, this, id);
StaticText->setTextAlignment(EGUIA_CENTER, EGUIA_CENTER); StaticText->setTextAlignment(EGUIA_CENTER, EGUIA_CENTER);
@ -262,6 +256,13 @@ void GUIButton::draw()
return; return;
// PATCH // PATCH
// Track hovered state, if it has changed then we need to update the style.
bool hovered = isHovered();
if (hovered != WasHovered) {
WasHovered = hovered;
setFromState();
}
GUISkin* skin = dynamic_cast<GUISkin*>(Environment->getSkin()); GUISkin* skin = dynamic_cast<GUISkin*>(Environment->getSkin());
video::IVideoDriver* driver = Environment->getVideoDriver(); video::IVideoDriver* driver = Environment->getVideoDriver();
// END PATCH // END PATCH
@ -271,21 +272,24 @@ void GUIButton::draw()
if (!Pressed) if (!Pressed)
{ {
// PATCH // PATCH
skin->drawColored3DButtonPaneStandard(this, AbsoluteRect, &AbsoluteClippingRect, skin->drawColored3DButtonPaneStandard(this, AbsoluteRect,
isHovered() ? HoveredColors : Colors); &AbsoluteClippingRect, Colors);
// END PATCH // END PATCH
} }
else else
{ {
// PATCH // PATCH
skin->drawColored3DButtonPanePressed(this, skin->drawColored3DButtonPanePressed(this, AbsoluteRect,
AbsoluteRect, &AbsoluteClippingRect, PressedColors); &AbsoluteClippingRect, Colors);
// END PATCH // END PATCH
} }
} }
const core::position2di buttonCenter(AbsoluteRect.getCenter()); const core::position2di buttonCenter(AbsoluteRect.getCenter());
EGUI_BUTTON_IMAGE_STATE imageState = getImageState(Pressed); // PATCH
// The image changes based on the state, so we use the default every time.
EGUI_BUTTON_IMAGE_STATE imageState = EGBIS_IMAGE_UP;
// END PATCH
if ( ButtonImages[(u32)imageState].Texture ) if ( ButtonImages[(u32)imageState].Texture )
{ {
core::position2d<s32> pos(buttonCenter); core::position2d<s32> pos(buttonCenter);
@ -548,18 +552,6 @@ void GUIButton::setPressedImage(video::ITexture* image, const core::rect<s32>& p
setImage(gui::EGBIS_IMAGE_DOWN, image, pos); setImage(gui::EGBIS_IMAGE_DOWN, image, pos);
} }
void GUIButton::setHoveredImage(video::ITexture* image)
{
setImage(gui::EGBIS_IMAGE_UP_MOUSEOVER, image);
setImage(gui::EGBIS_IMAGE_UP_FOCUSED_MOUSEOVER, image);
}
void GUIButton::setHoveredImage(video::ITexture* image, const core::rect<s32>& pos)
{
setImage(gui::EGBIS_IMAGE_UP_MOUSEOVER, image, pos);
setImage(gui::EGBIS_IMAGE_UP_FOCUSED_MOUSEOVER, image, pos);
}
//! Sets the text displayed by the button //! Sets the text displayed by the button
void GUIButton::setText(const wchar_t* text) void GUIButton::setText(const wchar_t* text)
{ {
@ -618,6 +610,8 @@ void GUIButton::setPressed(bool pressed)
skin->getSize(irr::gui::EGDS_BUTTON_PRESSED_IMAGE_OFFSET_Y))); skin->getSize(irr::gui::EGDS_BUTTON_PRESSED_IMAGE_OFFSET_Y)));
} }
} }
setFromState();
} }
} }
@ -729,10 +723,12 @@ void GUIButton::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWri
} }
// PATCH // PATCH
GUIButton* GUIButton::addButton(IGUIEnvironment *environment, const core::rect<s32>& rectangle, GUIButton* GUIButton::addButton(IGUIEnvironment *environment,
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)
{ {
GUIButton* button = new GUIButton(environment, parent ? parent : environment->getRootGUIElement(), id, rectangle); GUIButton* button = new GUIButton(environment, parent ? parent : environment->getRootGUIElement(), id, rectangle, tsrc);
if (text) if (text)
button->setText(text); button->setText(text);
@ -749,76 +745,87 @@ void GUIButton::setColor(video::SColor color)
for (size_t i = 0; i < 4; i++) { for (size_t i = 0; i < 4; i++) {
video::SColor base = Environment->getSkin()->getColor((gui::EGUI_DEFAULT_COLOR)i); video::SColor base = Environment->getSkin()->getColor((gui::EGUI_DEFAULT_COLOR)i);
Colors[i] = base.getInterpolated(color, d); Colors[i] = base.getInterpolated(color, d);
HoveredColors[i] = irr::video::SColor(Colors[i].getAlpha(),
core::clamp<u32>(Colors[i].getRed() * COLOR_HOVERED_MOD, 0, 255),
core::clamp<u32>(Colors[i].getGreen() * COLOR_HOVERED_MOD, 0, 255),
core::clamp<u32>(Colors[i].getBlue() * COLOR_HOVERED_MOD, 0, 255));
PressedColors[i] = irr::video::SColor(Colors[i].getAlpha(),
core::clamp<u32>(Colors[i].getRed() * COLOR_PRESSED_MOD, 0, 255),
core::clamp<u32>(Colors[i].getGreen() * COLOR_PRESSED_MOD, 0, 255),
core::clamp<u32>(Colors[i].getBlue() * COLOR_PRESSED_MOD, 0, 255));
}
}
void GUIButton::setHoveredColor(video::SColor color)
{
float d = 0.65f;
for (size_t i = 0; i < 4; i++) {
video::SColor base = Environment->getSkin()->getColor((gui::EGUI_DEFAULT_COLOR)i);
HoveredColors[i] = base.getInterpolated(color, d);
}
}
void GUIButton::setPressedColor(video::SColor color)
{
float d = 0.65f;
for (size_t i = 0; i < 4; i++) {
video::SColor base = Environment->getSkin()->getColor((gui::EGUI_DEFAULT_COLOR)i);
PressedColors[i] = base.getInterpolated(color, d);
} }
} }
//! Set element properties from a StyleSpec //! Set element properties from a StyleSpec corresponding to the button state
void GUIButton::setFromStyle(const StyleSpec& style, ISimpleTextureSource *tsrc) void GUIButton::setFromState()
{ {
StyleSpec::State state = StyleSpec::STATE_DEFAULT;
if (isPressed())
state = static_cast<StyleSpec::State>(state | StyleSpec::STATE_PRESSED);
if (isHovered())
state = static_cast<StyleSpec::State>(state | StyleSpec::STATE_HOVERED);
setFromStyle(StyleSpec::getStyleFromStatePropagation(Styles, state));
}
//! Set element properties from a StyleSpec
void GUIButton::setFromStyle(const StyleSpec& style)
{
bool hovered = (style.getState() & StyleSpec::STATE_HOVERED) != 0;
bool pressed = (style.getState() & StyleSpec::STATE_PRESSED) != 0;
if (style.isNotDefault(StyleSpec::BGCOLOR)) { if (style.isNotDefault(StyleSpec::BGCOLOR)) {
setColor(style.getColor(StyleSpec::BGCOLOR)); setColor(style.getColor(StyleSpec::BGCOLOR));
}
if (style.isNotDefault(StyleSpec::BGCOLOR_HOVERED)) { // If we have a propagated hover/press color, we need to automatically
setHoveredColor(style.getColor(StyleSpec::BGCOLOR_HOVERED)); // lighten/darken it
} if (!Styles[style.getState()].isNotDefault(StyleSpec::BGCOLOR)) {
if (style.isNotDefault(StyleSpec::BGCOLOR_PRESSED)) { for (size_t i = 0; i < 4; i++) {
setPressedColor(style.getColor(StyleSpec::BGCOLOR_PRESSED)); if (pressed) {
Colors[i] = multiplyColorValue(Colors[i], COLOR_PRESSED_MOD);
} else if (hovered) {
Colors[i] = multiplyColorValue(Colors[i], COLOR_HOVERED_MOD);
}
}
}
} else {
for (size_t i = 0; i < 4; i++) {
video::SColor base =
Environment->getSkin()->getColor((gui::EGUI_DEFAULT_COLOR)i);
if (pressed) {
Colors[i] = multiplyColorValue(base, COLOR_PRESSED_MOD);
} else if (hovered) {
Colors[i] = multiplyColorValue(base, COLOR_HOVERED_MOD);
} else {
Colors[i] = base;
}
}
} }
if (style.isNotDefault(StyleSpec::TEXTCOLOR)) { if (style.isNotDefault(StyleSpec::TEXTCOLOR)) {
setOverrideColor(style.getColor(StyleSpec::TEXTCOLOR)); setOverrideColor(style.getColor(StyleSpec::TEXTCOLOR));
} else {
setOverrideColor(video::SColor(255,255,255,255));
OverrideColorEnabled = false;
} }
setNotClipped(style.getBool(StyleSpec::NOCLIP, isNotClipped())); setNotClipped(style.getBool(StyleSpec::NOCLIP, false));
setDrawBorder(style.getBool(StyleSpec::BORDER, DrawBorder)); setDrawBorder(style.getBool(StyleSpec::BORDER, true));
setUseAlphaChannel(style.getBool(StyleSpec::ALPHA, true)); setUseAlphaChannel(style.getBool(StyleSpec::ALPHA, true));
const core::position2di buttonCenter(AbsoluteRect.getCenter()); const core::position2di buttonCenter(AbsoluteRect.getCenter());
core::position2d<s32> geom(buttonCenter); core::position2d<s32> geom(buttonCenter);
if (style.isNotDefault(StyleSpec::BGIMG)) { if (style.isNotDefault(StyleSpec::BGIMG)) {
video::ITexture *texture = style.getTexture(StyleSpec::BGIMG, tsrc); video::ITexture *texture = style.getTexture(StyleSpec::BGIMG,
getTextureSource());
setImage(guiScalingImageButton( setImage(guiScalingImageButton(
Environment->getVideoDriver(), texture, geom.X, geom.Y)); Environment->getVideoDriver(), texture, geom.X, geom.Y));
setScaleImage(true);
}
if (style.isNotDefault(StyleSpec::BGIMG_HOVERED)) {
video::ITexture *hovered_texture = style.getTexture(StyleSpec::BGIMG_HOVERED, tsrc);
setHoveredImage(guiScalingImageButton(
Environment->getVideoDriver(), hovered_texture, geom.X, geom.Y));
setScaleImage(true);
}
if (style.isNotDefault(StyleSpec::BGIMG_PRESSED)) {
video::ITexture *pressed_texture = style.getTexture(StyleSpec::BGIMG_PRESSED, tsrc);
setPressedImage(guiScalingImageButton(
Environment->getVideoDriver(), pressed_texture, geom.X, geom.Y));
setScaleImage(true); setScaleImage(true);
} else {
setImage(nullptr);
} }
BgMiddle = style.getRect(StyleSpec::BGIMG_MIDDLE, BgMiddle); BgMiddle = style.getRect(StyleSpec::BGIMG_MIDDLE, BgMiddle);
} }
//! Set the styles used for each state
void GUIButton::setStyles(const std::array<StyleSpec, StyleSpec::NUM_STATES>& styles)
{
Styles = styles;
setFromState();
}
// END PATCH // END PATCH

@ -13,6 +13,7 @@
#include "ITexture.h" #include "ITexture.h"
#include "SColor.h" #include "SColor.h"
#include "guiSkin.h" #include "guiSkin.h"
#include "StyleSpec.h"
using namespace irr; using namespace irr;
@ -67,7 +68,6 @@ using namespace irr;
#endif #endif
class ISimpleTextureSource; class ISimpleTextureSource;
class StyleSpec;
class GUIButton : public gui::IGUIButton class GUIButton : public gui::IGUIButton
{ {
@ -75,7 +75,8 @@ public:
//! constructor //! constructor
GUIButton(gui::IGUIEnvironment* environment, gui::IGUIElement* parent, GUIButton(gui::IGUIEnvironment* environment, gui::IGUIElement* parent,
s32 id, core::rect<s32> rectangle, bool noclip=false); s32 id, core::rect<s32> rectangle, ISimpleTextureSource *tsrc,
bool noclip=false);
//! destructor //! destructor
virtual ~GUIButton(); virtual ~GUIButton();
@ -125,16 +126,10 @@ public:
//! Sets an image which should be displayed on the button when it is in pressed state. //! Sets an image which should be displayed on the button when it is in pressed state.
virtual void setPressedImage(video::ITexture* image, const core::rect<s32>& pos) override; virtual void setPressedImage(video::ITexture* image, const core::rect<s32>& pos) override;
//! Sets an image which should be displayed on the button when it is in hovered state.
virtual void setHoveredImage(video::ITexture* image=nullptr);
//! Sets the text displayed by the button //! Sets the text displayed by the button
virtual void setText(const wchar_t* text) override; virtual void setText(const wchar_t* text) override;
// END PATCH // END PATCH
//! Sets an image which should be displayed on the button when it is in hovered state.
virtual void setHoveredImage(video::ITexture* image, const core::rect<s32>& pos);
//! Sets the sprite bank used by the button //! Sets the sprite bank used by the button
virtual void setSpriteBank(gui::IGUISpriteBank* bank=0) override; virtual void setSpriteBank(gui::IGUISpriteBank* bank=0) override;
@ -225,22 +220,29 @@ public:
void setColor(video::SColor color); void setColor(video::SColor color);
// PATCH // PATCH
void setHoveredColor(video::SColor color); //! Set element properties from a StyleSpec corresponding to the button state
void setPressedColor(video::SColor color); void setFromState();
//! Set element properties from a StyleSpec //! Set element properties from a StyleSpec
virtual void setFromStyle(const StyleSpec& style, ISimpleTextureSource *tsrc); virtual void setFromStyle(const StyleSpec& style);
//! Set the styles used for each state
void setStyles(const std::array<StyleSpec, StyleSpec::NUM_STATES>& styles);
// END PATCH // END PATCH
//! Do not drop returned handle //! Do not drop returned handle
static GUIButton* addButton(gui::IGUIEnvironment *environment, const core::rect<s32>& rectangle, static GUIButton* addButton(gui::IGUIEnvironment *environment,
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"");
protected: protected:
void drawSprite(gui::EGUI_BUTTON_STATE state, u32 startTime, const core::position2di& center); void drawSprite(gui::EGUI_BUTTON_STATE state, u32 startTime, const core::position2di& center);
gui::EGUI_BUTTON_IMAGE_STATE getImageState(bool pressed) const; gui::EGUI_BUTTON_IMAGE_STATE getImageState(bool pressed) const;
ISimpleTextureSource *getTextureSource() { return TSrc; }
struct ButtonImage struct ButtonImage
{ {
ButtonImage() : Texture(0), SourceRect(core::rect<s32>(0,0,0,0)) ButtonImage() : Texture(0), SourceRect(core::rect<s32>(0,0,0,0))
@ -308,6 +310,8 @@ private:
ButtonImage ButtonImages[gui::EGBIS_COUNT]; ButtonImage ButtonImages[gui::EGBIS_COUNT];
std::array<StyleSpec, StyleSpec::NUM_STATES> Styles;
gui::IGUIFont* OverrideFont; gui::IGUIFont* OverrideFont;
bool OverrideColorEnabled; bool OverrideColorEnabled;
@ -326,8 +330,8 @@ private:
video::SColor Colors[4]; video::SColor Colors[4];
// PATCH // PATCH
video::SColor HoveredColors[4]; bool WasHovered = false;
video::SColor PressedColors[4]; ISimpleTextureSource *TSrc;
gui::IGUIStaticText *StaticText; gui::IGUIStaticText *StaticText;

@ -30,8 +30,9 @@ using namespace irr;
using namespace gui; using namespace gui;
GUIButtonImage::GUIButtonImage(gui::IGUIEnvironment *environment, GUIButtonImage::GUIButtonImage(gui::IGUIEnvironment *environment,
gui::IGUIElement *parent, s32 id, core::rect<s32> rectangle, bool noclip) gui::IGUIElement *parent, s32 id, core::rect<s32> rectangle,
: GUIButton (environment, parent, id, rectangle, noclip) ISimpleTextureSource *tsrc, bool noclip)
: GUIButton (environment, parent, id, rectangle, tsrc, noclip)
{ {
m_image = Environment->addImage( m_image = Environment->addImage(
core::rect<s32>(0,0,rectangle.getWidth(),rectangle.getHeight()), this); core::rect<s32>(0,0,rectangle.getWidth(),rectangle.getHeight()), this);
@ -39,100 +40,38 @@ GUIButtonImage::GUIButtonImage(gui::IGUIEnvironment *environment,
sendToBack(m_image); 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)
{
if (state >= EGBIS_COUNT)
return;
if (image)
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) void GUIButtonImage::setForegroundImage(video::ITexture *image)
{ {
setForegroundImage(gui::EGBIS_IMAGE_UP, image); if (image == m_foreground_image)
return;
if (image != nullptr)
image->grab();
if (m_foreground_image != nullptr)
m_foreground_image->drop();
m_foreground_image = image;
m_image->setImage(image);
} }
void GUIButtonImage::setForegroundImage(video::ITexture *image, const core::rect<s32> &pos) //! Set element properties from a StyleSpec
void GUIButtonImage::setFromStyle(const StyleSpec& style)
{ {
setForegroundImage(gui::EGBIS_IMAGE_UP, image, pos); GUIButton::setFromStyle(style);
}
void GUIButtonImage::setPressedForegroundImage(video::ITexture *image)
{
setForegroundImage(gui::EGBIS_IMAGE_DOWN, image);
}
void GUIButtonImage::setPressedForegroundImage(video::ITexture *image, const core::rect<s32> &pos)
{
setForegroundImage(gui::EGBIS_IMAGE_DOWN, image, pos);
}
void GUIButtonImage::setHoveredForegroundImage(video::ITexture *image)
{
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);
video::IVideoDriver *driver = Environment->getVideoDriver(); video::IVideoDriver *driver = Environment->getVideoDriver();
const core::position2di buttonCenter(AbsoluteRect.getCenter()); const core::position2di buttonCenter(AbsoluteRect.getCenter());
core::position2d<s32> geom(buttonCenter); core::position2d<s32> geom(buttonCenter);
if (style.isNotDefault(StyleSpec::FGIMG)) { 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)); setForegroundImage(guiScalingImageButton(driver, texture, geom.X, geom.Y));
setScaleImage(true); setScaleImage(true);
} } else {
if (style.isNotDefault(StyleSpec::FGIMG_HOVERED)) { setForegroundImage(nullptr);
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);
} }
} }
@ -143,11 +82,12 @@ void GUIButtonImage::setScaleImage(bool scaleImage)
} }
GUIButtonImage *GUIButtonImage::addButton(IGUIEnvironment *environment, GUIButtonImage *GUIButtonImage::addButton(IGUIEnvironment *environment,
const core::rect<s32> &rectangle, IGUIElement *parent, s32 id, const core::rect<s32> &rectangle, ISimpleTextureSource *tsrc,
const wchar_t *text, const wchar_t *tooltiptext) IGUIElement *parent, s32 id, const wchar_t *text,
const wchar_t *tooltiptext)
{ {
GUIButtonImage *button = new GUIButtonImage(environment, GUIButtonImage *button = new GUIButtonImage(environment,
parent ? parent : environment->getRootGUIElement(), id, rectangle); parent ? parent : environment->getRootGUIElement(), id, rectangle, tsrc);
if (text) if (text)
button->setText(text); button->setText(text);

@ -27,33 +27,23 @@ class GUIButtonImage : public GUIButton
public: public:
//! constructor //! constructor
GUIButtonImage(gui::IGUIEnvironment *environment, gui::IGUIElement *parent, GUIButtonImage(gui::IGUIEnvironment *environment, gui::IGUIElement *parent,
s32 id, core::rect<s32> rectangle, bool noclip = false); s32 id, core::rect<s32> rectangle, ISimpleTextureSource *tsrc,
bool noclip = false);
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));
void setForegroundImage(video::ITexture *image = nullptr); void setForegroundImage(video::ITexture *image = nullptr);
void setForegroundImage(video::ITexture *image, const core::rect<s32> &pos);
void setPressedForegroundImage(video::ITexture *image = nullptr); //! Set element properties from a StyleSpec
void setPressedForegroundImage(video::ITexture *image, const core::rect<s32> &pos); virtual void setFromStyle(const StyleSpec& style) override;
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;
virtual void setScaleImage(bool scaleImage=true) override; virtual void setScaleImage(bool scaleImage=true) override;
//! Do not drop returned handle //! Do not drop returned handle
static GUIButtonImage *addButton(gui::IGUIEnvironment *environment, static GUIButtonImage *addButton(gui::IGUIEnvironment *environment,
const core::rect<s32> &rectangle, IGUIElement *parent, s32 id, const core::rect<s32> &rectangle, ISimpleTextureSource *tsrc,
const wchar_t *text, const wchar_t *tooltiptext = L""); IGUIElement *parent, s32 id, const wchar_t *text,
const wchar_t *tooltiptext = L"");
private: private:
ButtonImage m_foreground_images[gui::EGBIS_COUNT]; video::ITexture *m_foreground_image = nullptr;
gui::IGUIImage *m_image; gui::IGUIImage *m_image;
}; };

@ -28,9 +28,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
using namespace irr; using namespace irr;
using namespace gui; using namespace gui;
GUIButtonItemImage::GUIButtonItemImage(gui::IGUIEnvironment *environment, gui::IGUIElement *parent, GUIButtonItemImage::GUIButtonItemImage(gui::IGUIEnvironment *environment,
s32 id, core::rect<s32> rectangle, std::string item, Client *client, bool noclip) gui::IGUIElement *parent, s32 id, core::rect<s32> rectangle,
: GUIButton (environment, parent, id, rectangle, noclip) ISimpleTextureSource *tsrc, std::string item, Client *client,
bool noclip)
: GUIButton (environment, parent, id, rectangle, tsrc, noclip)
{ {
m_image = new GUIItemImage(environment, this, id, m_image = new GUIItemImage(environment, this, id,
core::rect<s32>(0,0,rectangle.getWidth(),rectangle.getHeight()), 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, GUIButtonItemImage *GUIButtonItemImage::addButton(IGUIEnvironment *environment,
const core::rect<s32> &rectangle, IGUIElement *parent, s32 id, const core::rect<s32> &rectangle, ISimpleTextureSource *tsrc,
const wchar_t *text, std::string item, Client *client) IGUIElement *parent, s32 id, const wchar_t *text, std::string item,
Client *client)
{ {
GUIButtonItemImage *button = new GUIButtonItemImage(environment, GUIButtonItemImage *button = new GUIButtonItemImage(environment,
parent ? parent : environment->getRootGUIElement(), parent ? parent : environment->getRootGUIElement(),
id, rectangle, item, client); id, rectangle, tsrc, item, client);
if (text) if (text)
button->setText(text); button->setText(text);

@ -30,13 +30,14 @@ class GUIButtonItemImage : public GUIButton
public: public:
//! constructor //! constructor
GUIButtonItemImage(gui::IGUIEnvironment *environment, gui::IGUIElement *parent, GUIButtonItemImage(gui::IGUIEnvironment *environment, gui::IGUIElement *parent,
s32 id, core::rect<s32> rectangle, std::string item, s32 id, core::rect<s32> rectangle, ISimpleTextureSource *tsrc,
Client *client, bool noclip = false); std::string item, Client *client, bool noclip = false);
//! Do not drop returned handle //! Do not drop returned handle
static GUIButtonItemImage *addButton(gui::IGUIEnvironment *environment, static GUIButtonItemImage *addButton(gui::IGUIEnvironment *environment,
const core::rect<s32> &rectangle, IGUIElement *parent, s32 id, const core::rect<s32> &rectangle, ISimpleTextureSource *tsrc,
const wchar_t *text, std::string item, Client *client); IGUIElement *parent, s32 id, const wchar_t *text, std::string item,
Client *client);
private: private:
std::string m_item_name; std::string m_item_name;

@ -40,10 +40,10 @@ const int ID_message = 266;
GUIConfirmRegistration::GUIConfirmRegistration(gui::IGUIEnvironment *env, GUIConfirmRegistration::GUIConfirmRegistration(gui::IGUIEnvironment *env,
gui::IGUIElement *parent, s32 id, IMenuManager *menumgr, Client *client, gui::IGUIElement *parent, s32 id, IMenuManager *menumgr, Client *client,
const std::string &playername, const std::string &password, const std::string &playername, const std::string &password,
bool *aborted) : bool *aborted, ISimpleTextureSource *tsrc) :
GUIModalMenu(env, parent, id, menumgr), GUIModalMenu(env, parent, id, menumgr),
m_client(client), m_playername(playername), m_password(password), m_client(client), m_playername(playername), m_password(password),
m_aborted(aborted) m_aborted(aborted), m_tsrc(tsrc)
{ {
#ifdef __ANDROID__ #ifdef __ANDROID__
m_touchscreen_visible = false; m_touchscreen_visible = false;
@ -130,14 +130,14 @@ void GUIConfirmRegistration::regenerateGui(v2u32 screensize)
core::rect<s32> rect2(0, 0, 230 * s, 35 * s); core::rect<s32> rect2(0, 0, 230 * s, 35 * s);
rect2 = rect2 + v2s32(size.X / 2 - 220 * s, ypos); rect2 = rect2 + v2s32(size.X / 2 - 220 * s, ypos);
text = wgettext("Register and Join"); 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; delete[] text;
} }
{ {
core::rect<s32> rect2(0, 0, 120 * s, 35 * s); core::rect<s32> rect2(0, 0, 120 * s, 35 * s);
rect2 = rect2 + v2s32(size.X / 2 + 70 * s, ypos); rect2 = rect2 + v2s32(size.X / 2 + 70 * s, ypos);
text = wgettext("Cancel"); text = wgettext("Cancel");
GUIButton::addButton(Environment, rect2, this, ID_cancel, text); GUIButton::addButton(Environment, rect2, m_tsrc, this, ID_cancel, text);
delete[] text; delete[] text;
} }
{ {

@ -25,6 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <string> #include <string>
class Client; class Client;
class ISimpleTextureSource;
class GUIConfirmRegistration : public GUIModalMenu class GUIConfirmRegistration : public GUIModalMenu
{ {
@ -32,7 +33,7 @@ public:
GUIConfirmRegistration(gui::IGUIEnvironment *env, gui::IGUIElement *parent, GUIConfirmRegistration(gui::IGUIEnvironment *env, gui::IGUIElement *parent,
s32 id, IMenuManager *menumgr, Client *client, s32 id, IMenuManager *menumgr, Client *client,
const std::string &playername, const std::string &password, const std::string &playername, const std::string &password,
bool *aborted); bool *aborted, ISimpleTextureSource *tsrc);
~GUIConfirmRegistration(); ~GUIConfirmRegistration();
void removeChildren(); void removeChildren();
@ -63,4 +64,5 @@ private:
const std::string &m_password; const std::string &m_password;
bool *m_aborted = nullptr; bool *m_aborted = nullptr;
std::wstring m_pass_confirm = L""; std::wstring m_pass_confirm = L"";
ISimpleTextureSource *m_tsrc;
}; };

@ -553,7 +553,7 @@ void GUIFormSpecMenu::parseCheckbox(parserData* data, const std::string &element
gui::IGUICheckBox *e = Environment->addCheckBox(fselected, rect, this, gui::IGUICheckBox *e = Environment->addCheckBox(fselected, rect, this,
spec.fid, spec.flabel.c_str()); spec.fid, spec.flabel.c_str());
auto style = getStyleForElement("checkbox", name); auto style = getDefaultStyleForElement("checkbox", name);
e->setNotClipped(style.getBool(StyleSpec::NOCLIP, false)); e->setNotClipped(style.getBool(StyleSpec::NOCLIP, false));
if (spec.fname == data->focused_fieldname) { 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, GUIScrollBar *e = new GUIScrollBar(Environment, this, spec.fid, rect,
is_horizontal, true); is_horizontal, true);
auto style = getStyleForElement("scrollbar", name); auto style = getDefaultStyleForElement("scrollbar", name);
e->setNotClipped(style.getBool(StyleSpec::NOCLIP, false)); e->setNotClipped(style.getBool(StyleSpec::NOCLIP, false));
e->setArrowsVisible(data->scrollbar_options.arrow_visiblity); 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); gui::IGUIImage *e = Environment->addImage(rect, this, spec.fid, 0, true);
e->setImage(texture); e->setImage(texture);
e->setScaleImage(true); 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)); e->setNotClipped(style.getBool(StyleSpec::NOCLIP, m_formspec_version < 3));
m_fields.push_back(spec); 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, gui::IGUIImage *e = Environment->addImage(texture, pos, true, this,
spec.fid, 0); 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)); e->setNotClipped(style.getBool(StyleSpec::NOCLIP, m_formspec_version < 3));
m_fields.push_back(spec); m_fields.push_back(spec);
@ -841,7 +841,7 @@ void GUIFormSpecMenu::parseAnimatedImage(parserData *data, const std::string &el
if (parts.size() >= 7) if (parts.size() >= 7)
e->setFrameIndex(stoi(parts[6]) - 1); 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->setNotClipped(style.getBool(StyleSpec::NOCLIP, false));
e->drop(); e->drop();
@ -888,7 +888,7 @@ void GUIFormSpecMenu::parseItemImage(parserData* data, const std::string &elemen
GUIItemImage *e = new GUIItemImage(Environment, this, spec.fid, GUIItemImage *e = new GUIItemImage(Environment, this, spec.fid,
core::rect<s32>(pos, pos + geom), name, m_font, m_client); 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)); e->setNotClipped(style.getBool(StyleSpec::NOCLIP, false));
// item images should let events through // item images should let events through
@ -949,10 +949,11 @@ void GUIFormSpecMenu::parseButton(parserData* data, const std::string &element,
if(type == "button_exit") if(type == "button_exit")
spec.is_exit = true; 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" : ""); auto style = getStyleForElement(type, name, (type != "button") ? "button" : "");
e->setFromStyle(style, m_tsrc); e->setStyles(style);
if (spec.fname == data->focused_fieldname) { if (spec.fname == data->focused_fieldname) {
Environment->setFocus(e); 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") if (!str_initial_selection.empty() && str_initial_selection != "0")
e->setSelected(stoi(str_initial_selection)); e->setSelected(stoi(str_initial_selection));
auto style = getStyleForElement("table", name); auto style = getDefaultStyleForElement("table", name);
e->setNotClipped(style.getBool(StyleSpec::NOCLIP, false)); e->setNotClipped(style.getBool(StyleSpec::NOCLIP, false));
m_tables.emplace_back(spec, e); 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") if (!str_initial_selection.empty() && str_initial_selection != "0")
e->setSelected(stoi(str_initial_selection)); e->setSelected(stoi(str_initial_selection));
auto style = getStyleForElement("textlist", name); auto style = getDefaultStyleForElement("textlist", name);
e->setNotClipped(style.getBool(StyleSpec::NOCLIP, false)); e->setNotClipped(style.getBool(StyleSpec::NOCLIP, false));
m_tables.emplace_back(spec, e); m_tables.emplace_back(spec, e);
@ -1306,7 +1307,7 @@ void GUIFormSpecMenu::parseDropDown(parserData* data, const std::string &element
if (!str_initial_selection.empty()) if (!str_initial_selection.empty())
e->setSelected(stoi(str_initial_selection)-1); e->setSelected(stoi(str_initial_selection)-1);
auto style = getStyleForElement("dropdown", name); auto style = getDefaultStyleForElement("dropdown", name);
e->setNotClipped(style.getBool(StyleSpec::NOCLIP, false)); e->setNotClipped(style.getBool(StyleSpec::NOCLIP, false));
m_fields.push_back(spec); m_fields.push_back(spec);
@ -1394,7 +1395,7 @@ void GUIFormSpecMenu::parsePwdField(parserData* data, const std::string &element
e->setPasswordBox(true,L'*'); e->setPasswordBox(true,L'*');
auto style = getStyleForElement("pwdfield", name, "field"); auto style = getDefaultStyleForElement("pwdfield", name, "field");
e->setNotClipped(style.getBool(StyleSpec::NOCLIP, false)); e->setNotClipped(style.getBool(StyleSpec::NOCLIP, false));
e->setDrawBorder(style.getBool(StyleSpec::BORDER, true)); e->setDrawBorder(style.getBool(StyleSpec::BORDER, true));
e->setOverrideColor(style.getColor(StyleSpec::TEXTCOLOR, video::SColor(0xFFFFFFFF))); 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 (e) {
if (is_editable && spec.fname == data->focused_fieldname) 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); spec.flabel.c_str(), rect, false, false, this, spec.fid);
e->setTextAlignment(gui::EGUIA_UPPERLEFT, gui::EGUIA_CENTER); 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->setNotClipped(style.getBool(StyleSpec::NOCLIP, false));
e->setOverrideColor(style.getColor(StyleSpec::TEXTCOLOR, video::SColor(0xFFFFFFFF))); 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); rect, false, false, this, spec.fid);
e->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_CENTER); 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->setNotClipped(style.getBool(StyleSpec::NOCLIP, false));
e->setOverrideColor(style.getColor(StyleSpec::TEXTCOLOR, video::SColor(0xFFFFFFFF))); 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_CHECKPOS("imagebutton",0);
MY_CHECKGEOM("imagebutton",1); MY_CHECKGEOM("imagebutton",1);
bool noclip = false;
bool drawborder = true;
std::string pressed_image_name; 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) { if (parts.size() >= 8) {
pressed_image_name = parts[7]; pressed_image_name = parts[7];
} }
@ -1911,35 +1903,30 @@ void GUIFormSpecMenu::parseImageButton(parserData* data, const std::string &elem
if (type == "image_button_exit") if (type == "image_button_exit")
spec.is_exit = true; 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) { if (spec.fname == data->focused_fieldname) {
Environment->setFocus(e); Environment->setFocus(e);
} }
auto style = getStyleForElement("image_button", spec.fname); auto style = getStyleForElement("image_button", spec.fname);
e->setFromStyle(style, m_tsrc);
// We explicitly handle these arguments *after* the style properties in // Override style properties with values specified directly in the element
// order to override them if they are provided
if (!image_name.empty()) if (!image_name.empty())
{ style[StyleSpec::STATE_DEFAULT].set(StyleSpec::FGIMG, image_name);
video::ITexture *texture = m_tsrc->getTexture(image_name);
e->setForegroundImage(guiScalingImageButton( if (!pressed_image_name.empty())
Environment->getVideoDriver(), texture, geom.X, geom.Y)); style[StyleSpec::STATE_PRESSED].set(StyleSpec::FGIMG, pressed_image_name);
}
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);
if (parts.size() >= 7) { if (parts.size() >= 7) {
e->setNotClipped(noclip); style[StyleSpec::STATE_DEFAULT].set(StyleSpec::NOCLIP, parts[5]);
e->setDrawBorder(drawborder); style[StyleSpec::STATE_DEFAULT].set(StyleSpec::BORDER, parts[6]);
} }
e->setStyles(style);
e->setScaleImage(true);
m_fields.push_back(spec); m_fields.push_back(spec);
return; return;
} }
@ -2033,7 +2020,7 @@ void GUIFormSpecMenu::parseTabHeader(parserData* data, const std::string &elemen
Environment->setFocus(e); Environment->setFocus(e);
} }
auto style = getStyleForElement("tabheader", name); auto style = getDefaultStyleForElement("tabheader", name);
e->setNotClipped(style.getBool(StyleSpec::NOCLIP, true)); e->setNotClipped(style.getBool(StyleSpec::NOCLIP, true));
for (const std::string &button : buttons) { for (const std::string &button : buttons) {
@ -2118,10 +2105,12 @@ void GUIFormSpecMenu::parseItemImageButton(parserData* data, const std::string &
2 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"); 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) { if (spec_btn.fname == data->focused_fieldname) {
Environment->setFocus(e_btn); 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); 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->setNotClipped(style.getBool(StyleSpec::NOCLIP, m_formspec_version < 3));
e->drop(); e->drop();
@ -2469,6 +2458,7 @@ bool GUIFormSpecMenu::parseStyle(parserData *data, const std::string &element, b
StyleSpec spec; StyleSpec spec;
// Parse properties
for (size_t i = 1; i < parts.size(); i++) { for (size_t i = 1; i < parts.size(); i++) {
size_t equal_pos = parts[i].find('='); size_t equal_pos = parts[i].find('=');
if (equal_pos == std::string::npos) { 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++) { for (size_t sel = 0; sel < selectors.size(); sel++) {
std::string selector = trim(selectors[sel]); std::string selector = trim(selectors[sel]);
if (selector.empty()) { // Copy the style properties to a new StyleSpec
errorstream << "Invalid style element (Empty selector): '" << element // This allows a separate state mask per-selector
<< "'" << std::endl; 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; continue;
} }
if (style_type) { if (style_type) {
theme_by_type[selector] |= spec; theme_by_type[selector].push_back(selector_spec);
} else { } 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 size.X / 2 - 70 + 140, pos.Y + m_btn_height * 2
); );
const wchar_t *text = wgettext("Proceed"); 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; delete[] text;
} }
} }
@ -4432,25 +4498,34 @@ std::wstring GUIFormSpecMenu::getLabelByID(s32 id)
return L""; 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) { 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()) { if (!parent_type.empty()) {
auto it = theme_by_type.find(parent_type); auto it = theme_by_type.find(parent_type);
if (it != theme_by_type.end()) { 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); auto it = theme_by_type.find(type);
if (it != theme_by_type.end()) { 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); it = theme_by_name.find(name);
if (it != theme_by_name.end()) { if (it != theme_by_name.end()) {
ret |= it->second; for (const StyleSpec &spec : it->second)
ret[(u32)spec.getState()] |= spec;
} }
return ret; return ret;

@ -274,11 +274,13 @@ protected:
v2s32 getRealCoordinateBasePos(const std::vector<std::string> &v_pos); v2s32 getRealCoordinateBasePos(const std::vector<std::string> &v_pos);
v2s32 getRealCoordinateGeometry(const std::vector<std::string> &v_geom); v2s32 getRealCoordinateGeometry(const std::vector<std::string> &v_geom);
std::unordered_map<std::string, StyleSpec> theme_by_type; std::unordered_map<std::string, std::vector<StyleSpec>> theme_by_type;
std::unordered_map<std::string, StyleSpec> theme_by_name; std::unordered_map<std::string, std::vector<StyleSpec>> theme_by_name;
std::unordered_set<std::string> property_warned; 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=""); const std::string &name="", const std::string &parent_type="");
v2s32 padding; v2s32 padding;

@ -82,8 +82,10 @@ enum
}; };
GUIKeyChangeMenu::GUIKeyChangeMenu(gui::IGUIEnvironment* env, GUIKeyChangeMenu::GUIKeyChangeMenu(gui::IGUIEnvironment* env,
gui::IGUIElement* parent, s32 id, IMenuManager *menumgr) : gui::IGUIElement* parent, s32 id, IMenuManager *menumgr,
GUIModalMenu(env, parent, id, menumgr) ISimpleTextureSource *tsrc) :
GUIModalMenu(env, parent, id, menumgr),
m_tsrc(tsrc)
{ {
init_keys(); init_keys();
} }
@ -157,7 +159,7 @@ void GUIKeyChangeMenu::regenerateGui(v2u32 screensize)
core::rect<s32> rect(0, 0, 100 * s, 30 * s); core::rect<s32> rect(0, 0, 100 * s, 30 * s);
rect += topleft + v2s32(offset.X + 150 * s, offset.Y - 5 * s); rect += topleft + v2s32(offset.X + 150 * s, offset.Y - 5 * s);
const wchar_t *text = wgettext(k->key.name()); 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; delete[] text;
} }
if ((i + 1) % KMaxButtonPerColumns == 0) { if ((i + 1) % KMaxButtonPerColumns == 0) {
@ -217,14 +219,14 @@ void GUIKeyChangeMenu::regenerateGui(v2u32 screensize)
core::rect<s32> rect(0, 0, 100 * s, 30 * s); core::rect<s32> rect(0, 0, 100 * s, 30 * s);
rect += topleft + v2s32(size.X / 2 - 105 * s, size.Y - 40 * s); rect += topleft + v2s32(size.X / 2 - 105 * s, size.Y - 40 * s);
const wchar_t *text = wgettext("Save"); 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; delete[] text;
} }
{ {
core::rect<s32> rect(0, 0, 100 * s, 30 * s); core::rect<s32> rect(0, 0, 100 * s, 30 * s);
rect += topleft + v2s32(size.X / 2 + 5 * s, size.Y - 40 * s); rect += topleft + v2s32(size.X / 2 + 5 * s, size.Y - 40 * s);
const wchar_t *text = wgettext("Cancel"); 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; delete[] text;
} }
} }

@ -28,6 +28,8 @@
#include <string> #include <string>
#include <vector> #include <vector>
class ISimpleTextureSource;
struct key_setting struct key_setting
{ {
int id; int id;
@ -41,7 +43,7 @@ class GUIKeyChangeMenu : public GUIModalMenu
{ {
public: public:
GUIKeyChangeMenu(gui::IGUIEnvironment *env, gui::IGUIElement *parent, s32 id, GUIKeyChangeMenu(gui::IGUIEnvironment *env, gui::IGUIElement *parent, s32 id,
IMenuManager *menumgr); IMenuManager *menumgr, ISimpleTextureSource *tsrc);
~GUIKeyChangeMenu(); ~GUIKeyChangeMenu();
void removeChildren(); void removeChildren();
@ -74,4 +76,5 @@ private:
key_setting *active_key = nullptr; key_setting *active_key = nullptr;
gui::IGUIStaticText *key_used_text = nullptr; gui::IGUIStaticText *key_used_text = nullptr;
std::vector<key_setting *> key_settings; std::vector<key_setting *> key_settings;
ISimpleTextureSource *m_tsrc;
}; };

@ -38,10 +38,12 @@ const int ID_cancel = 261;
GUIPasswordChange::GUIPasswordChange(gui::IGUIEnvironment* env, GUIPasswordChange::GUIPasswordChange(gui::IGUIEnvironment* env,
gui::IGUIElement* parent, s32 id, gui::IGUIElement* parent, s32 id,
IMenuManager *menumgr, IMenuManager *menumgr,
Client* client Client* client,
ISimpleTextureSource *tsrc
): ):
GUIModalMenu(env, parent, id, menumgr), 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); core::rect<s32> rect(0, 0, 100 * s, 30 * s);
rect = rect + v2s32(size.X / 4 + 56 * s, ypos); rect = rect + v2s32(size.X / 4 + 56 * s, ypos);
text = wgettext("Change"); text = wgettext("Change");
GUIButton::addButton(Environment, rect, this, ID_change, text); GUIButton::addButton(Environment, rect, m_tsrc, this, ID_change, text);
delete[] text; delete[] text;
} }
{ {
core::rect<s32> rect(0, 0, 100 * s, 30 * s); core::rect<s32> rect(0, 0, 100 * s, 30 * s);
rect = rect + v2s32(size.X / 4 + 185 * s, ypos); rect = rect + v2s32(size.X / 4 + 185 * s, ypos);
text = wgettext("Cancel"); text = wgettext("Cancel");
GUIButton::addButton(Environment, rect, this, ID_cancel, text); GUIButton::addButton(Environment, rect, m_tsrc, this, ID_cancel, text);
delete[] text; delete[] text;
} }

@ -23,12 +23,14 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include <string> #include <string>
class Client; class Client;
class ISimpleTextureSource;
class GUIPasswordChange : public GUIModalMenu class GUIPasswordChange : public GUIModalMenu
{ {
public: public:
GUIPasswordChange(gui::IGUIEnvironment *env, gui::IGUIElement *parent, s32 id, GUIPasswordChange(gui::IGUIEnvironment *env, gui::IGUIElement *parent, s32 id,
IMenuManager *menumgr, Client *client); IMenuManager *menumgr, Client *client,
ISimpleTextureSource *tsrc);
~GUIPasswordChange(); ~GUIPasswordChange();
void removeChildren(); void removeChildren();
@ -57,4 +59,5 @@ private:
std::wstring m_oldpass = L""; std::wstring m_oldpass = L"";
std::wstring m_newpass = L""; std::wstring m_newpass = L"";
std::wstring m_newpass_confirm = L""; std::wstring m_newpass_confirm = L"";
ISimpleTextureSource *m_tsrc;
}; };

@ -38,9 +38,10 @@ const int ID_soundMuteButton = 266;
GUIVolumeChange::GUIVolumeChange(gui::IGUIEnvironment* env, GUIVolumeChange::GUIVolumeChange(gui::IGUIEnvironment* env,
gui::IGUIElement* parent, s32 id, 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); core::rect<s32> rect(0, 0, 80 * s, 30 * s);
rect = rect + v2s32(size.X / 2 - 80 * s / 2, size.Y / 2 + 55 * s); rect = rect + v2s32(size.X / 2 - 80 * s / 2, size.Y / 2 + 55 * s);
const wchar_t *text = wgettext("Exit"); 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; delete[] text;
} }
{ {

@ -23,12 +23,14 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include "modalMenu.h" #include "modalMenu.h"
#include <string> #include <string>
class ISimpleTextureSource;
class GUIVolumeChange : public GUIModalMenu class GUIVolumeChange : public GUIModalMenu
{ {
public: public:
GUIVolumeChange(gui::IGUIEnvironment* env, GUIVolumeChange(gui::IGUIEnvironment* env,
gui::IGUIElement* parent, s32 id, gui::IGUIElement* parent, s32 id,
IMenuManager *menumgr); IMenuManager *menumgr, ISimpleTextureSource *tsrc);
~GUIVolumeChange(); ~GUIVolumeChange();
void removeChildren(); void removeChildren();
@ -46,4 +48,7 @@ public:
protected: protected:
std::wstring getLabelByID(s32 id) { return L""; } std::wstring getLabelByID(s32 id) { return L""; }
std::string getNameByID(s32 id) { return ""; } std::string getNameByID(s32 id) { return ""; }
private:
ISimpleTextureSource *m_tsrc;
}; };

@ -571,9 +571,10 @@ int ModApiMainMenu::l_show_keys_menu(lua_State *L)
sanity_check(engine != NULL); sanity_check(engine != NULL);
GUIKeyChangeMenu *kmenu = new GUIKeyChangeMenu(RenderingEngine::get_gui_env(), GUIKeyChangeMenu *kmenu = new GUIKeyChangeMenu(RenderingEngine::get_gui_env(),
engine->m_parent, engine->m_parent,
-1, -1,
engine->m_menumanager); engine->m_menumanager,
engine->m_texture_source);
kmenu->drop(); kmenu->drop();
return 0; return 0;
} }
@ -904,12 +905,12 @@ int ModApiMainMenu::l_show_path_select_dialog(lua_State *L)
GUIFileSelectMenu* fileOpenMenu = GUIFileSelectMenu* fileOpenMenu =
new GUIFileSelectMenu(RenderingEngine::get_gui_env(), new GUIFileSelectMenu(RenderingEngine::get_gui_env(),
engine->m_parent, engine->m_parent,
-1, -1,
engine->m_menumanager, engine->m_menumanager,
title, title,
formname, formname,
is_file_select); is_file_select);
fileOpenMenu->setTextDest(engine->m_buttonhandler); fileOpenMenu->setTextDest(engine->m_buttonhandler);
fileOpenMenu->drop(); fileOpenMenu->drop();
return 0; return 0;

@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "irr_v2d.h" #include "irr_v2d.h"
#include "irr_v3d.h" #include "irr_v3d.h"
#include "irr_aabb3d.h" #include "irr_aabb3d.h"
#include "SColor.h"
#include <matrix4.h> #include <matrix4.h>
#define rangelim(d, min, max) ((d) < (min) ? (min) : ((d) > (max) ? (max) : (d))) #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; 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));
}