implement formspec - I seem to have done this before

This commit is contained in:
darkrose 2014-03-02 20:44:02 +10:00
parent 2d07060a27
commit 33320c800d
18 changed files with 1503 additions and 852 deletions

80
doc/formspec.txt Normal file
View File

@ -0,0 +1,80 @@
Formspec
--------
Formspec defines a menu. Currently not much else than inventories are
supported. It is a string, with a somewhat strange format.
Spaces and newlines can be inserted between the blocks, as is used in the
examples.
Examples:
- Chest:
size[8,9]
list[current_name;main;0,0;8,4;]
list[current_player;main;0,5;8,4;]
- Furnace:
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;]
list[current_player;main;0,5;8,4;]
Elements:
size[<W>,<H>]
^ Define the size of the menu in inventory slots
^ deprecated: invsize[<W>,<H>;]
list[<inventory location>;<list name>;<X>,<Y>;<W>,<H>;]
^ Show an inventory list
image[<X>,<Y>;<W>,<H>;<texture name>]
^ Show an image
^ Position and size units are inventory slots
field[<X>,<Y>;<W>,<H>;<name>;<label>;<default>]
^ Textual field; will be sent to server when a button is clicked
^ x and y position the field relative to the top left of the menu
^ w and h are the size of the field
^ fields are a set height, but will be vertically centred on h
^ Position and size units are inventory slots
^ name is the name of the field as returned in fields to on_receive_fields
^ label, if not blank, will be text printed on the top left above the field
^ default is the default value of the field
^ default may contain variable references such as '${text}' which
will fill the value from the metadata value 'text'
^ Note: no extra text or more than a single variable is supported ATM.
field[<name>;<label>;<default>]
^ as above but without position/size units
^ special field for creating simple forms, such as sign text input
^ must be used without a size[] element
^ a 'Write It' button will be added automatically
label[<X>,<Y>;<label>]
^ x and y work as per field
^ label is the text on the label
^ Position and size units are inventory slots
button[<X>,<Y>;<W>,<H>;<name>;<label>]
^ Clickable button. When clicked, fields will be sent.
^ x, y and name work as per field
^ w and h are the size of the button
^ label is the text on the button
^ Position and size units are inventory slots
image_button[<X>,<Y>;<W>,<H>;<texture name>;<name>;<label>]
^ x, y, w, h, and name work as per button
^ image is the filename of an image
^ Position and size units are inventory slots
button_exit[<X>,<Y>;<W>,<H>;<name>;<label>]
^ When clicked, fields will be sent and the form will quit.
image_button_exit[<X>,<Y>;<W>,<H>;<texture name>;<name>;<label>]
^ When clicked, fields will be sent and the form will quit.
Inventory location:
- "current_name": Selected node metadata
- "current_player": Player to whom the menu is shown
- "player:<name>": Any player
- "nodemeta:<X>,<Y>,<Z>": Any node metadata

View File

@ -162,7 +162,7 @@ set(minetest_SRCS
guiKeyChangeMenu.cpp
guiMessageMenu.cpp
guiTextInputMenu.cpp
guiInventoryMenu.cpp
guiFormSpecMenu.cpp
guiPauseMenu.cpp
guiPasswordChange.cpp
guiDeathScreen.cpp

View File

@ -1639,32 +1639,31 @@ void Client::clickActiveObject(u8 button, u16 id, u16 item_i)
Send(0, data, true);
}
void Client::sendSignNodeText(v3s16 p, std::string text)
void Client::sendNodemetaFields(v3s16 p, const std::string &formname,
const std::map<std::string, std::string> &fields)
{
/*
u16 command
v3s16 p
u16 textlen
textdata
*/
std::ostringstream os(std::ios_base::binary);
u8 buf[12];
// Write command
writeU16(buf, TOSERVER_SIGNNODETEXT);
writeU16(buf, TOSERVER_NODEMETA_FIELDS);
os.write((char*)buf, 2);
// Write p
writeV3S16(buf, p);
os.write((char*)buf, 6);
u16 textlen = text.size();
// Write text length
writeS16(buf, textlen);
os.write((char*)buf, 2);
os<<serializeString(formname);
// Write text
os.write((char*)text.c_str(), textlen);
// Write number of fields
writeU16(buf, fields.size());
os.write((char*)buf, 2);
for (std::map<std::string, std::string>::const_iterator i = fields.begin(); i != fields.end(); i++) {
const std::string &name = i->first;
const std::string &value = i->second;
os<<serializeString(name);
os<<serializeLongString(value);
}
// Make data buffer
std::string s = os.str();
@ -2018,6 +2017,41 @@ Inventory* Client::getInventory(InventoryContext *c, std::string id)
infostream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
return NULL;
}
Inventory* Client::getInventory(const InventoryLocation *loc)
{
switch(loc->type){
case InventoryLocation::UNDEFINED:
{}
break;
case InventoryLocation::CURRENT_PLAYER:
{
Player *player = m_env.getLocalPlayer();
assert(player != NULL);
return &player->inventory;
}
break;
case InventoryLocation::PLAYER:
{
Player *player = m_env.getPlayer(loc->name.c_str());
if(!player)
return NULL;
return &player->inventory;
}
break;
case InventoryLocation::NODEMETA:
{
NodeMetadata *meta = m_env.getMap().getNodeMetadata(loc->p);
if(!meta)
return NULL;
return meta->getInventory();
}
break;
default:
assert(0);
}
return NULL;
}
void Client::inventoryAction(InventoryAction *a)
{
sendInventoryAction(a);

View File

@ -195,7 +195,8 @@ public:
v3s16 nodepos_oversurface, u16 item);
void clickActiveObject(u8 button, u16 id, u16 item_i);
void sendSignNodeText(v3s16 p, std::string text);
void sendNodemetaFields(v3s16 p, const std::string &formname,
const std::map<std::string, std::string> &fields);
void sendInventoryAction(InventoryAction *a);
void sendChatMessage(const std::wstring &message);
void sendChangePassword(const std::wstring oldpassword,
@ -236,6 +237,7 @@ public:
InventoryContext *getInventoryContext();
Inventory* getInventory(InventoryContext *c, std::string id);
Inventory* getInventory(const InventoryLocation *loc);
void inventoryAction(InventoryAction *a);
// Gets closest object pointed by the shootline

View File

@ -356,6 +356,20 @@ enum ToServerCommand
/*
u16 TOSERVER_WANTCOOKIE
*/
TOSERVER_NODEMETA_FIELDS = 0x3b,
/*
u16 command
v3s16 p
u16 len
u8[len] form name (reserved for future use)
u16 number of fields
for each field:
u16 len
u8[len] field name
u32 len
u8[len] field value
*/
};
inline SharedBuffer<u8> makePacket_TOCLIENT_TIME_OF_DAY(u16 time)

View File

@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "content_mapnode.h"
#include "content_craft.h"
#include "log.h"
#include "player.h"
/*
SignNodeMetadata
@ -56,6 +57,10 @@ std::string SignNodeMetadata::infoText()
{
return std::string("\"")+m_text+"\"";
}
std::string SignNodeMetadata::getDrawSpecString()
{
return std::string("field[text;;") + m_text + "]";
}
/*
LockingSignNodeMetadata
@ -93,6 +98,16 @@ std::string LockingSignNodeMetadata::infoText()
{
return std::string("(")+m_owner+") \""+m_text+"\"";
}
void LockingSignNodeMetadata::receiveFields(std::string formname, std::map<std::string, std::string> fields, Player *player)
{
if (getOwner() != player->getName())
return;
m_text = fields["text"];
}
std::string LockingSignNodeMetadata::getDrawSpecString()
{
return std::string("field[text;;") + m_text + "]";
}
/*
ChestNodeMetadata
@ -148,10 +163,10 @@ bool ChestNodeMetadata::nodeRemovalDisabled()
return false;
return true;
}
std::string ChestNodeMetadata::getInventoryDrawSpecString()
std::string ChestNodeMetadata::getDrawSpecString()
{
return
"invsize[8,9;]"
"size[8,9]"
"list[current_name;0;0,0;8,4;]"
"list[current_player;main;0,5;8,4;]";
}
@ -212,10 +227,10 @@ bool LockingChestNodeMetadata::nodeRemovalDisabled()
return false;
return true;
}
std::string LockingChestNodeMetadata::getInventoryDrawSpecString()
std::string LockingChestNodeMetadata::getDrawSpecString()
{
return
"invsize[8,9;]"
"size[8,9]"
"list[current_name;0;0,0;8,4;]"
"list[current_player;main;0,5;8,4;]";
}
@ -504,10 +519,10 @@ bool FurnaceNodeMetadata::step(float dtime, v3s16 pos, ServerEnvironment *env)
}
return changed;
}
std::string FurnaceNodeMetadata::getInventoryDrawSpecString()
std::string FurnaceNodeMetadata::getDrawSpecString()
{
return
"invsize[8,9;]"
"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;]"
@ -742,10 +757,10 @@ bool LockingFurnaceNodeMetadata::step(float dtime, v3s16 pos, ServerEnvironment
}
return changed;
}
std::string LockingFurnaceNodeMetadata::getInventoryDrawSpecString()
std::string LockingFurnaceNodeMetadata::getDrawSpecString()
{
return
"invsize[8,9;]"
"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;]"
@ -878,10 +893,10 @@ void IncineratorNodeMetadata::inventoryModified()
{
infostream<<"Incinerator inventory modification callback"<<std::endl;
}
std::string IncineratorNodeMetadata::getInventoryDrawSpecString()
std::string IncineratorNodeMetadata::getDrawSpecString()
{
return
"invsize[8,7;]"
"size[8,7]"
"list[current_name;fuel;4,1;1,1;]"
"list[current_player;main;0,3;8,4;]";
}
@ -994,10 +1009,10 @@ bool CraftGuideNodeMetadata::step(float dtime, v3s16 pos, ServerEnvironment *env
return true;
}
std::string CraftGuideNodeMetadata::getInventoryDrawSpecString()
std::string CraftGuideNodeMetadata::getDrawSpecString()
{
return
"invsize[22,15;]"
"size[22,15]"
"list[current_name;list;4,1;17,13;]"
"list[current_name;recipe;0,3;3,3;]"
"list[current_name;result;1,7;1,1;]";

View File

@ -39,6 +39,11 @@ public:
std::string getText(){ return m_text; }
void setText(std::string t){ m_text = t; }
virtual void receiveFields(std::string formname, std::map<std::string, std::string> fields, Player *player)
{
m_text = fields["text"];
}
virtual std::string getDrawSpecString();
private:
std::string m_text;
@ -63,6 +68,8 @@ public:
std::string getText(){ return m_text; }
void setText(std::string t){ m_text = t; }
virtual void receiveFields(std::string formname, std::map<std::string, std::string> fields, Player *player);
virtual std::string getDrawSpecString();
private:
std::string m_text;
@ -82,7 +89,7 @@ public:
virtual std::string infoText();
virtual Inventory* getInventory() {return m_inventory;}
virtual bool nodeRemovalDisabled();
virtual std::string getInventoryDrawSpecString();
virtual std::string getDrawSpecString();
private:
Inventory *m_inventory;
@ -101,7 +108,7 @@ public:
virtual std::string infoText();
virtual Inventory* getInventory() {return m_inventory;}
virtual bool nodeRemovalDisabled();
virtual std::string getInventoryDrawSpecString();
virtual std::string getDrawSpecString();
virtual std::string getOwner(){ return m_owner; }
virtual void setOwner(std::string t){ m_owner = t; }
@ -166,7 +173,7 @@ public:
virtual void inventoryModified();
virtual bool step(float dtime, v3s16 pos, ServerEnvironment *env);
virtual bool nodeRemovalDisabled();
virtual std::string getInventoryDrawSpecString();
virtual std::string getDrawSpecString();
private:
Inventory *m_inventory;
@ -192,7 +199,7 @@ public:
virtual void inventoryModified();
virtual bool step(float dtime, v3s16 pos, ServerEnvironment *env);
virtual bool nodeRemovalDisabled();
virtual std::string getInventoryDrawSpecString();
virtual std::string getDrawSpecString();
virtual std::string getOwner(){ return m_owner; }
virtual void setOwner(std::string t){ m_owner = t; }
@ -260,7 +267,7 @@ public:
virtual Inventory* getInventory() {return m_inventory;}
virtual void inventoryModified();
virtual bool nodeRemovalDisabled();
virtual std::string getInventoryDrawSpecString();
virtual std::string getDrawSpecString();
private:
Inventory *m_inventory;
@ -281,7 +288,7 @@ public:
virtual bool nodeRemovalDisabled();
virtual void inventoryModified();
virtual bool step(float dtime, v3s16 pos, ServerEnvironment *env);
virtual std::string getInventoryDrawSpecString();
virtual std::string getDrawSpecString();
private:
Inventory *m_inventory;

View File

@ -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 "config.h"
@ -111,22 +111,34 @@ struct TextDestChat : public TextDest
m_client->addChatMessage(text);
}
void gotText(std::map<std::string, std::string> fields)
{
gotText(narrow_to_wide(fields["text"]));
}
Client *m_client;
};
struct TextDestSignNode : public TextDest
struct TextDestNodeMetadata : public TextDest
{
TextDestSignNode(v3s16 p, Client *client)
TextDestNodeMetadata(v3s16 p, Client *client)
{
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;
m_client->sendSignNodeText(m_p, ntext);
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;
@ -153,6 +165,53 @@ private:
Client *m_client;
};
/* Form update callback */
class NodeMetadataFormSource: public IFormSource
{
public:
NodeMetadataFormSource(ClientMap *map, v3s16 p):
m_map(map),
m_p(p)
{
}
std::string getForm()
{
NodeMetadata *meta = m_map->getNodeMetadata(m_p);
if (!meta)
return "";
return meta->getDrawSpecString();
}
NodeMetadata *getMeta()
{
return m_map->getNodeMetadata(m_p);
}
ClientMap *m_map;
v3s16 m_p;
};
class PlayerInventoryFormSource: public IFormSource
{
public:
PlayerInventoryFormSource(Client *client):
m_client(client)
{
}
std::string getForm()
{
return
"size[8,7]"
"list[current_player;main;0,3;8,4;]"
"list[current_player;craft;2,0;3,3;]"
"list[current_player;craftresult;6,1;1,1;]";
}
Client *m_client;
};
/*
Hotbar draw routine
*/
@ -1207,26 +1266,34 @@ void the_game(
infostream<<"the_game: "
<<"Launching inventory"<<std::endl;
GUIInventoryMenu *menu =
new GUIInventoryMenu(guienv, guiroot, -1,
&g_menumgr, v2s16(8,7),
client.getInventoryContext(),
GUIFormSpecMenu *menu =
new GUIFormSpecMenu(guienv, guiroot, -1,
&g_menumgr,
&client);
core::array<GUIInventoryMenu::DrawSpec> draw_spec;
draw_spec.push_back(GUIInventoryMenu::DrawSpec(
"list", "current_player", "main",
v2s32(0, 3), v2s32(8, 4)));
draw_spec.push_back(GUIInventoryMenu::DrawSpec(
"list", "current_player", "craft",
v2s32(2, 0), v2s32(3, 3)));
draw_spec.push_back(GUIInventoryMenu::DrawSpec(
"list", "current_player", "craftresult",
v2s32(6, 1), v2s32(1, 1)));
menu->setDrawSpec(draw_spec);
InventoryLocation inventoryloc;
inventoryloc.setCurrentPlayer();
PlayerInventoryFormSource *src = new PlayerInventoryFormSource(&client);
assert(src);
menu->setFormSpec(src->getForm(), inventoryloc);
menu->setFormSource(src);
menu->drop();
//core::array<GUIInventoryMenu::DrawSpec> draw_spec;
//draw_spec.push_back(GUIInventoryMenu::DrawSpec(
//"list", "current_player", "main",
//v2s32(0, 3), v2s32(8, 4)));
//draw_spec.push_back(GUIInventoryMenu::DrawSpec(
//"list", "current_player", "craft",
//v2s32(2, 0), v2s32(3, 3)));
//draw_spec.push_back(GUIInventoryMenu::DrawSpec(
//"list", "current_player", "craftresult",
//v2s32(6, 1), v2s32(1, 1)));
//menu->setDrawSpec(draw_spec);
//menu->drop();
}
else if(input->wasKeyDown(EscapeKey))
{
@ -1798,59 +1865,25 @@ void the_game(
infostream<<"Ground right-clicked"<<std::endl;
// If metadata provides an inventory view, activate it
if(meta && meta->getInventoryDrawSpecString() != "" && !random_input)
if(meta && meta->getDrawSpecString() != "" && !random_input)
{
infostream<<"Launching custom inventory view"<<std::endl;
/*
Construct the unique identification string of the node
*/
std::string current_name;
current_name += "nodemeta:";
current_name += itos(nodepos.X);
current_name += ",";
current_name += itos(nodepos.Y);
current_name += ",";
current_name += itos(nodepos.Z);
/*
Create menu
*/
InventoryLocation inventoryloc;
inventoryloc.setNodeMeta(nodepos);
core::array<GUIInventoryMenu::DrawSpec> draw_spec;
v2s16 invsize =
GUIInventoryMenu::makeDrawSpecArrayFromString(
draw_spec,
meta->getInventoryDrawSpecString(),
current_name);
/* Create menu */
GUIInventoryMenu *menu =
new GUIInventoryMenu(guienv, guiroot, -1,
&g_menumgr, invsize,
client.getInventoryContext(),
GUIFormSpecMenu *menu =
new GUIFormSpecMenu(guienv, guiroot, -1,
&g_menumgr,
&client);
menu->setDrawSpec(draw_spec);
menu->setFormSpec(meta->getDrawSpecString(), inventoryloc);
menu->setFormSource(new NodeMetadataFormSource(
&client.getEnv().getClientMap(), nodepos));
menu->setTextDest(new TextDestNodeMetadata(nodepos, &client));
menu->drop();
}else if (
meta
&& (
meta->typeId() == CONTENT_SIGN_WALL
|| meta->typeId() == CONTENT_LOCKABLE_SIGN_WALL
) && !random_input
) {
infostream<<"Sign node right-clicked"<<std::endl;
SignNodeMetadata *signmeta = (SignNodeMetadata*)meta;
// Get a new text for it
TextDest *dest = new TextDestSignNode(nodepos, &client);
std::wstring wtext =
narrow_to_wide(signmeta->getText());
(new GUITextInputMenu(guienv, guiroot, -1,
&g_menumgr, dest,
wtext))->drop();
}
else
{

822
src/guiFormSpecMenu.cpp Normal file
View File

@ -0,0 +1,822 @@
/*
Minetest-c55
Copyright (C) 2010 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 "common_irrlicht.h"
#include "inventory.h"
#include "utility.h"
#include "modalMenu.h"
#include "keycode.h"
#include "guiFormSpecMenu.h"
#include <IGUICheckBox.h>
#include <IGUIEditBox.h>
#include <IGUIButton.h>
#include <IGUIStaticText.h>
#include <IGUIFont.h>
#include "constants.h"
#include "log.h"
#include "tile.h" // ITextureSource
#include "path.h"
#include "gettext.h"
void drawInventoryItem(video::IVideoDriver *driver,
gui::IGUIFont *font,
InventoryItem *item,
core::rect<s32> rect,
const core::rect<s32> *clip)
{
if(item == NULL)
return;
video::ITexture *texture = NULL;
texture = item->getImage();
if(texture != NULL)
{
const video::SColor color(255,255,255,255);
const video::SColor colors[] = {color,color,color,color};
driver->draw2DImage(texture, rect,
core::rect<s32>(core::position2d<s32>(0,0),
core::dimension2di(texture->getOriginalSize())),
clip, colors, true);
}
else
{
video::SColor bgcolor(255,50,50,128);
driver->draw2DRectangle(bgcolor, rect, clip);
}
if(font != NULL)
{
std::string text = item->getText();
if(font && text != "")
{
v2u32 dim = font->getDimension(narrow_to_wide(text).c_str());
v2s32 sdim(dim.X,dim.Y);
core::rect<s32> rect2(
/*rect.UpperLeftCorner,
core::dimension2d<u32>(rect.getWidth(), 15)*/
rect.LowerRightCorner - sdim,
sdim
);
video::SColor bgcolor(128,0,0,0);
driver->draw2DRectangle(bgcolor, rect2, clip);
font->draw(text.c_str(), rect2,
video::SColor(255,255,255,255), false, false,
clip);
}
}
}
/*
GUIFormSpecMenu
*/
GUIFormSpecMenu::GUIFormSpecMenu(gui::IGUIEnvironment* env,
gui::IGUIElement* parent, s32 id,
IMenuManager *menumgr,
InventoryManager *invmgr
):
GUIModalMenu(env, parent, id, menumgr),
m_invmgr(invmgr),
m_form_src(NULL),
m_text_dst(NULL),
m_selected_item(NULL),
m_selected_amount(0),
m_selected_dragging(false),
m_tooltip_element(NULL)
{
}
GUIFormSpecMenu::~GUIFormSpecMenu()
{
removeChildren();
delete m_selected_item;
delete m_form_src;
delete m_text_dst;
}
void GUIFormSpecMenu::removeChildren()
{
const core::list<gui::IGUIElement*> &children = getChildren();
core::list<gui::IGUIElement*> children_copy;
for(core::list<gui::IGUIElement*>::ConstIterator
i = children.begin(); i != children.end(); i++)
{
children_copy.push_back(*i);
}
for(core::list<gui::IGUIElement*>::Iterator
i = children_copy.begin();
i != children_copy.end(); i++)
{
(*i)->remove();
}
/*{
gui::IGUIElement *e = getElementFromId(256);
if(e != NULL)
e->remove();
}*/
if(m_tooltip_element)
{
m_tooltip_element->remove();
m_tooltip_element = NULL;
}
}
void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
{
// Remove children
removeChildren();
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" || type == "size")
{
v2f invsize;
invsize.X = stof(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);
imgsize = v2s32(screensize.Y/15, screensize.Y/15);
size = v2s32(
padding.X*2+spacing.X*(invsize.X-1.0)+imgsize.X,
padding.Y*2+spacing.Y*(invsize.Y-1.0)+imgsize.Y + (helptext_h-5)
);
rect = core::rect<s32>(
screensize.X/2 - size.X/2,
screensize.Y/2 - size.Y/2,
screensize.X/2 + size.X/2,
screensize.Y/2 + size.Y/2
);
DesiredRect = rect;
recalculateAbsolutePosition(false);
basepos = getBasePos();
bp_set = 2;
}
else if(type == "list")
{
std::string name = f.next(";");
InventoryLocation loc;
if(name == "context" || name == "current_name")
loc = m_current_inventory_location;
else
loc.deSerialize(name);
std::string listname = f.next(";");
v2s32 pos = basepos;
pos.X += stof(f.next(",")) * (float)spacing.X;
pos.Y += stof(f.next(";")) * (float)spacing.Y;
v2s32 geom;
geom.X = stoi(f.next(","));
geom.Y = stoi(f.next(";"));
infostream<<"list inv="<<name<<", listname="<<listname
<<", pos=("<<pos.X<<","<<pos.Y<<")"
<<", geom=("<<geom.X<<","<<geom.Y<<")"
<<std::endl;
f.next("]");
if(bp_set != 2)
errorstream<<"WARNING: invalid use of list without a size[] element"<<std::endl;
m_inventorylists.push_back(ListDrawSpec(loc, listname, pos, geom));
}
else if(type == "image")
{
v2s32 pos = basepos;
pos.X += stof(f.next(",")) * (float)spacing.X;
pos.Y += stof(f.next(";")) * (float)spacing.Y;
v2s32 geom;
geom.X = stof(f.next(",")) * (float)imgsize.X;
geom.Y = stof(f.next(";")) * (float)imgsize.Y;
std::string name = f.next("]");
infostream<<"image name="<<name
<<", pos=("<<pos.X<<","<<pos.Y<<")"
<<", geom=("<<geom.X<<","<<geom.Y<<")"
<<std::endl;
if(bp_set != 2)
errorstream<<"WARNING: invalid use of image 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 - 160,
screensize.Y/2 - 60,
screensize.X/2 + 160,
screensize.Y/2 + 60
);
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()+1*50);
printf("%d\n",pos.Y);
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, false, 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, false, 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" || type == "button_exit")
{
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;
if (type == "button_exit")
spec.is_exit = true;
Environment->addButton(rect, this, spec.fid, spec.flabel.c_str());
m_fields.push_back(spec);
}
else if(type == "image_button" || type == "image_button_exit")
{
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;
if (type == "image_button_exit")
spec.is_exit = true;
video::ITexture *texture = Environment->getVideoDriver()->getTexture(getTexturePath(fimage).c_str());
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
std::string ts = f.next("]");
infostream<<"Unknown DrawSpec: type="<<type<<", data=\""<<ts<<"\""
<<std::endl;
}
}
// 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 = 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 - 160,
screensize.Y/2 - 60,
screensize.X/2 + 160,
screensize.Y/2 + 50+(m_fields.size()*50)
);
DesiredRect = rect;
recalculateAbsolutePosition(false);
basepos = getBasePos();
changeCtype("");
{
v2s32 pos = basepos;
pos.Y = ((m_fields.size()+1)*50);
v2s32 size = DesiredRect.getSize();
rect = core::rect<s32>(size.X/2-70, pos.Y, (size.X/2-70)+140, pos.Y+25);
Environment->addButton(rect, this, 257, wgettext("Write It"));
}
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);
m_tooltip_element->setBackgroundColor(video::SColor(140,30,30,50));
m_tooltip_element->setDrawBackground(true);
m_tooltip_element->setDrawBorder(true);
m_tooltip_element->setOverrideColor(video::SColor(255,255,255,255));
m_tooltip_element->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_CENTER);
m_tooltip_element->setWordWrap(false);
}
}
GUIFormSpecMenu::ItemSpec GUIFormSpecMenu::getItemAtPos(v2s32 p) const
{
core::rect<s32> imgrect(0,0,imgsize.X,imgsize.Y);
for(u32 i=0; i<m_inventorylists.size(); i++)
{
const ListDrawSpec &s = m_inventorylists[i];
for(s32 i=0; i<s.geom.X*s.geom.Y; i++)
{
s32 x = (i%s.geom.X) * spacing.X;
s32 y = (i/s.geom.X) * spacing.Y;
v2s32 p0(x,y);
core::rect<s32> rect = imgrect + s.pos + p0;
if(rect.isPointInside(p))
{
return ItemSpec(s.inventoryloc, s.listname, i);
}
}
}
return ItemSpec(InventoryLocation(), "", -1);
}
void GUIFormSpecMenu::drawList(const ListDrawSpec &s, int phase)
{
video::IVideoDriver* driver = Environment->getVideoDriver();
// Get font
gui::IGUIFont *font = NULL;
gui::IGUISkin* skin = Environment->getSkin();
if (skin)
font = skin->getFont();
Inventory *inv = m_invmgr->getInventory(&s.inventoryloc);
assert(inv);
InventoryList *ilist = inv->getList(s.listname);
core::rect<s32> imgrect(0,0,imgsize.X,imgsize.Y);
video::SColor bdcolor(245,60,60,80);
video::SColor hbcolor(240,255,0,0);
video::SColor bgcolor(240,30,30,50);
for (s32 i=0; i<s.geom.X*s.geom.Y; i++) {
s32 x = (i%s.geom.X) * spacing.X;
s32 y = (i/s.geom.X) * spacing.Y;
v2s32 p(x,y);
core::rect<s32> rect = imgrect + s.pos + p;
InventoryItem *item = NULL;
if (ilist)
item = ilist->getItem(i);
driver->draw2DRectangle(bgcolor, rect, &AbsoluteClippingRect);
if (m_selected_item != NULL && m_selected_item->listname == s.listname && m_selected_item->i == i) {
driver->draw2DRectangleOutline(rect, hbcolor);
}else{
driver->draw2DRectangleOutline(rect, bdcolor);
}
if (item) {
drawInventoryItem(driver, font, item, rect, &AbsoluteClippingRect);
if (rect.isPointInside(m_pointer)) {
std::string name = item->getGuiName();
if (name != "") {
m_tooltip_element->setVisible(true);
this->bringToFront(m_tooltip_element);
m_tooltip_element->setText(narrow_to_wide(name).c_str());
s32 tooltip_x = m_pointer.X + 15;
s32 tooltip_y = m_pointer.Y + 15;
s32 tooltip_width = m_tooltip_element->getTextWidth() + 14;
s32 tooltip_height = m_tooltip_element->getTextHeight() + 4;
m_tooltip_element->setRelativePosition(
core::rect<s32>(
core::position2d<s32>(tooltip_x, tooltip_y),
core::dimension2d<s32>(tooltip_width, tooltip_height)
)
);
}
}
}
}
}
void GUIFormSpecMenu::drawMenu()
{
if (m_form_src) {
std::string newform = m_form_src->getForm();
if (newform != m_formspec_string) {
m_formspec_string = newform;
regenerateGui(m_screensize_old);
}
}
gui::IGUISkin* skin = Environment->getSkin();
if (!skin)
return;
video::IVideoDriver* driver = Environment->getVideoDriver();
video::SColor bgtcolor(240,50,50,70);
video::SColor bgbcolor(240,30,30,50);
driver->draw2DRectangle(AbsoluteRect,bgtcolor, bgtcolor, bgbcolor, bgbcolor, &AbsoluteClippingRect);
video::SColor bdcolor(245,60,60,80);
driver->draw2DRectangleOutline(AbsoluteRect, bdcolor);
m_tooltip_element->setVisible(false);
/*
Draw items
Phase 0: Item slot rectangles
Phase 1: Item images; prepare tooltip
*/
for(u32 i=0; i<m_inventorylists.size(); i++)
{
drawList(m_inventorylists[i], 1);
}
for(u32 i=0; i<m_images.size(); i++)
{
const ImageDrawSpec &spec = m_images[i];
video::ITexture *texture = Environment->getVideoDriver()->getTexture(getTexturePath(spec.name).c_str());
// Image size on screen
core::rect<s32> imgrect(0, 0, spec.geom.X, spec.geom.Y);
// Image rectangle on screen
core::rect<s32> rect = imgrect + spec.pos;
const video::SColor color(255,255,255,255);
const video::SColor colors[] = {color,color,color,color};
driver->draw2DImage(texture, rect,
core::rect<s32>(core::position2d<s32>(0,0),
core::dimension2di(texture->getOriginalSize())),
NULL/*&AbsoluteClippingRect*/, colors, true);
}
/*
Call base class
*/
gui::IGUIElement::draw();
}
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);
}
}
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")))
{
m_tooltip_element->setVisible(false);
quitMenu();
return true;
}
if(event.KeyInput.Key==KEY_RETURN && event.KeyInput.PressedDown)
{
m_tooltip_element->setVisible(false);
acceptInput();
quitMenu();
return true;
}
}
if(event.EventType==EET_MOUSE_INPUT_EVENT) {
char amount = -1;
if(event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN)
amount = 0;
else if(event.MouseInput.Event == EMIE_RMOUSE_PRESSED_DOWN)
amount = 1;
else if(event.MouseInput.Event == EMIE_MMOUSE_PRESSED_DOWN)
amount = 10;
m_pointer.X = event.MouseInput.X;
m_pointer.Y = event.MouseInput.Y;
if(amount >= 0)
{
v2s32 p(event.MouseInput.X, event.MouseInput.Y);
//infostream<<"Mouse down at p=("<<p.X<<","<<p.Y<<")"<<std::endl;
ItemSpec s = getItemAtPos(p);
if(s.isValid())
{
if(m_selected_item)
{
Inventory *inv_from = m_invmgr->getInventory(&m_selected_item->inventoryloc);
Inventory *inv_to = m_invmgr->getInventory(&s.inventoryloc);
assert(inv_from);
assert(inv_to);
InventoryList *list_from =
inv_from->getList(m_selected_item->listname);
InventoryList *list_to =
inv_to->getList(s.listname);
if(list_from == NULL)
infostream<<"from list doesn't exist"<<std::endl;
if(list_to == NULL)
infostream<<"to list doesn't exist"<<std::endl;
// Indicates whether source slot completely empties
bool source_empties = false;
if(list_from && list_to
&& list_from->getItem(m_selected_item->i) != NULL)
{
infostream<<"Handing IACTION_MOVE to manager"<<std::endl;
IMoveAction *a = new IMoveAction();
a->count = amount;
a->from_inv = m_selected_item->inventoryloc.getName();
a->from_list = m_selected_item->listname;
a->from_i = m_selected_item->i;
a->to_inv = s.inventoryloc.getName();
a->to_list = s.listname;
a->to_i = s.i;
//ispec.actions->push_back(a);
m_invmgr->inventoryAction(a);
if(list_from->getItem(m_selected_item->i)->getCount()==1)
source_empties = true;
}
// Remove selection if target was left-clicked or source
// slot was emptied
if(amount == 0 || source_empties)
{
delete m_selected_item;
m_selected_item = NULL;
}
}
else
{
/*
Select if non-NULL
*/
Inventory *inv = m_invmgr->getInventory(&s.inventoryloc);
assert(inv);
InventoryList *list = inv->getList(s.listname);
if(list->getItem(s.i) != NULL)
{
m_selected_item = new ItemSpec(s);
}
}
}
else
{
if(m_selected_item)
{
delete m_selected_item;
m_selected_item = NULL;
}
}
}
}
if(event.EventType==EET_GUI_EVENT)
{
if(event.GUIEvent.EventType==gui::EGET_ELEMENT_FOCUS_LOST
&& isVisible())
{
if(!canTakeFocus(event.GUIEvent.Element))
{
infostream<<"GUIFormSpecMenu: Not allowing focus change."
<<std::endl;
// Returning true disables focus change
return true;
}
}
if(event.GUIEvent.EventType==gui::EGET_BUTTON_CLICKED)
{
switch(event.GUIEvent.Caller->getID())
{
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
// receiveFields knows which button was pressed
if (s.is_button && s.fid == event.GUIEvent.Caller->getID())
{
s.send = true;
acceptInput();
if (s.is_exit) {
quitMenu();
}else{
s.send = false;
}
return true;
}
}
}
if(event.GUIEvent.EventType==gui::EGET_EDITBOX_ENTER)
{
if(event.GUIEvent.Caller->getID() > 257)
{
acceptInput();
quitMenu();
// quitMenu deallocates menu
return true;
}
}
}
return Parent ? Parent->OnEvent(event) : false;
}

