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