1 // -*- C++ -*- 2 /* GG is a GUI for OpenGL. 3 Copyright (C) 2003-2008 T. Zachary Laine 4 5 This library is free software; you can redistribute it and/or 6 modify it under the terms of the GNU Lesser General Public License 7 as published by the Free Software Foundation; either version 2.1 8 of the License, or (at your option) any later version. 9 10 This library is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 Lesser General Public License for more details. 14 15 You should have received a copy of the GNU Lesser General Public 16 License along with this library; if not, write to the Free 17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 18 02111-1307 USA 19 20 If you do not wish to comply with the terms of the LGPL please 21 contact the author as other terms are available for a fee. 22 23 Zach Laine 24 whatwasthataddress@gmail.com */ 25 26 /** \file Wnd.h \brief Contains the Wnd class, upon which all GG GUI elements 27 are based. */ 28 29 #ifndef _GG_Wnd_h_ 30 #define _GG_Wnd_h_ 31 32 #include <GG/Base.h> 33 #include <GG/Exception.h> 34 #include <GG/Flags.h> 35 36 #include <boost/signals2/trackable.hpp> 37 38 #include <list> 39 #include <set> 40 #include <vector> 41 #include <memory> 42 43 44 namespace GG { 45 46 class BrowseInfoWnd; 47 class Layout; 48 class StyleFactory; 49 class Timer; 50 class WndEvent; 51 52 53 /** Wnd creation flags type. */ 54 GG_FLAG_TYPE(WndFlag); 55 56 /** Clicks hit this window, rather than passing through it, and mouse-overs 57 detect that they are over this window. */ 58 extern GG_API const WndFlag INTERACTIVE; 59 60 /** When a mouse button is held down over this window, it expects to receive 61 multiple *ButtonDown messages. */ 62 extern GG_API const WndFlag REPEAT_BUTTON_DOWN; 63 64 /** This window can be dragged around independently. */ 65 extern GG_API const WndFlag DRAGABLE; 66 67 /** This window can be resized by the user, with the mouse. */ 68 extern GG_API const WndFlag RESIZABLE; 69 70 /** This windows is an "on-top" window, and will always appear above all 71 non-on-top and non-modal windows. Note that this only applies to 72 top-level (Parent()-less) Wnds. */ 73 extern GG_API const WndFlag ONTOP; 74 75 /** This window is modal; while it is active, no other windows are 76 interactive. Modal windows are considered above "on-top" windows, and 77 should not be flagged as OnTop. Note that this only applies to top-level 78 (Parent()-less) Wnds. */ 79 extern GG_API const WndFlag MODAL; 80 81 /** When a keyboard key is held down while this window has input focus, it 82 expects to receive KeyPress messages. */ 83 extern GG_API const WndFlag REPEAT_KEY_PRESS; 84 85 /** None of the above flags */ 86 extern GG_API const WndFlag NO_WND_FLAGS; 87 88 89 /** \brief This is the basic GG window class. 90 91 <h3>Window Geometry</h3> 92 93 <br>The coordinates of Wnd boundaries are STL-style (as are most 94 range-values throughout GG), meaning that LowerRight() denotes the "last + 95 1" pixel of a Wnd. The on-screen representation of a rectangular Wnd 96 covers the pixels from UpperLeft() to LowerRight() - Pt(X1, Y1), \a not 97 UpperLeft() to LowerRight(). Each Wnd has a client area from 98 ClientUpperLeft() to ClientLowerRight(). These two methods are virtual, 99 and may return anything the user likes; the default implementation is to 100 return UpperLeft() and LowerRight(), respectively, meaning that the client 101 area is the entire window. 102 103 <h3>Child Windows</h3> 104 105 <br>It is assumed that child windows exists within the boundaries of their 106 parents, although this is not required. By default, Wnds do not clip 107 their children; child clipping can be turned on or off using 108 SetChildClippingMode(), which clips all children to the client and/or 109 non-client areas of the Wnd. Subclasses can override BeginClippingImpl(), 110 EndClippingImpl(), BeginNonclientClippingImpl(), and 111 EndNonclientClippingImpl() if the clipping should be done using techniques 112 other than scissor clipping and stencil testing, or if the Wnd is 113 nonrectangular. Regardless of clipping, all clicks that land on a child 114 but outside of the parent will not reach the child, since clicks are 115 detected by seaching the top-level Wnds and then searching the children 116 within the ones that are hit. Ideally, "sibling" child windows should not 117 overlap (unless they can without interfering). If this is impossible or 118 undesirable, and control is needed over the order in which children are 119 layered, MoveChildUp() and MoveChildDown() provide such control. 120 121 <br>Windows are owned by the GUI, as top level or modal windows, owned by 122 their parent windows as children, or during a drag drop operation jointly 123 owned by the GUI and the originating/accepting window. Changes of ownership 124 are indicated by passing a shared_ptr. Other objects should use weak_ptr to 125 refer to windows that they do not wish to preserve beyond its natural demise. 126 This avoids "leaking" a window by storing a shared_ptr to a window that is 127 no longer part of the hierarchy. This would prevent a window from being 128 removed from memory, event processing, etc. 129 130 <h3>Effects of Window-Creation Flags</h3> 131 132 <br>Resizable() windows are able to be stretched by the user by dragging 133 the areas of the window outside the client area. So the RESIZABLE flag 134 will have no effect on a window that does not have non-default 135 ClientUpperLeft() and/or ClientLowerRight(). The WindowRegion() method 136 can also be overidden in derived classes, and can return regions that are 137 appropriate to nonrectangular windows, or those whose client area must 138 cover the entire window. 139 140 <br>OnTop() windows are drawn after all others (except Modal() ones), to 141 ensure that they remain on top. This means that other non-OnTop() windows 142 that are moved to the top of the z-order stop at some z-value below the 143 lowest OnTop() window in the z-order. On-topness is useful for modeless 144 dialog boxes, among other things. 145 146 <br>Modal() windows are available (by setting the MODAL window creation 147 flag), and are also always-on-top, but are handled differently and do not 148 have ONTOP specified in their creation flags. Modal windows are executed 149 by calling Run(), which registers them as modal windows and starts the 150 local execution of the GUI's event pump. Execution of the code that calls 151 Run() is effectively halted until Run() returns. Derived classes that 152 wish to use modal execution should set m_done = true to escape from the 153 modal execution loop. GUI::RunModal has more information about processing 154 during modal dialog execution. 155 156 <br>Note that OnTop() and Modal() flags only apply to top-level 157 (Parent()-less) Wnds. 158 159 <h3>Resource Management</h3> 160 Wnd uses std::shared_ptr and std::weak_ptr to manage its resources. 161 162 Parent windows point to their children with shared_ptr and own the children. 163 All other pointers should be non-owning weak_ptr to prevent leaks and/or 164 referencing windows already removed from the hierarchy. 165 166 Each window uses shared_from_this() to refer to itself. The internal 167 weak_ptr from shared_from_this is not constructed until after the Wnd is 168 assigned to at least one shared_ptr. Consequently, neither AttachChild() 169 nor SetLayout() can be called from within a constructor. 170 171 A default factory function Create<T> is provided that creates the shared_ptr 172 and then calls CompleteConstruction() in order to assemble the children. A 173 dervied class can override CompleteConstruction() to correctly assemble its 174 children. 175 176 <h3>Signal Considerations</h3> 177 178 <br>Wnd inherits from boost::signals2::trackable. This means that any 179 slots contained in a Wnd object or Wnd-derived object will automatically 180 be disconnected from any connected signals when the Wnd is destroyed. 181 Every Wnd responds to input as driven by the singleton GUI object. 182 183 <h3>Event Filters</h3> 184 185 <br>Every Wnd can also have its incoming WndEvents filtered by an 186 arbitrary number of other Wnds. Each such Wnd in a Wnd's "filter chain" 187 gets an opportunity, one at a time, to process an incoming WndEvent, or 188 pass it on to the next filter in the chain. If all EventFilter() calls in 189 the chain return false, the filtered Wnd then gets the chance to process 190 the WndEvent as normal. Filter Wnds are traversed in reverse order that 191 they are installed, and no filter Wnd can be in a filter chain more than 192 once. Installing the same filter Wnd more than once removes the Wnd from 193 the filter chain and re-adds it to the beginning of the chain. Note that 194 the default implementation of EventFilter() is to return false and do 195 nothing else, so installing a Wnd-derived type with no overridden 196 EventFilter() in a filter Wnd will have no effect. Also note that just as 197 it is legal for keyboard accelerator slots to do nontrivial work and still 198 return false (causing a keystroke event to be generated), EventFilter() 199 may return false even when it does nontrivial work, and the next filter in 200 the chain will also get a chance to process the WndEvent. It is even 201 possible to have an arbitrary number of filters that all do processing on 202 an WndEvent, and finally let the filtered Wnd do its normal WndEvent 203 processing. 204 205 <h3>Layouts</h3> 206 207 <br>Layouts arrange children in the client area of a window, and can be 208 assigned to a window in 4 ways. HorizontalLayout(), VerticalLayout(), and 209 GridLayout() all arrange the window's client-area children automatically, 210 and take ownership of them as their own children, becoming the window's 211 only client-area child. Any existing layout is removed first. 212 SetLayout() allows you to attach a pre-configured Layout object directly, 213 without automatically arranging the window's client-area children. 214 Because SetLayout() does no auto-arrangement, it does not know how to 215 place any client-area children the window may have at the time it is 216 called; for this reason, it not only removes any previous layout, but 217 deletes all current client-area children as well. Therefore, SetLayout() 218 should usually only be called before any client-area children are attached 219 to a window; all client-area children should be attached directly to the 220 layout. <br>When a window has an attached layout and is resized, it 221 resizes its layout automatically. Further, if a window is part of a 222 layout, it notifies its containing layout whenever it is moved, resized, 223 or has its MinSize() changed. This ensures that layouts are always 224 current. Note the use of the phrase "client-area children". This refers 225 to children entirely within the client area of the window. 226 227 <h3>Frame Timing</h3> 228 229 <br>Each frame is a cycle culminating in rendering the screen. The 230 following things happen, in order: 231 + events from the GUI and the data sources are handled 232 + PreRender() is called to update layout if required. 233 + Render() is called. 234 235 Wnd does not distinguish between events from the GUI and events from the 236 data sources. 237 238 PreRender() and Render() are only called if the window is visible. 239 240 PreRender() defers all layout changes until after all events have been 241 handled. This improves performance by preventing event handling causing 242 multiple layout actions between calls to Render(). PreRender() allows Wnd 243 to perform any required expensive updates only once per frame. 244 245 PreRender() prevents bugs caused by early events in a frame changing the 246 layout so that later events trigger on a layout different from the layout 247 visible to the player. This is a change from the original GG behavior. 248 Core parts of GG will continue to immediately update layout until 249 peripheral parts are updated to expect deferred updates. 250 251 The default implementation of PreRender() only clears the flag set by RequirePreRender(). 252 For a class to defer its layout to the prerender phase it needs to override PreRender() and 253 implement its layout changes in PreRender(). 254 255 Legacy GG did not have a prerender phase and all layout changes were immediate. Any Wnd class 256 that does not override PreRender() will update layout immediately when executing mutating functions. 257 258 <h3>Browse Info</h3> 259 260 <br>Browse info is a non-interactive informational window that pops up 261 after the user keeps the mouse over the Wnd for a certain period of time. 262 This can reproduce "tooltip"-like functionality, but is not limited to 263 displaying only text. An arbitrary BrowseInfoWnd-derived window can be 264 displayed. There can be multiple browse info modes, numbered 0 through 265 N - 1. Each mode has a time associated with it, and after the associated 266 time has elapsed, that mode is entered. This is intended to allow 267 different levels of detail to be shown for different lengths of mouse 268 presence. For instance, hovering over a Wnd for 1 second might produce a 269 box that says "FooWnd", but leaving it there a total of 2 seconds might 270 produce a box that says "FooWnd: currently doing nothing". When the mouse 271 leaves the Wnd, a click occurs, etc., the Wnd reverts to browse mode -1, 272 indicating that no browse info should be displayed. By default, every Wnd 273 has a single browse info mode at time DefaultBrowseTime(), using the 274 DefaultBrowseInfoWnd(), with no associated text. Note that 275 DefaultBrowseInfoWnd() returns a null window unless it is set by the user. 276 As this implies, it is legal to have no BrowseInfoWnd associated with a 277 browse mode, in which case nothing is shown. Also note that it is legal 278 to have no text associated with a browse mode. \see BrowseInfoWnd 279 280 <h3>Style Factory</h3> 281 282 <br>A StyleFactory is responsible for creating controls and dialogs that 283 other Wnds may need (e.g. when Slider needs to create a Button for its 284 sliding tab). There is an GUI-wide StyleFactory available, but for 285 complete customization, each Wnd may have one installed as well. The 286 GetStyleFactory() method returns the one installed in the Wnd, if one 287 exists, or the GUI-wide one otherwise. */ 288 class GG_API Wnd : public boost::signals2::trackable, 289 public std::enable_shared_from_this<Wnd> 290 { 291 public: 292 /** \brief The data necessary to represent a browse info mode. 293 294 Though \a browse_text will not apply to all browse info schemes, it is 295 nevertheless part of BrowseInfoMode, since it will surely be the most 296 common data displayed in a BrowseInfoWnd. */ 297 struct GG_API BrowseInfoMode 298 { 299 /** The time the cursor must linger over the Wnd before this mode 300 becomes active, in ms. */ 301 unsigned int time = 0; 302 303 /** The BrowseInfoWnd used to display the browse info for this 304 mode. */ 305 std::shared_ptr<BrowseInfoWnd> wnd; 306 307 /** The text to display in the BrowseInfoWnd shown for this mode. */ 308 std::string text; 309 }; 310 311 /** The type of the iterator parameters passed to DropsAcceptable(). */ 312 typedef std::map<const Wnd*, bool>::iterator DropsAcceptableIter; 313 314 /** The modes of child clipping. */ 315 enum ChildClippingMode : int { 316 /** No child clipping is performed. */ 317 DontClip, 318 319 /** Children or parts of children that fall outside the client area 320 are not visible. */ 321 ClipToClient, 322 323 /** Children or parts of children that fall outside the window's area 324 are not visible. */ 325 ClipToWindow, 326 327 /** Acts as ClipToClient on children whose NonClientChild() member 328 returns false. For a child C whose NonClientChild() returns true, 329 any part of C that is inside the client area or outside the 330 window's area is not visible. This mode is useful for Wnds that 331 have client contents that should be clipped, but that also have 332 nonclient children (e.g. minimize/maximize/close buttons). */ 333 ClipToClientAndWindowSeparately 334 }; 335 336 /** \name Structors */ ///@{ 337 virtual ~Wnd(); 338 //@} 339 340 /** Create is the default factory which allocates and configures a T type 341 derived from Wnd. It requires that the T constructor followed by 342 T->CompleteConstruction() produce a correct T. */ 343 template <typename T, typename... Args> Create(Args &&...args)344 static std::shared_ptr<T> Create(Args&&... args) 345 { 346 // This intentionally doesn't use std::make_shared in order to make lazy cleanup of 347 // weak_ptrs a low priority. 348 349 // std::make_shared<T> might depending on 350 // the stdlib implementation allocate a single block of memory for the 351 // shared_ptr control block and T. This is efficient in terms of 352 // number of memory allocations. However, after the shared_ptr count 353 // decreases to zero any existing weak_ptrs will still prevent the 354 // block of memory from being released. 355 356 // std::shared_ptr<T>(new T()) allocates the memory for T and the 357 // shared_ptr control block in two separate allocations. When the 358 // shared_ptr count decreases to zero the memory allocated for T is 359 // immediately released. 360 361 // Allocating shared_ptr in this manner means any floating weak_ptrs 362 // will not prevent more that a smart pointer control block worth of 363 // memory from being released. 364 std::shared_ptr<T> wnd(new T(std::forward<Args>(args)...)); 365 wnd->CompleteConstruction(); 366 return wnd; 367 } 368 369 /** CompleteConstruction() should be overriden to complete construction of derived classes that 370 need a fully formed weak_from_this() (e.g. to call AttachChild()) to be correctly constructed. */ CompleteConstruction()371 virtual void CompleteConstruction() {}; 372 373 /** \name Accessors */ ///@{ 374 /** Returns true iff a click over this window does not pass through. Note 375 that this also determines whether a mouse-over will detect this window 376 or the ones under it. */ 377 bool Interactive() const; 378 379 /** Returns true iff holding a keyboard key while this Wnd has the input 380 focus generates multiple key-press messages. */ 381 bool RepeatKeyPress() const; 382 383 /** Returns true iff holding a mouse button down over this Wnd generates 384 multiple button-down messages. */ 385 bool RepeatButtonDown() const; 386 387 /** Returns true iff this Wnd be dragged by the user. */ 388 bool Dragable() const; 389 390 /** Returns true iff this Wnd can be resized by the user. */ 391 bool Resizable() const; 392 393 /** Returns true iff this Wnd is an on-top Wnd. */ 394 bool OnTop() const; 395 396 /** Returns true iff this Wnd is a modal Wnd. */ 397 bool Modal() const; 398 399 /** Returns the mode to use for child clipping. */ 400 ChildClippingMode GetChildClippingMode() const; 401 402 /** Returns true iff this Wnd should be considered a non-client-area child 403 of its parent, for clipping purposes. \see ChildClippingMode. */ 404 bool NonClientChild() const; 405 406 /** Returns true iff this Wnd will be rendered if it is registered. */ 407 bool Visible() const; 408 409 /** Returns true if this Wnd will be pre-rendered. */ 410 bool PreRenderRequired() const; 411 412 /** Returns the name of this Wnd. This name is not used by GG in any way; 413 it only exists for user convenience. */ 414 const std::string& Name() const; 415 416 /** Returns the string key that defines the type of data that this Wnd 417 represents in drag-and-drop drags. Returns an empty string when this 418 Wnd cannot be drag-and-dropped. */ 419 const std::string& DragDropDataType() const; 420 421 /** Returns the upper-left corner of window in \a screen \a coordinates 422 (taking into account parent's screen position, if any) */ 423 Pt UpperLeft() const; 424 X Left() const; 425 Y Top() const; 426 427 /** Returns (one pixel past) the lower-right corner of window in \a screen 428 \a coordinates (taking into account parent's screen position, if 429 any) */ 430 Pt LowerRight() const; 431 X Right() const; 432 Y Bottom() const; 433 434 /** Returns the upper-left corner of window, relative to its parent's 435 client area, or in screen coordinates if no parent exists. */ 436 Pt RelativeUpperLeft() const; 437 438 /** Returns (one pixel past) the lower-right corner of window, relative to 439 its parent's client area, or in screen coordinates if no parent 440 exists. */ 441 Pt RelativeLowerRight() const; 442 443 X Width() const; ///< Returns width of window. 444 Y Height() const; ///< Returns height of window. 445 446 /** Returns a \a Pt packed with width in \a x and height in \a y. */ 447 Pt Size() const; 448 449 Pt MinSize() const; ///< Returns the minimum allowable size of window. 450 Pt MaxSize() const; ///< Returns the maximum allowable size of window. 451 452 /** Returns the size of the minimum bounding box that can enclose the Wnd 453 and still show all of its elements, plus enough room for interaction 454 with those elements (if applicable). For example, a TextControl's 455 MinUsableSize() is just the area of its text, and a Scroll's 456 MinUsableSize() is the combined sizes of its up-button, down-button, 457 and tab (plus a bit of room in which to drag the tab). */ 458 virtual Pt MinUsableSize() const; 459 460 /** Returns upper-left corner of window's client area in screen 461 coordinates (or of the entire area, if no client area is specified). 462 Virtual because different windows have different shapes (and so ways 463 of calculating client area). */ 464 virtual Pt ClientUpperLeft() const; 465 466 /** Returns (one pixel past) lower-right corner of window's client area in 467 screen coordinates (or of the entire area, if no client area is 468 specified). Virtual because different windows have different shapes 469 (and so ways of calculating client area). */ 470 virtual Pt ClientLowerRight() const; 471 472 /** Returns the size of the client area \see Size(). */ 473 Pt ClientSize() const; 474 475 X ClientWidth() const; ///< Returns the width of the client area. 476 Y ClientHeight() const; ///< Returns the height of the client area. 477 478 /** Returns \a pt translated from screen- to window-coordinates. */ 479 Pt ScreenToWindow(const Pt& pt) const; 480 481 /** Returns \a pt translated from screen- to client-coordinates. */ 482 Pt ScreenToClient(const Pt& pt) const; 483 484 /** Returns true if screen-coordinate point \a pt falls within the 485 window. */ 486 virtual bool InWindow(const Pt& pt) const; 487 488 /** Returns true if screen-coordinate point \a pt falls within the 489 window's client area. */ 490 virtual bool InClient(const Pt& pt) const; 491 492 /** Returns child list; the list is const, but the children may be 493 manipulated. */ 494 const std::list<std::shared_ptr<Wnd>>& Children() const; 495 496 /** Returns the window's parent (may be null). */ 497 std::shared_ptr<Wnd> Parent() const; 498 499 /** Returns true iff \a wnd is an ancestor (indirect parent) of this wnd. */ 500 bool IsAncestorOf(const std::shared_ptr<Wnd>& wnd) const; 501 502 /** Returns the earliest ancestor window (may be null). */ 503 std::shared_ptr<Wnd> RootParent() const; 504 505 /** Returns the layout for the window, if any. */ 506 std::shared_ptr<Layout> GetLayout() const; 507 508 /** Returns the layout containing the window, if any. */ 509 Layout* ContainingLayout() const; 510 511 /** Returns the browse modes for the Wnd, including time cutoffs (in 512 milliseconds), the BrowseInfoWnds to be displayed for each browse info 513 mode, and the text (if any) to be displayed in each mode. As the time 514 that the cursor is over this Wnd exceeds each mode's time, the 515 corresponding Wnd is shown superimposed over this Wnd and its 516 children. Set the first time cutoff to 0 for immediate browse info 517 display. */ 518 const std::vector<BrowseInfoMode>& BrowseModes() const; 519 520 /** Returns the text to display for browse info mode \a mode. \throw 521 std::out_of_range May throw std::out_of_range if \a mode is not a 522 valid browse mode. */ 523 const std::string& BrowseInfoText(std::size_t mode) const; 524 525 /** Returns the currently-installed style factory if none exists, or the 526 GUI-wide one otherwise. */ 527 const std::shared_ptr<StyleFactory>& GetStyleFactory() const; 528 529 /** Returns the region under point \a pt. */ 530 virtual WndRegion WindowRegion(const Pt& pt) const; 531 532 /** Adjusts \p ul and \p lr to correct for minsize and maxsize.*/ 533 void ClampRectWithMinAndMaxSize(Pt& ul, Pt& lr) const; 534 //@} 535 536 /** \name Mutators */ ///@{ 537 /** Sets the string key that defines the type of data that this Wnd 538 represents in a drag-and-drop drag. This should be set to the empty 539 string when this Wnd cannot be used in drag-and-drop. */ 540 void SetDragDropDataType(const std::string& data_type); 541 542 /** Indicates to the Wnd that a child Wnd \a wnd is being dragged in a 543 drag-and-drop operation, which gives it the opportunity to add other 544 associated drag-and-drop Wnds (see GUI::RegisterDragDropWnd()). \a 545 offset indicates the position of the mouse relative to \a wnd's 546 UpperLeft(). */ 547 virtual void StartingChildDragDrop(const Wnd* wnd, const Pt& offset); 548 549 /** When the user drops Wnds onto this Wnd, a DragDropHere event is 550 generated, which determines which of the dropped Wnds are acceptable 551 by the dropped-on Wnd by calling DropsAcceptable. The acceptable Wnds 552 are then passed to AcceptDrops(), which handles the receipt of one or 553 more drag-and-drop wnds into this Wnd. 554 555 The shared_ptrs are passed by value to allow the compiler to move rvalues. 556 */ 557 virtual void AcceptDrops(const Pt& pt, std::vector<std::shared_ptr<Wnd>> wnds, Flags<ModKey> mod_keys); 558 559 /** Handles the cancellation of the dragging of one or more child windows, 560 whose dragging was established by the most recent call to 561 StartingChildDragDrop(). Note that even if an accepting Wnd accepts 562 some but not all Wnds via DropsAcceptable(), this function will be 563 called on those Wnds not accepted. \note CancellingChildDragDrop() 564 and ChildrenDraggedAway() are always called in that order, and are 565 always called at the end of any drag-and-drop sequence performed on a 566 child of this Wnd, whether the drag-and-drop is successful or not. */ 567 virtual void CancellingChildDragDrop(const std::vector<const Wnd*>& wnds); 568 569 /** Handles the removal of one or more child windows that have been 570 dropped onto another window which has accepted them as drops via 571 DropsAcceptable(). The accepting window retains ownership. \note 572 CancellingChildDragDrop() and ChildrenDraggedAway() are always called 573 in that order, and are always called at the end of any drag-and-drop 574 sequence performed on a child of this Wnd, whether the drag-and-drop 575 is successful or not. */ 576 virtual void ChildrenDraggedAway(const std::vector<Wnd*>& wnds, const Wnd* destination); 577 578 /** Sets a name for this Wnd. This name is not used by GG in any way; it 579 only exists for user convenience. */ 580 void SetName(const std::string& name); 581 582 /** Suppresses rendering of this window (and possibly its children) during 583 render loop. */ 584 virtual void Hide(); 585 586 /** Enables rendering of this window (and possibly its children) during 587 render loop. */ 588 virtual void Show(); 589 590 /** Called during Run(), after a modal window is registered, this is the 591 place that subclasses should put specialized modal window 592 initialization, such as setting focus to child controls. */ 593 virtual void ModalInit(); 594 595 /** Sets the mode to use for child clipping. */ 596 void SetChildClippingMode(ChildClippingMode mode); 597 598 /** Sets whether this Wnd should be considered a non-client-area child of 599 its parent, for clipping purposes. \see ChildClippingMode. */ 600 void NonClientChild(bool b); 601 602 void MoveTo(const Pt& pt); ///< Moves upper-left corner of window to \a pt. 603 void OffsetMove(const Pt& pt); ///< Moves window by \a pt pixels. 604 605 /** Resizes and/or moves window to new upper-left and lower right 606 boundaries. */ 607 virtual void SizeMove(const Pt& ul, const Pt& lr); 608 609 /** Resizes window without moving upper-left corner. */ 610 void Resize(const Pt& sz); 611 612 /** Sets the minimum allowable size of window \a pt. */ 613 virtual void SetMinSize(const Pt& sz); 614 615 /** Sets the maximum allowable size of window \a pt. */ 616 virtual void SetMaxSize(const Pt& sz); 617 618 /** Places \a wnd in child ptr list, sets's child's \a m_parent member to 619 \a this. This takes ownership of \p wnd. */ 620 void AttachChild(std::shared_ptr<Wnd> wnd); 621 622 /** Places \a wnd at the end of the child ptr list, so it is rendered last 623 (on top of the other children). */ 624 void MoveChildUp(Wnd* wnd); 625 void MoveChildUp(const std::shared_ptr<Wnd>& wnd); 626 627 /** Places \a wnd at the beginning of the child ptr list, so it is 628 rendered first (below the other children). */ 629 void MoveChildDown(Wnd* wnd); 630 void MoveChildDown(const std::shared_ptr<Wnd>& wnd); 631 632 /** Removes \a wnd from the child ptr list and resets child's m_parent. */ 633 void DetachChild(Wnd* wnd); 634 void DetachChild(const std::shared_ptr<Wnd>& wnd); 635 636 /** Remove \p wnd from the child ptr list and reset \p wnd. */ 637 template <typename T> DetachChildAndReset(T & wnd)638 void DetachChildAndReset(T& wnd) 639 { 640 DetachChild(wnd); 641 wnd.reset(); 642 } 643 644 /** Removes all Wnds from child ptr list and resets all childrens' m_parents. */ 645 void DetachChildren(); 646 647 /** Adds \a wnd to the front of the event filtering chain. */ 648 void InstallEventFilter(const std::shared_ptr<Wnd>& wnd); 649 650 /** Removes \a wnd from the filter chain. */ 651 void RemoveEventFilter(const std::shared_ptr<Wnd>& wnd); 652 653 /** Places the window's client-area children in a horizontal layout, 654 handing ownership of the window's client-area children over to the 655 layout. Removes any current layout which may exist. */ 656 void HorizontalLayout(); 657 658 /** Places the window's client-area children in a vertical layout, handing 659 ownership of the window's client-area children over to the layout. 660 Removes any current layout which may exist. */ 661 void VerticalLayout(); 662 663 /** Places the window's client-area children in a grid layout, handing 664 ownership of the window's client-area children over to the layout. 665 Removes any current layout which may exist. */ 666 void GridLayout(); 667 668 /** Sets \a layout as the layout for the window. Removes any current 669 layout which may exist, and deletes all client-area child windows. */ 670 void SetLayout(const std::shared_ptr<Layout>& layout); 671 672 /** Removes the window's layout, handing ownership of all its children 673 back to the window, with the sizes and positions they had before the 674 layout resized them. If no layout exists for the window, no action is 675 taken. */ 676 void RemoveLayout(); 677 678 /** Removes the window's layout, including all attached children, and 679 returns it. If no layout exists for the window, no action is 680 taken. */ 681 std::shared_ptr<Layout> DetachLayout(); 682 683 /** Sets the margin that should exist between the outer edges of the 684 windows in the layout and the edge of the client area. If no layout 685 exists for the window, this has no effect. */ 686 void SetLayoutBorderMargin(unsigned int margin); 687 688 /** Sets the margin that should exist between the windows in the layout. 689 If no layout exists for the window, this has no effect. */ 690 void SetLayoutCellMargin(unsigned int margin); 691 692 /** Update Wnd prior to Render(). 693 694 PreRender() is called before Render() if RequirePreRender() was called. 695 The default PreRender() resets the flag from RequirePreRender(). 696 Wnd::PreRender() should be called in any overrides to reset 697 RequirePreRender(). 698 699 In the GUI processing loop the PreRender() of child windows whose 700 RequirePreRender() flag is set will have been called before their 701 parent PreRender(). */ 702 virtual void PreRender(); 703 704 /** Require that PreRender() be called to update layout before the next Render(). */ 705 virtual void RequirePreRender(); 706 707 /** Draws this Wnd. Note that Wnds being dragged for a drag-and-drop 708 operation are rendered twice -- once in-place as normal, once in the 709 location of the drag operation, attached to the cursor. Such Wnds may 710 wish to render themselves differently in those two cases. To 711 determine which render is being performed, they can call 712 GUI::GetGUI()->RenderingDragDropWnds(). */ 713 virtual void Render(); 714 715 /** This executes a modal window and gives it its modality. For non-modal 716 windows, this function is a no-op. It returns false if the window is 717 non-modal, or true after successful modal execution.*/ 718 virtual bool Run(); 719 720 /** Ends the current execution of Run(), if any. */ 721 virtual void EndRun(); 722 723 /** Sets the time cutoff (in milliseconds) for a browse info mode. If \a 724 mode is not less than the current number of modes, extra modes will be 725 created as needed. The extra nodes will be set to the value of the 726 last time at the time the method is called, or \a time if there were 727 initially no modes. */ 728 void SetBrowseModeTime(unsigned int time, std::size_t mode = 0); 729 730 /** Sets the Wnd that is used to show browse info about this Wnd in the 731 browse info mode \a mode. \throw std::out_of_range May throw 732 std::out_of_range if \a mode is not a valid browse mode. */ 733 void SetBrowseInfoWnd(const std::shared_ptr<BrowseInfoWnd>& wnd, std::size_t mode = 0); 734 735 /** Removes the Wnd that is used to show browse info about this Wnd in the 736 browse info mode \a mode (but does nothing to the mode itself). 737 \throw std::out_of_range May throw std::out_of_range if \a mode is not 738 a valid browse mode. */ 739 void ClearBrowseInfoWnd(std::size_t mode = 0); 740 741 /** Sets the browse info window for mode \a mode to a Wnd with the 742 specified color and border color which contains the specified text. 743 \throw std::out_of_range May throw std::out_of_range if \a mode is not 744 a valid browse mode. */ 745 void SetBrowseText(const std::string& text, std::size_t mode = 0); 746 747 /** Sets the browse modes for the Wnd, including time cutoffs (in 748 milliseconds), the BrowseInfoWnds to be displayed for each browse info 749 mode, and the text (if any) to be displayed in each mode. As the time 750 that the cursor is over this Wnd exceeds each mode's time, the 751 corresponding Wnd is shown superimposed over this Wnd and its 752 children. Set the first time cutoff to 0 for immediate browse info 753 display. */ 754 void SetBrowseModes(const std::vector<BrowseInfoMode>& modes); 755 756 /** Sets the currently-installed style factory. */ 757 void SetStyleFactory(const std::shared_ptr<StyleFactory>& factory); 758 //@} 759 760 761 /** Returns the single time to place in the browse modes during Wnd 762 construction. */ 763 static unsigned int DefaultBrowseTime(); 764 765 /** Sets the single time to place in the browse modes during Wnd 766 construction. */ 767 static void SetDefaultBrowseTime(unsigned int time); 768 769 /** Returns the single BrowseInfoWnd to place in the browse modes during 770 Wnd construction. This returns a TextBoxBrowseInfoWnd with a default 771 parameterization. */ 772 static const std::shared_ptr<BrowseInfoWnd>& DefaultBrowseInfoWnd(); 773 774 /** Sets the single BrowseInfoWnd to place in the browse modes during Wnd 775 construction. */ 776 static void SetDefaultBrowseInfoWnd(const std::shared_ptr<BrowseInfoWnd>& browse_info_wnd); 777 778 /** \name Exceptions */ ///@{ 779 /** The base class for Wnd exceptions. */ 780 GG_ABSTRACT_EXCEPTION(Exception); 781 782 /** Thrown when a request to perform a layout fails due to child Wnds in 783 illegal starting positions, or when a SetLayout() call would result in 784 an illegal state. */ 785 GG_CONCRETE_EXCEPTION(BadLayout, GG::Wnd, Exception); 786 //@} 787 788 protected: 789 /** Sets the \a second member of each iterator to true or false, 790 indicating whether the Wnd in the \a first member would be accepted if 791 dropped on this Wnd at \a pt. */ 792 virtual void DropsAcceptable(DropsAcceptableIter first, DropsAcceptableIter last, 793 const Pt& pt, Flags<ModKey> mod_keys) const; 794 795 /** The states a Wnd may be in, with respect to drag-and-drop operations. 796 Wnds may wish to consider the current state when rendering to provide 797 visual feedback to the user. */ 798 enum DragDropRenderingState : int { 799 /** No drag-and-drop is taking place at all with this Wnd. */ 800 NOT_DRAGGED, 801 802 /** This Wnd is being dragged-and-dropped, but we're currently rendering 803 the unmoving copy. The dragged copy is rendered at another time. */ 804 IN_PLACE_COPY, 805 806 /** This Wnd is being dragged-and-dropped, and it is currently over a 807 drop target that \b will \b not accept it. */ 808 DRAGGED_OVER_UNACCEPTING_DROP_TARGET, 809 810 /** This Wnd is being dragged-and-dropped, and it is currently over a 811 drop target that \b will accept it. */ 812 DRAGGED_OVER_ACCEPTING_DROP_TARGET 813 }; 814 815 /** \name Structors */ ///@{ 816 Wnd(); 817 818 /** Ctor that allows a size and position to be specified, as well as 819 creation flags. */ 820 Wnd(X x, Y y, X w, Y h, Flags<WndFlag> flags = INTERACTIVE | DRAGABLE); 821 //@} 822 823 /** \name Accessors */ ///@{ 824 /** Returns the states the Wnd is in, with respect to drag-and-drop 825 operations. Wnds may wish to consider the current state when 826 rendering to provide visual feedback to the user. */ 827 DragDropRenderingState GetDragDropRenderingState() const; 828 //@} 829 830 /** \name Mutators */ ///@{ 831 /** Respond to left button down msg. A window receives this whenever any 832 input device button changes from up to down while over the window. 833 \note If this Wnd was created with the REPEAT_BUTTON_DOWN flag, this 834 method may be called multiple times during a single button 835 press-release cycle. \see GG::GUI */ 836 virtual void LButtonDown(const Pt& pt, Flags<ModKey> mod_keys); 837 838 /** Respond to left button drag msg (even if this Wnd is not dragable). 839 Drag messages are only sent to the window over which the button was 840 pressed at the beginning of the drag. A window receives this whenever 841 any input device button is down and the cursor is moving while over 842 the window. The window will also receive drag messages when the mouse 843 is being dragged outside the window's area. */ 844 virtual void LDrag(const Pt& pt, const Pt& move, Flags<ModKey> mod_keys); 845 846 /** Respond to release of left mouse button outside this Wnd, if it was 847 originally depressed over this Wnd. A Wnd will receive an LButtonUp() 848 message whenever a drag that started over its area ends, even if the 849 cursor is not currently over the window when this happens. */ 850 virtual void LButtonUp(const Pt& pt, Flags<ModKey> mod_keys); 851 852 /** Respond to release of left mouse button over this Wnd, if it was also 853 originally depressed over this Wnd. A Wnd will receive an LButtonUp() 854 message whenever a drag that started over its area ends over its area 855 as well. */ 856 virtual void LClick(const Pt& pt, Flags<ModKey> mod_keys); 857 858 /** Respond to second left click in window within the time limit. A 859 window will receive an LDoubleClick() message instead of an 860 LButtonDown() or LClick() message if the left input device button is 861 pressed over a window that was l-clicked within a double-click time 862 interval. Note that this means a double click is always preceded by a 863 click. For a double click to occur, no other window may have received 864 a *Click() or *ButtonDown() message in during the interval. */ 865 virtual void LDoubleClick(const Pt& pt, Flags<ModKey> mod_keys); 866 867 /** Respond to middle button down msg. \see LButtonDown() */ 868 virtual void MButtonDown(const Pt& pt, Flags<ModKey> mod_keys); 869 870 /** Respond to middle button drag msg (even if this Wnd is not dragable). 871 \see LDrag() */ 872 virtual void MDrag(const Pt& pt, const Pt& move, Flags<ModKey> mod_keys); 873 874 /** Respond to release of middle mouse button outside this Wnd, if it was 875 originally depressed over this Wnd. \see LButtonUp() */ 876 virtual void MButtonUp(const Pt& pt, Flags<ModKey> mod_keys); 877 878 /** Respond to release of middle mouse button over this Wnd, if it was 879 also originally depressed over this Wnd. \see LClick() */ 880 virtual void MClick(const Pt& pt, Flags<ModKey> mod_keys); 881 882 /** Respond to second middle click in window within the time limit. \see 883 LDoubleClick() */ 884 virtual void MDoubleClick(const Pt& pt, Flags<ModKey> mod_keys); 885 886 /** Respond to right button down msg. \see LButtonDown() */ 887 virtual void RButtonDown(const Pt& pt, Flags<ModKey> mod_keys); 888 889 /** Respond to right button drag msg (even if this Wnd is not dragable). 890 \see LDrag() */ 891 virtual void RDrag(const Pt& pt, const Pt& move, Flags<ModKey> mod_keys); 892 893 /** Respond to release of right mouse button outside this Wnd, if it was 894 originally depressed over this Wnd. \see LButtonUp() */ 895 virtual void RButtonUp(const Pt& pt, Flags<ModKey> mod_keys); 896 897 /** Respond to release of right mouse button over this Wnd, if it was also 898 originally depressed over this Wnd. \see LClick() */ 899 virtual void RClick(const Pt& pt, Flags<ModKey> mod_keys); 900 901 /** Respond to second right click in window within the time limit. \see 902 LDoubleClick() */ 903 virtual void RDoubleClick(const Pt& pt, Flags<ModKey> mod_keys); 904 905 /** Respond to cursor entering window's coords. */ 906 virtual void MouseEnter(const Pt& pt, Flags<ModKey> mod_keys); 907 908 /** Respond to cursor moving about within the Wnd, or to cursor lingering 909 within the Wnd for a long period of time. A MouseHere() message will 910 not be generated the first time the cursor enters the window's area. 911 In that case, a MouseEnter() message is generated. */ 912 virtual void MouseHere(const Pt& pt, Flags<ModKey> mod_keys); 913 914 /** Respond to cursor leaving window's coords. */ 915 virtual void MouseLeave(); 916 917 /** Respond to movement of the mouse wheel (move > 0 indicates the wheel 918 is rolled up, < 0 indicates down) */ 919 virtual void MouseWheel(const Pt& pt, int move, Flags<ModKey> mod_keys); 920 921 /** Respond to the cursor entering the Wnd's coords while dragging 922 drag-and-drop Wnds. \a drop_wnds_acceptable will have the bools 923 set to true or valse to indicate whether this Wnd can accept the 924 dragged wnds as a drop. */ 925 virtual void DragDropEnter(const Pt& pt, std::map<const Wnd*, bool>& drop_wnds_acceptable, 926 Flags<ModKey> mod_keys); 927 928 /** Respond to cursor moving about within the Wnd, or to cursor lingering 929 within the Wnd for a long period of time, while dragging drag-and-drop 930 Wnds. A DragDropHere() message will not be generated the first time 931 the cursor enters the window's area. In that case, a DragDropEnter() 932 message is generated. \a drop_wnds_acceptable will have the bools 933 set to true or valse to indicate whether this Wnd can accept the 934 dragged wnds as a drop. */ 935 virtual void DragDropHere(const Pt& pt, std::map<const Wnd*, bool>& drop_wnds_acceptable, 936 Flags<ModKey> mod_keys); 937 938 /** Polls this Wnd about whether the Wnds in \a drop_wnds_acceptable will 939 be accpeted by this Wnd by calling DropsAcceptable(...) */ 940 virtual void CheckDrops(const Pt& pt, std::map<const Wnd*, bool>& drop_wnds_acceptable, 941 Flags<ModKey> mod_keys); 942 943 /** Respond to cursor leaving the Wnd's bounds while dragging 944 drag-and-drop Wnds. */ 945 virtual void DragDropLeave(); 946 947 /** Respond to down-keystrokes (focus window only). A window may receive 948 KeyPress() messages passed up to it from its children. For instance, 949 Control-derived classes pass KeyPress() messages to their Parent() 950 windows by default. \note Though mouse clicks consist of a press and 951 a release, all Control classes by default respond immediately to 952 KeyPress(), not KeyRelease(); in fact, by default no Wnd class does 953 anything at all on a KeyRelease event. \note \a key_code_point will 954 be zero if Unicode support is unavailable. */ 955 virtual void KeyPress(Key key, std::uint32_t key_code_point, Flags<ModKey> mod_keys); 956 957 /** Respond to up-keystrokes (focus window only). A window may receive 958 KeyRelease() messages passed up to it from its children. For 959 instance, Control-derived classes pass KeyRelease() messages to their 960 Parent() windows by default. \note \a key_code_point will be zero if 961 Unicode support is unavailable. */ 962 virtual void KeyRelease(Key key, std::uint32_t key_code_point, Flags<ModKey> mod_keys); 963 964 /** Respond to text input regardless of the method. Focus window only. 965 A window may receive TextInput() messages passed up to it from its 966 children. */ 967 virtual void TextInput(const std::string* text); 968 969 /** Respond to this window gaining the input focus. */ 970 virtual void GainingFocus(); 971 972 /** Respond to this window losing the input focus. */ 973 virtual void LosingFocus(); 974 975 /** Respond to Timer \a timer firing at time \a ticks. */ 976 virtual void TimerFiring(unsigned int ticks, Timer* timer); 977 978 /** Handles an WndEvent destined for Wnd \a w, but which this Wnd is 979 allowed to handle first. Returns true if this filter processed the 980 message. */ 981 virtual bool EventFilter(Wnd* w, const WndEvent& event); 982 983 /** Handles all messages, and calls appropriate function (LButtonDown(), 984 LDrag(), etc.). */ 985 void HandleEvent(const WndEvent& event); 986 987 /** Sends the current event to Parent() for processing, if Parent() is 988 non-null. This must only be called from within a WndEvent handler 989 (e.g. LClick()). */ 990 void ForwardEventToParent(); 991 992 /** Sets up child clipping for this window. */ 993 void BeginClipping(); 994 995 /** Restores state to what it was before BeginClipping() was called. */ 996 void EndClipping(); 997 998 /** Sets up non-client-area-only child clipping for this window. \note 999 This function is only useful when GetChildClippingMode() is 1000 ClipToClientAndWindowSeparately. */ 1001 void BeginNonclientClipping(); 1002 1003 /** Restores state to what it was before BeginNonclientClipping() was 1004 called. \note This function is only useful when 1005 GetChildClippingMode() is ClipToClientAndWindowSeparately. */ 1006 void EndNonclientClipping(); 1007 1008 virtual void SetParent(const std::shared_ptr<Wnd>& wnd); 1009 //@} 1010 1011 /** Modal Wnd's set this to true to stop modal loop. */ 1012 bool m_done = false; 1013 1014 private: 1015 void ValidateFlags(); ///< Sanity-checks the window creation flags 1016 virtual void BeginClippingImpl(ChildClippingMode mode); 1017 virtual void EndClippingImpl(ChildClippingMode mode); 1018 virtual void BeginNonclientClippingImpl(); 1019 virtual void EndNonclientClippingImpl(); 1020 1021 /** Code common to DetachChild and DetachChildren. */ 1022 void DetachChildCore(Wnd* wnd); 1023 1024 /// m_parent may be expired or null if there is no parent. m_parent will reset itself if expired. 1025 mutable std::weak_ptr<Wnd> m_parent; 1026 std::string m_name = ""; ///< A user-significant name for this Wnd 1027 std::list<std::shared_ptr<Wnd>> m_children; ///< List of ptrs to child windows kept in order of decreasing area 1028 bool m_visible = true; 1029 bool m_needs_prerender = false; ///< Indicates if Wnd needs a PreRender(); 1030 std::string m_drag_drop_data_type = ""; ///< The type of drag-and-drop data this Wnd represents, if any. If empty/blank, indicates that this Wnd cannot be drag-dropped. 1031 ChildClippingMode m_child_clipping_mode; 1032 bool m_non_client_child = false; 1033 Pt m_upperleft; ///< Upper left point of window 1034 Pt m_lowerright; ///< Lower right point of window 1035 Pt m_min_size; ///< Minimum window size Pt(0, 0) (= none) by default 1036 Pt m_max_size; ///< Maximum window size Pt(1 << 30, 1 << 30) (= none) by default 1037 1038 /** The Wnds that are filtering this Wnd's events. These are in reverse 1039 order: top of the stack is back(). */ 1040 std::vector<std::weak_ptr<Wnd>> m_filters; 1041 1042 std::set<std::weak_ptr<Wnd>, std::owner_less<std::weak_ptr<Wnd>>> 1043 m_filtering; ///< The Wnds in whose filter chains this Wnd lies 1044 mutable std::weak_ptr<Layout> m_layout; ///< The layout for this Wnd, if any 1045 mutable std::weak_ptr<Layout> m_containing_layout; ///< The layout that contains this Wnd, if any 1046 std::vector<BrowseInfoMode> m_browse_modes; ///< The browse info modes for this window 1047 1048 /** The style factory to use when creating dialogs or child controls. */ 1049 std::shared_ptr<StyleFactory> m_style_factory; 1050 1051 /** Flags supplied at window creation for clickability, dragability, 1052 resizability, etc. */ 1053 Flags<WndFlag> m_flags; 1054 1055 /** The default time to set for the first (and only) value in 1056 m_browse_mode_times during Wnd contruction */ 1057 static unsigned int s_default_browse_time; 1058 1059 /** The default BrowseInfoWmd to set for the first (and only) value in 1060 m_browse_mode_times during Wnd contruction */ 1061 static std::shared_ptr<BrowseInfoWnd> s_default_browse_info_wnd; 1062 1063 friend class GUI; ///< GUI needs access to \a m_children, etc. 1064 friend struct GUIImpl; 1065 friend class Timer; ///< Timer needs to be able to call HandleEvent 1066 }; 1067 1068 } // namespace GG 1069 1070 #endif 1071