Skip to content
Permalink
Browse files

Add gradients and borders to FormSpec boxes (#8676)

  • Loading branch information
v-rob committed Aug 20, 2020
1 parent 471497f commit 83d0c360cc648e02650aa4d341dbf5205c1e708f
Showing with 218 additions and 47 deletions.
  1. +29 −14 doc/lua_api.txt
  2. +64 −0 src/gui/StyleSpec.h
  3. +82 −4 src/gui/guiBox.cpp
  4. +9 −2 src/gui/guiBox.h
  5. +34 −27 src/gui/guiFormSpecMenu.cpp
@@ -2442,6 +2442,8 @@ Elements
* Simple colored box
* `color` is color specified as a `ColorString`.
If the alpha component is left blank, the box will be semitransparent.
If the color is not specified, the box will use the options specified by
its style. If the color is specified, all styling options will be ignored.

### `dropdown[<X>,<Y>;<W>;<name>;<item 1>,<item 2>, ...,<item n>;<selected idx>;<index event>]`

@@ -2708,21 +2710,23 @@ Setting a property to nothing will reset it to the default value. For example:
Some types may inherit styles from parent types.

* animated_image, inherits from image
* box
* button
* button_exit, inherits from button
* checkbox
* scrollbar
* table
* textlist
* dropdown
* field
* pwdfield, inherits from field
* textarea
* label
* vertlabel, inherits from field
* image
* image_button
* item_image_button
* label
* pwdfield, inherits from field
* scrollbar
* tabheader
* table
* textarea
* textlist
* vertlabel, inherits from label


### Valid Properties
@@ -2731,7 +2735,18 @@ Some types may inherit styles from parent types.
* noclip - boolean, set to true to allow the element to exceed formspec bounds.
* box
* noclip - boolean, set to true to allow the element to exceed formspec bounds.
* Default to false in formspec_version version 3 or higher
* Defaults to false in formspec_version version 3 or higher
* **Note**: `colors`, `bordercolors`, and `borderwidths` accept multiple input types:
* Single value (e.g. `#FF0`): All corners/borders.
* Two values (e.g. `red,#FFAAFF`): top-left and bottom-right,top-right and bottom-left/
top and bottom,left and right.
* Four values (e.g. `blue,#A0F,green,#FFFA`): top-left/top and rotates clockwise.
* These work similarly to CSS borders.
* colors - `ColorString`. Sets the color(s) of the box corners. Default `black`.
* bordercolors - `ColorString`. Sets the color(s) of the borders. Default `black`.
* borderwidths - Integer. Sets the width(s) of the borders in pixels. If the width is
negative, the border will extend inside the box, whereas positive extends outside
the box. A width of zero results in no border; this is default.
* button, button_exit, image_button, item_image_button
* alpha - boolean, whether to draw alpha in bgimg. Default true.
* bgcolor - color, sets button tint.
@@ -2767,12 +2782,6 @@ Some types may inherit styles from parent types.
* textcolor - color, default white.
* checkbox
* noclip - boolean, set to true to allow the element to exceed formspec bounds.
* scrollbar
* noclip - boolean, set to true to allow the element to exceed formspec bounds.
* table, textlist
* font - Sets font type. See button `font` property for more information.
* font_size - Sets font size. See button `font_size` property for more information.
* noclip - boolean, set to true to allow the element to exceed formspec bounds.
* dropdown
* noclip - boolean, set to true to allow the element to exceed formspec bounds.
* field, pwdfield, textarea
@@ -2797,9 +2806,15 @@ Some types may inherit styles from parent types.
* fgimg_pressed - image when pressed. Defaults to fgimg when not provided.
* This is deprecated, use states instead.
* NOTE: The parameters of any given image_button will take precedence over fgimg/fgimg_pressed
* scrollbar
* noclip - boolean, set to true to allow the element to exceed formspec bounds.
* tabheader
* noclip - boolean, set to true to allow the element to exceed formspec bounds.
* textcolor - color. Default white.
* table, textlist
* font - Sets font type. See button `font` property for more information.
* font_size - Sets font size. See button `font_size` property for more information.
* noclip - boolean, set to true to allow the element to exceed formspec bounds.

### Valid States

@@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "util/string.h"
#include <algorithm>
#include <array>
#include <vector>

#pragma once

@@ -50,6 +51,9 @@ class StyleSpec
PADDING,
FONT,
FONT_SIZE,
COLORS,
BORDERCOLORS,
BORDERWIDTHS,
NUM_PROPERTIES,
NONE
};
@@ -106,6 +110,12 @@ class StyleSpec
return FONT;
} else if (name == "font_size") {
return FONT_SIZE;
} else if (name == "colors") {
return COLORS;
} else if (name == "bordercolors") {
return BORDERCOLORS;
} else if (name == "borderwidths") {
return BORDERWIDTHS;
} else {
return NONE;
}
@@ -187,6 +197,42 @@ class StyleSpec
return color;
}

std::array<video::SColor, 4> getColorArray(Property prop,
std::array<video::SColor, 4> def) const
{
const auto &val = properties[prop];
if (val.empty())
return def;

std::vector<std::string> strs;
if (!parseArray(val, strs))
return def;

for (size_t i = 0; i <= 3; i++) {
video::SColor color;
if (parseColorString(strs[i], color, false, 0xff))
def[i] = color;
}

return def;
}

