X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2FguiFormSpecMenu.cpp;h=330124fe1aebf7441a9c6531fa7e2b6de27c1f9e;hb=503e1d2b7c800a76a161541d90b799e9786adbd9;hp=b0215a84aee11e79de3094649140c8068583a99c;hpb=88acda02567d586820867059718cac551dc7a58b;p=oweals%2Fminetest.git diff --git a/src/guiFormSpecMenu.cpp b/src/guiFormSpecMenu.cpp index b0215a84a..330124fe1 100644 --- a/src/guiFormSpecMenu.cpp +++ b/src/guiFormSpecMenu.cpp @@ -42,7 +42,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "filesys.h" #include "gettime.h" #include "gettext.h" -#include "scripting_game.h" +#include "serverscripting.h" #include "porting.h" #include "settings.h" #include "client.h" @@ -50,6 +50,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "util/hex.h" #include "util/numeric.h" #include "util/string.h" // for parseColorString() +#include "irrlicht_changes/static_text.h" #include "guiscalingfilter.h" #if USE_FREETYPE && IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 9 @@ -78,14 +79,14 @@ static unsigned int font_line_height(gui::IGUIFont *font) } GUIFormSpecMenu::GUIFormSpecMenu(irr::IrrlichtDevice* dev, + JoystickController *joystick, gui::IGUIElement* parent, s32 id, IMenuManager *menumgr, - InventoryManager *invmgr, IGameDef *gamedef, + Client *client, ISimpleTextureSource *tsrc, IFormSource* fsrc, TextDest* tdst, - Client* client, bool remap_dbl_click) : + bool remap_dbl_click) : GUIModalMenu(dev->getGUIEnvironment(), parent, id, menumgr), m_device(dev), - m_invmgr(invmgr), - m_gamedef(gamedef), + m_invmgr(client), m_tsrc(tsrc), m_client(client), m_selected_item(NULL), @@ -101,6 +102,8 @@ GUIFormSpecMenu::GUIFormSpecMenu(irr::IrrlichtDevice* dev, m_text_dst(tdst), m_formspec_version(0), m_focused_element(""), + m_joystick(joystick), + current_field_enter_pending(""), m_font(NULL), m_remap_dbl_click(remap_dbl_click) #ifdef __ANDROID__ @@ -249,37 +252,6 @@ std::vector* GUIFormSpecMenu::getDropDownValues(const std::string & return NULL; } -static std::vector split(const std::string &s, char delim) -{ - std::vector tokens; - - std::string current = ""; - bool last_was_escape = false; - for (unsigned int i = 0; i < s.size(); i++) { - char si = s.c_str()[i]; - if (last_was_escape) { - current += '\\'; - current += si; - last_was_escape = false; - } else { - if (si == delim) { - tokens.push_back(current); - current = ""; - last_was_escape = false; - } else if (si == '\\') { - last_was_escape = true; - } else { - current += si; - last_was_escape = false; - } - } - } - //push last element - tokens.push_back(current); - - return tokens; -} - void GUIFormSpecMenu::parseSize(parserData* data,std::string element) { std::vector parts = split(element,','); @@ -306,10 +278,36 @@ void GUIFormSpecMenu::parseSize(parserData* data,std::string element) errorstream<< "Invalid size element (" << parts.size() << "): '" << element << "'" << std::endl; } +void GUIFormSpecMenu::parseContainer(parserData* data, std::string element) +{ + std::vector parts = split(element, ','); + + if (parts.size() >= 2) { + if (parts[1].find(';') != std::string::npos) + parts[1] = parts[1].substr(0, parts[1].find(';')); + + container_stack.push(pos_offset); + pos_offset.X += MYMAX(0, stof(parts[0])); + pos_offset.Y += MYMAX(0, stof(parts[1])); + return; + } + errorstream<< "Invalid container start element (" << parts.size() << "): '" << element << "'" << std::endl; +} + +void GUIFormSpecMenu::parseContainerEnd(parserData* data) +{ + if (container_stack.empty()) { + errorstream<< "Invalid container end element, no matching container start element" << std::endl; + } else { + pos_offset = container_stack.top(); + container_stack.pop(); + } +} + void GUIFormSpecMenu::parseList(parserData* data,std::string element) { - if (m_gamedef == 0) { - warningstream<<"invalid use of 'list' with m_gamedef==0"< v_geom = split(parts[1],','); std::string name = unescape_string(parts[2]); - MY_CHECKPOS("image",0); - MY_CHECKGEOM("image",1); + MY_CHECKPOS("image", 0); + MY_CHECKGEOM("image", 1); - v2s32 pos = padding + AbsoluteRect.UpperLeftCorner; + v2s32 pos = padding + AbsoluteRect.UpperLeftCorner + pos_offset * spacing; pos.X += stof(v_pos[0]) * (float) spacing.X; pos.Y += stof(v_pos[1]) * (float) spacing.Y; @@ -533,23 +531,21 @@ void GUIFormSpecMenu::parseImage(parserData* data,std::string element) geom.X = stof(v_geom[0]) * (float)imgsize.X; geom.Y = stof(v_geom[1]) * (float)imgsize.Y; - if(!data->explicit_size) + if (!data->explicit_size) warningstream<<"invalid use of image without a size[] element"< v_pos = split(parts[0],','); std::string name = unescape_string(parts[1]); - MY_CHECKPOS("image",0); + MY_CHECKPOS("image", 0); - v2s32 pos = padding + AbsoluteRect.UpperLeftCorner; + v2s32 pos = padding + AbsoluteRect.UpperLeftCorner + pos_offset * spacing; pos.X += stof(v_pos[0]) * (float) spacing.X; pos.Y += stof(v_pos[1]) * (float) spacing.Y; - if(!data->explicit_size) + if (!data->explicit_size) warningstream<<"invalid use of image without a size[] element"<explicit_size) + warningstream<<"invalid use of background without a size[] element"<explicit_size) - warningstream<<"invalid use of background without a size[] element"< parts = split(element,';'); + if (parts.size() == 2 || + (parts.size() > 2 && m_formspec_version > FORMSPEC_API_VERSION)) { + field_close_on_enter[parts[0]] = is_yes(parts[1]); + } +} + void GUIFormSpecMenu::parsePwdField(parserData* data,std::string element) { std::vector parts = split(element,';'); - if ((parts.size() == 4) || - ((parts.size() > 4) && (m_formspec_version > FORMSPEC_API_VERSION))) + if ((parts.size() == 4) || (parts.size() == 5) || + ((parts.size() > 5) && (m_formspec_version > FORMSPEC_API_VERSION))) { std::vector v_pos = split(parts[0],','); std::vector v_geom = split(parts[1],','); @@ -932,7 +938,7 @@ void GUIFormSpecMenu::parsePwdField(parserData* data,std::string element) MY_CHECKPOS("pwdfield",0); MY_CHECKGEOM("pwdfield",1); - v2s32 pos; + v2s32 pos = pos_offset * spacing; pos.X += stof(v_pos[0]) * (float)spacing.X; pos.Y += stof(v_pos[1]) * (float)spacing.Y; @@ -966,7 +972,7 @@ void GUIFormSpecMenu::parsePwdField(parserData* data,std::string element) int font_height = g_fontengine->getTextHeight(); rect.UpperLeftCorner.Y -= font_height; rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + font_height; - Environment->addStaticText(spec.flabel.c_str(), rect, false, true, this, 0); + addStaticText(Environment, spec.flabel.c_str(), rect, false, true, this, 0); } e->setPasswordBox(true,L'*'); @@ -979,6 +985,14 @@ void GUIFormSpecMenu::parsePwdField(parserData* data,std::string element) evt.KeyInput.Shift = 0; evt.KeyInput.PressedDown = true; e->OnEvent(evt); + + if (parts.size() >= 5) { + // TODO: remove after 2016-11-03 + warningstream << "pwdfield: use field_close_on_enter[name, enabled]" << + " instead of the 5th param" << std::endl; + field_close_on_enter[name] = is_yes(parts[4]); + } + m_fields.push_back(spec); return; } @@ -997,7 +1011,7 @@ void GUIFormSpecMenu::parseSimpleField(parserData* data, if(data->explicit_size) warningstream<<"invalid use of unpositioned \"field\" in inventory"<addStaticText(spec.flabel.c_str(), rect, false, true, this, spec.fid); + addStaticText(Environment, spec.flabel.c_str(), rect, false, true, this, spec.fid); } else { @@ -1056,10 +1070,17 @@ void GUIFormSpecMenu::parseSimpleField(parserData* data, int font_height = g_fontengine->getTextHeight(); rect.UpperLeftCorner.Y -= font_height; rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + font_height; - Environment->addStaticText(spec.flabel.c_str(), rect, false, true, this, 0); + addStaticText(Environment, spec.flabel.c_str(), rect, false, true, this, 0); } } + if (parts.size() >= 4) { + // TODO: remove after 2016-11-03 + warningstream << "field/simple: use field_close_on_enter[name, enabled]" << + " instead of the 4th param" << std::endl; + field_close_on_enter[name] = is_yes(parts[3]); + } + m_fields.push_back(spec); } @@ -1076,9 +1097,9 @@ void GUIFormSpecMenu::parseTextArea(parserData* data, MY_CHECKPOS(type,0); MY_CHECKGEOM(type,1); - v2s32 pos; - pos.X = stof(v_pos[0]) * (float) spacing.X; - pos.Y = stof(v_pos[1]) * (float) spacing.Y; + v2s32 pos = pos_offset * spacing; + pos.X += stof(v_pos[0]) * (float) spacing.X; + pos.Y += stof(v_pos[1]) * (float) spacing.Y; v2s32 geom; @@ -1117,7 +1138,7 @@ void GUIFormSpecMenu::parseTextArea(parserData* data, if (name == "") { // spec field id to 0, this stops submit searching for a value that isn't there - Environment->addStaticText(spec.flabel.c_str(), rect, false, true, this, spec.fid); + addStaticText(Environment, spec.flabel.c_str(), rect, false, true, this, spec.fid); } else { @@ -1161,9 +1182,17 @@ void GUIFormSpecMenu::parseTextArea(parserData* data, int font_height = g_fontengine->getTextHeight(); rect.UpperLeftCorner.Y -= font_height; rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + font_height; - Environment->addStaticText(spec.flabel.c_str(), rect, false, true, this, 0); + addStaticText(Environment, spec.flabel.c_str(), rect, false, true, this, 0); } } + + if (parts.size() >= 6) { + // TODO: remove after 2016-11-03 + warningstream << "field/textarea: use field_close_on_enter[name, enabled]" << + " instead of the 6th param" << std::endl; + field_close_on_enter[name] = is_yes(parts[5]); + } + m_fields.push_back(spec); } @@ -1177,8 +1206,8 @@ void GUIFormSpecMenu::parseField(parserData* data,std::string element, return; } - if ((parts.size() == 5) || - ((parts.size() > 5) && (m_formspec_version > FORMSPEC_API_VERSION))) + if ((parts.size() == 5) || (parts.size() == 6) || + ((parts.size() > 6) && (m_formspec_version > FORMSPEC_API_VERSION))) { parseTextArea(data,parts,type); return; @@ -1198,7 +1227,7 @@ void GUIFormSpecMenu::parseLabel(parserData* data,std::string element) MY_CHECKPOS("label",0); - v2s32 pos = padding; + v2s32 pos = padding + pos_offset * spacing; pos.X += stof(v_pos[0]) * (float)spacing.X; pos.Y += (stof(v_pos[1]) + 7.0/30.0) * (float)spacing.Y; @@ -1230,7 +1259,7 @@ void GUIFormSpecMenu::parseLabel(parserData* data,std::string element) 258+m_fields.size() ); gui::IGUIStaticText *e = - Environment->addStaticText(spec.flabel.c_str(), + addStaticText(Environment, spec.flabel.c_str(), rect, false, false, this, spec.fid); e->setTextAlignment(gui::EGUIA_UPPERLEFT, gui::EGUIA_CENTER); @@ -1255,7 +1284,7 @@ void GUIFormSpecMenu::parseVertLabel(parserData* data,std::string element) MY_CHECKPOS("vertlabel",1); - v2s32 pos = padding; + v2s32 pos = padding + pos_offset * spacing; pos.X += stof(v_pos[0]) * (float)spacing.X; pos.Y += stof(v_pos[1]) * (float)spacing.Y; @@ -1284,7 +1313,7 @@ void GUIFormSpecMenu::parseVertLabel(parserData* data,std::string element) 258+m_fields.size() ); gui::IGUIStaticText *t = - Environment->addStaticText(spec.flabel.c_str(), rect, false, false, this, spec.fid); + addStaticText(Environment, spec.flabel.c_str(), rect, false, false, this, spec.fid); t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_CENTER); m_fields.push_back(spec); return; @@ -1309,7 +1338,7 @@ void GUIFormSpecMenu::parseImageButton(parserData* data,std::string element, MY_CHECKPOS("imagebutton",0); MY_CHECKGEOM("imagebutton",1); - v2s32 pos = padding; + v2s32 pos = padding + pos_offset * spacing; pos.X += stof(v_pos[0]) * (float)spacing.X; pos.Y += stof(v_pos[1]) * (float)spacing.Y; v2s32 geom; @@ -1414,7 +1443,7 @@ void GUIFormSpecMenu::parseTabHeader(parserData* data,std::string element) spec.ftype = f_TabHeader; - v2s32 pos(0,0); + v2s32 pos = pos_offset * spacing; pos.X += stof(v_pos[0]) * (float)spacing.X; pos.Y += stof(v_pos[1]) * (float)spacing.Y - m_btn_height * 2; v2s32 geom; @@ -1456,8 +1485,8 @@ void GUIFormSpecMenu::parseTabHeader(parserData* data,std::string element) void GUIFormSpecMenu::parseItemImageButton(parserData* data,std::string element) { - if (m_gamedef == 0) { - warningstream << "invalid use of item_image_button with m_gamedef==0" + if (m_client == 0) { + warningstream << "invalid use of item_image_button with m_client==0" << std::endl; return; } @@ -1479,7 +1508,7 @@ void GUIFormSpecMenu::parseItemImageButton(parserData* data,std::string element) MY_CHECKPOS("itemimagebutton",0); MY_CHECKGEOM("itemimagebutton",1); - v2s32 pos = padding; + v2s32 pos = padding + pos_offset * spacing; pos.X += stof(v_pos[0]) * (float)spacing.X; pos.Y += stof(v_pos[1]) * (float)spacing.Y; v2s32 geom; @@ -1491,7 +1520,7 @@ void GUIFormSpecMenu::parseItemImageButton(parserData* data,std::string element) if(!data->explicit_size) warningstream<<"invalid use of item_image_button without a size[] element"<idef(); + IItemDefManager *idef = m_client->idef(); ItemStack item; item.deSerialize(item_name, idef); @@ -1517,7 +1546,7 @@ void GUIFormSpecMenu::parseItemImageButton(parserData* data,std::string element) rect+=data->basepos-padding; spec.rect=rect; m_fields.push_back(spec); - pos = padding + AbsoluteRect.UpperLeftCorner; + pos = padding + AbsoluteRect.UpperLeftCorner + pos_offset * spacing; pos.X += stof(v_pos[0]) * (float) spacing.X; pos.Y += stof(v_pos[1]) * (float) spacing.Y; m_itemimages.push_back(ImageDrawSpec("", item_name, e, pos, geom)); @@ -1540,7 +1569,7 @@ void GUIFormSpecMenu::parseBox(parserData* data,std::string element) MY_CHECKPOS("box",0); MY_CHECKGEOM("box",1); - v2s32 pos = padding + AbsoluteRect.UpperLeftCorner; + v2s32 pos = padding + AbsoluteRect.UpperLeftCorner + pos_offset * spacing; pos.X += stof(v_pos[0]) * (float) spacing.X; pos.Y += stof(v_pos[1]) * (float) spacing.Y; @@ -1677,6 +1706,74 @@ bool GUIFormSpecMenu::parseSizeDirect(parserData* data, std::string element) return true; } +bool GUIFormSpecMenu::parsePositionDirect(parserData *data, const std::string &element) +{ + if (element.empty()) + return false; + + std::vector parts = split(element, '['); + + if (parts.size() != 2) + return false; + + std::string type = trim(parts[0]); + std::string description = trim(parts[1]); + + if (type != "position") + return false; + + parsePosition(data, description); + + return true; +} + +void GUIFormSpecMenu::parsePosition(parserData *data, const std::string &element) +{ + std::vector parts = split(element, ','); + + if (parts.size() == 2) { + data->offset.X = stof(parts[0]); + data->offset.Y = stof(parts[1]); + return; + } + + errorstream << "Invalid position element (" << parts.size() << "): '" << element << "'" << std::endl; +} + +bool GUIFormSpecMenu::parseAnchorDirect(parserData *data, const std::string &element) +{ + if (element.empty()) + return false; + + std::vector parts = split(element, '['); + + if (parts.size() != 2) + return false; + + std::string type = trim(parts[0]); + std::string description = trim(parts[1]); + + if (type != "anchor") + return false; + + parseAnchor(data, description); + + return true; +} + +void GUIFormSpecMenu::parseAnchor(parserData *data, const std::string &element) +{ + std::vector parts = split(element, ','); + + if (parts.size() == 2) { + data->anchor.X = stof(parts[0]); + data->anchor.Y = stof(parts[1]); + return; + } + + errorstream << "Invalid anchor element (" << parts.size() << "): '" << element << "'" << std::endl; +} + void GUIFormSpecMenu::parseElement(parserData* data, std::string element) { //some prechecks @@ -1702,8 +1799,18 @@ void GUIFormSpecMenu::parseElement(parserData* data, std::string element) std::string type = trim(parts[0]); std::string description = trim(parts[1]); + if (type == "container") { + parseContainer(data, description); + return; + } + + if (type == "container_end") { + parseContainerEnd(data); + return; + } + if (type == "list") { - parseList(data,description); + parseList(data, description); return; } @@ -1713,22 +1820,22 @@ void GUIFormSpecMenu::parseElement(parserData* data, std::string element) } if (type == "checkbox") { - parseCheckbox(data,description); + parseCheckbox(data, description); return; } if (type == "image") { - parseImage(data,description); + parseImage(data, description); return; } if (type == "item_image") { - parseItemImage(data,description); + parseItemImage(data, description); return; } - if ((type == "button") || (type == "button_exit")) { - parseButton(data,description,type); + if (type == "button" || type == "button_exit") { + parseButton(data, description, type); return; } @@ -1762,6 +1869,11 @@ void GUIFormSpecMenu::parseElement(parserData* data, std::string element) return; } + if (type == "field_close_on_enter") { + parseFieldCloseOnEnter(data, description); + return; + } + if (type == "pwdfield") { parsePwdField(data,description); return; @@ -1873,6 +1985,8 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize) mydata.size= v2s32(100,100); mydata.screensize = screensize; + mydata.offset = v2f32(0.5f, 0.5f); + mydata.anchor = v2f32(0.5f, 0.5f); // Base position of contents of form mydata.basepos = getBasePos(); @@ -1905,12 +2019,11 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize) m_slotbordercolor = video::SColor(200,0,0,0); m_slotborder = false; - m_clipbackground = false; // Add tooltip { assert(m_tooltip_element == NULL); // Note: parent != this so that the tooltip isn't clipped by the menu rectangle - m_tooltip_element = Environment->addStaticText(L"",core::rect(0,0,110,18)); + m_tooltip_element = addStaticText(Environment, L"",core::rect(0,0,110,18)); m_tooltip_element->enableOverrideColor(true); m_tooltip_element->setBackgroundColor(m_default_tooltip_bgcolor); m_tooltip_element->setDrawBackground(true); @@ -1940,6 +2053,21 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize) } } + /* "position" element is always after "size" element if it used */ + for (; i< elements.size(); i++) { + if (!parsePositionDirect(&mydata, elements[i])) { + break; + } + } + + /* "anchor" element is always after "position" (or "size" element) if it used */ + for (; i< elements.size(); i++) { + if (!parseAnchorDirect(&mydata, elements[i])) { + break; + } + } + + if (mydata.explicit_size) { // compute scaling for specified form size if (m_lock) { @@ -2023,10 +2151,10 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize) padding.Y*2+spacing.Y*(mydata.invsize.Y-1.0)+imgsize.Y + m_btn_height*2.0/3.0 ); DesiredRect = mydata.rect = core::rect( - mydata.screensize.X/2 - mydata.size.X/2 + offset.X, - mydata.screensize.Y/2 - mydata.size.Y/2 + offset.Y, - mydata.screensize.X/2 + mydata.size.X/2 + offset.X, - mydata.screensize.Y/2 + mydata.size.Y/2 + offset.Y + (s32)((f32)mydata.screensize.X * mydata.offset.X) - (s32)(mydata.anchor.X * (f32)mydata.size.X) + offset.X, + (s32)((f32)mydata.screensize.Y * mydata.offset.Y) - (s32)(mydata.anchor.Y * (f32)mydata.size.Y) + offset.Y, + (s32)((f32)mydata.screensize.X * mydata.offset.X) + (s32)((1.0 - mydata.anchor.X) * (f32)mydata.size.X) + offset.X, + (s32)((f32)mydata.screensize.Y * mydata.offset.Y) + (s32)((1.0 - mydata.anchor.Y) * (f32)mydata.size.Y) + offset.Y ); } else { // Non-size[] form must consist only of text fields and @@ -2035,10 +2163,10 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize) m_font = g_fontengine->getFont(); m_btn_height = font_line_height(m_font) * 0.875; DesiredRect = core::rect( - mydata.screensize.X/2 - 580/2, - mydata.screensize.Y/2 - 300/2, - mydata.screensize.X/2 + 580/2, - mydata.screensize.Y/2 + 300/2 + (s32)((f32)mydata.screensize.X * mydata.offset.X) - (s32)(mydata.anchor.X * 580.0), + (s32)((f32)mydata.screensize.Y * mydata.offset.Y) - (s32)(mydata.anchor.Y * 300.0), + (s32)((f32)mydata.screensize.X * mydata.offset.X) + (s32)((1.0 - mydata.anchor.X) * 580.0), + (s32)((f32)mydata.screensize.Y * mydata.offset.Y) + (s32)((1.0 - mydata.anchor.Y) * 300.0) ); } recalculateAbsolutePosition(false); @@ -2050,10 +2178,16 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize) gui::IGUIFont *old_font = skin->getFont(); skin->setFont(m_font); + pos_offset = v2s32(); for (; i< elements.size(); i++) { parseElement(&mydata, elements[i]); } + if (!container_stack.empty()) { + errorstream << "Invalid formspec string: container was never closed!" + << std::endl; + } + // If there are fields without explicit size[], add a "Proceed" // button and adjust size to fit all the fields. if (m_fields.size() && !mydata.explicit_size) { @@ -2247,15 +2381,22 @@ void GUIFormSpecMenu::drawList(const ListDrawSpec &s, int phase, if(!item.empty()) { drawItemStack(driver, m_font, item, - rect, &AbsoluteClippingRect, m_gamedef, + rect, &AbsoluteClippingRect, m_client, rotation_kind); } // Draw tooltip std::wstring tooltip_text = L""; if (hovering && !m_selected_item) { - tooltip_text = utf8_to_wide(item.getDefinition(m_gamedef->idef()).description); - tooltip_text = unescape_enriched(tooltip_text); + const std::string &desc = item.metadata.getString("description"); + if (desc.empty()) + tooltip_text = + utf8_to_wide(item.getDefinition(m_client->idef()).description); + else + tooltip_text = utf8_to_wide(desc); + // Show itemstring as fallback for easier debugging + if (!item.name.empty() && tooltip_text.empty()) + tooltip_text = utf8_to_wide(item.name); } if (tooltip_text != L"") { std::vector tt_rows = str_split(tooltip_text, L'\n'); @@ -2263,12 +2404,12 @@ void GUIFormSpecMenu::drawList(const ListDrawSpec &s, int phase, m_tooltip_element->setOverrideColor(m_default_tooltip_color); m_tooltip_element->setVisible(true); this->bringToFront(m_tooltip_element); - m_tooltip_element->setText(tooltip_text.c_str()); + setStaticText(m_tooltip_element, tooltip_text.c_str()); s32 tooltip_width = m_tooltip_element->getTextWidth() + m_btn_height; -#if IRRLICHT_VERSION_MAJOR >= 1 && IRRLICHT_VERSION_MINOR >= 8 && IRRLICHT_VERSION_REVISION >= 2 - s32 tooltip_height = m_tooltip_element->getTextHeight() + 5; -#else +#if (IRRLICHT_VERSION_MAJOR <= 1 && IRRLICHT_VERSION_MINOR <= 8 && IRRLICHT_VERSION_REVISION < 2) || USE_FREETYPE == 1 s32 tooltip_height = m_tooltip_element->getTextHeight() * tt_rows.size() + 5; +#else + s32 tooltip_height = m_tooltip_element->getTextHeight() + 5; #endif v2u32 screenSize = driver->getScreenSize(); int tooltip_offset_x = m_btn_height; @@ -2300,7 +2441,7 @@ void GUIFormSpecMenu::drawSelectedItem() if (!m_selected_item) { drawItemStack(driver, m_font, ItemStack(), core::rect(v2s32(0, 0), v2s32(0, 0)), - NULL, m_gamedef, IT_ROT_DRAGGED); + NULL, m_client, IT_ROT_DRAGGED); return; } @@ -2313,7 +2454,8 @@ void GUIFormSpecMenu::drawSelectedItem() core::rect imgrect(0,0,imgsize.X,imgsize.Y); core::rect rect = imgrect + (m_pointer - imgrect.getCenter()); - drawItemStack(driver, m_font, stack, rect, NULL, m_gamedef, IT_ROT_DRAGGED); + rect.constrainTo(driver->getViewPort()); + drawItemStack(driver, m_font, stack, rect, NULL, m_client, IT_ROT_DRAGGED); } void GUIFormSpecMenu::drawMenu() @@ -2358,7 +2500,7 @@ void GUIFormSpecMenu::drawMenu() // Image rectangle on screen core::rect rect = imgrect + spec.pos; - if (m_clipbackground) { + if (spec.clip) { core::dimension2d absrec_size = AbsoluteRect.getSize(); rect = core::rect(AbsoluteRect.UpperLeftCorner.X - spec.pos.X, AbsoluteRect.UpperLeftCorner.Y - spec.pos.Y, @@ -2372,8 +2514,7 @@ void GUIFormSpecMenu::drawMenu() core::rect(core::position2d(0,0), core::dimension2di(texture->getOriginalSize())), NULL/*&AbsoluteClippingRect*/, colors, true); - } - else { + } else { errorstream << "GUIFormSpecMenu::drawMenu() Draw backgrounds unable to load texture:" << std::endl; errorstream << "\t" << spec.name << std::endl; } @@ -2439,11 +2580,11 @@ void GUIFormSpecMenu::drawMenu() */ for(u32 i=0; iidef(); + IItemDefManager *idef = m_client->idef(); ItemStack item; item.deSerialize(spec.item_name, idef); core::rect imgrect(0, 0, spec.geom.X, spec.geom.Y); @@ -2460,7 +2601,7 @@ void GUIFormSpecMenu::drawMenu() #endif } drawItemStack(driver, m_font, item, rect, &AbsoluteClippingRect, - m_gamedef, IT_ROT_NONE); + m_client, IT_ROT_NONE); } /* @@ -2478,7 +2619,7 @@ void GUIFormSpecMenu::drawMenu() if (!item_hovered) { drawItemStack(driver, m_font, ItemStack(), core::rect(v2s32(0, 0), v2s32(0, 0)), - NULL, m_gamedef, IT_ROT_HOVERED); + NULL, m_client, IT_ROT_HOVERED); } /* TODO find way to show tooltips on touchscreen */ @@ -2490,7 +2631,7 @@ void GUIFormSpecMenu::drawMenu() Draw static text elements */ for (u32 i = 0; i < m_static_texts.size(); i++) { - const StaticTextSpec &spec = m_static_texts[i]; + const StaticTextSpec &spec = m_static_texts[i]; core::rect rect = spec.rect; if (spec.parent_button && spec.parent_button->isPressed()) { #if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8) @@ -2535,8 +2676,10 @@ void GUIFormSpecMenu::drawMenu() iter != m_fields.end(); ++iter) { if (iter->fid == id && m_tooltips[iter->fname].tooltip != L"") { if (m_old_tooltip != m_tooltips[iter->fname].tooltip) { + m_tooltip_element->setBackgroundColor(m_tooltips[iter->fname].bgcolor); + m_tooltip_element->setOverrideColor(m_tooltips[iter->fname].color); m_old_tooltip = m_tooltips[iter->fname].tooltip; - m_tooltip_element->setText(m_tooltips[iter->fname].tooltip.c_str()); + setStaticText(m_tooltip_element, m_tooltips[iter->fname].tooltip.c_str()); std::vector tt_rows = str_split(m_tooltips[iter->fname].tooltip, L'\n'); s32 tooltip_width = m_tooltip_element->getTextWidth() + m_btn_height; s32 tooltip_height = m_tooltip_element->getTextHeight() * tt_rows.size() + 5; @@ -2558,8 +2701,6 @@ void GUIFormSpecMenu::drawMenu() core::position2d(tooltip_x, tooltip_y), core::dimension2d(tooltip_width, tooltip_height))); } - m_tooltip_element->setBackgroundColor(m_tooltips[iter->fname].bgcolor); - m_tooltip_element->setOverrideColor(m_tooltips[iter->fname].color); m_tooltip_element->setVisible(true); this->bringToFront(m_tooltip_element); break; @@ -2568,6 +2709,8 @@ void GUIFormSpecMenu::drawMenu() } } + m_tooltip_element->draw(); + /* Draw dragged item stack */ @@ -2722,6 +2865,11 @@ void GUIFormSpecMenu::acceptInput(FormspecQuitMode quitmode=quit_mode_no) current_keys_pending.key_enter = false; } + if (!current_field_enter_pending.empty()) { + fields["key_enter_field"] = current_field_enter_pending; + current_field_enter_pending = ""; + } + if (current_keys_pending.key_escape) { fields["key_escape"] = "true"; current_keys_pending.key_escape = false; @@ -3053,6 +3201,25 @@ bool GUIFormSpecMenu::preprocessEvent(const SEvent& event) } #endif + if (event.EventType == irr::EET_JOYSTICK_INPUT_EVENT) { + /* TODO add a check like: + if (event.JoystickEvent != joystick_we_listen_for) + return false; + */ + bool handled = m_joystick->handleEvent(event.JoystickEvent); + if (handled) { + if (m_joystick->wasKeyDown(KeyType::ESC)) { + tryClose(); + } else if (m_joystick->wasKeyDown(KeyType::JUMP)) { + if (m_allowclose) { + acceptInput(quit_mode_accept); + quitMenu(); + } + } + } + return handled; + } + return false; } @@ -3114,19 +3281,24 @@ bool GUIFormSpecMenu::DoubleClickDetection(const SEvent event) return false; } +void GUIFormSpecMenu::tryClose() +{ + if (m_allowclose) { + doPause = false; + acceptInput(quit_mode_cancel); + quitMenu(); + } else { + m_text_dst->gotText(L"MenuQuit"); + } +} + bool GUIFormSpecMenu::OnEvent(const SEvent& event) { if (event.EventType==EET_KEY_INPUT_EVENT) { KeyPress kp(event.KeyInput); if (event.KeyInput.PressedDown && ( (kp == EscapeKey) || (kp == getKeySetting("keymap_inventory")) || (kp == CancelKey))) { - if (m_allowclose) { - doPause = false; - acceptInput(quit_mode_cancel); - quitMenu(); - } else { - m_text_dst->gotText(L"MenuQuit"); - } + tryClose(); return true; } else if (m_client != NULL && event.KeyInput.PressedDown && (kp == getKeySetting("keymap_screenshot"))) { @@ -3390,7 +3562,7 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event) // Check how many items can be moved move_amount = stack_from.count = MYMIN(move_amount, stack_from.count); - ItemStack leftover = stack_to.addItem(stack_from, m_gamedef->idef()); + ItemStack leftover = stack_to.addItem(stack_from, m_client->idef()); // If source stack cannot be added to destination stack at all, // they are swapped if ((leftover.count == stack_from.count) && @@ -3628,8 +3800,23 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event) if (event.GUIEvent.EventType == gui::EGET_EDITBOX_ENTER) { if (event.GUIEvent.Caller->getID() > 257) { + bool close_on_enter = true; + for (u32 i = 0; i < m_fields.size(); i++) { + FieldSpec &s = m_fields[i]; + if (s.ftype == f_Unknown && + s.fid == event.GUIEvent.Caller->getID()) { + current_field_enter_pending = s.fname; + UNORDERED_MAP::const_iterator it = + field_close_on_enter.find(s.fname); + if (it != field_close_on_enter.end()) + close_on_enter = (*it).second; + + break; + } + } - if (m_allowclose) { + if (m_allowclose && close_on_enter) { + current_keys_pending.key_enter = true; acceptInput(quit_mode_accept); quitMenu(); } else {