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