aboutsummaryrefslogtreecommitdiff
path: root/src/gui
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui')
-rw-r--r--src/gui/CMakeLists.txt1
-rw-r--r--src/gui/StyleSpec.h119
-rw-r--r--src/gui/guiButton.cpp204
-rw-r--r--src/gui/guiButton.h36
-rw-r--r--src/gui/guiButtonImage.cpp107
-rw-r--r--src/gui/guiButtonImage.h28
-rw-r--r--src/gui/guiButtonItemImage.cpp15
-rw-r--r--src/gui/guiButtonItemImage.h11
-rw-r--r--src/gui/guiChatConsole.cpp4
-rw-r--r--src/gui/guiConfirmRegistration.cpp8
-rw-r--r--src/gui/guiConfirmRegistration.h4
-rw-r--r--src/gui/guiEngine.cpp4
-rw-r--r--src/gui/guiFormSpecMenu.cpp508
-rw-r--r--src/gui/guiFormSpecMenu.h14
-rw-r--r--src/gui/guiHyperText.cpp20
-rw-r--r--src/gui/guiHyperText.h2
-rw-r--r--src/gui/guiInventoryList.cpp42
-rw-r--r--src/gui/guiInventoryList.h5
-rw-r--r--src/gui/guiKeyChangeMenu.cpp12
-rw-r--r--src/gui/guiKeyChangeMenu.h5
-rw-r--r--src/gui/guiPasswordChange.cpp10
-rw-r--r--src/gui/guiPasswordChange.h5
-rw-r--r--src/gui/guiScrollContainer.cpp70
-rw-r--r--src/gui/guiScrollContainer.h60
-rw-r--r--src/gui/guiVolumeChange.cpp7
-rw-r--r--src/gui/guiVolumeChange.h7
-rw-r--r--src/gui/modalMenu.cpp59
-rw-r--r--src/gui/touchscreengui.cpp421
-rw-r--r--src/gui/touchscreengui.h55
29 files changed, 1081 insertions, 762 deletions
diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt
index 110a00595..147f445f4 100644
--- a/src/gui/CMakeLists.txt
+++ b/src/gui/CMakeLists.txt
@@ -16,6 +16,7 @@ set(gui_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/guiPasswordChange.cpp
${CMAKE_CURRENT_SOURCE_DIR}/guiPathSelectMenu.cpp
${CMAKE_CURRENT_SOURCE_DIR}/guiScrollBar.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/guiScrollContainer.cpp
${CMAKE_CURRENT_SOURCE_DIR}/guiSkin.cpp
${CMAKE_CURRENT_SOURCE_DIR}/guiTable.cpp
${CMAKE_CURRENT_SOURCE_DIR}/guiHyperText.cpp
diff --git a/src/gui/StyleSpec.h b/src/gui/StyleSpec.h
index 999c1d237..3e842e826 100644
--- a/src/gui/StyleSpec.h
+++ b/src/gui/StyleSpec.h
@@ -18,6 +18,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
*/
#include "client/tile.h" // ITextureSource
+#include "debug.h"
#include "irrlichttypes_extrabloated.h"
#include "util/string.h"
#include <array>
@@ -31,25 +32,36 @@ public:
{
TEXTCOLOR,
BGCOLOR,
- BGCOLOR_HOVERED,
- BGCOLOR_PRESSED,
+ BGCOLOR_HOVERED, // Note: Deprecated property
+ BGCOLOR_PRESSED, // Note: Deprecated property
NOCLIP,
BORDER,
BGIMG,
- BGIMG_HOVERED,
+ BGIMG_HOVERED, // Note: Deprecated property
BGIMG_MIDDLE,
- BGIMG_PRESSED,
+ BGIMG_PRESSED, // Note: Deprecated property
FGIMG,
- FGIMG_HOVERED,
- FGIMG_PRESSED,
+ FGIMG_HOVERED, // Note: Deprecated property
+ FGIMG_PRESSED, // Note: Deprecated property
ALPHA,
+ CONTENT_OFFSET,
+ PADDING,
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)
@@ -82,6 +94,10 @@ public:
return FGIMG_PRESSED;
} else if (name == "alpha") {
return ALPHA;
+ } else if (name == "content_offset") {
+ return CONTENT_OFFSET;
+ } else if (name == "padding") {
+ return PADDING;
} else {
return NONE;
}
@@ -99,6 +115,49 @@ public:
property_set[prop] = true;
}
+ //! Parses a name and returns the corresponding state enum
+ static State getStateByName(const std::string &name)
+ {
+ if (name == "default") {
+ return STATE_DEFAULT;
+ } else if (name == "hovered") {
+ return STATE_HOVERED;
+ } else if (name == "pressed") {
+ return STATE_PRESSED;
+ } else {
+ return STATE_INVALID;
+ }
+ }
+
+ //! Gets the state that this style is intended for
+ State getState() const
+ {
+ return state_map;
+ }
+
+ //! Set the given state on this style
+ void addState(State state)
+ {
+ FATAL_ERROR_IF(state >= NUM_STATES, "Out-of-bounds state received");
+
+ state_map = static_cast<State>(state_map | state);
+ }
+
+ //! Using a list of styles mapped to state values, calculate the final
+ // combined style for a state by propagating values in its component states
+ static StyleSpec getStyleFromStatePropagation(const std::array<StyleSpec, NUM_STATES> &styles, State state)
+ {
+ StyleSpec temp = styles[StyleSpec::STATE_DEFAULT];
+ temp.state_map = state;
+ for (int i = StyleSpec::STATE_DEFAULT + 1; i <= state; i++) {
+ if ((state & i) != 0) {
+ temp = temp | styles[i];
+ }
+ }
+
+ return temp;
+ }
+
video::SColor getColor(Property prop, video::SColor def) const
{
const auto &val = properties[prop];
@@ -143,6 +202,29 @@ public:
return rect;
}
+ irr::core::vector2d<s32> getVector2i(Property prop, irr::core::vector2d<s32> def) const
+ {
+ const auto &val = properties[prop];
+ if (val.empty())
+ return def;
+
+ irr::core::vector2d<s32> vec;
+ if (!parseVector2i(val, &vec))
+ return def;
+
+ return vec;
+ }
+
+ irr::core::vector2d<s32> getVector2i(Property prop) const
+ {
+ const auto &val = properties[prop];
+ FATAL_ERROR_IF(val.empty(), "Unexpected missing property");
+
+ irr::core::vector2d<s32> vec;
+ parseVector2i(val, &vec);
+ return vec;
+ }
+
video::ITexture *getTexture(Property prop, ISimpleTextureSource *tsrc,
video::ITexture *def) const
{
@@ -233,4 +315,29 @@ private:
return true;
}
+
+ bool parseVector2i(const std::string &value, irr::core::vector2d<s32> *parsed_vec) const
+ {
+ irr::core::vector2d<s32> vec;
+ std::vector<std::string> v_vector = split(value, ',');
+
+ if (v_vector.size() == 1) {
+ s32 x = stoi(v_vector[0]);
+ vec.X = x;
+ vec.Y = x;
+ } else if (v_vector.size() == 2) {
+ s32 x = stoi(v_vector[0]);
+ s32 y = stoi(v_vector[1]);
+ vec.X = x;
+ vec.Y = y;
+ } else {
+ warningstream << "Invalid vector2d string format: \"" << value
+ << "\"" << std::endl;
+ return false;
+ }
+
+ *parsed_vec = vec;
+
+ return true;
+ }
};
diff --git a/src/gui/guiButton.cpp b/src/gui/guiButton.cpp
index 4c16ee237..6732a9233 100644
--- a/src/gui/guiButton.cpp
+++ b/src/gui/guiButton.cpp
@@ -14,6 +14,7 @@
#include "irrlicht_changes/static_text.h"
#include "porting.h"
#include "StyleSpec.h"
+#include "util/numeric.h"
using namespace irr;
using namespace gui;
@@ -26,14 +27,15 @@ using namespace gui;
//! constructor
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),
SpriteBank(0), OverrideFont(0),
OverrideColorEnabled(false), OverrideColor(video::SColor(101,255,255,255)),
ClickTime(0), HoverTime(0), FocusTime(0),
ClickShiftState(false), ClickControlState(false),
IsPushButton(false), Pressed(false),
- UseAlphaChannel(false), DrawBorder(true), ScaleImage(false)
+ UseAlphaChannel(false), DrawBorder(true), ScaleImage(false), TSrc(tsrc)
{
setNotClipped(noclip);
@@ -44,14 +46,6 @@ GUIButton::GUIButton(IGUIEnvironment* environment, IGUIElement* parent,
// PATCH
for (size_t i = 0; i < 4; 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->setTextAlignment(EGUIA_CENTER, EGUIA_CENTER);
@@ -262,6 +256,13 @@ void GUIButton::draw()
return;
// 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());
video::IVideoDriver* driver = Environment->getVideoDriver();
// END PATCH
@@ -271,21 +272,24 @@ void GUIButton::draw()
if (!Pressed)
{
// PATCH
- skin->drawColored3DButtonPaneStandard(this, AbsoluteRect, &AbsoluteClippingRect,
- isHovered() ? HoveredColors : Colors);
+ skin->drawColored3DButtonPaneStandard(this, AbsoluteRect,
+ &AbsoluteClippingRect, Colors);
// END PATCH
}
else
{
// PATCH
- skin->drawColored3DButtonPanePressed(this,
- AbsoluteRect, &AbsoluteClippingRect, PressedColors);
+ skin->drawColored3DButtonPanePressed(this, AbsoluteRect,
+ &AbsoluteClippingRect, Colors);
// END PATCH
}
}
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 )
{
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);
}
-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
void GUIButton::setText(const wchar_t* text)
{
@@ -600,24 +592,7 @@ void GUIButton::setPressed(bool pressed)
{
ClickTime = porting::getTimeMs();
Pressed = pressed;
-
- GUISkin* skin = dynamic_cast<GUISkin*>(Environment->getSkin());
-
- for(IGUIElement *child : getChildren())
- {
- core::rect<s32> originalRect = child->getRelativePosition();
- if (Pressed) {
- child->setRelativePosition(originalRect +
- core::dimension2d<s32>(
- skin->getSize(irr::gui::EGDS_BUTTON_PRESSED_IMAGE_OFFSET_X),
- skin->getSize(irr::gui::EGDS_BUTTON_PRESSED_IMAGE_OFFSET_Y)));
- } else {
- child->setRelativePosition(originalRect -
- core::dimension2d<s32>(
- skin->getSize(irr::gui::EGDS_BUTTON_PRESSED_IMAGE_OFFSET_X),
- skin->getSize(irr::gui::EGDS_BUTTON_PRESSED_IMAGE_OFFSET_Y)));
- }
- }
+ setFromState();
}
}
@@ -729,10 +704,12 @@ void GUIButton::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWri
}
// PATCH
-GUIButton* GUIButton::addButton(IGUIEnvironment *environment, const core::rect<s32>& rectangle,
- IGUIElement* parent, s32 id, const wchar_t* text, const wchar_t *tooltiptext)
+GUIButton* GUIButton::addButton(IGUIEnvironment *environment,
+ 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)
button->setText(text);
@@ -749,76 +726,111 @@ void GUIButton::setColor(video::SColor color)
for (size_t i = 0; i < 4; i++) {
video::SColor base = Environment->getSkin()->getColor((gui::EGUI_DEFAULT_COLOR)i);
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)
+
+//! Set element properties from a StyleSpec corresponding to the button state
+void GUIButton::setFromState()
{
- 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);
- }
+ 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, ISimpleTextureSource *tsrc)
+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)) {
+
setColor(style.getColor(StyleSpec::BGCOLOR));
- }
- if (style.isNotDefault(StyleSpec::BGCOLOR_HOVERED)) {
- setHoveredColor(style.getColor(StyleSpec::BGCOLOR_HOVERED));
- }
- if (style.isNotDefault(StyleSpec::BGCOLOR_PRESSED)) {
- setPressedColor(style.getColor(StyleSpec::BGCOLOR_PRESSED));
+
+ // If we have a propagated hover/press color, we need to automatically
+ // lighten/darken it
+ if (!Styles[style.getState()].isNotDefault(StyleSpec::BGCOLOR)) {
+ for (size_t i = 0; i < 4; i++) {
+ 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)) {
setOverrideColor(style.getColor(StyleSpec::TEXTCOLOR));
+ } else {
+ setOverrideColor(video::SColor(255,255,255,255));
+ OverrideColorEnabled = false;
}
- setNotClipped(style.getBool(StyleSpec::NOCLIP, isNotClipped()));
- setDrawBorder(style.getBool(StyleSpec::BORDER, DrawBorder));
+ setNotClipped(style.getBool(StyleSpec::NOCLIP, false));
+ setDrawBorder(style.getBool(StyleSpec::BORDER, true));
setUseAlphaChannel(style.getBool(StyleSpec::ALPHA, true));
- const core::position2di buttonCenter(AbsoluteRect.getCenter());
- core::position2d<s32> geom(buttonCenter);
if (style.isNotDefault(StyleSpec::BGIMG)) {
- video::ITexture *texture = style.getTexture(StyleSpec::BGIMG, tsrc);
-
+ video::ITexture *texture = style.getTexture(StyleSpec::BGIMG,
+ getTextureSource());
setImage(guiScalingImageButton(
- Environment->getVideoDriver(), texture, geom.X, geom.Y));
+ Environment->getVideoDriver(), texture,
+ AbsoluteRect.getWidth(), AbsoluteRect.getHeight()));
setScaleImage(true);
+ } else {
+ setImage(nullptr);
}
- 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);
+ BgMiddle = style.getRect(StyleSpec::BGIMG_MIDDLE, BgMiddle);
- setPressedImage(guiScalingImageButton(
- Environment->getVideoDriver(), pressed_texture, geom.X, geom.Y));
- setScaleImage(true);
+ // Child padding and offset
+ Padding = style.getRect(StyleSpec::PADDING, core::rect<s32>());
+ Padding = core::rect<s32>(
+ Padding.UpperLeftCorner + BgMiddle.UpperLeftCorner,
+ Padding.LowerRightCorner + BgMiddle.LowerRightCorner);
+
+ GUISkin* skin = dynamic_cast<GUISkin*>(Environment->getSkin());
+ core::vector2d<s32> defaultPressOffset(
+ skin->getSize(irr::gui::EGDS_BUTTON_PRESSED_IMAGE_OFFSET_X),
+ skin->getSize(irr::gui::EGDS_BUTTON_PRESSED_IMAGE_OFFSET_Y));
+ ContentOffset = style.getVector2i(StyleSpec::CONTENT_OFFSET, isPressed()
+ ? defaultPressOffset
+ : core::vector2d<s32>(0));
+
+ core::rect<s32> childBounds(
+ Padding.UpperLeftCorner.X + ContentOffset.X,
+ Padding.UpperLeftCorner.Y + ContentOffset.Y,
+ AbsoluteRect.getWidth() + Padding.LowerRightCorner.X + ContentOffset.X,
+ AbsoluteRect.getHeight() + Padding.LowerRightCorner.Y + ContentOffset.Y);
+
+ for (IGUIElement *child : getChildren()) {
+ child->setRelativePosition(childBounds);
}
- 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
diff --git a/src/gui/guiButton.h b/src/gui/guiButton.h
index 3d1f98c32..95fa1a2a1 100644
--- a/src/gui/guiButton.h
+++ b/src/gui/guiButton.h
@@ -13,6 +13,7 @@
#include "ITexture.h"
#include "SColor.h"
#include "guiSkin.h"
+#include "StyleSpec.h"
using namespace irr;
@@ -67,7 +68,6 @@ using namespace irr;
#endif
class ISimpleTextureSource;
-class StyleSpec;
class GUIButton : public gui::IGUIButton
{
@@ -75,7 +75,8 @@ public:
//! constructor
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
virtual ~GUIButton();
@@ -125,16 +126,10 @@ public:
//! 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;
- //! 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
virtual void setText(const wchar_t* text) override;
// 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
virtual void setSpriteBank(gui::IGUISpriteBank* bank=0) override;
@@ -225,22 +220,29 @@ public:
void setColor(video::SColor color);
// PATCH
- void setHoveredColor(video::SColor color);
- void setPressedColor(video::SColor color);
+ //! Set element properties from a StyleSpec corresponding to the button state
+ void setFromState();
//! 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
//! Do not drop returned handle
- static GUIButton* addButton(gui::IGUIEnvironment *environment, const core::rect<s32>& rectangle,
- IGUIElement* parent, s32 id, const wchar_t* text, const wchar_t *tooltiptext=L"");
+ static GUIButton* addButton(gui::IGUIEnvironment *environment,
+ const core::rect<s32>& rectangle, ISimpleTextureSource *tsrc,
+ IGUIElement* parent, s32 id, const wchar_t* text,
+ const wchar_t *tooltiptext=L"");
protected:
void drawSprite(gui::EGUI_BUTTON_STATE state, u32 startTime, const core::position2di& center);
gui::EGUI_BUTTON_IMAGE_STATE getImageState(bool pressed) const;
+ ISimpleTextureSource *getTextureSource() { return TSrc; }
+
struct ButtonImage
{
ButtonImage() : Texture(0), SourceRect(core::rect<s32>(0,0,0,0))
@@ -308,6 +310,8 @@ private:
ButtonImage ButtonImages[gui::EGBIS_COUNT];
+ std::array<StyleSpec, StyleSpec::NUM_STATES> Styles;
+
gui::IGUIFont* OverrideFont;
bool OverrideColorEnabled;
@@ -326,11 +330,13 @@ private:
video::SColor Colors[4];
// PATCH
- video::SColor HoveredColors[4];
- video::SColor PressedColors[4];
+ bool WasHovered = false;
+ ISimpleTextureSource *TSrc;
gui::IGUIStaticText *StaticText;
core::rect<s32> BgMiddle;
+ core::rect<s32> Padding;
+ core::vector2d<s32> ContentOffset;
// END PATCH
};
diff --git a/src/gui/guiButtonImage.cpp b/src/gui/guiButtonImage.cpp
index 02d920277..b507ffece 100644
--- a/src/gui/guiButtonImage.cpp
+++ b/src/gui/guiButtonImage.cpp
@@ -30,8 +30,9 @@ using namespace irr;
using namespace gui;
GUIButtonImage::GUIButtonImage(gui::IGUIEnvironment *environment,
- gui::IGUIElement *parent, s32 id, core::rect<s32> rectangle, bool noclip)
- : GUIButton (environment, parent, id, rectangle, noclip)
+ gui::IGUIElement *parent, s32 id, core::rect<s32> rectangle,
+ ISimpleTextureSource *tsrc, bool noclip)
+ : GUIButton (environment, parent, id, rectangle, tsrc, noclip)
{
m_image = Environment->addImage(
core::rect<s32>(0,0,rectangle.getWidth(),rectangle.getHeight()), this);
@@ -39,100 +40,37 @@ GUIButtonImage::GUIButtonImage(gui::IGUIEnvironment *environment,
sendToBack(m_image);
}
-bool GUIButtonImage::OnEvent(const SEvent& event)
-{
- bool result = GUIButton::OnEvent(event);
-
- EGUI_BUTTON_IMAGE_STATE imageState = getImageState(isPressed(), m_foreground_images);
- video::ITexture *texture = m_foreground_images[(u32)imageState].Texture;
- if (texture != nullptr)
- {
- m_image->setImage(texture);
- }
-
- m_image->setVisible(texture != nullptr);
-
- return result;
-}
-
-void GUIButtonImage::setForegroundImage(EGUI_BUTTON_IMAGE_STATE state,
- video::ITexture *image, const core::rect<s32> &sourceRect)
+void GUIButtonImage::setForegroundImage(video::ITexture *image)
{
- if (state >= EGBIS_COUNT)
+ if (image == m_foreground_image)
return;
- if (image)
+ if (image != nullptr)
image->grab();
- u32 stateIdx = (u32)state;
- if (m_foreground_images[stateIdx].Texture)
- m_foreground_images[stateIdx].Texture->drop();
-
- m_foreground_images[stateIdx].Texture = image;
- m_foreground_images[stateIdx].SourceRect = sourceRect;
-
- EGUI_BUTTON_IMAGE_STATE imageState = getImageState(isPressed(), m_foreground_images);
- if (imageState == stateIdx)
- m_image->setImage(image);
-}
-
-void GUIButtonImage::setForegroundImage(video::ITexture *image)
-{
- setForegroundImage(gui::EGBIS_IMAGE_UP, image);
-}
-
-void GUIButtonImage::setForegroundImage(video::ITexture *image, const core::rect<s32> &pos)
-{
- setForegroundImage(gui::EGBIS_IMAGE_UP, image, pos);
-}
-
-void GUIButtonImage::setPressedForegroundImage(video::ITexture *image)
-{
- setForegroundImage(gui::EGBIS_IMAGE_DOWN, image);
-}
+ if (m_foreground_image != nullptr)
+ m_foreground_image->drop();
-void GUIButtonImage::setPressedForegroundImage(video::ITexture *image, const core::rect<s32> &pos)
-{
- setForegroundImage(gui::EGBIS_IMAGE_DOWN, image, pos);
+ m_foreground_image = image;
+ m_image->setImage(image);
}
-void GUIButtonImage::setHoveredForegroundImage(video::ITexture *image)
+//! Set element properties from a StyleSpec
+void GUIButtonImage::setFromStyle(const StyleSpec& style)
{
- setForegroundImage(gui::EGBIS_IMAGE_UP_MOUSEOVER, image);
- setForegroundImage(gui::EGBIS_IMAGE_UP_FOCUSED_MOUSEOVER, image);
-}
-
-void GUIButtonImage::setHoveredForegroundImage(video::ITexture *image, const core::rect<s32> &pos)
-{
- setForegroundImage(gui::EGBIS_IMAGE_UP_MOUSEOVER, image, pos);
- setForegroundImage(gui::EGBIS_IMAGE_UP_FOCUSED_MOUSEOVER, image, pos);
-}
-
-void GUIButtonImage::setFromStyle(const StyleSpec &style, ISimpleTextureSource *tsrc)
-{
- GUIButton::setFromStyle(style, tsrc);
+ GUIButton::setFromStyle(style);
video::IVideoDriver *driver = Environment->getVideoDriver();
- const core::position2di buttonCenter(AbsoluteRect.getCenter());
- core::position2d<s32> geom(buttonCenter);
if (style.isNotDefault(StyleSpec::FGIMG)) {
- video::ITexture *texture = style.getTexture(StyleSpec::FGIMG, tsrc);
-
- 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);
+ video::ITexture *texture = style.getTexture(StyleSpec::FGIMG,
+ getTextureSource());
- setPressedForegroundImage(guiScalingImageButton(driver, pressed_texture, geom.X, geom.Y));
+ setForegroundImage(guiScalingImageButton(driver, texture,
+ AbsoluteRect.getWidth(), AbsoluteRect.getHeight()));
setScaleImage(true);
+ } else {
+ setForegroundImage(nullptr);
}
}
@@ -143,11 +81,12 @@ void GUIButtonImage::setScaleImage(bool scaleImage)
}
GUIButtonImage *GUIButtonImage::addButton(IGUIEnvironment *environment,
- const core::rect<s32> &rectangle, IGUIElement *parent, s32 id,
- const wchar_t *text, const wchar_t *tooltiptext)
+ const core::rect<s32> &rectangle, ISimpleTextureSource *tsrc,
+ IGUIElement *parent, s32 id, const wchar_t *text,
+ const wchar_t *tooltiptext)
{
GUIButtonImage *button = new GUIButtonImage(environment,
- parent ? parent : environment->getRootGUIElement(), id, rectangle);
+ parent ? parent : environment->getRootGUIElement(), id, rectangle, tsrc);
if (text)
button->setText(text);
diff --git a/src/gui/guiButtonImage.h b/src/gui/guiButtonImage.h
index 15901ee5d..59a25b4f0 100644
--- a/src/gui/guiButtonImage.h
+++ b/src/gui/guiButtonImage.h
@@ -17,6 +17,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+#pragma once
+
#include "guiButton.h"
#include "IGUIButton.h"
@@ -27,33 +29,23 @@ class GUIButtonImage : public GUIButton
public:
//! constructor
GUIButtonImage(gui::IGUIEnvironment *environment, gui::IGUIElement *parent,
- s32 id, core::rect<s32> rectangle, bool noclip = false);
-
- virtual bool OnEvent(const SEvent& event) override;
-
- void setForegroundImage(gui::EGUI_BUTTON_IMAGE_STATE state,
- video::ITexture *image = nullptr,
- const core::rect<s32> &sourceRect = core::rect<s32>(0, 0, 0, 0));
+ s32 id, core::rect<s32> rectangle, ISimpleTextureSource *tsrc,
+ bool noclip = false);
void setForegroundImage(video::ITexture *image = nullptr);
- void setForegroundImage(video::ITexture *image, const core::rect<s32> &pos);
-
- void setPressedForegroundImage(video::ITexture *image = nullptr);
- void setPressedForegroundImage(video::ITexture *image, const core::rect<s32> &pos);
-
- void setHoveredForegroundImage(video::ITexture *image = nullptr);
- void setHoveredForegroundImage(video::ITexture *image, const core::rect<s32> &pos);
- virtual void setFromStyle(const StyleSpec &style, ISimpleTextureSource *tsrc) override;
+ //! Set element properties from a StyleSpec
+ virtual void setFromStyle(const StyleSpec& style) override;
virtual void setScaleImage(bool scaleImage=true) override;
//! Do not drop returned handle
static GUIButtonImage *addButton(gui::IGUIEnvironment *environment,
- const core::rect<s32> &rectangle, IGUIElement *parent, s32 id,
- const wchar_t *text, const wchar_t *tooltiptext = L"");
+ const core::rect<s32> &rectangle, ISimpleTextureSource *tsrc,
+ IGUIElement *parent, s32 id, const wchar_t *text,
+ const wchar_t *tooltiptext = L"");
private:
- ButtonImage m_foreground_images[gui::EGBIS_COUNT];
+ video::ITexture *m_foreground_image = nullptr;
gui::IGUIImage *m_image;
};
diff --git a/src/gui/guiButtonItemImage.cpp b/src/gui/guiButtonItemImage.cpp
index 5c48b2acd..d8b9042ac 100644
--- a/src/gui/guiButtonItemImage.cpp
+++ b/src/gui/guiButtonItemImage.cpp
@@ -28,9 +28,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
using namespace irr;
using namespace gui;
-GUIButtonItemImage::GUIButtonItemImage(gui::IGUIEnvironment *environment, gui::IGUIElement *parent,
- s32 id, core::rect<s32> rectangle, std::string item, Client *client, bool noclip)
- : GUIButton (environment, parent, id, rectangle, noclip)
+GUIButtonItemImage::GUIButtonItemImage(gui::IGUIEnvironment *environment,
+ gui::IGUIElement *parent, s32 id, core::rect<s32> rectangle,
+ ISimpleTextureSource *tsrc, std::string item, Client *client,
+ bool noclip)
+ : GUIButton (environment, parent, id, rectangle, tsrc, noclip)
{
m_image = new GUIItemImage(environment, this, id,
core::rect<s32>(0,0,rectangle.getWidth(),rectangle.getHeight()),
@@ -42,12 +44,13 @@ GUIButtonItemImage::GUIButtonItemImage(gui::IGUIEnvironment *environment, gui::I
}
GUIButtonItemImage *GUIButtonItemImage::addButton(IGUIEnvironment *environment,
- const core::rect<s32> &rectangle, IGUIElement *parent, s32 id,
- const wchar_t *text, std::string item, Client *client)
+ const core::rect<s32> &rectangle, ISimpleTextureSource *tsrc,
+ IGUIElement *parent, s32 id, const wchar_t *text, std::string item,
+ Client *client)
{
GUIButtonItemImage *button = new GUIButtonItemImage(environment,
parent ? parent : environment->getRootGUIElement(),
- id, rectangle, item, client);
+ id, rectangle, tsrc, item, client);
if (text)
button->setText(text);
diff --git a/src/gui/guiButtonItemImage.h b/src/gui/guiButtonItemImage.h
index 0a61874da..aad923bda 100644
--- a/src/gui/guiButtonItemImage.h
+++ b/src/gui/guiButtonItemImage.h
@@ -17,6 +17,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+#pragma once
+
#include "guiButton.h"
#include "IGUIButton.h"
@@ -30,13 +32,14 @@ class GUIButtonItemImage : public GUIButton
public:
//! constructor
GUIButtonItemImage(gui::IGUIEnvironment *environment, gui::IGUIElement *parent,
- s32 id, core::rect<s32> rectangle, std::string item,
- Client *client, bool noclip = false);
+ s32 id, core::rect<s32> rectangle, ISimpleTextureSource *tsrc,
+ std::string item, Client *client, bool noclip = false);
//! Do not drop returned handle
static GUIButtonItemImage *addButton(gui::IGUIEnvironment *environment,
- const core::rect<s32> &rectangle, IGUIElement *parent, s32 id,
- const wchar_t *text, std::string item, Client *client);
+ const core::rect<s32> &rectangle, ISimpleTextureSource *tsrc,
+ IGUIElement *parent, s32 id, const wchar_t *text, std::string item,
+ Client *client);
private:
std::string m_item_name;
diff --git a/src/gui/guiChatConsole.cpp b/src/gui/guiChatConsole.cpp
index e67fae3c6..8de00c12f 100644
--- a/src/gui/guiChatConsole.cpp
+++ b/src/gui/guiChatConsole.cpp
@@ -74,7 +74,9 @@ GUIChatConsole::GUIChatConsole(
m_background_color.setBlue(clamp_u8(myround(console_color.Z)));
}
- m_font = g_fontengine->getFont(FONT_SIZE_UNSPECIFIED, FM_Mono);
+ u16 chat_font_size = g_settings->getU16("chat_font_size");
+ m_font = g_fontengine->getFont(chat_font_size != 0 ?
+ chat_font_size : FONT_SIZE_UNSPECIFIED, FM_Mono);
if (!m_font) {
errorstream << "GUIChatConsole: Unable to load mono font" << std::endl;
diff --git a/src/gui/guiConfirmRegistration.cpp b/src/gui/guiConfirmRegistration.cpp
index 0d8bdf54e..58ac42740 100644
--- a/src/gui/guiConfirmRegistration.cpp
+++ b/src/gui/guiConfirmRegistration.cpp
@@ -40,10 +40,10 @@ const int ID_message = 266;
GUIConfirmRegistration::GUIConfirmRegistration(gui::IGUIEnvironment *env,
gui::IGUIElement *parent, s32 id, IMenuManager *menumgr, Client *client,
const std::string &playername, const std::string &password,
- bool *aborted) :
+ bool *aborted, ISimpleTextureSource *tsrc) :
GUIModalMenu(env, parent, id, menumgr),
m_client(client), m_playername(playername), m_password(password),
- m_aborted(aborted)
+ m_aborted(aborted), m_tsrc(tsrc)
{
#ifdef __ANDROID__
m_touchscreen_visible = false;
@@ -130,14 +130,14 @@ void GUIConfirmRegistration::regenerateGui(v2u32 screensize)
core::rect<s32> rect2(0, 0, 230 * s, 35 * s);
rect2 = rect2 + v2s32(size.X / 2 - 220 * s, ypos);
text = wgettext("Register and Join");
- GUIButton::addButton(Environment, rect2, this, ID_confirm, text);
+ GUIButton::addButton(Environment, rect2, m_tsrc, this, ID_confirm, text);
delete[] text;
}
{
core::rect<s32> rect2(0, 0, 120 * s, 35 * s);
rect2 = rect2 + v2s32(size.X / 2 + 70 * s, ypos);
text = wgettext("Cancel");
- GUIButton::addButton(Environment, rect2, this, ID_cancel, text);
+ GUIButton::addButton(Environment, rect2, m_tsrc, this, ID_cancel, text);
delete[] text;
}
{
diff --git a/src/gui/guiConfirmRegistration.h b/src/gui/guiConfirmRegistration.h
index 42c07e4ed..d8387201d 100644
--- a/src/gui/guiConfirmRegistration.h
+++ b/src/gui/guiConfirmRegistration.h
@@ -25,6 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <string>
class Client;
+class ISimpleTextureSource;
class GUIConfirmRegistration : public GUIModalMenu
{
@@ -32,7 +33,7 @@ public:
GUIConfirmRegistration(gui::IGUIEnvironment *env, gui::IGUIElement *parent,
s32 id, IMenuManager *menumgr, Client *client,
const std::string &playername, const std::string &password,
- bool *aborted);
+ bool *aborted, ISimpleTextureSource *tsrc);
~GUIConfirmRegistration();
void removeChildren();
@@ -63,4 +64,5 @@ private:
const std::string &m_password;
bool *m_aborted = nullptr;
std::wstring m_pass_confirm = L"";
+ ISimpleTextureSource *m_tsrc;
};
diff --git a/src/gui/guiEngine.cpp b/src/gui/guiEngine.cpp
index 3107d64cd..b40707d01 100644
--- a/src/gui/guiEngine.cpp
+++ b/src/gui/guiEngine.cpp
@@ -144,10 +144,10 @@ GUIEngine::GUIEngine(JoystickController *joystick,
//create soundmanager
MenuMusicFetcher soundfetcher;
#if USE_SOUND
- if (g_settings->getBool("enable_sound"))
+ if (g_settings->getBool("enable_sound") && g_sound_manager_singleton.get())
m_sound_manager = createOpenALSoundManager(g_sound_manager_singleton.get(), &soundfetcher);
#endif
- if(!m_sound_manager)
+ if (!m_sound_manager)
m_sound_manager = &dummySoundManager;
//create topleft header
diff --git a/src/gui/guiFormSpecMenu.cpp b/src/gui/guiFormSpecMenu.cpp
index 59cd130ef..37edf3c4b 100644
--- a/src/gui/guiFormSpecMenu.cpp
+++ b/src/gui/guiFormSpecMenu.cpp
@@ -65,6 +65,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "guiInventoryList.h"
#include "guiItemImage.h"
#include "guiScrollBar.h"
+#include "guiScrollContainer.h"
#include "guiTable.h"
#include "intlGUIEditBox.h"
#include "guiHyperText.h"
@@ -143,6 +144,8 @@ GUIFormSpecMenu::~GUIFormSpecMenu()
tooltip_rect_it.first->drop();
for (auto &clickthrough_it : m_clickthrough_elements)
clickthrough_it->drop();
+ for (auto &scroll_container_it : m_scroll_containers)
+ scroll_container_it.second->drop();
delete m_selected_item;
delete m_form_src;
@@ -351,6 +354,102 @@ void GUIFormSpecMenu::parseContainerEnd(parserData* data)
}
}
+void GUIFormSpecMenu::parseScrollContainer(parserData *data, const std::string &element)
+{
+ std::vector<std::string> parts = split(element, ';');
+
+ if (parts.size() < 4 ||
+ (parts.size() > 5 && m_formspec_version <= FORMSPEC_API_VERSION)) {
+ errorstream << "Invalid scroll_container start element (" << parts.size()
+ << "): '" << element << "'" << std::endl;
+ return;
+ }
+
+ std::vector<std::string> v_pos = split(parts[0], ',');
+ std::vector<std::string> v_geom = split(parts[1], ',');
+ std::string scrollbar_name = parts[2];
+ std::string orientation = parts[3];
+ f32 scroll_factor = 0.1f;
+ if (parts.size() >= 5 && !parts[4].empty())
+ scroll_factor = stof(parts[4]);
+
+ MY_CHECKPOS("scroll_container", 0);
+ MY_CHECKGEOM("scroll_container", 1);
+
+ v2s32 pos = getRealCoordinateBasePos(v_pos);
+ v2s32 geom = getRealCoordinateGeometry(v_geom);
+
+ if (orientation == "vertical")
+ scroll_factor *= -imgsize.Y;
+ else if (orientation == "horizontal")
+ scroll_factor *= -imgsize.X;
+ else
+ warningstream << "GUIFormSpecMenu::parseScrollContainer(): "
+ << "Invalid scroll_container orientation: " << orientation
+ << std::endl;
+
+ // old parent (at first: this)
+ // ^ is parent of clipper
+ // ^ is parent of mover
+ // ^ is parent of other elements
+
+ // make clipper
+ core::rect<s32> rect_clipper = core::rect<s32>(pos, pos + geom);
+
+ gui::IGUIElement *clipper = new gui::IGUIElement(EGUIET_ELEMENT, Environment,
+ data->current_parent, 0, rect_clipper);
+
+ // make mover
+ FieldSpec spec_mover(
+ "",
+ L"",
+ L"",
+ 258 + m_fields.size()
+ );
+
+ core::rect<s32> rect_mover = core::rect<s32>(0, 0, geom.X, geom.Y);
+
+ GUIScrollContainer *mover = new GUIScrollContainer(Environment,
+ clipper, spec_mover.fid, rect_mover, orientation, scroll_factor);
+
+ data->current_parent = mover;
+
+ m_scroll_containers.emplace_back(scrollbar_name, mover);
+
+ m_fields.push_back(spec_mover);
+
+ clipper->drop();
+
+ // remove interferring offset of normal containers
+ container_stack.push(pos_offset);
+ pos_offset.X = 0.0f;
+ pos_offset.Y = 0.0f;
+}
+
+void GUIFormSpecMenu::parseScrollContainerEnd(parserData *data)
+{
+ if (data->current_parent == this || data->current_parent->getParent() == this ||
+ container_stack.empty()) {
+ errorstream << "Invalid scroll_container end element, "
+ << "no matching scroll_container start element" << std::endl;
+ return;
+ }
+
+ if (pos_offset.getLengthSQ() != 0.0f) {
+ // pos_offset is only set by containers and scroll_containers.
+ // scroll_containers always set it to 0,0 which means that if it is
+ // not 0,0, it is a normal container that was opened last, not a
+ // scroll_container
+ errorstream << "Invalid scroll_container end element, "
+ << "an inner container was left open" << std::endl;
+ return;
+ }
+
+ data->current_parent = data->current_parent->getParent()->getParent();
+ pos_offset = container_stack.top();
+ container_stack.pop();
+}
+
void GUIFormSpecMenu::parseList(parserData *data, const std::string &element)
{
if (m_client == 0) {
@@ -390,38 +489,10 @@ void GUIFormSpecMenu::parseList(parserData *data, const std::string &element)
start_i = stoi(startindex);
if (geom.X < 0 || geom.Y < 0 || start_i < 0) {
- errorstream<< "Invalid list element: '" << element << "'" << std::endl;
+ errorstream << "Invalid list element: '" << element << "'" << std::endl;
return;
}
- // check for the existence of inventory and list
- Inventory *inv = m_invmgr->getInventory(loc);
- if (!inv) {
- warningstream << "GUIFormSpecMenu::parseList(): "
- << "The inventory location "
- << "\"" << loc.dump() << "\" doesn't exist"
- << std::endl;
- return;
- }
- InventoryList *ilist = inv->getList(listname);
- if (!ilist) {
- warningstream << "GUIFormSpecMenu::parseList(): "
- << "The inventory list \"" << listname << "\" "
- << "@ \"" << loc.dump() << "\" doesn't exist"
- << std::endl;
- return;
- }
-
- // trim geom if it is larger than the actual inventory size
- s32 list_size = (s32)ilist->getSize();
- if (list_size < geom.X * geom.Y + start_i) {
- list_size -= MYMAX(start_i, 0);
- geom.Y = list_size / geom.X;
- geom.Y += list_size % geom.X > 0 ? 1 : 0;
- if (geom.Y <= 1)
- geom.X = list_size;
- }
-
if (!data->explicit_size)
warningstream << "invalid use of list without a size[] element" << std::endl;
@@ -443,9 +514,9 @@ void GUIFormSpecMenu::parseList(parserData *data, const std::string &element)
pos.X + (geom.X - 1) * slot_spacing.X + imgsize.X,
pos.Y + (geom.Y - 1) * slot_spacing.Y + imgsize.Y);
- GUIInventoryList *e = new GUIInventoryList(Environment, this, spec.fid,
- rect, m_invmgr, loc, listname, geom, start_i, imgsize, slot_spacing,
- this, data->inventorylist_options, m_font);
+ GUIInventoryList *e = new GUIInventoryList(Environment, data->current_parent,
+ spec.fid, rect, m_invmgr, loc, listname, geom, start_i, imgsize,
+ slot_spacing, this, data->inventorylist_options, m_font);
m_inventorylists.push_back(e);
m_fields.push_back(spec);
@@ -550,10 +621,10 @@ void GUIFormSpecMenu::parseCheckbox(parserData* data, const std::string &element
spec.ftype = f_CheckBox;
- gui::IGUICheckBox *e = Environment->addCheckBox(fselected, rect, this,
- spec.fid, spec.flabel.c_str());
+ gui::IGUICheckBox *e = Environment->addCheckBox(fselected, rect,
+ data->current_parent, 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) {
@@ -610,10 +681,10 @@ void GUIFormSpecMenu::parseScrollBar(parserData* data, const std::string &elemen
spec.ftype = f_ScrollBar;
spec.send = true;
- GUIScrollBar *e = new GUIScrollBar(Environment, this, spec.fid, rect,
- is_horizontal, true);
+ GUIScrollBar *e = new GUIScrollBar(Environment, data->current_parent,
+ 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);
@@ -737,10 +808,11 @@ void GUIFormSpecMenu::parseImage(parserData* data, const std::string &element)
1
);
core::rect<s32> rect(pos, pos + geom);
- gui::IGUIImage *e = Environment->addImage(rect, this, spec.fid, 0, true);
+ gui::IGUIImage *e = Environment->addImage(rect, data->current_parent,
+ 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);
@@ -774,9 +846,9 @@ void GUIFormSpecMenu::parseImage(parserData* data, const std::string &element)
L"",
258 + m_fields.size()
);
- gui::IGUIImage *e = Environment->addImage(texture, pos, true, this,
- spec.fid, 0);
- auto style = getStyleForElement("image", spec.fname);
+ gui::IGUIImage *e = Environment->addImage(texture, pos, true,
+ data->current_parent, spec.fid, 0);
+ auto style = getDefaultStyleForElement("image", spec.fname);
e->setNotClipped(style.getBool(StyleSpec::NOCLIP, m_formspec_version < 3));
m_fields.push_back(spec);
@@ -841,9 +913,11 @@ void GUIFormSpecMenu::parseAnimatedImage(parserData *data, const std::string &el
if (parts.size() >= 7)
e->setFrameIndex(stoi(parts[6]) - 1);
- auto style = getStyleForElement("animated_image", spec.fname, "image");
+ auto style = getDefaultStyleForElement("animated_image", spec.fname, "image");
e->setNotClipped(style.getBool(StyleSpec::NOCLIP, false));
- e->drop();
+
+ // Animated images should let events through
+ m_clickthrough_elements.push_back(e);
m_fields.push_back(spec);
}
@@ -886,9 +960,9 @@ void GUIFormSpecMenu::parseItemImage(parserData* data, const std::string &elemen
);
spec.ftype = f_ItemImage;
- GUIItemImage *e = new GUIItemImage(Environment, this, spec.fid,
+ GUIItemImage *e = new GUIItemImage(Environment, data->current_parent, spec.fid,
core::rect<s32>(pos, pos + geom), name, m_font, m_client);
- auto style = getStyleForElement("item_image", spec.fname);
+ auto style = getDefaultStyleForElement("item_image", spec.fname);
e->setNotClipped(style.getBool(StyleSpec::NOCLIP, false));
// item images should let events through
@@ -949,10 +1023,11 @@ void GUIFormSpecMenu::parseButton(parserData* data, const std::string &element,
if(type == "button_exit")
spec.is_exit = true;
- GUIButton *e = GUIButton::addButton(Environment, rect, this, spec.fid, spec.flabel.c_str());
+ GUIButton *e = GUIButton::addButton(Environment, rect, m_tsrc,
+ data->current_parent, 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);
@@ -1140,7 +1215,8 @@ void GUIFormSpecMenu::parseTable(parserData* data, const std::string &element)
}
//now really show table
- GUITable *e = new GUITable(Environment, this, spec.fid, rect, m_tsrc);
+ GUITable *e = new GUITable(Environment, data->current_parent, spec.fid,
+ rect, m_tsrc);
if (spec.fname == data->focused_fieldname) {
Environment->setFocus(e);
@@ -1155,7 +1231,7 @@ void GUIFormSpecMenu::parseTable(parserData* data, const std::string &element)
if (!str_initial_selection.empty() && str_initial_selection != "0")
e->setSelected(stoi(str_initial_selection));
- auto style = getStyleForElement("table", name);
+ auto style = getDefaultStyleForElement("table", name);
e->setNotClipped(style.getBool(StyleSpec::NOCLIP, false));
m_tables.emplace_back(spec, e);
@@ -1216,7 +1292,8 @@ void GUIFormSpecMenu::parseTextList(parserData* data, const std::string &element
}
//now really show list
- GUITable *e = new GUITable(Environment, this, spec.fid, rect, m_tsrc);
+ GUITable *e = new GUITable(Environment, data->current_parent, spec.fid,
+ rect, m_tsrc);
if (spec.fname == data->focused_fieldname) {
Environment->setFocus(e);
@@ -1231,7 +1308,7 @@ void GUIFormSpecMenu::parseTextList(parserData* data, const std::string &element
if (!str_initial_selection.empty() && str_initial_selection != "0")
e->setSelected(stoi(str_initial_selection));
- auto style = getStyleForElement("textlist", name);
+ auto style = getDefaultStyleForElement("textlist", name);
e->setNotClipped(style.getBool(StyleSpec::NOCLIP, false));
m_tables.emplace_back(spec, e);
@@ -1292,7 +1369,8 @@ void GUIFormSpecMenu::parseDropDown(parserData* data, const std::string &element
spec.send = true;
//now really show list
- gui::IGUIComboBox *e = Environment->addComboBox(rect, this, spec.fid);
+ gui::IGUIComboBox *e = Environment->addComboBox(rect, data->current_parent,
+ spec.fid);
if (spec.fname == data->focused_fieldname) {
Environment->setFocus(e);
@@ -1306,7 +1384,7 @@ void GUIFormSpecMenu::parseDropDown(parserData* data, const std::string &element
if (!str_initial_selection.empty())
e->setSelected(stoi(str_initial_selection)-1);
- auto style = getStyleForElement("dropdown", name);
+ auto style = getDefaultStyleForElement("dropdown", name);
e->setNotClipped(style.getBool(StyleSpec::NOCLIP, false));
m_fields.push_back(spec);
@@ -1378,7 +1456,8 @@ void GUIFormSpecMenu::parsePwdField(parserData* data, const std::string &element
);
spec.send = true;
- gui::IGUIEditBox * e = Environment->addEditBox(0, rect, true, this, spec.fid);
+ gui::IGUIEditBox *e = Environment->addEditBox(0, rect, true,
+ data->current_parent, spec.fid);
if (spec.fname == data->focused_fieldname) {
Environment->setFocus(e);
@@ -1389,12 +1468,12 @@ void GUIFormSpecMenu::parsePwdField(parserData* data, const std::string &element
rect.UpperLeftCorner.Y -= font_height;
rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + font_height;
gui::StaticText::add(Environment, spec.flabel.c_str(), rect, false, true,
- this, 0);
+ data->current_parent, 0);
}
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)));
@@ -1424,7 +1503,7 @@ void GUIFormSpecMenu::createTextField(parserData *data, FieldSpec &spec,
if (!is_editable && !is_multiline) {
// spec field id to 0, this stops submit searching for a value that isn't there
gui::StaticText::add(Environment, spec.flabel.c_str(), rect, false, true,
- this, spec.fid);
+ data->current_parent, 0);
return;
}
@@ -1442,19 +1521,19 @@ void GUIFormSpecMenu::createTextField(parserData *data, FieldSpec &spec,
if (use_intl_edit_box && g_settings->getBool("freetype")) {
e = new gui::intlGUIEditBox(spec.fdefault.c_str(), true, Environment,
- this, spec.fid, rect, is_editable, is_multiline);
+ data->current_parent, spec.fid, rect, is_editable, is_multiline);
} else {
if (is_multiline) {
- e = new GUIEditBoxWithScrollBar(spec.fdefault.c_str(), true,
- Environment, this, spec.fid, rect, is_editable, true);
+ e = new GUIEditBoxWithScrollBar(spec.fdefault.c_str(), true, Environment,
+ data->current_parent, spec.fid, rect, is_editable, true);
} else if (is_editable) {
- e = Environment->addEditBox(spec.fdefault.c_str(), rect, true, this,
- spec.fid);
+ e = Environment->addEditBox(spec.fdefault.c_str(), rect, true,
+ data->current_parent, spec.fid);
e->grab();
}
}
- 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)
@@ -1490,7 +1569,7 @@ void GUIFormSpecMenu::createTextField(parserData *data, FieldSpec &spec,
rect.UpperLeftCorner.Y -= font_height;
rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + font_height;
IGUIElement *t = gui::StaticText::add(Environment, spec.flabel.c_str(),
- rect, false, true, this, 0);
+ rect, false, true, data->current_parent, 0);
if (t)
t->setNotClipped(style.getBool(StyleSpec::NOCLIP, false));
@@ -1670,8 +1749,8 @@ void GUIFormSpecMenu::parseHyperText(parserData *data, const std::string &elemen
);
spec.ftype = f_HyperText;
- GUIHyperText *e = new GUIHyperText(spec.flabel.c_str(), Environment, this,
- spec.fid, rect, m_client, m_tsrc);
+ GUIHyperText *e = new GUIHyperText(spec.flabel.c_str(), Environment,
+ data->current_parent, spec.fid, rect, m_client, m_tsrc);
e->drop();
m_fields.push_back(spec);
@@ -1749,10 +1828,11 @@ void GUIFormSpecMenu::parseLabel(parserData* data, const std::string &element)
4
);
gui::IGUIStaticText *e = gui::StaticText::add(Environment,
- spec.flabel.c_str(), rect, false, false, this, spec.fid);
+ spec.flabel.c_str(), rect, false, false, data->current_parent,
+ 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)));
@@ -1829,10 +1909,10 @@ void GUIFormSpecMenu::parseVertLabel(parserData* data, const std::string &elemen
258 + m_fields.size()
);
gui::IGUIStaticText *e = gui::StaticText::add(Environment, spec.flabel.c_str(),
- rect, false, false, this, spec.fid);
+ rect, false, false, data->current_parent, spec.fid);
e->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_CENTER);
- auto style = getStyleForElement("vertlabel", spec.fname, "label");
+ auto style = getDefaultStyleForElement("vertlabel", spec.fname, "label");
e->setNotClipped(style.getBool(StyleSpec::NOCLIP, false));
e->setOverrideColor(style.getColor(StyleSpec::TEXTCOLOR, video::SColor(0xFFFFFFFF)));
@@ -1863,17 +1943,8 @@ void GUIFormSpecMenu::parseImageButton(parserData* data, const std::string &elem
MY_CHECKPOS("imagebutton",0);
MY_CHECKGEOM("imagebutton",1);
- bool noclip = false;
- bool drawborder = true;
std::string pressed_image_name;
- if (parts.size() >= 7) {
- if (parts[5] == "true")
- noclip = true;
- if (parts[6] == "false")
- drawborder = false;
- }
-
if (parts.size() >= 8) {
pressed_image_name = parts[7];
}
@@ -1911,35 +1982,30 @@ void GUIFormSpecMenu::parseImageButton(parserData* data, const std::string &elem
if (type == "image_button_exit")
spec.is_exit = true;
- GUIButtonImage *e = GUIButtonImage::addButton(Environment, rect, this, spec.fid, spec.flabel.c_str());
+ GUIButtonImage *e = GUIButtonImage::addButton(Environment, rect, m_tsrc,
+ data->current_parent, 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;
}
@@ -1961,7 +2027,7 @@ void GUIFormSpecMenu::parseTabHeader(parserData* data, const std::string &elemen
// Width is not here because tabs are the width of the text, and
// there's no reason to change that.
unsigned int i = 0;
- std::vector<std::string> v_geom = {"1", "0.75"}; // Dummy width and default height
+ std::vector<std::string> v_geom = {"1", "1"}; // Dummy width and height
bool auto_width = true;
if (parts.size() == 7) {
i++;
@@ -2005,6 +2071,9 @@ void GUIFormSpecMenu::parseTabHeader(parserData* data, const std::string &elemen
pos = getRealCoordinateBasePos(v_pos);
geom = getRealCoordinateGeometry(v_geom);
+ // Set default height
+ if (parts.size() <= 6)
+ geom.Y = m_btn_height * 2;
pos.Y -= geom.Y; // TabHeader base pos is the bottom, not the top.
if (auto_width)
geom.X = DesiredRect.getWidth(); // Set automatic width
@@ -2023,8 +2092,8 @@ void GUIFormSpecMenu::parseTabHeader(parserData* data, const std::string &elemen
core::rect<s32> rect = core::rect<s32>(pos.X, pos.Y, pos.X+geom.X,
pos.Y+geom.Y);
- gui::IGUITabControl *e = Environment->addTabControl(rect, this,
- show_background, show_border, spec.fid);
+ gui::IGUITabControl *e = Environment->addTabControl(rect,
+ data->current_parent, show_background, show_border, spec.fid);
e->setAlignment(irr::gui::EGUIA_UPPERLEFT, irr::gui::EGUIA_UPPERLEFT,
irr::gui::EGUIA_UPPERLEFT, irr::gui::EGUIA_LOWERRIGHT);
e->setTabHeight(geom.Y);
@@ -2033,7 +2102,7 @@ void GUIFormSpecMenu::parseTabHeader(parserData* data, const std::string &elemen
Environment->setFocus(e);
}
- auto style = getStyleForElement("tabheader", name);
+ auto style = getDefaultStyleForElement("tabheader", name);
e->setNotClipped(style.getBool(StyleSpec::NOCLIP, true));
for (const std::string &button : buttons) {
@@ -2059,7 +2128,6 @@ void GUIFormSpecMenu::parseTabHeader(parserData* data, const std::string &elemen
void GUIFormSpecMenu::parseItemImageButton(parserData* data, const std::string &element)
{
-
if (m_client == 0) {
warningstream << "invalid use of item_image_button with m_client==0"
<< std::endl;
@@ -2118,10 +2186,12 @@ void GUIFormSpecMenu::parseItemImageButton(parserData* data, const std::string &
2
);
- GUIButtonItemImage *e_btn = GUIButtonItemImage::addButton(Environment, rect, this, spec_btn.fid, spec_btn.flabel.c_str(), item_name, m_client);
+ GUIButtonItemImage *e_btn = GUIButtonItemImage::addButton(Environment,
+ rect, m_tsrc, data->current_parent, 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);
@@ -2175,9 +2245,10 @@ void GUIFormSpecMenu::parseBox(parserData* data, const std::string &element)
core::rect<s32> rect(pos, pos + geom);
- GUIBox *e = new GUIBox(Environment, this, spec.fid, rect, tmp_color);
+ GUIBox *e = new GUIBox(Environment, data->current_parent, 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();
@@ -2327,7 +2398,7 @@ void GUIFormSpecMenu::parseTooltip(parserData* data, const std::string &element)
core::rect<s32> rect(pos, pos + geom);
gui::IGUIElement *e = new gui::IGUIElement(EGUIET_ELEMENT, Environment,
- this, fieldspec.fid, rect);
+ data->current_parent, fieldspec.fid, rect);
// the element the rect tooltip is bound to should not block mouse-clicks
e->setVisible(false);
@@ -2469,6 +2540,7 @@ bool GUIFormSpecMenu::parseStyle(parserData *data, const std::string &element, b
StyleSpec spec;
+ // Parse properties
for (size_t i = 1; i < parts.size(); i++) {
size_t equal_pos = parts[i].find('=');
if (equal_pos == std::string::npos) {
@@ -2490,7 +2562,7 @@ bool GUIFormSpecMenu::parseStyle(parserData *data, const std::string &element, b
<< "'" << std::endl;
property_warned.insert(propname);
}
- return false;
+ continue;
}
spec.set(prop, value);
@@ -2500,16 +2572,92 @@ bool GUIFormSpecMenu::parseStyle(parserData *data, const std::string &element, b
for (size_t sel = 0; sel < selectors.size(); sel++) {
std::string selector = trim(selectors[sel]);
- if (selector.empty()) {
- errorstream << "Invalid style element (Empty selector): '" << element
- << "'" << std::endl;
+ // Copy the style properties to a new StyleSpec
+ // This allows a separate state mask per-selector
+ StyleSpec selector_spec = spec;
+
+ // Parse state information, if it exists
+ bool state_valid = true;
+ size_t state_pos = selector.find(':');
+ if (state_pos != std::string::npos) {
+ std::string state_str = selector.substr(state_pos + 1);
+ selector = selector.substr(0, state_pos);
+
+ if (state_str.empty()) {
+ errorstream << "Invalid style element (Invalid state): '" << element
+ << "'" << std::endl;
+ state_valid = false;
+ } else {
+ std::vector<std::string> states = split(state_str, '+');
+ for (std::string &state : states) {
+ StyleSpec::State converted = StyleSpec::getStateByName(state);
+ if (converted == StyleSpec::STATE_INVALID) {
+ infostream << "Unknown style state " << state <<
+ " in element '" << element << "'" << std::endl;
+ state_valid = false;
+ break;
+ }
+
+ selector_spec.addState(converted);
+ }
+ }
+ }
+
+ if (!state_valid) {
+ // Skip this selector
continue;
}
if (style_type) {
- theme_by_type[selector] |= spec;
+ theme_by_type[selector].push_back(selector_spec);
} else {
- theme_by_name[selector] |= spec;
+ theme_by_name[selector].push_back(selector_spec);
+ }
+
+ // Backwards-compatibility for existing _hovered/_pressed properties
+ if (selector_spec.hasProperty(StyleSpec::BGCOLOR_HOVERED)
+ || selector_spec.hasProperty(StyleSpec::BGIMG_HOVERED)
+ || selector_spec.hasProperty(StyleSpec::FGIMG_HOVERED)) {
+ StyleSpec hover_spec;
+ hover_spec.addState(StyleSpec::STATE_HOVERED);
+
+ if (selector_spec.hasProperty(StyleSpec::BGCOLOR_HOVERED)) {
+ hover_spec.set(StyleSpec::BGCOLOR, selector_spec.get(StyleSpec::BGCOLOR_HOVERED, ""));
+ }
+ if (selector_spec.hasProperty(StyleSpec::BGIMG_HOVERED)) {
+ hover_spec.set(StyleSpec::BGIMG, selector_spec.get(StyleSpec::BGIMG_HOVERED, ""));
+ }
+ if (selector_spec.hasProperty(StyleSpec::FGIMG_HOVERED)) {
+ hover_spec.set(StyleSpec::FGIMG, selector_spec.get(StyleSpec::FGIMG_HOVERED, ""));
+ }
+
+ if (style_type) {
+ theme_by_type[selector].push_back(hover_spec);
+ } else {
+ theme_by_name[selector].push_back(hover_spec);
+ }
+ }
+ if (selector_spec.hasProperty(StyleSpec::BGCOLOR_PRESSED)
+ || selector_spec.hasProperty(StyleSpec::BGIMG_PRESSED)
+ || selector_spec.hasProperty(StyleSpec::FGIMG_PRESSED)) {
+ StyleSpec press_spec;
+ press_spec.addState(StyleSpec::STATE_PRESSED);
+
+ if (selector_spec.hasProperty(StyleSpec::BGCOLOR_PRESSED)) {
+ press_spec.set(StyleSpec::BGCOLOR, selector_spec.get(StyleSpec::BGCOLOR_PRESSED, ""));
+ }
+ if (selector_spec.hasProperty(StyleSpec::BGIMG_PRESSED)) {
+ press_spec.set(StyleSpec::BGIMG, selector_spec.get(StyleSpec::BGIMG_PRESSED, ""));
+ }
+ if (selector_spec.hasProperty(StyleSpec::FGIMG_PRESSED)) {
+ press_spec.set(StyleSpec::FGIMG, selector_spec.get(StyleSpec::FGIMG_PRESSED, ""));
+ }
+
+ if (style_type) {
+ theme_by_type[selector].push_back(press_spec);
+ } else {
+ theme_by_name[selector].push_back(press_spec);
+ }
}
}
@@ -2525,24 +2673,12 @@ void GUIFormSpecMenu::parseElement(parserData* data, const std::string &element)
if (parseVersionDirect(element))
return;
- std::vector<std::string> parts = split(element,'[');
-
- // ugly workaround to keep compatibility
- if (parts.size() > 2) {
- if (trim(parts[0]) == "image") {
- for (unsigned int i=2;i< parts.size(); i++) {
- parts[1] += "[" + parts[i];
- }
- }
- else { return; }
- }
-
- if (parts.size() < 2) {
+ size_t pos = element.find('[');
+ if (pos == std::string::npos)
return;
- }
- std::string type = trim(parts[0]);
- std::string description = trim(parts[1]);
+ std::string type = trim(element.substr(0, pos));
+ std::string description = element.substr(pos+1);
if (type == "container") {
parseContainer(data, description);
@@ -2709,6 +2845,16 @@ void GUIFormSpecMenu::parseElement(parserData* data, const std::string &element)
return;
}
+ if (type == "scroll_container") {
+ parseScrollContainer(data, description);
+ return;
+ }
+
+ if (type == "scroll_container_end") {
+ parseScrollContainerEnd(data);
+ return;
+ }
+
// Ignore others
infostream << "Unknown DrawSpec: type=" << type << ", data=\"" << description << "\""
<< std::endl;
@@ -2765,8 +2911,10 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
tooltip_rect_it.first->drop();
for (auto &clickthrough_it : m_clickthrough_elements)
clickthrough_it->drop();
+ for (auto &scroll_container_it : m_scroll_containers)
+ scroll_container_it.second->drop();
- mydata.size= v2s32(100,100);
+ mydata.size = v2s32(100, 100);
mydata.screensize = screensize;
mydata.offset = v2f32(0.5f, 0.5f);
mydata.anchor = v2f32(0.5f, 0.5f);
@@ -2775,6 +2923,9 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
// Base position of contents of form
mydata.basepos = getBasePos();
+ // the parent for the parsed elements
+ mydata.current_parent = this;
+
m_inventorylists.clear();
m_backgrounds.clear();
m_tables.clear();
@@ -2785,6 +2936,7 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
m_tooltip_rects.clear();
m_inventory_rings.clear();
m_dropdowns.clear();
+ m_scroll_containers.clear();
theme_by_name.clear();
theme_by_type.clear();
m_clickthrough_elements.clear();
@@ -3051,11 +3203,24 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
parseElement(&mydata, elements[i]);
}
- if (!container_stack.empty()) {
+ if (mydata.current_parent != this) {
+ errorstream << "Invalid formspec string: scroll_container was never closed!"
+ << std::endl;
+ } else if (!container_stack.empty()) {
errorstream << "Invalid formspec string: container was never closed!"
<< std::endl;
}
+ // get the scrollbar elements for scroll_containers
+ for (const std::pair<std::string, GUIScrollContainer *> &c : m_scroll_containers) {
+ for (const std::pair<FieldSpec, GUIScrollBar *> &b : m_scrollbars) {
+ if (c.first == b.first.fname) {
+ c.second->setScrollBar(b.second);
+ break;
+ }
+ }
+ }
+
// If there are fields without explicit size[], add a "Proceed"
// button and adjust size to fit all the fields.
if (mydata.simple_field_count > 0 && !mydata.explicit_size) {
@@ -3080,7 +3245,7 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
size.X / 2 - 70 + 140, pos.Y + m_btn_height * 2
);
const wchar_t *text = wgettext("Proceed");
- GUIButton::addButton(Environment, mydata.rect, this, 257, text);
+ GUIButton::addButton(Environment, mydata.rect, m_tsrc, this, 257, text);
delete[] text;
}
}
@@ -3146,28 +3311,24 @@ bool GUIFormSpecMenu::getAndroidUIInput()
if (!hasAndroidUIInput())
return false;
+ // still waiting
+ if (porting::getInputDialogState() == -1)
+ return true;
+
std::string fieldname = m_jni_field_name;
m_jni_field_name.clear();
- for (std::vector<FieldSpec>::iterator iter = m_fields.begin();
- iter != m_fields.end(); ++iter) {
-
- if (iter->fname != fieldname) {
+ for (const FieldSpec &field : m_fields) {
+ if (field.fname != fieldname)
continue;
- }
- IGUIElement *tochange = getElementFromId(iter->fid, true);
- if (tochange == 0) {
- return false;
- }
+ IGUIElement *element = getElementFromId(field.fid, true);
- if (tochange->getType() != irr::gui::EGUIET_EDIT_BOX) {
+ if (!element || element->getType() != irr::gui::EGUIET_EDIT_BOX)
return false;
- }
std::string text = porting::getInputDialogValue();
-
- ((gui::IGUIEditBox *)tochange)->setText(utf8_to_wide(text).c_str());
+ ((gui::IGUIEditBox *)element)->setText(utf8_to_wide(text).c_str());
}
return false;
}
@@ -3314,8 +3475,12 @@ void GUIFormSpecMenu::drawMenu()
bool hovered_element_found = false;
if (hovered != NULL) {
- s32 id = hovered->getID();
+ if (m_show_debug) {
+ core::rect<s32> rect = hovered->getAbsoluteClippingRect();
+ driver->draw2DRectangle(0x22FFFF00, rect, &rect);
+ }
+ s32 id = hovered->getID();
u64 delta = 0;
if (id == -1) {
m_old_tooltip_id = id;
@@ -3395,6 +3560,10 @@ void GUIFormSpecMenu::showTooltip(const std::wstring &text,
tooltip_offset_y = 0;
if (m_pointer.X > (s32)screenSize.X / 2)
tooltip_offset_x = -(tooltip_offset_x + tooltip_width);
+
+ // Hide tooltip after ETIE_LEFT_UP
+ if (m_pointer.X == 0)
+ return;
#endif
// Calculate and set the tooltip position
@@ -3837,6 +4006,10 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event)
(kp == getKeySetting("keymap_screenshot"))) {
m_client->makeScreenshot();
}
+
+ if (event.KeyInput.PressedDown && kp == getKeySetting("keymap_toggle_debug"))
+ m_show_debug = !m_show_debug;
+
if (event.KeyInput.PressedDown &&
(event.KeyInput.Key==KEY_RETURN ||
event.KeyInput.Key==KEY_UP ||
@@ -4344,6 +4517,12 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event)
}
}
+ if (event.GUIEvent.EventType == gui::EGET_SCROLL_BAR_CHANGED) {
+ // move scroll_containers
+ for (const std::pair<std::string, GUIScrollContainer *> &c : m_scroll_containers)
+ c.second->onScrollEvent(event.GUIEvent.Caller);
+ }
+
if (event.GUIEvent.EventType == gui::EGET_EDITBOX_ENTER) {
if (event.GUIEvent.Caller->getID() > 257) {
bool close_on_enter = true;
@@ -4432,25 +4611,46 @@ std::wstring GUIFormSpecMenu::getLabelByID(s32 id)
return L"";
}
-StyleSpec GUIFormSpecMenu::getStyleForElement(const std::string &type,
+StyleSpec GUIFormSpecMenu::getDefaultStyleForElement(const std::string &type,
const std::string &name, const std::string &parent_type) {
- StyleSpec ret;
+ return getStyleForElement(type, name, parent_type)[StyleSpec::STATE_DEFAULT];
+}
+
+std::array<StyleSpec, StyleSpec::NUM_STATES> GUIFormSpecMenu::getStyleForElement(
+ const std::string &type, const std::string &name, const std::string &parent_type)
+{
+ std::array<StyleSpec, StyleSpec::NUM_STATES> ret;
+
+ auto it = theme_by_type.find("*");
+ if (it != theme_by_type.end()) {
+ for (const StyleSpec &spec : it->second)
+ ret[(u32)spec.getState()] |= spec;
+ }
+
+ it = theme_by_name.find("*");
+ if (it != theme_by_name.end()) {
+ for (const StyleSpec &spec : it->second)
+ ret[(u32)spec.getState()] |= spec;
+ }
if (!parent_type.empty()) {
- auto it = theme_by_type.find(parent_type);
+ 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);
+ 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;
diff --git a/src/gui/guiFormSpecMenu.h b/src/gui/guiFormSpecMenu.h
index 17bfef205..28088416d 100644
--- a/src/gui/guiFormSpecMenu.h
+++ b/src/gui/guiFormSpecMenu.h
@@ -39,6 +39,7 @@ class ISimpleTextureSource;
class Client;
class GUIScrollBar;
class TexturePool;
+class GUIScrollContainer;
typedef enum {
f_Button,
@@ -274,11 +275,13 @@ protected:
v2s32 getRealCoordinateBasePos(const std::vector<std::string> &v_pos);
v2s32 getRealCoordinateGeometry(const std::vector<std::string> &v_geom);
- std::unordered_map<std::string, StyleSpec> theme_by_type;
- std::unordered_map<std::string, StyleSpec> theme_by_name;
+ std::unordered_map<std::string, std::vector<StyleSpec>> theme_by_type;
+ std::unordered_map<std::string, std::vector<StyleSpec>> theme_by_name;
std::unordered_set<std::string> property_warned;
- StyleSpec getStyleForElement(const std::string &type,
+ StyleSpec getDefaultStyleForElement(const std::string &type,
+ const std::string &name="", const std::string &parent_type="");
+ std::array<StyleSpec, StyleSpec::NUM_STATES> getStyleForElement(const std::string &type,
const std::string &name="", const std::string &parent_type="");
v2s32 padding;
@@ -308,6 +311,7 @@ protected:
std::vector<std::pair<FieldSpec, GUIScrollBar *>> m_scrollbars;
std::vector<std::pair<FieldSpec, std::vector<std::string>>> m_dropdowns;
std::vector<gui::IGUIElement *> m_clickthrough_elements;
+ std::vector<std::pair<std::string, GUIScrollContainer *>> m_scroll_containers;
GUIInventoryList::ItemSpec *m_selected_item = nullptr;
u16 m_selected_amount = 0;
@@ -341,6 +345,7 @@ private:
u16 m_formspec_version = 1;
std::string m_focused_element = "";
JoystickController *m_joystick;
+ bool m_show_debug = false;
typedef struct {
bool explicit_size;
@@ -356,6 +361,7 @@ private:
std::string focused_fieldname;
GUITable::TableOptions table_options;
GUITable::TableColumns table_columns;
+ gui::IGUIElement *current_parent = nullptr;
GUIInventoryList::Options inventorylist_options;
@@ -388,6 +394,8 @@ private:
void parseSize(parserData* data, const std::string &element);
void parseContainer(parserData* data, const std::string &element);
void parseContainerEnd(parserData* data);
+ void parseScrollContainer(parserData *data, const std::string &element);
+ void parseScrollContainerEnd(parserData *data);
void parseList(parserData* data, const std::string &element);
void parseListRing(parserData* data, const std::string &element);
void parseCheckbox(parserData* data, const std::string &element);
diff --git a/src/gui/guiHyperText.cpp b/src/gui/guiHyperText.cpp
index e107b5a3e..88931cdf9 100644
--- a/src/gui/guiHyperText.cpp
+++ b/src/gui/guiHyperText.cpp
@@ -917,20 +917,20 @@ void TextDrawer::place(const core::rect<s32> &dest_rect)
// Draw text in a rectangle with a given offset. Items are actually placed in
// relative (to upper left corner) coordinates.
-void TextDrawer::draw(const core::rect<s32> &dest_rect,
+void TextDrawer::draw(const core::rect<s32> &clip_rect,
const core::position2d<s32> &dest_offset)
{
irr::video::IVideoDriver *driver = m_environment->getVideoDriver();
- core::position2d<s32> offset = dest_rect.UpperLeftCorner + dest_offset;
+ core::position2d<s32> offset = dest_offset;
offset.Y += m_voffset;
if (m_text.background_type == ParsedText::BACKGROUND_COLOR)
- driver->draw2DRectangle(m_text.background_color, dest_rect);
+ driver->draw2DRectangle(m_text.background_color, clip_rect);
for (auto &p : m_text.m_paragraphs) {
for (auto &el : p.elements) {
core::rect<s32> rect(el.pos + offset, el.dim);
- if (!rect.isRectCollided(dest_rect))
+ if (!rect.isRectCollided(clip_rect))
continue;
switch (el.type) {
@@ -947,7 +947,7 @@ void TextDrawer::draw(const core::rect<s32> &dest_rect,
if (el.type == ParsedText::ELEMENT_TEXT)
el.font->draw(el.text, rect, color, false, true,
- &dest_rect);
+ &clip_rect);
if (el.underline && el.drawwidth) {
s32 linepos = el.pos.Y + offset.Y +
@@ -958,7 +958,7 @@ void TextDrawer::draw(const core::rect<s32> &dest_rect,
el.pos.X + offset.X + el.drawwidth,
linepos + (el.baseline >> 3));
- driver->draw2DRectangle(color, linerect, &dest_rect);
+ driver->draw2DRectangle(color, linerect, &clip_rect);
}
} break;
@@ -972,7 +972,7 @@ void TextDrawer::draw(const core::rect<s32> &dest_rect,
irr::core::rect<s32>(
core::position2d<s32>(0, 0),
texture->getOriginalSize()),
- &dest_rect, 0, true);
+ &clip_rect, 0, true);
} break;
case ParsedText::ELEMENT_ITEM: {
@@ -982,7 +982,7 @@ void TextDrawer::draw(const core::rect<s32> &dest_rect,
drawItemStack(
m_environment->getVideoDriver(),
- g_fontengine->getFont(), item, rect, &dest_rect,
+ g_fontengine->getFont(), item, rect, &clip_rect,
m_client, IT_ROT_OTHER, el.angle, el.rotation
);
} break;
@@ -1094,6 +1094,7 @@ bool GUIHyperText::OnEvent(const SEvent &event)
m_text_scrollpos.Y = -m_vscrollbar->getPos();
m_drawer.draw(m_display_text_rect, m_text_scrollpos);
checkHover(event.MouseInput.X, event.MouseInput.Y);
+ return true;
} else if (event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN) {
ParsedText::Element *element = getElementAt(
@@ -1151,7 +1152,8 @@ void GUIHyperText::draw()
m_vscrollbar->setPos(0);
m_vscrollbar->setVisible(false);
}
- m_drawer.draw(m_display_text_rect, m_text_scrollpos);
+ m_drawer.draw(AbsoluteClippingRect,
+ m_display_text_rect.UpperLeftCorner + m_text_scrollpos);
// draw children
IGUIElement::draw();
diff --git a/src/gui/guiHyperText.h b/src/gui/guiHyperText.h
index c55f8a705..5b936262e 100644
--- a/src/gui/guiHyperText.h
+++ b/src/gui/guiHyperText.h
@@ -174,7 +174,7 @@ public:
void place(const core::rect<s32> &dest_rect);
inline s32 getHeight() { return m_height; };
- void draw(const core::rect<s32> &dest_rect,
+ void draw(const core::rect<s32> &clip_rect,
const core::position2d<s32> &dest_offset);
ParsedText::Element *getElementAt(core::position2d<s32> pos);
ParsedText::Tag *m_hovertag;
diff --git a/src/gui/guiInventoryList.cpp b/src/gui/guiInventoryList.cpp
index 536471229..dfdb60448 100644
--- a/src/gui/guiInventoryList.cpp
+++ b/src/gui/guiInventoryList.cpp
@@ -47,7 +47,8 @@ GUIInventoryList::GUIInventoryList(gui::IGUIEnvironment *env,
m_fs_menu(fs_menu),
m_options(options),
m_font(font),
- m_hovered_i(-1)
+ m_hovered_i(-1),
+ m_already_warned(false)
{
}
@@ -58,20 +59,27 @@ void GUIInventoryList::draw()
Inventory *inv = m_invmgr->getInventory(m_inventoryloc);
if (!inv) {
- warningstream << "GUIInventoryList::draw(): "
- << "The inventory location "
- << "\"" << m_inventoryloc.dump() << "\" doesn't exist anymore"
- << std::endl;
+ if (!m_already_warned) {
+ warningstream << "GUIInventoryList::draw(): "
+ << "The inventory location "
+ << "\"" << m_inventoryloc.dump() << "\" doesn't exist"
+ << std::endl;
+ m_already_warned = true;
+ }
return;
}
InventoryList *ilist = inv->getList(m_listname);
if (!ilist) {
- warningstream << "GUIInventoryList::draw(): "
- << "The inventory list \"" << m_listname << "\" @ \""
- << m_inventoryloc.dump() << "\" doesn't exist anymore"
- << std::endl;
+ if (!m_already_warned) {
+ warningstream << "GUIInventoryList::draw(): "
+ << "The inventory list \"" << m_listname << "\" @ \""
+ << m_inventoryloc.dump() << "\" doesn't exist"
+ << std::endl;
+ m_already_warned = true;
+ }
return;
}
+ m_already_warned = false;
video::IVideoDriver *driver = Environment->getVideoDriver();
Client *client = m_fs_menu->getClient();
@@ -80,9 +88,11 @@ void GUIInventoryList::draw()
core::rect<s32> imgrect(0, 0, m_slot_size.X, m_slot_size.Y);
v2s32 base_pos = AbsoluteRect.UpperLeftCorner;
+ const s32 list_size = (s32)ilist->getSize();
+
for (s32 i = 0; i < m_geom.X * m_geom.Y; i++) {
s32 item_i = i + m_start_item_i;
- if (item_i >= (s32)ilist->getSize())
+ if (item_i >= list_size)
break;
v2s32 p((i % m_geom.X) * m_slot_spacing.X,
@@ -192,10 +202,19 @@ bool GUIInventoryList::OnEvent(const SEvent &event)
s32 GUIInventoryList::getItemIndexAtPos(v2s32 p) const
{
+ // no item if no gui element at pointer
if (!IsVisible || AbsoluteClippingRect.getArea() <= 0 ||
!AbsoluteClippingRect.isPointInside(p))
return -1;
+ // there can not be an item if the inventory or the inventorylist does not exist
+ Inventory *inv = m_invmgr->getInventory(m_inventoryloc);
+ if (!inv)
+ return -1;
+ InventoryList *ilist = inv->getList(m_listname);
+ if (!ilist)
+ return -1;
+
core::rect<s32> imgrect(0, 0, m_slot_size.X, m_slot_size.Y);
v2s32 base_pos = AbsoluteRect.UpperLeftCorner;
@@ -210,7 +229,8 @@ s32 GUIInventoryList::getItemIndexAtPos(v2s32 p) const
rect.clipAgainst(AbsoluteClippingRect);
- if (rect.getArea() > 0 && rect.isPointInside(p))
+ if (rect.getArea() > 0 && rect.isPointInside(p) &&
+ i + m_start_item_i < (s32)ilist->getSize())
return i + m_start_item_i;
return -1;
diff --git a/src/gui/guiInventoryList.h b/src/gui/guiInventoryList.h
index fd2c3601b..28e95fbbf 100644
--- a/src/gui/guiInventoryList.h
+++ b/src/gui/guiInventoryList.h
@@ -107,7 +107,7 @@ private:
const InventoryLocation m_inventoryloc;
const std::string m_listname;
- // specifies the width and height of the inventorylist in itemslots
+ // the specified width and height of the shown inventorylist in itemslots
const v2s32 m_geom;
// the first item's index in inventory
const s32 m_start_item_i;
@@ -127,4 +127,7 @@ private:
// the index of the hovered item; -1 if no item is hovered
s32 m_hovered_i;
+
+ // we do not want to write a warning on every draw
+ bool m_already_warned;
};
diff --git a/src/gui/guiKeyChangeMenu.cpp b/src/gui/guiKeyChangeMenu.cpp
index 3f270fc7a..da0e25c23 100644
--- a/src/gui/guiKeyChangeMenu.cpp
+++ b/src/gui/guiKeyChangeMenu.cpp
@@ -82,8 +82,10 @@ enum
};
GUIKeyChangeMenu::GUIKeyChangeMenu(gui::IGUIEnvironment* env,
- gui::IGUIElement* parent, s32 id, IMenuManager *menumgr) :
-GUIModalMenu(env, parent, id, menumgr)
+ gui::IGUIElement* parent, s32 id, IMenuManager *menumgr,
+ ISimpleTextureSource *tsrc) :
+ GUIModalMenu(env, parent, id, menumgr),
+ m_tsrc(tsrc)
{
init_keys();
}
@@ -157,7 +159,7 @@ void GUIKeyChangeMenu::regenerateGui(v2u32 screensize)
core::rect<s32> rect(0, 0, 100 * s, 30 * s);
rect += topleft + v2s32(offset.X + 150 * s, offset.Y - 5 * s);
const wchar_t *text = wgettext(k->key.name());
- k->button = GUIButton::addButton(Environment, rect, this, k->id, text);
+ k->button = GUIButton::addButton(Environment, rect, m_tsrc, this, k->id, text);
delete[] text;
}
if ((i + 1) % KMaxButtonPerColumns == 0) {
@@ -217,14 +219,14 @@ void GUIKeyChangeMenu::regenerateGui(v2u32 screensize)
core::rect<s32> rect(0, 0, 100 * s, 30 * s);
rect += topleft + v2s32(size.X / 2 - 105 * s, size.Y - 40 * s);
const wchar_t *text = wgettext("Save");
- GUIButton::addButton(Environment, rect, this, GUI_ID_BACK_BUTTON, text);
+ GUIButton::addButton(Environment, rect, m_tsrc, this, GUI_ID_BACK_BUTTON, text);
delete[] text;
}
{
core::rect<s32> rect(0, 0, 100 * s, 30 * s);
rect += topleft + v2s32(size.X / 2 + 5 * s, size.Y - 40 * s);
const wchar_t *text = wgettext("Cancel");
- GUIButton::addButton(Environment, rect, this, GUI_ID_ABORT_BUTTON, text);
+ GUIButton::addButton(Environment, rect, m_tsrc, this, GUI_ID_ABORT_BUTTON, text);
delete[] text;
}
}
diff --git a/src/gui/guiKeyChangeMenu.h b/src/gui/guiKeyChangeMenu.h
index 528827fd9..1c0f40247 100644
--- a/src/gui/guiKeyChangeMenu.h
+++ b/src/gui/guiKeyChangeMenu.h
@@ -28,6 +28,8 @@
#include <string>
#include <vector>
+class ISimpleTextureSource;
+
struct key_setting
{
int id;
@@ -41,7 +43,7 @@ class GUIKeyChangeMenu : public GUIModalMenu
{
public:
GUIKeyChangeMenu(gui::IGUIEnvironment *env, gui::IGUIElement *parent, s32 id,
- IMenuManager *menumgr);
+ IMenuManager *menumgr, ISimpleTextureSource *tsrc);
~GUIKeyChangeMenu();
void removeChildren();
@@ -74,4 +76,5 @@ private:
key_setting *active_key = nullptr;
gui::IGUIStaticText *key_used_text = nullptr;
std::vector<key_setting *> key_settings;
+ ISimpleTextureSource *m_tsrc;
};
diff --git a/src/gui/guiPasswordChange.cpp b/src/gui/guiPasswordChange.cpp
index af91ce84c..965a2d6f7 100644
--- a/src/gui/guiPasswordChange.cpp
+++ b/src/gui/guiPasswordChange.cpp
@@ -38,10 +38,12 @@ const int ID_cancel = 261;
GUIPasswordChange::GUIPasswordChange(gui::IGUIEnvironment* env,
gui::IGUIElement* parent, s32 id,
IMenuManager *menumgr,
- Client* client
+ Client* client,
+ ISimpleTextureSource *tsrc
):
GUIModalMenu(env, parent, id, menumgr),
- m_client(client)
+ m_client(client),
+ m_tsrc(tsrc)
{
}
@@ -146,14 +148,14 @@ void GUIPasswordChange::regenerateGui(v2u32 screensize)
core::rect<s32> rect(0, 0, 100 * s, 30 * s);
rect = rect + v2s32(size.X / 4 + 56 * s, ypos);
text = wgettext("Change");
- GUIButton::addButton(Environment, rect, this, ID_change, text);
+ GUIButton::addButton(Environment, rect, m_tsrc, this, ID_change, text);
delete[] text;
}
{
core::rect<s32> rect(0, 0, 100 * s, 30 * s);
rect = rect + v2s32(size.X / 4 + 185 * s, ypos);
text = wgettext("Cancel");
- GUIButton::addButton(Environment, rect, this, ID_cancel, text);
+ GUIButton::addButton(Environment, rect, m_tsrc, this, ID_cancel, text);
delete[] text;
}
diff --git a/src/gui/guiPasswordChange.h b/src/gui/guiPasswordChange.h
index 58541a399..7141100c0 100644
--- a/src/gui/guiPasswordChange.h
+++ b/src/gui/guiPasswordChange.h
@@ -23,12 +23,14 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include <string>
class Client;
+class ISimpleTextureSource;
class GUIPasswordChange : public GUIModalMenu
{
public:
GUIPasswordChange(gui::IGUIEnvironment *env, gui::IGUIElement *parent, s32 id,
- IMenuManager *menumgr, Client *client);
+ IMenuManager *menumgr, Client *client,
+ ISimpleTextureSource *tsrc);
~GUIPasswordChange();
void removeChildren();
@@ -57,4 +59,5 @@ private:
std::wstring m_oldpass = L"";
std::wstring m_newpass = L"";
std::wstring m_newpass_confirm = L"";
+ ISimpleTextureSource *m_tsrc;
};
diff --git a/src/gui/guiScrollContainer.cpp b/src/gui/guiScrollContainer.cpp
new file mode 100644
index 000000000..88cdc7057
--- /dev/null
+++ b/src/gui/guiScrollContainer.cpp
@@ -0,0 +1,70 @@
+/*
+Minetest
+Copyright (C) 2020 DS
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "guiScrollContainer.h"
+
+GUIScrollContainer::GUIScrollContainer(gui::IGUIEnvironment *env,
+ gui::IGUIElement *parent, s32 id, const core::rect<s32> &rectangle,
+ const std::string &orientation, f32 scrollfactor) :
+ gui::IGUIElement(gui::EGUIET_ELEMENT, env, parent, id, rectangle),
+ m_scrollbar(nullptr), m_scrollfactor(scrollfactor)
+{
+ if (orientation == "vertical")
+ m_orientation = VERTICAL;
+ else if (orientation == "horizontal")
+ m_orientation = HORIZONTAL;
+ else
+ m_orientation = UNDEFINED;
+}
+
+bool GUIScrollContainer::OnEvent(const SEvent &event)
+{
+ if (event.EventType == EET_MOUSE_INPUT_EVENT &&
+ event.MouseInput.Event == EMIE_MOUSE_WHEEL &&
+ !event.MouseInput.isLeftPressed() && m_scrollbar) {
+ Environment->setFocus(m_scrollbar);
+ bool retval = m_scrollbar->OnEvent(event);
+
+ // a hacky fix for updating the hovering and co.
+ IGUIElement *hovered_elem = getElementFromPoint(core::position2d<s32>(
+ event.MouseInput.X, event.MouseInput.Y));
+ SEvent mov_event = event;
+ mov_event.MouseInput.Event = EMIE_MOUSE_MOVED;
+ Environment->postEventFromUser(mov_event);
+ if (hovered_elem)
+ hovered_elem->OnEvent(mov_event);
+
+ return retval;
+ }
+
+ return IGUIElement::OnEvent(event);
+}
+
+void GUIScrollContainer::updateScrolling()
+{
+ s32 pos = m_scrollbar->getPos();
+ core::rect<s32> rect = getRelativePosition();
+
+ if (m_orientation == VERTICAL)
+ rect.UpperLeftCorner.Y = pos * m_scrollfactor;
+ else if (m_orientation == HORIZONTAL)
+ rect.UpperLeftCorner.X = pos * m_scrollfactor;
+
+ setRelativePosition(rect);
+}
diff --git a/src/gui/guiScrollContainer.h b/src/gui/guiScrollContainer.h
new file mode 100644
index 000000000..a0306291e
--- /dev/null
+++ b/src/gui/guiScrollContainer.h
@@ -0,0 +1,60 @@
+/*
+Minetest
+Copyright (C) 2020 DS
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#pragma once
+
+#include "irrlichttypes_extrabloated.h"
+#include "util/string.h"
+#include "guiScrollBar.h"
+
+class GUIScrollContainer : public gui::IGUIElement
+{
+public:
+ GUIScrollContainer(gui::IGUIEnvironment *env, gui::IGUIElement *parent, s32 id,
+ const core::rect<s32> &rectangle, const std::string &orientation,
+ f32 scrollfactor);
+
+ virtual bool OnEvent(const SEvent &event) override;
+
+ inline void onScrollEvent(gui::IGUIElement *caller)
+ {
+ if (caller == m_scrollbar)
+ updateScrolling();
+ }
+
+ inline void setScrollBar(GUIScrollBar *scrollbar)
+ {
+ m_scrollbar = scrollbar;
+ updateScrolling();
+ }
+
+private:
+ enum OrientationEnum
+ {
+ VERTICAL,
+ HORIZONTAL,
+ UNDEFINED
+ };
+
+ GUIScrollBar *m_scrollbar;
+ OrientationEnum m_orientation;
+ f32 m_scrollfactor;
+
+ void updateScrolling();
+};
diff --git a/src/gui/guiVolumeChange.cpp b/src/gui/guiVolumeChange.cpp
index 9428cde83..07b11248c 100644
--- a/src/gui/guiVolumeChange.cpp
+++ b/src/gui/guiVolumeChange.cpp
@@ -38,9 +38,10 @@ const int ID_soundMuteButton = 266;
GUIVolumeChange::GUIVolumeChange(gui::IGUIEnvironment* env,
gui::IGUIElement* parent, s32 id,
- IMenuManager *menumgr
+ IMenuManager *menumgr, ISimpleTextureSource *tsrc
):
- GUIModalMenu(env, parent, id, menumgr)
+ GUIModalMenu(env, parent, id, menumgr),
+ m_tsrc(tsrc)
{
}
@@ -104,7 +105,7 @@ void GUIVolumeChange::regenerateGui(v2u32 screensize)
core::rect<s32> rect(0, 0, 80 * s, 30 * s);
rect = rect + v2s32(size.X / 2 - 80 * s / 2, size.Y / 2 + 55 * s);
const wchar_t *text = wgettext("Exit");
- GUIButton::addButton(Environment, rect, this, ID_soundExitButton, text);
+ GUIButton::addButton(Environment, rect, m_tsrc, this, ID_soundExitButton, text);
delete[] text;
}
{
diff --git a/src/gui/guiVolumeChange.h b/src/gui/guiVolumeChange.h
index f4f4e9eea..466e17f9d 100644
--- a/src/gui/guiVolumeChange.h
+++ b/src/gui/guiVolumeChange.h
@@ -23,12 +23,14 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include "modalMenu.h"
#include <string>
+class ISimpleTextureSource;
+
class GUIVolumeChange : public GUIModalMenu
{
public:
GUIVolumeChange(gui::IGUIEnvironment* env,
gui::IGUIElement* parent, s32 id,
- IMenuManager *menumgr);
+ IMenuManager *menumgr, ISimpleTextureSource *tsrc);
~GUIVolumeChange();
void removeChildren();
@@ -46,4 +48,7 @@ public:
protected:
std::wstring getLabelByID(s32 id) { return L""; }
std::string getNameByID(s32 id) { return ""; }
+
+private:
+ ISimpleTextureSource *m_tsrc;
};
diff --git a/src/gui/modalMenu.cpp b/src/gui/modalMenu.cpp
index 8fb6c6f0f..a6fe7ebaf 100644
--- a/src/gui/modalMenu.cpp
+++ b/src/gui/modalMenu.cpp
@@ -28,8 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "touchscreengui.h"
#endif
-// clang-format off
-GUIModalMenu::GUIModalMenu(gui::IGUIEnvironment* env, gui::IGUIElement* parent, s32 id,
+GUIModalMenu::GUIModalMenu(gui::IGUIEnvironment *env, gui::IGUIElement *parent, s32 id,
IMenuManager *menumgr) :
IGUIElement(gui::EGUIET_ELEMENT, env, parent, id,
core::rect<s32>(0, 0, 100, 100)),
@@ -153,8 +152,8 @@ bool GUIModalMenu::preprocessEvent(const SEvent &event)
if (((gui::IGUIEditBox *)hovered)->isPasswordBox())
type = 3;
- porting::showInputDialog(gettext("ok"), "",
- wide_to_utf8(((gui::IGUIEditBox *)hovered)->getText()), type);
+ porting::showInputDialog(gettext("OK"), "",
+ wide_to_utf8(((gui::IGUIEditBox *)hovered)->getText()), type);
return retval;
}
}
@@ -167,18 +166,17 @@ bool GUIModalMenu::preprocessEvent(const SEvent &event)
if (!root) {
errorstream << "GUIModalMenu::preprocessEvent"
- << " unable to get root element" << std::endl;
+ << " unable to get root element" << std::endl;
return false;
}
- gui::IGUIElement *hovered = root->getElementFromPoint(
- core::position2d<s32>(event.TouchInput.X, event.TouchInput.Y));
+ gui::IGUIElement *hovered =
+ root->getElementFromPoint(core::position2d<s32>(
+ event.TouchInput.X, event.TouchInput.Y));
translated.MouseInput.X = event.TouchInput.X;
translated.MouseInput.Y = event.TouchInput.Y;
translated.MouseInput.Control = false;
- bool dont_send_event = false;
-
if (event.TouchInput.touchedCount == 1) {
switch (event.TouchInput.Event) {
case ETIE_PRESSED_DOWN:
@@ -205,11 +203,7 @@ bool GUIModalMenu::preprocessEvent(const SEvent &event)
m_down_pos = v2s32(0, 0);
break;
default:
- dont_send_event = true;
- // this is not supposed to happen
- errorstream << "GUIModalMenu::preprocessEvent"
- << " unexpected usecase Event="
- << event.TouchInput.Event << std::endl;
+ break;
}
} else if ((event.TouchInput.touchedCount == 2) &&
(event.TouchInput.Event == ETIE_PRESSED_DOWN)) {
@@ -219,50 +213,37 @@ bool GUIModalMenu::preprocessEvent(const SEvent &event)
translated.MouseInput.ButtonStates = EMBSM_LEFT | EMBSM_RIGHT;
translated.MouseInput.X = m_pointer.X;
translated.MouseInput.Y = m_pointer.Y;
- if (hovered) {
+ if (hovered)
hovered->OnEvent(translated);
- }
translated.MouseInput.Event = EMIE_RMOUSE_LEFT_UP;
translated.MouseInput.ButtonStates = EMBSM_LEFT;
- if (hovered) {
+ if (hovered)
hovered->OnEvent(translated);
- }
- dont_send_event = true;
- }
- // ignore unhandled 2 touch events ... accidental moving for example
- else if (event.TouchInput.touchedCount == 2) {
- dont_send_event = true;
- }
- else if (event.TouchInput.touchedCount > 2) {
- errorstream << "GUIModalMenu::preprocessEvent"
- << " to many multitouch events "
- << event.TouchInput.touchedCount << " ignoring them"
- << std::endl;
- }
- if (dont_send_event) {
+ return true;
+ } else {
+ // ignore unhandled 2 touch events (accidental moving for example)
return true;
}
// check if translated event needs to be preprocessed again
- if (preprocessEvent(translated)) {
+ if (preprocessEvent(translated))
return true;
- }
+
if (hovered) {
grab();
bool retval = hovered->OnEvent(translated);
- if (event.TouchInput.Event == ETIE_LEFT_UP) {
+ if (event.TouchInput.Event == ETIE_LEFT_UP)
// reset pointer
m_pointer = v2s32(0, 0);
- }
+
drop();
return retval;
}
}
- // clang-format on
#endif
return false;
}
@@ -271,14 +252,12 @@ bool GUIModalMenu::preprocessEvent(const SEvent &event)
bool GUIModalMenu::hasAndroidUIInput()
{
// no dialog shown
- if (m_jni_field_name.empty()) {
+ if (m_jni_field_name.empty())
return false;
- }
// still waiting
- if (porting::getInputDialogState() == -1) {
+ if (porting::getInputDialogState() == -1)
return true;
- }
// no value abort dialog processing
if (porting::getInputDialogState() != 0) {
diff --git a/src/gui/touchscreengui.cpp b/src/gui/touchscreengui.cpp
index 94e331f72..0d64aa618 100644
--- a/src/gui/touchscreengui.cpp
+++ b/src/gui/touchscreengui.cpp
@@ -34,19 +34,16 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <ISceneCollisionManager.h>
-// Very slow button repeat frequency (in seconds)
-#define SLOW_BUTTON_REPEAT (1.0f)
-
using namespace irr::core;
-const char **touchgui_button_imagenames = (const char *[]) {
+const char **button_imagenames = (const char *[]) {
"jump_btn.png",
"down.png",
"zoom.png",
"aux_btn.png"
};
-const char **touchgui_joystick_imagenames = (const char *[]) {
+const char **joystick_imagenames = (const char *[]) {
"joystick_off.png",
"joystick_bg.png",
"joystick_center.png"
@@ -113,15 +110,17 @@ static irr::EKEY_CODE id2keycode(touch_gui_button_id id)
case range_id:
key = "rangeselect";
break;
+ default:
+ break;
}
- assert(key != "");
+ assert(!key.empty());
return keyname_to_keycode(g_settings->get("keymap_" + key).c_str());
}
TouchScreenGUI *g_touchscreengui;
static void load_button_texture(button_info *btn, const char *path,
- rect<s32> button_rect, ISimpleTextureSource *tsrc, video::IVideoDriver *driver)
+ const rect<s32> &button_rect, ISimpleTextureSource *tsrc, video::IVideoDriver *driver)
{
unsigned int tid;
video::ITexture *texture = guiScalingImageButton(driver,
@@ -141,7 +140,7 @@ static void load_button_texture(button_info *btn, const char *path,
}
btn->guibutton->setDrawBorder(false);
btn->guibutton->setText(L"");
- }
+ }
}
AutoHideButtonBar::AutoHideButtonBar(IrrlichtDevice *device,
@@ -153,8 +152,8 @@ AutoHideButtonBar::AutoHideButtonBar(IrrlichtDevice *device,
}
void AutoHideButtonBar::init(ISimpleTextureSource *tsrc,
- const char *starter_img, int button_id, v2s32 UpperLeft,
- v2s32 LowerRight, autohide_button_bar_dir dir, float timeout)
+ const char *starter_img, int button_id, const v2s32 &UpperLeft,
+ const v2s32 &LowerRight, autohide_button_bar_dir dir, float timeout)
{
m_texturesource = tsrc;
@@ -166,7 +165,7 @@ void AutoHideButtonBar::init(ISimpleTextureSource *tsrc,
irr::core::rect<int> current_button = rect<s32>(UpperLeft.X, UpperLeft.Y,
LowerRight.X, LowerRight.Y);
- m_starter.guibutton = m_guienv->addButton(current_button, 0, button_id, L"", 0);
+ m_starter.guibutton = m_guienv->addButton(current_button, nullptr, button_id, L"", nullptr);
m_starter.guibutton->grab();
m_starter.repeatcounter = -1;
m_starter.keycode = KEY_OEM_8; // use invalid keycode as it's not relevant
@@ -201,16 +200,14 @@ void AutoHideButtonBar::addButton(touch_gui_button_id button_id,
}
int button_size = 0;
- if ((m_dir == AHBB_Dir_Top_Bottom) || (m_dir == AHBB_Dir_Bottom_Top)) {
+ if ((m_dir == AHBB_Dir_Top_Bottom) || (m_dir == AHBB_Dir_Bottom_Top))
button_size = m_lower_right.X - m_upper_left.X;
- } else {
+ else
button_size = m_lower_right.Y - m_upper_left.Y;
- }
irr::core::rect<int> current_button;
if ((m_dir == AHBB_Dir_Right_Left) || (m_dir == AHBB_Dir_Left_Right)) {
-
int x_start = 0;
int x_end = 0;
@@ -227,8 +224,8 @@ void AutoHideButtonBar::addButton(touch_gui_button_id button_id,
current_button = rect<s32>(x_start, m_upper_left.Y, x_end,
m_lower_right.Y);
} else {
- int y_start = 0;
- int y_end = 0;
+ double y_start = 0;
+ double y_end = 0;
if (m_dir == AHBB_Dir_Top_Bottom) {
y_start = m_lower_right.X + (button_size * 1.25 * m_buttons.size())
@@ -240,12 +237,13 @@ void AutoHideButtonBar::addButton(touch_gui_button_id button_id,
y_start = y_end - button_size;
}
- current_button = rect<s32>(m_upper_left.X, y_start, m_lower_right.Y,
- y_end);
+ current_button = rect<s32>(m_upper_left.X, y_start,
+ m_lower_right.Y, y_end);
}
- button_info *btn = new button_info();
- btn->guibutton = m_guienv->addButton(current_button, 0, button_id, caption, 0);
+ auto *btn = new button_info();
+ btn->guibutton = m_guienv->addButton(current_button,
+ nullptr, button_id, caption, nullptr);
btn->guibutton->grab();
btn->guibutton->setVisible(false);
btn->guibutton->setEnabled(false);
@@ -275,26 +273,23 @@ bool AutoHideButtonBar::isButton(const SEvent &event)
{
IGUIElement *rootguielement = m_guienv->getRootGUIElement();
- if (rootguielement == NULL) {
+ if (rootguielement == nullptr)
return false;
- }
gui::IGUIElement *element = rootguielement->getElementFromPoint(
core::position2d<s32>(event.TouchInput.X, event.TouchInput.Y));
- if (element == NULL) {
+ if (element == nullptr)
return false;
- }
if (m_active) {
// check for all buttons in vector
-
- std::vector<button_info *>::iterator iter = m_buttons.begin();
+ auto iter = m_buttons.begin();
while (iter != m_buttons.end()) {
if ((*iter)->guibutton == element) {
- SEvent *translated = new SEvent();
+ auto *translated = new SEvent();
memset(translated, 0, sizeof(SEvent));
translated->EventType = irr::EET_KEY_INPUT_EVENT;
translated->KeyInput.Key = (*iter)->keycode;
@@ -341,7 +336,7 @@ bool AutoHideButtonBar::isButton(const SEvent &event)
m_active = true;
m_timeout = 0;
- std::vector<button_info*>::iterator iter = m_buttons.begin();
+ auto iter = m_buttons.begin();
while (iter != m_buttons.end()) {
(*iter)->guibutton->setVisible(true);
@@ -355,41 +350,13 @@ bool AutoHideButtonBar::isButton(const SEvent &event)
return false;
}
-bool AutoHideButtonBar::isReleaseButton(int eventID)
-{
- std::vector<int>::iterator id = std::find(m_starter.ids.begin(),
- m_starter.ids.end(), eventID);
-
- if (id != m_starter.ids.end()) {
- m_starter.ids.erase(id);
- return true;
- }
-
- std::vector<button_info *>::iterator iter = m_buttons.begin();
-
- while (iter != m_buttons.end()) {
- std::vector<int>::iterator id = std::find((*iter)->ids.begin(),
- (*iter)->ids.end(), eventID);
-
- if (id != (*iter)->ids.end()) {
- (*iter)->ids.erase(id);
- // TODO handle settings button release
- return true;
- }
- ++iter;
- }
-
- return false;
-}
-
void AutoHideButtonBar::step(float dtime)
{
if (m_active) {
m_timeout += dtime;
- if (m_timeout > m_timeout_value) {
+ if (m_timeout > m_timeout_value)
deactivate();
- }
}
}
@@ -401,11 +368,11 @@ void AutoHideButtonBar::deactivate()
}
m_active = false;
- std::vector<button_info *>::iterator iter = m_buttons.begin();
+ auto iter = m_buttons.begin();
while (iter != m_buttons.end()) {
- (*iter)->guibutton->setVisible(false);
- (*iter)->guibutton->setEnabled(false);
+ (*iter)->guibutton->setVisible(false);
+ (*iter)->guibutton->setEnabled(false);
++iter;
}
}
@@ -416,7 +383,7 @@ void AutoHideButtonBar::hide()
m_starter.guibutton->setVisible(false);
m_starter.guibutton->setEnabled(false);
- std::vector<button_info *>::iterator iter = m_buttons.begin();
+ auto iter = m_buttons.begin();
while (iter != m_buttons.end()) {
(*iter)->guibutton->setVisible(false);
@@ -430,7 +397,7 @@ void AutoHideButtonBar::show()
m_visible = true;
if (m_active) {
- std::vector<button_info *>::iterator iter = m_buttons.begin();
+ auto iter = m_buttons.begin();
while (iter != m_buttons.end()) {
(*iter)->guibutton->setVisible(true);
@@ -450,24 +417,26 @@ TouchScreenGUI::TouchScreenGUI(IrrlichtDevice *device, IEventReceiver *receiver)
m_settingsbar(device, receiver),
m_rarecontrolsbar(device, receiver)
{
- for (unsigned int i=0; i < after_last_element_id; i++) {
- m_buttons[i].guibutton = 0;
- m_buttons[i].repeatcounter = -1;
- m_buttons[i].repeatdelay = BUTTON_REPEAT_DELAY;
+ for (auto &button : m_buttons) {
+ button.guibutton = nullptr;
+ button.repeatcounter = -1;
+ button.repeatdelay = BUTTON_REPEAT_DELAY;
}
m_touchscreen_threshold = g_settings->getU16("touchscreen_threshold");
m_fixed_joystick = g_settings->getBool("fixed_virtual_joystick");
m_joystick_triggers_special1 = g_settings->getBool("virtual_joystick_triggers_aux");
m_screensize = m_device->getVideoDriver()->getScreenSize();
+ button_size = MYMIN(m_screensize.Y / 4.5f,
+ porting::getDisplayDensity() *
+ g_settings->getFloat("hud_scaling") * 65.0f);
}
-void TouchScreenGUI::initButton(touch_gui_button_id id, rect<s32> button_rect,
- std::wstring caption, bool immediate_release, float repeat_delay)
+void TouchScreenGUI::initButton(touch_gui_button_id id, const rect<s32> &button_rect,
+ const std::wstring &caption, bool immediate_release, float repeat_delay)
{
-
button_info *btn = &m_buttons[id];
- btn->guibutton = m_guienv->addButton(button_rect, 0, id, caption.c_str());
+ btn->guibutton = m_guienv->addButton(button_rect, nullptr, id, caption.c_str());
btn->guibutton->grab();
btn->repeatcounter = -1;
btn->repeatdelay = repeat_delay;
@@ -475,42 +444,29 @@ void TouchScreenGUI::initButton(touch_gui_button_id id, rect<s32> button_rect,
btn->immediate_release = immediate_release;
btn->ids.clear();
- load_button_texture(btn, touchgui_button_imagenames[id], button_rect,
+ load_button_texture(btn, button_imagenames[id], button_rect,
m_texturesource, m_device->getVideoDriver());
}
-button_info *TouchScreenGUI::initJoystickButton(touch_gui_button_id id, rect<s32> button_rect,
- int texture_id, bool visible)
+button_info *TouchScreenGUI::initJoystickButton(touch_gui_button_id id,
+ const rect<s32> &button_rect, int texture_id, bool visible)
{
- button_info *btn = new button_info();
- btn->guibutton = m_guienv->addButton(button_rect, 0, id, L"O");
+ auto *btn = new button_info();
+ btn->guibutton = m_guienv->addButton(button_rect, nullptr, id, L"O");
btn->guibutton->setVisible(visible);
btn->guibutton->grab();
btn->ids.clear();
- load_button_texture(btn, touchgui_joystick_imagenames[texture_id], button_rect,
- m_texturesource, m_device->getVideoDriver());
+ load_button_texture(btn, joystick_imagenames[texture_id],
+ button_rect, m_texturesource, m_device->getVideoDriver());
return btn;
}
-static int getMaxControlPadSize(float density) {
- return 200 * density * g_settings->getFloat("hud_scaling");
-}
-
-int TouchScreenGUI::getGuiButtonSize()
-{
- u32 control_pad_size = MYMIN((2 * m_screensize.Y) / 3,
- getMaxControlPadSize(porting::getDisplayDensity()));
-
- return control_pad_size / 3;
-}
-
void TouchScreenGUI::init(ISimpleTextureSource *tsrc)
{
assert(tsrc);
- u32 button_size = getGuiButtonSize();
m_visible = true;
m_texturesource = tsrc;
@@ -608,35 +564,31 @@ void TouchScreenGUI::init(ISimpleTextureSource *tsrc)
m_rarecontrolsbar.addButton(chat_id, L"Chat", "chat_btn.png");
m_rarecontrolsbar.addButton(inventory_id, L"inv", "inventory_btn.png");
m_rarecontrolsbar.addButton(drop_id, L"drop", "drop_btn.png");
-
}
touch_gui_button_id TouchScreenGUI::getButtonID(s32 x, s32 y)
{
IGUIElement *rootguielement = m_guienv->getRootGUIElement();
- if (rootguielement != NULL) {
+ if (rootguielement != nullptr) {
gui::IGUIElement *element =
rootguielement->getElementFromPoint(core::position2d<s32>(x, y));
- if (element) {
- for (unsigned int i=0; i < after_last_element_id; i++) {
- if (element == m_buttons[i].guibutton) {
+ if (element)
+ for (unsigned int i = 0; i < after_last_element_id; i++)
+ if (element == m_buttons[i].guibutton)
return (touch_gui_button_id) i;
- }
- }
- }
}
+
return after_last_element_id;
}
-touch_gui_button_id TouchScreenGUI::getButtonID(int eventID)
+touch_gui_button_id TouchScreenGUI::getButtonID(size_t eventID)
{
- for (unsigned int i=0; i < after_last_element_id; i++) {
+ for (unsigned int i = 0; i < after_last_element_id; i++) {
button_info *btn = &m_buttons[i];
- std::vector<int>::iterator id =
- std::find(btn->ids.begin(), btn->ids.end(), eventID);
+ auto id = std::find(btn->ids.begin(), btn->ids.end(), eventID);
if (id != btn->ids.end())
return (touch_gui_button_id) i;
@@ -648,55 +600,30 @@ touch_gui_button_id TouchScreenGUI::getButtonID(int eventID)
bool TouchScreenGUI::isHUDButton(const SEvent &event)
{
// check if hud item is pressed
- for (std::map<int, rect<s32> >::iterator iter = m_hud_rects.begin();
- iter != m_hud_rects.end(); ++iter) {
- if (iter->second.isPointInside(
- v2s32(event.TouchInput.X,
- event.TouchInput.Y)
- )) {
- if ( iter->first < 8) {
- SEvent *translated = new SEvent();
- memset(translated, 0, sizeof(SEvent));
- translated->EventType = irr::EET_KEY_INPUT_EVENT;
- translated->KeyInput.Key = (irr::EKEY_CODE) (KEY_KEY_1 + iter->first);
- translated->KeyInput.Control = false;
- translated->KeyInput.Shift = false;
- translated->KeyInput.PressedDown = true;
- m_receiver->OnEvent(*translated);
- m_hud_ids[event.TouchInput.ID] = translated->KeyInput.Key;
- delete translated;
- return true;
- }
+ for (auto &hud_rect : m_hud_rects) {
+ if (hud_rect.second.isPointInside(v2s32(event.TouchInput.X,
+ event.TouchInput.Y))) {
+ auto *translated = new SEvent();
+ memset(translated, 0, sizeof(SEvent));
+ translated->EventType = irr::EET_KEY_INPUT_EVENT;
+ translated->KeyInput.Key = (irr::EKEY_CODE) (KEY_KEY_1 + hud_rect.first);
+ translated->KeyInput.Control = false;
+ translated->KeyInput.Shift = false;
+ translated->KeyInput.PressedDown = true;
+ m_receiver->OnEvent(*translated);
+ m_hud_ids[event.TouchInput.ID] = translated->KeyInput.Key;
+ delete translated;
+ return true;
}
}
return false;
}
-bool TouchScreenGUI::isReleaseHUDButton(int eventID)
-{
- std::map<int, irr::EKEY_CODE>::iterator iter = m_hud_ids.find(eventID);
-
- if (iter != m_hud_ids.end()) {
- SEvent *translated = new SEvent();
- memset(translated, 0, sizeof(SEvent));
- translated->EventType = irr::EET_KEY_INPUT_EVENT;
- translated->KeyInput.Key = iter->second;
- translated->KeyInput.PressedDown = false;
- translated->KeyInput.Control = false;
- translated->KeyInput.Shift = false;
- m_receiver->OnEvent(*translated);
- m_hud_ids.erase(iter);
- delete translated;
- return true;
- }
- return false;
-}
-
void TouchScreenGUI::handleButtonEvent(touch_gui_button_id button,
- int eventID, bool action)
+ size_t eventID, bool action)
{
button_info *btn = &m_buttons[button];
- SEvent *translated = new SEvent();
+ auto *translated = new SEvent();
memset(translated, 0, sizeof(SEvent));
translated->EventType = irr::EET_KEY_INPUT_EVENT;
translated->KeyInput.Key = btn->keycode;
@@ -717,16 +644,16 @@ void TouchScreenGUI::handleButtonEvent(touch_gui_button_id button,
translated->KeyInput.Key = btn->keycode;
m_receiver->OnEvent(*translated);
}
+
// remove event
if ((!action) || (btn->immediate_release)) {
-
- std::vector<int>::iterator pos =
- std::find(btn->ids.begin(), btn->ids.end(), eventID);
+ auto pos = std::find(btn->ids.begin(), btn->ids.end(), eventID);
// has to be in touch list
assert(pos != btn->ids.end());
btn->ids.erase(pos);
- if (btn->ids.size() > 0) { return; }
+ if (!btn->ids.empty())
+ return;
translated->KeyInput.PressedDown = false;
btn->repeatcounter = -1;
@@ -735,30 +662,21 @@ void TouchScreenGUI::handleButtonEvent(touch_gui_button_id button,
delete translated;
}
-
-void TouchScreenGUI::handleReleaseEvent(int evt_id)
+void TouchScreenGUI::handleReleaseEvent(size_t evt_id)
{
touch_gui_button_id button = getButtonID(evt_id);
- // handle button events
+
if (button != after_last_element_id) {
+ // handle button events
handleButtonEvent(button, evt_id, false);
- }
- // handle hud button events
- else if (isReleaseHUDButton(evt_id)) {
- // nothing to do here
- } else if (m_settingsbar.isReleaseButton(evt_id)) {
- // nothing to do here
- } else if (m_rarecontrolsbar.isReleaseButton(evt_id)) {
- // nothing to do here
- }
- // handle the point used for moving view
- else if (evt_id == m_move_id) {
+ } else if (evt_id == m_move_id) {
+ // handle the point used for moving view
m_move_id = -1;
// if this pointer issued a mouse event issue symmetric release here
if (m_move_sent_as_mouse_event) {
- SEvent *translated = new SEvent;
+ auto *translated = new SEvent;
memset(translated, 0, sizeof(SEvent));
translated->EventType = EET_MOUSE_INPUT_EVENT;
translated->MouseInput.X = m_move_downlocation.X;
@@ -769,32 +687,31 @@ void TouchScreenGUI::handleReleaseEvent(int evt_id)
translated->MouseInput.Event = EMIE_LMOUSE_LEFT_UP;
m_receiver->OnEvent(*translated);
delete translated;
- }
- else {
+ } else {
// do double tap detection
doubleTapDetection();
}
}
+
// handle joystick
else if (evt_id == m_joystick_id) {
m_joystick_id = -1;
// reset joystick
- for (unsigned int i = 0; i < 4; i ++)
+ for (unsigned int i = 0; i < 4; i++)
m_joystick_status[i] = false;
applyJoystickStatus();
m_joystick_btn_off->guibutton->setVisible(true);
m_joystick_btn_bg->guibutton->setVisible(false);
m_joystick_btn_center->guibutton->setVisible(false);
- }
- else {
+ } else {
infostream
<< "TouchScreenGUI::translateEvent released unknown button: "
<< evt_id << std::endl;
}
- for (std::vector<id_status>::iterator iter = m_known_ids.begin();
+ for (auto iter = m_known_ids.begin();
iter != m_known_ids.end(); ++iter) {
if (iter->id == evt_id) {
m_known_ids.erase(iter);
@@ -806,27 +723,28 @@ void TouchScreenGUI::handleReleaseEvent(int evt_id)
void TouchScreenGUI::translateEvent(const SEvent &event)
{
if (!m_visible) {
- infostream << "TouchScreenGUI::translateEvent got event but not visible?!" << std::endl;
+ infostream
+ << "TouchScreenGUI::translateEvent got event but not visible!"
+ << std::endl;
return;
}
- if (event.EventType != EET_TOUCH_INPUT_EVENT) {
+ if (event.EventType != EET_TOUCH_INPUT_EVENT)
return;
- }
if (event.TouchInput.Event == ETIE_PRESSED_DOWN) {
-
- /* add to own copy of eventlist ...
- * android would provide this information but irrlicht guys don't
+ /*
+ * Add to own copy of event list...
+ * android would provide this information but Irrlicht guys don't
* wanna design a efficient interface
*/
- id_status toadd;
+ id_status toadd{};
toadd.id = event.TouchInput.ID;
toadd.X = event.TouchInput.X;
toadd.Y = event.TouchInput.Y;
m_known_ids.push_back(toadd);
- int eventID = event.TouchInput.ID;
+ size_t eventID = event.TouchInput.ID;
touch_gui_button_id button =
getButtonID(event.TouchInput.X, event.TouchInput.Y);
@@ -846,21 +764,19 @@ void TouchScreenGUI::translateEvent(const SEvent &event)
} else if (m_rarecontrolsbar.isButton(event)) {
m_settingsbar.deactivate();
// already handled in isSettingsBarButton()
- }
- // handle non button events
- else {
+ } else {
+ // handle non button events
m_settingsbar.deactivate();
m_rarecontrolsbar.deactivate();
- u32 button_size = getGuiButtonSize();
- s32 dxj = event.TouchInput.X - button_size * 5 / 2;
- s32 dyj = event.TouchInput.Y - m_screensize.Y + button_size * 5 / 2;
+ s32 dxj = event.TouchInput.X - button_size * 5.0f / 2.0f;
+ s32 dyj = event.TouchInput.Y - m_screensize.Y + button_size * 5.0f / 2.0f;
/* Select joystick when left 1/3 of screen dragged or
* when joystick tapped (fixed joystick position)
*/
if ((m_fixed_joystick && dxj * dxj + dyj * dyj <= button_size * button_size * 1.5 * 1.5) ||
- (!m_fixed_joystick && event.TouchInput.X < m_screensize.X / 3)) {
+ (!m_fixed_joystick && event.TouchInput.X < m_screensize.X / 3.0f)) {
// If we don't already have a starting point for joystick make this the one.
if (m_joystick_id == -1) {
m_joystick_id = event.TouchInput.ID;
@@ -871,14 +787,14 @@ void TouchScreenGUI::translateEvent(const SEvent &event)
m_joystick_btn_center->guibutton->setVisible(true);
// If it's a fixed joystick, don't move the joystick "button".
- if (!m_fixed_joystick) {
+ if (!m_fixed_joystick)
m_joystick_btn_bg->guibutton->setRelativePosition(v2s32(
- event.TouchInput.X - button_size * 3 / 2,
- event.TouchInput.Y - button_size * 3 / 2));
- }
+ event.TouchInput.X - button_size * 3.0f / 2.0f,
+ event.TouchInput.Y - button_size * 3.0f / 2.0f));
+
m_joystick_btn_center->guibutton->setRelativePosition(v2s32(
- event.TouchInput.X - button_size / 2,
- event.TouchInput.Y - button_size / 2));
+ event.TouchInput.X - button_size / 2.0f,
+ event.TouchInput.Y - button_size / 2.0f));
}
} else {
// If we don't already have a moving point make this the moving one.
@@ -895,17 +811,15 @@ void TouchScreenGUI::translateEvent(const SEvent &event)
m_pointerpos[event.TouchInput.ID] = v2s32(event.TouchInput.X, event.TouchInput.Y);
}
else if (event.TouchInput.Event == ETIE_LEFT_UP) {
- verbosestream << "Up event for pointerid: " << event.TouchInput.ID << std::endl;
+ verbosestream
+ << "Up event for pointerid: " << event.TouchInput.ID << std::endl;
handleReleaseEvent(event.TouchInput.ID);
- }
- else {
+ } else {
assert(event.TouchInput.Event == ETIE_MOVED);
- int move_idx = event.TouchInput.ID;
if (m_pointerpos[event.TouchInput.ID] ==
- v2s32(event.TouchInput.X, event.TouchInput.Y)) {
+ v2s32(event.TouchInput.X, event.TouchInput.Y))
return;
- }
if (m_move_id != -1) {
if ((event.TouchInput.ID == m_move_id) &&
@@ -928,9 +842,7 @@ void TouchScreenGUI::translateEvent(const SEvent &event)
s32 dy = Y - m_pointerpos[event.TouchInput.ID].Y;
// adapt to similar behaviour as pc screen
- double d = g_settings->getFloat("mouse_sensitivity") * 4;
- double old_yaw = m_camera_yaw_change;
- double old_pitch = m_camera_pitch;
+ double d = g_settings->getFloat("mouse_sensitivity") * 3.0f;
m_camera_yaw_change -= dx * d;
m_camera_pitch = MYMIN(MYMAX(m_camera_pitch + (dy * d), -180), 180);
@@ -942,8 +854,7 @@ void TouchScreenGUI::translateEvent(const SEvent &event)
->getRayFromScreenCoordinates(v2s32(X, Y));
m_pointerpos[event.TouchInput.ID] = v2s32(X, Y);
}
- }
- else if ((event.TouchInput.ID == m_move_id) &&
+ } else if ((event.TouchInput.ID == m_move_id) &&
(m_move_sent_as_mouse_event)) {
m_shootline = m_device
->getSceneManager()
@@ -954,7 +865,6 @@ void TouchScreenGUI::translateEvent(const SEvent &event)
}
if (m_joystick_id != -1 && event.TouchInput.ID == m_joystick_id) {
- u32 button_size = getGuiButtonSize();
s32 X = event.TouchInput.X;
s32 Y = event.TouchInput.Y;
@@ -967,8 +877,8 @@ void TouchScreenGUI::translateEvent(const SEvent &event)
double distance_sq = dx * dx + dy * dy;
- s32 dxj = event.TouchInput.X - button_size * 5 / 2;
- s32 dyj = event.TouchInput.Y - m_screensize.Y + button_size * 5 / 2;
+ s32 dxj = event.TouchInput.X - button_size * 5.0f / 2.0f;
+ s32 dyj = event.TouchInput.Y - m_screensize.Y + button_size * 5.0f / 2.0f;
bool inside_joystick = (dxj * dxj + dyj * dyj <= button_size * button_size * 1.5 * 1.5);
if (m_joystick_has_really_moved ||
@@ -986,8 +896,8 @@ void TouchScreenGUI::translateEvent(const SEvent &event)
angle = fmod(angle + 180 + 22.5, 360);
// reset state before applying
- for (unsigned int i = 0; i < 5; i ++)
- m_joystick_status[i] = false;
+ for (bool & joystick_status : m_joystick_status)
+ joystick_status = false;
if (distance <= m_touchscreen_threshold) {
// do nothing
@@ -1016,8 +926,8 @@ void TouchScreenGUI::translateEvent(const SEvent &event)
if (distance > button_size) {
m_joystick_status[j_special1] = true;
// move joystick "button"
- s32 ndx = (s32) button_size * dx / distance - (s32) button_size / 2;
- s32 ndy = (s32) button_size * dy / distance - (s32) button_size / 2;
+ s32 ndx = button_size * dx / distance - button_size / 2.0f;
+ s32 ndy = button_size * dy / distance - button_size / 2.0f;
if (m_fixed_joystick) {
m_joystick_btn_center->guibutton->setRelativePosition(v2s32(
button_size * 5 / 2 + ndx,
@@ -1028,64 +938,54 @@ void TouchScreenGUI::translateEvent(const SEvent &event)
m_pointerpos[event.TouchInput.ID].Y + ndy));
}
} else {
- m_joystick_btn_center->guibutton->setRelativePosition(v2s32(
- X - button_size / 2, Y - button_size / 2));
+ m_joystick_btn_center->guibutton->setRelativePosition(
+ v2s32(X - button_size / 2, Y - button_size / 2));
}
}
}
- if (m_move_id == -1 && m_joystick_id == -1) {
+ if (m_move_id == -1 && m_joystick_id == -1)
handleChangedButton(event);
- }
}
}
void TouchScreenGUI::handleChangedButton(const SEvent &event)
{
for (unsigned int i = 0; i < after_last_element_id; i++) {
-
- if (m_buttons[i].ids.empty()) {
+ if (m_buttons[i].ids.empty())
continue;
- }
- for (std::vector<int>::iterator iter = m_buttons[i].ids.begin();
- iter != m_buttons[i].ids.end(); ++iter) {
+ for (auto iter = m_buttons[i].ids.begin();
+ iter != m_buttons[i].ids.end(); ++iter) {
if (event.TouchInput.ID == *iter) {
-
int current_button_id =
getButtonID(event.TouchInput.X, event.TouchInput.Y);
- if (current_button_id == i) {
+ if (current_button_id == i)
continue;
- }
// remove old button
handleButtonEvent((touch_gui_button_id) i, *iter, false);
- if (current_button_id == after_last_element_id) {
+ if (current_button_id == after_last_element_id)
return;
- }
+
handleButtonEvent((touch_gui_button_id) current_button_id, *iter, true);
return;
-
}
}
}
int current_button_id = getButtonID(event.TouchInput.X, event.TouchInput.Y);
- if (current_button_id == after_last_element_id) {
+ if (current_button_id == after_last_element_id)
return;
- }
button_info *btn = &m_buttons[current_button_id];
if (std::find(btn->ids.begin(), btn->ids.end(), event.TouchInput.ID)
== btn->ids.end())
- {
handleButtonEvent((touch_gui_button_id) current_button_id,
event.TouchInput.ID, true);
- }
-
}
bool TouchScreenGUI::doubleTapDetection()
@@ -1102,14 +1002,15 @@ bool TouchScreenGUI::doubleTapDetection()
return false;
double distance = sqrt(
- (m_key_events[0].x - m_key_events[1].x) * (m_key_events[0].x - m_key_events[1].x) +
- (m_key_events[0].y - m_key_events[1].y) * (m_key_events[0].y - m_key_events[1].y));
-
+ (m_key_events[0].x - m_key_events[1].x) *
+ (m_key_events[0].x - m_key_events[1].x) +
+ (m_key_events[0].y - m_key_events[1].y) *
+ (m_key_events[0].y - m_key_events[1].y));
if (distance > (20 + m_touchscreen_threshold))
return false;
- SEvent *translated = new SEvent();
+ auto *translated = new SEvent();
memset(translated, 0, sizeof(SEvent));
translated->EventType = EET_MOUSE_INPUT_EVENT;
translated->MouseInput.X = m_key_events[0].x;
@@ -1129,17 +1030,16 @@ bool TouchScreenGUI::doubleTapDetection()
m_receiver->OnEvent(*translated);
translated->MouseInput.ButtonStates = 0;
- translated->MouseInput.Event = EMIE_RMOUSE_LEFT_UP;
+ translated->MouseInput.Event = EMIE_RMOUSE_LEFT_UP;
verbosestream << "TouchScreenGUI::translateEvent right click release" << std::endl;
m_receiver->OnEvent(*translated);
delete translated;
return true;
-
}
void TouchScreenGUI::applyJoystickStatus()
{
- for (unsigned int i = 0; i < 5; i ++) {
+ for (unsigned int i = 0; i < 5; i++) {
if (i == 4 && !m_joystick_triggers_special1)
continue;
@@ -1158,50 +1058,48 @@ void TouchScreenGUI::applyJoystickStatus()
TouchScreenGUI::~TouchScreenGUI()
{
- for (unsigned int i = 0; i < after_last_element_id; i++) {
- button_info *btn = &m_buttons[i];
- if (btn->guibutton) {
- btn->guibutton->drop();
- btn->guibutton = NULL;
+ for (auto &button : m_buttons) {
+ if (button.guibutton) {
+ button.guibutton->drop();
+ button.guibutton = nullptr;
}
}
if (m_joystick_btn_off->guibutton) {
m_joystick_btn_off->guibutton->drop();
- m_joystick_btn_off->guibutton = NULL;
+ m_joystick_btn_off->guibutton = nullptr;
}
if (m_joystick_btn_bg->guibutton) {
m_joystick_btn_bg->guibutton->drop();
- m_joystick_btn_bg->guibutton = NULL;
+ m_joystick_btn_bg->guibutton = nullptr;
}
if (m_joystick_btn_center->guibutton) {
m_joystick_btn_center->guibutton->drop();
- m_joystick_btn_center->guibutton = NULL;
+ m_joystick_btn_center->guibutton = nullptr;
}
}
void TouchScreenGUI::step(float dtime)
{
// simulate keyboard repeats
- for (unsigned int i = 0; i < after_last_element_id; i++) {
- button_info *btn = &m_buttons[i];
-
- if (btn->ids.size() > 0) {
- btn->repeatcounter += dtime;
+ for (auto &button : m_buttons) {
+ if (!button.ids.empty()) {
+ button.repeatcounter += dtime;
// in case we're moving around digging does not happen
if (m_move_id != -1)
m_move_has_really_moved = true;
- if (btn->repeatcounter < btn->repeatdelay) continue;
+ if (button.repeatcounter < button.repeatdelay)
+ continue;
- btn->repeatcounter = 0;
+ button.repeatcounter = 0;
SEvent translated;
memset(&translated, 0, sizeof(SEvent));
translated.EventType = irr::EET_KEY_INPUT_EVENT;
- translated.KeyInput.Key = btn->keycode;
+ translated.KeyInput.Key = button.keycode;
translated.KeyInput.PressedDown = false;
m_receiver->OnEvent(translated);
@@ -1211,7 +1109,12 @@ void TouchScreenGUI::step(float dtime)
}
// joystick
- applyJoystickStatus();
+ for (unsigned int i = 0; i < 4; i++) {
+ if (m_joystick_status[i]) {
+ applyJoystickStatus();
+ break;
+ }
+ }
// if a new placed pointer isn't moved for some time start digging
if ((m_move_id != -1) &&
@@ -1259,22 +1162,18 @@ void TouchScreenGUI::registerHudItem(int index, const rect<s32> &rect)
void TouchScreenGUI::Toggle(bool visible)
{
m_visible = visible;
- for (unsigned int i = 0; i < after_last_element_id; i++) {
- button_info *btn = &m_buttons[i];
- if (btn->guibutton) {
- btn->guibutton->setVisible(visible);
- }
+ for (auto &button : m_buttons) {
+ if (button.guibutton)
+ button.guibutton->setVisible(visible);
}
- if (m_joystick_btn_off->guibutton) {
+ if (m_joystick_btn_off->guibutton)
m_joystick_btn_off->guibutton->setVisible(visible);
- }
// clear all active buttons
if (!visible) {
- while (m_known_ids.size() > 0) {
+ while (!m_known_ids.empty())
handleReleaseEvent(m_known_ids.begin()->id);
- }
m_settingsbar.hide();
m_rarecontrolsbar.hide();
diff --git a/src/gui/touchscreengui.h b/src/gui/touchscreengui.h
index 2a3f24a3f..761d33207 100644
--- a/src/gui/touchscreengui.h
+++ b/src/gui/touchscreengui.h
@@ -80,21 +80,22 @@ typedef enum
} autohide_button_bar_dir;
#define MIN_DIG_TIME_MS 500
-#define MAX_TOUCH_COUNT 64
#define BUTTON_REPEAT_DELAY 0.2f
-
#define SETTINGS_BAR_Y_OFFSET 5
#define RARE_CONTROLS_BAR_Y_OFFSET 5
-extern const char **touchgui_button_imagenames;
-extern const char **touchgui_joystick_imagenames;
+// Very slow button repeat frequency
+#define SLOW_BUTTON_REPEAT 1.0f
+
+extern const char **button_imagenames;
+extern const char **joystick_imagenames;
struct button_info
{
float repeatcounter;
float repeatdelay;
irr::EKEY_CODE keycode;
- std::vector<int> ids;
+ std::vector<size_t> ids;
IGUIButton *guibutton = nullptr;
bool immediate_release;
@@ -109,8 +110,8 @@ public:
AutoHideButtonBar(IrrlichtDevice *device, IEventReceiver *receiver);
void init(ISimpleTextureSource *tsrc, const char *starter_img, int button_id,
- v2s32 UpperLeft, v2s32 LowerRight, autohide_button_bar_dir dir,
- float timeout);
+ const v2s32 &UpperLeft, const v2s32 &LowerRight,
+ autohide_button_bar_dir dir, float timeout);
~AutoHideButtonBar();
@@ -125,9 +126,6 @@ public:
// detect settings bar button events
bool isButton(const SEvent &event);
- // handle released hud buttons
- bool isReleaseButton(int eventID);
-
// step handler
void step(float dtime);
@@ -182,7 +180,7 @@ public:
double getPitch() { return m_camera_pitch; }
- /*!
+ /*
* Returns a line which describes what the player is pointing at.
* The starting point and looking direction are significant,
* the line should be scaled to match its length to the actual distance
@@ -206,9 +204,10 @@ private:
IEventReceiver *m_receiver;
ISimpleTextureSource *m_texturesource;
v2u32 m_screensize;
+ s32 button_size;
double m_touchscreen_threshold;
std::map<int, rect<s32>> m_hud_rects;
- std::map<int, irr::EKEY_CODE> m_hud_ids;
+ std::map<size_t, irr::EKEY_CODE> m_hud_ids;
bool m_visible; // is the gui visible
// value in degree
@@ -220,7 +219,7 @@ private:
forward_id, backward_id, left_id, right_id, special1_id};
bool m_joystick_status[5] = {false, false, false, false, false};
- /*!
+ /*
* A line starting at the camera and pointing towards the
* selected object.
* The line ends on the camera's far plane.
@@ -248,23 +247,24 @@ private:
touch_gui_button_id getButtonID(s32 x, s32 y);
// gui button by eventID
- touch_gui_button_id getButtonID(int eventID);
+ touch_gui_button_id getButtonID(size_t eventID);
// check if a button has changed
void handleChangedButton(const SEvent &event);
// initialize a button
- void initButton(touch_gui_button_id id, rect<s32> button_rect,
- std::wstring caption, bool immediate_release,
+ void initButton(touch_gui_button_id id, const rect<s32> &button_rect,
+ const std::wstring &caption, bool immediate_release,
float repeat_delay = BUTTON_REPEAT_DELAY);
// initialize a joystick button
- button_info *initJoystickButton(touch_gui_button_id id, rect<s32> button_rect,
- int texture_id, bool visible = true);
+ button_info *initJoystickButton(touch_gui_button_id id,
+ const rect<s32> &button_rect, int texture_id,
+ bool visible = true);
struct id_status
{
- int id;
+ size_t id;
int X;
int Y;
};
@@ -273,27 +273,21 @@ private:
std::vector<id_status> m_known_ids;
// handle a button event
- void handleButtonEvent(touch_gui_button_id bID, int eventID, bool action);
+ void handleButtonEvent(touch_gui_button_id bID, size_t eventID, bool action);
// handle pressed hud buttons
bool isHUDButton(const SEvent &event);
- // handle released hud buttons
- bool isReleaseHUDButton(int eventID);
-
// handle double taps
bool doubleTapDetection();
// handle release event
- void handleReleaseEvent(int evt_id);
+ void handleReleaseEvent(size_t evt_id);
// apply joystick status
void applyJoystickStatus();
- // get size of regular gui control button
- int getGuiButtonSize();
-
- // doubleclick detection variables
+ // double-click detection variables
struct key_event
{
u64 down_time;
@@ -302,9 +296,9 @@ private:
};
// array for saving last known position of a pointer
- v2s32 m_pointerpos[MAX_TOUCH_COUNT];
+ std::map<size_t, v2s32> m_pointerpos;
- // array for doubletap detection
+ // array for double tap detection
key_event m_key_events[2];
// settings bar
@@ -313,4 +307,5 @@ private:
// rare controls bar
AutoHideButtonBar m_rarecontrolsbar;
};
+
extern TouchScreenGUI *g_touchscreengui;