gui/dialogs/field.hpp

Go to the documentation of this file.
00001 /* $Id: field.hpp 52533 2012-01-07 02:35:17Z shadowmaster $ */
00002 /*
00003    Copyright (C) 2008 - 2012 by Mark de Wever <koraq@xs4all.nl>
00004    Part of the Battle for Wesnoth Project http://www.wesnoth.org/
00005 
00006    This program is free software; you can redistribute it and/or modify
00007    it under the terms of the GNU General Public License as published by
00008    the Free Software Foundation; either version 2 of the License, or
00009    (at your option) any later version.
00010    This program is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY.
00012 
00013    See the COPYING file for more details.
00014 */
00015 
00016 /**
00017  * @file
00018  * Implements some helper classes to ease adding fields to a dialog and hide
00019  * the synchronization needed. Since some templates are used all is stored in
00020  * the header.
00021  *
00022  */
00023 
00024 #ifndef GUI_DIALOGS_FIELD_HPP_INCLUDED
00025 #define GUI_DIALOGS_FIELD_HPP_INCLUDED
00026 
00027 #include "gui/dialogs/field-fwd.hpp"
00028 #include "gui/widgets/control.hpp"
00029 #include "gui/widgets/selectable.hpp"
00030 #include "gui/widgets/text_box.hpp"
00031 #include "gui/widgets/window.hpp"
00032 #include "wml_exception.hpp"
00033 
00034 #include <boost/static_assert.hpp>
00035 
00036 namespace gui2 {
00037 
00038 /**
00039  * Abstract base class for the fields.
00040  *
00041  * @note In this context a widget is a @ref gui2::tcontrol and not a @ref
00042  * gui2::twidget. This name widget is a generic name and fits, however some
00043  * functions used are first declared in a control.
00044  */
00045 class tfield_
00046 {
00047 public:
00048 
00049     /**
00050      * Constructor.
00051      *
00052      * @param id                  The id of the widget to connect to the window.
00053      *                            A widget can only be connected once.
00054      * @param mandatory           Is the widget mandatory
00055      */
00056     tfield_(const std::string& id, const bool mandatory)
00057         : id_(id)
00058         , mandatory_(mandatory)
00059         , widget_(NULL)
00060     {
00061     }
00062 
00063     virtual ~tfield_() {}
00064 
00065     /**
00066      * Attaches the field to a window.
00067      *
00068      * When attached the widget which we're a wrapper around is stored linked
00069      * in here.
00070      *
00071      * @warning After attaching the window must remain a valid. Before the
00072      * window is destroyed the @ref detach_from_window function must be called.
00073      *
00074      * @todo Most functions that have a window parameter only use it to get the
00075      * widget. Evaluate and remove the window parameter where applicable.
00076      *
00077      * @pre widget_ == NULL
00078      *
00079      * @param window               The window to be attached to.
00080      */
00081     void attach_to_window(twindow& window)
00082     {
00083         assert(!widget_);
00084         widget_ = find_widget<tcontrol>(&window, id(), false, mandatory_);
00085     }
00086 
00087     /**
00088      * Initializes the widget.
00089      *
00090      * This routine is called before the dialog is shown and the pre_show() is
00091      * called. So the user can override the values set. This routine does the
00092      * following:
00093      * - If no widget available exit gives feedback it the widget must exist.
00094      * - If a getter is defined we use to set value_ and the widget.
00095      * - If no setter is defined we use the widget value to set value_.
00096      *
00097      * The function calls two functions
00098      *  - init_generic which is to be used in the template subclass.
00099      *  - init_specialized which is to be used in subclasses of the template
00100      *     class. This way they can override this function without to use their
00101      *     signature to inherit.
00102      *
00103      * @param window              The window containing the widget.
00104      */
00105     void widget_init(twindow& window)
00106     {
00107         init_generic(window);
00108         init_specialized(window);
00109     }
00110 
00111     /**
00112      * Finalizes the widget.
00113      *
00114      * This routine is called after the dialog is closed with OK. It's called
00115      * before post_show(). This routine does the following:
00116      * - if no active widget available exit.
00117      * - if a setter is defined the widget value is saved in the setter.
00118      * - The widget value is saved in value_.
00119      *
00120      * Like widget_init it calls two functions with the same purpose.
00121      *
00122      * @param window              The window containing the widget.
00123      */
00124     void widget_finalize(twindow& window)
00125     {
00126         finalize_generic(window);
00127         finalize_specialized(window);
00128     }
00129 
00130     /**
00131      * Detaches the field from a window.
00132      *
00133      * @pre widget_ != NULL || !mandatory_
00134      *
00135      * @param window               The window to be attached to.
00136      */
00137     void detach_from_window()
00138     {
00139         assert(!mandatory_ || widget_);
00140         widget_ = NULL;
00141     }
00142 
00143     /**
00144      * Saves a widget.
00145      *
00146      * It can be a window must be recreated, in that case the state needs to be
00147      * saved and restored. This routine does the following:
00148      * - if no widget available exit (doesn't look at the active state).
00149      * - The widget value is saved in value_.
00150      *
00151      * @param window              The window containing the widget.
00152      */
00153     virtual void widget_save(twindow& window) = 0;
00154 
00155     /**
00156      * Restores a widget.
00157      *
00158      * See widget_save for more info.
00159      *
00160      * @param window              The window containing the widget.
00161      */
00162     virtual void widget_restore(twindow& window) = 0;
00163 
00164     /**
00165      * Enables a widget.
00166      *
00167      * @param window              The window containing the widget.
00168      * @param enable              If true enables the widget, disables otherwise.
00169      * @param sync                If the state is changed do we need to
00170      *                            synchronize. Upon disabling, write the value
00171      *                            of the widget in the variable value_. Upon
00172      *                            enabling write the value of value_ in the
00173      *                            widget.
00174      */
00175     void widget_set_enabled(twindow& window, const bool enable, const bool sync)
00176     {
00177         tcontrol* widget =
00178             dynamic_cast<tcontrol*>(window.find(id(), false));
00179 
00180         if(!widget) {
00181             return;
00182         }
00183 
00184         const bool widget_state =  widget->get_active();
00185         if(widget_state == enable) {
00186             return;
00187         }
00188 
00189         if(sync) {
00190             if(enable) {
00191                 widget_restore(window);
00192             } else {
00193                 widget_save(window);
00194             }
00195         }
00196 
00197         widget->set_active(enable);
00198     }
00199 
00200     /***** ***** ***** setters / getters for members ***** ****** *****/
00201 
00202     const std::string& id() const { return id_; }
00203 
00204     bool is_mandatory() const { return mandatory_; }
00205 
00206     tcontrol* widget()
00207     {
00208         return widget_;
00209     }
00210 
00211     const tcontrol* widget() const
00212     {
00213         return widget_;
00214     }
00215 
00216 private:
00217     /** The id field of the widget, should be unique in a window. */
00218     const std::string id_;
00219 
00220     /** Is the widget optional or mandatory in this window. */
00221     const bool mandatory_;
00222 
00223     /** The widget attached to the field. */
00224     tcontrol* widget_;
00225 
00226     /** See widget_init. */
00227     virtual void init_generic(twindow& window) = 0;
00228 
00229     /** See widget_init. */
00230     virtual void init_specialized(twindow& /*window*/) {}
00231 
00232 
00233     /** See widget_finalize. */
00234     virtual void finalize_generic(twindow& window) = 0;
00235 
00236     /** See widget_finalize. */
00237     virtual void finalize_specialized(twindow& /*window*/) {}
00238 };
00239 
00240 /**
00241  * Template class to implement the generic field implementation.
00242  *
00243  * @param T                       The type of the item to show in the widget.
00244  * @param W                       The type of widget to show, this is not a
00245  *                                widget class but a behaviour class.
00246  * @param CT                      The type tp be used in the
00247  *                                callback_save_value callback. Normally this
00248  *                                is const T but for example with strings it
00249  *                                can be const T&. Note the const needs to be
00250  *                                in the template otherwise compilation on
00251  *                                GCC-4.3 fails (not sure whether compiler bug
00252  *                                or not).
00253  */
00254 template<class T, class W, class CT> class tfield : public tfield_
00255 {
00256 public:
00257 
00258     /**
00259      * Constructor.
00260      *
00261      * @param id                  The id of the widget to connect to the window.
00262      *                            A widget can only be connected once.
00263      * @param mandatory           Is the widget mandatory?
00264      * @param callback_load_value A callback function which is called when the
00265      *                            window is shown. This callback returns the
00266      *                            initial value of the field.
00267      * @param callback_save_value A callback function which is called when the
00268      *                            window closed with the OK button. The
00269      *                            callback is executed with the new value of
00270      *                            the field. It's meant to set the value of
00271      *                            some variable in the engine after the window
00272      *                            is closed with OK.
00273      */
00274     tfield(const std::string& id,
00275             const bool mandatory,
00276             T (*callback_load_value) (),
00277             void (*callback_save_value) (CT value)) :
00278         tfield_(id, mandatory),
00279         value_(T()),
00280         link_(value_),
00281         callback_load_value_(callback_load_value),
00282         callback_save_value_(callback_save_value)
00283     {
00284         BOOST_STATIC_ASSERT((!boost::is_same<tcontrol, W>::value));
00285     }
00286 
00287     /**
00288      * Constructor.
00289      *
00290      * @param id                  The id of the widget to connect to the window.
00291      *                            A widget can only be connected once.
00292      * @param mandatory           Is the widget mandatory?
00293      * @param linked_variable     The variable which is linked to the field.
00294      *                            * Upon loading its value is used as initial
00295      *                              value of the widget.
00296      *                            * Upon closing:
00297      *                              * with OK its value is set to the value of
00298      *                                the widget.
00299      *                              * else, its value is undefined.
00300      */
00301     tfield(const std::string& id
00302             , const bool mandatory
00303             , T& linked_variable)
00304         : tfield_(id, mandatory)
00305         , value_(T())
00306         , link_(linked_variable)
00307         , callback_load_value_(NULL)
00308         , callback_save_value_(NULL)
00309     {
00310         BOOST_STATIC_ASSERT((!boost::is_same<tcontrol, W>::value));
00311     }
00312 
00313     /**
00314      * Constructor.
00315      *
00316      * This version is used for read only variables.
00317      *
00318      * @note The difference between this constructor and the one above is the
00319      * sending of the third parameter as const ref instead of a non-const ref.
00320      * So it feels a bit tricky. Since this constructor is only used for a
00321      * the @ref tcontrol class and the other constructors not the issue is
00322      * solved by using static asserts to test whether the proper constructor
00323      * is used.
00324      *
00325      * @param mandatory            Is the widget mandatory?
00326      * @param id                  The id of the widget to connect to the window.
00327      *                            A widget can only be connected once.
00328      * @param value               The value of the widget.
00329      */
00330     tfield(const std::string& id
00331             , const bool mandatory
00332             , const T& value)
00333         : tfield_(id, mandatory)
00334         , value_(value)
00335         , link_(value_)
00336         , callback_load_value_(NULL)
00337         , callback_save_value_(NULL)
00338     {
00339         BOOST_STATIC_ASSERT((boost::is_same<tcontrol, W>::value));
00340     }
00341 
00342     /** Inherited from tfield_. */
00343     void widget_restore(twindow& window)
00344     {
00345         validate_widget(window);
00346 
00347         restore(window);
00348     }
00349 
00350     /**
00351      * Sets the value of the field.
00352      *
00353      * This sets the value in both the internal cache value and in the widget
00354      * itself.
00355      *
00356      * @param window              The window containing the widget.
00357      * @param value               The new value.
00358      */
00359     void set_widget_value(twindow& window, CT value)
00360     {
00361         value_ = value;
00362         restore(window);
00363     }
00364 
00365     /**
00366      * Sets the value of the field.
00367      *
00368      * This sets the internal cache value but not the widget value, this can
00369      * be used to initialize the field.
00370      *
00371      * @param value               The new value.
00372      */
00373     void set_cache_value(CT value)
00374     {
00375         value_ = value;
00376     }
00377 
00378     /** Inherited from tfield_. */
00379     void widget_save(twindow& window)
00380     {
00381         save(window, false);
00382     }
00383 
00384     /**
00385      * Gets the value of the field.
00386      *
00387      * This function gets the value of the widget and stores that in the
00388      * internal cache, then that value is returned.
00389      *
00390      * @deprecated Use references to a variable instead.
00391      *
00392      * @param window              The window containing the widget.
00393      *
00394      * @returns                   The current value of the widget.
00395      */
00396     T get_widget_value(twindow& window)
00397     {
00398         save(window, false);
00399         return value_;
00400     }
00401 
00402 private:
00403 
00404     /**
00405      * The value_ of the widget, this value is also available once the widget
00406      * is destroyed.
00407      */
00408     T value_;
00409 
00410     /**
00411      * The variable linked to the field.
00412      *
00413      * When set determines the initial value and the final value is stored here
00414      * in the finallizer.
00415      */
00416     T& link_;
00417 
00418     /**
00419      * The callback function to load the value.
00420      *
00421      * This is used to load the initial value of the widget, if defined.
00422      */
00423     T (*callback_load_value_) ();
00424 
00425     /** Inherited from tfield_. */
00426     void init_generic(twindow& window)
00427     {
00428         validate_widget(window);
00429 
00430         if(callback_load_value_) {
00431             value_ = callback_load_value_();
00432         } else {
00433             value_ = link_;
00434         }
00435 
00436         restore(window);
00437     }
00438 
00439     /** Inherited from tfield_. */
00440     void finalize_generic(twindow& window)
00441     {
00442         save(window, true);
00443 
00444         if(callback_save_value_) {
00445             callback_save_value_(value_);
00446         } else {
00447             link_ = value_;
00448         }
00449     }
00450 
00451     /**
00452      * The callback function to save the value.
00453      *
00454      * Once the dialog has been successful this function is used to store the
00455      * result of this widget.
00456      */
00457     void (*callback_save_value_) ( CT value);
00458 
00459     /**
00460      * Test whether the widget exists if the widget is mandatory.
00461      *
00462      * @param window              The window containing the widget.
00463      */
00464     void validate_widget(twindow& window)
00465     {
00466         if(!is_mandatory()) {
00467             return;
00468         }
00469         find_widget<const W>(&window, id(), false);
00470     }
00471 
00472     /**
00473      * Stores the value in the widget in the interval value_.
00474      *
00475      * @param window              The window containing the widget.
00476      * @param must_be_active      If true only active widgets will store their value.
00477      */
00478     void save(twindow& window, const bool must_be_active);
00479 
00480     /**
00481      * Stores the internal value_ in the widget.
00482      *
00483      * @param window              The window containing the widget.
00484      */
00485     void restore(twindow& window);
00486 
00487 };
00488 
00489 template<class T, class W, class CT>
00490 void tfield<T, W, CT>::save(twindow& window, const bool must_be_active)
00491 {
00492     const W* widget =
00493             find_widget<const W>(&window, id(), must_be_active, false);
00494 
00495     if(widget) {
00496         value_ = widget->get_value();
00497     }
00498 }
00499 
00500 template<>
00501 inline void tfield<std::string, tcontrol, const std::string&>::save(
00502           twindow& window
00503         , const bool must_be_active)
00504 {
00505     const tcontrol* control =
00506             find_widget<const tcontrol>(&window, id(), must_be_active, false);
00507 
00508     if(control) {
00509         value_ = control->label();
00510     }
00511 }
00512 
00513 template<class T, class W, class CT>
00514 void tfield<T, W, CT>::restore(twindow& window)
00515 {
00516     W* widget = find_widget<W>(&window, id(), false, false);
00517 
00518     if(widget) {
00519         widget->set_value(value_);
00520     }
00521 }
00522 
00523 template<>
00524 inline void tfield<std::string, tcontrol, const std::string&>::restore(
00525           twindow& window)
00526 {
00527     tcontrol* control = find_widget<tcontrol>(&window, id(), false, false);
00528 
00529     if(control) {
00530         control->set_label(value_);
00531     }
00532 }
00533 
00534 /** Specialized field class for boolean. */
00535 class tfield_bool : public tfield<bool, tselectable_>
00536 {
00537 public:
00538     tfield_bool(const std::string& id,
00539             const bool mandatory,
00540             bool (*callback_load_value) (),
00541             void (*callback_save_value) (const bool value),
00542             void (*callback_change) (twidget* widget)) :
00543         tfield<bool, gui2::tselectable_>
00544             (id, mandatory, callback_load_value, callback_save_value),
00545         callback_change_(callback_change)
00546         {
00547         }
00548 
00549     tfield_bool(const std::string& id
00550             , const bool mandatory
00551             , bool& linked_variable
00552             , void (*callback_change) (twidget* widget))
00553         : tfield<bool, gui2::tselectable_>(id, mandatory, linked_variable)
00554         , callback_change_(callback_change)
00555     {
00556     }
00557 
00558 private:
00559 
00560     /** Overridden from tfield_. */
00561     void init_specialized(twindow& window)
00562     {
00563         if(callback_change_) {
00564             tselectable_* widget =
00565                 dynamic_cast<tselectable_*>(window.find(id(), false));
00566 
00567             if(widget) {
00568                 widget->set_callback_state_change(callback_change_);
00569             }
00570         }
00571     }
00572 
00573     void (*callback_change_) (twidget* widget);
00574 };
00575 
00576 /** Specialized field class for text. */
00577 class tfield_text : public tfield<std::string, ttext_, const std::string& >
00578 {
00579 public:
00580     tfield_text(const std::string& id,
00581             const bool mandatory,
00582             std::string (*callback_load_value) (),
00583             void (*callback_save_value) (const std::string& value)) :
00584         tfield<std::string, ttext_, const std::string& >
00585             (id, mandatory, callback_load_value, callback_save_value)
00586         {
00587         }
00588 
00589     tfield_text(const std::string& id
00590             , const bool mandatory
00591             , std::string& linked_variable)
00592         : tfield<std::string, ttext_, const std::string&>(
00593                 id
00594                 , mandatory
00595                 , linked_variable)
00596     {
00597     }
00598 
00599 private:
00600     /** Overridden from tfield_. */
00601     void finalize_specialized(twindow& window)
00602     {
00603         ttext_box* widget = dynamic_cast<ttext_box*>(window.find(id(), false));
00604 
00605         if(widget) {
00606             widget->save_to_history();
00607         }
00608     }
00609 };
00610 
00611 /** Specialized field class for a control, used for labels and images.. */
00612 class tfield_label : public tfield<std::string, tcontrol, const std::string&>
00613 {
00614 public:
00615     tfield_label(const std::string& id
00616             , const bool mandatory
00617             , const std::string& text
00618             , const bool use_markup)
00619         : tfield<std::string, tcontrol, const std::string&>(
00620                 id
00621                 , mandatory
00622                 , text)
00623         , use_markup_(use_markup)
00624 
00625         {
00626         }
00627 
00628 private:
00629 
00630     /** Whether or not the label uses markup. */
00631     bool use_markup_;
00632 
00633     /** Overridden from tfield_. */
00634     void init_specialized(twindow& window)
00635     {
00636         find_widget<tcontrol>(&window, id(), false).set_use_markup(use_markup_);
00637     }
00638 };
00639 
00640 } // namespace gui2
00641 
00642 #endif
00643 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated by doxygen 1.7.1 on Thu May 24 2012 01:02:42 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs