The Battle for Wesnoth  1.17.0-dev
modal_dialog.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008 - 2021
3  by Mark de Wever <koraq@xs4all.nl>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 #pragma once
17 
20 #include <functional>
21 
22 #include <string>
23 #include <vector>
24 
25 namespace gui2::dialogs
26 {
27 /**
28  * Registers a window.
29  *
30  * This function registers a window. The registration is used to validate
31  * whether the config for the window exists when starting Wesnoth.
32  *
33  * @note Most of the time you want to call @ref REGISTER_DIALOG instead of this
34  * function. It also directly adds the code for the dialog's id function.
35  *
36  * @param id Id of the window, multiple dialogs can use
37  * the same window so the id doesn't need to be
38  * unique.
39  */
40 #define REGISTER_WINDOW(id) \
41  namespace \
42  { \
43  namespace ns_##id \
44  { \
45  struct register_helper \
46  { \
47  register_helper() \
48  { \
49  register_window(#id); \
50  } \
51  }; \
52  \
53  struct register_helper register_helper; \
54  } \
55  }
56 
57 /**
58  * Registers a window for a dialog.
59  *
60  * Call this function to register a window. In the header of the class it adds
61  * the following code:
62  *@code
63  * virtual const std::string& id() const;
64  *@endcode
65  * Then use this macro in the implementation, inside the gui2 namespace.
66  *
67  * @note When the @p id is "foo" and the type tfoo it's easier to use
68  * REGISTER_DIALOG(foo).
69  *
70  * @param type Class type of the window to register.
71  * @param id Id of the window, multiple dialogs can use
72  * the same window so the id doesn't need to be
73  * unique.
74  */
75 #define REGISTER_DIALOG2(type, id) \
76  REGISTER_WINDOW(id) const std::string& type::window_id() const \
77  { \
78  static const std::string result(#id); \
79  return result; \
80  }
81 
82 /**
83  * Wrapper for REGISTER_DIALOG2.
84  *
85  * "Calls" REGISTER_DIALOG2(window_id, window_id)
86  */
87 #define REGISTER_DIALOG(window_id) REGISTER_DIALOG2(window_id, window_id)
88 
89 /**
90  * Adds a bare-bones static `display` function to a dialog class that immediately
91  * invokes the dialogs's modal_dialog::show function. If more complex behavior
92  * is desired, the function should be defined manually.
93  *
94  * See the modal_dialog documentation (below) for more info.
95  */
96 #define DEFINE_SIMPLE_DISPLAY_WRAPPER(dialog) \
97  template<typename... T> \
98  static void display(T&&... args) \
99  { \
100  dialog(std::forward<T>(args)...).show(); \
101  }
102 
103 /**
104  * Adds a bare-bonesstatic `execute` function to a dialog class that immediately
105  * invokes and return the result of the dialogs's modal_dialog::show function.
106  * If more complex behavior is desired, the function should be defined manually.
107  *
108  * See the modal_dialog documentation (below) for more info.
109  */
110 #define DEFINE_SIMPLE_EXECUTE_WRAPPER(dialog) \
111  template<typename... T> \
112  static bool execute(T&&... args) \
113  { \
114  return dialog(std::forward<T>(args)...).show(); \
115  }
116 
117 /**
118  * Abstract base class for all modal dialogs.
119  *
120  * A dialog shows a certain window instance to the user. The subclasses of this
121  * class will hold the parameters used for a certain window, eg a server
122  * connection dialog will hold the name of the selected server as parameter that
123  * way the caller doesn't need to know about the 'contents' of the window.
124  *
125  * @par Usage
126  *
127  * Simple dialogs that are shown to query user information it is recommended to
128  * add a static member called @p execute. The parameters to the function are:
129  * - references to in + out parameters by reference
130  * - references to the in parameters
131  * - the parameters for @ref modal_dialog::show.
132  *
133  * The 'in + out parameters' are used as initial value and final value when the
134  * OK button is pressed. The 'in parameters' are just extra parameters for
135  * showing.
136  *
137  * When a function only has 'in parameters' it should return a void value and
138  * the function should be called @p display, if it has 'in + out parameters' it
139  * must return a bool value. This value indicates whether or not the OK button
140  * was pressed to close the dialog. See editor_new_map::execute for an
141  * example.
142  */
144 {
145  /**
146  * Special helper function to get the id of the window.
147  *
148  * This is used in the unit tests, but these implementation details
149  * shouldn't be used in the normal code.
150  */
151  friend std::string unit_test_mark_as_tested(const modal_dialog& dialog);
152 
153 public:
154  modal_dialog();
155 
156  virtual ~modal_dialog();
157 
158  /**
159  * Shows the window.
160  *
161  * @param auto_close_time The time in ms after which the dialog will
162  * automatically close, if 0 it doesn't close.
163  * @note the timeout is a minimum time and
164  * there's no guarantee about how fast it closes
165  * after the minimum.
166  *
167  * @returns Whether the final retval_ == retval::OK
168  */
169  bool show(const unsigned auto_close_time = 0);
170 
171  /***** ***** ***** setters / getters for members ***** ****** *****/
172 
173  /** Returns a pointer to the dialog's window. Will be null if it hasn't been built yet. */
175  {
176  return window_.get();
177  }
178 
179  /** Returns the cached window exit code. */
180  int get_retval() const
181  {
182  return retval_;
183  }
184 
185  /** Convenience wrapper to set the window's exit code. */
186  void set_retval(int retval);
187 
188  void set_always_save_fields(const bool always_save_fields)
189  {
190  always_save_fields_ = always_save_fields;
191  }
192 
193  void set_restore(const bool restore)
194  {
195  restore_ = restore;
196  }
197 
198  void set_allow_plugin_skip(const bool allow_plugin_skip)
199  {
200  allow_plugin_skip_ = allow_plugin_skip;
201  }
202 
203  void set_show_even_without_video(const bool show_even_without_video)
204  {
205  show_even_without_video_ = show_even_without_video;
206  }
207 
208 protected:
209  /**
210  * Creates a new boolean field.
211  *
212  * The field created is owned by modal_dialog, the returned pointer can be used
213  * in the child classes as access to a field.
214  *
215  * @param id Id of the widget, same value as in WML.
216  * @param mandatory Is the widget mandatory or mandatory.
217  * @param callback_load_value The callback function to set the initial value
218  * of the widget.
219  * @param callback_save_value The callback function to write the resulting
220  * value of the widget. Saving will only happen
221  * if the widget is enabled and the window closed
222  * with ok.
223  * @param callback_change When the value of the widget changes this
224  * callback is called.
225  * @param initial_fire
226  *
227  * @returns Pointer to the created widget.
228  */
229  field_bool*
230  register_bool(const std::string& id,
231  const bool mandatory,
232  const std::function<bool()> callback_load_value = nullptr,
233  const std::function<void(bool)> callback_save_value = nullptr,
234  const std::function<void(widget&)> callback_change = nullptr,
235  const bool initial_fire = false);
236 
237  /**
238  * Creates a new boolean field.
239  *
240  * The field created is owned by modal_dialog, the returned pointer can be used
241  * in the child classes as access to a field.
242  *
243  * @param id Id of the widget, same value as in WML.
244  * @param mandatory Is the widget mandatory or mandatory.
245  * @param linked_variable The variable the widget is linked to. See
246  * @ref field::field for more information.
247  * @param callback_change When the value of the widget changes this
248  * callback is called.
249  * @param initial_fire
250  *
251  * @returns Pointer to the created widget.
252  */
253  field_bool*
254  register_bool(const std::string& id,
255  const bool mandatory,
256  bool& linked_variable,
257  const std::function<void(widget&)> callback_change = nullptr,
258  const bool initial_fire = false);
259 
260  /**
261  * Creates a new integer field.
262  *
263  * See @ref register_bool for more info.
264  */
266  register_integer(const std::string& id,
267  const bool mandatory,
268  const std::function<int()> callback_load_value = nullptr,
269  const std::function<void(int)> callback_save_value = nullptr);
270 
271  /**
272  * Creates a new integer field.
273  *
274  * See @ref register_bool for more info.
275  */
276  field_integer* register_integer(const std::string& id,
277  const bool mandatory,
278  int& linked_variable);
279  /**
280  * Creates a new text field.
281  *
282  * See @ref register_bool for more info.
283  */
285  const std::string& id,
286  const bool mandatory,
287  const std::function<std::string()> callback_load_value = nullptr,
288  const std::function<void(const std::string&)> callback_save_value = nullptr,
289  const bool capture_focus = false);
290 
291  /**
292  * Creates a new text field.
293  *
294  * See @ref register_bool for more info.
295  */
296  field_text* register_text(const std::string& id,
297  const bool mandatory,
298  std::string& linked_variable,
299  const bool capture_focus = false);
300 
301  /**
302  * Registers a new styled_widget as a label.
303  *
304  * The label is used for a styled_widget to set the 'label' since it calls the
305  * @ref styled_widget::set_label it can also be used for the @ref image since
306  * there this sets the filename. (The @p use_markup makes no sense in an
307  * image but that's a detail.)
308  *
309  * @note In general it's preferred a widget sets its markup flag in WML, but
310  * some generic windows (like messages) may need different versions
311  * depending on where used.
312  *
313  * @param id Id of the widget, same value as in WML.
314  * @param mandatory Is the widget mandatory or optional.
315  * @param text The text for the label.
316  * @param use_markup Whether or not use markup for the label.
317  */
318  field_label* register_label(const std::string& id,
319  const bool mandatory,
320  const std::string& text,
321  const bool use_markup = false);
322 
323  /** Registers a new styled_widget as image. */
324  field_label* register_image(const std::string& id,
325  const bool mandatory,
326  const std::string& filename)
327  {
328  return register_label(id, mandatory, filename);
329  }
330 
331 protected:
332  /** The window object build for this dialog. */
333  std::unique_ptr<window> window_;
334 
335 private:
336  /**
337  * The window's exit code (return value).
338  *
339  * We keep a copy here so it may be accessed even after the dialog is closed and
340  * the window object is destroyed.
341  *
342  * This value is initially set to 0 (retval::NONE) meaning the dialog was not
343  * shown. After @ref show returns, it will hold the most recent retval of the
344  * window object, including any modifications made in @ref post_show.
345  */
346  int retval_;
347 
348  /**
349  * Always save the fields upon closing.
350  *
351  * Normally fields are only saved when the retval::OK button is pressed.
352  * With this flag set is always saves. Be careful with the flag since it
353  * also updates upon canceling, which can be a problem when the field sets
354  * a preference.
355  */
357 
358  /**
359  * Contains the automatically managed fields.
360  *
361  * Since the fields are automatically managed and there are no search
362  * functions defined we don't offer access to the vector. If access is
363  * needed the creator should store a copy of the pointer.
364  */
365  std::vector<std::unique_ptr<class field_base>> fields_;
366 
367  /**
368  * Contains the widget that should get the focus when the window is shown.
369  */
370  std::string focus_;
371 
372  /**
373  * Restore the screen after showing?
374  *
375  * Most windows should restore the display after showing so this value
376  * defaults to true. Toplevel windows (like the titlescreen don't want this
377  * behavior so they can change it in pre_show().
378  */
379  bool restore_;
380 
381  /**
382  * Allow plugins to skip through the dialog?
383  * Most dialogs install a plugins context to allow plugins to accept whatever the dialog is offering
384  * and continue. Some dialogs, especially those that install their own plugins context, may want to
385  * disable this.
386  */
388 
389  /**
390  * Show the dialog even with --nogui?
391  * Some dialogs need to be shown even when --nogui is specified if the game is being driven by a plugin.
392  * Those dialogs allow the plugin to styled_widget them by creating a plugin context in pre_show().
393  */
395 
396  /** The id of the window to build. */
397  virtual const std::string& window_id() const = 0;
398 
399  /**
400  * Builds the window.
401  *
402  * Every dialog shows it's own kind of window, this function should return
403  * the window to show.
404  *
405  * @returns The window to show.
406  */
407  std::unique_ptr<window> build_window() const;
408 
409  /**
410  * Actions to be taken directly after the window is build.
411  *
412  * At this point the registered fields are not yet registered.
413  *
414  * @param window The window just created.
415  */
416  virtual void post_build(window& window);
417 
418  /**
419  * Actions to be taken before showing the window.
420  *
421  * At this point the registered fields are registered and initialized with
422  * their initial values.
423  *
424  * @param window The window to be shown.
425  */
426  virtual void pre_show(window& window);
427 
428  /**
429  * Actions to be taken after the window has been shown.
430  *
431  * At this point the registered fields already stored their values (if the
432  * OK has been pressed).
433  *
434  * @param window The window which has been shown.
435  */
436  virtual void post_show(window& window);
437 
438  /**
439  * Initializes all fields in the dialog and set the keyboard focus.
440  *
441  * @param window The window which has been shown.
442  */
443  virtual void init_fields(window& window);
444 
445  /**
446  * When the dialog is closed with the OK status saves all fields.
447  *
448  * Saving only happens if a callback handler is installed.
449  *
450  * @param window The window which has been shown.
451  * @param save_fields Does the value in the fields need to be saved?
452  */
453  virtual void finalize_fields(window& window, const bool save_fields);
454 };
455 
456 } // namespace dialogs
bool show_even_without_video_
Show the dialog even with –nogui? Some dialogs need to be shown even when –nogui is specified if th...
Specialized field class for boolean.
Definition: field.hpp:545
virtual void post_build(window &window)
Actions to be taken directly after the window is build.
Base class for all widgets.
Definition: widget.hpp:49
virtual void finalize_fields(window &window, const bool save_fields)
When the dialog is closed with the OK status saves all fields.
bool allow_plugin_skip_
Allow plugins to skip through the dialog? Most dialogs install a plugins context to allow plugins to ...
window * get_window() const
Returns a pointer to the dialog&#39;s window.
field_bool * register_bool(const std::string &id, const bool mandatory, const std::function< bool()> callback_load_value=nullptr, const std::function< void(bool)> callback_save_value=nullptr, const std::function< void(widget &)> callback_change=nullptr, const bool initial_fire=false)
Creates a new boolean field.
bool always_save_fields_
Always save the fields upon closing.
bool show(const unsigned auto_close_time=0)
Shows the window.
field_text * register_text(const std::string &id, const bool mandatory, const std::function< std::string()> callback_load_value=nullptr, const std::function< void(const std::string &)> callback_save_value=nullptr, const bool capture_focus=false)
Creates a new text field.
std::vector< std::unique_ptr< class field_base > > fields_
Contains the automatically managed fields.
void set_show_even_without_video(const bool show_even_without_video)
bool restore_
Restore the screen after showing?
field_integer * register_integer(const std::string &id, const bool mandatory, const std::function< int()> callback_load_value=nullptr, const std::function< void(int)> callback_save_value=nullptr)
Creates a new integer field.
Contains all forward declarations for field.hpp.
virtual void init_fields(window &window)
Initializes all fields in the dialog and set the keyboard focus.
friend std::string unit_test_mark_as_tested(const modal_dialog &dialog)
Special helper function to get the id of the window.
Definition: test_gui2.cpp:142
Specialized field class for a styled_widget, used for labels and images.
Definition: field.hpp:627
field_label * register_label(const std::string &id, const bool mandatory, const std::string &text, const bool use_markup=false)
Registers a new styled_widget as a label.
virtual const std::string & window_id() const =0
The id of the window to build.
int get_retval() const
Returns the cached window exit code.
int retval_
The window&#39;s exit code (return value).
void set_allow_plugin_skip(const bool allow_plugin_skip)
std::unique_ptr< window > window_
The window object build for this dialog.
std::unique_ptr< window > build_window() const
Builds the window.
virtual void pre_show(window &window)
Actions to be taken before showing the window.
Abstract base class for all modal dialogs.
retval
Default window/dialog return values.
Definition: retval.hpp:29
virtual void post_show(window &window)
Actions to be taken after the window has been shown.
std::string focus_
Contains the widget that should get the focus when the window is shown.
field_label * register_image(const std::string &id, const bool mandatory, const std::string &filename)
Registers a new styled_widget as image.
Specialized field class for text.
Definition: field.hpp:593
void set_retval(int retval)
Convenience wrapper to set the window&#39;s exit code.
base class of top level items, the only item which needs to store the final canvases to draw on...
Definition: window.hpp:65
Template class to implement the generic field implementation.
Definition: field-fwd.hpp:36
void set_restore(const bool restore)
void set_always_save_fields(const bool always_save_fields)