27 changes: 11 additions & 16 deletions src/gui/guiButtonImage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,15 @@ using namespace gui;
GUIButtonImage::GUIButtonImage(gui::IGUIEnvironment *environment,
gui::IGUIElement *parent, s32 id, core::rect<s32> rectangle,
ISimpleTextureSource *tsrc, bool noclip)
: GUIButton (environment, parent, id, rectangle, tsrc, noclip)
: GUIButton(environment, parent, id, rectangle, tsrc, noclip)
{
m_image = Environment->addImage(
core::rect<s32>(0,0,rectangle.getWidth(),rectangle.getHeight()), this);
m_image->setScaleImage(isScalingImage());
GUIButton::setScaleImage(true);
m_image = new GUIAnimatedImage(environment, this, id, rectangle);
sendToBack(m_image);
}

void GUIButtonImage::setForegroundImage(video::ITexture *image)
void GUIButtonImage::setForegroundImage(video::ITexture *image,
const core::rect<s32> &middle)
{
if (image == m_foreground_image)
return;
Expand All @@ -52,11 +52,12 @@ void GUIButtonImage::setForegroundImage(video::ITexture *image)
m_foreground_image->drop();

m_foreground_image = image;
m_image->setImage(image);
m_image->setTexture(image);
m_image->setMiddleRect(middle);
}

//! Set element properties from a StyleSpec
void GUIButtonImage::setFromStyle(const StyleSpec& style)
void GUIButtonImage::setFromStyle(const StyleSpec &style)
{
GUIButton::setFromStyle(style);

Expand All @@ -67,19 +68,13 @@ void GUIButtonImage::setFromStyle(const StyleSpec& style)
getTextureSource());

setForegroundImage(guiScalingImageButton(driver, texture,
AbsoluteRect.getWidth(), AbsoluteRect.getHeight()));
setScaleImage(true);
AbsoluteRect.getWidth(), AbsoluteRect.getHeight()),
style.getRect(StyleSpec::FGIMG_MIDDLE, m_image->getMiddleRect()));
} else {
setForegroundImage(nullptr);
setForegroundImage();
}
}

void GUIButtonImage::setScaleImage(bool scaleImage)
{
GUIButton::setScaleImage(scaleImage);
m_image->setScaleImage(scaleImage);
}

GUIButtonImage *GUIButtonImage::addButton(IGUIEnvironment *environment,
const core::rect<s32> &rectangle, ISimpleTextureSource *tsrc,
IGUIElement *parent, s32 id, const wchar_t *text,
Expand Down
10 changes: 5 additions & 5 deletions src/gui/guiButtonImage.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,

#include "guiButton.h"
#include "IGUIButton.h"
#include "guiAnimatedImage.h"

using namespace irr;

Expand All @@ -32,12 +33,11 @@ class GUIButtonImage : public GUIButton
s32 id, core::rect<s32> rectangle, ISimpleTextureSource *tsrc,
bool noclip = false);

void setForegroundImage(video::ITexture *image = nullptr);
void setForegroundImage(video::ITexture *image = nullptr,
const core::rect<s32> &middle = core::rect<s32>());

//! Set element properties from a StyleSpec
virtual void setFromStyle(const StyleSpec& style) override;

virtual void setScaleImage(bool scaleImage=true) override;
virtual void setFromStyle(const StyleSpec &style) override;

