aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordarkrose <lisa@ltmnet.com>2012-07-16 02:19:38 +1000
committerPerttu Ahola <celeron55@gmail.com>2012-07-22 17:40:41 +0300
commit506203345ba2795aa0af68a434f4b77cf50e664a (patch)
tree51e168ed612bb0bcb7f2e0e2e77242e50bd8e855 /src
parentc259f7c8bd67e38c7be19a90c5113dbf8fd13670 (diff)
downloadminetest-506203345ba2795aa0af68a434f4b77cf50e664a.tar.gz
minetest-506203345ba2795aa0af68a434f4b77cf50e664a.tar.bz2
minetest-506203345ba2795aa0af68a434f4b77cf50e664a.zip
Implement formspec
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt2
-rw-r--r--src/content_nodemeta.cpp8
-rw-r--r--src/game.cpp36
-rw-r--r--src/guiFormSpecMenu.cpp (renamed from src/guiInventoryMenu.cpp)351
-rw-r--r--src/guiFormSpecMenu.h (renamed from src/guiInventoryMenu.h)49
-rw-r--r--src/guiTextInputMenu.h7
-rw-r--r--src/nodemetadata.h9
7 files changed, 406 insertions, 56 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 3e9f6d357..a0276cfaa 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -251,7 +251,7 @@ set(minetest_SRCS
guiKeyChangeMenu.cpp
guiMessageMenu.cpp
guiTextInputMenu.cpp
- guiInventoryMenu.cpp
+ guiFormSpecMenu.cpp
guiPauseMenu.cpp
guiPasswordChange.cpp
guiDeathScreen.cpp
diff --git a/src/content_nodemeta.cpp b/src/content_nodemeta.cpp
index 12c8aa426..0e4c3dd75 100644
--- a/src/content_nodemeta.cpp
+++ b/src/content_nodemeta.cpp
@@ -63,7 +63,7 @@ static bool content_nodemeta_deserialize_legacy_body(
//meta->setString("infotext","\"${text}\"");
meta->setString("infotext",
std::string("\"") + meta->getString("text") + "\"");
- meta->setString("formspec","hack:sign_text_input");
+ meta->setString("formspec","field[text;;${text}]");
return false;
}
else if(id == NODEMETA_CHEST) // ChestNodeMetadata
@@ -77,7 +77,7 @@ static bool content_nodemeta_deserialize_legacy_body(
}
assert(inv->getList("main") && !inv->getList("0"));
- meta->setString("formspec","invsize[8,9;]"
+ meta->setString("formspec","size[8,9]"
"list[current_name;main;0,0;8,4;]"
"list[current_player;main;0,5;8,4;]");
return false;
@@ -94,7 +94,7 @@ static bool content_nodemeta_deserialize_legacy_body(
}
assert(inv->getList("main") && !inv->getList("0"));
- meta->setString("formspec","invsize[8,9;]"
+ meta->setString("formspec","size[8,9]"
"list[current_name;main;0,0;8,4;]"
"list[current_player;main;0,5;8,4;]");
return false;
@@ -115,7 +115,7 @@ static bool content_nodemeta_deserialize_legacy_body(
is>>temp;
meta->setString("src_time", ftos((float)temp/10));
- meta->setString("formspec","invsize[8,9;]"
+ meta->setString("formspec","size[8,9]"
"list[current_name;fuel;2,3;1,1;]"
"list[current_name;src;2,1;1,1;]"
"list[current_name;dst;5,1;2,2;]"
diff --git a/src/game.cpp b/src/game.cpp
index 347dbf44b..3ba90789a 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -28,7 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "server.h"
#include "guiPauseMenu.h"
#include "guiPasswordChange.h"
-#include "guiInventoryMenu.h"
+#include "guiFormSpecMenu.h"
#include "guiTextInputMenu.h"
#include "guiDeathScreen.h"
#include "tool.h"
@@ -77,6 +77,10 @@ struct TextDestChat : public TextDest
{
m_client->typeChatMessage(text);
}
+ void gotText(std::map<std::string, std::string> fields)
+ {
+ m_client->typeChatMessage(narrow_to_wide(fields["text"]));
+ }
Client *m_client;
};
@@ -88,15 +92,20 @@ struct TextDestNodeMetadata : public TextDest
m_p = p;
m_client = client;
}
+ // This is deprecated I guess? -celeron55
void gotText(std::wstring text)
{
std::string ntext = wide_to_narrow(text);
- infostream<<"Changing text of a sign node: "
- <<ntext<<std::endl;
+ infostream<<"Submitting 'text' field of node at ("<<m_p.X<<","
+ <<m_p.Y<<","<<m_p.Z<<"): "<<ntext<<std::endl;
std::map<std::string, std::string> fields;
fields["text"] = ntext;
m_client->sendNodemetaFields(m_p, "", fields);
}
+ void gotText(std::map<std::string, std::string> fields)
+ {
+ m_client->sendNodemetaFields(m_p, "", fields);
+ }
v3s16 m_p;
Client *m_client;
@@ -139,6 +148,13 @@ public:
return "";
return meta->getString("formspec");
}
+ std::string resolveText(std::string str)
+ {
+ NodeMetadata *meta = m_map->getNodeMetadata(m_p);
+ if(!meta)
+ return str;
+ return meta->resolveString(str);
+ }
ClientMap *m_map;
v3s16 m_p;
@@ -1479,8 +1495,8 @@ void the_game(
infostream<<"the_game: "
<<"Launching inventory"<<std::endl;
- GUIInventoryMenu *menu =
- new GUIInventoryMenu(guienv, guiroot, -1,
+ GUIFormSpecMenu *menu =
+ new GUIFormSpecMenu(guienv, guiroot, -1,
&g_menumgr,
&client, gamedef);
@@ -1490,7 +1506,7 @@ void the_game(
PlayerInventoryFormSource *src = new PlayerInventoryFormSource(&client);
assert(src);
menu->setFormSpec(src->getForm(), inventoryloc);
- menu->setFormSource(new PlayerInventoryFormSource(&client));
+ menu->setFormSource(src);
menu->drop();
}
else if(input->wasKeyDown(EscapeKey))
@@ -2219,7 +2235,8 @@ void the_game(
{
infostream<<"Ground right-clicked"<<std::endl;
- // sign special case, at least until formspec is properly implemented
+ // Sign special case, at least until formspec is properly implemented.
+ // Deprecated?
if(meta && meta->getString("formspec") == "hack:sign_text_input" && !random_input)
{
infostream<<"Launching metadata text input"<<std::endl;
@@ -2244,14 +2261,15 @@ void the_game(
/* Create menu */
- GUIInventoryMenu *menu =
- new GUIInventoryMenu(guienv, guiroot, -1,
+ GUIFormSpecMenu *menu =
+ new GUIFormSpecMenu(guienv, guiroot, -1,
&g_menumgr,
&client, gamedef);
menu->setFormSpec(meta->getString("formspec"),
inventoryloc);
menu->setFormSource(new NodeMetadataFormSource(
&client.getEnv().getClientMap(), nodepos));
+ menu->setTextDest(new TextDestNodeMetadata(nodepos, &client));
menu->drop();
}
// Otherwise report right click to server
diff --git a/src/guiInventoryMenu.cpp b/src/guiFormSpecMenu.cpp
index f60c5b455..02a4fcaad 100644
--- a/src/guiInventoryMenu.cpp
+++ b/src/guiFormSpecMenu.cpp
@@ -18,7 +18,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
*/
-#include "guiInventoryMenu.h"
+#include "guiFormSpecMenu.h"
#include "constants.h"
#include "gamedef.h"
#include "keycode.h"
@@ -33,6 +33,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "util/string.h"
#include "util/numeric.h"
+#include "gettext.h"
+
void drawItemStack(video::IVideoDriver *driver,
gui::IGUIFont *font,
const ItemStack &item,
@@ -120,10 +122,10 @@ void drawItemStack(video::IVideoDriver *driver,
}
/*
- GUIInventoryMenu
+ GUIFormSpecMenu
*/
-GUIInventoryMenu::GUIInventoryMenu(gui::IGUIEnvironment* env,
+GUIFormSpecMenu::GUIFormSpecMenu(gui::IGUIEnvironment* env,
gui::IGUIElement* parent, s32 id,
IMenuManager *menumgr,
InventoryManager *invmgr,
@@ -133,6 +135,7 @@ GUIInventoryMenu::GUIInventoryMenu(gui::IGUIEnvironment* env,
m_invmgr(invmgr),
m_gamedef(gamedef),
m_form_src(NULL),
+ m_text_dst(NULL),
m_selected_item(NULL),
m_selected_amount(0),
m_selected_dragging(false),
@@ -140,7 +143,7 @@ GUIInventoryMenu::GUIInventoryMenu(gui::IGUIEnvironment* env,
{
}
-GUIInventoryMenu::~GUIInventoryMenu()
+GUIFormSpecMenu::~GUIFormSpecMenu()
{
removeChildren();
@@ -148,7 +151,7 @@ GUIInventoryMenu::~GUIInventoryMenu()
delete m_form_src;
}
-void GUIInventoryMenu::removeChildren()
+void GUIFormSpecMenu::removeChildren()
{
const core::list<gui::IGUIElement*> &children = getChildren();
core::list<gui::IGUIElement*> children_copy;
@@ -175,7 +178,7 @@ void GUIInventoryMenu::removeChildren()
}
}
-void GUIInventoryMenu::regenerateGui(v2u32 screensize)
+void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
{
// Remove children
removeChildren();
@@ -183,24 +186,38 @@ void GUIInventoryMenu::regenerateGui(v2u32 screensize)
v2s32 size(100,100);
s32 helptext_h = 15;
core::rect<s32> rect;
+
+ // Base position of contents of form
v2s32 basepos = getBasePos();
+ // State of basepos, 0 = not set, 1= set by formspec, 2 = set by size[] element
+ // Used to adjust form size automatically if needed
+ // A proceed button is added if there is no size[] element
+ int bp_set = 0;
/* Convert m_init_draw_spec to m_inventorylists */
m_inventorylists.clear();
m_images.clear();
+ m_fields.clear();
Strfnd f(m_formspec_string);
while(f.atend() == false)
{
std::string type = trim(f.next("["));
- if(type == "invsize")
+ if(type == "invsize" || type == "size")
{
v2f invsize;
invsize.X = stof(f.next(","));
- invsize.Y = stof(f.next(";"));
- infostream<<"invsize ("<<invsize.X<<","<<invsize.Y<<")"<<std::endl;
- f.next("]");
+ if(type == "size")
+ {
+ invsize.Y = stof(f.next("]"));
+ }
+ else{
+ invsize.Y = stof(f.next(";"));
+ errorstream<<"WARNING: invsize is deprecated, use size"<<std::endl;
+ f.next("]");
+ }
+ infostream<<"size ("<<invsize.X<<","<<invsize.Y<<")"<<std::endl;
padding = v2s32(screensize.Y/40, screensize.Y/40);
spacing = v2s32(screensize.Y/12, screensize.Y/13);
@@ -218,6 +235,7 @@ void GUIInventoryMenu::regenerateGui(v2u32 screensize)
DesiredRect = rect;
recalculateAbsolutePosition(false);
basepos = getBasePos();
+ bp_set = 2;
}
else if(type == "list")
{
@@ -239,6 +257,8 @@ void GUIInventoryMenu::regenerateGui(v2u32 screensize)
<<", geom=("<<geom.X<<","<<geom.Y<<")"
<<std::endl;
f.next("]");
+ if(bp_set != 2)
+ errorstream<<"WARNING: invalid use of button without a size[] element"<<std::endl;
m_inventorylists.push_back(ListDrawSpec(loc, listname, pos, geom));
}
else if(type == "image")
@@ -254,8 +274,189 @@ void GUIInventoryMenu::regenerateGui(v2u32 screensize)
<<", pos=("<<pos.X<<","<<pos.Y<<")"
<<", geom=("<<geom.X<<","<<geom.Y<<")"
<<std::endl;
+ if(bp_set != 2)
+ errorstream<<"WARNING: invalid use of button without a size[] element"<<std::endl;
m_images.push_back(ImageDrawSpec(name, pos, geom));
}
+ else if(type == "field")
+ {
+ std::string fname = f.next(";");
+ std::string flabel = f.next(";");
+
+ if(fname.find(",") == std::string::npos && flabel.find(",") == std::string::npos)
+ {
+ if(!bp_set)
+ {
+ rect = core::rect<s32>(
+ screensize.X/2 - 580/2,
+ screensize.Y/2 - 300/2,
+ screensize.X/2 + 580/2,
+ screensize.Y/2 + 300/2
+ );
+ DesiredRect = rect;
+ recalculateAbsolutePosition(false);
+ basepos = getBasePos();
+ bp_set = 1;
+ }
+ else if(bp_set == 2)
+ errorstream<<"WARNING: invalid use of unpositioned field in inventory"<<std::endl;
+
+ v2s32 pos = basepos;
+ pos.Y = ((m_fields.size()+2)*60);
+ v2s32 size = DesiredRect.getSize();
+ rect = core::rect<s32>(size.X/2-150, pos.Y, (size.X/2-150)+300, pos.Y+30);
+ }
+ else
+ {
+ v2s32 pos;
+ pos.X = stof(fname.substr(0,fname.find(","))) * (float)spacing.X;
+ pos.Y = stof(fname.substr(fname.find(",")+1)) * (float)spacing.Y;
+ v2s32 geom;
+ geom.X = (stof(flabel.substr(0,flabel.find(","))) * (float)spacing.X)-(spacing.X-imgsize.X);
+ pos.Y += (stof(flabel.substr(flabel.find(",")+1)) * (float)imgsize.Y)/2;
+
+ rect = core::rect<s32>(pos.X, pos.Y-15, pos.X+geom.X, pos.Y+15);
+
+ fname = f.next(";");
+ flabel = f.next(";");
+ if(bp_set != 2)
+ errorstream<<"WARNING: invalid use of positioned field without a size[] element"<<std::endl;
+
+ }
+
+ std::string odefault = f.next("]");
+ std::string fdefault;
+
+ // fdefault may contain a variable reference, which
+ // needs to be resolved from the node metadata
+ if(m_form_src)
+ fdefault = m_form_src->resolveText(odefault);
+ else
+ fdefault = odefault;
+
+ FieldSpec spec = FieldSpec(
+ narrow_to_wide(fname.c_str()),
+ narrow_to_wide(flabel.c_str()),
+ narrow_to_wide(fdefault.c_str()),
+ 258+m_fields.size()
+ );
+
+ // three cases: field and no label, label and no field, label and field
+ if (flabel == "")
+ {
+ spec.send = true;
+ gui::IGUIElement *e = Environment->addEditBox(spec.fdefault.c_str(), rect, true, this, spec.fid);
+ Environment->setFocus(e);
+
+ irr::SEvent evt;
+ evt.EventType = EET_KEY_INPUT_EVENT;
+ evt.KeyInput.Key = KEY_END;
+ evt.KeyInput.PressedDown = true;
+ e->OnEvent(evt);
+ }
+ else if (fname == "")
+ {
+ // set 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);
+ }
+ else
+ {
+ spec.send = true;
+ gui::IGUIElement *e = Environment->addEditBox(spec.fdefault.c_str(), rect, true, this, spec.fid);
+ Environment->setFocus(e);
+ rect.UpperLeftCorner.Y -= 15;
+ rect.LowerRightCorner.Y -= 15;
+ Environment->addStaticText(spec.flabel.c_str(), rect, false, true, this, 0);
+
+ irr::SEvent evt;
+ evt.EventType = EET_KEY_INPUT_EVENT;
+ evt.KeyInput.Key = KEY_END;
+ evt.KeyInput.PressedDown = true;
+ e->OnEvent(evt);
+ }
+
+ m_fields.push_back(spec);
+ }
+ else if(type == "label")
+ {
+ v2s32 pos;
+ pos.X = stof(f.next(",")) * (float)spacing.X;
+ pos.Y = stof(f.next(";")) * (float)spacing.Y;
+
+ rect = core::rect<s32>(pos.X, pos.Y+((imgsize.Y/2)-15), pos.X+300, pos.Y+((imgsize.Y/2)+15));
+
+ std::string flabel = f.next("]");
+ if(bp_set != 2)
+ errorstream<<"WARNING: invalid use of label without a size[] element"<<std::endl;
+
+ FieldSpec spec = FieldSpec(
+ narrow_to_wide(""),
+ narrow_to_wide(flabel.c_str()),
+ narrow_to_wide(""),
+ 258+m_fields.size()
+ );
+ Environment->addStaticText(spec.flabel.c_str(), rect, false, true, this, spec.fid);
+ m_fields.push_back(spec);
+ }
+ else if(type == "button")
+ {
+ v2s32 pos;
+ pos.X = stof(f.next(",")) * (float)spacing.X;
+ pos.Y = stof(f.next(";")) * (float)spacing.Y;
+ v2s32 geom;
+ geom.X = (stof(f.next(",")) * (float)spacing.X)-(spacing.X-imgsize.X);
+ pos.Y += (stof(f.next(";")) * (float)imgsize.Y)/2;
+
+ rect = core::rect<s32>(pos.X, pos.Y-15, pos.X+geom.X, pos.Y+15);
+
+ std::string fname = f.next(";");
+ std::string flabel = f.next("]");
+ if(bp_set != 2)
+ errorstream<<"WARNING: invalid use of button without a size[] element"<<std::endl;
+
+ FieldSpec spec = FieldSpec(
+ narrow_to_wide(fname.c_str()),
+ narrow_to_wide(flabel.c_str()),
+ narrow_to_wide(""),
+ 258+m_fields.size()
+ );
+ spec.is_button = true;
+ Environment->addButton(rect, this, spec.fid, spec.flabel.c_str());
+ m_fields.push_back(spec);
+ }
+ else if(type == "image_button")
+ {
+ v2s32 pos;
+ pos.X = stof(f.next(",")) * (float)spacing.X;
+ pos.Y = stof(f.next(";")) * (float)spacing.Y;
+ v2s32 geom;
+ geom.X = (stof(f.next(",")) * (float)spacing.X)-(spacing.X-imgsize.X);
+ geom.Y = (stof(f.next(";")) * (float)spacing.Y)-(spacing.Y-imgsize.Y);
+
+ rect = core::rect<s32>(pos.X, pos.Y, pos.X+geom.X, pos.Y+geom.Y);
+
+ std::string fimage = f.next(";");
+ std::string fname = f.next(";");
+ std::string flabel = f.next("]");
+ if(bp_set != 2)
+ errorstream<<"WARNING: invalid use of image_button without a size[] element"<<std::endl;
+
+ FieldSpec spec = FieldSpec(
+ narrow_to_wide(fname.c_str()),
+ narrow_to_wide(flabel.c_str()),
+ narrow_to_wide(fimage.c_str()),
+ 258+m_fields.size()
+ );
+ spec.is_button = true;
+
+ video::ITexture *texture = m_gamedef->tsrc()->getTextureRaw(fimage);
+ gui::IGUIButton *e = Environment->addButton(rect, this, spec.fid, spec.flabel.c_str());
+ e->setImage(texture);
+ e->setPressedImage(texture);
+ e->setScaleImage(true);
+
+ m_fields.push_back(spec);
+ }
else
{
// Ignore others
@@ -265,16 +466,44 @@ void GUIInventoryMenu::regenerateGui(v2u32 screensize)
}
}
- // Add children
+ // If there's inventory, put the usage string at the bottom
+ if (m_inventorylists.size())
{
+ changeCtype("");
core::rect<s32> rect(0, 0, size.X-padding.X*2, helptext_h);
rect = rect + v2s32(size.X/2 - rect.getWidth()/2,
size.Y-rect.getHeight()-5);
- const wchar_t *text =
- L"Left click: Move all items, Right click: Move single item";
+ const wchar_t *text = wgettext("Left click: Move all items, Right click: Move single item");
Environment->addStaticText(text, rect, false, true, this, 256);
+ changeCtype("C");
+ }
+ // If there's fields, add a Proceed button
+ if (m_fields.size() && bp_set != 2)
+ {
+ // if the size wasn't set by an invsize[] or size[] adjust it now to fit all the fields
+ rect = core::rect<s32>(
+ screensize.X/2 - 580/2,
+ screensize.Y/2 - 300/2,
+ screensize.X/2 + 580/2,
+ screensize.Y/2 + 240/2+(m_fields.size()*60)
+ );
+ DesiredRect = rect;
+ recalculateAbsolutePosition(false);
+ basepos = getBasePos();
- // Add tooltip
+ changeCtype("");
+ {
+ v2s32 pos = basepos;
+ pos.Y = ((m_fields.size()+2)*60);
+
+ v2s32 size = DesiredRect.getSize();
+ rect = core::rect<s32>(size.X/2-70, pos.Y, (size.X/2-70)+140, pos.Y+30);
+ Environment->addButton(rect, this, 257, wgettext("Proceed"));
+ }
+ changeCtype("C");
+ }
+ // Add tooltip
+ {
// Note: parent != this so that the tooltip isn't clipped by the menu rectangle
m_tooltip_element = Environment->addStaticText(L"",core::rect<s32>(0,0,110,18));
m_tooltip_element->enableOverrideColor(true);
@@ -287,7 +516,7 @@ void GUIInventoryMenu::regenerateGui(v2u32 screensize)
}
}
-GUIInventoryMenu::ItemSpec GUIInventoryMenu::getItemAtPos(v2s32 p) const
+GUIFormSpecMenu::ItemSpec GUIFormSpecMenu::getItemAtPos(v2s32 p) const
{
core::rect<s32> imgrect(0,0,imgsize.X,imgsize.Y);
@@ -311,7 +540,7 @@ GUIInventoryMenu::ItemSpec GUIInventoryMenu::getItemAtPos(v2s32 p) const
return ItemSpec(InventoryLocation(), "", -1);
}
-void GUIInventoryMenu::drawList(const ListDrawSpec &s, int phase)
+void GUIFormSpecMenu::drawList(const ListDrawSpec &s, int phase)
{
video::IVideoDriver* driver = Environment->getVideoDriver();
@@ -323,7 +552,7 @@ void GUIInventoryMenu::drawList(const ListDrawSpec &s, int phase)
Inventory *inv = m_invmgr->getInventory(s.inventoryloc);
if(!inv){
- infostream<<"GUIInventoryMenu::drawList(): WARNING: "
+ infostream<<"GUIFormSpecMenu::drawList(): WARNING: "
<<"The inventory location "
<<"\""<<s.inventoryloc.dump()<<"\" doesn't exist"
<<std::endl;
@@ -331,7 +560,7 @@ void GUIInventoryMenu::drawList(const ListDrawSpec &s, int phase)
}
InventoryList *ilist = inv->getList(s.listname);
if(!ilist){
- infostream<<"GUIInventoryMenu::drawList(): WARNING: "
+ infostream<<"GUIFormSpecMenu::drawList(): WARNING: "
<<"The inventory list \""<<s.listname<<"\" @ \""
<<s.inventoryloc.dump()<<"\" doesn't exist"
<<std::endl;
@@ -404,7 +633,7 @@ void GUIInventoryMenu::drawList(const ListDrawSpec &s, int phase)
}
}
-void GUIInventoryMenu::drawSelectedItem()
+void GUIFormSpecMenu::drawSelectedItem()
{
if(!m_selected_item)
return;
@@ -429,7 +658,7 @@ void GUIInventoryMenu::drawSelectedItem()
drawItemStack(driver, font, stack, rect, NULL, m_gamedef);
}
-void GUIInventoryMenu::drawMenu()
+void GUIFormSpecMenu::drawMenu()
{
if(m_form_src){
std::string newform = m_form_src->getForm();
@@ -491,7 +720,7 @@ void GUIInventoryMenu::drawMenu()
gui::IGUIElement::draw();
}
-void GUIInventoryMenu::updateSelectedItem()
+void GUIFormSpecMenu::updateSelectedItem()
{
// If the selected stack has become empty for some reason, deselect it.
// If the selected stack has become smaller, adjust m_selected_amount.
@@ -558,7 +787,38 @@ void GUIInventoryMenu::updateSelectedItem()
}
}
-bool GUIInventoryMenu::OnEvent(const SEvent& event)
+void GUIFormSpecMenu::acceptInput()
+{
+ if(m_text_dst)
+ {
+ std::map<std::string, std::string> fields;
+ gui::IGUIElement *e;
+ for(u32 i=0; i<m_fields.size(); i++)
+ {
+ const FieldSpec &s = m_fields[i];
+ if(s.send)
+ {
+ if(s.is_button)
+ {
+ fields[wide_to_narrow(s.fname.c_str())] = wide_to_narrow(s.flabel.c_str());
+ }
+ else
+ {
+ e = getElementFromId(s.fid);
+ if(e != NULL)
+ {
+ fields[wide_to_narrow(s.fname.c_str())] = wide_to_narrow(e->getText());
+ }
+ }
+ }
+ }
+ m_text_dst->gotText(fields);
+ delete m_text_dst;
+ m_text_dst = NULL;
+ }
+}
+
+bool GUIFormSpecMenu::OnEvent(const SEvent& event)
{
if(event.EventType==EET_KEY_INPUT_EVENT)
{
@@ -569,6 +829,12 @@ bool GUIInventoryMenu::OnEvent(const SEvent& event)
quitMenu();
return true;
}
+ if(event.KeyInput.Key==KEY_RETURN && event.KeyInput.PressedDown)
+ {
+ acceptInput();
+ quitMenu();
+ return true;
+ }
}
if(event.EventType==EET_MOUSE_INPUT_EVENT
&& event.MouseInput.Event == EMIE_MOUSE_MOVED)
@@ -860,7 +1126,7 @@ bool GUIInventoryMenu::OnEvent(const SEvent& event)
{
if(!canTakeFocus(event.GUIEvent.Element))
{
- infostream<<"GUIInventoryMenu: Not allowing focus change."
+ infostream<<"GUIFormSpecMenu: Not allowing focus change."
<<std::endl;
// Returning true disables focus change
return true;
@@ -868,15 +1134,38 @@ bool GUIInventoryMenu::OnEvent(const SEvent& event)
}
if(event.GUIEvent.EventType==gui::EGET_BUTTON_CLICKED)
{
- /*switch(event.GUIEvent.Caller->getID())
+ switch(event.GUIEvent.Caller->getID())
{
- case 256: // continue
- setVisible(false);
- break;
- case 257: // exit
- dev->closeDevice();
- break;
- }*/
+ case 257:
+ acceptInput();
+ quitMenu();
+ // quitMenu deallocates menu
+ return true;
+ }
+ // find the element that was clicked
+ for(u32 i=0; i<m_fields.size(); i++)
+ {
+ FieldSpec &s = m_fields[i];
+ // if its a button, set the send field so
+ // lua knows which button was pressed
+ if (s.is_button && s.fid == event.GUIEvent.Caller->getID())
+ {
+ s.send = true;
+ acceptInput();
+ quitMenu();
+ return true;
+ }
+ }
+ }
+ if(event.GUIEvent.EventType==gui::EGET_EDITBOX_ENTER)
+ {
+ if(event.GUIEvent.Caller->getID() > 257)
+ {
+ acceptInput();
+ quitMenu();
+ // quitMenu deallocates menu
+ return true;
+ }
}
}
diff --git a/src/guiInventoryMenu.h b/src/guiFormSpecMenu.h
index 5613db356..a60629153 100644
--- a/src/guiInventoryMenu.h
+++ b/src/guiFormSpecMenu.h
@@ -29,11 +29,21 @@ with this program; if not, write to the Free Software Foundation, Inc.,
class IGameDef;
class InventoryManager;
+struct TextDest
+{
+ virtual ~TextDest() {};
+ // This is deprecated I guess? -celeron55
+ virtual void gotText(std::wstring text) = 0;
+ virtual void gotText(std::map<std::string, std::string> fields) = 0;
+};
+
class IFormSource
{
public:
virtual ~IFormSource(){}
virtual std::string getForm() = 0;
+ // Fill in variables in field text
+ virtual std::string resolveText(std::string str){ return str; }
};
void drawItemStack(video::IVideoDriver *driver,
@@ -43,7 +53,7 @@ void drawItemStack(video::IVideoDriver *driver,
const core::rect<s32> *clip,
IGameDef *gamedef);
-class GUIInventoryMenu : public GUIModalMenu
+class GUIFormSpecMenu : public GUIModalMenu
{
struct ItemSpec
{
@@ -106,15 +116,37 @@ class GUIInventoryMenu : public GUIModalMenu
v2s32 pos;
v2s32 geom;
};
+
+ struct FieldSpec
+ {
+ FieldSpec()
+ {
+ }
+ FieldSpec(const std::wstring name, const std::wstring label, const std::wstring fdeflt, int id):
+ fname(name),
+ flabel(label),
+ fdefault(fdeflt),
+ fid(id)
+ {
+ send = false;
+ is_button = false;
+ }
+ std::wstring fname;
+ std::wstring flabel;
+ std::wstring fdefault;
+ int fid;
+ bool send;
+ bool is_button;
+ };
public:
- GUIInventoryMenu(gui::IGUIEnvironment* env,
+ GUIFormSpecMenu(gui::IGUIEnvironment* env,
gui::IGUIElement* parent, s32 id,
IMenuManager *menumgr,
InventoryManager *invmgr,
IGameDef *gamedef
);
- ~GUIInventoryMenu();
+ ~GUIFormSpecMenu();
void setFormSpec(const std::string &formspec_string,
InventoryLocation current_inventory_location)
@@ -124,12 +156,18 @@ public:
regenerateGui(m_screensize_old);
}
- // form_src is deleted by this GUIInventoryMenu
+ // form_src is deleted by this GUIFormSpecMenu
void setFormSource(IFormSource *form_src)
{
m_form_src = form_src;
}
+ // text_dst is deleted by this GUIFormSpecMenu
+ void setTextDest(TextDest *text_dst)
+ {
+ m_text_dst = text_dst;
+ }
+
void removeChildren();
/*
Remove and re-add (or reposition) stuff
@@ -142,6 +180,7 @@ public:
void drawMenu();
void updateSelectedItem();
+ void acceptInput();
bool OnEvent(const SEvent& event);
protected:
@@ -160,9 +199,11 @@ protected:
std::string m_formspec_string;
InventoryLocation m_current_inventory_location;
IFormSource *m_form_src;
+ TextDest *m_text_dst;
core::array<ListDrawSpec> m_inventorylists;
core::array<ImageDrawSpec> m_images;
+ core::array<FieldSpec> m_fields;
ItemSpec *m_selected_item;
u32 m_selected_amount;
diff --git a/src/guiTextInputMenu.h b/src/guiTextInputMenu.h
index 76417894b..1a55525c9 100644
--- a/src/guiTextInputMenu.h
+++ b/src/guiTextInputMenu.h
@@ -22,14 +22,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "irrlichttypes_extrabloated.h"
#include "modalMenu.h"
+#include "guiFormSpecMenu.h"
#include <string>
-struct TextDest
-{
- virtual void gotText(std::wstring text) = 0;
- virtual ~TextDest() {};
-};
-
class GUITextInputMenu : public GUIModalMenu
{
public:
diff --git a/src/nodemetadata.h b/src/nodemetadata.h
index 24779a1ea..262b64d74 100644
--- a/src/nodemetadata.h
+++ b/src/nodemetadata.h
@@ -55,7 +55,7 @@ public:
i = m_stringvars.find(name);
if(i == m_stringvars.end())
return "";
- return i->second;
+ return resolveString(i->second);
}
void setString(const std::string &name, const std::string &var)
{
@@ -64,6 +64,13 @@ public:
else
m_stringvars[name] = var;
}
+ // support variable names in values
+ std::string resolveString(const std::string &str) const
+ {
+ if(str.substr(0,2) == "${" && str[str.length()-1] == '}')
+ return resolveString(getString(str.substr(2,str.length()-3)));
+ return str;
+ }
std::map<std::string, std::string> getStrings() const
{
return m_stringvars;