The Battle for Wesnoth  1.17.4+dev
modal_dialog.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008 - 2022
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 #define GETTEXT_DOMAIN "wesnoth-lib"
17 
19 
20 #include "cursor.hpp"
21 #include "gui/auxiliary/field.hpp"
25 #include "video.hpp"
26 
27 namespace gui2::dialogs
28 {
30  : window_(nullptr)
31  , retval_(retval::NONE)
32  , always_save_fields_(false)
33  , fields_()
34  , focus_()
35  , restore_(false)
36  , allow_plugin_skip_(true)
37  , show_even_without_video_(false)
38 {
39 }
40 
42 {
43 }
44 
45 namespace {
46  struct window_stack_handler {
47  window_stack_handler(std::unique_ptr<window>& win) : local_window(win) {
48  open_window_stack.push_back(local_window.get());
49  }
50  ~window_stack_handler() {
52  }
53  std::unique_ptr<window>& local_window;
54  };
55 }
56 
57 bool modal_dialog::show(const unsigned auto_close_time)
58 {
60  if(!allow_plugin_skip_) {
61  return false;
62  }
63 
65  if (pm && pm->any_running())
66  {
67  plugins_context pc("Dialog");
68  pc.set_callback("skip_dialog", [this](config) { retval_ = retval::OK; }, false);
69  pc.set_callback("quit", [](config) {}, false);
70  pc.play_slice();
71  }
72 
73  return false;
74  }
75 
77  assert(window_.get());
78 
80 
81  window_->set_owner(this);
82 
84 
85  pre_show(*window_);
86 
87  { // Scope the window stack
89  window_stack_handler push_window_stack(window_);
90  retval_ = window_->show(restore_, auto_close_time);
91  }
92 
93  /*
94  * It can happen that when two clicks follow each other fast that the event
95  * handling code in events.cpp generates a DOUBLE_CLICK_EVENT. For some
96  * reason it can happen that this event gets pushed in the queue when the
97  * window is shown, but processed after the window is closed. This causes
98  * the next window to get this pending event.
99  *
100  * This caused a bug where double clicking in the campaign selection dialog
101  * directly selected a difficulty level and started the campaign. In order
102  * to avoid that problem, filter all pending DOUBLE_CLICK_EVENT events after
103  * the window is closed.
104  */
105  SDL_FlushEvent(DOUBLE_CLICK_EVENT);
106 
108 
109  post_show(*window_);
110 
111  // post_show may have updated the window retval. Update it here.
112  retval_ = window_->get_retval();
113 
114  // Reset window object.
115  window_.reset(nullptr);
116 
117  return retval_ == retval::OK;
118 }
119 
121 {
122  if(window_) {
123  window_->set_retval(retval);
124  }
125 }
126 
127 template<typename T, typename... Args>
129 {
130  static_assert(std::is_base_of_v<field_base, T>, "Type is not a field type");
131  auto field = std::make_unique<T>(std::forward<Args>(args)...);
132  T* res = field.get();
133  fields_.push_back(std::move(field));
134  return res;
135 }
136 
138  const std::string& id,
139  const bool mandatory,
140  const std::function<bool()> callback_load_value,
141  const std::function<void(bool)> callback_save_value,
142  const std::function<void(widget&)> callback_change,
143  const bool initial_fire)
144 {
145  field_bool* field = new field_bool(id,
146  mandatory,
147  callback_load_value,
148  callback_save_value,
149  callback_change,
150  initial_fire);
151 
152  fields_.emplace_back(field);
153  return field;
154 }
155 
156 field_bool*
157 modal_dialog::register_bool(const std::string& id,
158  const bool mandatory,
159  bool& linked_variable,
160  const std::function<void(widget&)> callback_change,
161  const bool initial_fire)
162 {
164  = new field_bool(id, mandatory, linked_variable, callback_change, initial_fire);
165 
166  fields_.emplace_back(field);
167  return field;
168 }
169 
171  const std::string& id,
172  const bool mandatory,
173  const std::function<int()> callback_load_value,
174  const std::function<void(const int)> callback_save_value)
175 {
177  id, mandatory, callback_load_value, callback_save_value);
178 
179  fields_.emplace_back(field);
180  return field;
181 }
182 
184  const bool mandatory,
185  int& linked_variable)
186 {
187  field_integer* field = new field_integer(id, mandatory, linked_variable);
188 
189  fields_.emplace_back(field);
190  return field;
191 }
192 
194  const std::string& id,
195  const bool mandatory,
196  const std::function<std::string()> callback_load_value,
197  const std::function<void(const std::string&)> callback_save_value,
198  const bool capture_focus)
199 {
200  field_text* field = new field_text(
201  id, mandatory, callback_load_value, callback_save_value);
202 
203  if(capture_focus) {
204  focus_ = id;
205  }
206 
207  fields_.emplace_back(field);
208  return field;
209 }
210 
212  const bool mandatory,
213  std::string& linked_variable,
214  const bool capture_focus)
215 {
216  field_text* field = new field_text(id, mandatory, linked_variable);
217 
218  if(capture_focus) {
219  focus_ = id;
220  }
221 
222  fields_.emplace_back(field);
223  return field;
224 }
225 
227  const bool mandatory,
228  const std::string& text,
229  const bool use_markup)
230 {
231  field_label* field = new field_label(id, mandatory, text, use_markup);
232 
233  fields_.emplace_back(field);
234  return field;
235 }
236 
237 std::unique_ptr<window> modal_dialog::build_window() const
238 {
239  return build(window_id());
240 }
241 
243 {
244  /* DO NOTHING */
245 }
246 
248 {
249  /* DO NOTHING */
250 }
251 
253 {
254  /* DO NOTHING */
255 }
256 
258 {
259  for(auto& field : fields_)
260  {
261  field->attach_to_window(window);
262  field->widget_init();
263  }
264 
265  if(!focus_.empty()) {
266  if(widget* widget = window.find(focus_, false)) {
267  window.keyboard_capture(widget);
268  }
269  }
270 }
271 
272 void modal_dialog::finalize_fields(const bool save_fields)
273 {
274  for(auto& field : fields_)
275  {
276  if(save_fields) {
278  }
280  }
281 }
282 
283 } // namespace dialogs
T * register_field(Args &&... args)
Creates a new field of given type with given arguments.
void keyboard_capture(widget *widget)
Definition: window.cpp:1253
void set_callback(const std::string &name, callback_function)
Definition: context.cpp:52
void attach_to_window(window &window)
Attaches the field to a window.
Definition: field.hpp:75
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:488
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
bool allow_plugin_skip_
Allow plugins to skip through the dialog? Most dialogs install a plugins context to allow plugins to ...
static CVideo & get_singleton()
Definition: video.hpp:52
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.
Implements some helper classes to ease adding fields to a dialog and hide the synchronization needed...
bool always_save_fields_
Always save the fields upon closing.
bool show(const unsigned auto_close_time=0)
Shows the window.
field< int, integer_selector > field_integer
Definition: field-fwd.hpp:37
void detach_from_window()
Detaches the field from a window.
Definition: field.hpp:125
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.
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.
void remove_from_window_stack(window *window)
Removes a entry from the open_window_stack list.
Definition: handler.cpp:1106
void widget_finalize()
Finalizes the widget.
Definition: field.hpp:114
widget * find(const std::string &id, const bool must_be_active) override
See widget::find.
Definition: window.cpp:816
std::string id
Text to match against addon_info.tags()
Definition: manager.cpp:215
#define DOUBLE_CLICK_EVENT
Definition: events.hpp:24
virtual void init_fields(window &window)
Initializes all fields in the dialog and set the keyboard focus.
Default, unset return value.
Definition: retval.hpp:32
virtual void finalize_fields(const bool save_fields)
When the dialog is closed with the OK status saves all fields.
Specialized field class for a styled_widget, used for labels and images.
Definition: field.hpp:568
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.
bool any_running()
Definition: manager.cpp:207
int retval_
The window&#39;s exit code (return value).
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.
void widget_init()
Initializes the widget.
Definition: field.hpp:97
retval
Default window/dialog return values.
Definition: retval.hpp:29
std::unique_ptr< window > build(const builder_window::window_resolution &definition)
Builds a window.
Dialog was closed with the OK button.
Definition: retval.hpp:35
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.
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:60
Specialized field class for text.
Definition: field.hpp:536
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
static plugins_manager * get()
Definition: manager.cpp:59
void play_slice()
Definition: context.cpp:97
std::vector< window * > open_window_stack
Keeps track of any open windows of any type (modal, non-modal, or tooltip) in the order in which they...
Definition: handler.cpp:1104