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
| Generated by doxygen 1.7.1 on Fri May 25 2012 01:02:57 for The Battle for Wesnoth | Gna! | Forum | Wiki | CIA | devdocs |