215
src/guiFormSpecMenu.h Normal file
View File

@ -0,0 +1,215 @@
/*
Minetest-c55
Copyright (C) 2010 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.
*/
#ifndef GUIINVENTORYMENU_HEADER
#define GUIINVENTORYMENU_HEADER
#include "common_irrlicht.h"
#include <IGUIFont.h>
#include "inventory.h"
#include "modalMenu.h"
#include "utility.h"
#include <map>
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 drawInventoryItem(video::IVideoDriver *driver,
gui::IGUIFont *font,
InventoryItem *item,
core::rect<s32> rect,
const core::rect<s32> *clip);
class GUIFormSpecMenu : public GUIModalMenu
{
struct ItemSpec
{
ItemSpec()
{
i = -1;
}
ItemSpec(const InventoryLocation &a_inventoryloc,
const std::string &a_listname,
s32 a_i)
{
inventoryloc = a_inventoryloc;
listname = a_listname;
i = a_i;
}
bool isValid() const
{
return i != -1;
}
InventoryLocation inventoryloc;
std::string listname;
s32 i;
};
struct ListDrawSpec
{
ListDrawSpec()
{
}
ListDrawSpec(const InventoryLocation &a_inventoryloc,
const std::string &a_listname,
v2s32 a_pos, v2s32 a_geom):
inventoryloc(a_inventoryloc),
listname(a_listname),
pos(a_pos),
geom(a_geom)
{
}
InventoryLocation inventoryloc;
std::string listname;
v2s32 pos;
v2s32 geom;
};
struct ImageDrawSpec
{
ImageDrawSpec()
{
}
ImageDrawSpec(const std::string &a_name,
v2s32 a_pos, v2s32 a_geom):
name(a_name),
pos(a_pos),
geom(a_geom)
{
}
std::string name;
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;
is_exit = false;
}
std::wstring fname;
std::wstring flabel;
std::wstring fdefault;
int fid;
bool send;
bool is_button;
bool is_exit;
};
public:
GUIFormSpecMenu(gui::IGUIEnvironment* env,
gui::IGUIElement* parent, s32 id,
IMenuManager *menumgr,
InventoryManager *invmgr
);
~GUIFormSpecMenu();
void setFormSpec(const std::string &formspec_string,
InventoryLocation current_inventory_location)
{
m_formspec_string = formspec_string;
m_current_inventory_location = current_inventory_location;
regenerateGui(m_screensize_old);
}
// 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
*/
void regenerateGui(v2u32 screensize);
ItemSpec getItemAtPos(v2s32 p) const;
void drawList(const ListDrawSpec &s, int phase);
void drawMenu();
void acceptInput();
bool OnEvent(const SEvent& event);
protected:
v2s32 getBasePos() const
{
return padding + AbsoluteRect.UpperLeftCorner;
}
v2s32 padding;
v2s32 spacing;
v2s32 imgsize;
InventoryManager *m_invmgr;
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;
bool m_selected_dragging;
v2s32 m_pointer;
gui::IGUIStaticText *m_tooltip_element;
};
#endif

View File

@ -1,527 +0,0 @@
/*
Minetest-c55
Copyright (C) 2010 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 General Public License as published by
the Free Software Foundation; either version 2 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 General Public License for more details.
You should have received a copy of the GNU 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 "guiInventoryMenu.h"
#include "constants.h"
#include "keycode.h"
#include "strfnd.h"
#include <IGUICheckBox.h>
#include <IGUIEditBox.h>
#include <IGUIButton.h>
#include <IGUIStaticText.h>
#include <IGUIFont.h>
#include "log.h"
void drawInventoryItem(video::IVideoDriver *driver,
gui::IGUIFont *font,
InventoryItem *item, core::rect<s32> rect,
const core::rect<s32> *clip)
{
if(item == NULL)
return;
video::ITexture *texture = NULL;
texture = item->getImage();
if(texture != NULL)
{
const video::SColor color(255,255,255,255);
const video::SColor colors[] = {color,color,color,color};
driver->draw2DImage(texture, rect,
core::rect<s32>(core::position2d<s32>(0,0),
core::dimension2di(texture->getOriginalSize())),
clip, colors, true);
}
else
{
video::SColor bgcolor(255,50,50,128);
driver->draw2DRectangle(bgcolor, rect, clip);
}
if(font != NULL)
{
std::string text = item->getText();
if(font && text != "")
{
v2u32 dim = font->getDimension(narrow_to_wide(text).c_str());
v2s32 sdim(dim.X,dim.Y);
core::rect<s32> rect2(
/*rect.UpperLeftCorner,
core::dimension2d<u32>(rect.getWidth(), 15)*/
rect.LowerRightCorner - sdim,
sdim
);
video::SColor bgcolor(128,0,0,0);
driver->draw2DRectangle(bgcolor, rect2, clip);
font->draw(text.c_str(), rect2,
video::SColor(255,255,255,255), false, false,
clip);
}
}
}
/*
GUIInventoryMenu
*/
GUIInventoryMenu::GUIInventoryMenu(gui::IGUIEnvironment* env,
gui::IGUIElement* parent, s32 id,
IMenuManager *menumgr,
v2s16 menu_size,
InventoryContext *c,
InventoryManager *invmgr
):
GUIModalMenu(env, parent, id, menumgr),
m_menu_size(menu_size),
m_c(c),
m_invmgr(invmgr),
m_pointer(0,0),
m_tooltip_element(NULL)
{
m_selected_item = NULL;
}
GUIInventoryMenu::~GUIInventoryMenu()
{
removeChildren();
if(m_selected_item)
delete m_selected_item;
}
void GUIInventoryMenu::removeChildren()
{
const core::list<gui::IGUIElement*> &children = getChildren();
core::list<gui::IGUIElement*> children_copy;
for(core::list<gui::IGUIElement*>::ConstIterator
i = children.begin(); i != children.end(); i++)
{
children_copy.push_back(*i);
}
for(core::list<gui::IGUIElement*>::Iterator
i = children_copy.begin();
i != children_copy.end(); i++)
{
(*i)->remove();
}
/*{
gui::IGUIElement *e = getElementFromId(256);
if(e != NULL)
e->remove();
}*/
}
void GUIInventoryMenu::regenerateGui(v2u32 screensize)
{
// Remove children
removeChildren();
padding = v2s32(screensize.Y/40, screensize.Y/40);
spacing = v2s32(screensize.Y/12, screensize.Y/13);
imgsize = v2s32(screensize.Y/15, screensize.Y/15);
s32 helptext_h = 15;
v2s32 size(
padding.X*2+spacing.X*(m_menu_size.X-1)+imgsize.X,
padding.Y*2+spacing.Y*(m_menu_size.Y-1)+imgsize.Y + helptext_h
);
core::rect<s32> rect(
screensize.X/2 - size.X/2,
screensize.Y/2 - size.Y/2,
screensize.X/2 + size.X/2,
screensize.Y/2 + size.Y/2
);
DesiredRect = rect;
recalculateAbsolutePosition(false);
v2s32 basepos = getBasePos();
m_draw_spec.clear();
for(u16 i=0; i<m_init_draw_spec.size(); i++)
{
DrawSpec &s = m_init_draw_spec[i];
if(s.type == "list")
{
m_draw_spec.push_back(ListDrawSpec(s.name, s.subname,
basepos + v2s32(spacing.X*s.pos.X, spacing.Y*s.pos.Y),
s.geom));
}
}
// Add children
{
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()-12);
const wchar_t *text =
L"Left click: Move all items, Right click: Move single item";
Environment->addStaticText(text, rect, false, true, this, 256);
}
// 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);
m_tooltip_element->setBackgroundColor(video::SColor(140,30,30,50));
m_tooltip_element->setDrawBackground(true);
m_tooltip_element->setDrawBorder(true);
m_tooltip_element->setOverrideColor(video::SColor(255,255,255,255));
m_tooltip_element->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_CENTER);
m_tooltip_element->setWordWrap(false);
}
}
GUIInventoryMenu::ItemSpec GUIInventoryMenu::getItemAtPos(v2s32 p) const
{
core::rect<s32> imgrect(0,0,imgsize.X,imgsize.Y);
for(u32 i=0; i<m_draw_spec.size(); i++)
{
const ListDrawSpec &s = m_draw_spec[i];
for(s32 i=0; i<s.geom.X*s.geom.Y; i++)
{
s32 x = (i%s.geom.X) * spacing.X;
s32 y = (i/s.geom.X) * spacing.Y;
v2s32 p0(x,y);
core::rect<s32> rect = imgrect + s.pos + p0;
if (rect.isPointInside(p)) {
return ItemSpec(s.inventoryname, s.listname, i);
}
}
}
return ItemSpec("", "", -1);
}
void GUIInventoryMenu::drawList(const ListDrawSpec &s)
{
video::IVideoDriver* driver = Environment->getVideoDriver();
// Get font
gui::IGUIFont *font = NULL;
gui::IGUISkin* skin = Environment->getSkin();
if (skin)
font = skin->getFont();
Inventory *inv = m_invmgr->getInventory(m_c, s.inventoryname);
assert(inv);
InventoryList *ilist = inv->getList(s.listname);
core::rect<s32> imgrect(0,0,imgsize.X,imgsize.Y);
video::SColor bdcolor(245,60,60,80);
video::SColor hbcolor(240,255,0,0);
video::SColor bgcolor(240,30,30,50);
for (s32 i=0; i<s.geom.X*s.geom.Y; i++) {
s32 x = (i%s.geom.X) * spacing.X;
s32 y = (i/s.geom.X) * spacing.Y;
v2s32 p(x,y);
core::rect<s32> rect = imgrect + s.pos + p;
InventoryItem *item = NULL;
if (ilist)
item = ilist->getItem(i);
driver->draw2DRectangle(bgcolor, rect, &AbsoluteClippingRect);
if (m_selected_item != NULL && m_selected_item->listname == s.listname && m_selected_item->i == i) {
driver->draw2DRectangleOutline(rect, hbcolor);
}else{
driver->draw2DRectangleOutline(rect, bdcolor);
}
if (item) {
drawInventoryItem(driver, font, item, rect, &AbsoluteClippingRect);
if (rect.isPointInside(m_pointer)) {
std::string name = item->getGuiName();
if (name != "") {
m_tooltip_element->setVisible(true);
this->bringToFront(m_tooltip_element);
m_tooltip_element->setText(narrow_to_wide(name).c_str());
s32 tooltip_x = m_pointer.X + 15;
s32 tooltip_y = m_pointer.Y + 15;
s32 tooltip_width = m_tooltip_element->getTextWidth() + 14;
s32 tooltip_height = m_tooltip_element->getTextHeight() + 4;
m_tooltip_element->setRelativePosition(
core::rect<s32>(
core::position2d<s32>(tooltip_x, tooltip_y),
core::dimension2d<s32>(tooltip_width, tooltip_height)
)
);
}
}
}
}
}
void GUIInventoryMenu::drawMenu()
{
gui::IGUISkin* skin = Environment->getSkin();
if (!skin)
return;
video::IVideoDriver* driver = Environment->getVideoDriver();
video::SColor bgtcolor(240,50,50,70);
video::SColor bgbcolor(240,30,30,50);
driver->draw2DRectangle(AbsoluteRect,bgtcolor, bgtcolor, bgbcolor, bgbcolor, &AbsoluteClippingRect);
video::SColor bdcolor(245,60,60,80);
driver->draw2DRectangleOutline(AbsoluteRect, bdcolor);
/*
Draw items
*/
m_tooltip_element->setVisible(false);
for (u32 i=0; i<m_draw_spec.size(); i++) {
ListDrawSpec &s = m_draw_spec[i];
drawList(s);
}
/*
Call base class
*/
gui::IGUIElement::draw();
}
bool GUIInventoryMenu::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")))
{
m_tooltip_element->setVisible(false);
quitMenu();
return true;
}
}
if(event.EventType==EET_MOUSE_INPUT_EVENT)
{
char amount = -1;
if(event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN)
amount = 0;
else if(event.MouseInput.Event == EMIE_RMOUSE_PRESSED_DOWN)
amount = 1;
else if(event.MouseInput.Event == EMIE_MMOUSE_PRESSED_DOWN)
amount = 10;
m_pointer.X = event.MouseInput.X;
m_pointer.Y = event.MouseInput.Y;
if(amount >= 0)
{
v2s32 p(event.MouseInput.X, event.MouseInput.Y);
//infostream<<"Mouse down at p=("<<p.X<<","<<p.Y<<")"<<std::endl;
ItemSpec s = getItemAtPos(p);
if(s.isValid())
{
infostream<<"Mouse down on "<<s.inventoryname
<<"/"<<s.listname<<" "<<s.i<<std::endl;
if(m_selected_item)
{
Inventory *inv_from = m_invmgr->getInventory(m_c,
m_selected_item->inventoryname);
Inventory *inv_to = m_invmgr->getInventory(m_c,
s.inventoryname);
assert(inv_from);
assert(inv_to);
InventoryList *list_from =
inv_from->getList(m_selected_item->listname);
InventoryList *list_to =
inv_to->getList(s.listname);
if(list_from == NULL)
infostream<<"from list doesn't exist"<<std::endl;
if(list_to == NULL)
infostream<<"to list doesn't exist"<<std::endl;
// Indicates whether source slot completely empties
bool source_empties = false;
if(list_from && list_to
&& list_from->getItem(m_selected_item->i) != NULL)
{
infostream<<"Handing IACTION_MOVE to manager"<<std::endl;
IMoveAction *a = new IMoveAction();
a->count = amount;
a->from_inv = m_selected_item->inventoryname;
a->from_list = m_selected_item->listname;
a->from_i = m_selected_item->i;
a->to_inv = s.inventoryname;
a->to_list = s.listname;
a->to_i = s.i;
//ispec.actions->push_back(a);
m_invmgr->inventoryAction(a);
if(list_from->getItem(m_selected_item->i)->getCount()==1)
source_empties = true;
}
// Remove selection if target was left-clicked or source
// slot was emptied
if(amount == 0 || source_empties)
{
delete m_selected_item;
m_selected_item = NULL;
}
}
else
{
/*
Select if non-NULL
*/
Inventory *inv = m_invmgr->getInventory(m_c,
s.inventoryname);
assert(inv);
InventoryList *list = inv->getList(s.listname);
if(list->getItem(s.i) != NULL)
{
m_selected_item = new ItemSpec(s);
}
}
}
else
{
if(m_selected_item)
{
delete m_selected_item;
m_selected_item = NULL;
}
}
}
}
if(event.EventType==EET_GUI_EVENT)
{
if(event.GUIEvent.EventType==gui::EGET_ELEMENT_FOCUS_LOST
&& isVisible())
{
if(!canTakeFocus(event.GUIEvent.Element))
{
infostream<<"GUIInventoryMenu: Not allowing focus change."
<<std::endl;
// Returning true disables focus change
return true;
}
}
if(event.GUIEvent.EventType==gui::EGET_BUTTON_CLICKED)
{
/*switch(event.GUIEvent.Caller->getID())
{
case 256: // continue
setVisible(false);
break;
case 257: // exit
dev->closeDevice();
break;
}*/
}
}
return Parent ? Parent->OnEvent(event) : false;
}
/*
Here is an example traditional set-up sequence for a DrawSpec list:
std::string furnace_inv_id = "nodemetadata:0,1,2";
core::array<GUIInventoryMenu::DrawSpec> draw_spec;
draw_spec.push_back(GUIInventoryMenu::DrawSpec(
"list", furnace_inv_id, "fuel",
v2s32(2, 3), v2s32(1, 1)));
draw_spec.push_back(GUIInventoryMenu::DrawSpec(
"list", furnace_inv_id, "src",
v2s32(2, 1), v2s32(1, 1)));
draw_spec.push_back(GUIInventoryMenu::DrawSpec(
"list", furnace_inv_id, "dst",
v2s32(5, 1), v2s32(2, 2)));
draw_spec.push_back(GUIInventoryMenu::DrawSpec(
"list", "current_player", "main",
v2s32(0, 5), v2s32(8, 4)));
setDrawSpec(draw_spec);
Here is the string for creating the same DrawSpec list (a single line,
spread to multiple lines here):
GUIInventoryMenu::makeDrawSpecArrayFromString(
draw_spec,
"nodemetadata:0,1,2",
"invsize[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;]"
"list[current_player;main;0,5;8,4;]");
Returns inventory menu size defined by invsize[].
*/
v2s16 GUIInventoryMenu::makeDrawSpecArrayFromString(
core::array<GUIInventoryMenu::DrawSpec> &draw_spec,
const std::string &data,
const std::string &current_name)
{
v2s16 invsize(8,9);
Strfnd f(data);
while(f.atend() == false)
{
std::string type = trim(f.next("["));
//infostream<<"type="<<type<<std::endl;
if(type == "list")
{
std::string name = f.next(";");
if(name == "current_name")
name = current_name;
std::string subname = f.next(";");
s32 pos_x = stoi(f.next(","));
s32 pos_y = stoi(f.next(";"));
s32 geom_x = stoi(f.next(","));
s32 geom_y = stoi(f.next(";"));
infostream<<"list name="<<name<<", subname="<<subname
<<", pos=("<<pos_x<<","<<pos_y<<")"
<<", geom=("<<geom_x<<","<<geom_y<<")"
<<std::endl;
draw_spec.push_back(GUIInventoryMenu::DrawSpec(
type, name, subname,
v2s32(pos_x,pos_y),v2s32(geom_x,geom_y)));
f.next("]");
}
else if(type == "invsize")
{
invsize.X = stoi(f.next(","));
invsize.Y = stoi(f.next(";"));
infostream<<"invsize ("<<invsize.X<<","<<invsize.Y<<")"<<std::endl;
f.next("]");
}
else
{
// Ignore others
std::string ts = f.next("]");
infostream<<"Unknown DrawSpec: type="<<type<<", data=\""<<ts<<"\""
<<std::endl;
}
}
return invsize;
}

