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