//! Do not drop returned handle
static GUIButtonImage *addButton(gui::IGUIEnvironment *environment,
Expand All @@ -47,5 +47,5 @@ class GUIButtonImage : public GUIButton

private:
video::ITexture *m_foreground_image = nullptr;
gui::IGUIImage *m_image;
GUIAnimatedImage *m_image;
};
182 changes: 93 additions & 89 deletions src/gui/guiFormSpecMenu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -767,101 +767,84 @@ void GUIFormSpecMenu::parseScrollBarOptions(parserData* data, const std::string
void GUIFormSpecMenu::parseImage(parserData* data, const std::string &element)
{
std::vector<std::string> parts;
if (!precheckElement("image", element, 2, 3, parts))
if (!precheckElement("image", element, 2, 4, parts))
return;

if (parts.size() >= 3) {
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]);
size_t offset = parts.size() >= 3;

std::vector<std::string> v_pos = split(parts[0],',');
MY_CHECKPOS("image", 0);

MY_CHECKPOS("image", 0);
std::vector<std::string> v_geom;
if (parts.size() >= 3) {
v_geom = split(parts[1],',');
MY_CHECKGEOM("image", 1);
}

v2s32 pos;
v2s32 geom;
std::string name = unescape_string(parts[1 + offset]);
video::ITexture *texture = m_tsrc->getTexture(name);

if (data->real_coordinates) {
pos = getRealCoordinateBasePos(v_pos);
geom = getRealCoordinateGeometry(v_geom);
v2s32 pos;
v2s32 geom;

if (parts.size() < 3) {
if (texture != nullptr) {
core::dimension2du dim = texture->getOriginalSize();
geom.X = dim.Width;
geom.Y = dim.Height;
} else {
pos = getElementBasePos(&v_pos);
geom.X = stof(v_geom[0]) * (float)imgsize.X;
geom.Y = stof(v_geom[1]) * (float)imgsize.Y;
geom = v2s32(0);
}
}

if (!data->explicit_size)
warningstream<<"invalid use of image without a size[] element"<<std::endl;

video::ITexture *texture = m_tsrc->getTexture(name);
if (!texture) {
errorstream << "GUIFormSpecMenu::parseImage() Unable to load texture:"
<< std::endl << "\t" << name << std::endl;
return;
if (data->real_coordinates) {
pos = getRealCoordinateBasePos(v_pos);
if (parts.size() >= 3)
geom = getRealCoordinateGeometry(v_geom);
} else {
pos = getElementBasePos(&v_pos);
if (parts.size() >= 3) {
geom.X = stof(v_geom[0]) * (float)imgsize.X;
geom.Y = stof(v_geom[1]) * (float)imgsize.Y;
}

FieldSpec spec(
name,
L"",
L"",
258 + m_fields.size(),
1
);
core::rect<s32> rect(pos, pos + geom);
gui::IGUIImage *e = Environment->addImage(rect, data->current_parent,
spec.fid, 0, true);
e->setImage(texture);
e->setScaleImage(true);
auto style = getDefaultStyleForElement("image", spec.fname);
e->setNotClipped(style.getBool(StyleSpec::NOCLIP, m_formspec_version < 3));
m_fields.push_back(spec);

// images should let events through
e->grab();
m_clickthrough_elements.push_back(e);
return;
}

// Else: 2 arguments in "parts"

std::vector<std::string> v_pos = split(parts[0],',');
std::string name = unescape_string(parts[1]);

MY_CHECKPOS("image", 0);

v2s32 pos = getElementBasePos(&v_pos);

if (!data->explicit_size)
warningstream<<"invalid use of image without a size[] element"<<std::endl;

video::ITexture *texture = m_tsrc->getTexture(name);
if (!texture) {
errorstream << "GUIFormSpecMenu::parseImage() Unable to load texture:"
<< std::endl << "\t" << name << std::endl;
return;
}
warningstream << "Invalid use of image without a size[] element" << std::endl;

FieldSpec spec(
name,
L"",
L"",
258 + m_fields.size()
258 + m_fields.size(),
1
);
gui::IGUIImage *e = Environment->addImage(texture, pos, true,
data->current_parent, spec.fid, 0);

core::rect<s32> rect = core::rect<s32>(pos, pos + geom);

core::rect<s32> middle;
if (parts.size() >= 4)
parseMiddleRect(parts[3], &middle);

GUIAnimatedImage *e = new GUIAnimatedImage(Environment, data->current_parent,
spec.fid, rect);

e->setTexture(texture);
e->setMiddleRect(middle);

auto style = getDefaultStyleForElement("image", spec.fname);
e->setNotClipped(style.getBool(StyleSpec::NOCLIP, m_formspec_version < 3));
m_fields.push_back(spec);

// images should let events through
e->grab();
// Animated images should let events through
m_clickthrough_elements.push_back(e);

m_fields.push_back(spec);
}

void GUIFormSpecMenu::parseAnimatedImage(parserData *data, const std::string &element)
{
std::vector<std::string> parts;
if (!precheckElement("animated_image", element, 6, 7, parts))
if (!precheckElement("animated_image", element, 6, 8, parts))
return;

std::vector<std::string> v_pos = split(parts[0], ',');
Expand All @@ -887,7 +870,8 @@ void GUIFormSpecMenu::parseAnimatedImage(parserData *data, const std::string &el
}

if (!data->explicit_size)
warningstream << "Invalid use of animated_image without a size[] element" << std::endl;
warningstream << "Invalid use of animated_image without a size[] element"
<< std::endl;

FieldSpec spec(
name,
Expand All @@ -900,9 +884,17 @@ void GUIFormSpecMenu::parseAnimatedImage(parserData *data, const std::string &el

core::rect<s32> rect = core::rect<s32>(pos, pos + geom);

GUIAnimatedImage *e = new GUIAnimatedImage(Environment, data->current_parent, spec.fid,
rect, texture_name, frame_count, frame_duration, m_tsrc);
core::rect<s32> middle;
if (parts.size() >= 8)
parseMiddleRect(parts[7], &middle);

GUIAnimatedImage *e = new GUIAnimatedImage(Environment, data->current_parent,
spec.fid, rect);

e->setTexture(m_tsrc->getTexture(texture_name));
e->setMiddleRect(middle);
e->setFrameDuration(frame_duration);
e->setFrameCount(frame_count);
if (parts.size() >= 7)
e->setFrameIndex(stoi(parts[6]) - 1);

Expand Down Expand Up @@ -1027,6 +1019,35 @@ void GUIFormSpecMenu::parseButton(parserData* data, const std::string &element,
m_fields.push_back(spec);
}

bool GUIFormSpecMenu::parseMiddleRect(const std::string &value, core::rect<s32> *parsed_rect)
{
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 = core::vector2di(x, x);
rect.LowerRightCorner = core::vector2di(-x, -x);
} else if (v_rect.size() == 2) {
s32 x = stoi(v_rect[0]);
s32 y = stoi(v_rect[1]);
rect.UpperLeftCorner = core::vector2di(x, y);
rect.LowerRightCorner = core::vector2di(-x, -y);
// `-x` is interpreted as `w - x`
} else if (v_rect.size() == 4) {
rect.UpperLeftCorner = core::vector2di(stoi(v_rect[0]), stoi(v_rect[1]));
rect.LowerRightCorner = 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;
}

void GUIFormSpecMenu::parseBackground(parserData* data, const std::string &element)
{
std::vector<std::string> parts;
Expand Down Expand Up @@ -1068,25 +1089,8 @@ void GUIFormSpecMenu::parseBackground(parserData* data, const std::string &eleme
}

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 (parts.size() >= 5)
parseMiddleRect(parts[4], &middle);

if (!data->explicit_size && !clip)
warningstream << "invalid use of unclipped background without a size[] element" << std::endl;
Expand Down
2 changes: 2 additions & 0 deletions src/gui/guiFormSpecMenu.h
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,8 @@ class GUIFormSpecMenu : public GUIModalMenu
void parseSetFocus(const std::string &element);
void parseModel(parserData *data, const std::string &element);

bool parseMiddleRect(const std::string &value, core::rect<s32> *parsed_rect);

void tryClose();

void showTooltip(const std::wstring &text, const irr::video::SColor &color,
Expand Down
4 changes: 2 additions & 2 deletions src/network/networkprotocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -228,8 +228,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define PASSWORD_SIZE 28 // Maximum password length. Allows for
// base64-encoded SHA-1 (27+\0).

// See also: Formspec Version History in doc/lua_api.txt
#define FORMSPEC_API_VERSION 5
// See also formspec [Version History] in doc/lua_api.txt
#define FORMSPEC_API_VERSION 6

#define TEXTURENAME_ALLOWED_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_.-"

Expand Down