View File

@ -1,162 +0,0 @@
/*
Minetest-c55
Copyright (C) 2010 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 General Public License as published by
the Free Software Foundation; either version 2 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 General Public License for more details.
You should have received a copy of the GNU 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.
*/
#ifndef GUIINVENTORYMENU_HEADER
#define GUIINVENTORYMENU_HEADER
#include "common_irrlicht.h"
#include "inventory.h"
#include "utility.h"
#include "modalMenu.h"
void drawInventoryItem(video::IVideoDriver *driver,
gui::IGUIFont *font,
InventoryItem *item, core::rect<s32> rect,
const core::rect<s32> *clip);
class GUIInventoryMenu : public GUIModalMenu
{
struct ItemSpec
{
ItemSpec()
{
i = -1;
}
ItemSpec(const std::string &a_inventoryname,
const std::string &a_listname,
s32 a_i)
{
inventoryname = a_inventoryname;
listname = a_listname;
i = a_i;
}
bool isValid() const
{
return i != -1;
}
std::string inventoryname;
std::string listname;
s32 i;
};
struct ListDrawSpec
{
ListDrawSpec()
{
}
ListDrawSpec(const std::string &a_inventoryname,
const std::string &a_listname,
v2s32 a_pos, v2s32 a_geom)
{
inventoryname = a_inventoryname;
listname = a_listname;
pos = a_pos;
geom = a_geom;
}
std::string inventoryname;
std::string listname;
v2s32 pos;
v2s32 geom;
};
public:
struct DrawSpec
{
DrawSpec()
{
}
DrawSpec(const std::string &a_type,
const std::string &a_name,
const std::string &a_subname,
v2s32 a_pos,
v2s32 a_geom)
{
type = a_type;
name = a_name;
subname = a_subname;
pos = a_pos;
geom = a_geom;
}
std::string type;
std::string name;
std::string subname;
v2s32 pos;
v2s32 geom;
};
// See .cpp for format
static v2s16 makeDrawSpecArrayFromString(
core::array<GUIInventoryMenu::DrawSpec> &draw_spec,
const std::string &data,
const std::string &current_name);
GUIInventoryMenu(gui::IGUIEnvironment* env,
gui::IGUIElement* parent, s32 id,
IMenuManager *menumgr,
v2s16 menu_size,
InventoryContext *c,
InventoryManager *invmgr
);
~GUIInventoryMenu();
void setDrawSpec(core::array<DrawSpec> &init_draw_spec)
{
m_init_draw_spec = init_draw_spec;
}
void removeChildren();
/*
Remove and re-add (or reposition) stuff
*/
void regenerateGui(v2u32 screensize);
ItemSpec getItemAtPos(v2s32 p) const;
void drawList(const ListDrawSpec &s);
void drawMenu();
bool OnEvent(const SEvent& event);
protected:
v2s32 getBasePos() const
{
return padding + AbsoluteRect.UpperLeftCorner;
}
v2s16 m_menu_size;
v2s32 padding;
v2s32 spacing;
v2s32 imgsize;
InventoryContext *m_c;
InventoryManager *m_invmgr;
core::array<DrawSpec> m_init_draw_spec;
core::array<ListDrawSpec> m_draw_spec;
ItemSpec *m_selected_item;
v2s32 m_pointer;
gui::IGUIStaticText *m_tooltip_element;
};
#endif

View File

@ -24,12 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "modalMenu.h"
#include "utility.h"
#include <string>
struct TextDest
{
virtual ~TextDest() {}
virtual void gotText(std::wstring text) = 0;
};
#include "guiFormSpecMenu.h"
class GUITextInputMenu : public GUIModalMenu
{

View File

@ -894,6 +894,76 @@ void IMoveAction::apply(InventoryContext *c, InventoryManager *mgr)
<<std::endl;
}
/*
InventoryLocation
*/
std::string InventoryLocation::dump() const
{
std::ostringstream os(std::ios::binary);
serialize(os);
return os.str();
}
void InventoryLocation::serialize(std::ostream &os) const
{
switch(type) {
case InventoryLocation::UNDEFINED:
{
os<<"undefined";
}
break;
case InventoryLocation::CURRENT_PLAYER:
{
os<<"current_player";
}
break;
case InventoryLocation::PLAYER:
{
os<<"player:"<<name;
}
break;
case InventoryLocation::NODEMETA:
{
os<<"nodemeta:"<<p.X<<","<<p.Y<<","<<p.Z;
}
break;
default:
assert(0);
}
}
void InventoryLocation::deSerialize(std::istream &is)
{
std::string tname;
std::getline(is, tname, ':');
if (tname == "undefined") {
type = InventoryLocation::UNDEFINED;
}else if (tname == "current_player") {
type = InventoryLocation::CURRENT_PLAYER;
}else if (tname == "player") {
type = InventoryLocation::PLAYER;
std::getline(is, name, '\n');
}else if (tname == "nodemeta") {
type = InventoryLocation::NODEMETA;
std::string pos;
std::getline(is, pos, '\n');
Strfnd fn(pos);
p.X = stoi(fn.next(","));
p.Y = stoi(fn.next(","));
p.Z = stoi(fn.next(","));
}else{
infostream<<"Unknown InventoryLocation type=\""<<tname<<"\""<<std::endl;
throw SerializationError("Unknown InventoryLocation type");
}
}
void InventoryLocation::deSerialize(std::string s)
{
std::istringstream is(s, std::ios::binary);
deSerialize(is);
}
/*
Craft checking system
*/

View File

@ -529,6 +529,7 @@ struct InventoryContext
};
struct InventoryAction;
struct InventoryLocation;
class InventoryManager
{
@ -544,6 +545,8 @@ public:
*/
virtual Inventory* getInventory(InventoryContext *c, std::string id)
{return NULL;}
virtual Inventory* getInventory(const InventoryLocation *loc)
{return NULL;}
// Used on the server by InventoryAction::apply and other stuff
virtual void inventoryModified(InventoryContext *c, std::string id)
{}
@ -623,6 +626,71 @@ struct IMoveAction : public InventoryAction
void apply(InventoryContext *c, InventoryManager *mgr);
};
struct InventoryLocation
{
enum Type{
UNDEFINED,
CURRENT_PLAYER,
PLAYER,
NODEMETA,
} type;
std::string name; // PLAYER
v3s16 p; // NODEMETA
InventoryLocation()
{
setUndefined();
}
void setUndefined()
{
type = UNDEFINED;
}
void setCurrentPlayer()
{
type = CURRENT_PLAYER;
}
void setPlayer(const std::string &name_)
{
type = PLAYER;
name = name_;
}
void setNodeMeta(v3s16 p_)
{
type = NODEMETA;
p = p_;
}
void applyCurrentPlayer(const std::string &name_)
{
if (type == CURRENT_PLAYER)
setPlayer(name_);
}
std::string getName()
{
std::string l_name("");
if (type == PLAYER) {
l_name += "player:";
l_name += name;
}else if (type == NODEMETA) {
l_name += "nodemeta:";
l_name += itos(p.X);
l_name += ",";
l_name += itos(p.Y);
l_name += ",";
l_name += itos(p.Z);
}else if (type == CURRENT_PLAYER) {
l_name += "current_player";
}
return l_name;
}
std::string dump() const;
void serialize(std::ostream &os) const;
void deSerialize(std::istream &is);
void deSerialize(std::string s);
};
/*
Craft checking system
*/

