aboutsummaryrefslogtreecommitdiff
path: root/src/gui/guiFormSpecMenu.cpp
diff options
context:
space:
mode:
authorElias Fleckenstein <eliasfleckenstein@web.de>2020-11-28 13:48:33 +0100
committerElias Fleckenstein <eliasfleckenstein@web.de>2020-11-28 13:48:33 +0100
commiteb6aca8b4a67ef55108231e71ff29a18a29bf5ae (patch)
treef891914d25cae2cdaa24392381436a287340651e /src/gui/guiFormSpecMenu.cpp
parent8de51dae97aa2fe6ea02e4cf437bfe2b2a38eb06 (diff)
parentf1d72d212a0661588be27003069abf4bd8092e55 (diff)
downloaddragonfireclient-eb6aca8b4a67ef55108231e71ff29a18a29bf5ae.tar.xz
Merged Minetest
Diffstat (limited to 'src/gui/guiFormSpecMenu.cpp')
-rw-r--r--src/gui/guiFormSpecMenu.cpp267
1 files changed, 200 insertions, 67 deletions
diff --git a/src/gui/guiFormSpecMenu.cpp b/src/gui/guiFormSpecMenu.cpp
index 601c5c18e..632b15992 100644
--- a/src/gui/guiFormSpecMenu.cpp
+++ b/src/gui/guiFormSpecMenu.cpp
@@ -48,6 +48,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "settings.h"
#include "client/client.h"
#include "client/fontengine.h"
+#include "client/sound.h"
#include "util/hex.h"
#include "util/numeric.h"
#include "util/string.h" // for parseColorString()
@@ -65,6 +66,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "guiScrollContainer.h"
#include "intlGUIEditBox.h"
#include "guiHyperText.h"
+#include "guiScene.h"
#define MY_CHECKPOS(a,b) \
if (v_pos.size() != 2) { \
@@ -94,11 +96,13 @@ inline u32 clamp_u8(s32 value)
GUIFormSpecMenu::GUIFormSpecMenu(JoystickController *joystick,
gui::IGUIElement *parent, s32 id, IMenuManager *menumgr,
- Client *client, ISimpleTextureSource *tsrc, IFormSource *fsrc, TextDest *tdst,
+ Client *client, ISimpleTextureSource *tsrc, ISoundManager *sound_manager,
+ IFormSource *fsrc, TextDest *tdst,
const std::string &formspecPrepend, bool remap_dbl_click):
GUIModalMenu(RenderingEngine::get_gui_env(), parent, id, menumgr, remap_dbl_click),
m_invmgr(client),
m_tsrc(tsrc),
+ m_sound_manager(sound_manager),
m_client(client),
m_formspec_prepend(formspecPrepend),
m_form_src(fsrc),
@@ -142,11 +146,12 @@ GUIFormSpecMenu::~GUIFormSpecMenu()
void GUIFormSpecMenu::create(GUIFormSpecMenu *&cur_formspec, Client *client,
JoystickController *joystick, IFormSource *fs_src, TextDest *txt_dest,
- const std::string &formspecPrepend)
+ const std::string &formspecPrepend, ISoundManager *sound_manager)
{
if (cur_formspec == nullptr) {
cur_formspec = new GUIFormSpecMenu(joystick, guiroot, -1, &g_menumgr,
- client, client->getTextureSource(), fs_src, txt_dest, formspecPrepend);
+ client, client->getTextureSource(), sound_manager, fs_src,
+ txt_dest, formspecPrepend);
cur_formspec->doPause = false;
/*
@@ -613,6 +618,9 @@ void GUIFormSpecMenu::parseCheckbox(parserData* data, const std::string &element
data->current_parent, spec.fid, spec.flabel.c_str());
auto style = getDefaultStyleForElement("checkbox", name);
+
+ spec.sound = style.get(StyleSpec::Property::SOUND, "");
+
e->setNotClipped(style.getBool(StyleSpec::NOCLIP, false));
if (spec.fname == m_focused_element) {
@@ -1019,6 +1027,9 @@ void GUIFormSpecMenu::parseButton(parserData* data, const std::string &element,
data->current_parent, spec.fid, spec.flabel.c_str());
auto style = getStyleForElement(type, name, (type != "button") ? "button" : "");
+
+ spec.sound = style[StyleSpec::STATE_DEFAULT].get(StyleSpec::Property::SOUND, "");
+
e->setStyles(style);
if (spec.fname == m_focused_element) {
@@ -1225,6 +1236,7 @@ void GUIFormSpecMenu::parseTable(parserData* data, const std::string &element)
auto style = getDefaultStyleForElement("table", name);
e->setNotClipped(style.getBool(StyleSpec::NOCLIP, false));
+ e->setOverrideFont(style.getFont());
m_tables.emplace_back(spec, e);
m_fields.push_back(spec);
@@ -1302,6 +1314,7 @@ void GUIFormSpecMenu::parseTextList(parserData* data, const std::string &element
auto style = getDefaultStyleForElement("textlist", name);
e->setNotClipped(style.getBool(StyleSpec::NOCLIP, false));
+ e->setOverrideFont(style.getFont());
m_tables.emplace_back(spec, e);
m_fields.push_back(spec);
@@ -1378,6 +1391,9 @@ void GUIFormSpecMenu::parseDropDown(parserData* data, const std::string &element
e->setSelected(stoi(str_initial_selection)-1);
auto style = getDefaultStyleForElement("dropdown", name);
+
+ spec.sound = style.get(StyleSpec::Property::SOUND, "");
+
e->setNotClipped(style.getBool(StyleSpec::NOCLIP, false));
m_fields.push_back(spec);
@@ -1738,12 +1754,16 @@ void GUIFormSpecMenu::parseHyperText(parserData *data, const std::string &elemen
FieldSpec spec(
name,
- utf8_to_wide(unescape_string(text)),
+ translate_string(utf8_to_wide(unescape_string(text))),
L"",
258 + m_fields.size()
);
spec.ftype = f_HyperText;
+
+ auto style = getDefaultStyleForElement("hypertext", spec.fname);
+ spec.sound = style.get(StyleSpec::Property::SOUND, "");
+
GUIHyperText *e = new GUIHyperText(spec.flabel.c_str(), Environment,
data->current_parent, spec.fid, rect, m_client, m_tsrc);
e->drop();
@@ -1996,6 +2016,8 @@ void GUIFormSpecMenu::parseImageButton(parserData* data, const std::string &elem
auto style = getStyleForElement("image_button", spec.fname);
+ spec.sound = style[StyleSpec::STATE_DEFAULT].get(StyleSpec::Property::SOUND, "");
+
// Override style properties with values specified directly in the element
if (!image_name.empty())
style[StyleSpec::STATE_DEFAULT].set(StyleSpec::FGIMG, image_name);
@@ -2104,6 +2126,9 @@ void GUIFormSpecMenu::parseTabHeader(parserData* data, const std::string &elemen
e->setTabHeight(geom.Y);
auto style = getDefaultStyleForElement("tabheader", name);
+
+ spec.sound = style.get(StyleSpec::Property::SOUND, "");
+
e->setNotClipped(style.getBool(StyleSpec::NOCLIP, true));
for (const std::string &button : buttons) {
@@ -2192,6 +2217,9 @@ void GUIFormSpecMenu::parseItemImageButton(parserData* data, const std::string &
item_name, m_client);
auto style = getStyleForElement("item_image_button", spec_btn.fname, "image_button");
+
+ spec_btn.sound = style[StyleSpec::STATE_DEFAULT].get(StyleSpec::Property::SOUND, "");
+
e_btn->setStyles(style);
if (spec_btn.fname == m_focused_element) {
@@ -2209,16 +2237,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;
@@ -2232,36 +2260,43 @@ void GUIFormSpecMenu::parseBox(parserData* data, const std::string &element)
geom.Y = stof(v_geom[1]) * spacing.Y;
}
- video::SColor tmp_color;
-
- if (parseColorString(parts[2], tmp_color, false, 0x8C)) {
- FieldSpec spec(
- "",
- L"",
- L"",
- 258 + m_fields.size(),
- -2
- );
- spec.ftype = f_Box;
+ FieldSpec spec(
+ "",
+ L"",
+ L"",
+ 258 + m_fields.size(),
+ -2
+ );
+ spec.ftype = f_Box;
- core::rect<s32> rect(pos, pos + geom);
+ auto style = getDefaultStyleForElement("box", spec.fname);
- GUIBox *e = new GUIBox(Environment, data->current_parent, spec.fid,
- rect, 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};
- auto style = getDefaultStyleForElement("box", spec.fname);
- e->setNotClipped(style.getBool(StyleSpec::NOCLIP, m_formspec_version < 3));
+ if (parseColorString(parts[2], tmp_color, true, 0x8C)) {
+ colors = {tmp_color, tmp_color, tmp_color, tmp_color};
+ } else {
+ 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});
+ }
- e->drop();
+ core::rect<s32> rect(pos, pos + geom);
- m_fields.push_back(spec);
+ 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();
- } else {
- errorstream<< "Invalid Box element(" << parts.size() << "): '" << element << "' INVALID COLOR" << std::endl;
- }
+ 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)
@@ -2686,6 +2721,86 @@ void GUIFormSpecMenu::parseSetFocus(const std::string &element)
<< "'" << std::endl;
}
+void GUIFormSpecMenu::parseModel(parserData *data, const std::string &element)
+{
+ std::vector<std::string> parts = split(element, ';');
+
+ if (parts.size() < 5 || (parts.size() > 8 &&
+ m_formspec_version <= FORMSPEC_API_VERSION)) {
+ errorstream << "Invalid model element (" << parts.size() << "): '" << element
+ << "'" << std::endl;
+ return;
+ }
+
+ // Avoid length checks by resizing
+ if (parts.size() < 8)
+ parts.resize(8);
+
+ 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]);
+ std::string meshstr = unescape_string(parts[3]);
+ std::vector<std::string> textures = split(parts[4], ',');
+ std::vector<std::string> vec_rot = split(parts[5], ',');
+ bool inf_rotation = is_yes(parts[6]);
+ bool mousectrl = is_yes(parts[7]) || parts[7].empty(); // default true
+
+ MY_CHECKPOS("model", 0);
+ MY_CHECKGEOM("model", 1);
+
+ v2s32 pos;
+ v2s32 geom;
+
+ if (data->real_coordinates) {
+ pos = getRealCoordinateBasePos(v_pos);
+ geom = getRealCoordinateGeometry(v_geom);
+ } else {
+ pos = getElementBasePos(&v_pos);
+ geom.X = stof(v_geom[0]) * (float)imgsize.X;
+ geom.Y = stof(v_geom[1]) * (float)imgsize.Y;
+ }
+
+ if (!data->explicit_size)
+ warningstream << "invalid use of model without a size[] element" << std::endl;
+
+ scene::IAnimatedMesh *mesh = m_client->getMesh(meshstr);
+
+ if (!mesh) {
+ errorstream << "Invalid model element: Unable to load mesh:"
+ << std::endl << "\t" << meshstr << std::endl;
+ return;
+ }
+
+ FieldSpec spec(
+ name,
+ L"",
+ L"",
+ 258 + m_fields.size()
+ );
+
+ core::rect<s32> rect(pos, pos + geom);
+
+ GUIScene *e = new GUIScene(Environment, RenderingEngine::get_scene_manager(),
+ data->current_parent, rect, spec.fid);
+
+ auto meshnode = e->setMesh(mesh);
+
+ for (u32 i = 0; i < textures.size() && i < meshnode->getMaterialCount(); ++i)
+ e->setTexture(i, m_tsrc->getTexture(textures[i]));
+
+ if (vec_rot.size() >= 2)
+ e->setRotation(v2f(stof(vec_rot[0]), stof(vec_rot[1])));
+
+ e->enableContinuousRotation(inf_rotation);
+ e->enableMouseControl(mousectrl);
+
+ auto style = getStyleForElement("model", spec.fname);
+ e->setStyles(style);
+ e->drop();
+
+ m_fields.push_back(spec);
+}
+
void GUIFormSpecMenu::parseElement(parserData* data, const std::string &element)
{
//some prechecks
@@ -2882,6 +2997,11 @@ void GUIFormSpecMenu::parseElement(parserData* data, const std::string &element)
return;
}
+ if (type == "model") {
+ parseModel(data, description);
+ return;
+ }
+
// Ignore others
infostream << "Unknown DrawSpec: type=" << type << ", data=\"" << description << "\""
<< std::endl;
@@ -3110,42 +3230,42 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
// and default scaling (1.00).
use_imgsize = 0.5555 * screen_dpi * gui_scaling;
} else {
- // In variable-size mode, we prefer to make the
- // inventory image size 1/15 of screen height,
- // multiplied by the gui_scaling config parameter.
- // If the preferred size won't fit the whole
- // form on the screen, either horizontally or
- // vertically, then we scale it down to fit.
- // (The magic numbers in the computation of what
- // fits arise from the scaling factors in the
- // following stanza, including the form border,
- // help text space, and 0.1 inventory slot spare.)
- // However, a minimum size is also set, that
- // the image size can't be less than 0.3 inch
- // multiplied by gui_scaling, even if this means
- // the form doesn't fit the screen.
+ // Variables for the maximum imgsize that can fit in the screen.
+ double fitx_imgsize;
+ double fity_imgsize;
+
+ // Pad the screensize with 5% of the screensize on all sides to ensure
+ // that even the largest formspecs don't touch the screen borders.
+ v2f padded_screensize(
+ mydata.screensize.X * 0.9f,
+ mydata.screensize.Y * 0.9f
+ );
+
+ if (mydata.real_coordinates) {
+ fitx_imgsize = padded_screensize.X / mydata.invsize.X;
+ fity_imgsize = padded_screensize.Y / mydata.invsize.Y;
+ } else {
+ // The maximum imgsize in the old coordinate system also needs to
+ // factor in padding and spacing along with 0.1 inventory slot spare
+ // and help text space, hence the magic numbers.
+ fitx_imgsize = padded_screensize.X /
+ ((5.0 / 4.0) * (0.5 + mydata.invsize.X));
+ fity_imgsize = padded_screensize.Y /
+ ((15.0 / 13.0) * (0.85 + mydata.invsize.Y));
+ }
+
#ifdef __ANDROID__
- // For mobile devices these magic numbers are
- // different and forms should always use the
- // maximum screen space available.
- double prefer_imgsize = mydata.screensize.Y / 10 * gui_scaling;
- double fitx_imgsize = mydata.screensize.X /
- ((12.0 / 8.0) * (0.5 + mydata.invsize.X));
- double fity_imgsize = mydata.screensize.Y /
- ((15.0 / 11.0) * (0.85 + mydata.invsize.Y));
- use_imgsize = MYMIN(prefer_imgsize,
- MYMIN(fitx_imgsize, fity_imgsize));
+ // In Android, the preferred imgsize should be larger to accommodate the
+ // smaller screensize.
+ double prefer_imgsize = padded_screensize.Y / 10 * gui_scaling;
#else
- double prefer_imgsize = mydata.screensize.Y / 15 * gui_scaling;
- double fitx_imgsize = mydata.screensize.X /
- ((5.0 / 4.0) * (0.5 + mydata.invsize.X));
- double fity_imgsize = mydata.screensize.Y /
- ((15.0 / 13.0) * (0.85 * mydata.invsize.Y));
- double screen_dpi = RenderingEngine::getDisplayDensity() * 96;
- double min_imgsize = 0.3 * screen_dpi * gui_scaling;
- use_imgsize = MYMAX(min_imgsize, MYMIN(prefer_imgsize,
- MYMIN(fitx_imgsize, fity_imgsize)));
+ // Desktop computers have more space, so try to fit 15 coordinates.
+ double prefer_imgsize = padded_screensize.Y / 15 * gui_scaling;
#endif
+ // Try to use the preferred imgsize, but if that's bigger than the maximum
+ // size, use the maximum size.
+ use_imgsize = std::min(prefer_imgsize,
+ std::min(fitx_imgsize, fity_imgsize));
}
// Everything else is scaled in proportion to the
@@ -3474,10 +3594,14 @@ void GUIFormSpecMenu::drawMenu()
e->setVisible(true);
/*
- Call base class
- (This is where all the drawing happens.)
+ This is where all the drawing happens.
*/
- gui::IGUIElement::draw();
+ core::list<IGUIElement*>::Iterator it = Children.begin();
+ for (; it != Children.end(); ++it)
+ if ((*it)->isNotClipped() ||
+ AbsoluteClippingRect.isRectCollided(
+ (*it)->getAbsolutePosition()))
+ (*it)->draw();
for (gui::IGUIElement *e : m_clickthrough_elements)
e->setVisible(false);
@@ -4387,6 +4511,8 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event)
for (GUIFormSpecMenu::FieldSpec &s : m_fields) {
if ((s.ftype == f_TabHeader) &&
(s.fid == event.GUIEvent.Caller->getID())) {
+ if (!s.sound.empty() && m_sound_manager)
+ m_sound_manager->playSound(s.sound, false, 1.0f);
s.send = true;
acceptInput();
s.send = false;
@@ -4430,6 +4556,9 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event)
continue;
if (s.ftype == f_Button || s.ftype == f_CheckBox) {
+ if (!s.sound.empty() && m_sound_manager)
+ m_sound_manager->playSound(s.sound, false, 1.0f);
+
s.send = true;
if (s.is_exit) {
if (m_allowclose) {
@@ -4452,6 +4581,8 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event)
s2.send = false;
}
}
+ if (!s.sound.empty() && m_sound_manager)
+ m_sound_manager->playSound(s.sound, false, 1.0f);
s.send = true;
acceptInput(quit_mode_no);
@@ -4468,6 +4599,8 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event)
acceptInput(quit_mode_no);
s.fdefault = L"";
} else if (s.ftype == f_Unknown || s.ftype == f_HyperText) {
+ if (!s.sound.empty() && m_sound_manager)
+ m_sound_manager->playSound(s.sound, false, 1.0f);
s.send = true;
acceptInput();
s.send = false;