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