gui/widgets/window.hpp

Go to the documentation of this file.
00001 /* $Id: window.hpp 54173 2012-05-13 15:46:12Z mordante $ */
00002 /*
00003    Copyright (C) 2007 - 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  *  This file contains the window object, this object is a top level container
00019  *  which has the event management as well.
00020  */
00021 
00022 #ifndef GUI_WIDGETS_WINDOW_HPP_INCLUDED
00023 #define GUI_WIDGETS_WINDOW_HPP_INCLUDED
00024 
00025 #include "cursor.hpp"
00026 #include "gui/auxiliary/formula.hpp"
00027 #include "gui/widgets/helper.hpp"
00028 #include "gui/widgets/panel.hpp"
00029 
00030 #include "events.hpp"
00031 #include "SDL.h"
00032 
00033 #include <string>
00034 #include <boost/function.hpp>
00035 
00036 class CVideo;
00037 
00038 namespace gui2{
00039 
00040 class tdialog;
00041 class tdebug_layout_graph;
00042 class tpane;
00043 
00044 namespace event {
00045     class tdistributor;
00046 } // namespace event
00047 
00048 /**
00049  * base class of top level items, the only item
00050  * which needs to store the final canvases to draw on
00051  */
00052 class twindow
00053     : public tpanel
00054     , public cursor::setter
00055 {
00056     friend class tdebug_layout_graph;
00057     friend twindow *build(CVideo &, const twindow_builder::tresolution *);
00058     friend struct twindow_implementation;
00059     friend class tinvalidate_layout_blocker;
00060     friend class tpane;
00061 
00062 public:
00063 
00064     twindow(CVideo& video,
00065         tformula<unsigned>x,
00066         tformula<unsigned>y,
00067         tformula<unsigned>w,
00068         tformula<unsigned>h,
00069         const bool automatic_placement,
00070         const unsigned horizontal_placement,
00071         const unsigned vertical_placement,
00072         const unsigned maximum_width,
00073         const unsigned maximum_height,
00074         const std::string& definition,
00075         const twindow_builder::tresolution::ttip& tooltip,
00076         const twindow_builder::tresolution::ttip& helptip);
00077 
00078     ~twindow();
00079 
00080     /**
00081      * Update the size of the screen variables in settings.
00082      *
00083      * Before a window gets build the screen sizes need to be updated. This
00084      * function does that. It's only done when no other window is active, if
00085      * another window is active it already updates the sizes with it's resize
00086      * event.
00087      */
00088     static void update_screen_size();
00089 
00090     /**
00091      * Returns the instance of a window.
00092      *
00093      * @param handle              The instance id of the window.
00094      *
00095      * @returns                   The window or NULL.
00096      */
00097     static twindow* window_instance(const unsigned handle);
00098 
00099     /**
00100      * Default return values.
00101      *
00102      * These values are named return values and most are assigned to a widget
00103      * automatically when using a certain id for that widget. The automatic
00104      * return values are always a negative number.
00105      *
00106      * Note this might be moved somewhere else since it will force people to
00107      * include the button, while it should be and implementation detail for most
00108      * callers.
00109      */
00110     enum tretval {
00111         NONE = 0,                      /**<
00112                                         * Dialog is closed with no return
00113                                         * value, should be rare but eg a
00114                                         * message popup can do it.
00115                                         */
00116         OK = -1,                       /**< Dialog is closed with ok button. */
00117         CANCEL = -2,                   /**<
00118                                         * Dialog is closed with the cancel
00119                                         * button.
00120                                         */
00121         AUTO_CLOSE = -3                /**<
00122                                         * The dialog is closed automatically
00123                                         * since it's timeout has been
00124                                         * triggered.
00125                                         */
00126         };
00127 
00128     /** Gets the retval for the default buttons. */
00129     static tretval get_retval_by_id(const std::string& id);
00130 
00131     /**
00132      * @todo Clean up the show functions.
00133      *
00134      * the show functions are a bit messy and can use a proper cleanup.
00135      */
00136 
00137     /**
00138      * Shows the window.
00139      *
00140      * @param restore             Restore the screenarea the window was on
00141      *                            after closing it?
00142      * @param auto_close_timeout  The time in ms after which the window will
00143      *                            automatically close, if 0 it doesn't close.
00144      *                            @note the timeout is a minimum time and
00145      *                            there's no quarantee about how fast it closes
00146      *                            after the minimum.
00147      *
00148      * @returns                   The close code of the window, predefined
00149      *                            values are listed in tretval.
00150      */
00151     int show(const bool restore = true,
00152             const unsigned auto_close_timeout = 0);
00153 
00154     /**
00155      * Shows the window as a tooltip.
00156      *
00157      * A tooltip can't be interacted with and is just shown.
00158      *
00159      * @todo implement @p auto_close_timeout.
00160      *
00161      * @param auto_close_timeout  The time in ms after which the window will
00162      *                            automatically close, if 0 it doesn't close.
00163      *                            @note the timeout is a minimum time and
00164      *                            there's no guarantee about how fast it closes
00165      *                            after the minimum.
00166      */
00167     void show_tooltip(/*const unsigned auto_close_timeout = 0*/);
00168 
00169     /**
00170      * Shows the window non modal.
00171      *
00172      * A tooltip can be interacted with unlike the tooltip.
00173      *
00174      * @todo implement @p auto_close_timeout.
00175      *
00176      * @param auto_close_timeout  The time in ms after which the window will
00177      *                            automatically close, if 0 it doesn't close.
00178      *                            @note the timeout is a minimum time and
00179      *                            there's no guarantee about how fast it closes
00180      *                            after the minimum.
00181      */
00182     void show_non_modal(/*const unsigned auto_close_timeout = 0*/);
00183 
00184     /**
00185      * Draws the window.
00186      *
00187      * This routine draws the window if needed, it's called from the event
00188      * handler. This is done by a drawing event. When a window is shown it
00189      * manages an SDL timer which fires a drawing event every X milliseconds,
00190      * that event calls this routine. Don't call it manually.
00191      */
00192     void draw();
00193 
00194     /**
00195      * Undraws the window.
00196      */
00197     void undraw();
00198 
00199     /**
00200      * Adds an item to the dirty_list_.
00201      *
00202      * @param call_stack          The list of widgets traversed to get to the
00203      *                            dirty widget.
00204      */
00205     void add_to_dirty_list(const std::vector<twidget*>& call_stack)
00206     {
00207         dirty_list_.push_back(call_stack);
00208     }
00209 
00210     /** The status of the window. */
00211     enum tstatus{
00212         NEW,                      /**< The window is new and not yet shown. */
00213         SHOWING,                  /**< The window is being shown. */
00214         REQUEST_CLOSE,            /**< The window has been requested to be
00215                                    *   closed but still needs to evaluate the
00216                                    *   request.
00217                                    */
00218         CLOSED                    /**< The window has been closed. */
00219         };
00220 
00221     /**
00222      * Requests to close the window.
00223      *
00224      * At the moment the request is always honored but that might change in the
00225      * future.
00226      */
00227     void close() { status_ = REQUEST_CLOSE; }
00228 
00229     /**
00230      * Helper class to block invalidate_layout.
00231      *
00232      * Some widgets can handling certain layout aspects without help. For
00233      * example a listbox can handle hiding and showing rows without help but
00234      * setting the visibility calls invalidate_layout(). When this blocker is
00235      * Instantiated the call to invalidate_layout() becomes a nop.
00236      *
00237      * @note The class can't be used recursively.
00238      */
00239     class tinvalidate_layout_blocker
00240     {
00241     public:
00242         tinvalidate_layout_blocker(twindow& window);
00243         ~tinvalidate_layout_blocker();
00244     private:
00245         twindow& window_;
00246     };
00247 
00248     /**
00249      * Updates the size of the window.
00250      *
00251      * If the window has automatic placement set this function recalculates the
00252      * window. To be used after creation and after modification or items which
00253      * can have different sizes eg listboxes.
00254      */
00255     void invalidate_layout();
00256 
00257     /** Inherited from tevent_handler. */
00258     twindow& get_window() { return *this; }
00259 
00260     /** Inherited from tevent_handler. */
00261     const twindow& get_window() const { return *this; }
00262 
00263     /** Inherited from tevent_handler. */
00264     twidget* find_at(const tpoint& coordinate, const bool must_be_active)
00265         { return tpanel::find_at(coordinate, must_be_active); }
00266 
00267     /** Inherited from tevent_handler. */
00268     const twidget* find_at(const tpoint& coordinate,
00269             const bool must_be_active) const
00270         { return tpanel::find_at(coordinate, must_be_active); }
00271 
00272     /** Inherited from twidget. */
00273     tdialog* dialog() { return owner_; }
00274 
00275     /** Inherited from tcontainer_. */
00276     twidget* find(const std::string& id, const bool must_be_active)
00277         { return tcontainer_::find(id, must_be_active); }
00278 
00279     /** Inherited from tcontainer_. */
00280     const twidget* find(const std::string& id,
00281             const bool must_be_active) const
00282         { return tcontainer_::find(id, must_be_active); }
00283 #if 0
00284     /** @todo Implement these functions. */
00285     /**
00286      * Register a widget that prevents easy closing.
00287      *
00288      * Duplicate registration are ignored. See click_dismiss_ for more info.
00289      *
00290      * @param id                  The id of the widget to register.
00291      */
00292     void add_click_dismiss_blocker(const std::string& id);
00293 
00294     /**
00295      * Unregister a widget the prevents easy closing.
00296      *
00297      * Removing a non registered id is allowed but will do nothing. See
00298      * click_dismiss_ for more info.
00299      *
00300      * @param id                  The id of the widget to register.
00301      */
00302     void remove_click_dismiss_blocker(const std::string& id);
00303 #endif
00304 
00305     /**
00306      * Does the window close easily?
00307      *
00308      * The behavior can change at run-time, but that might cause oddities
00309      * with the easy close button (when one is needed).
00310      *
00311      * @returns                   Whether or not the window closes easily.
00312      */
00313     bool does_click_dismiss() const
00314     {
00315         return click_dismiss_ && !disable_click_dismiss();
00316     }
00317 
00318     /**
00319      * Disable the enter key.
00320      *
00321      * This is added to block dialogs from being closed automatically.
00322      *
00323      * @todo this function should be merged with the hotkey support once
00324      * that has been added.
00325      */
00326     void set_enter_disabled(const bool enter_disabled)
00327         { enter_disabled_ = enter_disabled; }
00328 
00329     /**
00330      * Disable the escape key.
00331      *
00332      * This is added to block dialogs from being closed automatically.
00333      *
00334      * @todo this function should be merged with the hotkey support once
00335      * that has been added.
00336      */
00337     void set_escape_disabled(const bool escape_disabled)
00338         { escape_disabled_ = escape_disabled; }
00339 
00340     /**
00341      * Initializes a linked size group.
00342      *
00343      * Note at least one of fixed_width or fixed_height must be true.
00344      *
00345      * @param id                  The id of the group.
00346      * @param fixed_width         Does the group have a fixed width?
00347      * @param fixed_height        Does the group have a fixed height?
00348      */
00349     void init_linked_size_group(const std::string& id,
00350             const bool fixed_width, const bool fixed_height);
00351 
00352     /**
00353      * Is the linked size group defined for this window?
00354      *
00355      * @param id                  The id of the group.
00356      *
00357      * @returns                   True if defined, false otherwise.
00358      */
00359     bool has_linked_size_group(const std::string& id);
00360 
00361     /**
00362      * Adds a widget to a linked size group.
00363      *
00364      * The group needs to exist, which is done by calling
00365      * init_linked_size_group. A widget may only be member of one group.
00366      * @todo Untested if a new widget is added after showing the widgets.
00367      *
00368      * @param id                  The id of the group.
00369      * @param widget              The widget to add to the group.
00370      */
00371     void add_linked_widget(const std::string& id, twidget* widget);
00372 
00373     /**
00374      * Removes a widget from a linked size group.
00375      *
00376      * The group needs to exist, which is done by calling
00377      * init_linked_size_group. If the widget is no member of the group the
00378      * function does nothing.
00379      *
00380      * @param id                  The id of the group.
00381      * @param widget              The widget to remove from the group.
00382      */
00383     void remove_linked_widget(const std::string& id, const twidget* widget);
00384 
00385     /***** ***** ***** setters / getters for members ***** ****** *****/
00386 
00387     CVideo& video() { return video_; }
00388 
00389     /**
00390      * Sets there return value of the window.
00391      *
00392      * @param retval              The return value for the window.
00393      * @param close_window        Close the window after setting the value.
00394      */
00395     void set_retval(const int retval, const bool close_window = true)
00396         { retval_ = retval; if(close_window) close(); }
00397 
00398     void set_owner(tdialog* owner) { owner_ = owner; }
00399 
00400     void set_click_dismiss(const bool click_dismiss)
00401     {
00402         click_dismiss_ = click_dismiss;
00403     }
00404 
00405     static void set_sunset(const unsigned interval)
00406         { sunset_ = interval ? interval : 5; }
00407 
00408     bool get_need_layout() const { return need_layout_; }
00409 
00410     void set_variable(const std::string& key, const variant& value)
00411     {
00412         variables_.add(key, value);
00413         set_dirty();
00414     }
00415 
00416 private:
00417 
00418     /** Needed so we can change what's drawn on the screen. */
00419     CVideo& video_;
00420 
00421     /** The status of the window. */
00422     tstatus status_;
00423 
00424     enum tshow_mode {
00425           none
00426         , modal
00427         , tooltip
00428     };
00429 
00430     /**
00431      * The mode in which the window is shown.
00432      *
00433      * This is used to determine whether or not to remove the tip.
00434      */
00435     tshow_mode show_mode_;
00436 
00437     // return value of the window, 0 default.
00438     int retval_;
00439 
00440     /** The dialog that owns the window. */
00441     tdialog* owner_;
00442 
00443     /**
00444      * When set the form needs a full layout redraw cycle.
00445      *
00446      * This happens when either a widget changes it's size or visibility or
00447      * the window is resized.
00448      */
00449     bool need_layout_;
00450 
00451     /** The variables of the canvas. */
00452     game_logic::map_formula_callable variables_;
00453 
00454     /** Is invalidate layout blocked see tinvalidate_layout_blocker. */
00455     bool invalidate_layout_blocked_;
00456 
00457     /** Avoid drawing the window.  */
00458     bool suspend_drawing_;
00459 
00460     /** When the window closes this surface is used to undraw the window. */
00461     surface restorer_;
00462 
00463     /** Do we wish to place the widget automatically? */
00464     const bool automatic_placement_;
00465 
00466     /**
00467      * Sets the horizontal placement.
00468      *
00469      * Only used if automatic_placement_ is true.
00470      * The value should be a tgrid placement flag.
00471      */
00472     const unsigned horizontal_placement_;
00473 
00474     /**
00475      * Sets the vertical placement.
00476      *
00477      * Only used if automatic_placement_ is true.
00478      * The value should be a tgrid placement flag.
00479      */
00480     const unsigned vertical_placement_;
00481 
00482     /** The maximum width if automatic_placement_ is true. */
00483     unsigned maximum_width_;
00484 
00485     /** The maximum height if automatic_placement_ is true. */
00486     unsigned maximum_height_;
00487 
00488     /** The formula to calulate the x value of the dialog. */
00489     tformula<unsigned>x_;
00490 
00491     /** The formula to calulate the y value of the dialog. */
00492     tformula<unsigned>y_;
00493 
00494     /** The formula to calulate the width of the dialog. */
00495     tformula<unsigned>w_;
00496 
00497     /** The formula to calulate the height of the dialog. */
00498     tformula<unsigned>h_;
00499 
00500     /** The settings for the tooltip. */
00501     twindow_builder::tresolution::ttip tooltip_;
00502 
00503     /** The settings for the helptip. */
00504     twindow_builder::tresolution::ttip helptip_;
00505 
00506     /**
00507      * Do we want to have easy close behavior?
00508      *
00509      * Easy closing means that whenever a mouse click is done the dialog will
00510      * be closed. The widgets in the window may override this behavior by
00511      * registering themselves as blockers. This is tested by the function
00512      * disable_click_dismiss().
00513      *
00514      * The handling of easy close is done in the window, in order to do so a
00515      * window either needs a click_dismiss or an ok button. Both will be hidden
00516      * when not needed and when needed first the ok is tried and then the
00517      * click_dismiss button. this allows adding a click_dismiss button to the
00518      * window definition and use the ok from the window instance.
00519      *
00520      * @todo After testing the click dismiss feature it should be documented in
00521      * the wiki.
00522      */
00523     bool click_dismiss_;
00524 
00525     /** Disable the enter key see our setter for more info. */
00526     bool enter_disabled_;
00527 
00528     /** Disable the escape key see our setter for more info. */
00529     bool escape_disabled_;
00530 
00531     /**
00532      * Controls the sunset feature.
00533      *
00534      * If this value is not 0 it will darken the entire screen every
00535      * sunset_th drawing request that nothing has been modified. It's a debug
00536      * feature.
00537      */
00538     static unsigned sunset_;
00539 
00540     /**
00541      * Helper struct to force widgets the have the same size.
00542      *
00543      * Widget which are linked will get the same width and/or height. This
00544      * can especially be useful for listboxes, but can also be used for other
00545      * applications.
00546      */
00547     struct tlinked_size
00548     {
00549         tlinked_size(const bool width = false, const bool height = false)
00550             : widgets()
00551             , width(width)
00552             , height(height)
00553         {
00554         }
00555 
00556         /** The widgets linked. */
00557         std::vector<twidget*> widgets;
00558 
00559         /** Link the widgets in the width? */
00560         bool width;
00561 
00562         /** Link the widgets in the height? */
00563         bool height;
00564     };
00565 
00566     /** List of the widgets, whose size are linked together. */
00567     std::map<std::string, tlinked_size> linked_size_;
00568 
00569     /**
00570      * Layouts the window.
00571      *
00572      * This part does the pre and post processing for the actual layout
00573      * algorithm.
00574      *
00575      * @see layout_algorihm for more information.
00576      */
00577     void layout();
00578 
00579     /**
00580      * Layouts the linked widgets.
00581      *
00582      * @see layout_algorihm for more information.
00583      */
00584     void layout_linked_widgets();
00585 
00586     /** Inherited from tevent_handler. */
00587     bool click_dismiss();
00588 
00589     /** Inherited from tcontrol. */
00590     const std::string& get_control_type() const;
00591 
00592     /**
00593      * Inherited from tpanel.
00594      *
00595      * Don't call this function it's only asserts.
00596      */
00597     void draw(surface& surface, const bool force = false,
00598             const bool invalidate_background = false);
00599 
00600     /**
00601      * The list with dirty items in the window.
00602      *
00603      * When drawing only the widgets that are dirty are updated. The draw()
00604      * function has more information about the dirty_list_.
00605      */
00606     std::vector<std::vector<twidget*> > dirty_list_;
00607 
00608     /**
00609      * Finishes the initialization of the grid.
00610      *
00611      * @param content_grid        The new contents for the content grid.
00612      */
00613     void finalize(const boost::intrusive_ptr<tbuilder_grid>& content_grid);
00614 
00615 #ifdef DEBUG_WINDOW_LAYOUT_GRAPHS
00616     tdebug_layout_graph* debug_layout_;
00617 
00618 public:
00619 
00620     /** wrapper for tdebug_layout_graph::generate_dot_file. */
00621     void generate_dot_file(
00622             const std::string& generator, const unsigned domain);
00623 private:
00624 
00625 #else
00626     void generate_dot_file(const std::string&,
00627             const unsigned) {}
00628 #endif
00629 
00630     event::tdistributor* event_distributor_;
00631 
00632 public:
00633     // mouse and keyboard_capture should be renamed and stored in the
00634     // dispatcher. Chaining probably should remain exclusive to windows.
00635     void mouse_capture(const bool capture = true);
00636     void keyboard_capture(twidget* widget);
00637 
00638     /**
00639      * Adds the widget to the keyboard chain.
00640      *
00641      * @todo rename to keyboard_add_to_chain.
00642      * @param widget              The widget to add to the chain. The widget
00643      *                            should be valid widget, which hasn't been
00644      *                            added to the chain yet.
00645      */
00646     void add_to_keyboard_chain(twidget* widget);
00647 
00648     /**
00649      * Remove the widget from the keyboard chain.
00650      *
00651      * @todo rename to keyboard_remove_from_chain.
00652      *
00653      * @param widget              The widget to be removed from the chain.
00654      */
00655     void remove_from_keyboard_chain(twidget* widget);
00656 
00657 private:
00658 
00659     /***** ***** ***** signal handlers ***** ****** *****/
00660 
00661     void signal_handler_sdl_video_resize(
00662             const event::tevent event, bool& handled, const tpoint& new_size);
00663 
00664     void signal_handler_click_dismiss(
00665             const event::tevent event, bool& handled, bool& halt);
00666 
00667     void signal_handler_sdl_key_down(
00668             const event::tevent event, bool& handled, const SDLKey key);
00669 
00670     void signal_handler_message_show_tooltip(
00671               const event::tevent event
00672             , bool& handled
00673             , event::tmessage& message);
00674 
00675     void signal_handler_message_show_helptip(
00676               const event::tevent event
00677             , bool& handled
00678             , event::tmessage& message);
00679 
00680     void signal_handler_request_placement(
00681               const event::tevent event
00682             , bool& handled);
00683 };
00684 
00685 } // namespace gui2
00686 
00687 #endif
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated by doxygen 1.7.1 on Fri May 25 2012 01:02:57 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs