forked from oerkki/voxelands
implement formspec - I seem to have done this before
This commit is contained in:
parent
2d07060a27
commit
33320c800d
|
@ -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
|
|
@ -162,7 +162,7 @@ set(minetest_SRCS
|
|||
guiKeyChangeMenu.cpp
|
||||
guiMessageMenu.cpp
|
||||
guiTextInputMenu.cpp
|
||||
guiInventoryMenu.cpp
|
||||
guiFormSpecMenu.cpp
|
||||
guiPauseMenu.cpp
|
||||
guiPasswordChange.cpp
|
||||
guiDeathScreen.cpp
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;]";
|
||||
|
|
|
@ -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;
|
||||
|
|
167
src/game.cpp
167
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 "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
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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 ¤t_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;
|
||||
}
|
||||
|
|
@ -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 ¤t_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
|
||||
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 "
|
||||
|
|
Loading…
Reference in New Issue