Formspec: draw order and clipping for all elements (#8740)

This commit is contained in:
DS 2019-11-07 20:11:01 +01:00 committed by SmallJoker
parent 15a030ec9f
commit 5506e97ed8
14 changed files with 825 additions and 455 deletions

@ -178,12 +178,15 @@ LOCAL_SRC_FILES := \
jni/src/filesys.cpp \
jni/src/genericobject.cpp \
jni/src/gettext.cpp \
jni/src/gui/guiBackgroundImage.cpp \
jni/src/gui/guiBox.cpp \
jni/src/gui/guiButton.cpp \
jni/src/gui/guiChatConsole.cpp \
jni/src/gui/guiConfirmRegistration.cpp \
jni/src/gui/guiEditBoxWithScrollbar.cpp \
jni/src/gui/guiEngine.cpp \
jni/src/gui/guiFormSpecMenu.cpp \
jni/src/gui/guiItemImage.cpp \
jni/src/gui/guiKeyChangeMenu.cpp \
jni/src/gui/guiPasswordChange.cpp \
jni/src/gui/guiPathSelectMenu.cpp \

@ -1923,6 +1923,11 @@ When displaying text which can contain formspec code, e.g. text set by a player,
use `minetest.formspec_escape`.
For coloured text you can use `minetest.colorize`.
Since formspec version 3, elements drawn in the order they are defined. All
background elements are drawn before all other elements.
`list` elements are an exception here. They are drawn last. This, however, might
be changed at any time.
**WARNING**: do _not_ use a element name starting with `key_`; those names are
reserved to pass key press events to formspec!
@ -2032,6 +2037,7 @@ Elements
be shown if the inventory list is of size 0.
* **Note**: With the new coordinate system, the spacing between inventory
slots is one-fourth the size of an inventory slot.
* **Note**: Lists are drawn after every other element. This might change at any time.
### `list[<inventory location>;<list name>;<X>,<Y>;<W>,<H>;<starting item index>]`
@ -2039,6 +2045,7 @@ Elements
be shown if the inventory list is of size 0.
* **Note**: With the new coordinate system, the spacing between inventory
slots is one-fourth the size of an inventory slot.
* **Note**: Lists are drawn after every other element. This might change at any time.
### `listring[<inventory location>;<list name>]`

@ -171,7 +171,8 @@ void draw2DImageFilterScaled(video::IVideoDriver *driver, video::ITexture *txr,
}
void draw2DImage9Slice(video::IVideoDriver *driver, video::ITexture *texture,
const core::rect<s32> &rect, const core::rect<s32> &middle)
const core::rect<s32> &rect, const core::rect<s32> &middle,
const core::rect<s32> *cliprect)
{
const video::SColor color(255,255,255,255);
const video::SColor colors[] = {color,color,color,color};
@ -222,9 +223,7 @@ void draw2DImage9Slice(video::IVideoDriver *driver, video::ITexture *texture,
break;
}
draw2DImageFilterScaled(driver, texture, dest,
src,
NULL/*&AbsoluteClippingRect*/, colors, true);
draw2DImageFilterScaled(driver, texture, dest, src, cliprect, colors, true);
}
}
}

@ -53,4 +53,5 @@ void draw2DImageFilterScaled(video::IVideoDriver *driver, video::ITexture *txr,
* 9-slice / segment drawing
*/
void draw2DImage9Slice(video::IVideoDriver *driver, video::ITexture *texture,
const core::rect<s32> &rect, const core::rect<s32> &middle);
const core::rect<s32> &rect, const core::rect<s32> &middle,
const core::rect<s32> *cliprect = nullptr);