std::array<s32, 4> getIntArray(Property prop, std::array<s32, 4> def) const
{
const auto &val = properties[prop];
if (val.empty())
return def;

std::vector<std::string> strs;
if (!parseArray(val, strs))
return def;

for (size_t i = 0; i <= 3; i++)
def[i] = stoi(strs[i]);

return def;
}

irr::core::rect<s32> getRect(Property prop, irr::core::rect<s32> def) const
{
const auto &val = properties[prop];
@@ -334,6 +380,24 @@ class StyleSpec
}

private:
bool parseArray(const std::string &value, std::vector<std::string> &arr) const
{
std::vector<std::string> strs = split(value, ',');

if (strs.size() == 1) {
arr = {strs[0], strs[0], strs[0], strs[0]};
} else if (strs.size() == 2) {
arr = {strs[0], strs[1], strs[0], strs[1]};
} else if (strs.size() == 4) {
arr = strs;
} else {
warningstream << "Invalid array size (" << strs.size()
<< " arguments): \"" << value << "\"" << std::endl;
return false;
}
return true;
}

bool parseRect(const std::string &value, irr::core::rect<s32> *parsed_rect) const
{
irr::core::rect<s32> rect;
@@ -20,9 +20,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "guiBox.h"

GUIBox::GUIBox(gui::IGUIEnvironment *env, gui::IGUIElement *parent, s32 id,
const core::rect<s32> &rectangle, const video::SColor &color) :
const core::rect<s32> &rectangle,
const std::array<video::SColor, 4> &colors,
const std::array<video::SColor, 4> &bordercolors,
const std::array<s32, 4> &borderwidths) :
gui::IGUIElement(gui::EGUIET_ELEMENT, env, parent, id, rectangle),
m_color(color)
m_colors(colors),
m_bordercolors(bordercolors),
m_borderwidths(borderwidths)
{
}

@@ -31,8 +36,81 @@ void GUIBox::draw()
if (!IsVisible)
return;

Environment->getVideoDriver()->draw2DRectangle(m_color, AbsoluteRect,
&AbsoluteClippingRect);
std::array<s32, 4> negative_borders = {0, 0, 0, 0};
std::array<s32, 4> positive_borders = {0, 0, 0, 0};

for (size_t i = 0; i <= 3; i++) {
if (m_borderwidths[i] > 0)
positive_borders[i] = m_borderwidths[i];
else
negative_borders[i] = m_borderwidths[i];
}

v2s32 upperleft = AbsoluteRect.UpperLeftCorner;
v2s32 lowerright = AbsoluteRect.LowerRightCorner;

v2s32 topleft_border = {
upperleft.X - positive_borders[3],
upperleft.Y - positive_borders[0]
};
v2s32 topleft_rect = {
upperleft.X - negative_borders[3],
upperleft.Y - negative_borders[0]
};

v2s32 lowerright_border = {
lowerright.X + positive_borders[1],
lowerright.Y + positive_borders[2]
};
v2s32 lowerright_rect = {
lowerright.X + negative_borders[1],
lowerright.Y + negative_borders[2]
};

core::rect<s32> main_rect(
topleft_rect.X,
topleft_rect.Y,
lowerright_rect.X,
lowerright_rect.Y
);

std::array<core::rect<s32>, 4> border_rects;

border_rects[0] = core::rect<s32>(
topleft_border.X,
topleft_border.Y,
lowerright_border.X,
topleft_rect.Y
);

border_rects[1] = core::rect<s32>(
lowerright_rect.X,
topleft_rect.Y,
lowerright_border.X,
lowerright_rect.Y
);

border_rects[2] = core::rect<s32>(
topleft_border.X,
lowerright_rect.Y,
lowerright_border.X,
lowerright_border.Y
);

border_rects[3] = core::rect<s32>(
topleft_border.X,
topleft_rect.Y,
topleft_rect.X,
lowerright_rect.Y
);

video::IVideoDriver *driver = Environment->getVideoDriver();

driver->draw2DRectangle(main_rect, m_colors[0], m_colors[1], m_colors[3],
m_colors[2], nullptr);

for (size_t i = 0; i <= 3; i++)
driver->draw2DRectangle(m_bordercolors[i], border_rects[i], nullptr);

IGUIElement::draw();
}
@@ -19,16 +19,23 @@ with this program; if not, write to the Free Software Foundation, Inc.,

#pragma once

#include <vector>
#include <array>
#include "irrlichttypes_extrabloated.h"

class GUIBox : public gui::IGUIElement
{
public:
GUIBox(gui::IGUIEnvironment *env, gui::IGUIElement *parent, s32 id,
const core::rect<s32> &rectangle, const video::SColor &color);
const core::rect<s32> &rectangle,
const std::array<video::SColor, 4> &colors,
const std::array<video::SColor, 4> &bordercolors,
const std::array<s32, 4> &borderwidths);

virtual void draw() override;

private:
video::SColor m_color;
std::array<video::SColor, 4> m_colors;
std::array<video::SColor, 4> m_bordercolors;
std::array<s32, 4> m_borderwidths;
};

0 comments on commit 83d0c36

Please sign in to comment.
You can’t perform that action at this time.