forked from Mirrorlandia_minetest/minetest
Add gradients and borders to FormSpec boxes (#8676)
This commit is contained in:
parent
471497fa91
commit
83d0c360cc
@ -2442,6 +2442,8 @@ Elements
|
|||||||
* Simple colored box
|
* Simple colored box
|
||||||
* `color` is color specified as a `ColorString`.
|
* `color` is color specified as a `ColorString`.
|
||||||
If the alpha component is left blank, the box will be semitransparent.
|
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>]`
|
### `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.
|
Some types may inherit styles from parent types.
|
||||||
|
|
||||||
* animated_image, inherits from image
|
* animated_image, inherits from image
|
||||||
|
* box
|
||||||
* button
|
* button
|
||||||
* button_exit, inherits from button
|
* button_exit, inherits from button
|
||||||
* checkbox
|
* checkbox
|
||||||
* scrollbar
|
|
||||||
* table
|
|
||||||
* textlist
|
|
||||||
* dropdown
|
* dropdown
|
||||||
* field
|
* field
|
||||||
* pwdfield, inherits from field
|
* image
|
||||||
* textarea
|
|
||||||
* label
|
|
||||||
* vertlabel, inherits from field
|
|
||||||
* image_button
|
* image_button
|
||||||
* item_image_button
|
* item_image_button
|
||||||
|
* label
|
||||||
|
* pwdfield, inherits from field
|
||||||
|
* scrollbar
|
||||||
* tabheader
|
* tabheader
|
||||||
|
* table
|
||||||
|
* textarea
|
||||||
|
* textlist
|
||||||
|
* vertlabel, inherits from label
|
||||||
|
|
||||||
|
|
||||||
### Valid Properties
|
### 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.
|
* noclip - boolean, set to true to allow the element to exceed formspec bounds.
|
||||||
* box
|
* box
|
||||||
* noclip - boolean, set to true to allow the element to exceed formspec bounds.
|
* noclip - boolean, set to true to allow the element to exceed formspec bounds.
|
||||||
* 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
|
* button, button_exit, image_button, item_image_button
|
||||||
* alpha - boolean, whether to draw alpha in bgimg. Default true.
|
* alpha - boolean, whether to draw alpha in bgimg. Default true.
|
||||||
* bgcolor - color, sets button tint.
|
* bgcolor - color, sets button tint.
|
||||||
@ -2767,12 +2782,6 @@ Some types may inherit styles from parent types.
|
|||||||
* textcolor - color, default white.
|
* textcolor - color, default white.
|
||||||
* checkbox
|
* checkbox
|
||||||
* noclip - boolean, set to true to allow the element to exceed formspec bounds.
|
* noclip - boolean, set to true to allow the element to exceed formspec bounds.
|
||||||
* 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
|
* dropdown
|
||||||
* noclip - boolean, set to true to allow the element to exceed formspec bounds.
|
* noclip - boolean, set to true to allow the element to exceed formspec bounds.
|
||||||
* field, pwdfield, textarea
|
* 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.
|
* fgimg_pressed - image when pressed. Defaults to fgimg when not provided.
|
||||||
* This is deprecated, use states instead.
|
* This is deprecated, use states instead.
|
||||||
* NOTE: The parameters of any given image_button will take precedence over fgimg/fgimg_pressed
|
* 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
|
* tabheader
|
||||||
* noclip - boolean, set to true to allow the element to exceed formspec bounds.
|
* noclip - boolean, set to true to allow the element to exceed formspec bounds.
|
||||||
* textcolor - color. Default white.
|
* textcolor - color. Default white.
|
||||||
|
* 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
|
### Valid States
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "util/string.h"
|
#include "util/string.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
@ -50,6 +51,9 @@ public:
|
|||||||
PADDING,
|
PADDING,
|
||||||
FONT,
|
FONT,
|
||||||
FONT_SIZE,
|
FONT_SIZE,
|
||||||
|
COLORS,
|
||||||
|
BORDERCOLORS,
|
||||||
|
BORDERWIDTHS,
|
||||||
NUM_PROPERTIES,
|
NUM_PROPERTIES,
|
||||||
NONE
|
NONE
|
||||||
};
|
};
|
||||||
@ -106,6 +110,12 @@ public:
|
|||||||
return FONT;
|
return FONT;
|
||||||
} else if (name == "font_size") {
|
} else if (name == "font_size") {
|
||||||
return FONT_SIZE;
|
return FONT_SIZE;
|
||||||
|
} else if (name == "colors") {
|
||||||
|
return COLORS;
|
||||||
|
} else if (name == "bordercolors") {
|
||||||
|
return BORDERCOLORS;
|
||||||
|
} else if (name == "borderwidths") {
|
||||||
|
return BORDERWIDTHS;
|
||||||
} else {
|
} else {
|
||||||
return NONE;
|
return NONE;
|
||||||
}
|
}
|
||||||
@ -187,6 +197,42 @@ public:
|
|||||||
return color;
|
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
|
irr::core::rect<s32> getRect(Property prop, irr::core::rect<s32> def) const
|
||||||
{
|
{
|
||||||
const auto &val = properties[prop];
|
const auto &val = properties[prop];
|
||||||
@ -334,6 +380,24 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
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
|
bool parseRect(const std::string &value, irr::core::rect<s32> *parsed_rect) const
|
||||||
{
|
{
|
||||||
irr::core::rect<s32> rect;
|
irr::core::rect<s32> rect;
|
||||||
|
@ -20,9 +20,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "guiBox.h"
|
#include "guiBox.h"
|
||||||
|
|
||||||
GUIBox::GUIBox(gui::IGUIEnvironment *env, gui::IGUIElement *parent, s32 id,
|
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),
|
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)
|
if (!IsVisible)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Environment->getVideoDriver()->draw2DRectangle(m_color, AbsoluteRect,
|
std::array<s32, 4> negative_borders = {0, 0, 0, 0};
|
||||||
&AbsoluteClippingRect);
|
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();
|
IGUIElement::draw();
|
||||||
}
|
}
|
||||||
|
@ -19,16 +19,23 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <array>
|
||||||
#include "irrlichttypes_extrabloated.h"
|
#include "irrlichttypes_extrabloated.h"
|
||||||
|
|
||||||
class GUIBox : public gui::IGUIElement
|
class GUIBox : public gui::IGUIElement
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
GUIBox(gui::IGUIEnvironment *env, gui::IGUIElement *parent, s32 id,
|
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;
|
virtual void draw() override;
|
||||||
|
|
||||||
private:
|
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;
|
||||||
};
|
};
|
||||||
|
@ -2211,16 +2211,16 @@ void GUIFormSpecMenu::parseItemImageButton(parserData* data, const std::string &
|
|||||||
|
|
||||||
void GUIFormSpecMenu::parseBox(parserData* data, const std::string &element)
|
void GUIFormSpecMenu::parseBox(parserData* data, const std::string &element)
|
||||||
{
|
{
|
||||||
std::vector<std::string> parts = split(element,';');
|
std::vector<std::string> parts = split(element, ';');
|
||||||
|
|
||||||
if ((parts.size() == 3) ||
|
if ((parts.size() == 3) ||
|
||||||
((parts.size() > 3) && (m_formspec_version > FORMSPEC_API_VERSION)))
|
((parts.size() > 3) && (m_formspec_version > FORMSPEC_API_VERSION)))
|
||||||
{
|
{
|
||||||
std::vector<std::string> v_pos = split(parts[0],',');
|
std::vector<std::string> v_pos = split(parts[0], ',');
|
||||||
std::vector<std::string> v_geom = split(parts[1],',');
|
std::vector<std::string> v_geom = split(parts[1], ',');
|
||||||
|
|
||||||
MY_CHECKPOS("box",0);
|
MY_CHECKPOS("box", 0);
|
||||||
MY_CHECKGEOM("box",1);
|
MY_CHECKGEOM("box", 1);
|
||||||
|
|
||||||
v2s32 pos;
|
v2s32 pos;
|
||||||
v2s32 geom;
|
v2s32 geom;
|
||||||
@ -2234,36 +2234,43 @@ void GUIFormSpecMenu::parseBox(parserData* data, const std::string &element)
|
|||||||
geom.Y = stof(v_geom[1]) * spacing.Y;
|
geom.Y = stof(v_geom[1]) * spacing.Y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FieldSpec spec(
|
||||||
|
"",
|
||||||
|
L"",
|
||||||
|
L"",
|
||||||
|
258 + m_fields.size(),
|
||||||
|
-2
|
||||||
|
);
|
||||||
|
spec.ftype = f_Box;
|
||||||
|
|
||||||
|
auto style = getDefaultStyleForElement("box", spec.fname);
|
||||||
|
|
||||||
video::SColor tmp_color;
|
video::SColor tmp_color;
|
||||||
|
std::array<video::SColor, 4> colors;
|
||||||
|
std::array<video::SColor, 4> bordercolors = {0x0, 0x0, 0x0, 0x0};
|
||||||
|
std::array<s32, 4> borderwidths = {0, 0, 0, 0};
|
||||||
|
|
||||||
if (parseColorString(parts[2], tmp_color, false, 0x8C)) {
|
if (parseColorString(parts[2], tmp_color, true, 0x8C)) {
|
||||||
FieldSpec spec(
|
colors = {tmp_color, tmp_color, tmp_color, tmp_color};
|
||||||
"",
|
|
||||||
L"",
|
|
||||||
L"",
|
|
||||||
258 + m_fields.size(),
|
|
||||||
-2
|
|
||||||
);
|
|
||||||
spec.ftype = f_Box;
|
|
||||||
|
|
||||||
core::rect<s32> rect(pos, pos + geom);
|
|
||||||
|
|
||||||
GUIBox *e = new GUIBox(Environment, data->current_parent, spec.fid,
|
|
||||||
rect, tmp_color);
|
|
||||||
|
|
||||||
auto style = getDefaultStyleForElement("box", spec.fname);
|
|
||||||
e->setNotClipped(style.getBool(StyleSpec::NOCLIP, m_formspec_version < 3));
|
|
||||||
|
|
||||||
e->drop();
|
|
||||||
|
|
||||||
m_fields.push_back(spec);
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
errorstream<< "Invalid Box element(" << parts.size() << "): '" << element << "' INVALID COLOR" << std::endl;
|
colors = style.getColorArray(StyleSpec::COLORS, {0x0, 0x0, 0x0, 0x0});
|
||||||
|
bordercolors = style.getColorArray(StyleSpec::BORDERCOLORS,
|
||||||
|
{0x0, 0x0, 0x0, 0x0});
|
||||||
|
borderwidths = style.getIntArray(StyleSpec::BORDERWIDTHS, {0, 0, 0, 0});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
core::rect<s32> rect(pos, pos + geom);
|
||||||
|
|
||||||
|
GUIBox *e = new GUIBox(Environment, data->current_parent, spec.fid, rect,
|
||||||
|
colors, bordercolors, borderwidths);
|
||||||
|
e->setNotClipped(style.getBool(StyleSpec::NOCLIP, m_formspec_version < 3));
|
||||||
|
e->drop();
|
||||||
|
|
||||||
|
m_fields.push_back(spec);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
errorstream<< "Invalid Box element(" << parts.size() << "): '" << element << "'" << std::endl;
|
errorstream << "Invalid Box element(" << parts.size() << "): '" << element
|
||||||
|
<< "'" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GUIFormSpecMenu::parseBackgroundColor(parserData* data, const std::string &element)
|
void GUIFormSpecMenu::parseBackgroundColor(parserData* data, const std::string &element)
|
||||||
|
Loading…
Reference in New Issue
Block a user