View File

@ -125,12 +125,12 @@ public:
protected:
//bool m_force_regenerate_gui;
v2u32 m_screensize_old;
private:
IMenuManager *m_menumgr;
// This might be necessary to expose to the implementation if it
// wants to launch other menus
bool m_allow_focus_removal;
v2u32 m_screensize_old;
};

View File

@ -23,6 +23,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "common_irrlicht.h"
#include <string>
#include <iostream>
#include <map>
class Player;
#define ENERGY_MAX 16
@ -67,13 +70,15 @@ public:
virtual bool nodeRemovalDisabled(){return false;}
// Used to make custom inventory menus.
// See format in guiInventoryMenu.cpp.
virtual std::string getInventoryDrawSpecString(){return "";}
virtual std::string getDrawSpecString(){return "";}
// the node owner - if not "" then only the owner can dig the node
virtual std::string getOwner(){ return std::string(""); }
virtual void setOwner(std::string t){ }
// the inventory owner - if not "" then only the owner can modify
virtual std::string getInventoryOwner(){ return std::string(""); }
virtual void setInventoryOwner(std::string t){ }
// receive data from the client
virtual void receiveFields(std::string formname, std::map<std::string, std::string> fields, Player *player) {}
// used by tnt to arm it, but also for future circuitry
// level is the amount of power
// powersrc is the generator or such that created the power

View File

@ -3957,59 +3957,9 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
}
else if(command == TOSERVER_SIGNNODETEXT)
{
if((getPlayerPrivs(player) & PRIV_BUILD) == 0)
infostream<<"Server: TOSERVER_SIGNNODETEXT not supported anymore"
<<std::endl;
return;
/*
u16 command
v3s16 p
u16 textlen
textdata
*/
std::string datastring((char*)&data[2], datasize-2);
std::istringstream is(datastring, std::ios_base::binary);
u8 buf[6];
// Read stuff
is.read((char*)buf, 6);
v3s16 p = readV3S16(buf);
is.read((char*)buf, 2);
u16 textlen = readU16(buf);
std::string text;
for(u16 i=0; i<textlen; i++)
{
is.read((char*)buf, 1);
text += (char)buf[0];
}
NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
if(!meta)
return;
if(meta->typeId() != CONTENT_SIGN_WALL) {
if (meta->typeId() != CONTENT_LOCKABLE_SIGN_WALL)
return;
LockingSignNodeMetadata *lsm = (LockingSignNodeMetadata*)meta;
if (lsm->getOwner() != player->getName())
return;
}
SignNodeMetadata *signmeta = (SignNodeMetadata*)meta;
signmeta->setText(text);
actionstream<<player->getName()<<" writes \""<<text<<"\" to sign "
<<" at "<<PP(p)<<std::endl;
v3s16 blockpos = getNodeBlockPos(p);
MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(blockpos);
if(block)
{
block->setChangedFlag();
}
for(core::map<u16, RemoteClient*>::Iterator
i = m_clients.getIterator();
i.atEnd()==false; i++)
{
RemoteClient *client = i.getNode()->getValue();
client->SetBlockNotSent(blockpos);
}
}
else if(command == TOSERVER_INVENTORY_ACTION)
{
@ -4398,6 +4348,36 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
{
SendPlayerCookie(player);
}
else if(command == TOSERVER_NODEMETA_FIELDS)
{
std::string datastring((char*)&data[2], datasize-2);
std::istringstream is(datastring, std::ios_base::binary);
u8 buf[6];
// Read p
is.read((char*)buf, 6);
v3s16 p = readV3S16(buf);
// Read formname
std::string formname = deSerializeString(is);
// Read number of fields
is.read((char*)buf, 2);
u16 num = readU16(buf);
// Read Fields
std::map<std::string, std::string> fields;
for (int k=0; k<num; k++) {
std::string fieldname = deSerializeString(is);
std::string fieldvalue = deSerializeLongString(is);
fields[fieldname] = fieldvalue;
}
NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
if(!meta)
return;
meta->receiveFields(formname,fields,player);
}
else
{
infostream<<"Server::ProcessData(): Ignoring "