1 /*
2  * OpenClonk, http://www.openclonk.org
3  *
4  * Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/
5  * Copyright (c) 2009-2016, The OpenClonk Team and contributors
6  *
7  * Distributed under the terms of the ISC license; see accompanying file
8  * "COPYING" for details.
9  *
10  * "Clonk" is a registered trademark of Matthes Bender, used with permission.
11  * See accompanying file "TRADEMARK" for details.
12  *
13  * To redistribute this file separately, substitute the full license texts
14  * for the above references.
15  */
16 // generic user interface
17 // defines user controls
18 
19 // 2do:
20 //   mouse wheel processing
21 //   disabled buttons
22 
23 #ifndef INC_C4Gui
24 #define INC_C4Gui
25 
26 #include "graphics/C4FacetEx.h"
27 #include "graphics/C4FontLoader.h"
28 #include "gui/C4KeyboardInput.h"
29 #include "lib/C4Rect.h"
30 #include "lib/C4LogBuf.h"
31 #include "object/C4Id.h"
32 #include "platform/C4Window.h"
33 #include "platform/StdScheduler.h"
34 
35 // consts (load those from a def file some time)
36 // font colors - alpha is font alpha, which is inversed opaque
37 #define C4GUI_CaptionFontClr     0xffffffff
38 #define C4GUI_Caption2FontClr    0xffffff00
39 #define C4GUI_InactCaptionFontClr 0xffafafaf
40 #define C4GUI_ButtonFontClr      0xffffff00
41 #define C4GUI_ButtonFontShadowClr 0xff000000
42 #define C4GUI_StatusFontClr      0xffffffff
43 #define C4GUI_MessageFontClr     0xffffffff
44 #define C4GUI_MessageFontAlpha   0xff000000
45 #define C4GUI_InactMessageFontClr 0xffafafaf
46 #define C4GUI_NotifyFontClr      0xffff0000
47 #define C4GUI_ComboFontClr       0xffffffff
48 #define C4GUI_CheckboxFontClr    0xffffffff
49 #define C4GUI_SmallCheckboxFontClr 0xffffffff
50 #define C4GUI_CheckboxDisabledFontClr 0xffafafaf
51 #define C4GUI_LogFontClr         0xffafafaf
52 #define C4GUI_LogFontClr2        0xffff1f1f
53 #define C4GUI_ErrorFontClr       0xffff1f1f
54 #define C4GUI_ProgressBarFontClr 0xffffffff
55 #define C4GUI_ContextFontClr     0xffffffff
56 #define C4GUI_GfxTabCaptActiveClr 0xff000000
57 #define C4GUI_GfxTabCaptInactiveClr 0xff000000
58 
59 // other colors
60 #define C4GUI_ImportantBGColor   0x2f00007f
61 #define C4GUI_ProgressBarColor   0x4fffffff
62 #define C4GUI_ListBoxSelColor    0x4faf0000
63 #define C4GUI_ListBoxInactSelColor  0x4f7f7f7f
64 #define C4GUI_ContextSelColor    0x4faf0000
65 #define C4GUI_ContextBGColor     0xaf3f1a00
66 #define C4GUI_StandardBGColor    0x9f000000
67 #define C4GUI_ActiveTabBGColor   C4GUI_StandardBGColor
68 #define C4GUI_ListBoxBarColor    0x7f772200
69 #define C4GUI_EditBGColor        0x7f000000
70 #define C4GUI_EditFontColor      0xffffffff
71 
72 #define C4GUI_ToolTipBGColor     0xFFF1EA78
73 #define C4GUI_ToolTipFrameColor  0x7f000000
74 #define C4GUI_ToolTipColor       0xFF483222
75 
76 // winner/loser color marking
77 #define C4GUI_WinningTextColor        0xffffdf00
78 #define C4GUI_WinningBackgroundColor  0xafaf7a00
79 #define C4GUI_LosingTextColor         0xffffffff
80 #define C4GUI_LosingBackgroundColor   0x7fafafaf
81 
82 
83 // border colors for 3D-frames
84 #define C4GUI_BorderAlpha        0x4f
85 #define C4GUI_BorderColor1       0x772200
86 #define C4GUI_BorderColor2       0x331100
87 #define C4GUI_BorderColor3       0xaa4400
88 #define C4GUI_BorderColorA1      (C4GUI_BorderAlpha<<24 | C4GUI_BorderColor1)
89 #define C4GUI_BorderColorA2      (C4GUI_BorderAlpha<<24 | C4GUI_BorderColor2)
90 #define C4GUI_BorderColorA3      (C4GUI_BorderAlpha<<24 | C4GUI_BorderColor3)
91 
92 // GUI icon sizes
93 #define C4GUI_IconWdt   40
94 #define C4GUI_IconHgt   40
95 #define C4GUI_IconExWdt 64
96 #define C4GUI_IconExHgt 64
97 #define C4GUI_ControllerIconWdt 100
98 #define C4GUI_ControllerIconHgt 100
99 
100 #define C4GUI_IconLabelSpacing   2 // space between an icon and its text
101 
102 // scroll bar size
103 #define C4GUI_ScrollBarWdt   16
104 #define C4GUI_ScrollBarHgt   16
105 #define C4GUI_ScrollArrowHgt 16
106 #define C4GUI_ScrollArrowWdt 16
107 #define C4GUI_ScrollThumbHgt 16 // only for non-dynamic scroll thumbs
108 #define C4GUI_ScrollThumbWdt 16 // only for non-dynamic scroll thumbs
109 
110 // button size
111 #define C4GUI_ButtonHgt         32 // height of buttons
112 #define C4GUI_BigButtonHgt      40 // height of bigger buttons (main menu)
113 #define C4GUI_ButtonAreaHgt     40 // height of button areas
114 #define C4GUI_DefButtonWdt     140 // width of default buttons
115 #define C4GUI_DefButton2Wdt    120 // width of default buttons if there are two of them
116 #define C4GUI_DefButton2HSpace  10 // horzontal space between two def dlg buttons
117 
118 // default checkbox height
119 #define C4GUI_CheckBoxHgt         32
120 #define C4GUI_CheckBoxLabelSpacing 4 // pixels between checkbox box and label
121 
122 // list box item spacing
123 #define C4GUI_DefaultListSpacing  1 // 1 px of free space between two list items
124 #define C4GUI_ListBoxBarIndent   10
125 
126 // default dialog box sizes
127 #define C4GUI_MessageDlgWdt    500 // width of message dialog
128 #define C4GUI_MessageDlgWdtMedium 360 // width of message dialog w/o much text
129 #define C4GUI_MessageDlgWdtSmall 300 // width of message dialog w/o much text
130 #define C4GUI_ProgressDlgWdt   500 // width of progress dialog
131 #define C4GUI_InputDlgWdt      300
132 #define C4GUI_DefDlgIndent      10 // indent for default dlg items
133 #define C4GUI_DefDlgSmallIndent  4 // indent for dlg items that are grouped
134 #define C4GUI_MessageDlgVRoom  100 // height added to text height in message dialog
135 #define C4GUI_ProgressDlgVRoom 150 // height added to text height in progress dialog
136 #define C4GUI_InputDlgVRoom    150
137 #define C4GUI_ProgressDlgPBHgt  30 // height of progress bar in progress dlg
138 #define C4GUI_InfoDlgWdt       620 // width of info dialog
139 #define C4GUI_InfoDlgVRoom     100 // height added to text height in info dialog
140 #define C4GUI_MaxToolTipWdt    500 // maximum width for tooltip boxes
141 
142 // time for tooltips to appear (msecs) -evaluated while drawing
143 #define C4GUI_ToolTipShowTime 500 // 0.5 seconds
144 
145 // time for title bars to start scrolling to make longer text visible -evaluated while drawing
146 #define C4GUI_TitleAutoScrollTime 3000 // 3 seconds
147 
148 // time interval for tab caption scrolling
149 #define C4GUI_TabCaptionScrollTime 500 // 0.5 seconds
150 
151 // Z-ordering of dialogs
152 #define C4GUI_Z_CHAT            +2 // chat input dialog more important than other input dialogs
153 #define C4GUI_Z_INPUT           +1 // input dialogs on top of others
154 #define C4GUI_Z_DEFAULT          0 // normal placement on top of viewports
155 #define C4GUI_Z_PLAYERMENU      -1 // inside viewport: player menu
156 #define C4GUI_Z_OBJECTMENU      -2 // inside viewport: cursor menu
157 
158 #define C4GUI_MinWoodBarHgt     23
159 
160 #define C4GUI_FullscreenDlg_TitleHeight      C4UpperBoardHeight // pixels reserved for top of fullscreen dialog title
161 #define C4GUI_FullscreenCaptionFontClr       0xffffff00
162 
163 namespace C4GUI
164 {
165 
166 	// some class predefs
167 
168 	// C4Gui.cpp
169 	class Element; class Screen; class CMouse;
170 	class ComponentAligner;
171 
172 	// C4GuiLabels.cpp
173 	class Label; class WoodenLabel; class MultilineLabel;
174 	class HorizontalLine; class ProgressBar;
175 	class Picture; class Icon; class PaintBox;
176 	class TextWindow;
177 
178 	// C4GuiContainers.cpp
179 	class Container; class Window; class GroupBox; class Control;
180 	class ScrollBar; class ScrollWindow;
181 
182 	// C4GuiButton.cpp
183 	class Button; template <class CallbackDlg, class Base> class CallbackButton;
184 	class IconButton;
185 	class CloseButton; class OKButton; class CancelButton;
186 	class CloseIconButton; class OKIconButton; class CancelIconButton;
187 
188 	// C4GuiEdit.cpp
189 	class Edit;
190 
191 	// C4GuiCheckBox.cpp
192 	class CheckBox;
193 
194 	// C4GuiListBox.cpp
195 	class ListBox;
196 
197 	// C4GuiTabular.cpp
198 	class Tabular;
199 
200 	// C4GuiMenu.cpp
201 	class ContextMenu;
202 	class ContextButton;
203 
204 	// C4GUIComboBox.cpp
205 	class ComboBox;
206 
207 	// C4GuiDialog.cpp
208 	class Dialog; class MessageDialog; class ProgressDialog;
209 	class InputDialog; class InfoDialog;
210 
211 	// inline
212 	class MenuHandler; class ContextHandler;
213 
214 
215 	// expand text like "Te&xt" to "Te<c ffff00>x</c>t". Color yellow for normal hotkey and red for tooltip.
216 	bool ExpandHotkeyMarkup(StdStrBuf &sText, uint32_t &rcHotkey, bool for_tooltip = false);
217 
218 	// make color readable on black: max alpha to 0x1f, max color hues
219 	DWORD MakeColorReadableOnBlack(DWORD &rdwClr);
220 
221 	// menu handler: generic context menu callback
222 	class MenuHandler
223 	{
224 	public:
225 		MenuHandler() = default; //ctor
226 		virtual ~MenuHandler() = default; // dtor
227 
228 		virtual void OnOK(Element *pTarget) = 0; // menu item selected
229 	};
230 
231 	// context handler: opens context menu on right-click or menu key
232 	class ContextHandler
233 	{
234 	private:
235 		int32_t iRefs{0};
236 	public:
237 		ContextHandler() = default; //ctor
238 		virtual ~ContextHandler() = default; // dtor
239 
240 		virtual bool OnContext(Element *pOnElement, int32_t iX, int32_t iY) = 0; // context queried - ret true if handled
241 		virtual ContextMenu *OnSubcontext(Element *pOnElement) = 0; // subcontext queried
242 
Ref()243 		inline void Ref() { ++iRefs; }
DeRef()244 		inline void DeRef() { if (!--iRefs) delete this; }
245 	};
246 
247 	// generic callback handler
248 	class BaseCallbackHandler
249 	{
250 	private:
251 		int32_t iRefs{0};
252 	public:
253 		BaseCallbackHandler()  = default;
254 		virtual ~BaseCallbackHandler() = default;
255 
Ref()256 		inline void Ref() { ++iRefs; }
DeRef()257 		inline void DeRef() { if (!--iRefs) delete this; }
258 
259 		virtual void DoCall(class Element *pElement) = 0;
260 	};
261 
262 	template <class CB> class CallbackHandler : public BaseCallbackHandler
263 	{
264 	public:
265 		typedef void (CB::*Func)(class Element *pElement);
266 
267 	private:
268 		CB *pCBClass;
269 		Func CBFunc;
270 
271 	public:
DoCall(class Element * pElement)272 		void DoCall(class Element *pElement) override
273 		{
274 			((pCBClass)->*CBFunc)(pElement);
275 		}
276 
CallbackHandler(CB * pTarget,Func rFunc)277 		CallbackHandler(CB *pTarget, Func rFunc) : pCBClass(pTarget), CBFunc(rFunc) {}
278 	};
279 
280 	template <class CB> class CallbackHandlerNoPar : public BaseCallbackHandler
281 	{
282 	public:
283 		typedef void (CB::*Func)();
284 
285 	private:
286 		CB *pCBClass;
287 		Func CBFunc;
288 
289 	public:
DoCall(class Element * pElement)290 		void DoCall(class Element *pElement) override
291 		{
292 			((pCBClass)->*CBFunc)();
293 		}
294 
CallbackHandlerNoPar(CB * pTarget,Func rFunc)295 		CallbackHandlerNoPar(CB *pTarget, Func rFunc) : pCBClass(pTarget), CBFunc(rFunc) {}
296 	};
297 
298 	template <class CB, class ParType> class CallbackHandlerExPar : public BaseCallbackHandler
299 	{
300 	public:
301 		typedef void (CB::*Func)(ParType);
302 
303 	private:
304 		CB *pCBClass;
305 		ParType par;
306 		Func CBFunc;
307 
308 	public:
DoCall(class Element * pElement)309 		void DoCall(class Element *pElement) override
310 		{
311 			((pCBClass)->*CBFunc)(par);
312 		}
313 
CallbackHandlerExPar(CB * pTarget,Func rFunc,ParType par)314 		CallbackHandlerExPar(CB *pTarget, Func rFunc, ParType par) : pCBClass(pTarget), par(par), CBFunc(rFunc) {}
315 	};
316 
317 	// callback with parameter coming from calling class
318 	template <class ParType> class BaseParCallbackHandler : public BaseCallbackHandler
319 	{
320 	protected:
DoCall(class Element * pElement)321 		void DoCall(class Element *pElement) override {assert(false);} // no-par: Not to be called
322 	public:
323 		BaseParCallbackHandler() = default;
324 
325 		virtual void DoCall(ParType par) = 0;
326 	};
327 
328 	template <class CB, class ParType> class ParCallbackHandler : public BaseParCallbackHandler<ParType>
329 	{
330 	public:
331 		typedef void (CB::*Func)(ParType par);
332 
333 	private:
334 		CB *pCBClass;
335 		Func CBFunc;
336 
337 
338 	protected:
339 		// not to be called, but avoid warning for hiding base class functions
340 		using BaseParCallbackHandler<ParType>::DoCall;
341 
342 	public:
DoCall(ParType par)343 		void DoCall(ParType par) override { ((pCBClass)->*CBFunc)(par); }
344 
ParCallbackHandler(CB * pTarget,Func rFunc)345 		ParCallbackHandler(CB *pTarget, Func rFunc) : pCBClass(pTarget), CBFunc(rFunc) {}
346 	};
347 
348 	// three facets for left/top, middle and right/bottom of an auto-sized bar
349 	struct DynBarFacet
350 	{
351 		C4Facet fctBegin, fctMiddle, fctEnd;
352 
353 		void SetHorizontal(C4Surface &rBySfc, int iHeight=0, int iBorderWidth=0);
354 		void SetHorizontal(C4Facet &rByFct, int32_t iBorderWidth=0);
ClearDynBarFacet355 		void Clear() { fctBegin.Default(); fctMiddle.Default(); fctEnd.Default(); }
356 	};
357 
358 	// facets used to draw a scroll bar
359 	struct ScrollBarFacets
360 	{
361 		DynBarFacet barScroll;
362 		C4Facet fctScrollDTop, fctScrollPin, fctScrollDBottom;
363 
364 		void Set(const C4Facet &rByFct, int32_t iPinIndex=0);
ClearScrollBarFacets365 		void Clear() { barScroll.Clear(); fctScrollDTop.Default(); fctScrollPin.Default(); fctScrollDBottom.Default(); }
366 	};
367 
368 	// a generic gui-element
369 	class Element
370 	{
371 	private:
372 		StdStrBuf ToolTip; // MouseOver - status text
373 		bool is_immediate_tooltip{false};
374 
375 	protected:
376 		Container *pParent{nullptr};     // owning container
377 		Element *pPrev, *pNext; // previous and next element of same container
378 		Window *pDragTarget{nullptr};    // target that is dragged around when the user drags this element
379 		int32_t iDragX, iDragY;     // drag start pos
380 		bool fDragging{false};         // if set, mouse is down on component and dragging enabled
381 		ContextHandler *pContextHandler{nullptr}; // context handler to be called upon context menu request
382 	public:
383 		bool fVisible{true}; // if false, component (and subcomponents) are not drawn
384 	protected:
385 		C4Rect rcBounds; // element bounds
386 
Draw(C4TargetFacet & cgo)387 		virtual void Draw(C4TargetFacet &cgo) { DrawElement(cgo); } // draw this class (this + any contents)
DrawElement(C4TargetFacet & cgo)388 		virtual void DrawElement(C4TargetFacet &cgo) { };           // draw element itself
389 
390 		virtual void RemoveElement(Element *pChild); // clear ptrs
391 
392 		virtual void UpdateSize();                // called when own size changed
393 		virtual void UpdatePos();                 // called when own position changed
394 
395 		void Draw3DFrame(C4TargetFacet &cgo, bool fUp=false, int32_t iIndent=1, BYTE byAlpha=C4GUI_BorderAlpha, bool fDrawTop=true, int32_t iTopOff=0, bool fDrawLeft=true, int32_t iLeftOff=0); // draw frame around element
396 		void DrawBar(C4TargetFacet &cgo, DynBarFacet &rFacets); // draw gfx bar within element bounds
397 		void DrawVBar(C4TargetFacet &cgo, DynBarFacet &rFacets); // draw gfx bar within element bounds
398 		void DrawHBarByVGfx(C4TargetFacet &cgo, DynBarFacet &rFacets);  // draw horizontal gfx bar within element bounds, using gfx of vertical one
399 		void DrawHVBar(C4TargetFacet &cgo, DynBarFacet &rFacets, C4DrawTransform &trf, int32_t iMiddleLength);
400 
IsOwnPtrElement()401 		virtual bool IsOwnPtrElement() { return false; } // if true is returned, item will not be deleted when container is cleared
IsExternalDrawDialog()402 		virtual bool IsExternalDrawDialog() { return false; }
IsMenu()403 		virtual bool IsMenu() { return false; }
GetDialogWindow()404 		virtual class DialogWindow* GetDialogWindow() { return nullptr; } // return DialogWindow if this element is a dialog
405 
406 		// for listbox-selection by character input
CheckNameHotkey(const char *)407 		virtual bool CheckNameHotkey(const char *) { return false; }
408 
409 	public:
GetContainer()410 		virtual Container *GetContainer() { return pParent; } // returns parent for elements; this for containers
411 
412 		virtual void MouseInput(CMouse &rMouse, int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyParam); // input: mouse movement or buttons
MouseEnter(CMouse & rMouse)413 		virtual void MouseEnter(CMouse &rMouse) {}; // called when mouse cursor enters element region
MouseLeave(CMouse & rMouse)414 		virtual void MouseLeave(CMouse &rMouse) {}; // called when mouse cursor leaves element region
415 
416 		virtual void StartDragging(CMouse &rMouse, int32_t iX, int32_t iY, DWORD dwKeyParam); // called by element in MouseInput: start dragging
417 		virtual void DoDragging(CMouse &rMouse, int32_t iX, int32_t iY, DWORD dwKeyParam);   // called by mouse: dragging process
418 		virtual void StopDragging(CMouse &rMouse, int32_t iX, int32_t iY, DWORD dwKeyParam); // called by mouse: mouse released after dragging process
419 
OnHotkey(uint32_t cHotkey)420 		virtual bool OnHotkey(uint32_t cHotkey) { return false; } // return true when hotkey has been processed
421 
422 	public:
423 		bool DoContext(); // open context menu if assigned
424 
425 	public:
426 		Element();  // ctor
427 		virtual ~Element(); // dtor
428 
GetParent()429 		Container *GetParent() { return pParent; } // get owning container
430 		virtual class Dialog *GetDlg(); // return contained dialog
431 		virtual Screen *GetScreen(); // return contained screen
IsFocusElement()432 		virtual Control *IsFocusElement() { return nullptr; }; // return control to gain focus in search-cycle
433 
UpdateOwnPos()434 		virtual void UpdateOwnPos() { };          // called when element bounds were changed externally
435 		void ScreenPos2ClientPos(int32_t &riX, int32_t &riY); // transform screen coordinates to element coordinates
436 		void ClientPos2ScreenPos(int32_t &riX, int32_t &riY); // transform element coordinates to screen coordinates
437 
438 		void SetToolTip(const char *szNewTooltip, bool is_immediate = false); // update used tooltip
439 		const char *GetToolTip();                  // return tooltip const char* (own or fallback to parent)
GetOwnToolTip()440 		const char *GetOwnToolTip() { return ToolTip.getData(); } // return tooltip const char*, without fallback to parent
IsImmediateToolTip()441 		bool IsImmediateToolTip() const { return is_immediate_tooltip; }
442 
GetWidth()443 		int32_t GetWidth() { return rcBounds.Wdt; }
GetHeight()444 		int32_t GetHeight() { return rcBounds.Hgt; }
GetBounds()445 		C4Rect &GetBounds() { return rcBounds; }
SetBounds(const C4Rect & rcNewBound)446 		void SetBounds(const C4Rect &rcNewBound) { rcBounds=rcNewBound; UpdatePos(); UpdateSize(); }
GetClientRect()447 		virtual C4Rect &GetClientRect() { return rcBounds; }
GetContainedClientRect()448 		C4Rect GetContainedClientRect() { C4Rect rc=GetClientRect(); rc.x=rc.y=0; return rc; }
GetNext()449 		Element *GetNext() const { return pNext; }
GetPrev()450 		Element *GetPrev() const { return pPrev; }
GetFirstNestedElement(bool fBackwards)451 		virtual Element *GetFirstNestedElement(bool fBackwards) { return this; }
GetFirstContained()452 		virtual Element *GetFirstContained() { return nullptr; }
453 		bool IsInActiveDlg(bool fForKeyboard);
IsParentOf(Element * pEl)454 		virtual bool IsParentOf(Element *pEl) { return false; } // whether this is the parent container (directly or recursively) of the passed element
455 
456 		C4Rect GetToprightCornerRect(int32_t iWidth=16, int32_t iHeight=16, int32_t iHIndent=4, int32_t iVIndent=4, int32_t iIndexX=0); // get rectangle to be used for context buttons and stuff
457 
458 		bool IsVisible();
459 		virtual void SetVisibility(bool fToValue);
460 
GetListItemTopSpacing()461 		virtual int32_t GetListItemTopSpacing() { return C4GUI_DefaultListSpacing; }
GetListItemTopSpacingBar()462 		virtual bool GetListItemTopSpacingBar() { return false; }
463 
SetDragTarget(Window * pToWindow)464 		void SetDragTarget(Window *pToWindow) { pDragTarget = pToWindow; }
SetContextHandler(ContextHandler * pNewHd)465 		void SetContextHandler(ContextHandler *pNewHd) // takes over ptr
466 		{
467 			if (pContextHandler) pContextHandler->DeRef();
468 			if ((pContextHandler = pNewHd)) pNewHd->Ref();
469 		}
470 		virtual ContextHandler *GetContextHandler(); // get context handler to be used (own or parent)
471 
472 		friend class Container; friend class TextWindow; friend class ListBox;
473 	};
474 
475 	// a simple text label on the screen
476 	class Label : public Element
477 	{
478 	protected:
479 		StdStrBuf sText; // label text
480 		DWORD dwFgClr; // text color
481 		int32_t x0, iAlign; // x-textstart-pos; horizontal alignment
482 		CStdFont *pFont;
483 		uint32_t cHotkey;   // hotkey for this label
484 		bool fAutosize;
485 		bool fMarkup;
486 
487 		Control *pClickFocusControl; // control that gets focus if the label is clicked or hotkey is pressed
488 
489 		void DrawElement(C4TargetFacet &cgo) override; // output label
490 		void UpdateOwnPos() override;
491 
492 		bool OnHotkey(uint32_t cHotkey) override; // focus control on correct hotkey
493 
GetLeftIndent()494 		virtual int32_t GetLeftIndent() { return 0; }
495 
496 	public:
497 		Label(const char *szLblText, int32_t iX0, int32_t iTop, int32_t iAlign=ALeft, DWORD dwFClr=0xffffffff, CStdFont *pFont=nullptr, bool fMakeReadableOnBlack = true, bool fMarkup=true); // ctor
498 		Label(const char *szLblText, const C4Rect &rcBounds, int32_t iAlign=ALeft, DWORD dwFClr=0xffffffff, CStdFont *pFont=nullptr, bool fMakeReadableOnBlack = true, bool fAutosize = true, bool fMarkup=true); // ctor
499 
500 		void MouseInput(CMouse &rMouse, int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyParam) override; // input: mouse
501 
502 		void SetText(const char *szToText, bool fAllowHotkey=true); // update text
GetText()503 		const char *GetText() { return sText.getData(); } // retrieve current text
SetClickFocusControl(Control * pToCtrl)504 		void SetClickFocusControl(Control *pToCtrl) { pClickFocusControl=pToCtrl; }
505 		void SetColor(DWORD dwToClr, bool fMakeReadableOnBlack=true) { dwFgClr = fMakeReadableOnBlack ? MakeColorReadableOnBlack(dwToClr) : dwToClr; } // update label color
506 		void SetX0(int32_t iToX0);
507 		void SetAutosize(bool fToVal) { fAutosize = fToVal; }
508 	};
509 
510 	// a label with some wood behind
511 	// used for captions
512 	class WoodenLabel : public Label
513 	{
514 	private:
515 		uint32_t iAutoScrollDelay; // if set and text is longer than would fit, the label will automatically start moving if not changed and displayed for a while
516 
517 		// Time when the label text was changed last. nullptr if not initialized; set upon first drawing
518 		C4TimeMilliseconds tLastChangeTime;
519 		int32_t iScrollPos, iScrollDir;
520 		int32_t iRightIndent;
521 	protected:
522 		void DrawElement(C4TargetFacet &cgo) override; // output label
523 
524 		C4Facet fctIcon; // icon shown at left-side of label; if set, text is aligned to left
525 
526 		int32_t GetLeftIndent() override { return fctIcon.Surface ? rcBounds.Hgt : 0; }
527 		int32_t GetRightIndent() const { return iRightIndent; }
528 
529 	public:
530 		WoodenLabel(const char *szLblText, const C4Rect &rcBounds, DWORD dwFClr=0xffffffff, CStdFont *pFont=nullptr, int32_t iAlign=ACenter, bool fMarkup=true) // ctor
531 				: Label(szLblText, rcBounds, iAlign, dwFClr, pFont, true, true, fMarkup), iAutoScrollDelay(0), tLastChangeTime(C4TimeMilliseconds::Now()), iScrollPos(0), iScrollDir(0), iRightIndent(0)
532 		{ SetAutosize(false); this->rcBounds=rcBounds; }// ctor - re-sets bounds after SetText
533 
534 		static int32_t GetDefaultHeight(CStdFont *pUseFont=nullptr);
535 
536 		void SetIcon(const C4Facet &rfctIcon);
537 		void SetAutoScrollTime(uint32_t tDelay) { iAutoScrollDelay=tDelay; ResetAutoScroll(); }
538 		void ResetAutoScroll();
539 
540 		void SetRightIndent(int32_t iNewIndent) { iRightIndent = iNewIndent; }
541 	};
542 
543 	// a multiline label with automated text clipping
544 	// used for display of log buffers
545 	class MultilineLabel : public Element
546 	{
547 	protected:
548 		C4LogBuffer Lines;
549 		bool fMarkup;
550 
551 	protected:
552 		void DrawElement(C4TargetFacet &cgo) override; // output label
553 		void UpdateHeight();
554 		void UpdateSize() override;                // update label height
555 
556 	public:
557 		MultilineLabel(const C4Rect &rcBounds, int32_t iMaxLines, int32_t iMaxBuf, const char *szIndentChars, bool fAutoGrow, bool fMarkup); // ctor
558 
559 		void AddLine(const char *szLine, CStdFont *pFont, DWORD dwClr, bool fDoUpdate, bool fMakeReadableOnBlack, CStdFont *pCaptionFont); // add line of text
560 		void Clear(bool fDoUpdate);                     // clear lines
561 
562 		friend class TextWindow;
563 	};
564 
565 	// a bar that show progress
566 	class ProgressBar : public Element
567 	{
568 	protected:
569 		int32_t iProgress, iMax;
570 
571 		void DrawElement(C4TargetFacet &cgo) override; // draw progress bar
572 
573 	public:
574 		ProgressBar(C4Rect &rrcBounds, int32_t iMaxProgress=100) // progress bar ctor
575 				: Element(), iProgress(0), iMax(iMaxProgress)
576 		{ rcBounds=rrcBounds; UpdatePos(); }
577 
578 		void SetProgress(int32_t iToProgress) { iProgress = iToProgress; }
579 	};
580 
581 	// Auxiliary design gfx: a horizontal line
582 	class HorizontalLine : public Element
583 	{
584 	protected:
585 		uint32_t dwClr, dwShadowClr;
586 
587 		void DrawElement(C4TargetFacet &cgo) override; // draw horizontal line
588 	public:
589 		HorizontalLine(C4Rect &rrcBounds, uint32_t dwClr=0x000000, uint32_t dwShadowClr=0xaf7f7f7f)
590 				: Element(), dwClr(dwClr), dwShadowClr(dwShadowClr)
591 		{ SetBounds(rrcBounds); }
592 	};
593 
594 	// picture displaying a FacetEx
595 	class Picture : public Element
596 	{
597 	protected:
598 		C4FacetSurface Facet; // picture facet
599 		bool fAspect;    // preserve width/height-ratio when drawing
600 		bool fCustomDrawClr; // custom drawing color for clrbyowner-surfaces
601 		uint32_t dwDrawClr;
602 		bool fAnimate; // if true, the picture is animated. Whoaa!
603 		int32_t iPhaseTime, iAnimationPhase, iDelay; // current animation phase - undefined if not animated
604 
605 		void DrawElement(C4TargetFacet &cgo) override; // draw the image
606 
607 	public:
608 		Picture(const C4Rect &rcBounds, bool fAspect); // ctor - does not load image
609 
610 		const C4FacetSurface &GetFacet() const { return Facet; } // get picture facet
611 		C4FacetSurface &GetMFacet() { return Facet; } // get picture facet
612 		void SetFacet(const C4Facet &fct) { Facet.Clear(); Facet.Set(fct); }
613 		bool EnsureOwnSurface();                // create an own surface, if it's just a link
614 		void SetDrawColor(uint32_t dwToClr) { dwDrawClr = dwToClr; fCustomDrawClr = true; }
615 		void SetAnimated(bool fEnabled, int iDelay); // starts/stops cycling through all phases of the specified facet
616 	};
617 
618 	// picture displaying two facets
619 	class OverlayPicture : public Picture
620 	{
621 	protected:
622 		int iBorderSize; // border of overlay image if not zoomed
623 		C4Facet OverlayImage; // image to be displayed on top of the actual picture
624 
625 		void DrawElement(C4TargetFacet &cgo) override; // draw the image
626 
627 	public:
628 		OverlayPicture(const C4Rect &rcBounds, bool fAspect, const C4Facet &rOverlayImage, int iBorderSize); // ctor - does not load image
629 	};
630 
631 	// icon indices
632 	enum
633 	{
634 		Ico_Extended   = 0x100, // icon index offset for extended icons
635 		Ico_Controller = 0x200,
636 	};
637 	enum Icons
638 	{
639 		Ico_Empty          = -2, // for context menus only
640 		Ico_None           = -1,
641 		Ico_Clonk          = 0,
642 		Ico_Notify         = 1,
643 		Ico_Wait           = 2,
644 		Ico_NetWait        = 3,
645 		Ico_Host           = 4,
646 		Ico_Client         = 5,
647 		Ico_UnknownClient  = 6,
648 		Ico_UnknownPlayer  = 7,
649 		Ico_ObserverClient = 8,
650 		Ico_Player         = 9,
651 		Ico_Resource       = 10,
652 		Ico_Error          = 11,
653 		Ico_SavegamePlayer = 12,
654 		Ico_Save           = 13,
655 		Ico_Active         = 14,
656 		Ico_Options        = 14,
657 		Ico_Editor         = 14,
658 		Ico_Inactive       = 15,
659 		Ico_Kick           = 16,
660 		Ico_Loading        = 17,
661 		Ico_Confirm        = 18,
662 		Ico_Team           = 19,
663 		Ico_AddPlr         = 20,
664 		Ico_Record         = 21,
665 		Ico_Chart          = 21,
666 		Ico_Gfx            = 22,
667 		Ico_Sound          = 23,
668 		Ico_Keyboard       = 24,
669 		Ico_Gamepad        = 25,
670 		Ico_MouseOff       = 26,
671 		Ico_MouseOn        = 27,
672 		Ico_Help           = 28,
673 		Ico_Definition     = 29,
674 		Ico_GameRunning    = 30,
675 		Ico_Lobby          = 31,
676 		Ico_RuntimeJoin    = 32,
677 		Ico_Exit           = 33,
678 		Ico_Close          = 34,
679 		Ico_Rank1          = 35,
680 		Ico_Rank2          = 36,
681 		Ico_Rank3          = 37,
682 		Ico_Rank4          = 38,
683 		Ico_Rank5          = 39,
684 		Ico_Rank6          = 40,
685 		Ico_Rank7          = 41,
686 		Ico_Rank8          = 42,
687 		Ico_Rank9          = 43,
688 		Ico_OfficialServer = 44,
689 		Ico_Surrender      = 45,
690 		Ico_MeleeLeague    = 46,
691 		Ico_Ready          = 47,
692 		Ico_Star           = 48,
693 		Ico_Disconnect     = 49,
694 		Ico_View           = 50,
695 //		Ico_RegJoinOnly    = 51,
696 		Ico_Ignored        = 52,
697 
698 		Ico_Ex_RecordOff     = Ico_Extended + 0,
699 		Ico_Ex_RecordOn      = Ico_Extended + 1,
700 //		Ico_Ex_FairCrew      = Ico_Extended + 2,
701 		Ico_Ex_NormalCrew    = Ico_Extended + 3,
702 		Ico_Ex_LeagueOff     = Ico_Extended + 4,
703 		Ico_Ex_LeagueOn      = Ico_Extended + 5,
704 		Ico_Ex_InternetOff   = Ico_Extended + 6,
705 		Ico_Ex_InternetOn    = Ico_Extended + 7,
706 		Ico_Ex_League        = Ico_Extended + 8,
707 //		Ico_Ex_FairCrewGray  = Ico_Extended + 9,
708 		Ico_Ex_NormalCrewGray= Ico_Extended + 10,
709 		Ico_Ex_Locked        = Ico_Extended + 11,
710 		Ico_Ex_Unlocked      = Ico_Extended + 12,
711 		Ico_Ex_LockedFrontal = Ico_Extended + 13,
712 		Ico_Ex_Update        = Ico_Extended + 14,
713 		Ico_Ex_Chat          = Ico_Extended + 15,
714 		Ico_Ex_GameList      = Ico_Extended + 16,
715 		Ico_Ex_Comment       = Ico_Extended + 17,
716 
717 		Ico_Controller_A             = Ico_Controller + 0,
718 		Ico_Controller_B             = Ico_Controller + 3,
719 		Ico_Controller_X             = Ico_Controller + 17,
720 		Ico_Controller_Y             = Ico_Controller + 18,
721 		Ico_Controller_Back          = Ico_Controller + 1,
722 		Ico_Controller_Start         = Ico_Controller + 16,
723 		Ico_Controller_Dpad          = Ico_Controller + 6,
724 		Ico_Controller_DpadLeft      = Ico_Controller + 5,
725 		Ico_Controller_DpadRight     = Ico_Controller + 7,
726 		Ico_Controller_DpadDown      = Ico_Controller + 4,
727 		Ico_Controller_DpadUp        = Ico_Controller + 8,
728 		Ico_Controller_LeftShoulder  = Ico_Controller + 9,
729 		Ico_Controller_RightShoulder = Ico_Controller + 12,
730 		Ico_Controller_LeftTrigger   = Ico_Controller + 11,
731 		Ico_Controller_RightTrigger  = Ico_Controller + 14,
732 		Ico_Controller_LeftStick     = Ico_Controller + 10,
733 		Ico_Controller_RightStick    = Ico_Controller + 13,
734 	};
735 
736 	// cute, litte, useless thingy
737 	class Icon : public Picture
738 	{
739 	public:
740 		Icon(const C4Rect &rcBounds, Icons icoIconIndex);
741 
742 		void SetIcon(Icons icoNewIconIndex);
743 		static C4Facet GetIconFacet(Icons icoIconIndex);
744 	};
745 
746 	// a collection of gui-elements
747 	class Container : public Element
748 	{
749 	protected:
750 		Element *pFirst, *pLast; // contained elements
751 
752 		void Draw(C4TargetFacet &cgo) override; // draw all elements
753 		virtual void ElementSizeChanged(Element *pOfElement) { } // called when an element size is changed
754 		virtual void ElementPosChanged(Element *pOfElement) { }  // called when an element position is changed
755 
756 		virtual void AfterElementRemoval()
757 		{ if (pParent) pParent->AfterElementRemoval(); } // called by ScrollWindow to parent after an element has been removed
758 
759 		bool OnHotkey(uint32_t cHotkey) override; // check all contained elements for hotkey
760 
761 	public:
762 		Container();  // ctor
763 		~Container() override; // dtor
764 
765 		void Clear();                        // delete all child elements
766 		void ClearChildren();                // delete all child elements
767 		void RemoveElement(Element *pChild) override; // remove child element from container
768 		void MakeLastElement(Element *pChild);       // resort to the end of the list
769 		void AddElement(Element *pChild); // add child element to container
770 		void ReaddElement(Element *pChild); // resort child element to end of list
771 		void InsertElement(Element *pChild, Element *pInsertBefore); // add child element to container, ordered directly before given, other element
772 		Element *GetNextNestedElement(Element *pPrevElement, bool fBackwards); // get next element after given, applying recursion
773 		Element *GetFirstContained() override { return pFirst; }
774 		virtual Element *GetLastContained() { return pLast; }
775 		Element *GetFirstNestedElement(bool fBackwards) override;
776 
777 		class Iterator
778 		{
779 		private:
780 			Element *current;
781 		public:
782 			Iterator(Element *element = nullptr) : current(element) { }
783 
784 			Element * operator*() const { return current; }
785 			Element * operator->() const { return current; }
786 			void operator++() { current = current->GetNext(); };
787 			void operator++(int) { operator++(); }
788 
789 			bool operator==(const Iterator & other) const
790 			{
791 				return (current == other.current);
792 			}
793 
794 			bool operator!=(const Iterator & other) const
795 			{
796 				return !(*this == other);
797 			}
798 		};
799 
800 		class ReverseIterator
801 		{
802 		private:
803 			Element *current;
804 		public:
805 			ReverseIterator(Element *element = nullptr) : current(element) { }
806 
807 			Element * operator*() const { return current; }
808 			Element * operator->() const { return current; }
809 			void operator++() { current = current->GetPrev(); };
810 			void operator++(int) { operator++(); }
811 
812 			bool operator==(const ReverseIterator & other) const
813 			{
814 				return (current == other.current);
815 			}
816 
817 			bool operator!=(const ReverseIterator & other) const
818 			{
819 				return !(*this == other);
820 			}
821 		};
822 
823 		// provide C++-style iterator interface
824 		Iterator begin() { return Iterator(pFirst); }
825 		Iterator end() { return Iterator(nullptr); }
826 		ReverseIterator rbegin() { return ReverseIterator(pLast); }
827 		ReverseIterator rend() { return ReverseIterator(nullptr); }
828 
829 		Element *GetFirst() { return pFirst; }
830 		Element *GetLast() { return pLast; }
831 		Container *GetContainer() override { return this; } // returns parent for elements; this for containers
832 		Element *GetElementByIndex(int32_t i); // get indexed child element
833 		int32_t GetElementCount();
834 
835 		void SetVisibility(bool fToValue) override;
836 		virtual bool IsFocused(Control *pCtrl) { return pParent ? pParent->IsFocused(pCtrl) : false; }
837 		virtual bool IsSelectedChild(Element *pChild) { return pParent ? pParent->IsSelectedChild(pChild) : true; } // whether the child element is selected - only false for list-box-containers which can have unselected children
838 		bool IsParentOf(Element *pEl) override; // whether this is the parent container (directly or recursively) of the passed element
839 
840 		virtual void ApplyElementOffset(int32_t &riX, int32_t &riY) {} // apply child drawing offset
841 		virtual void ApplyInvElementOffset(int32_t &riX, int32_t &riY) {} // subtract child drawing offset
842 
843 
844 		friend class Element; friend class ScrollWindow;
845 	};
846 
847 	// a rectangled control that contains other elements
848 	class Window : public Container
849 	{
850 	protected:
851 		C4Rect rcClientRect; // area for contained elements
852 
853 		void Draw(C4TargetFacet &cgo) override; // draw this window
854 
855 	public:
856 		Window(); // ctor
857 
858 		void MouseInput(CMouse &rMouse, int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyParam) override; // input: mouse movement or buttons
859 
860 		void SetPos(int32_t iXPos, int32_t iYPos)
861 		{ rcBounds.x=iXPos; rcBounds.y=iYPos; UpdatePos(); }
862 
863 		void UpdateOwnPos() override; // update client rect
864 		C4Rect &GetClientRect() override { return rcClientRect; }
865 
866 		void ApplyElementOffset(int32_t &riX, int32_t &riY) override
867 		{ riX -= rcClientRect.x; riY -= rcClientRect.y; }
868 		void ApplyInvElementOffset(int32_t &riX, int32_t &riY) override
869 		{ riX += rcClientRect.x; riY += rcClientRect.y; }
870 		virtual bool IsComponentOutsideClientArea() { return false; } // if set, drawing routine of subcomponents will clip to Bounds rather than to ClientRect
871 
872 		// get margins from bounds to client rect
873 		virtual int32_t GetMarginTop() { return 0; }
874 		virtual int32_t GetMarginLeft() { return 0; }
875 		virtual int32_t GetMarginRight() { return 0; }
876 		virtual int32_t GetMarginBottom() { return 0; }
877 	};
878 
879 	// a scroll bar
880 	class ScrollBar : public Element
881 	{
882 	protected:
883 		bool fScrolling;        // if set, scrolling is currently enabled
884 		bool fAutoHide;         // if set, bar is made invisible if scrolling is not possible anyway
885 		int32_t iScrollThumbSize; // height(/width) of scroll thumb
886 		int32_t iScrollPos;         // y(/x) offset of scroll thumb
887 		bool fTopDown, fBottomDown; // whether scrolling buttons are pressed
888 		bool fHorizontal;           // if set, the scroll bar is horizontal instead of vertical
889 		int32_t iCBMaxRange;        // range for callback class
890 
891 		ScrollWindow *pScrollWindow; // associated scrolled window - may be 0 for callback scrollbars
892 		BaseParCallbackHandler<int32_t> *pScrollCallback; // callback called when scroll pos changes
893 
894 		ScrollBarFacets *pCustomGfx;
895 
896 		void Update();       // update scroll bar according to window
897 		void OnPosChanged(); // update window according to scroll bar, and/or do callbacks
898 
899 		void DrawElement(C4TargetFacet &cgo) override; // draw scroll bar
900 
901 		// suppress scrolling pin for very narrow menus
902 		bool HasPin()
903 		{
904 			if (fHorizontal) return rcBounds.Wdt > (2*C4GUI_ScrollArrowWdt + C4GUI_ScrollThumbWdt);
905 			else             return rcBounds.Hgt > (2*C4GUI_ScrollArrowHgt + C4GUI_ScrollThumbHgt);
906 		}
907 		int32_t GetMaxScroll()
908 		{
909 			if (fHorizontal) return HasPin() ? GetBounds().Wdt - 2*C4GUI_ScrollArrowWdt - iScrollThumbSize : 100;
910 			else             return HasPin() ? GetBounds().Hgt - 2*C4GUI_ScrollArrowHgt - iScrollThumbSize : 100;
911 		}
912 		int32_t GetScrollByPos(int32_t iX, int32_t iY)
913 		{
914 			return Clamp<int32_t>((fHorizontal ? iX-C4GUI_ScrollArrowWdt : iY-C4GUI_ScrollArrowHgt)-iScrollThumbSize/2, 0, GetMaxScroll());
915 		}
916 		bool IsScrolling() { return fScrolling; }
917 
918 	public:
919 		ScrollBar(C4Rect &rcBounds, ScrollWindow *pWin); // ctor for scroll window
920 		ScrollBar(C4Rect &rcBounds, bool fHorizontal, BaseParCallbackHandler<int32_t> *pCB, int32_t iCBMaxRange=256); // ctor for callback
921 		~ScrollBar() override; // dtor
922 
923 		// mouse handling
924 		void MouseInput(CMouse &rMouse, int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyParam) override; // input: mouse movement or buttons
925 		void DoDragging(CMouse &rMouse, int32_t iX, int32_t iY, DWORD dwKeyParam) override;   // dragging: allow dragging of thumb
926 		void MouseLeave(CMouse &rMouse) override;                                     // mouse leaves with button down: reset down state of buttons
927 
928 		// change style
929 		void SetDecoration(ScrollBarFacets *pToGfx, bool fAutoHide)
930 		{ pCustomGfx = pToGfx; this->fAutoHide=fAutoHide; }
931 		// change scroll pos in a [0, iCBMaxRange-1] scale
932 		void SetScrollPos(int32_t iToPos) { iScrollPos = iToPos * GetMaxScroll() / (iCBMaxRange-1); }
933 
934 		friend class ScrollWindow;
935 		friend class ::C4ScriptGuiWindow;
936 	};
937 
938 	// a window that can be scrolled
939 	class ScrollWindow : public Window
940 	{
941 	protected:
942 		ScrollBar *pScrollBar; // vertical scroll bar associated with the window
943 		int32_t iScrollY;          // vertical scroll pos
944 		int32_t iClientHeight;     // client rect height
945 		bool fHasBar;
946 		int32_t iFrozen;           // if >0, no scrolling updates are done (used during window refill)
947 
948 		// pass element updates through to parent window
949 		void ElementSizeChanged(Element *pOfElement) override // called when an element size is changed
950 		{
951 			Window::ElementSizeChanged(pOfElement);
952 			if (pParent) pParent->ElementSizeChanged(pOfElement);
953 		}
954 		void ElementPosChanged(Element *pOfElement) override  // called when an element position is changed
955 		{
956 			Window::ElementPosChanged(pOfElement);
957 			if (pParent) pParent->ElementPosChanged(pOfElement);
958 		}
959 
960 	public:
961 		ScrollWindow(Window *pParentWindow); // create scroll window in client area of window
962 		~ScrollWindow() override { if (pScrollBar) pScrollBar->pScrollWindow = nullptr; }
963 
964 		void MouseInput(CMouse &rMouse, int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyParam) override;
965 
966 		bool IsComponentOutsideClientArea() override { return true; } // always clip drawing routine of subcomponents to Bounds
967 		void Update();               // update client rect and scroll bar according to window
968 		void UpdateOwnPos() override;
969 		void Freeze() { ++iFrozen; }
970 		void UnFreeze() { if (!--iFrozen) Update(); }
971 		bool IsFrozen() const { return !!iFrozen; }
972 
973 		void SetClientHeight(int32_t iToHgt) // set new client height
974 		{ iClientHeight=iToHgt; Update(); }
975 
976 		// change style
977 		void SetDecoration(ScrollBarFacets *pToGfx, bool fAutoScroll)
978 		{ if (pScrollBar) pScrollBar->SetDecoration(pToGfx, fAutoScroll); }
979 
980 		void SetScroll(int32_t iToScroll); // sets new scrolling; does not update scroll bar
981 		void ScrollToBottom();    // set scrolling to bottom range; updates scroll bar
982 		void ScrollPages(int iPageCount);    // scroll down by multiples of visible height; updates scroll bar
983 		void ScrollBy(int iAmount);    // scroll down by vertical pixel amount; updates scroll bar
984 		void ScrollRangeInView(int32_t iY, int32_t iHgt); // sets scrolling so range is in view; updates scroll bar
985 		bool IsRangeInView(int32_t iY, int32_t iHgt); // returns whether scrolling range is in view
986 
987 		int32_t GetScrollY() { return iScrollY; }
988 
989 		void SetScrollBarEnabled(bool fToVal, bool noAutomaticPositioning = false);
990 		bool IsScrollBarEnabled() { return fHasBar; }
991 
992 		bool IsScrollingActive() { return fHasBar && pScrollBar && pScrollBar->IsScrolling(); }
993 		bool IsScrollingNecessary() { return iClientHeight > rcBounds.Hgt; }
994 
995 		friend class ScrollBar;
996 	};
997 
998 	// a collection of components
999 	class GroupBox : public Window
1000 	{
1001 	private:
1002 		StdStrBuf sTitle;
1003 		CStdFont *pFont;
1004 		uint32_t dwFrameClr, dwTitleClr, dwBackClr;
1005 		int32_t iMargin;
1006 
1007 		CStdFont *GetTitleFont() const;
1008 
1009 	public:
1010 		GroupBox(C4Rect &rtBounds) : Window(), pFont(nullptr), dwFrameClr(0u), dwTitleClr(C4GUI_CaptionFontClr), dwBackClr(0xffffffff), iMargin(4)
1011 		{
1012 			// init client rect
1013 			SetBounds(rtBounds);
1014 		} // ctor
1015 
1016 		void SetFont(CStdFont *pToFont) { pFont = pToFont; }
1017 		void SetColors(uint32_t dwFrameClr, uint32_t dwTitleClr, uint32_t dwBackClr=0xffffffff) { this->dwFrameClr = dwFrameClr; this->dwTitleClr = dwTitleClr; this->dwBackClr = dwBackClr; }
1018 		void SetTitle(const char *szToTitle) { if (szToTitle && *szToTitle) sTitle.Copy(szToTitle); else sTitle.Clear(); UpdateOwnPos(); }
1019 		void SetMargin(int32_t iNewMargin) { iMargin = iNewMargin; UpdateOwnPos(); }
1020 
1021 		bool HasTitle() const { return !!sTitle.getLength(); }
1022 
1023 		void DrawElement(C4TargetFacet &cgo) override; // draw frame
1024 
1025 		int32_t GetMarginTop() override { return HasTitle() ? iMargin + GetTitleFont()->GetLineHeight() : iMargin; }
1026 		int32_t GetMarginLeft() override { return iMargin; }
1027 		int32_t GetMarginRight() override { return iMargin; }
1028 		int32_t GetMarginBottom() override { return iMargin; }
1029 	};
1030 
1031 	// a drawing area
1032 	class PaintBox : public Window
1033 	{
1034 	protected:
1035 		C4FacetSurface fctPaint;
1036 
1037 		void DrawElement(C4TargetFacet &cgo) override; // draw what has been painted
1038 	public:
1039 		PaintBox(C4Rect &rtBounds, int32_t iSfcWdt=-1, int32_t iSfcHgt=-1); // ctor
1040 		~PaintBox() override;                // dtor
1041 
1042 		void MouseInput(CMouse &rMouse, int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyParam) override; // input: mouse
1043 	};
1044 
1045 	// a control that may have focus
1046 	class Control : public Window
1047 	{
1048 	private:
1049 		class C4KeyBinding *pKeyContext;
1050 	protected:
1051 		virtual bool CharIn(const char *) { return false; }         // input: character key pressed - should return false for none-character-inputs
1052 
1053 		void DisableFocus(); // called when control gets disabled: Make sure it loses focus
1054 		virtual bool IsFocusOnClick() { return true; } // defaultly, controls get focused on left-down
1055 		Control *IsFocusElement() override { return this; }; // this control can gain focus
1056 		virtual void OnGetFocus(bool fByMouse) {}; // callback when control gains focus
1057 		virtual void OnLooseFocus() {}; // callback when control looses focus
1058 
1059 		bool KeyContext() { return DoContext(); }
1060 
1061 	public:
1062 		Control(const C4Rect &rtBounds);  // ctor
1063 		~Control() override;
1064 
1065 		void MouseInput(CMouse &rMouse, int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyParam) override; // input: mouse. left-click sets focus
1066 
1067 		bool HasFocus() { return pParent && pParent->IsFocused(this); }
1068 		bool HasDrawFocus();
1069 
1070 		friend class Dialog; friend class ListBox;
1071 	};
1072 
1073 	// generic callback-functions to the dialog
1074 	template <class CallbackDlg> class DlgCallback
1075 	{
1076 	public:
1077 		typedef void (CallbackDlg::*Func)(Control *pFromControl);
1078 		typedef bool (CallbackDlg::*BoolFunc)(Control *pFromControl);
1079 		typedef bool (CallbackDlg::*Bool2Func)(Control *pFromControl, bool fBool, bool fBool2);
1080 		typedef ContextMenu *(CallbackDlg::*ContextFunc)(Element *pFromElement, int32_t iX, int32_t iY);
1081 		typedef void (CallbackDlg::*ContextClickFunc)(Element *pTargetElement);
1082 	};
1083 
1084 	// multi-param callback-functions to the dialog
1085 	template <class CallbackDlg, class TEx> class DlgCallbackEx
1086 	{
1087 	public:
1088 		typedef void (CallbackDlg::*ContextClickFunc)(Element *pTargetElement, TEx Extra);
1089 	};
1090 
1091 	// a button. may be pressed.
1092 	class Button : public Control
1093 	{
1094 	private:
1095 		class C4KeyBinding *pKeyButton;
1096 		DynBarFacet *pCustomGfx, *pCustomGfxDown;
1097 
1098 	protected:
1099 		StdStrBuf sText;    // button label
1100 		CStdFont *pCustomFont;    // custom font (if assigned)
1101 		DWORD dwCustomFontClr;    // text font color (valid only if pCustomFont)
1102 		bool fDown;         // if set, button is currently held down
1103 		bool fMouseOver;    // if set, the mouse hovers over the button
1104 		uint32_t cHotkey;   // hotkey for this button
1105 		bool fEnabled;
1106 
1107 		bool IsFocusOnClick() override { return false; } // buttons don't get focus on click (for easier input, e.g. in chatbox)
1108 
1109 		void DrawElement(C4TargetFacet &cgo) override; // draw dlg bg
1110 
1111 		virtual void OnPress(); // called when button is pressed
1112 
1113 		bool KeyButtonDown();
1114 		bool KeyButtonUp();
1115 		void SetDown(); // mark down and play sound
1116 		void SetUp(bool fPress);   // mark up and play sound
1117 
1118 		bool OnHotkey(uint32_t cHotkey) override; // press btn on correct hotkey
1119 
1120 	public:
1121 		Button(const char *szBtnText, const C4Rect &rtBounds); // ctor
1122 		~Button() override; // dtor
1123 
1124 		void MouseInput(CMouse &rMouse, int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyParam) override; // input: mouse movement or buttons
1125 		void MouseEnter(CMouse &rMouse) override; // mouse re-enters with button down: set button down
1126 		void MouseLeave(CMouse &rMouse) override; // mouse leaves with button down: reset down state
1127 
1128 		void SetText(const char *szToText); // update button text (and hotkey)
1129 		void SetCustomGraphics(DynBarFacet *pCustomGfx, DynBarFacet *pCustomGfxDown)
1130 		{ this->pCustomGfx = pCustomGfx; this->pCustomGfxDown = pCustomGfxDown; }
1131 		void SetEnabled(bool fToVal) { fEnabled=fToVal; if (!fEnabled) fDown=false; }
1132 		void SetFont(CStdFont *pFont, DWORD dwCustomFontClr=C4GUI_CaptionFontClr) { this->pCustomFont = pFont; this->dwCustomFontClr=dwCustomFontClr; }
1133 	};
1134 
1135 	// button using icon image
1136 	class IconButton : public Button
1137 	{
1138 	protected:
1139 		C4Facet fctIcon;
1140 		uint32_t dwClr;
1141 		bool fHasClr;
1142 		bool fHighlight; // if true, the button is highlighted permanently
1143 
1144 		void DrawElement(C4TargetFacet &cgo) override; // draw icon and highlight if necessary
1145 
1146 	public:
1147 		IconButton(Icons eUseIcon, const C4Rect &rtBounds, char cHotkey='\0', const char *tooltip_text=nullptr); // ctor
1148 		void SetIcon(Icons eUseIcon);
1149 		void SetFacet(const C4Facet &rCpy, uint32_t dwClr=0u) { fctIcon = rCpy; }
1150 		void SetColor(uint32_t dwClr) { fHasClr=true; this->dwClr=dwClr; }
1151 		void SetHighlight(bool fToVal) { fHighlight=fToVal; }
1152 	};
1153 
1154 	// button using arrow image
1155 	class ArrowButton : public Button
1156 	{
1157 	public:
1158 		enum ArrowFct { Left=0, Right=1, Down=2 };
1159 	protected:
1160 		ArrowFct eDir;
1161 
1162 		void DrawElement(C4TargetFacet &cgo) override; // draw arrow; highlight and down if necessary
1163 
1164 	public:
1165 		ArrowButton(ArrowFct eDir, const C4Rect &rtBounds, char cHotkey=0); // ctor
1166 
1167 		static int32_t GetDefaultWidth();
1168 		static int32_t GetDefaultHeight();
1169 	};
1170 
1171 	// button using facets for highlight
1172 	class FacetButton : public Button
1173 	{
1174 	protected:
1175 		C4Facet fctBase, fctHighlight;
1176 		uint32_t dwTextClrInact, dwTextClrAct; // text colors for inactive/active button
1177 		FLOAT_RECT rcfDrawBounds; // drawing bounds
1178 
1179 		// title drawing parameters
1180 		int32_t iTxtOffX, iTxtOffY;
1181 		uint8_t byTxtAlign;         // ALeft, ACenter or ARight
1182 		CStdFont *pFont; float fFontZoom;
1183 
1184 		void DrawElement(C4TargetFacet &cgo) override; // draw base facet or highlight facet if necessary
1185 
1186 	public:
1187 		FacetButton(const C4Facet &rBaseFct, const C4Facet &rHighlightFct, const FLOAT_RECT &rtfBounds, char cHotkey); // ctor
1188 		void SetTextColors(uint32_t dwClrInact, uint32_t dwClrAct)
1189 		{ dwTextClrInact = dwClrInact; dwTextClrAct = dwClrAct; }
1190 		void SetTextPos(int32_t iOffX, int32_t iOffY, uint8_t byAlign=ACenter)
1191 		{ iTxtOffX=iOffX; iTxtOffY=iOffY; byTxtAlign=byAlign; }
1192 		void SetTextFont(CStdFont *pFont, float fFontZoom=1.0f)
1193 		{ this->pFont=pFont; this->fFontZoom=fFontZoom; }
1194 	};
1195 
1196 	// a button doing some callback...
1197 	template <class CallbackDlg, class Base=Button> class CallbackButton : public Base
1198 	{
1199 	protected:
1200 		CallbackDlg *pCB;
1201 
1202 		typename DlgCallback<CallbackDlg>::Func pCallbackFn; // callback function
1203 		void OnPress() override
1204 		{
1205 			if (pCallbackFn)
1206 			{
1207 				CallbackDlg *pC=pCB;
1208 				if (!pC) if (!(pC=reinterpret_cast<CallbackDlg *>(Base::GetDlg()))) return;
1209 				(pC->*pCallbackFn)(this);
1210 			}
1211 		}
1212 
1213 	public:
1214 		CallbackButton(ArrowButton::ArrowFct eDir, const C4Rect &rtBounds, typename DlgCallback<CallbackDlg>::Func pFn, CallbackDlg *pCB=nullptr) // ctor
1215 				: Base(eDir, rtBounds, 0), pCB(pCB), pCallbackFn(pFn) { }
1216 		CallbackButton(const char *szBtnText, C4Rect &rtBounds, typename DlgCallback<CallbackDlg>::Func pFn, CallbackDlg *pCB=nullptr) // ctor
1217 				: Base(szBtnText, rtBounds), pCB(pCB), pCallbackFn(pFn) { }
1218 		CallbackButton(Icons eUseIcon, const C4Rect &rtBounds, char cHotkey, typename DlgCallback<CallbackDlg>::Func pFn, CallbackDlg *pCB=nullptr) // ctor
1219 				: Base(eUseIcon, rtBounds, cHotkey), pCB(pCB), pCallbackFn(pFn) { }
1220 		CallbackButton(Icons eUseIcon, const C4Rect &rtBounds, const char *tooltip_text, typename DlgCallback<CallbackDlg>::Func pFn, CallbackDlg *pCB = nullptr) // ctor
1221 				: Base(eUseIcon, rtBounds, '\0', tooltip_text), pCB(pCB), pCallbackFn(pFn) { }
1222 		CallbackButton(int32_t iID, const C4Rect &rtBounds, char cHotkey, typename DlgCallback<CallbackDlg>::Func pFn, CallbackDlg *pCB=nullptr) // ctor
1223 				: Base(iID, rtBounds, cHotkey), pCB(pCB), pCallbackFn(pFn) { }
1224 	};
1225 
1226 	// a button doing some callback to any class
1227 	template <class CallbackDlg, class Base=Button> class CallbackButtonEx : public Base
1228 	{
1229 	protected:
1230 		typedef CallbackDlg * CallbackDlgPointer;
1231 		CallbackDlgPointer pCBTarget;                     // callback target
1232 		typename DlgCallback<CallbackDlg>::Func pCallbackFn; // callback function
1233 		void OnPress() override
1234 		{ (pCBTarget->*pCallbackFn)(this); }
1235 
1236 	public:
1237 		CallbackButtonEx(const char *szBtnText, const C4Rect &rtBounds, CallbackDlgPointer pCBTarget, typename DlgCallback<CallbackDlg>::Func pFn) // ctor
1238 				: Base(szBtnText, rtBounds), pCBTarget(pCBTarget), pCallbackFn(pFn) { }
1239 		CallbackButtonEx(Icons eUseIcon, const C4Rect &rtBounds, char cHotkey, CallbackDlgPointer pCBTarget, typename DlgCallback<CallbackDlg>::Func pFn) // ctor
1240 				: Base(eUseIcon, rtBounds, cHotkey), pCBTarget(pCBTarget), pCallbackFn(pFn) { }
1241 		CallbackButtonEx(const C4Facet &fctBase, const C4Facet &fctHighlight, const FLOAT_RECT &rtfBounds, char cHotkey, CallbackDlgPointer pCBTarget, typename DlgCallback<CallbackDlg>::Func pFn) // ctor
1242 				: Base(fctBase, fctHighlight, rtfBounds, cHotkey), pCBTarget(pCBTarget), pCallbackFn(pFn) { }
1243 	};
1244 
1245 	// an edit control to type text in
1246 	class Edit : public Control
1247 	{
1248 	public:
1249 		Edit(const C4Rect &rtBounds, bool fFocusEdit=false); // ctor
1250 		~Edit() override;
1251 
1252 		enum InputResult // action to be taken when text is confirmed with enter
1253 		{
1254 			IR_None=0,    // do nothing and continue pasting
1255 			IR_CloseDlg,  // stop any pastes and close parent dialog successfully
1256 			IR_CloseEdit, // stop any pastes and remove this control
1257 			IR_Abort      // do nothing and stop any pastes
1258 		};
1259 
1260 	private:
1261 		enum CursorOperation { COP_BACK, COP_DELETE, COP_LEFT, COP_RIGHT, COP_HOME, COP_END };
1262 		static const char *CursorRepresentation;
1263 
1264 		bool KeyCursorOp(const C4KeyCodeEx &key, const CursorOperation &op);
1265 		bool KeyEnter();
1266 		bool KeyCopy() { Copy(); return true; }
1267 		bool KeyPaste() { Paste(); return true; }
1268 		bool KeyCut() { Cut(); return true; }
1269 		bool KeySelectAll() { SelectAll(); return true; }
1270 
1271 		class C4KeyBinding *RegisterCursorOp(CursorOperation op, C4KeyCode key, const char *szName, C4CustomKey::Priority eKeyPrio);
1272 
1273 		class C4KeyBinding *pKeyCursorBack, *pKeyCursorDel, *pKeyCursorLeft, *pKeyCursorRight, *pKeyCursorHome, *pKeyCursorEnd,
1274 					*pKeyEnter, *pKeyCopy, *pKeyPaste, *pKeyCut, *pKeySelAll;
1275 
1276 	protected:
1277 		// context callbacks
1278 		ContextMenu *OnContext(C4GUI::Element *pListItem, int32_t iX, int32_t iY);
1279 		void OnCtxCopy(C4GUI::Element *pThis) { Copy(); };
1280 		void OnCtxPaste(C4GUI::Element *pThis) { Paste(); };
1281 		void OnCtxCut(C4GUI::Element *pThis) { Cut(); };
1282 		void OnCtxClear(C4GUI::Element *pThis) { DeleteSelection(); };
1283 		void OnCtxSelAll(C4GUI::Element *pThis) { SelectAll(); };
1284 
1285 	private:
1286 		void Deselect(); // clear selection range
1287 		void ClearText();    // remove all the text
1288 
1289 	public:
1290 		bool InsertText(const char *szText, bool fUser); // insert text at cursor pos (returns whether all text could be inserted)
1291 		void DeleteSelection(); // deletes the selected text. Adjust cursor position if necessary
1292 		bool SetText(const char *szText, bool fUser) { ClearText(); return InsertText(szText, fUser); }
1293 		void SetPasswordMask(char cNewPasswordMask) { cPasswordMask = cNewPasswordMask; } // mask edit box contents using the given character
1294 
1295 	private:
1296 		int32_t GetCharPos(int32_t iControlXPos); // get character index of pixel position; always resides within current text length
1297 		void EnsureBufferSize(int32_t iMinBufferSize); // ensure buffer has desired size
1298 		void ScrollCursorInView();                 // ensure cursor pos is visible in edit control
1299 		bool DoFinishInput(bool fPasting, bool fPastingMore); // do OnFinishInput callback and process result - returns whether pasting operation should be continued
1300 
1301 		bool Copy(); bool Cut(); bool Paste();     // clipboard operations
1302 
1303 	protected:
1304 		CStdFont *pFont;           // font for edit
1305 		char *Text;                // edit text
1306 		uint32_t dwBGClr, dwFontClr, dwBorderColor; // drawing colors for edit box
1307 		int32_t iBufferSize;           // size of current buffer
1308 		int32_t iCursorPos;            // cursor position: char, before which the cursor is located
1309 		int32_t iSelectionStart, iSelectionEnd; // selection range (start may be larger than end)
1310 		int32_t iMaxTextLength;        // maximum number of characters to be input here
1311 		C4TimeMilliseconds tLastInputTime;     // time of last input (for cursor flashing)
1312 		int32_t iXScroll;              // horizontal scrolling
1313 		char cPasswordMask;         // character to be used for masking the contents. 0 for none.
1314 
1315 		bool fLeftBtnDown;         // flag whether left mouse button is down or not
1316 
1317 		bool CharIn(const char * c) override;                                            // input: character key pressed - should return false for none-character-inputs
1318 		void DoDragging(CMouse &rMouse, int32_t iX, int32_t iY, DWORD dwKeyParam) override;   // dragging: allow text selection outside the component
1319 		bool IsFocusOnClick() override { return true; } // edit fields do get focus on click
1320 		void OnGetFocus(bool fByMouse) override;                     // edit control gets focus
1321 		void OnLooseFocus() override;                   // edit control looses focus
1322 
1323 		void DrawElement(C4TargetFacet &cgo) override; // draw edit control
1324 
1325 		// called when user presses enter in single-line edit control - closes the current dialog
1326 		virtual InputResult OnFinishInput(bool fPasting, bool fPastingMore) { return IR_CloseDlg; }
1327 		virtual void OnAbortInput() {}
1328 
1329 		// get margins from bounds to client rect
1330 		int32_t GetMarginTop() override { return 2; }
1331 		int32_t GetMarginLeft() override { return 4; }
1332 		int32_t GetMarginRight() override { return 4; }
1333 		int32_t GetMarginBottom() override { return 2; }
1334 
1335 	public:
1336 		void MouseInput(CMouse &rMouse, int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyParam) override; // input: mouse movement or buttons
1337 
1338 		const char *GetText() { return Text; }
1339 		void SelectAll(); // select all the text
1340 
1341 		static int32_t GetDefaultEditHeight();
1342 		static int32_t GetCustomEditHeight(CStdFont *pUseFont);
1343 
1344 		bool GetCurrentWord(char *szTargetBuf, int32_t iMaxTargetBufLen); // get word before cursor pos (for nick completion)
1345 
1346 		// layout
1347 		void SetFont(CStdFont *pToFont) { pFont=pToFont; ScrollCursorInView(); }
1348 		void SetColors(uint32_t dwNewBGClr, uint32_t dwNewFontClr, uint32_t dwNewBorderColor)
1349 		{ dwBGClr = dwNewBGClr; dwFontClr = dwNewFontClr; dwBorderColor = dwNewBorderColor; }
1350 
1351 		void SetMaxText(int32_t iTo) { iMaxTextLength = iTo; }
1352 	};
1353 
1354 	// an edit doing some callback
1355 	template <class CallbackCtrl> class CallbackEdit : public Edit
1356 	{
1357 	private:
1358 		CallbackCtrl *pCBCtrl;
1359 
1360 	protected:
1361 		typedef InputResult (CallbackCtrl::*CBFunc)(Edit *, bool, bool);
1362 		typedef void (CallbackCtrl::*CBAbortFunc)();
1363 		CBFunc pCBFunc; CBAbortFunc pCBAbortFunc;
1364 		InputResult OnFinishInput(bool fPasting, bool fPastingMore) override
1365 		{ if (pCBFunc && pCBCtrl) return (pCBCtrl->*pCBFunc)(this, fPasting, fPastingMore); else return IR_CloseDlg; }
1366 		void OnAbortInput() override
1367 		{ if (pCBAbortFunc && pCBCtrl) (pCBCtrl->*pCBAbortFunc)(); }
1368 
1369 	public:
1370 		CallbackEdit(const C4Rect &rtBounds, CallbackCtrl * pCBCtrl, CBFunc pCBFunc, CBAbortFunc pCBAbortFunc=nullptr) // ctor
1371 				: Edit(rtBounds), pCBCtrl(pCBCtrl), pCBFunc(pCBFunc), pCBAbortFunc(pCBAbortFunc) { }
1372 	};
1373 
1374 	// an edit control that renames a label - some less decoration; abort on Escape and focus loss
1375 	class RenameEdit : public Edit
1376 	{
1377 	private:
1378 		C4KeyBinding *pKeyAbort; // key bindings
1379 		bool fFinishing;  // set during deletion process
1380 		Label *pForLabel; // label that is being renamed
1381 		Control *pPrevFocusCtrl; // previous focus element to be restored after rename
1382 
1383 	public:
1384 		enum RenameResult
1385 		{
1386 			RR_Invalid=0, // rename not accepted; continue editing
1387 			RR_Accepted,  // rename accepted; delete control
1388 			RR_Deleted    // control deleted - leave everything
1389 		};
1390 
1391 	public:
1392 		RenameEdit(Label *pLabel); // ctor - construct for label; add element; set focus
1393 		~RenameEdit() override;
1394 
1395 		void Abort();
1396 
1397 	private:
1398 		void FinishRename(); // renaming aborted or finished - remove this element and restore label
1399 
1400 	protected:
1401 		bool KeyAbort() { Abort(); return true; }
1402 		InputResult OnFinishInput(bool fPasting, bool fPastingMore) override; // forward last input to OnOKRename
1403 		void OnLooseFocus() override; // callback when control looses focus: OK input
1404 
1405 		virtual void OnCancelRename() {} // renaming was aborted
1406 		virtual RenameResult OnOKRename(const char *szNewName) = 0; // rename performed - return whether name was accepted
1407 	};
1408 
1409 	template <class CallbackDlg, class ParType> class CallbackRenameEdit : public RenameEdit
1410 	{
1411 	public:
1412 	protected:
1413 		typedef void (CallbackDlg::*CBCancelFunc)(ParType);
1414 		typedef RenameResult (CallbackDlg::*CBOKFunc)(ParType, const char *);
1415 
1416 		CBCancelFunc pCBCancelFunc; CBOKFunc pCBOKFunc;
1417 		CallbackDlg *pDlg; ParType par;
1418 
1419 		void OnCancelRename() override { if (pDlg && pCBCancelFunc) (pDlg->*pCBCancelFunc)(par); }
1420 		RenameResult OnOKRename(const char *szNewName) override { return (pDlg && pCBOKFunc) ? (pDlg->*pCBOKFunc)(par, szNewName) : RR_Accepted; }
1421 
1422 	public:
1423 		CallbackRenameEdit(Label *pForLabel, CallbackDlg *pDlg, const ParType &par, CBOKFunc pCBOKFunc, CBCancelFunc pCBCancelFunc) // ctor
1424 				: RenameEdit(pForLabel), pCBCancelFunc(pCBCancelFunc), pCBOKFunc(pCBOKFunc), pDlg(pDlg), par(par) { }
1425 	};
1426 
1427 	// editbox below descriptive label sharing one window for common tooltip
1428 	class LabeledEdit : public C4GUI::Window
1429 	{
1430 	public:
1431 		LabeledEdit(const C4Rect &rcBounds, const char *szName, bool fMultiline, const char *szPrefText=nullptr, CStdFont *pUseFont=nullptr, uint32_t dwTextClr = C4GUI_CaptionFontClr);
1432 	private:
1433 		C4GUI::Edit *pEdit;
1434 	public:
1435 		const char *GetText() const { return pEdit->GetText(); }
1436 		C4GUI::Edit *GetEdit() const { return pEdit; }
1437 		static bool GetControlSize(int *piWdt, int *piHgt, const char *szForText, CStdFont *pForFont, bool fMultiline);
1438 	};
1439 
1440 	// checkbox with a text label right of it
1441 	class CheckBox : public Control
1442 	{
1443 	private:
1444 		bool fChecked;
1445 		class C4KeyBinding *pKeyCheck;
1446 		StdStrBuf sCaption;
1447 		bool fMouseOn;
1448 		BaseCallbackHandler *pCBHandler; // callback handler called if check state changes
1449 		bool fEnabled;
1450 		CStdFont *pFont;
1451 		uint32_t dwEnabledClr, dwDisabledClr;
1452 		uint32_t cHotkey;
1453 
1454 	public:
1455 		CheckBox(const C4Rect &rtBounds, const char *szCaption, bool fChecked); // ctor
1456 		~CheckBox() override;
1457 
1458 	private:
1459 		bool KeyCheck() { ToggleCheck(true); return true; }
1460 
1461 	public:
1462 		void ToggleCheck(bool fByUser); // check on/off; do callback
1463 
1464 	protected:
1465 		void UpdateOwnPos() override;
1466 		bool IsFocusOnClick() override { return false; } // just check/uncheck on click; do not gain keyboard focus as well
1467 		Control *IsFocusElement() override { return fEnabled ? Control::IsFocusElement() : nullptr; }; // this control can gain focus if enabled
1468 		void DrawElement(C4TargetFacet &cgo) override; // draw checkbox
1469 		bool OnHotkey(uint32_t cHotkey) override; // return true when hotkey has been processed
1470 
1471 	public:
1472 		void MouseInput(CMouse &rMouse, int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyParam) override; // input: mouse movement or buttons
1473 		void MouseEnter(CMouse &rMouse) override;
1474 		void MouseLeave(CMouse &rMouse) override;
1475 
1476 		void SetChecked(bool fToVal) { fChecked = fToVal; } // set w/o callback
1477 		bool GetChecked() const { return fChecked; }
1478 		void SetOnChecked(BaseCallbackHandler *pCB);
1479 		void SetEnabled(bool fToVal) { if (!(fEnabled=fToVal)) DisableFocus(); }
1480 
1481 		const char *GetText() { return sCaption.getData(); }
1482 
1483 		void SetFont(CStdFont *pFont, uint32_t dwEnabledClr, uint32_t dwDisabledClr)
1484 		{ this->pFont=pFont; this->dwEnabledClr=dwEnabledClr; this->dwDisabledClr=dwDisabledClr; }
1485 
1486 		static bool GetStandardCheckBoxSize(int *piWdt, int *piHgt, const char *szForCaptionText, CStdFont *pUseFont); // get needed size to construct a checkbox
1487 	};
1488 
1489 	// a vertical list of elements
1490 	class ListBox : public Control
1491 	{
1492 	private:
1493 		class C4KeyBinding *pKeyContext, *pKeyUp, *pKeyDown, *pKeyPageUp, *pKeyPageDown, *pKeyHome, *pKeyEnd, *pKeyActivate, *pKeyLeft, *pKeyRight;
1494 
1495 		bool KeyContext();
1496 		bool KeyUp();
1497 		bool KeyDown();
1498 		bool KeyLeft();
1499 		bool KeyRight();
1500 		bool KeyPageUp();
1501 		bool KeyPageDown();
1502 		bool KeyHome();
1503 		bool KeyEnd();
1504 		bool KeyActivate();
1505 
1506 	protected:
1507 		int32_t iMultiColItemWidth; // if nonzero, the listbox is multicolumn and the column count depends on how many items fit in
1508 		int32_t iColCount; // number of columns (usually 1)
1509 		ScrollWindow *pClientWindow; // client scrolling window
1510 		Element *pSelectedItem;      // selected list item
1511 		BaseCallbackHandler *pSelectionChangeHandler, *pSelectionDblClickHandler;
1512 		bool fDrawBackground; // whether darker background is to be drawn
1513 		bool fDrawBorder;     // whether 3D frame around box shall be drawn or nay
1514 		bool fSelectionDisabled; // if set, no entries can be selected
1515 
1516 		void DrawElement(C4TargetFacet &cgo) override; // draw listbox
1517 
1518 		bool IsFocused(Control *pCtrl) override
1519 		{
1520 			// subcontrol also counts as focused if the list has focus and the subcontrol is selected
1521 			return Control::IsFocused(pCtrl) || (HasFocus() && pSelectedItem == pCtrl);
1522 		}
1523 		bool IsFocusOnClick() override { return true; } // list boxes do get focus on click
1524 		Control *IsFocusElement() override { return this; }; // this control can gain focus
1525 		void OnGetFocus(bool fByMouse) override; // callback when control gains focus - select a list item if none are selected
1526 		bool CharIn(const char * c) override; // character input for direct list element selection
1527 
1528 		void AfterElementRemoval() override
1529 		{ Container::AfterElementRemoval(); UpdateElementPositions(); } // called by ScrollWindow to parent after an element has been removed
1530 
1531 		void UpdateColumnCount();
1532 
1533 	public:
1534 		ListBox(const C4Rect &rtBounds, int32_t iMultiColItemWidth=0); // ctor
1535 		~ListBox() override; // dtor
1536 
1537 		void MouseInput(CMouse &rMouse, int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyParam) override; // input: mouse movement or buttons
1538 
1539 		void RemoveElement(Element *pChild) override; // remove child component
1540 		bool AddElement(Element *pChild, int32_t iIndent=0); // add element and adjust its pos
1541 		bool InsertElement(Element *pChild, Element *pInsertBefore, int32_t iIndent=0); // insert element and adjust its pos
1542 		void ElementSizeChanged(Element *pOfElement) override; // called when an element size is changed
1543 		void ElementPosChanged(Element *pOfElement) override;  // called when an element position is changed
1544 
1545 		int32_t GetItemWidth() { return iMultiColItemWidth ? iMultiColItemWidth : pClientWindow->GetClientRect().Wdt; }
1546 
1547 		void SelectionChanged(bool fByUser); // pSelectedItem changed: sound, tooltip, etc.
1548 		void SetSelectionChangeCallbackFn(BaseCallbackHandler *pToHandler) // update selection change handler
1549 		{
1550 			if (pSelectionChangeHandler) pSelectionChangeHandler->DeRef();
1551 			if ((pSelectionChangeHandler = pToHandler)) pToHandler->Ref();
1552 		}
1553 		void SetSelectionDblClickFn(BaseCallbackHandler *pToHandler) // update selection doubleclick handler
1554 		{
1555 			if (pSelectionDblClickHandler) pSelectionDblClickHandler->DeRef();
1556 			if ((pSelectionDblClickHandler = pToHandler)) pSelectionDblClickHandler->Ref();
1557 		}
1558 
1559 		void ScrollToBottom() // set scrolling to bottom range
1560 		{ if (pClientWindow) pClientWindow->ScrollToBottom(); }
1561 		void ScrollItemInView(Element *pItem); // set scrolling so a specific item is visible
1562 		void FreezeScrolling() { pClientWindow->Freeze(); }
1563 		void UnFreezeScrolling() { pClientWindow->UnFreeze(); }
1564 
1565 		// change style
1566 		void SetDecoration(bool fDrawBG, ScrollBarFacets *pToGfx, bool fAutoScroll, bool fDrawBorder=false)
1567 		{ fDrawBackground=fDrawBG; this->fDrawBorder=fDrawBorder; if (pClientWindow) pClientWindow->SetDecoration(pToGfx, fAutoScroll); }
1568 		void SetSelectionDiabled(bool fToVal=true) { fSelectionDisabled = fToVal; }
1569 
1570 		// get head and tail list items
1571 		Element *GetFirst() { return pClientWindow ? pClientWindow->GetFirst() : nullptr; }
1572 		Element *GetLast() { return pClientWindow ? pClientWindow->GetLast() : nullptr; }
1573 
1574 		// get margins from bounds to client rect
1575 		int32_t GetMarginTop() override { return 3; }
1576 		int32_t GetMarginLeft() override { return 3; }
1577 		int32_t GetMarginRight() override { return 3; }
1578 		int32_t GetMarginBottom() override { return 3; }
1579 
1580 		Element *GetSelectedItem() { return pSelectedItem; } // get focused listbox item
1581 		bool IsScrollingActive() { return pClientWindow && pClientWindow->IsScrollingActive(); }
1582 		bool IsScrollingNecessary() { return pClientWindow && pClientWindow->IsScrollingNecessary(); }
1583 		void SelectEntry(Element *pNewSel, bool fByUser);
1584 		void SelectFirstEntry(bool fByUser) { SelectEntry(GetFirst(), fByUser); }
1585 		void SelectNone(bool fByUser) { SelectEntry(nullptr, fByUser); }
1586 		bool IsMultiColumn() const { return iColCount > 1; }
1587 		int32_t ContractToElementHeight(); // make smaller if elements don't use up all of the available height. Return amount by which list box got contracted
1588 
1589 		void UpdateElementPositions();            // reposition list items so they are stacked vertically
1590 		void UpdateElementPosition(Element *pOfElement, int32_t iIndent); // update pos for one specific element
1591 		void UpdateSize() override { Control::UpdateSize(); if (pClientWindow) { pClientWindow->UpdateSize(); UpdateElementPositions(); } }
1592 
1593 		bool IsSelectedChild(Element *pChild) override { return pChild == pSelectedItem || (pSelectedItem && pSelectedItem->IsParentOf(pChild)); }
1594 
1595 		typedef int32_t (*SortFunction)(const Element *pEl1, const Element *pEl2, void *par);
1596 		void SortElements(SortFunction SortFunc, void *par); // sort list items
1597 	};
1598 
1599 	// tabbing panel
1600 	class Tabular : public Control
1601 	{
1602 	public:
1603 		// sheet covering the client area of a tabular
1604 		class Sheet : public Window
1605 		{
1606 		protected:
1607 			StdStrBuf sTitle; // sheet label
1608 			int32_t icoTitle; // sheet label icon
1609 			uint32_t cHotkey;
1610 			uint32_t dwCaptionClr; // caption color - default if 0
1611 			bool fHasCloseButton, fCloseButtonHighlighted;
1612 			bool fTitleMarkup;
1613 
1614 			Sheet(const char *szTitle, const C4Rect &rcBounds, int32_t icoTitle = Ico_None, bool fHasCloseButton=false, bool fTitleMarkup=true); // ctor; expands hotkey markup in title
1615 
1616 			void DrawCaption(C4TargetFacet &cgo, int32_t x, int32_t y, int32_t iMaxWdt, bool fLarge, bool fActive, bool fFocus, C4Facet *pfctClip, C4Facet *pfctIcon, CStdFont *pUseFont);
1617 			void GetCaptionSize(int32_t *piWdt, int32_t *piHgt, bool fLarge, bool fActive, C4Facet *pfctClip, C4Facet *pfctIcon, CStdFont *pUseFont);
1618 			virtual void OnShown(bool fByUser) { } // calklback from tabular after sheet has been made visible
1619 			void SetCloseButtonHighlight(bool fToVal) { fCloseButtonHighlighted = fToVal; }
1620 			bool IsPosOnCloseButton(int32_t x, int32_t y, int32_t iCaptWdt, int32_t iCaptHgt, bool fLarge);
1621 			bool IsActiveSheet();
1622 
1623 		public:
1624 			const char *GetTitle() { return sTitle.getData(); }
1625 			char GetHotkey() { return cHotkey; }
1626 			void SetTitle(const char *szNewTitle);
1627 			void SetCaptionColor(uint32_t dwNewClr=0) { dwCaptionClr=dwNewClr; }
1628 			virtual void UserClose() { delete this; } // user pressed close button
1629 			bool HasCloseButton() const { return fHasCloseButton; }
1630 
1631 			friend class Tabular;
1632 		};
1633 
1634 		enum TabPosition
1635 		{
1636 			tbNone=0, // no tabs
1637 			tbTop,    // tabs on top
1638 			tbLeft  // tabs to the left
1639 		};
1640 
1641 	private:
1642 		Sheet *pActiveSheet; // currently selected sheet
1643 		TabPosition eTabPos; // whither tabs shalt be shown or nay, en where art thy shown?
1644 		int32_t iMaxTabWidth; // maximum tab length; used when tabs are positioned left and do not have gfx
1645 		int32_t iSheetSpacing, iSheetOff; // distances of sheet captions
1646 		int32_t iCaptionLengthTotal, iCaptionScrollPos; // scrolling in captions (top only)
1647 		bool fScrollingLeft, fScrollingRight, fScrollingLeftDown, fScrollingRightDown; // scrolling in captions (top only)
1648 		C4TimeMilliseconds tLastScrollTime; // set when fScrollingLeftDown or fScrollingRightDown are true: Time for next scrolling if mouse is held down
1649 		int iSheetMargin;
1650 		bool fDrawSelf; // if border and bg shall be drawn
1651 
1652 		C4Facet *pfctBack, *pfctClip, *pfctIcons; // set for tabulars that have custom gfx
1653 		CStdFont *pSheetCaptionFont;                // font to be used for caption drawing; nullptr if default GUI font is to be used
1654 
1655 		C4KeyBinding *pKeySelUp, *pKeySelDown, *pKeySelUp2, *pKeySelDown2, *pKeyCloseTab; // key bindings
1656 
1657 		void SelectionChanged(bool fByUser); // pActiveSheet changed: sound, tooltip, etc.
1658 		void SheetsChanged(); // update iMaxTabWidth by new set of sheet labels
1659 		void UpdateScrolling();
1660 		void DoCaptionScroll(int32_t iDir);
1661 
1662 
1663 	private:
1664 		bool HasGfx() { return pfctBack && pfctClip && pfctIcons; } // whether the control uses custom graphics
1665 
1666 	protected:
1667 		bool KeySelUp(); // keyboard callback: Select previous sheet
1668 		bool KeySelDown(); // keyboard callback: Select next sheet
1669 		bool KeyCloseTab(); // keyboard callback: Close current sheet if possible
1670 
1671 		void DrawElement(C4TargetFacet &cgo) override;
1672 		void MouseLeaveCaptionArea();
1673 		void MouseLeave(CMouse &rMouse) override;
1674 		void OnGetFocus(bool fByMouse) override;
1675 
1676 		Control *IsFocusElement() override { return eTabPos ? this : nullptr; }; // this control can gain focus only if tabs are enabled only
1677 		bool IsFocusOnClick() override { return false; } // but never get focus on single mouse click, because this would de-focus any contained controls!
1678 
1679 		int32_t GetTopSize() { return (eTabPos == tbTop) ? 20 : 0; } // vertical size of tab selection bar
1680 		int32_t GetLeftSize() { return (eTabPos == tbLeft) ? (HasGfx() ? GetLeftClipSize(pfctClip) : 20+iMaxTabWidth) : 0; } // horizontal size of tab selection bar
1681 		bool HasLargeCaptions() { return eTabPos == tbLeft; }
1682 
1683 		int32_t GetMarginTop() override { return iSheetMargin+GetTopSize() + (HasGfx() ? (rcBounds.Hgt-GetTopSize())*30/483 : 0); }
1684 		int32_t GetMarginLeft() override { return iSheetMargin+GetLeftSize() + (HasGfx() ? (rcBounds.Wdt-GetLeftSize())*13/628 : 0); }
1685 		int32_t GetMarginRight() override { return iSheetMargin + (HasGfx() ? (rcBounds.Wdt-GetLeftSize())*30/628 : 0); }
1686 		int32_t GetMarginBottom() override { return iSheetMargin + (HasGfx() ? (rcBounds.Hgt-GetTopSize())*32/483 : 0); }
1687 
1688 		void UpdateSize() override;
1689 
1690 		bool IsSelectedChild(Element *pChild) override { return pChild == pActiveSheet || (pActiveSheet && pActiveSheet->IsParentOf(pChild)); }
1691 
1692 	public:
1693 		Tabular(C4Rect &rtBounds, TabPosition eTabPos); // ctor
1694 		~Tabular() override; // dtor
1695 
1696 		void MouseInput(CMouse &rMouse, int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyParam) override;
1697 
1698 		void RemoveElement(Element *pChild) override; // clear ptr
1699 		Sheet *AddSheet(const char *szTitle, int32_t icoTitle = Ico_None);
1700 		void AddCustomSheet(Sheet *pAddSheet);
1701 		void ClearSheets(); // del all sheets
1702 		void SelectSheet(int32_t iIndex, bool fByUser);
1703 		void SelectSheet(Sheet *pSelSheet, bool fByUser);
1704 
1705 
1706 		Sheet *GetSheet(int32_t iIndex) { return (Sheet *) GetElementByIndex(iIndex); }
1707 		Sheet *GetActiveSheet() { return pActiveSheet; }
1708 		int32_t GetActiveSheetIndex();
1709 		int32_t GetSheetCount() { return GetElementCount(); }
1710 
1711 		void SetGfx(C4Facet *pafctBack, C4Facet *pafctClip, C4Facet *pafctIcons, CStdFont *paSheetCaptionFont, bool fResizeByAspect);
1712 		static int32_t GetLeftClipSize(C4Facet *pfctForClip) { return pfctForClip->Wdt*95/120; } // left clip area size by gfx
1713 		void SetSheetMargin(int32_t iMargin) { iSheetMargin = iMargin; UpdateOwnPos(); }
1714 		void SetDrawDecoration(bool fToVal) { fDrawSelf = fToVal; }
1715 
1716 		friend class Sheet;
1717 	};
1718 
1719 	// scrollable text box
1720 	class TextWindow : public Control
1721 	{
1722 	protected:
1723 		ScrollWindow *pClientWindow; // client scrolling window
1724 		Picture *pTitlePicture;      // [optional]: Picture shown atop the text
1725 		MultilineLabel *pLogBuffer;  // buffer holding text data
1726 		bool fDrawBackground, fDrawFrame;        // whether dark background should be drawn (default true)
1727 		size_t iPicPadding;
1728 
1729 		void DrawElement(C4TargetFacet &cgo) override; // draw text window
1730 
1731 		void ElementSizeChanged(Element *pOfElement) override; // called when an element size is changed
1732 		void ElementPosChanged(Element *pOfElement) override;  // called when an element position is changed
1733 		void UpdateSize() override;
1734 
1735 		Control *IsFocusElement() override { return nullptr; }; // no focus element for now, because there's nothing to do (2do: scroll?)
1736 
1737 	public:
1738 		TextWindow(C4Rect &rtBounds, size_t iPicWdt=0, size_t iPicHgt=0, size_t iPicPadding=0, size_t iMaxLines=100, size_t iMaxTextLen=4096, const char *szIndentChars="    ", bool fAutoGrow=false, const C4Facet *pOverlayPic=nullptr, int iOverlayBorder=0, bool fMarkup=false); // ctor
1739 
1740 		void AddTextLine(const char *szText, CStdFont *pFont, DWORD dwClr, bool fDoUpdate, bool fMakeReadableOnBlack, CStdFont *pCaptionFont=nullptr) // add text in a new line
1741 		{ if (pLogBuffer) pLogBuffer->AddLine(szText, pFont, dwClr, fDoUpdate, fMakeReadableOnBlack, pCaptionFont); }
1742 		void ScrollToBottom() // set scrolling to bottom range
1743 		{ if (pClientWindow) pClientWindow->ScrollToBottom(); }
1744 		void ClearText(bool fDoUpdate)
1745 		{ if (pLogBuffer) pLogBuffer->Clear(fDoUpdate); }
1746 		int32_t GetScrollPos()
1747 		{ return pClientWindow ? pClientWindow->GetScrollY() : 0; }
1748 		void SetScrollPos(int32_t iPos)
1749 		{ if (pClientWindow) pClientWindow->ScrollRangeInView(iPos, 0); }
1750 		void UpdateHeight()
1751 		{ if (pLogBuffer) pLogBuffer->UpdateHeight(); }
1752 		void SetDecoration(bool fDrawBG, bool fDrawFrame, ScrollBarFacets *pToGfx, bool fAutoScroll)
1753 		{ fDrawBackground=fDrawBG; this->fDrawFrame=fDrawFrame; if (pClientWindow) pClientWindow->SetDecoration(pToGfx, fAutoScroll); }
1754 		void SetPicture(const C4Facet &rNewPic);
1755 
1756 		// get margins from bounds to client rect
1757 		int32_t GetMarginTop() override { return 8; }
1758 		int32_t GetMarginLeft() override { return 10; }
1759 		int32_t GetMarginRight() override { return 5; }
1760 		int32_t GetMarginBottom() override { return 8; }
1761 	};
1762 
1763 	// context menu opened on right-click
1764 	class ContextMenu : public Window
1765 	{
1766 	private:
1767 		// key bindings
1768 		class C4KeyBinding *pKeySelUp, *pKeySelDown, *pKeySubmenu, *pKeyBack, *pKeyAbort, *pKeyConfirm, *pKeyHotkey;
1769 
1770 		bool KeySelUp();
1771 		bool KeySelDown();
1772 		bool KeySubmenu();
1773 		bool KeyBack();
1774 		bool KeyAbort();
1775 		bool KeyConfirm();
1776 		bool KeyHotkey(const C4KeyCodeEx &key);
1777 
1778 	private:
1779 		static int32_t iGlobalMenuIndex;
1780 		int32_t iMenuIndex;
1781 
1782 		void UpdateElementPositions(); // stack all menu elements
1783 
1784 		// element adding made private: May only add entries
1785 		bool AddElement(Element *pChild);
1786 		bool InsertElement(Element *pChild, Element *pInsertBefore);
1787 
1788 	public:
1789 		// one text entry (icon+text+eventually right-arrow)
1790 		class Entry : public Element
1791 		{
1792 		private:
1793 			int32_t GetIconIndent() { return (icoIcon==-1) ? 0 : rcBounds.Hgt+2; }
1794 
1795 		protected:
1796 			StdStrBuf sText; // entry text
1797 			uint32_t cHotkey;       // entry hotkey
1798 			Icons icoIcon;      // icon to be drawn left of text
1799 			MenuHandler *pMenuHandler; // callback when item is selected
1800 			ContextHandler *pSubmenuHandler; // callback when submenu is opened
1801 
1802 		protected:
1803 			void DrawElement(C4TargetFacet &cgo) override; // draw element
1804 
1805 			MenuHandler *GetAndZeroCallback()
1806 			{ MenuHandler *pMH = pMenuHandler; pMenuHandler=nullptr; return pMH; }
1807 
1808 			void MouseLeave(CMouse &rMouse) override
1809 			{ if (GetParent()) ((ContextMenu *) GetParent())->MouseLeaveEntry(rMouse, this); }
1810 
1811 			bool OnHotkey(uint32_t cKey) override { return cKey==cHotkey; }
1812 
1813 			bool IsMenu() override { return true; }
1814 
1815 		public:
1816 			Entry(const char *szText, Icons icoIcon=Ico_None, MenuHandler *pMenuHandler=nullptr, ContextHandler *pSubmenuHandler=nullptr); // ctor
1817 			~Entry() override
1818 			{
1819 				if (pMenuHandler) delete pMenuHandler;
1820 				if (pSubmenuHandler) delete pSubmenuHandler;
1821 			}
1822 
1823 			const char *GetText() { return sText.getData(); }
1824 
1825 			friend class ContextMenu;
1826 		};
1827 
1828 	protected:
1829 		Element *pTarget{nullptr}; // target element; close menu if this is lost
1830 		Element *pSelectedItem{nullptr}; // currently highlighted menu item
1831 
1832 		ContextMenu *pSubmenu{nullptr}; // currently open submenu
1833 
1834 		// mouse movement or buttons forwarded from screen:
1835 		// Check bounds and forward as MouseInput to context menu or submenus
1836 		// return whether inside context menu bounds
1837 		bool CtxMouseInput(CMouse &rMouse, int32_t iButton, int32_t iScreenX, int32_t iScreenY, DWORD dwKeyParam);
1838 		void RemoveElement(Element *pChild) override; // clear ptr - abort menu if target is destroyed
1839 
1840 		virtual bool CharIn(const char * c);                                            // input: character key pressed - should return false for none-character-inputs
1841 		void MouseLeaveEntry(CMouse &rMouse, Entry *pOldEntry); // callback: mouse leaves - deselect menu item if no submenu is open (callback done by menu item)
1842 
1843 		void DrawElement(C4TargetFacet &cgo) override; // draw BG
1844 		void Draw(C4TargetFacet &cgo) override;        // draw inherited (element+contents) plus submenu
1845 
1846 		bool IsMenu() override { return true; }
1847 
1848 		Screen *GetScreen() override; // return screen by static var
1849 
1850 		int32_t GetMarginTop() override { return 5; }
1851 		int32_t GetMarginLeft() override { return 5; }
1852 		int32_t GetMarginRight() override { return 5; }
1853 		int32_t GetMarginBottom() override { return 5; }
1854 
1855 		void SelectionChanged(bool fByUser); // other item selected: Close any submenu; do callbacks
1856 
1857 		void ElementSizeChanged(Element *pOfElement) override; // called when an element size is changed
1858 		void ElementPosChanged(Element *pOfElement) override;  // called when an element position is changed
1859 
1860 		void CheckOpenSubmenu(); // open submenu if present for selected item
1861 		bool IsSubmenu(); // return whether it's a submenu
1862 		void DoOK();      // do OK for selected item
1863 
1864 	public:
1865 		ContextMenu();  // ctor
1866 		~ContextMenu() override; // dtor
1867 
1868 		void MouseInput(CMouse &rMouse, int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyParam) override; // input: mouse movement or buttons
1869 
1870 		void Open(Element *pTarget, int32_t iScreenX, int32_t iScreenY);
1871 		void Abort(bool fByUser);
1872 
1873 		void AddItem(const char *szText, const char *szToolTip=nullptr, Icons icoIcon=Ico_None, MenuHandler *pMenuHandler=nullptr, ContextHandler *pSubmenuHandler=nullptr)
1874 		{
1875 			Element *pNew = new ContextMenu::Entry(szText, icoIcon, pMenuHandler, pSubmenuHandler);
1876 			AddElement(pNew); pNew->SetToolTip(szToolTip);
1877 		}
1878 
1879 		Entry *GetIndexedEntry(int32_t iIndex) { return static_cast<Entry *>(GetElementByIndex(iIndex)); }
1880 
1881 		void SelectItem(int32_t iIndex);
1882 
1883 		int32_t GetMenuIndex() { return iMenuIndex; }
1884 		static int32_t GetLastMenuIndex() { return iGlobalMenuIndex; }
1885 
1886 		Dialog *GetTargetDialog() const { return pTarget ? pTarget->GetDlg() : nullptr; }
1887 
1888 		friend class Screen; friend class Entry; friend class Dialog;
1889 	};
1890 
1891 	// a button to open a context menu
1892 	class ContextButton : public Control
1893 	{
1894 	private:
1895 		C4KeyBinding *pKeyContext;
1896 		int32_t iOpenMenu; // associated menu (used to flag button down)
1897 		bool fMouseOver;
1898 
1899 	public:
1900 		ContextButton(C4Rect &rtBounds); // ctor
1901 		ContextButton(Element *pForEl, bool fAdd, int32_t iHIndent=4, int32_t iVIndent=4);  // ctor creating at topright pos of element
1902 		~ContextButton() override;
1903 
1904 	private:
1905 		bool DoContext(int32_t iX=-1, int32_t iY=-1); // open context menu
1906 		bool KeyContext() { return DoContext(); }
1907 		void RegisterContextKey();
1908 
1909 	protected:
1910 		void DrawElement(C4TargetFacet &cgo) override;    // draw btn
1911 
1912 		bool IsFocusOnClick() override { return false; } // don't select control on click
1913 
1914 	public:
1915 		void MouseInput(CMouse &rMouse, int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyParam) override; // input: mouse. left-click opens menu
1916 		void MouseEnter(CMouse &rMouse) override;
1917 		void MouseLeave(CMouse &rMouse) override;
1918 	};
1919 
1920 
1921 	// combo box filler
1922 	// should be ComboBox::FillCB; but nested class will cause internal compiler faults
1923 	class ComboBox_FillCB
1924 	{
1925 	private:
1926 		ComboBox *pCombo;
1927 		ContextMenu *pDrop;
1928 	public:
1929 		virtual ~ComboBox_FillCB() = default;
1930 		void FillDropDown(ComboBox *pComboBox, ContextMenu *pDropdownList)
1931 		{ pCombo = pComboBox; pDrop = pDropdownList; FillDropDownCB(); }
1932 		virtual void FillDropDownCB() = 0;
1933 		virtual bool OnComboSelChange(ComboBox *pForCombo, int32_t idNewSelection) = 0;
1934 
1935 		// to be used in fill-callback only (crash otherwise!)
1936 		void AddEntry(const char *szText, int32_t id);
1937 		bool FindEntry(const char *szText);
1938 		void ClearEntries();
1939 		void SelectEntry(int32_t iEntry); // select entry by index
1940 	};
1941 
1942 	template <class CB> class ComboBox_FillCallback : public ComboBox_FillCB
1943 	{
1944 	public:
1945 		typedef void (CB::*ComboFillFunc)(ComboBox_FillCB *pFiller);
1946 		typedef bool (CB::*ComboSelFunc)(ComboBox *pForCombo, int32_t idNewSelection);
1947 
1948 	private:
1949 		CB *pCBClass;
1950 		ComboFillFunc FillFunc;
1951 		ComboSelFunc SelFunc;
1952 	protected:
1953 		void FillDropDownCB() override
1954 		{ if (pCBClass && FillFunc) (pCBClass->*FillFunc)(this); }
1955 		bool OnComboSelChange(ComboBox *pForCombo, int32_t idNewSelection) override
1956 		{ if (pCBClass && SelFunc) return (pCBClass->*SelFunc)(pForCombo, idNewSelection); else return false; }
1957 
1958 	public:
1959 		ComboBox_FillCallback(CB * pCBClass, ComboFillFunc FillFunc, ComboSelFunc SelFunc) :
1960 				pCBClass(pCBClass), FillFunc(FillFunc), SelFunc(SelFunc) { }
1961 	};
1962 
1963 
1964 	// dropdown box to select elements from a list
1965 	class ComboBox : public Control
1966 	{
1967 	public:
1968 		struct ComboMenuCBStruct // struct used as menu callback parameter for dropdown menu
1969 		{
1970 			StdCopyStrBuf sText;
1971 			int32_t id{0};
1972 
1973 			ComboMenuCBStruct() : sText() {}
1974 			ComboMenuCBStruct(const char *szText, int32_t id) : sText(szText), id(id) {}
1975 		};
1976 	private:
1977 		class C4KeyBinding *pKeyOpenCombo, *pKeyCloseCombo;
1978 	private:
1979 		int32_t iOpenMenu; // associated menu (used to flag dropped down)
1980 		ComboBox_FillCB *pFillCallback; // callback used to display the dropdown
1981 		char Text[C4MaxTitle+1]; // currently selected item
1982 		bool fReadOnly;  // merely a label in ReadOnly-mode
1983 		bool fSimple;    // combo without border and stuff
1984 		bool fMouseOver; // mouse hovering over this?
1985 		CStdFont *pUseFont;                       // font used to draw this control
1986 		uint32_t dwFontClr, dwBGClr, dwBorderClr; // colors used to draw this control
1987 		C4Facet *pFctSideArrow;                   // arrow gfx used to start combo-dropdown
1988 
1989 	private:
1990 		bool DoDropdown(); // open dropdown menu (context menu)
1991 		bool KeyDropDown() { return DoDropdown(); }
1992 		bool KeyAbortDropDown() { return AbortDropdown(true); }
1993 		bool AbortDropdown(bool fByUser); // abort dropdown menu, if it's open
1994 
1995 	protected:
1996 		void DrawElement(C4TargetFacet &cgo) override;    // draw combo box
1997 
1998 		bool IsFocusOnClick() override { return false; } // don't select control on click
1999 		Control *IsFocusElement() override { return fReadOnly ? nullptr : this; }; // this control can gain focus if not readonly
2000 
2001 		void OnCtxComboSelect(C4GUI::Element *pListItem, const ComboMenuCBStruct &rNewSel);
2002 
2003 	public:
2004 		ComboBox(const C4Rect &rtBounds);
2005 		~ComboBox() override;
2006 
2007 		void MouseInput(CMouse &rMouse, int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyParam) override; // input: mouse. left-click opens menu
2008 		void MouseEnter(CMouse &rMouse) override; // called when mouse cursor enters element region
2009 		void MouseLeave(CMouse &rMouse) override; // called when mouse cursor leaves element region
2010 
2011 		void SetComboCB(ComboBox_FillCB *pNewFillCallback);
2012 		static int32_t GetDefaultHeight();
2013 		void SetText(const char *szToText);
2014 		void SetReadOnly(bool fToVal) { if ((fReadOnly = fToVal)) AbortDropdown(false); }
2015 		void SetSimple(bool fToVal) { fSimple = fToVal; }
2016 		const StdStrBuf GetText() { return StdStrBuf(Text, false); }
2017 		void SetFont(CStdFont *pToFont) { pUseFont=pToFont; }
2018 		void SetColors(uint32_t dwFontClr, uint32_t dwBGClr, uint32_t dwBorderClr)
2019 		{ this->dwFontClr=dwFontClr; this->dwBGClr=dwBGClr; this->dwBorderClr=dwBorderClr; }
2020 		void SetDecoration(C4Facet *pFctSideArrow)
2021 		{ this->pFctSideArrow = pFctSideArrow; }
2022 
2023 		friend class ComboBox_FillCB;
2024 	};
2025 
2026 	class Dialog;
2027 
2028 	// EM window class
2029 	class DialogWindow : public C4Window
2030 	{
2031 	public:
2032 		Dialog* pDialog{nullptr};
2033 		DialogWindow(): C4Window() {}
2034 		using C4Window::Init;
2035 		C4Window * Init(C4AbstractApp * pApp, const char * Title, const C4Rect &rcBounds, const char *szID);
2036 		void Close() override;
2037 		void PerformUpdate() override;
2038 	};
2039 
2040 	// information on how to draw dialog borders and face
2041 	class FrameDecoration
2042 	{
2043 	private:
2044 		int iRefCount{0};
2045 
2046 		bool SetFacetByAction(C4Def *pOfDef, class C4TargetFacet &rfctTarget, const char *szFacetName);
2047 
2048 	public:
2049 		C4Def *pSourceDef;
2050 		C4ID idSourceDef;
2051 		uint32_t dwBackClr; // background face color
2052 		C4TargetFacet fctTop, fctTopRight, fctRight, fctBottomRight, fctBottom, fctBottomLeft, fctLeft, fctTopLeft;
2053 		int iBorderTop, iBorderLeft, iBorderRight, iBorderBottom;
2054 		bool fHasGfxOutsideClientArea;
2055 
2056 		FrameDecoration()  { Clear(); }
2057 		void Clear(); // zero data
2058 
2059 		// create from ActMap and graphics of a definition (does some script callbacks to get parameters)
2060 		bool SetByDef(C4Def *pSrcDef);
2061 		bool SetByDef(C4ID idSourceDef); // a wrapper for the above method
2062 		bool UpdateGfx(); // update Surface, e.g. after def reload
2063 
2064 		void Ref() { ++iRefCount; }
2065 		void Deref() { if (!--iRefCount) delete this; }
2066 
2067 		void Draw(C4TargetFacet &cgo, C4Rect &rcDrawArea); // draw deco for given rect (rect includes border)
2068 	};
2069 
2070 	// a dialog
2071 	class Dialog: public Window
2072 	{
2073 	private:
2074 		enum Fade { eFadeNone=0, eFadeOut, eFadeIn };
2075 
2076 		C4KeyBinding *pKeyAdvanceControl, *pKeyAdvanceControlB, *pKeyHotkey, *pKeyEnter, *pKeyEscape, *pKeyFocusDefControl;
2077 	protected:
2078 		WoodenLabel *pTitle; // title bar text
2079 		CallbackButton<Dialog, C4GUI::IconButton> *pCloseBtn;
2080 		Control *pActiveCtrl; // control that has focus
2081 		bool fShow;    // if set, the dlg is shown
2082 		bool fOK;      // if set, the user pressed OK
2083 		int32_t iFade;     // dlg fade (percent)
2084 		Fade eFade;    // fading mode
2085 		bool fDelOnClose; // auto-delete when closing
2086 		StdStrBuf TitleString;
2087 		bool fViewportDlg; // set in ctor: if true, dlg is not independant, but drawn ad controlled within viewports
2088 		DialogWindow *pWindow;  // window in console mode
2089 		FrameDecoration *pFrameDeco;
2090 
2091 		bool CreateConsoleWindow();
2092 		void DestroyConsoleWindow();
2093 
2094 		void UpdateSize() override;                // called when own size changed - update assigned pWindow
2095 		void UpdatePos() override; // Dialogs with their own windows can only be at 0/0
2096 
2097 	public:
2098 		Dialog(int32_t iWdt, int32_t iHgt, const char *szTitle, bool fViewportDlg); // ctor
2099 		~Dialog() override; // dtor
2100 
2101 		void RemoveElement(Element *pChild) override; // clear ptr
2102 
2103 		void Draw(C4TargetFacet &cgo) override; // render dialog (published)
2104 		void DrawElement(C4TargetFacet &cgo) override; // draw dlg bg
2105 		bool IsComponentOutsideClientArea() override { return !!pTitle; } // pTitle lies outside client area
2106 
2107 		virtual const char *GetID() { return nullptr; }
2108 
2109 		// special handling for viewport dialogs
2110 		void ApplyElementOffset(int32_t &riX, int32_t &riY) override;
2111 		void ApplyInvElementOffset(int32_t &riX, int32_t &riY) override;
2112 
2113 		bool IsFocused(Control *pCtrl) override { return pCtrl == pActiveCtrl; }
2114 		void SetFocus(Control *pCtrl, bool fByMouse);
2115 		Control *GetFocus() { return pActiveCtrl; }
2116 		Dialog *GetDlg() override { return this; } // this is the dialog
2117 		DialogWindow* GetDialogWindow() override { return pWindow; }
2118 
2119 		virtual bool CharIn(const char * c);                                 // input: character key pressed - should return false for none-character-inputs  (forward to focused control)
2120 
2121 	private:
2122 		bool KeyHotkey(const C4KeyCodeEx &key);
2123 		bool KeyFocusDefault();
2124 
2125 	public:
2126 		void MouseInput(CMouse &rMouse, int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyParam) override; // input: mouse. forwards to child controls
2127 
2128 		// default control to be set if unprocessed keyboard input has been detected
2129 		virtual class Control *GetDefaultControl() { return nullptr; }
2130 
2131 		// default dlg actions for enter/escape
2132 		virtual bool OnEnter() { UserClose(true); return true; }
2133 		bool KeyEnter() { return OnEnter(); }
2134 		virtual bool OnEscape() { UserClose(false); return true; }
2135 		bool KeyEscape() { return OnEscape(); }
2136 
2137 		void AdvanceFocus(bool fBackwards); // change focus to next component
2138 		bool KeyAdvanceFocus(bool fBackwards) { AdvanceFocus(fBackwards); return true; }
2139 
2140 		int32_t GetMarginTop() override { return (pTitle ? pTitle->GetBounds().Hgt : 0) + (pFrameDeco ? pFrameDeco->iBorderTop : Window::GetMarginTop()); }
2141 		int32_t GetMarginLeft() override { return pFrameDeco ? pFrameDeco->iBorderLeft : Window::GetMarginLeft(); }
2142 		int32_t GetMarginRight() override { return pFrameDeco ? pFrameDeco->iBorderRight: Window::GetMarginRight(); }
2143 		int32_t GetMarginBottom() override { return pFrameDeco ? pFrameDeco->iBorderBottom: Window::GetMarginBottom(); }
2144 
2145 		static int32_t GetDefaultTitleHeight();
2146 
2147 		bool IsShown() { return fShow; } // returns whether dlg is on screen (may be invisible)
2148 		bool IsOK() { return fOK; }      // returns whether user pressed OK
2149 		bool IsAborted() { return !fShow && !fOK; } // returns whether dialog has been aborted
2150 		bool IsActive(bool fForKeyboard); // return whether dlg has mouse control focus
2151 		bool IsFading() { return eFade != eFadeNone; }
2152 
2153 		virtual bool IsFullscreenDialog() { return false; }
2154 		virtual bool HasBackground() { return false; } // true if dlg draws screen background (fullscreen dialogs only)
2155 
2156 		// true for dialogs that should span the whole screen
2157 		// not just the mouse-viewport
2158 		virtual bool IsFreePlaceDialog() { return false; }
2159 
2160 		// true for dialogs that should be placed at the bottom of the screen (chat)
2161 		virtual bool IsBottomPlacementDialog() { return false; }
2162 
2163 		// true for dialogs that receive full keyboard and mouse input even in shared mode
2164 		virtual bool IsExclusiveDialog() { return false; }
2165 
2166 		// some dialogs, like menus or chat control, don't really need a mouse
2167 		// so do not enable it for those in shared mode if mouse control is disabled
2168 		virtual bool IsMouseControlled() { return true; }
2169 
2170 		// For dialogs associated to a viewport: Return viewport (for placement)
2171 		virtual C4Viewport *GetViewport() { return nullptr; }
2172 		bool IsViewportDialog() { return fViewportDlg; }
2173 
2174 		// for custom placement procedures; should call SetPos
2175 		virtual bool DoPlacement(Screen *pOnScreen, const C4Rect &rPreferredDlgRect)  { return false; }
2176 
2177 		// true for dialogs drawn externally
2178 		bool IsExternalDrawDialog() override { return false; }
2179 
2180 		// z-ordering used for dialog placement
2181 		virtual int32_t GetZOrdering() { return C4GUI_Z_DEFAULT; }
2182 
2183 		bool Show(Screen *pOnScreen, bool fCB); // show dialog on screen - default to last created screen
2184 		void Close(bool fOK);         // close dlg
2185 		bool FadeIn(Screen *pOnScreen); // fade dlg into screen
2186 		void FadeOut(bool fCloseWithOK); // fade out dlg
2187 		bool DoModal();               // execute message loop until dlg is closed (or GUI destructed) - returns whether dlg was OK
2188 		bool Execute();               // execute dialog - does message handling, gfx output and idle proc; return false if dlg got closed or GUI deleted
2189 		bool Execute2();              // execute dialog - does message handling, gfx output and idle proc; return false and deletes self if dlg got closed or GUI deleted
2190 		void SetDelOnClose(bool fToVal=true) { fDelOnClose=fToVal; } // dialog will delete itself when closed
2191 
2192 		void SetTitle(const char *szToTitle, bool fShowCloseButton = true); // change title text; creates or removes title bar if necessary
2193 		void SetFrameDeco(FrameDecoration *pNewDeco) // change border decoration
2194 		{
2195 			if (pFrameDeco) pFrameDeco->Deref();
2196 			if ((pFrameDeco = pNewDeco)) pNewDeco->Ref();
2197 			UpdateOwnPos(); // margin may have changed; might need to reposition stuff
2198 		}
2199 		void ClearFrameDeco() // clear border decoration; no own pos update!
2200 		{if (pFrameDeco) pFrameDeco->Deref(); pFrameDeco = nullptr; }
2201 		FrameDecoration *GetFrameDecoration() const { return pFrameDeco; }
2202 		void SetClientSize(int32_t iToWdt, int32_t iToHgt); // resize dialog so its client area has the specified size
2203 
2204 		void OnUserClose(C4GUI::Control *btn) // user presses close btn: Usually close dlg with abort
2205 		{ UserClose(false); }
2206 		virtual void UserClose(bool fOK) { Close(fOK); }
2207 		virtual void OnClosed(bool fOK);    // callback when dlg got closed
2208 		virtual void OnShown() {}           // callback when shown - should not delete the dialog
2209 		virtual void OnIdle() {}            // idle proc in DoModal
2210 
2211 		ContextHandler *GetContextHandler() override // always use own context handler only (no fall-through to screen)
2212 		{ return pContextHandler; }
2213 #ifdef _WIN32
2214 		static bool RegisterWindowClass(HINSTANCE hInst); // registers WNDCLASS for console mode dialogs
2215 #endif
2216 		friend class Screen;
2217 	};
2218 
2219 	// a dialog covering the whole screen (using UpperBoard-caption)
2220 	class FullscreenDialog : public Dialog
2221 	{
2222 	protected:
2223 		Label *pFullscreenTitle, *pSubTitle; // subtitle to be put in upper-right corner
2224 		int32_t iDlgMarginX, iDlgMarginY; // dialog margin set by screen size
2225 
2226 		const char *GetID() override { return nullptr; } // no ID needed, because it's never created as a window
2227 
2228 	public:
2229 		FullscreenDialog(const char *szTitle, const char *szSubtitle); // ctor
2230 
2231 		void SetTitle(const char *szToTitle); // change title text; creates or removes title bar if necessary
2232 
2233 	protected:
2234 		void DrawElement(C4TargetFacet &cgo) override; // draw dlg bg
2235 
2236 		// fullscreen dialogs are not closed on Enter
2237 		bool OnEnter() override { return false; }
2238 
2239 		bool IsComponentOutsideClientArea() override { return true; }
2240 
2241 		virtual bool HasUpperBoard() { return false; } // standard fullscreen dialog: UpperBoard no longer present
2242 
2243 		bool IsFullscreenDialog() override { return true; }
2244 		bool DoPlacement(Screen *pOnScreen, const C4Rect &rPreferredDlgRect) override  { return true; } // fullscreen dlg already placed
2245 
2246 		int32_t GetMarginTop() override { return (HasUpperBoard() ? C4UpperBoardHeight : C4GUI_FullscreenDlg_TitleHeight) + iDlgMarginY; }
2247 		int32_t GetMarginLeft() override { return iDlgMarginX; }
2248 		int32_t GetMarginRight() override { return iDlgMarginX; }
2249 		int32_t GetMarginBottom() override { return iDlgMarginY; }
2250 		void UpdateOwnPos() override; // called when element bounds were changed externally
2251 
2252 		// helper func: draw facet to screen background
2253 		void DrawBackground(C4TargetFacet &cgo, C4Facet &rFromFct);
2254 	};
2255 
2256 	// a button closing the Dlg
2257 	class CloseButton : public Button
2258 	{
2259 	protected:
2260 		bool fCloseResult;
2261 
2262 		void OnPress() override
2263 		{ Dialog *pDlg; if ((pDlg = GetDlg())) pDlg->UserClose(fCloseResult); }
2264 
2265 	public:
2266 		CloseButton(const char *szBtnText, const C4Rect &rtBounds, bool fResult) // ctor
2267 				: Button(szBtnText, rtBounds), fCloseResult(fResult) { }
2268 	};
2269 	class CloseIconButton : public IconButton
2270 	{
2271 	protected:
2272 		bool fCloseResult;
2273 
2274 		void OnPress() override
2275 		{ Dialog *pDlg; if ((pDlg = GetDlg())) pDlg->UserClose(fCloseResult); }
2276 
2277 	public:
2278 		CloseIconButton(const C4Rect &rtBounds, Icons eIcon, bool fResult) // ctor
2279 				: IconButton(eIcon, rtBounds, 0), fCloseResult(fResult) { }
2280 	};
2281 
2282 	// OK button
2283 	class OKButton : public CloseButton
2284 	{
2285 	public: OKButton(const C4Rect &rtBounds) // ctor
2286 				: CloseButton(LoadResStr("IDS_DLG_OK"), rtBounds, true) {} };
2287 	class OKIconButton : public CloseIconButton
2288 	{
2289 	public: OKIconButton(const C4Rect &rtBounds, Icons eIcon) // ctor
2290 				: CloseIconButton(rtBounds, eIcon, true) {} };
2291 	// cancel button
2292 	class CancelButton : public CloseButton
2293 	{
2294 	public: CancelButton(const C4Rect &rtBounds) // ctor
2295 				: CloseButton(LoadResStr("IDS_DLG_CANCEL"), rtBounds, false) {} };
2296 	class CancelIconButton : public CloseIconButton
2297 	{
2298 	public: CancelIconButton(const C4Rect &rtBounds, Icons eIcon) // ctor
2299 				: CloseIconButton(rtBounds, eIcon, false) {} };
2300 	// regular close button
2301 	class DlgCloseButton : public CloseButton
2302 	{
2303 	public: DlgCloseButton(const C4Rect &rtBounds) // ctor
2304 				: CloseButton(LoadResStr("IDS_DLG_CLOSE"), rtBounds, true) {} };
2305 	// Yes button
2306 	class YesButton : public CloseButton
2307 	{
2308 	public: YesButton(const C4Rect &rtBounds) // ctor
2309 				: CloseButton(LoadResStr("IDS_DLG_YES"), rtBounds, true) {} };
2310 	// No button
2311 	class NoButton : public CloseButton
2312 	{
2313 	public: NoButton(const C4Rect &rtBounds) // ctor
2314 				: CloseButton(LoadResStr("IDS_DLG_NO"), rtBounds, false) {} };
2315 	// Retry button
2316 	class RetryButton : public CloseButton
2317 	{
2318 	public: RetryButton(const C4Rect &rtBounds) // ctor
2319 				: CloseButton(LoadResStr("IDS_BTN_RETRY"), rtBounds, true) {} };
2320 	// Reset button
2321 	class ResetButton : public CloseButton
2322 	{
2323 	public: ResetButton(const C4Rect &rtBounds) // ctor
2324 				: CloseButton(LoadResStr("IDS_BTN_RESET"), rtBounds, true) {} };
2325 
2326 	// a simple message dialog
2327 	class MessageDialog : public Dialog
2328 	{
2329 	private:
2330 		bool fHasOK;
2331 		int32_t *piConfigDontShowAgainSetting;
2332 		class C4KeyBinding *pKeyCopy;
2333 		std::string sCopyText; // text that goes into clipboard if user presses Ctrl+C on this window
2334 	public:
2335 		enum Buttons { btnOK=1, btnAbort=2, btnYes=4, btnNo=8, btnRetry=16, btnReset=32,
2336 		               btnOKAbort=btnOK|btnAbort, btnYesNo=btnYes|btnNo, btnRetryAbort=btnRetry|btnAbort
2337 		             };
2338 		enum DlgSize { dsRegular=C4GUI_MessageDlgWdt, dsMedium=C4GUI_MessageDlgWdtMedium, dsSmall=C4GUI_MessageDlgWdtSmall };
2339 		MessageDialog(const char *szMessage, const char *szCaption, DWORD dwButtons, Icons icoIcon, DlgSize eSize=dsRegular, int32_t *piConfigDontShowAgainSetting=nullptr, bool fDefaultNo=false);
2340 		~MessageDialog() override;
2341 
2342 	protected:
2343 		bool OnEnter() override { if (!fHasOK) return false; Close(true); return true; }
2344 		void OnDontShowAgainCheck(C4GUI::Element *pCheckBox)
2345 		{ if (piConfigDontShowAgainSetting) *piConfigDontShowAgainSetting = static_cast<C4GUI::CheckBox *>(pCheckBox)->GetChecked(); }
2346 		bool KeyCopy();
2347 
2348 		const char *GetID() override { return "MessageDialog"; }
2349 		int32_t GetZOrdering() override { return C4GUI_Z_INPUT; }
2350 	};
2351 
2352 	// a confirmation dialog, which performs a callback after confirmation
2353 	class ConfirmationDialog : public MessageDialog
2354 	{
2355 	private:
2356 		BaseCallbackHandler *pCB;
2357 
2358 	public:
2359 		ConfirmationDialog(const char *szMessage, const char *szCaption, BaseCallbackHandler *pCB, DWORD dwButtons=MessageDialog::btnOKAbort, bool fSmall=false, Icons icoIcon=Ico_Confirm);
2360 		~ConfirmationDialog() override { if (pCB) pCB->DeRef(); }
2361 
2362 	protected:
2363 		void OnClosed(bool fOK) override;    // callback when dlg got closed
2364 	};
2365 
2366 	// a simple progress dialog
2367 	class ProgressDialog : public Dialog
2368 	{
2369 	protected:
2370 		ProgressBar *pBar; // progress bar component
2371 
2372 		const char *GetID() override { return "ProgressDialog"; }
2373 
2374 	public:
2375 		ProgressDialog(const char *szMessage, const char *szCaption, int32_t iMaxProgress, int32_t iInitialProgress, Icons icoIcon);
2376 
2377 		void SetProgress(int32_t iToProgress) { pBar->SetProgress(iToProgress); } // change progress
2378 		bool OnEnter() override { return false; } // don't close on Enter!
2379 	};
2380 
2381 
2382 	class BaseInputCallback
2383 	{
2384 	public:
2385 		virtual void OnOK(const StdStrBuf &sText) = 0;
2386 		virtual ~BaseInputCallback() = default;
2387 	};
2388 
2389 	template <class T> class InputCallback : public BaseInputCallback
2390 	{
2391 	public:
2392 		typedef void (T::*CBFunc)(const StdStrBuf &);
2393 	private:
2394 		T *pTarget;
2395 		CBFunc pCBFunc;
2396 	public:
2397 		InputCallback(T *pTarget, CBFunc pCBFunc) : pTarget(pTarget), pCBFunc(pCBFunc) {}
2398 
2399 		void OnOK(const StdStrBuf &sText) override { (pTarget->*pCBFunc)(sText); }
2400 	};
2401 
2402 	// a dialog for a one-line text input; contains OK and cancel button
2403 	class InputDialog : public Dialog
2404 	{
2405 	protected:
2406 		Edit *pEdit; // edit for text input
2407 		BaseInputCallback *pCB;
2408 		C4Rect rcEditBounds;
2409 		bool fChatLayout;
2410 		Label *pChatLbl;
2411 
2412 		const char *GetID() override { return "InputDialog"; }
2413 
2414 	public:
2415 		InputDialog(const char *szMessage, const char *szCaption, Icons icoIcon, BaseInputCallback *pCB, bool fChatLayout=false);
2416 		~InputDialog() override { if (pCB) delete pCB; }
2417 
2418 		void OnClosed(bool fOK) override { if (pCB && fOK) pCB->OnOK(StdStrBuf(pEdit->GetText())); Dialog::OnClosed(fOK); } // close CB
2419 		void SetMaxText(int32_t iMaxLen) { pEdit->SetMaxText(iMaxLen); }
2420 		void SetInputText(const char *szToText);
2421 		const char *GetInputText() { return pEdit->GetText(); }
2422 		void SetCustomEdit(Edit *pCustomEdit);
2423 	};
2424 
2425 	// a dialog showing some information text
2426 	class InfoDialog : public Dialog, private C4ApplicationSec1Timer
2427 	{
2428 	private:
2429 		int32_t iScroll;      // current scroll pos; backup for text update
2430 
2431 	protected:
2432 		TextWindow *pTextWin;
2433 
2434 		void CreateSubComponents(); // ctor func
2435 
2436 		// add text to the info window
2437 		void AddLine(const char *szText);
2438 		void AddLineFmt(const char *szFmtString, ...) GNUC_FORMAT_ATTRIBUTE_O;
2439 
2440 		void BeginUpdateText(); // backup scrolling and clear text window
2441 		void EndUpdateText();   // restore scroll pos; set last update time
2442 
2443 		virtual void UpdateText() {}; // function to be overwritten for timed dlgs: Update window text
2444 
2445 		void OnSec1Timer() override; // idle proc: update text if necessary
2446 	public:
2447 		InfoDialog(const char *szCaption, int32_t iLineCount); // ctor
2448 		InfoDialog(const char *szCaption, int iLineCount, const StdStrBuf &sText); // ctor - init w/o timer
2449 		~InfoDialog() override;
2450 	};
2451 
2452 	// a keyboard event that's only executed if the dialog is activated
2453 	template <class TargetClass> class DlgKeyCB : public C4KeyCB<TargetClass>
2454 	{
2455 	private:
2456 		typedef C4KeyCB<TargetClass> Base;
2457 		typedef bool(TargetClass::*CallbackFunc)();
2458 	public:
2459 		DlgKeyCB(TargetClass &rTarget, CallbackFunc pFuncDown, CallbackFunc pFuncUp=nullptr, CallbackFunc pFuncPressed=nullptr)
2460 				: Base(rTarget, pFuncDown, pFuncUp, pFuncPressed) {}
2461 
2462 		bool CheckCondition() override { return Base::rTarget.IsInActiveDlg(true) && Base::rTarget.IsVisible(); }
2463 	};
2464 
2465 	template <class TargetClass> class DlgKeyCBPassKey : public C4KeyCBPassKey<TargetClass>
2466 	{
2467 	private:
2468 		typedef C4KeyCBPassKey<TargetClass> Base;
2469 		typedef bool(TargetClass::*CallbackFunc)(const C4KeyCodeEx &key);
2470 	public:
2471 		DlgKeyCBPassKey(TargetClass &rTarget, CallbackFunc pFuncDown, CallbackFunc pFuncUp=nullptr, CallbackFunc pFuncPressed=nullptr)
2472 				: Base(rTarget, pFuncDown, pFuncUp, pFuncPressed) {}
2473 
2474 		bool CheckCondition() override { return Base::rTarget.IsInActiveDlg(true) && Base::rTarget.IsVisible(); }
2475 	};
2476 
2477 	template <class TargetClass, class ParameterType> class DlgKeyCBEx : public C4KeyCBEx<TargetClass, ParameterType>
2478 	{
2479 	private:
2480 		typedef C4KeyCBEx<TargetClass, ParameterType> Base;
2481 		typedef bool(TargetClass::*CallbackFunc)(ParameterType par);
2482 	public:
2483 		DlgKeyCBEx(TargetClass &rTarget, const ParameterType &par, CallbackFunc pFuncDown, CallbackFunc pFuncUp=nullptr, CallbackFunc pFuncPressed=nullptr)
2484 				: Base(rTarget, par, pFuncDown, pFuncUp, pFuncPressed) {}
2485 
2486 		bool CheckCondition() override { return Base::rTarget.IsInActiveDlg(true) && Base::rTarget.IsVisible(); }
2487 	};
2488 
2489 	// a keyboard event that's only executed if the control has focus
2490 	template <class TargetClass> class ControlKeyCB : public C4KeyCB<TargetClass>
2491 	{
2492 	private:
2493 		typedef C4KeyCB<TargetClass> Base;
2494 		typedef bool(TargetClass::*CallbackFunc)();
2495 	public:
2496 		ControlKeyCB(TargetClass &rTarget, CallbackFunc pFuncDown, CallbackFunc pFuncUp=nullptr, CallbackFunc pFuncPressed=nullptr)
2497 				: Base(rTarget, pFuncDown, pFuncUp, pFuncPressed) {}
2498 
2499 		bool CheckCondition() override { return Base::rTarget.HasDrawFocus(); }
2500 	};
2501 
2502 	template <class TargetClass, class ParameterType> class ControlKeyCBExPassKey : public C4KeyCBExPassKey<TargetClass, ParameterType>
2503 	{
2504 	private:
2505 		typedef C4KeyCBExPassKey<TargetClass, ParameterType> Base;
2506 		typedef bool(TargetClass::*CallbackFunc)(const C4KeyCodeEx &key, const ParameterType &par);
2507 	public:
2508 		ControlKeyCBExPassKey(TargetClass &rTarget, const ParameterType &rPar, CallbackFunc pFuncDown, CallbackFunc pFuncUp=nullptr, CallbackFunc pFuncPressed=nullptr)
2509 				: Base(rTarget, rPar, pFuncDown, pFuncUp, pFuncPressed) {}
2510 
2511 		bool CheckCondition() override { return Base::rTarget.HasDrawFocus(); }
2512 	};
2513 
2514 	// key event that checks whether a control is active, but forwards to the dialog
2515 	template <class TargetClass> class ControlKeyDlgCB : public C4KeyCB<TargetClass>
2516 	{
2517 	private:
2518 		class Control *pCtrl;
2519 		typedef C4KeyCB<TargetClass> Base;
2520 		typedef bool(TargetClass::*CallbackFunc)();
2521 	public:
2522 		ControlKeyDlgCB(Control *pCtrl, TargetClass &rTarget, CallbackFunc pFuncDown, CallbackFunc pFuncUp=nullptr, CallbackFunc pFuncPressed=nullptr)
2523 				: Base(rTarget, pFuncDown, pFuncUp, pFuncPressed), pCtrl(pCtrl) {}
2524 
2525 		bool CheckCondition() override { return pCtrl && pCtrl->IsInActiveDlg(true) && pCtrl->IsVisible(); }
2526 	};
2527 
2528 	// mouse cursor control
2529 	class CMouse
2530 	{
2531 	public:
2532 		int32_t x,y; // cursor position
2533 		bool LDown, MDown, RDown; // mouse button states
2534 		int32_t LDownX, LDownY;       // position where left button was pressed last
2535 		DWORD dwKeys;             // shift, ctrl, etc.
2536 		bool fActive;
2537 		C4TimeMilliseconds tLastMovementTime; // C4TimeMilliseconds::Now() when the mouse pos changed last
2538 
2539 		// whether last input was done by mouse
2540 		// set to true whenever mouse pos changes or buttons are pressed
2541 		// reset by keyboard actions to avoid tooltips where the user isn't even doing anything
2542 		bool fActiveInput;
2543 
2544 		enum TooltipShowState
2545 		{
2546 			TTST_None = 0, // show no tooltips
2547 			TTST_Immediate = 1, // show only tooltips of elements that require immediate show (i.e. otherwise unlabeled buttons)
2548 			TTST_All = 2, // show all tooltips (mouse hovered on same element for some time)
2549 		};
2550 
2551 	public:
2552 		Element *pMouseOverElement, *pPrevMouseOverElement; // elements at mouse position (after and before processing of mouse event)
2553 		Element *pDragElement;                              // element at pos where left mouse button was clicked last
2554 
2555 	public:
2556 		CMouse(int32_t iX, int32_t iY);  // ctor
2557 		~CMouse(); // dtor
2558 
2559 		void Draw(C4TargetFacet &cgo, TooltipShowState draw_tool_tips); // draw cursor
2560 
2561 		void Input(int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyParam); // process mouse input
2562 		bool IsLDown() { return LDown; }
2563 
2564 		void GetLastXY(int32_t &rX, int32_t &rY, DWORD &rdwKeys) { rX=x; rY=y; rdwKeys=dwKeys; }
2565 
2566 		void ResetElements() // reset MouseOver/etc.-controls
2567 		{ pMouseOverElement=pPrevMouseOverElement=pDragElement=nullptr; }
2568 		void ReleaseElements(); // reset MouseOver/etc.-controls, doing the appropriate callbacks
2569 		void OnElementGetsInvisible(Element *pChild); // clear ptr
2570 
2571 		void RemoveElement(Element *pChild); // clear ptr
2572 
2573 		void SetOwnedMouse(bool fToVal) { fActive=fToVal; }
2574 
2575 		void ResetToolTipTime() { tLastMovementTime = C4TimeMilliseconds::Now(); }
2576 		bool IsMouseStill() { return C4TimeMilliseconds::Now()-tLastMovementTime >= C4GUI_ToolTipShowTime; }
2577 		void ResetActiveInput() { fActiveInput = false; }
2578 		bool IsActiveInput() { return fActiveInput; }
2579 
2580 		void ReleaseButtons() { LDown = RDown = MDown = false; }
2581 	};
2582 
2583 	// the dialog client area
2584 	class Screen : public Window
2585 	{
2586 	public:
2587 		CMouse Mouse;
2588 
2589 	protected:
2590 		Dialog *pActiveDlg;    // current, active dialog
2591 		ContextMenu *pContext{nullptr}; // currently opened context menu (lowest submenu)
2592 		bool fExclusive{true};       // default true. if false, input is shared with the game
2593 		C4Rect PreferredDlgRect; // rectangle in which dialogs should be placed
2594 		float fZoom{1.0f};
2595 
2596 		static Screen *pScreen; // static singleton var
2597 
2598 	public:
2599 		void RemoveElement(Element *pChild) override; // clear ptr
2600 		const C4Rect &GetPreferredDlgRect() { return PreferredDlgRect; }
2601 
2602 	protected:
2603 		using Window::Draw;
2604 		virtual void Draw(C4TargetFacet &cgo, bool fDoBG); // draw screen contents
2605 
2606 		void ElementPosChanged(Element *pOfElement) override; // called when a dialog is moved
2607 
2608 	public:
2609 		void ShowDialog(Dialog *pDlg, bool fFade); // present dialog to user
2610 		void CloseDialog(Dialog *pDlg, bool fFade);// hide dialog from user
2611 		void ActivateDialog(Dialog *pDlg);         // set dlg as active
2612 		void RecheckActiveDialog();
2613 
2614 		Dialog *GetTopDialog(); // get topmost dlg
2615 	public:
2616 		Screen();
2617 		~Screen() override;
2618 
2619 		void Init(int32_t tx, int32_t ty, int32_t twdt, int32_t thgt);
2620 		void Clear();
2621 
2622 		void Render(bool fDoBG);                 // render to pDraw
2623 		void RenderMouse(C4TargetFacet &cgo);        // draw mouse only
2624 
2625 		Screen *GetScreen() override { return this; }; // return contained screen
2626 		static Screen *GetScreenS() { return pScreen; } // get global screen
2627 
2628 		float GetZoom() const { return fZoom; }; // get GUI zoom
2629 
2630 		bool IsActive() { return !!GetTopDialog(); } // return whether GUI is active
2631 
2632 		bool KeyAny(); // to be called on keystrokes; resets some tooltip-times
2633 		virtual bool CharIn(const char * c);        // input: character key pressed - should return false for none-character-inputs
2634 		using Window::MouseInput;
2635 		bool MouseInput(int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyParam, Dialog *pDlg, class C4Viewport *pVP); // input: mouse movement or buttons; sends MouseEnter/Leave; return whether inside dialog
2636 		void MouseMove(int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyParam, class C4Viewport *pVP); // pVP specified for console mode viewports only
2637 		void SetMouseInGUI(bool fInGUI, bool fByMouse);
2638 		bool RecheckMouseInput();                                       // do mouse movement iusing last input flags
2639 
2640 		bool ShowMessage(const char *szMessage, const char *szCaption, Icons icoIcon, int32_t *piConfigDontShowAgainSetting=nullptr); // show message
2641 		bool ShowErrorMessage(const char *szMessage); // show message: Error caption and icon
2642 		bool ShowMessageModal(const char *szMessage, const char *szCaption, DWORD dwButtons, Icons icoIcon, int32_t *piConfigDontShowAgainSetting=nullptr); // show modal message dlg
2643 		ProgressDialog *ShowProgressDlg(const char *szMessage, const char *szCaption, int32_t iMaxProgress=100, int32_t iInitialProgress=0, Icons icoIcon=Ico_Wait); // create and show a progress dialog
2644 		bool ShowModalDlg(Dialog *pDlg, bool fDestruct=true); // show any dialog modal and destruct it afterwards
2645 		bool ShowRemoveDlg(Dialog *pDlg); // show dialog, and flag it to delete itself when closed; return immediately
2646 
2647 		void CloseAllDialogs(bool fWithOK); // close all dialogs on the screen; top dlgs first
2648 		void SetPreferredDlgRect(const C4Rect &rtNewPref) { PreferredDlgRect = rtNewPref; }
2649 #ifdef USE_WIN32_WINDOWS
2650 		Dialog *GetDialog(HWND hWindow); // get console dialog
2651 #endif
2652 		Dialog *GetDialog(C4Window * pWindow); // get console dialog
2653 		void DoContext(ContextMenu *pNewCtx, Element *pAtElement, int32_t iX, int32_t iY); // open context menu (closes any other contextmenu)
2654 		void AbortContext(bool fByUser) { if (pContext) pContext->Abort(fByUser); } // close context menu
2655 		int32_t GetContextMenuIndex() { return pContext ? pContext->GetMenuIndex() : 0; } // get current context-menu (lowest level)
2656 		int32_t GetLastContextMenuIndex() { return ContextMenu::GetLastMenuIndex(); } // get last opened context-menu (lowest level)
2657 		bool HasContext() { return !!pContext; }
2658 
2659 		bool HasFullscreenDialog(bool fIncludeFading); // true if on fullscreen dialog is visible
2660 		Dialog *GetFullscreenDialog(bool fIncludeFading); // return dlg pointer to first found fullscreen dialog
2661 
2662 		// callback from C4Game from message-handling of WM_TIMER; forwards to dialog-timer
2663 		void OnSec1Timer();
2664 
2665 		// exclusive
2666 		void SetExclusive(bool fToState) { fExclusive = fToState; Mouse.SetOwnedMouse(fExclusive); UpdateMouseFocus(); }
2667 		bool IsExclusive() { return fExclusive; }
2668 		bool HasKeyboardFocus()
2669 		{
2670 			// always hook keyboard in exclusive mode; only on exclusive top dialogs in shared mode
2671 			if (IsExclusive()) return true;
2672 			Dialog *pDlg = GetTopDialog();
2673 			return pDlg && pDlg->IsExclusiveDialog();
2674 		}
2675 		bool HasMouseFocus() // return whether mouse controls GUI only
2676 		{ return HasKeyboardFocus(); }
2677 		int32_t GetMouseControlledDialogCount(); // count dlgs with that flag set
2678 		void UpdateMouseFocus(); // when exclusive mode has changed: Make sure mouse clip is correct
2679 
2680 		// draw a tooltip in a box
2681 		static void DrawToolTip(const char *szTip, C4TargetFacet &cgo, float guix, float guiy);
2682 
2683 		// gamepad
2684 		void UpdateGamepadGUIControlEnabled(); // callback when gamepad gui option changed
2685 
2686 		friend class Dialog; friend class ContextMenu;
2687 	};
2688 
2689 	// menu handler bound to member functions of another class
2690 	template <class CBClass> class CBMenuHandler : public MenuHandler
2691 	{
2692 	private:
2693 		CBClass *pCBTarget; // callback target
2694 		typename DlgCallback<CBClass>::ContextClickFunc pCallbackFn; // callback function
2695 
2696 	public:
2697 		// ctor
2698 		CBMenuHandler<CBClass>(CBClass *pCBTarget, typename DlgCallback<CBClass>::ContextClickFunc pCallbackFn, int32_t iaExtra=0)
2699 				: MenuHandler(), pCBTarget(pCBTarget), pCallbackFn(pCallbackFn) { }
2700 
2701 		void OnOK(Element *pTargetElement) override
2702 		{
2703 			if (!pCBTarget /* || !pCallbackFn */) return;
2704 			// do callback
2705 			(pCBTarget->*pCallbackFn)(pTargetElement);
2706 		}
2707 	};
2708 
2709 	// menu handler bound to member functions of another class, providing extra storage for parameters
2710 	template <class CBClass, class TEx> class CBMenuHandlerEx : public MenuHandler
2711 	{
2712 	private:
2713 		CBClass *pCBTarget; // callback target
2714 		typename DlgCallbackEx<CBClass, const TEx &>::ContextClickFunc pCallbackFn; // callback function
2715 		TEx Extra;  // extra data
2716 	public:
2717 		// ctor
2718 		CBMenuHandlerEx<CBClass, TEx>(CBClass *pCBTarget, typename DlgCallbackEx<CBClass, const TEx &>::ContextClickFunc pCallbackFn, TEx aExtra)
2719 				: MenuHandler(), pCBTarget(pCBTarget), pCallbackFn(pCallbackFn), Extra(std::move(aExtra)) { }
2720 		CBMenuHandlerEx<CBClass, TEx>(CBClass *pCBTarget, typename DlgCallbackEx<CBClass, const TEx &>::ContextClickFunc pCallbackFn)
2721 				: MenuHandler(), pCBTarget(pCBTarget), pCallbackFn(pCallbackFn), Extra() { }
2722 
2723 		const TEx &GetExtra() const { return Extra; }
2724 		void SetExtra(const TEx &e) { Extra = e; }
2725 
2726 		void OnOK(Element *pTargetElement) override
2727 		{
2728 			if (!pCBTarget || !pCallbackFn) return;
2729 			// do callback
2730 			(pCBTarget->*pCallbackFn)(pTargetElement, Extra);
2731 		}
2732 	};
2733 
2734 	// context handler bound to member functions of another class
2735 	template <class CBClass> class CBContextHandler : public ContextHandler
2736 	{
2737 	private:
2738 		CBClass *pCBTarget; // callback target
2739 		typename DlgCallback<CBClass>::ContextFunc pCallbackFn; // callback function
2740 
2741 	public:
2742 		// ctor
2743 		CBContextHandler<CBClass>(CBClass *pCBTarget, typename DlgCallback<CBClass>::ContextFunc pCallbackFn)
2744 				: ContextHandler(), pCBTarget(pCBTarget), pCallbackFn(pCallbackFn) { }
2745 
2746 		bool OnContext(Element *pOnElement, int32_t iX, int32_t iY) override
2747 		{
2748 			DlgCallback<CBClass>();
2749 			if (!pCBTarget) return false;
2750 			// if (!pCallbackFn) return false;
2751 			Screen *pScreen = pOnElement->GetScreen();
2752 			if (!pScreen) return false;
2753 			// let CB func create context menu
2754 			ContextMenu *pNewMenu = (pCBTarget->*pCallbackFn)(pOnElement, iX, iY);
2755 			if (!pNewMenu) return false;
2756 			// open it on screen
2757 			pScreen->DoContext(pNewMenu, pOnElement, iX, iY);
2758 			// done, success
2759 			return true;
2760 		}
2761 
2762 		C4GUI::ContextMenu *OnSubcontext(Element *pOnElement) override
2763 		{
2764 			// query directly
2765 			return (pCBTarget->*pCallbackFn)(pOnElement, 0, 0);
2766 		}
2767 		friend class Dialog;
2768 	};
2769 
2770 	// a helper used to align elements
2771 	class ComponentAligner
2772 	{
2773 	protected:
2774 		C4Rect rcClientArea; // free client area
2775 		int32_t iMarginX, iMarginY; // horizontal and vertical margins of components
2776 
2777 		static C4Rect rcTemp; // temp rect
2778 
2779 	public:
2780 		ComponentAligner(const C4Rect &rcArea, int32_t iMarginX, int32_t iMarginY, bool fZeroAreaXY=false) // ctor
2781 				: rcClientArea(rcArea), iMarginX(iMarginX), iMarginY(iMarginY)
2782 		{ if (fZeroAreaXY) rcClientArea.x=rcClientArea.y=0; }
2783 
2784 		bool GetFromTop(int32_t iHgt, int32_t iWdt, C4Rect &rcOut); // get a portion from the top
2785 		bool GetFromLeft(int32_t iWdt, int32_t iHgt, C4Rect &rcOut); // get a portion from the left
2786 		bool GetFromRight(int32_t iWdt, int32_t iHgt, C4Rect &rcOut); // get a portion from the right
2787 		bool GetFromBottom(int32_t iHgt, int32_t iWdt, C4Rect &rcOut); // get a portion from the bottom
2788 		void GetAll(C4Rect &rcOut); // get remaining client area
2789 		bool GetCentered(int32_t iWdt, int32_t iHgt, C4Rect &rcOut); // get centered subregion within area
2790 
2791 		C4Rect &GetFromTop(int32_t iHgt, int32_t iWdt=-1) { GetFromTop(iHgt, iWdt, rcTemp); return rcTemp; } // get a portion from the top
2792 		C4Rect &GetFromLeft(int32_t iWdt, int32_t iHgt=-1) { GetFromLeft(iWdt, iHgt, rcTemp); return rcTemp; } // get a portion from the left
2793 		C4Rect &GetFromRight(int32_t iWdt, int32_t iHgt=-1) { GetFromRight(iWdt, iHgt, rcTemp); return rcTemp; } // get a portion from the right
2794 		C4Rect &GetFromBottom(int32_t iHgt, int32_t iWdt=-1) { GetFromBottom(iHgt, iWdt, rcTemp); return rcTemp; } // get a portion from the bottom
2795 		C4Rect &GetAll() { GetAll(rcTemp); return rcTemp; } // get remaining client are
2796 		C4Rect &GetCentered(int32_t iWdt, int32_t iHgt) { GetCentered(iWdt, iHgt, rcTemp); return rcTemp; } // get centered subregion within area (w/o size checks)
2797 
2798 		C4Rect &GetGridCell(int32_t iSectX, int32_t iSectXMax, int32_t iSectY, int32_t iSectYMax, int32_t iSectSizeX=-1, int32_t iSectSizeY=-1, bool fCenterPos=false, int32_t iSectNumX=1, int32_t iSectNumY=1);
2799 
2800 		int32_t GetWidth() const { return rcClientArea.Wdt; }
2801 		int32_t GetHeight() const { return rcClientArea.Hgt; }
2802 		int32_t GetHMargin() const { return iMarginX; }
2803 		int32_t GetVMargin() const { return iMarginY; }
2804 
2805 		int32_t GetInnerWidth() const { return rcClientArea.Wdt-2*iMarginX; }
2806 		int32_t GetInnerHeight() const { return rcClientArea.Hgt-2*iMarginY; }
2807 
2808 		void ExpandTop(int32_t iByHgt) { rcClientArea.y-=iByHgt; rcClientArea.Hgt+=iByHgt; } // enlarge client rect
2809 		void ExpandLeft(int32_t iByWdt) { rcClientArea.x-=iByWdt; rcClientArea.Wdt+=iByWdt; } // enlarge client rect
2810 		void ExpandRight(int32_t iByWdt) { rcClientArea.Wdt+=iByWdt; } // enlarge client rect
2811 		void ExpandBottom(int32_t iByHgt) { rcClientArea.Hgt+=iByHgt; } // enlarge client rect
2812 
2813 		void LogIt(const char *szName);
2814 	};
2815 
2816 	// shortcut for check whether GUI is active
2817 	inline bool IsActive() { return Screen::GetScreenS()->IsActive(); }
2818 	inline bool IsExclusive() { return Screen::GetScreenS()->IsExclusive(); }
2819 
2820 	// shortcut for GUI screen size
2821 	inline int32_t GetScreenWdt() { return Screen::GetScreenS()->GetBounds().Wdt; }
2822 	inline int32_t GetScreenHgt() { return Screen::GetScreenS()->GetBounds().Hgt; }
2823 
2824 	// sound effect in GUI: Only if enabled
2825 	void GUISound(const char *szSound);
2826 
2827 	// Zoom
2828 	inline float GetZoom() { return Screen::GetScreenS()->GetZoom(); }
2829 	inline void MouseMove(int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyParam, class C4Viewport *pVP) // pVP specified for console mode viewports only
2830 	{ Screen::GetScreenS()->MouseMove(iButton, iX, iY, dwKeyParam, pVP); }
2831 
2832 	extern Screen TheScreen;
2833 } // end of namespace
2834 
2835 typedef C4GUI::Screen C4GUIScreen;
2836 extern C4GUIScreen *pGUI;
2837 #endif
2838