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