]> git.lizzy.rs Git - dragonfireclient.git/blob - src/gui/guiFormSpecMenu.h
Formspec: Fix priorities for version < 3 (#9121)
[dragonfireclient.git] / src / gui / 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 #pragma once
21
22 #include <utility>
23 #include <stack>
24 #include <unordered_set>
25
26 #include "irrlichttypes_extrabloated.h"
27 #include "inventorymanager.h"
28 #include "modalMenu.h"
29 #include "guiTable.h"
30 #include "network/networkprotocol.h"
31 #include "client/joystick_controller.h"
32 #include "util/string.h"
33 #include "util/enriched_string.h"
34 #include "StyleSpec.h"
35
36 class InventoryManager;
37 class ISimpleTextureSource;
38 class Client;
39 class GUIScrollBar;
40
41 typedef enum {
42         f_Button,
43         f_Table,
44         f_TabHeader,
45         f_CheckBox,
46         f_DropDown,
47         f_ScrollBar,
48         f_Box,
49         f_ItemImage,
50         f_Unknown
51 } FormspecFieldType;
52
53 typedef enum {
54         quit_mode_no,
55         quit_mode_accept,
56         quit_mode_cancel
57 } FormspecQuitMode;
58
59 struct TextDest
60 {
61         virtual ~TextDest() = default;
62
63         // This is deprecated I guess? -celeron55
64         virtual void gotText(const std::wstring &text) {}
65         virtual void gotText(const StringMap &fields) = 0;
66
67         std::string m_formname;
68 };
69
70 class IFormSource
71 {
72 public:
73         virtual ~IFormSource() = default;
74         virtual const std::string &getForm() const = 0;
75         // Fill in variables in field text
76         virtual std::string resolveText(const std::string &str) { return str; }
77 };
78
79 class GUIFormSpecMenu : public GUIModalMenu
80 {
81         struct ItemSpec
82         {
83                 ItemSpec() = default;
84
85                 ItemSpec(const InventoryLocation &a_inventoryloc,
86                                 const std::string &a_listname,
87                                 s32 a_i) :
88                         inventoryloc(a_inventoryloc),
89                         listname(a_listname),
90                         i(a_i)
91                 {
92                 }
93
94                 bool isValid() const { return i != -1; }
95
96                 InventoryLocation inventoryloc;
97                 std::string listname;
98                 s32 i = -1;
99         };
100
101         struct ListDrawSpec
102         {
103                 ListDrawSpec() = default;
104
105                 ListDrawSpec(const InventoryLocation &a_inventoryloc,
106                                 const std::string &a_listname,
107                                 IGUIElement *elem, v2s32 a_geom, s32 a_start_item_i,
108                                 bool a_real_coordinates):
109                         inventoryloc(a_inventoryloc),
110                         listname(a_listname),
111                         e(elem),
112                         geom(a_geom),
113                         start_item_i(a_start_item_i),
114                         real_coordinates(a_real_coordinates)
115                 {
116                 }
117
118                 InventoryLocation inventoryloc;
119                 std::string listname;
120                 IGUIElement *e;
121                 v2s32 geom;
122                 s32 start_item_i;
123                 bool real_coordinates;
124         };
125
126         struct ListRingSpec
127         {
128                 ListRingSpec() = default;
129
130                 ListRingSpec(const InventoryLocation &a_inventoryloc,
131                                 const std::string &a_listname):
132                         inventoryloc(a_inventoryloc),
133                         listname(a_listname)
134                 {
135                 }
136
137                 InventoryLocation inventoryloc;
138                 std::string listname;
139         };
140
141         struct FieldSpec
142         {
143                 FieldSpec() = default;
144
145                 FieldSpec(const std::string &name, const std::wstring &label,
146                                 const std::wstring &default_text, s32 id, int priority = 0) :
147                         fname(name),
148                         flabel(label),
149                         fdefault(unescape_enriched(translate_string(default_text))),
150                         fid(id),
151                         send(false),
152                         ftype(f_Unknown),
153                         is_exit(false),
154                         priority(priority)
155                 {
156                 }
157
158                 std::string fname;
159                 std::wstring flabel;
160                 std::wstring fdefault;
161                 s32 fid;
162                 bool send;
163                 FormspecFieldType ftype;
164                 bool is_exit;
165                 // Draw priority for formspec version < 3
166                 int priority;
167                 core::rect<s32> rect;
168         };
169
170         struct TooltipSpec
171         {
172                 TooltipSpec() = default;
173                 TooltipSpec(const std::wstring &a_tooltip, irr::video::SColor a_bgcolor,
174                                 irr::video::SColor a_color):
175                         tooltip(translate_string(a_tooltip)),
176                         bgcolor(a_bgcolor),
177                         color(a_color)
178                 {
179                 }
180
181                 std::wstring tooltip;
182                 irr::video::SColor bgcolor;
183                 irr::video::SColor color;
184         };
185
186         struct StaticTextSpec
187         {
188                 StaticTextSpec():
189                         parent_button(NULL)
190                 {
191                 }
192
193                 StaticTextSpec(const std::wstring &a_text,
194                                 const core::rect<s32> &a_rect):
195                         text(a_text),
196                         rect(a_rect),
197                         parent_button(NULL)
198                 {
199                 }
200
201                 StaticTextSpec(const std::wstring &a_text,
202                                 const core::rect<s32> &a_rect,
203                                 gui::IGUIButton *a_parent_button):
204                         text(a_text),
205                         rect(a_rect),
206                         parent_button(a_parent_button)
207                 {
208                 }
209
210                 std::wstring text;
211                 core::rect<s32> rect;
212                 gui::IGUIButton *parent_button;
213         };
214
215 public:
216         GUIFormSpecMenu(JoystickController *joystick,
217                         gui::IGUIElement* parent, s32 id,
218                         IMenuManager *menumgr,
219                         Client *client,
220                         ISimpleTextureSource *tsrc,
221                         IFormSource* fs_src,
222                         TextDest* txt_dst,
223                         const std::string &formspecPrepend,
224                         bool remap_dbl_click = true);
225
226         ~GUIFormSpecMenu();
227
228         static void create(GUIFormSpecMenu *&cur_formspec, Client *client,
229                 JoystickController *joystick, IFormSource *fs_src, TextDest *txt_dest,
230                 const std::string &formspecPrepend);
231
232         void setFormSpec(const std::string &formspec_string,
233                         const InventoryLocation &current_inventory_location)
234         {
235                 m_formspec_string = formspec_string;
236                 m_current_inventory_location = current_inventory_location;
237                 regenerateGui(m_screensize_old);
238         }
239
240         const InventoryLocation &getFormspecLocation()
241         {
242                 return m_current_inventory_location;
243         }
244
245         void setFormspecPrepend(const std::string &formspecPrepend)
246         {
247                 m_formspec_prepend = formspecPrepend;
248         }
249
250         // form_src is deleted by this GUIFormSpecMenu
251         void setFormSource(IFormSource *form_src)
252         {
253                 delete m_form_src;
254                 m_form_src = form_src;
255         }
256
257         // text_dst is deleted by this GUIFormSpecMenu
258         void setTextDest(TextDest *text_dst)
259         {
260                 delete m_text_dst;
261                 m_text_dst = text_dst;
262         }
263
264         void allowClose(bool value)
265         {
266                 m_allowclose = value;
267         }
268
269         void lockSize(bool lock,v2u32 basescreensize=v2u32(0,0))
270         {
271                 m_lock = lock;
272                 m_lockscreensize = basescreensize;
273         }
274
275         void removeChildren();
276         void setInitialFocus();
277
278         void setFocus(const std::string &elementname)
279         {
280                 m_focused_element = elementname;
281         }
282
283         /*
284                 Remove and re-add (or reposition) stuff
285         */
286         void regenerateGui(v2u32 screensize);
287
288         ItemSpec getItemAtPos(v2s32 p) const;
289         void drawList(const ListDrawSpec &s, int layer, bool &item_hovered);
290         void drawSelectedItem();
291         void drawMenu();
292         void updateSelectedItem();
293         ItemStack verifySelectedItem();
294
295         void acceptInput(FormspecQuitMode quitmode);
296         bool preprocessEvent(const SEvent& event);
297         bool OnEvent(const SEvent& event);
298         bool doPause;
299         bool pausesGame() { return doPause; }
300
301         GUITable* getTable(const std::string &tablename);
302         std::vector<std::string>* getDropDownValues(const std::string &name);
303
304 #ifdef __ANDROID__
305         bool getAndroidUIInput();
306 #endif
307
308 protected:
309         v2s32 getBasePos() const
310         {
311                         return padding + offset + AbsoluteRect.UpperLeftCorner;
312         }
313         std::wstring getLabelByID(s32 id);
314         std::string getNameByID(s32 id);
315         const FieldSpec *getSpecByID(s32 id);
316         v2s32 getElementBasePos(const std::vector<std::string> *v_pos);
317         v2s32 getRealCoordinateBasePos(const std::vector<std::string> &v_pos);
318         v2s32 getRealCoordinateGeometry(const std::vector<std::string> &v_geom);
319
320         std::unordered_map<std::string, StyleSpec> theme_by_type;
321         std::unordered_map<std::string, StyleSpec> theme_by_name;
322         std::unordered_set<std::string> property_warned;
323
324         StyleSpec getStyleForElement(const std::string &type,
325                         const std::string &name="", const std::string &parent_type="");
326
327         v2s32 padding;
328         v2f32 spacing;
329         v2s32 imgsize;
330         v2s32 offset;
331         v2f32 pos_offset;
332         std::stack<v2f32> container_stack;
333
334         InventoryManager *m_invmgr;
335         ISimpleTextureSource *m_tsrc;
336         Client *m_client;
337
338         std::string m_formspec_string;
339         std::string m_formspec_prepend;
340         InventoryLocation m_current_inventory_location;
341
342         std::vector<ListDrawSpec> m_inventorylists;
343         std::vector<ListRingSpec> m_inventory_rings;
344         std::vector<gui::IGUIElement *> m_backgrounds;
345         std::unordered_map<std::string, bool> field_close_on_enter;
346         std::vector<FieldSpec> m_fields;
347         std::vector<std::pair<FieldSpec, GUITable *>> m_tables;
348         std::vector<std::pair<FieldSpec, gui::IGUICheckBox *>> m_checkboxes;
349         std::map<std::string, TooltipSpec> m_tooltips;
350         std::vector<std::pair<gui::IGUIElement *, TooltipSpec>> m_tooltip_rects;
351         std::vector<std::pair<FieldSpec, GUIScrollBar *>> m_scrollbars;
352         std::vector<std::pair<FieldSpec, std::vector<std::string>>> m_dropdowns;
353
354         ItemSpec *m_selected_item = nullptr;
355         u16 m_selected_amount = 0;
356         bool m_selected_dragging = false;
357         ItemStack m_selected_swap;
358
359         gui::IGUIStaticText *m_tooltip_element = nullptr;
360
361         u64 m_tooltip_show_delay;
362         bool m_tooltip_append_itemname;
363         u64 m_hovered_time = 0;
364         s32 m_old_tooltip_id = -1;
365
366         bool m_auto_place = false;
367
368         bool m_allowclose = true;
369         bool m_lock = false;
370         v2u32 m_lockscreensize;
371
372         bool m_bgfullscreen;
373         bool m_slotborder;
374         video::SColor m_bgcolor;
375         video::SColor m_fullscreen_bgcolor;
376         video::SColor m_slotbg_n;
377         video::SColor m_slotbg_h;
378         video::SColor m_slotbordercolor;
379         video::SColor m_default_tooltip_bgcolor;
380         video::SColor m_default_tooltip_color;
381
382         
383 private:
384         IFormSource        *m_form_src;
385         TextDest           *m_text_dst;
386         u16                 m_formspec_version = 1;
387         std::string         m_focused_element = "";
388         JoystickController *m_joystick;
389
390         typedef struct {
391                 bool explicit_size;
392                 bool real_coordinates;
393                 u8 simple_field_count;
394                 v2f invsize;
395                 v2s32 size;
396                 v2f32 offset;
397                 v2f32 anchor;
398                 core::rect<s32> rect;
399                 v2s32 basepos;
400                 v2u32 screensize;
401                 std::string focused_fieldname;
402                 GUITable::TableOptions table_options;
403                 GUITable::TableColumns table_columns;
404                 // used to restore table selection/scroll/treeview state
405                 std::unordered_map<std::string, GUITable::DynamicData> table_dyndata;
406         } parserData;
407
408         typedef struct {
409                 bool key_up;
410                 bool key_down;
411                 bool key_enter;
412                 bool key_escape;
413         } fs_key_pendig;
414
415         fs_key_pendig current_keys_pending;
416         std::string current_field_enter_pending = "";
417
418         void parseElement(parserData* data, const std::string &element);
419
420         void parseSize(parserData* data, const std::string &element);
421         void parseContainer(parserData* data, const std::string &element);
422         void parseContainerEnd(parserData* data);
423         void parseList(parserData* data, const std::string &element);
424         void parseListRing(parserData* data, const std::string &element);
425         void parseCheckbox(parserData* data, const std::string &element);
426         void parseImage(parserData* data, const std::string &element);
427         void parseItemImage(parserData* data, const std::string &element);
428         void parseButton(parserData* data, const std::string &element,
429                         const std::string &typ);
430         void parseBackground(parserData* data, const std::string &element);
431         void parseTableOptions(parserData* data, const std::string &element);
432         void parseTableColumns(parserData* data, const std::string &element);
433         void parseTable(parserData* data, const std::string &element);
434         void parseTextList(parserData* data, const std::string &element);
435         void parseDropDown(parserData* data, const std::string &element);
436         void parseFieldCloseOnEnter(parserData *data, const std::string &element);
437         void parsePwdField(parserData* data, const std::string &element);
438         void parseField(parserData* data, const std::string &element, const std::string &type);
439         void createTextField(parserData *data, FieldSpec &spec,
440                 core::rect<s32> &rect, bool is_multiline);
441         void parseSimpleField(parserData* data,std::vector<std::string> &parts);
442         void parseTextArea(parserData* data,std::vector<std::string>& parts,
443                         const std::string &type);
444         void parseHyperText(parserData *data, const std::string &element);
445         void parseLabel(parserData* data, const std::string &element);
446         void parseVertLabel(parserData* data, const std::string &element);
447         void parseImageButton(parserData* data, const std::string &element,
448                         const std::string &type);
449         void parseItemImageButton(parserData* data, const std::string &element);
450         void parseTabHeader(parserData* data, const std::string &element);
451         void parseBox(parserData* data, const std::string &element);
452         void parseBackgroundColor(parserData* data, const std::string &element);
453         void parseListColors(parserData* data, const std::string &element);
454         void parseTooltip(parserData* data, const std::string &element);
455         bool parseVersionDirect(const std::string &data);
456         bool parseSizeDirect(parserData* data, const std::string &element);
457         void parseScrollBar(parserData* data, const std::string &element);
458         bool parsePositionDirect(parserData *data, const std::string &element);
459         void parsePosition(parserData *data, const std::string &element);
460         bool parseAnchorDirect(parserData *data, const std::string &element);
461         void parseAnchor(parserData *data, const std::string &element);
462         bool parseStyle(parserData *data, const std::string &element, bool style_type);
463
464         void tryClose();
465
466         void showTooltip(const std::wstring &text, const irr::video::SColor &color,
467                 const irr::video::SColor &bgcolor);
468
469         /**
470          * In formspec version < 2 the elements were not ordered properly. Some element
471          * types were drawn before others.
472          * This function sorts the elements in the old order for backwards compatibility.
473          */
474         void legacySortElements(core::list<IGUIElement *>::Iterator from);
475
476         /**
477          * check if event is part of a double click
478          * @param event event to evaluate
479          * @return true/false if a doubleclick was detected
480          */
481         bool DoubleClickDetection(const SEvent event);
482
483         struct clickpos
484         {
485                 v2s32 pos;
486                 s64 time;
487         };
488         clickpos m_doubleclickdetect[2];
489
490         int m_btn_height;
491         gui::IGUIFont *m_font = nullptr;
492
493         /* If true, remap a double-click (or double-tap) action to ESC. This is so
494          * that, for example, Android users can double-tap to close a formspec.
495         *
496          * This value can (currently) only be set by the class constructor
497          * and the default value for the setting is true.
498          */
499         bool m_remap_dbl_click;
500 };
501
502 class FormspecFormSource: public IFormSource
503 {
504 public:
505         FormspecFormSource(const std::string &formspec):
506                 m_formspec(formspec)
507         {
508         }
509
510         ~FormspecFormSource() = default;
511
512         void setForm(const std::string &formspec)
513         {
514                 m_formspec = formspec;
515         }
516
517         const std::string &getForm() const
518         {
519                 return m_formspec;
520         }
521
522         std::string m_formspec;
523 };