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