aboutsummaryrefslogtreecommitdiff
path: root/src/gui
diff options
context:
space:
mode:
authorrubenwardy <rw@rubenwardy.com>2019-06-22 15:03:54 +0100
committerSmallJoker <SmallJoker@users.noreply.github.com>2019-06-22 16:03:54 +0200
commit429a98964859b83016f2eb47a47a08ab8dc3c57e (patch)
treeb02a16132e5cdf6696917910921942c464bc39c6 /src/gui
parent4e3c1916f731058a137ec1f9eecf2b7eff4d8fcc (diff)
downloadminetest-429a98964859b83016f2eb47a47a08ab8dc3c57e.tar.gz
minetest-429a98964859b83016f2eb47a47a08ab8dc3c57e.tar.bz2
minetest-429a98964859b83016f2eb47a47a08ab8dc3c57e.zip
Add support for 9-sliced backgrounds (#8600)
9-slice textures are commonly used in GUIs to allow scaling them to match any resolution without distortion. https://en.wikipedia.org/wiki/9-slice_scaling
Diffstat (limited to 'src/gui')
-rw-r--r--src/gui/guiFormSpecMenu.cpp55
-rw-r--r--src/gui/guiFormSpecMenu.h13
2 files changed, 57 insertions, 11 deletions
diff --git a/src/gui/guiFormSpecMenu.cpp b/src/gui/guiFormSpecMenu.cpp
index 0514ffbbe..9240dc4c8 100644
--- a/src/gui/guiFormSpecMenu.cpp
+++ b/src/gui/guiFormSpecMenu.cpp
@@ -653,9 +653,8 @@ void GUIFormSpecMenu::parseBackground(parserData* data, const std::string &eleme
{
std::vector<std::string> parts = split(element,';');
- if (((parts.size() == 3) || (parts.size() == 4)) ||
- ((parts.size() > 4) && (m_formspec_version > FORMSPEC_API_VERSION)))
- {
+ if ((parts.size() >= 3 && parts.size() <= 5) ||
+ (parts.size() > 5 && 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::string name = unescape_string(parts[2]);
@@ -672,16 +671,37 @@ void GUIFormSpecMenu::parseBackground(parserData* data, const std::string &eleme
geom.Y = stof(v_geom[1]) * spacing.Y;
bool clip = false;
- if (parts.size() == 4 && is_yes(parts[3])) {
+ if (parts.size() >= 4 && is_yes(parts[3])) {
pos.X = stoi(v_pos[0]); //acts as offset
pos.Y = stoi(v_pos[1]); //acts as offset
clip = true;
}
+ core::rect<s32> middle;
+ if (parts.size() >= 5) {
+ std::vector<std::string> v_middle = split(parts[4], ',');
+ if (v_middle.size() == 1) {
+ s32 x = stoi(v_middle[0]);
+ middle.UpperLeftCorner = core::vector2di(x, x);
+ middle.LowerRightCorner = core::vector2di(-x, -x);
+ } else if (v_middle.size() == 2) {
+ s32 x = stoi(v_middle[0]);
+ s32 y = stoi(v_middle[1]);
+ middle.UpperLeftCorner = core::vector2di(x, y);
+ middle.LowerRightCorner = core::vector2di(-x, -y);
+ // `-x` is interpreted as `w - x`
+ } else if (v_middle.size() == 4) {
+ middle.UpperLeftCorner = core::vector2di(stoi(v_middle[0]), stoi(v_middle[1]));
+ middle.LowerRightCorner = core::vector2di(stoi(v_middle[2]), stoi(v_middle[3]));
+ } else {
+ warningstream << "Invalid rectangle given to middle param of background[] element" << std::endl;
+ }
+ }
+
if (!data->explicit_size && !clip)
warningstream << "invalid use of unclipped background without a size[] element" << std::endl;
- m_backgrounds.emplace_back(name, pos, geom, clip);
+ m_backgrounds.emplace_back(name, pos, geom, middle, clip);
return;
}
@@ -2514,6 +2534,8 @@ void GUIFormSpecMenu::drawMenu()
core::rect<s32> imgrect(0, 0, spec.geom.X, spec.geom.Y);
// Image rectangle on screen
core::rect<s32> rect = imgrect + spec.pos;
+ // Middle rect for 9-slicing
+ core::rect<s32> middle = spec.middle;
if (spec.clip) {
core::dimension2d<s32> absrec_size = AbsoluteRect.getSize();
@@ -2523,12 +2545,23 @@ void GUIFormSpecMenu::drawMenu()
AbsoluteRect.UpperLeftCorner.Y + absrec_size.Height + spec.pos.Y);
}
- const video::SColor color(255,255,255,255);
- const video::SColor colors[] = {color,color,color,color};
- draw2DImageFilterScaled(driver, texture, rect,
- core::rect<s32>(core::position2d<s32>(0,0),
- core::dimension2di(texture->getOriginalSize())),
- NULL/*&AbsoluteClippingRect*/, colors, true);
+ if (middle.getArea() == 0) {
+ const video::SColor color(255, 255, 255, 255);
+ const video::SColor colors[] = {color, color, color, color};
+ draw2DImageFilterScaled(driver, texture, rect,
+ core::rect<s32>(core::position2d<s32>(0, 0),
+ core::dimension2di(texture->getOriginalSize())),
+ NULL/*&AbsoluteClippingRect*/, colors, true);
+ } else {
+ // `-x` is interpreted as `w - x`
+ if (middle.LowerRightCorner.X < 0) {
+ middle.LowerRightCorner.X += texture->getOriginalSize().Width;
+ }
+ if (middle.LowerRightCorner.Y < 0) {
+ middle.LowerRightCorner.Y += texture->getOriginalSize().Height;
+ }
+ draw2DImage9Slice(driver, texture, rect, middle);
+ }
} else {
errorstream << "GUIFormSpecMenu::drawMenu() Draw backgrounds unable to load texture:" << std::endl;
errorstream << "\t" << spec.name << std::endl;
diff --git a/src/gui/guiFormSpecMenu.h b/src/gui/guiFormSpecMenu.h
index ccd9cb753..b1ca9a48a 100644
--- a/src/gui/guiFormSpecMenu.h
+++ b/src/gui/guiFormSpecMenu.h
@@ -177,6 +177,18 @@ class GUIFormSpecMenu : public GUIModalMenu
}
ImageDrawSpec(const std::string &a_name,
+ const v2s32 &a_pos, const v2s32 &a_geom, const core::rect<s32> &middle, bool clip=false):
+ name(a_name),
+ parent_button(NULL),
+ pos(a_pos),
+ geom(a_geom),
+ middle(middle),
+ scale(true),
+ clip(clip)
+ {
+ }
+
+ ImageDrawSpec(const std::string &a_name,
const v2s32 &a_pos):
name(a_name),
parent_button(NULL),
@@ -191,6 +203,7 @@ class GUIFormSpecMenu : public GUIModalMenu
gui::IGUIButton *parent_button;
v2s32 pos;
v2s32 geom;
+ core::rect<s32> middle;
bool scale;
bool clip;
};