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