The Battle for Wesnoth  1.19.0-dev
field.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008 - 2024
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 /**
17  * @file
18  * Implements some helper classes to ease adding fields to a dialog and hide
19  * the synchronization needed. Since some templates are used all is stored in
20  * the header.
21  *
22  */
23 
24 #pragma once
25 
30 #include "gui/widgets/text_box.hpp"
31 #include "gui/widgets/window.hpp"
32 
33 namespace gui2
34 {
35 
36 /**
37  * Abstract base class for the fields.
38  *
39  * @note In this context a widget is a @ref gui2::styled_widget and not a @ref
40  * gui2::widget. This name widget is a generic name and fits, however some
41  * functions used are first declared in a styled_widget.
42  */
44 {
45 public:
46  /**
47  * Constructor.
48  *
49  * @param id The id of the widget to connect to the window.
50  * A widget can only be connected once.
51  * @param mandatory Is the widget mandatory
52  */
53  field_base(const std::string& id, const bool mandatory)
54  : id_(id), mandatory_(mandatory), widget_(nullptr)
55  {
56  }
57 
58  virtual ~field_base()
59  {
60  }
61 
62  /**
63  * Attaches the field to a window.
64  *
65  * When attached the widget which we're a wrapper around is stored linked
66  * in here.
67  *
68  * @warning After attaching the window must remain a valid. Before the
69  * window is destroyed the @ref detach_from_window function must be called.
70  *
71  * @pre widget_ == nullptr
72  *
73  * @param window The window to be attached to.
74  */
76  {
77  assert(!widget_);
78  widget_ = find_widget<styled_widget>(&window, id(), false, mandatory_);
79  }
80 
81  /**
82  * Initializes the widget.
83  *
84  * This routine is called before the dialog is shown and the pre_show() is
85  * called. So the user can override the values set. This routine does the
86  * following:
87  * - If no widget available exit gives feedback it the widget must exist.
88  * - If a getter is defined we use to set value_ and the widget.
89  * - If no setter is defined we use the widget value to set value_.
90  *
91  * The function calls two functions
92  * - init_generic which is to be used in the template subclass.
93  * - init_specialized which is to be used in subclasses of the template
94  * class. This way they can override this function without to use their
95  * signature to inherit.
96  */
97  void widget_init()
98  {
99  init_generic();
101  }
102 
103  /**
104  * Finalizes the widget.
105  *
106  * This routine is called after the dialog is closed with OK. It's called
107  * before post_show(). This routine does the following:
108  * - if no active widget available exit.
109  * - if a setter is defined the widget value is saved in the setter.
110  * - The widget value is saved in value_.
111  *
112  * Like widget_init it calls two functions with the same purpose.
113  */
115  {
118  }
119 
120  /**
121  * Detaches the field from a window.
122  *
123  * @pre widget_ != nullptr || !mandatory_
124  */
126  {
127  assert(!mandatory_ || widget_);
128  widget_ = nullptr;
129  }
130 
131  /**
132  * Saves a widget.
133  *
134  * It can be a window must be recreated, in that case the state needs to be
135  * saved and restored. This routine does the following:
136  * - if no widget available exit (doesn't look at the active state).
137  * - The widget value is saved in value_.
138  */
139  virtual void widget_save() = 0;
140 
141  /**
142  * Restores a widget.
143  *
144  * See widget_save for more info.
145  */
146  virtual void widget_restore() = 0;
147 
148  /**
149  * Enables a widget.
150  *
151  * @param enable If true enables the widget, disables
152  * otherwise.
153  * @param sync If the state is changed do we need to
154  * synchronize. Upon disabling, write the value
155  * of the widget in the variable value_. Upon
156  * enabling write the value of value_ in the
157  * widget.
158  */
159  void widget_set_enabled(const bool enable, const bool sync)
160  {
161  if(!get_widget()) {
162  return;
163  }
164 
165  const bool widget_state = get_widget()->get_active();
166  if(widget_state == enable) {
167  return;
168  }
169 
170  if(sync) {
171  if(enable) {
172  widget_restore();
173  } else {
174  widget_save();
175  }
176  }
177 
178  get_widget()->set_active(enable);
179  }
180 
181  /***** ***** ***** setters / getters for members ***** ****** *****/
182 
183  const std::string& id() const
184  {
185  return id_;
186  }
187 
188  bool is_mandatory() const
189  {
190  return mandatory_;
191  }
192 
194  {
195  return widget_;
196  }
197 
198  const styled_widget* get_widget() const
199  {
200  return widget_;
201  }
202 
203 private:
204  /** The id field of the widget, should be unique in a window. */
205  const std::string id_;
206 
207  /** Is the widget optional or mandatory in this window. */
208  const bool mandatory_;
209 
210  /** The widget attached to the field. */
212 
213  /** See widget_init. */
214  virtual void init_generic() = 0;
215 
216  /** See widget_init. */
217  virtual void init_specialized()
218  {
219  }
220 
221  /** See widget_finalize. */
222  virtual void finalize_generic() = 0;
223 
224  /** See widget_finalize. */
225  virtual void finalize_specialized()
226  {
227  }
228 };
229 
230 /**
231  * Template class to implement the generic field implementation.
232  *
233  * @tparam T The type of the item to show in the widget.
234  * @tparam W The type of widget to show, this is not a
235  * widget class but a behavior class.
236  * @tparam CT The type tp be used in the
237  * callback_save_value callback. Normally this
238  * is const T but for example with strings it
239  * can be const T&. Note the const needs to be
240  * in the template otherwise compilation on
241  * GCC-4.3 fails (not sure whether compiler bug
242  * or not).
243  */
244 template <class T, class W, class CT>
245 class field : public field_base
246 {
247 public:
248  /**
249  * Constructor.
250  *
251  * @param id The id of the widget to connect to the window.
252  * A widget can only be connected once.
253  * @param mandatory Is the widget mandatory?
254  * @param callback_load_value A callback function which is called when the
255  * window is shown. This callback returns the
256  * initial value of the field.
257  * @param callback_save_value A callback function which is called when the
258  * window closed with the OK button. The
259  * callback is executed with the new value of
260  * the field. It's meant to set the value of
261  * some variable in the engine after the window
262  * is closed with OK.
263  */
264  field(const std::string& id,
265  const bool mandatory,
266  const std::function<T()>& callback_load_value,
267  const std::function<void(CT)>& callback_save_value)
268  : field_base(id, mandatory)
269  , value_(T())
270  , link_(value_)
271  , callback_load_value_(callback_load_value)
272  , callback_save_value_(callback_save_value)
273  {
274  static_assert(!std::is_same_v<styled_widget, W>, "Second template argument cannot be styled_widget");
275  }
276 
277  /**
278  * Constructor.
279  *
280  * @param id The id of the widget to connect to the window.
281  * A widget can only be connected once.
282  * @param mandatory Is the widget mandatory?
283  * @param linked_variable The variable which is linked to the field.
284  * * Upon loading its value is used as initial
285  * value of the widget.
286  * * Upon closing:
287  * * with OK its value is set to the value of
288  * the widget.
289  * * else, its value is undefined.
290  */
291  field(const std::string& id, const bool mandatory, T& linked_variable)
292  : field_base(id, mandatory)
293  , value_(T())
294  , link_(linked_variable)
295  , callback_load_value_(nullptr)
296  , callback_save_value_(nullptr)
297  {
298  static_assert(!std::is_same_v<styled_widget, W>, "Second template argument cannot be styled_widget");
299  }
300 
301  /**
302  * Constructor.
303  *
304  * This version is used for read only variables.
305  *
306  * @note The difference between this constructor and the one above is the
307  * sending of the third parameter as const ref instead of a non-const ref.
308  * So it feels a bit tricky. Since this constructor is only used for a
309  * the @ref styled_widget class and the other constructors not the issue is
310  * solved by using static asserts to test whether the proper constructor
311  * is used.
312  *
313  * @param mandatory Is the widget mandatory?
314  * @param id The id of the widget to connect to the window.
315  * A widget can only be connected once.
316  * @param value The value of the widget.
317  */
318  field(const std::string& id, const bool mandatory, const T& value)
319  : field_base(id, mandatory)
320  , value_(value)
321  , link_(value_)
322  , callback_load_value_(nullptr)
323  , callback_save_value_(nullptr)
324  {
325  static_assert(std::is_same_v<styled_widget, W>, "Second template argument must be styled_widget");
326  }
327 
328  /** Inherited from field_base. */
330  {
331  validate_widget();
332 
333  restore();
334  }
335 
336  /**
337  * Sets the value of the field.
338  *
339  * This sets the value in both the internal cache value and in the widget
340  * itself.
341  *
342  * @param value The new value.
343  */
344  void set_widget_value(CT value)
345  {
346  value_ = value;
347  restore();
348  }
349 
350  /**
351  * Sets the value of the field.
352  *
353  * This sets the internal cache value but not the widget value, this can
354  * be used to initialize the field.
355  *
356  * @param value The new value.
357  */
358  void set_cache_value(CT value)
359  {
360  value_ = value;
361  }
362 
363  /** Inherited from field_base. */
364  void widget_save()
365  {
366  save(false);
367  }
368 
369  /**
370  * Gets the value of the field.
371  *
372  * This function gets the value of the widget and stores that in the
373  * internal cache, then that value is returned.
374  *
375  * @deprecated Use references to a variable instead.
376  *
377  * @returns The current value of the widget.
378  */
380  {
381  save(false);
382  return value_;
383  }
384 
385 private:
386  /**
387  * The value_ of the widget, this value is also available once the widget
388  * is destroyed.
389  */
391 
392  /**
393  * The variable linked to the field.
394  *
395  * When set determines the initial value and the final value is stored here
396  * in the finalizer.
397  */
398  T& link_;
399 
400  /**
401  * The callback function to load the value.
402  *
403  * This is used to load the initial value of the widget, if defined.
404  */
405  std::function<T()> callback_load_value_;
406 
407  /** Inherited from field_base. */
409  {
410  validate_widget();
411 
414  } else {
415  value_ = link_;
416  }
417 
418  restore();
419  }
420 
421  /** Inherited from field_base. */
423  {
424  save(true);
425 
428  } else {
429  link_ = value_;
430  }
431  }
432 
433  /**
434  * The callback function to save the value.
435  *
436  * Once the dialog has been successful this function is used to store the
437  * result of this widget.
438  */
439  std::function<void(CT)> callback_save_value_;
440 
441  /**
442  * Test whether the widget exists if the widget is mandatory.
443  */
445  {
446  if(is_mandatory() && get_widget() == nullptr) {
447  throw std::runtime_error("Mandatory field widget is null");
448  }
449  }
450 
451  /**
452  * Stores the value in the widget in the interval value_.
453  *
454  * @param must_be_active If true only active widgets will store their value.
455  */
456  void save(const bool must_be_active)
457  {
458  if(auto* widget = dynamic_cast<W*>(get_widget())) {
459  // get_active is only defined for styled_widget so use the non-cast pointer
460  if(!must_be_active || get_widget()->get_active()) {
461  if constexpr(std::is_same_v<W, styled_widget>) {
462  value_ = widget->get_label();
463  } else if constexpr(std::is_same_v<W, selectable_item>) {
464  value_ = widget->get_value_bool();
465  } else {
466  value_ = widget->get_value();
467  }
468  }
469  }
470  }
471 
472  /**
473  * Stores the internal value_ in the widget.
474  */
475  void restore()
476  {
477  if(auto* widget = dynamic_cast<W*>(get_widget())) {
478  if constexpr(std::is_same_v<W, styled_widget>) {
479  widget->set_label(value_);
480  } else {
481  widget->set_value(value_);
482  }
483  }
484  }
485 };
486 
487 /** Specialized field class for boolean. */
488 class field_bool : public field<bool, selectable_item>
489 {
490 public:
491  field_bool(const std::string& id,
492  const bool mandatory,
493  const std::function<bool()>& callback_load_value,
494  const std::function<void(const bool)>& callback_save_value,
495  const std::function<void(widget&)>& callback_change,
496  const bool initial_fire)
497  : field<bool, gui2::selectable_item>(
498  id, mandatory, callback_load_value, callback_save_value)
499  , callback_change_(callback_change)
500  , initial_fire_(initial_fire)
501  {
502  }
503 
504  field_bool(const std::string& id,
505  const bool mandatory,
506  bool& linked_variable,
507  const std::function<void(widget&)>& callback_change,
508  const bool initial_fire)
509  : field<bool, gui2::selectable_item>(id, mandatory, linked_variable)
510  , callback_change_(callback_change)
511  , initial_fire_(initial_fire)
512  {
513  }
514 
515 private:
516  /** Overridden from field_base. */
518  {
519  if(callback_change_) {
520  if(widget* widget = get_widget()) {
521  if(initial_fire_) {
523  }
524 
525  connect_signal_notify_modified(*widget, std::bind(callback_change_, std::placeholders::_1));
526  }
527  }
528  }
529 
530  std::function<void(widget&)> callback_change_;
531 
532  const bool initial_fire_;
533 };
534 
535 /** Specialized field class for text. */
536 class field_text : public field<std::string, text_box_base, const std::string&>
537 {
538 public:
539  field_text(const std::string& id,
540  const bool mandatory,
541  const std::function<std::string()>& callback_load_value,
542  const std::function<void(const std::string&)>&
543  callback_save_value)
544  : field<std::string, text_box_base, const std::string&>(
545  id, mandatory, callback_load_value, callback_save_value)
546  {
547  }
548 
549  field_text(const std::string& id,
550  const bool mandatory,
551  std::string& linked_variable)
552  : field<std::string, text_box_base, const std::string&>(
553  id, mandatory, linked_variable)
554  {
555  }
556 
557 private:
558  /** Overridden from field_base. */
560  {
561  if(auto* widget = dynamic_cast<text_box*>(get_widget())) {
562  widget->save_to_history();
563  }
564  }
565 };
566 
567 /** Specialized field class for a styled_widget, used for labels and images. */
568 class field_label : public field<std::string, styled_widget, const std::string&>
569 {
570 public:
571  field_label(const std::string& id,
572  const bool mandatory,
573  const std::string& text,
574  const bool use_markup)
575  : field<std::string, styled_widget, const std::string&>(id, mandatory, text)
576  , use_markup_(use_markup)
577  {
578  }
579 
580 private:
581  /** Whether or not the label uses markup. */
583 
584  /** Overridden from field_base. */
586  {
588  }
589 };
590 
591 } // namespace gui2
Abstract base class for the fields.
Definition: field.hpp:44
void widget_finalize()
Finalizes the widget.
Definition: field.hpp:114
void widget_init()
Initializes the widget.
Definition: field.hpp:97
styled_widget * get_widget()
Definition: field.hpp:193
virtual void init_specialized()
See widget_init.
Definition: field.hpp:217
const std::string id_
The id field of the widget, should be unique in a window.
Definition: field.hpp:205
field_base(const std::string &id, const bool mandatory)
Constructor.
Definition: field.hpp:53
virtual void init_generic()=0
See widget_init.
const std::string & id() const
Definition: field.hpp:183
virtual void finalize_specialized()
See widget_finalize.
Definition: field.hpp:225
const styled_widget * get_widget() const
Definition: field.hpp:198
const bool mandatory_
Is the widget optional or mandatory in this window.
Definition: field.hpp:208
void detach_from_window()
Detaches the field from a window.
Definition: field.hpp:125
virtual void widget_restore()=0
Restores a widget.
void widget_set_enabled(const bool enable, const bool sync)
Enables a widget.
Definition: field.hpp:159
void attach_to_window(window &window)
Attaches the field to a window.
Definition: field.hpp:75
styled_widget * widget_
The widget attached to the field.
Definition: field.hpp:211
virtual void widget_save()=0
Saves a widget.
virtual void finalize_generic()=0
See widget_finalize.
bool is_mandatory() const
Definition: field.hpp:188
virtual ~field_base()
Definition: field.hpp:58
Specialized field class for boolean.
Definition: field.hpp:489
field_bool(const std::string &id, const bool mandatory, const std::function< bool()> &callback_load_value, const std::function< void(const bool)> &callback_save_value, const std::function< void(widget &)> &callback_change, const bool initial_fire)
Definition: field.hpp:491
const bool initial_fire_
Definition: field.hpp:532
field_bool(const std::string &id, const bool mandatory, bool &linked_variable, const std::function< void(widget &)> &callback_change, const bool initial_fire)
Definition: field.hpp:504
std::function< void(widget &)> callback_change_
Definition: field.hpp:530
void init_specialized()
Overridden from field_base.
Definition: field.hpp:517
Specialized field class for a styled_widget, used for labels and images.
Definition: field.hpp:569
bool use_markup_
Whether or not the label uses markup.
Definition: field.hpp:582
void init_specialized()
Overridden from field_base.
Definition: field.hpp:585
field_label(const std::string &id, const bool mandatory, const std::string &text, const bool use_markup)
Definition: field.hpp:571
Specialized field class for text.
Definition: field.hpp:537
field_text(const std::string &id, const bool mandatory, std::string &linked_variable)
Definition: field.hpp:549
field_text(const std::string &id, const bool mandatory, const std::function< std::string()> &callback_load_value, const std::function< void(const std::string &)> &callback_save_value)
Definition: field.hpp:539
void finalize_specialized()
Overridden from field_base.
Definition: field.hpp:559
Template class to implement the generic field implementation.
Definition: field.hpp:246
void widget_save()
Inherited from field_base.
Definition: field.hpp:364
void widget_restore()
Inherited from field_base.
Definition: field.hpp:329
void init_generic()
Inherited from field_base.
Definition: field.hpp:408
void set_widget_value(CT value)
Sets the value of the field.
Definition: field.hpp:344
void save(const bool must_be_active)
Stores the value in the widget in the interval value_.
Definition: field.hpp:456
field(const std::string &id, const bool mandatory, const T &value)
Constructor.
Definition: field.hpp:318
T & link_
The variable linked to the field.
Definition: field.hpp:398
T value_
The value_ of the widget, this value is also available once the widget is destroyed.
Definition: field.hpp:390
field(const std::string &id, const bool mandatory, const std::function< T()> &callback_load_value, const std::function< void(CT)> &callback_save_value)
Constructor.
Definition: field.hpp:264
void validate_widget()
Test whether the widget exists if the widget is mandatory.
Definition: field.hpp:444
void set_cache_value(CT value)
Sets the value of the field.
Definition: field.hpp:358
std::function< void(CT)> callback_save_value_
The callback function to save the value.
Definition: field.hpp:439
void finalize_generic()
Inherited from field_base.
Definition: field.hpp:422
field(const std::string &id, const bool mandatory, T &linked_variable)
Constructor.
Definition: field.hpp:291
T get_widget_value()
Gets the value of the field.
Definition: field.hpp:379
void restore()
Stores the internal value_ in the widget.
Definition: field.hpp:475
std::function< T()> callback_load_value_
The callback function to load the value.
Definition: field.hpp:405
Small abstract helper class.
Base class for all visible items.
virtual void set_active(const bool active)=0
Sets the styled_widget's state.
virtual bool get_active() const =0
Gets the active state of the styled_widget.
virtual void set_use_markup(bool use_markup)
Abstract base class for text items.
Class for a single line text area.
Definition: text_box.hpp:142
Base class for all widgets.
Definition: widget.hpp:53
base class of top level items, the only item which needs to store the final canvases to draw on.
Definition: window.hpp:63
Contains all forward declarations for field.hpp.
This file contains the window object, this object is a top level container which has the event manage...
void connect_signal_notify_modified(dispatcher &dispatcher, const signal_notification &signal)
Connects a signal handler for getting a notification upon modification.
Definition: dispatcher.cpp:203
Generic file dialog.