@ -1,10 +1,13 @@
set(gui_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/guiBackgroundImage.cpp
${CMAKE_CURRENT_SOURCE_DIR}/guiBox.cpp
${CMAKE_CURRENT_SOURCE_DIR}/guiButton.cpp
${CMAKE_CURRENT_SOURCE_DIR}/guiChatConsole.cpp
${CMAKE_CURRENT_SOURCE_DIR}/guiConfirmRegistration.cpp
${CMAKE_CURRENT_SOURCE_DIR}/guiEditBoxWithScrollbar.cpp
${CMAKE_CURRENT_SOURCE_DIR}/guiEngine.cpp
${CMAKE_CURRENT_SOURCE_DIR}/guiFormSpecMenu.cpp
${CMAKE_CURRENT_SOURCE_DIR}/guiItemImage.cpp
${CMAKE_CURRENT_SOURCE_DIR}/guiKeyChangeMenu.cpp
${CMAKE_CURRENT_SOURCE_DIR}/guiPasswordChange.cpp
${CMAKE_CURRENT_SOURCE_DIR}/guiPathSelectMenu.cpp

@ -0,0 +1,69 @@
/*
Part of Minetest
Copyright (C) 2013 RealBadAngel, Maciej Kasatkin <mk@realbadangel.pl>
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "guiBackgroundImage.h"
#include "client/guiscalingfilter.h"
#include "log.h"
GUIBackgroundImage::GUIBackgroundImage(gui::IGUIEnvironment *env,
gui::IGUIElement *parent, s32 id, const core::rect<s32> &rectangle,
const std::string &name, const core::rect<s32> &middle,
ISimpleTextureSource *tsrc, bool autoclip) :
gui::IGUIElement(gui::EGUIET_ELEMENT, env, parent, id, rectangle),
m_name(name), m_middle(middle), m_tsrc(tsrc), m_autoclip(autoclip)
{
}
void GUIBackgroundImage::draw()
{
if (!IsVisible)
return;
video::ITexture *texture = m_tsrc->getTexture(m_name);
if (!texture) {
errorstream << "GUIBackgroundImage::draw() Unable to load texture:"
<< std::endl;
errorstream << "\t" << m_name << std::endl;
return;
}
core::rect<s32> rect = AbsoluteRect;
if (m_autoclip)
rect.LowerRightCorner += Parent->getAbsolutePosition().getSize();
video::IVideoDriver *driver = Environment->getVideoDriver();
if (m_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())),
nullptr, colors, true);
} else {
core::rect<s32> middle = m_middle;
// `-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);
}
IGUIElement::draw();
}

@ -0,0 +1,38 @@
/*
Part of Minetest
Copyright (C) 2013 RealBadAngel, Maciej Kasatkin <mk@realbadangel.pl>
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#pragma once
#include "irrlichttypes_extrabloated.h"
#include "util/string.h"
#include "client/tile.h" // ITextureSource
class GUIBackgroundImage : public gui::IGUIElement
{
public:
GUIBackgroundImage(gui::IGUIEnvironment *env, gui::IGUIElement *parent, s32 id,
const core::rect<s32> &rectangle, const std::string &name,
const core::rect<s32> &middle, ISimpleTextureSource *tsrc, bool autoclip);
virtual void draw() override;
private:
std::string m_name;
core::rect<s32> m_middle;
ISimpleTextureSource *m_tsrc;
bool m_autoclip;
};

38
src/gui/guiBox.cpp Normal file

@ -0,0 +1,38 @@
/*
Minetest
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "guiBox.h"
GUIBox::GUIBox(gui::IGUIEnvironment *env, gui::IGUIElement *parent, s32 id,
const core::rect<s32> &rectangle, const video::SColor &color) :
gui::IGUIElement(gui::EGUIET_ELEMENT, env, parent, id, rectangle),
m_color(color)
{
}
void GUIBox::draw()
{
if (!IsVisible)
return;
Environment->getVideoDriver()->draw2DRectangle(m_color, AbsoluteRect,
&AbsoluteClippingRect);
IGUIElement::draw();
}

34
src/gui/guiBox.h Normal file

@ -0,0 +1,34 @@
/*
Minetest
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#pragma once
#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);
virtual void draw() override;
private:
video::SColor m_color;
};

File diff suppressed because it is too large Load Diff

@ -36,6 +36,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
class InventoryManager;
class ISimpleTextureSource;
class Client;
class GUIScrollBar;
typedef enum {
f_Button,
@ -44,6 +45,8 @@ typedef enum {
f_CheckBox,
f_DropDown,
f_ScrollBar,
f_Box,
f_ItemImage,
f_Unknown
} FormspecFieldType;
@ -101,11 +104,11 @@ class GUIFormSpecMenu : public GUIModalMenu
ListDrawSpec(const InventoryLocation &a_inventoryloc,
const std::string &a_listname,
v2s32 a_pos, v2s32 a_geom, s32 a_start_item_i,
IGUIElement *elem, v2s32 a_geom, s32 a_start_item_i,
bool a_real_coordinates):
inventoryloc(a_inventoryloc),
listname(a_listname),
pos(a_pos),
e(elem),
geom(a_geom),
start_item_i(a_start_item_i),
real_coordinates(a_real_coordinates)
@ -114,7 +117,7 @@ class GUIFormSpecMenu : public GUIModalMenu
InventoryLocation inventoryloc;
std::string listname;
v2s32 pos;
IGUIElement *e;
v2s32 geom;
s32 start_item_i;
bool real_coordinates;
@ -135,84 +138,6 @@ class GUIFormSpecMenu : public GUIModalMenu
std::string listname;
};
struct ImageDrawSpec
{
ImageDrawSpec():
parent_button(NULL),
clip(false)
{
}
ImageDrawSpec(const std::string &a_name,
const std::string &a_item_name,
gui::IGUIButton *a_parent_button,
const v2s32 &a_pos, const v2s32 &a_geom):
name(a_name),
item_name(a_item_name),
parent_button(a_parent_button),
pos(a_pos),
geom(a_geom),
scale(true),
clip(false)
{
}
ImageDrawSpec(const std::string &a_name,
const std::string &a_item_name,
const v2s32 &a_pos, const v2s32 &a_geom):
name(a_name),
item_name(a_item_name),
parent_button(NULL),
pos(a_pos),
geom(a_geom),
scale(true),
clip(false)
{
}
ImageDrawSpec(const std::string &a_name,
const v2s32 &a_pos, const v2s32 &a_geom, bool clip=false):
name(a_name),
parent_button(NULL),
pos(a_pos),
geom(a_geom),
scale(true),
clip(clip)
{
}
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),
pos(a_pos),
scale(false),
clip(false)
{
}
std::string name;
std::string item_name;
gui::IGUIButton *parent_button;
v2s32 pos;
v2s32 geom;
core::rect<s32> middle;
bool scale;
bool clip;
};
struct FieldSpec
{
FieldSpec() = default;
@ -239,19 +164,6 @@ class GUIFormSpecMenu : public GUIModalMenu
core::rect<s32> rect;
};
struct BoxDrawSpec
{
BoxDrawSpec(v2s32 a_pos, v2s32 a_geom, irr::video::SColor a_color):
pos(a_pos),
geom(a_geom),
color(a_color)
{
}
v2s32 pos;
v2s32 geom;
irr::video::SColor color;
};
struct TooltipSpec
{
TooltipSpec() = default;
@ -397,10 +309,9 @@ protected:
}
std::wstring getLabelByID(s32 id);
std::string getNameByID(s32 id);
v2s32 getElementBasePos(bool absolute,
const std::vector<std::string> *v_pos);
v2s32 getRealCoordinateBasePos(bool absolute,
const std::vector<std::string> &v_pos);
FormspecFieldType getTypeByID(s32 id);
v2s32 getElementBasePos(const std::vector<std::string> *v_pos);
v2s32 getRealCoordinateBasePos(const std::vector<std::string> &v_pos);
v2s32 getRealCoordinateGeometry(const std::vector<std::string> &v_geom);
std::unordered_map<std::string, StyleSpec> theme_by_type;
@ -427,18 +338,14 @@ protected:
std::vector<ListDrawSpec> m_inventorylists;
std::vector<ListRingSpec> m_inventory_rings;
std::vector<ImageDrawSpec> m_backgrounds;
std::vector<ImageDrawSpec> m_images;
std::vector<ImageDrawSpec> m_itemimages;
std::vector<BoxDrawSpec> m_boxes;
std::vector<gui::IGUIElement *> m_backgrounds;
std::unordered_map<std::string, bool> field_close_on_enter;
std::vector<FieldSpec> m_fields;
std::vector<StaticTextSpec> m_static_texts;
std::vector<std::pair<FieldSpec, GUITable *>> m_tables;
std::vector<std::pair<FieldSpec, gui::IGUICheckBox *>> m_checkboxes;
std::map<std::string, TooltipSpec> m_tooltips;
std::vector<std::pair<irr::core::rect<s32>, TooltipSpec>> m_tooltip_rects;
std::vector<std::pair<FieldSpec,gui::IGUIScrollBar*> > m_scrollbars;
std::vector<std::pair<gui::IGUIElement *, TooltipSpec>> m_tooltip_rects;
std::vector<std::pair<FieldSpec, GUIScrollBar *>> m_scrollbars;
std::vector<std::pair<FieldSpec, std::vector<std::string>>> m_dropdowns;
ItemSpec *m_selected_item = nullptr;
@ -480,6 +387,7 @@ private:
typedef struct {
bool explicit_size;
bool real_coordinates;
u8 simple_field_count;
v2f invsize;
v2s32 size;
v2f32 offset;
@ -555,6 +463,13 @@ private:
void showTooltip(const std::wstring &text, const irr::video::SColor &color,
const irr::video::SColor &bgcolor);
/**
* In formspec version < 2 the elements were not ordered properly. Some element
* types were drawn before others.
* This function sorts the elements in the old order for backwards compatibility.
*/
void legacySortElements(core::list<IGUIElement *>::Iterator from);
/**
* check if event is part of a double click
* @param event event to evaluate

64
src/gui/guiItemImage.cpp Normal file

@ -0,0 +1,64 @@
/*
Minetest
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "guiItemImage.h"
#include "client/client.h"
GUIItemImage::GUIItemImage(gui::IGUIEnvironment *env, gui::IGUIElement *parent,
s32 id, const core::rect<s32> &rectangle, const std::string &item_name,
gui::IGUIFont *font, Client *client) :
gui::IGUIElement(gui::EGUIET_ELEMENT, env, parent, id, rectangle),
m_item_name(item_name), m_font(font), m_client(client), m_label(core::stringw())
{
}
void GUIItemImage::draw()
{
if (!IsVisible)
return;
if (!m_client) {
IGUIElement::draw();
return;
}
IItemDefManager *idef = m_client->idef();
ItemStack item;
item.deSerialize(m_item_name, idef);
// Viewport rectangle on screen
core::rect<s32> rect = core::rect<s32>(AbsoluteRect);
if (Parent->getType() == gui::EGUIET_BUTTON &&
((irr::gui::IGUIButton *)Parent)->isPressed()) {
#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8)
rect += core::dimension2d<s32>(0.05 * (float)rect.getWidth(),
0.05 * (float)rect.getHeight());
#else
gui::IGUISkin *skin = Environment->getSkin();
rect += core::dimension2d<s32>(
skin->getSize(irr::gui::EGDS_BUTTON_PRESSED_IMAGE_OFFSET_X),
skin->getSize(irr::gui::EGDS_BUTTON_PRESSED_IMAGE_OFFSET_Y));
#endif
}
drawItemStack(Environment->getVideoDriver(), m_font, item, rect,
&AbsoluteClippingRect, m_client, IT_ROT_NONE);
video::SColor color(255, 255, 255, 255);
m_font->draw(m_label, rect, color, true, true, &AbsoluteClippingRect);
IGUIElement::draw();
}

46
src/gui/guiItemImage.h Normal file

@ -0,0 +1,46 @@
/*
Minetest
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#pragma once
#include "irrlichttypes_extrabloated.h"
#include "util/string.h"
class Client;
class GUIItemImage : public gui::IGUIElement
{
public:
GUIItemImage(gui::IGUIEnvironment *env, gui::IGUIElement *parent, s32 id,
const core::rect<s32> &rectangle, const std::string &item_name,
gui::IGUIFont *font, Client *client);
virtual void draw() override;
virtual void setText(const wchar_t *text) override
{
m_label = text;
}
private:
std::string m_item_name;
gui::IGUIFont *m_font;
Client *m_client;
core::stringw m_label;
};

@ -228,9 +228,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
(too much)
FORMSPEC VERSION 2:
Forced real coordinates
background[]: 9-slice scaling parameters
background9[]: 9-slice scaling parameters
FORMSPEC VERSION 3:
Formspec elements are drawn in the order of definition
*/
#define FORMSPEC_API_VERSION 2
#define FORMSPEC_API_VERSION 3
#define TEXTURENAME_ALLOWED_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_.-"