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