Fix many formspec menu bugs
[oweals/minetest.git] / src / guiFormSpecMenu.h
1 /*
2 Minetest
3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20
21 #ifndef GUIINVENTORYMENU_HEADER
22 #define GUIINVENTORYMENU_HEADER
23
24 #include <utility>
25
26 #include "irrlichttypes_extrabloated.h"
27 #include "inventory.h"
28 #include "inventorymanager.h"
29 #include "modalMenu.h"
30
31 class IGameDef;
32 class InventoryManager;
33
34 typedef enum {
35         f_Button,
36         f_ListBox,
37         f_TabHeader,
38         f_CheckBox,
39         f_DropDown,
40         f_Unknown
41 } FormspecFieldType;
42
43 struct TextDest
44 {
45         virtual ~TextDest() {};
46         // This is deprecated I guess? -celeron55
47         virtual void gotText(std::wstring text){}
48         virtual void gotText(std::map<std::string, std::string> fields) = 0;
49 };
50
51 class IFormSource
52 {
53 public:
54         virtual ~IFormSource(){}
55         virtual std::string getForm() = 0;
56         // Fill in variables in field text
57         virtual std::string resolveText(std::string str){ return str; }
58 };
59
60 void drawItemStack(video::IVideoDriver *driver,
61                 gui::IGUIFont *font,
62                 const ItemStack &item,
63                 const core::rect<s32> &rect,
64                 const core::rect<s32> *clip,
65                 IGameDef *gamedef);
66
67 class GUIFormSpecMenu : public GUIModalMenu
68 {
69         struct ItemSpec
70         {
71                 ItemSpec()
72                 {
73                         i = -1;
74                 }
75                 ItemSpec(const InventoryLocation &a_inventoryloc,
76                                 const std::string &a_listname,
77                                 s32 a_i)
78                 {
79                         inventoryloc = a_inventoryloc;
80                         listname = a_listname;
81                         i = a_i;
82                 }
83                 bool isValid() const
84                 {
85                         return i != -1;
86                 }
87
88                 InventoryLocation inventoryloc;
89                 std::string listname;
90                 s32 i;
91         };
92
93         struct ListDrawSpec
94         {
95                 ListDrawSpec()
96                 {
97                 }
98                 ListDrawSpec(const InventoryLocation &a_inventoryloc,
99                                 const std::string &a_listname,
100                                 v2s32 a_pos, v2s32 a_geom, s32 a_start_item_i):
101                         inventoryloc(a_inventoryloc),
102                         listname(a_listname),
103                         pos(a_pos),
104                         geom(a_geom),
105                         start_item_i(a_start_item_i)
106                 {
107                 }
108
109                 InventoryLocation inventoryloc;
110                 std::string listname;
111                 v2s32 pos;
112                 v2s32 geom;
113                 s32 start_item_i;
114         };
115
116         struct ImageDrawSpec
117         {
118                 ImageDrawSpec()
119                 {
120                 }
121                 ImageDrawSpec(const std::string &a_name,
122                                 v2s32 a_pos, v2s32 a_geom):
123                         name(a_name),
124                         pos(a_pos),
125                         geom(a_geom)
126                 {
127                         scale = true;
128                 }
129                 ImageDrawSpec(const std::string &a_name,
130                                 v2s32 a_pos):
131                         name(a_name),
132                         pos(a_pos)
133                 {
134                         scale = false;
135                 }
136                 std::string name;
137                 v2s32 pos;
138                 v2s32 geom;
139                 bool scale;
140         };
141         
142         struct FieldSpec
143         {
144                 FieldSpec()
145                 {
146                 }
147                 FieldSpec(const std::wstring name, const std::wstring label, const std::wstring fdeflt, int id):
148                         fname(name),
149                         flabel(label),
150                         fdefault(fdeflt),
151                         fid(id)
152                 {
153                         send = false;
154                         ftype = f_Unknown;
155                         is_exit = false;
156                         tooltip="";
157                 }
158                 std::wstring fname;
159                 std::wstring flabel;
160                 std::wstring fdefault;
161                 int fid;
162                 bool send;
163                 FormspecFieldType ftype;
164                 bool is_exit;
165                 core::rect<s32> rect;
166                 std::string tooltip;
167         };
168
169         struct BoxDrawSpec {
170                 BoxDrawSpec(v2s32 a_pos, v2s32 a_geom,irr::video::SColor a_color):
171                         pos(a_pos),
172                         geom(a_geom),
173                         color(a_color)
174                 {
175                 }
176                 v2s32 pos;
177                 v2s32 geom;
178                 irr::video::SColor color;
179         };
180
181 public:
182         GUIFormSpecMenu(irr::IrrlichtDevice* dev,
183                         gui::IGUIElement* parent, s32 id,
184                         IMenuManager *menumgr,
185                         InventoryManager *invmgr,
186                         IGameDef *gamedef
187                         );
188
189         ~GUIFormSpecMenu();
190
191         void setFormSpec(const std::string &formspec_string,
192                         InventoryLocation current_inventory_location)
193         {
194                 m_formspec_string = formspec_string;
195                 m_current_inventory_location = current_inventory_location;
196                 regenerateGui(m_screensize_old);
197         }
198         
199         // form_src is deleted by this GUIFormSpecMenu
200         void setFormSource(IFormSource *form_src)
201         {
202                 m_form_src = form_src;
203         }
204
205         // text_dst is deleted by this GUIFormSpecMenu
206         void setTextDest(TextDest *text_dst)
207         {
208                 m_text_dst = text_dst;
209         }
210
211         void allowClose(bool value)
212         {
213                 m_allowclose = value;
214         }
215
216         void useGettext(bool value) {
217                 m_use_gettext = true;
218         }
219
220         void lockSize(bool lock,v2u32 basescreensize=v2u32(0,0)) {
221                 m_lock = lock;
222                 m_lockscreensize = basescreensize;
223         }
224
225         void removeChildren();
226         /*
227                 Remove and re-add (or reposition) stuff
228         */
229         void regenerateGui(v2u32 screensize);
230         
231         ItemSpec getItemAtPos(v2s32 p) const;
232         void drawList(const ListDrawSpec &s, int phase);
233         void drawSelectedItem();
234         void drawMenu();
235         void updateSelectedItem();
236         ItemStack verifySelectedItem();
237
238         void acceptInput(int evttype=-1);
239         bool OnEvent(const SEvent& event);
240         
241         int getListboxIndex(std::string listboxname);
242
243 protected:
244         v2s32 getBasePos() const
245         {
246                         return padding + offset + AbsoluteRect.UpperLeftCorner;
247         }
248
249         v2s32 padding;
250         v2s32 spacing;
251         v2s32 imgsize;
252         v2s32 offset;
253         
254         irr::IrrlichtDevice* m_device;
255         InventoryManager *m_invmgr;
256         IGameDef *m_gamedef;
257
258         std::string m_formspec_string;
259         InventoryLocation m_current_inventory_location;
260         IFormSource *m_form_src;
261         TextDest *m_text_dst;
262
263         std::vector<ListDrawSpec> m_inventorylists;
264         std::vector<ImageDrawSpec> m_backgrounds;
265         std::vector<ImageDrawSpec> m_images;
266         std::vector<ImageDrawSpec> m_itemimages;
267         std::vector<BoxDrawSpec> m_boxes;
268         std::vector<FieldSpec> m_fields;
269         std::vector<std::pair<FieldSpec,gui::IGUIListBox*> > m_listboxes;
270         std::vector<std::pair<FieldSpec,gui::IGUICheckBox*> > m_checkboxes;
271
272         ItemSpec *m_selected_item;
273         u32 m_selected_amount;
274         bool m_selected_dragging;
275         
276         // WARNING: BLACK MAGIC
277         // Used to guess and keep up with some special things the server can do.
278         // If name is "", no guess exists.
279         ItemStack m_selected_content_guess;
280         InventoryLocation m_selected_content_guess_inventory;
281
282         v2s32 m_pointer;
283         gui::IGUIStaticText *m_tooltip_element;
284
285         bool m_allowclose;
286         bool m_use_gettext;
287         bool m_lock;
288         v2u32 m_lockscreensize;
289 private:
290         typedef struct {
291                 v2s32 size;
292                 s32 helptext_h;
293                 core::rect<s32> rect;
294                 v2s32 basepos;
295                 int bp_set;
296                 v2u32 screensize;
297                 std::map<std::wstring,int> listbox_selections;
298         } parserData;
299
300         typedef struct {
301                 bool key_up;
302                 bool key_down;
303                 bool key_enter;
304                 bool key_escape;
305         } fs_key_pendig;
306
307         std::vector<video::ITexture *> m_Textures;
308
309         fs_key_pendig current_keys_pending;
310
311         void parseElement(parserData* data,std::string element);
312
313         void parseSize(parserData* data,std::string element);
314         void parseList(parserData* data,std::string element);
315         void parseCheckbox(parserData* data,std::string element);
316         void parseImage(parserData* data,std::string element);
317         void parseItemImage(parserData* data,std::string element);
318         void parseButton(parserData* data,std::string element,std::string typ);
319         void parseBackground(parserData* data,std::string element);
320         void parseTextList(parserData* data,std::string element);
321         void parseDropDown(parserData* data,std::string element);
322         void parsePwdField(parserData* data,std::string element);
323         void parseField(parserData* data,std::string element,std::string type);
324         void parseSimpleField(parserData* data,std::vector<std::string> &parts);
325         void parseTextArea(parserData* data,std::vector<std::string>& parts,std::string type);
326         void parseLabel(parserData* data,std::string element);
327         void parseVertLabel(parserData* data,std::string element);
328         void parseImageButton(parserData* data,std::string element,std::string type);
329         void parseItemImageButton(parserData* data,std::string element);
330         void parseTabHeader(parserData* data,std::string element);
331         void parseBox(parserData* data,std::string element);
332
333         bool parseColor(std::string color, irr::video::SColor& outcolor); 
334 };
335
336 class FormspecFormSource: public IFormSource
337 {
338 public:
339         FormspecFormSource(std::string formspec,FormspecFormSource** game_formspec)
340         {
341                 m_formspec = formspec;
342                 m_game_formspec = game_formspec;
343         }
344
345         ~FormspecFormSource()
346         {
347                 *m_game_formspec = 0;
348         }
349
350         void setForm(std::string formspec) {
351                 m_formspec = formspec;
352         }
353
354         std::string getForm()
355         {
356                 return m_formspec;
357         }
358
359         std::string m_formspec;
360         FormspecFormSource** m_game_formspec;
361 };
362
363 #endif
364