1
0
Fork 0
mirror of https://github.com/luanti-org/luanti.git synced 2025-06-27 16:36:03 +00:00

Add gradients and borders to FormSpec boxes (#8676)

This commit is contained in:
v-rob 2020-08-19 18:14:47 -07:00 committed by GitHub
parent 471497fa91
commit 83d0c360cc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 220 additions and 49 deletions

View file

@ -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 @@ public:
PADDING,
FONT,
FONT_SIZE,
COLORS,
BORDERCOLORS,
BORDERWIDTHS,
NUM_PROPERTIES,
NONE
};
@ -106,6 +110,12 @@ public:
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 @@ public:
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 @@ public:
}
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;

View file

@ -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();
}

View file

@ -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;
};

View file

@ -2211,16 +2211,16 @@ void GUIFormSpecMenu::parseItemImageButton(parserData* data, const std::string &
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) ||
((parts.size() > 3) && (m_formspec_version > FORMSPEC_API_VERSION)))
{
std::vector<std::string> v_pos = split(parts[0],',');
std::vector<std::string> v_geom = split(parts[1],',');
std::vector<std::string> v_pos = split(parts[0], ',');
std::vector<std::string> v_geom = split(parts[1], ',');
MY_CHECKPOS("box",0);
MY_CHECKGEOM("box",1);
MY_CHECKPOS("box", 0);
MY_CHECKGEOM("box", 1);
v2s32 pos;
v2s32 geom;
@ -2234,36 +2234,43 @@ void GUIFormSpecMenu::parseBox(parserData* data, const std::string &element)
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;
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)) {
FieldSpec spec(
"",
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);
if (parseColorString(parts[2], tmp_color, true, 0x8C)) {
colors = {tmp_color, tmp_color, tmp_color, tmp_color};
} 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;
}
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)