]> git.lizzy.rs Git - dragonfireclient.git/blobdiff - src/gui/StyleSpec.h
Make lint happy; Remove stupid redirector
[dragonfireclient.git] / src / gui / StyleSpec.h
index 5c9e20a1123849e7af14d3480ac6c879da186ff9..67caf4f7bb3b1fe6470878e723676367fae0cf3e 100644 (file)
@@ -18,8 +18,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 */
 
 #include "client/tile.h" // ITextureSource
+#include "client/fontengine.h"
+#include "debug.h"
 #include "irrlichttypes_extrabloated.h"
 #include "util/string.h"
+#include <algorithm>
 #include <array>
 
 #pragma once
@@ -31,24 +34,38 @@ class StyleSpec
        {
                TEXTCOLOR,
                BGCOLOR,
-               BGCOLOR_HOVERED,
-               BGCOLOR_PRESSED,
+               BGCOLOR_HOVERED, // Note: Deprecated property
+               BGCOLOR_PRESSED, // Note: Deprecated property
                NOCLIP,
                BORDER,
                BGIMG,
-               BGIMG_HOVERED,
-               BGIMG_PRESSED,
+               BGIMG_HOVERED, // Note: Deprecated property
+               BGIMG_MIDDLE,
+               BGIMG_PRESSED, // Note: Deprecated property
                FGIMG,
-               FGIMG_HOVERED,
-               FGIMG_PRESSED,
+               FGIMG_HOVERED, // Note: Deprecated property
+               FGIMG_PRESSED, // Note: Deprecated property
                ALPHA,
+               CONTENT_OFFSET,
+               PADDING,
+               FONT,
+               FONT_SIZE,
                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)
@@ -69,6 +86,8 @@ class StyleSpec
                        return BGIMG;
                } else if (name == "bgimg_hovered") {
                        return BGIMG_HOVERED;
+               } else if (name == "bgimg_middle") {
+                       return BGIMG_MIDDLE;
                } else if (name == "bgimg_pressed") {
                        return BGIMG_PRESSED;
                } else if (name == "fgimg") {
@@ -79,6 +98,14 @@ class StyleSpec
                        return FGIMG_PRESSED;
                } else if (name == "alpha") {
                        return ALPHA;
+               } else if (name == "content_offset") {
+                       return CONTENT_OFFSET;
+               } else if (name == "padding") {
+                       return PADDING;
+               } else if (name == "font") {
+                       return FONT;
+               } else if (name == "font_size") {
+                       return FONT_SIZE;
                } else {
                        return NONE;
                }
@@ -96,6 +123,49 @@ class StyleSpec
                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];
@@ -117,6 +187,93 @@ class StyleSpec
                return color;
        }
 
+       irr::core::rect<s32> getRect(Property prop, irr::core::rect<s32> def) const
+       {
+               const auto &val = properties[prop];
+               if (val.empty())
+                       return def;
+
+               irr::core::rect<s32> rect;
+               if (!parseRect(val, &rect))
+                       return def;
+
+               return rect;
+       }
+
+       irr::core::rect<s32> getRect(Property prop) const
+       {
+               const auto &val = properties[prop];
+               FATAL_ERROR_IF(val.empty(), "Unexpected missing property");
+
+               irr::core::rect<s32> rect;
+               parseRect(val, &rect);
+               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;
+       }
+
+       gui::IGUIFont *getFont() const
+       {
+               FontSpec spec(FONT_SIZE_UNSPECIFIED, FM_Standard, false, false);
+
+               const std::string &font = properties[FONT];
+               const std::string &size = properties[FONT_SIZE];
+
+               if (font.empty() && size.empty())
+                       return nullptr;
+
+               std::vector<std::string> modes = split(font, ',');
+
+               for (size_t i = 0; i < modes.size(); i++) {
+                       if (modes[i] == "normal")
+                               spec.mode = FM_Standard;
+                       else if (modes[i] == "mono")
+                               spec.mode = FM_Mono;
+                       else if (modes[i] == "bold")
+                               spec.bold = true;
+                       else if (modes[i] == "italic")
+                               spec.italic = true;
+               }
+
+               if (!size.empty()) {
+                       int calc_size = 1;
+
+                       if (size[0] == '*') {
+                               std::string new_size = size.substr(1); // Remove '*' (invalid for stof)
+                               calc_size = stof(new_size) * g_fontengine->getFontSize(spec.mode);
+                       } else if (size[0] == '+' || size[0] == '-') {
+                               calc_size = stoi(size) + g_fontengine->getFontSize(spec.mode);
+                       } else {
+                               calc_size = stoi(size);
+                       }
+
+                       spec.size = (unsigned)std::min(std::max(calc_size, 1), 999);
+               }
+
+               return g_fontengine->getFont(spec);
+       }
+
        video::ITexture *getTexture(Property prop, ISimpleTextureSource *tsrc,
                        video::ITexture *def) const
        {
@@ -175,4 +332,61 @@ class StyleSpec
                newspec |= other;
                return newspec;
        }
+
+private:
+       bool parseRect(const std::string &value, irr::core::rect<s32> *parsed_rect) const
+       {
+               irr::core::rect<s32> rect;
+               std::vector<std::string> v_rect = split(value, ',');
+
+               if (v_rect.size() == 1) {
+                       s32 x = stoi(v_rect[0]);
+                       rect.UpperLeftCorner = irr::core::vector2di(x, x);
+                       rect.LowerRightCorner = irr::core::vector2di(-x, -x);
+               } else if (v_rect.size() == 2) {
+                       s32 x = stoi(v_rect[0]);
+                       s32 y = stoi(v_rect[1]);
+                       rect.UpperLeftCorner = irr::core::vector2di(x, y);
+                       rect.LowerRightCorner = irr::core::vector2di(-x, -y);
+                       // `-x` is interpreted as `w - x`
+               } else if (v_rect.size() == 4) {
+                       rect.UpperLeftCorner = irr::core::vector2di(
+                                       stoi(v_rect[0]), stoi(v_rect[1]));
+                       rect.LowerRightCorner = irr::core::vector2di(
+                                       stoi(v_rect[2]), stoi(v_rect[3]));
+               } else {
+                       warningstream << "Invalid rectangle string format: \"" << value
+                                       << "\"" << std::endl;
+                       return false;
+               }
+
+               *parsed_rect = rect;
+
+               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;
+       }
 };