OpenClonk
C4Gui.cpp
Go to the documentation of this file.
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 // all generic classes that do not fit into other C4Gui*-files
18 
19 #include "C4Include.h"
20 #include "gui/C4Gui.h"
21 
22 #include "game/C4Application.h"
23 #include "game/C4FullScreen.h"
24 #include "game/C4GraphicsSystem.h"
25 #include "game/C4Viewport.h"
26 #include "graphics/C4Draw.h"
28 #include "gui/C4LoaderScreen.h"
29 #include "gui/C4MouseControl.h"
30 #include "platform/C4GamePadCon.h"
31 
32 namespace C4GUI
33 {
34 
35 // --------------------------------------------------
36 // Generic helpers
37 
38  bool ExpandHotkeyMarkup(StdStrBuf &sText, uint32_t &rcHotkey, bool for_tooltip)
39  {
40  const char *HotkeyMarkup = (for_tooltip ? "<c ff800000>%s</c>" : "<c ffffff7f>%s</c>");
41 
42  StdStrBuf output;
43 
44  const char *input = sText.getData();
45  rcHotkey = 0;
46 
47  // Iterate over all input characters
48  while (input && *input)
49  {
50  if (*input != '&')
51  {
52  // This will correctly copy UTF-8 chars too
53  output.AppendChar(*input++);
54  }
55  else
56  {
57  ++input;
58  if (*input == '\0' || *input == '&')
59  {
60  // If the ampersand is followed by another ampersand, or it is the last character, copy it verbatimly
61  // Note: This means you can't use an ampersand as an accelerator key.
62  output.AppendChar(*input);
63  }
64  else
65  {
66  // Store the start of the hotkey so we can copy it later
67  const char *accel_start = input;
68  rcHotkey = GetNextCharacter(&input);
69  // Using std::string because StdStrBuf doesn't have a ctor from two iterators
70  std::string accel(accel_start, input);
71  output.AppendFormat(HotkeyMarkup, accel.c_str());
72 
73  // Converting a char code to upper case isn't trivial for unicode. (This should really just use ICU.)
74  if (Inside(rcHotkey, static_cast<uint32_t>('a'), static_cast<uint32_t>('z')))
75  {
76  rcHotkey += static_cast<uint32_t>('A') - 'a';
77  }
78  else if (!Inside(rcHotkey, static_cast<uint32_t>('A'), static_cast<uint32_t>('Z')))
79  {
80  // Warn about accelerator keys outside the basic latin alphabet.
81  LogF(LoadResStr("IDS_ERR_UNSUPPORTED_ACCELERATOR"), accel.c_str(), sText.getData());
82  }
83  }
84  }
85  }
86 
87  if (rcHotkey == 0)
88  {
89  // No accelerator found
90  return false;
91  }
92 
93  sText.Take(output);
94  // done, success
95  return true;
96  }
97 
99  {
100  // max alpha
101  DWORD dwAlpha = std::max<DWORD>(rdwClr>>24&255, 0xff)<<24;
102  rdwClr &= 0xffffff;
103  // determine brightness
104  // 50% red, 87% green, 27% blue (max 164 * 255)
105  DWORD r=(rdwClr>>16&255), g=(rdwClr>>8&255), b=(rdwClr&255);
106  int32_t iLightness = r*50 + g*87 + b*27;
107  // above 65/164 (*255) is OK
108  if (iLightness < 16575)
109  {
110  int32_t iInc = (16575-iLightness) / 164;
111  // otherwise, lighten
112  rdwClr = (std::min<DWORD>(r+iInc, 255)<<16) | (std::min<DWORD>(g+iInc, 255)<<8) | std::min<DWORD>(b+iInc, 255);
113  }
114  // return color and alpha
115  rdwClr |= dwAlpha;
116  return rdwClr;
117  }
118 
119  void DynBarFacet::SetHorizontal(C4Surface &rBySfc, int iHeight, int iBorderWidth)
120  {
121  if (!iHeight) iHeight = rBySfc.Hgt;
122  if (!iBorderWidth) iBorderWidth = iHeight;
123  fctBegin.Set(&rBySfc,0,0,iBorderWidth,iHeight);
124  fctMiddle.Set(&rBySfc,iBorderWidth,0,rBySfc.Wdt-2*iBorderWidth,iHeight);
125  fctEnd.Set(&rBySfc,rBySfc.Wdt-iBorderWidth,0,iBorderWidth,iHeight);
126  }
127 
128  void DynBarFacet::SetHorizontal(C4Facet &rByFct, int32_t iBorderWidth)
129  {
130  if (!iBorderWidth) iBorderWidth = rByFct.Hgt;
131  fctBegin.Set(rByFct.Surface,rByFct.X,rByFct.Y,iBorderWidth,rByFct.Hgt);
132  fctMiddle.Set(rByFct.Surface,rByFct.Hgt,rByFct.X,rByFct.Y+rByFct.Wdt-2*iBorderWidth,rByFct.Hgt);
133  fctEnd.Set(rByFct.Surface,rByFct.X+rByFct.Wdt-iBorderWidth,rByFct.Y,iBorderWidth,rByFct.Hgt);
134  }
135 
136  void ScrollBarFacets::Set(const C4Facet &rByFct, int32_t iPinIndex)
137  {
138  // set by hardcoded size
139  barScroll.fctBegin.Set(rByFct.Surface,0,0,16,16);
140  barScroll.fctMiddle.Set(rByFct.Surface,0,16,16,16);
141  barScroll.fctEnd.Set(rByFct.Surface,0,32,16,16);
142  fctScrollDTop.Set(rByFct.Surface,16,0,16,16);
143  if (iPinIndex)
144  fctScrollPin.Set(rByFct.Surface,32,16*(iPinIndex-1),16,16);
145  else
146  fctScrollPin.Set(rByFct.Surface,16,16,16,16);
147  fctScrollDBottom.Set(rByFct.Surface,16,32,16,16);
148  }
149 
150 // --------------------------------------------------
151 // Element
152 
154  {
155  // pParent=nullptr invalidates pPrev/pNext
156  // fDragging=false invalidates iDragX/Y
157  // zero fields
158  rcBounds.Set(0,0,0,0);
159  }
160 
162  {
163  // delete context handler
165  // remove from any container
166  if (pParent)
167  pParent->RemoveElement(this);
168  else if (this != Screen::GetScreenS() && Screen::GetScreenS())
169  // always ensure removal from screen!
171  }
172 
174  {
175  // child removed: forward to parent
176  if (pParent)
177  pParent->RemoveElement(pChild);
178  else if (this != Screen::GetScreenS())
179  // always ensure removal from screen!
180  // but not if this is the context menu, to avoid endless flip-flop!
181  if (!IsMenu())
183  }
184 
186  {
187  // update own fields
188  UpdateOwnPos();
189  // notify container
190  if (pParent) pParent->ElementSizeChanged(this);
191  }
192 
194  {
195  // update own fields
196  UpdateOwnPos();
197  // notify container
198  if (pParent) pParent->ElementPosChanged(this);
199  }
200 
202  {
203  // self and parent must be visible
204  return fVisible && (!pParent || pParent->IsVisible());
205  }
206 
207  void Element::SetVisibility(bool fToValue)
208  {
209  fVisible = fToValue;
210  // stop mouseover for invisible
211  if (!fVisible)
212  {
213  Screen *pScreen = GetScreen();
214  if (pScreen) pScreen->Mouse.OnElementGetsInvisible(this);
215  }
216  }
217 
218  void Element::ScreenPos2ClientPos(int32_t &riX, int32_t &riY)
219  {
220  // apply all parent offsets
221  Container *pCont = pParent;
222  while (pCont)
223  {
224  pCont->ApplyElementOffset(riX, riY);
225  pCont = pCont->GetParent();
226  }
227  // apply own offset
228  riX -= rcBounds.x; riY -= rcBounds.y;
229  }
230 
231  void Element::ClientPos2ScreenPos(int32_t &riX, int32_t &riY)
232  {
233  // apply all parent offsets
234  Container *pCont = pParent;
235  while (pCont)
236  {
237  pCont->ApplyInvElementOffset(riX, riY);
238  pCont = pCont->GetParent();
239  }
240  // apply own offset
241  riX += rcBounds.x; riY += rcBounds.y;
242  }
243 
244  void Element::MouseInput(CMouse &rMouse, int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyParam)
245  {
246  // store self as mouse-over-component
247  rMouse.pMouseOverElement = this;
248  // evaluate dragging
249  if (pDragTarget && iButton == C4MC_Button_LeftDown && !rMouse.pDragElement)
250  StartDragging(rMouse, iX, iY, dwKeyParam);
251  // right button down: open context menu
252  if (iButton == C4MC_Button_RightDown)
253  {
255  if (pCtx) pCtx->OnContext(this, iX, iY);
256  }
257  }
258 
259  void Element::StartDragging(CMouse &rMouse, int32_t iX, int32_t iY, DWORD dwKeyParam)
260  {
261  // set flag
262  fDragging = true;
263  // set drag start pos
264  iDragX = iX; iDragY = iY;
265  // mark drag in mouse
266  rMouse.pDragElement = this;
267  }
268 
269  void Element::DoDragging(CMouse &rMouse, int32_t iX, int32_t iY, DWORD dwKeyParam)
270  {
271  // check if anything moved
272  if (pDragTarget && (iX != iDragX || iY != iDragY))
273  {
274  // move position, then
275  pDragTarget->rcBounds.x += iX-iDragX;
276  pDragTarget->rcBounds.y += iY-iDragY;
277  // drag X/Y is up-to-date if this is a child element of the drag target
279  }
280  }
281 
282  void Element::StopDragging(CMouse &rMouse, int32_t iX, int32_t iY, DWORD dwKeyParam)
283  {
284  // move element pos
285  DoDragging(rMouse, iX, iY, dwKeyParam);
286  }
287 
288  Dialog *Element::GetDlg () { if (pParent) return pParent->GetDlg (); return nullptr; }
289  Screen *Element::GetScreen() { if (pParent) return pParent->GetScreen(); return nullptr; }
290 
291  void Element::Draw3DFrame(C4TargetFacet &cgo, bool fUp, int32_t iIndent, BYTE byAlpha, bool fDrawTop, int32_t iTopOff, bool fDrawLeft, int32_t iLeftOff)
292  {
293  DWORD dwAlpha = byAlpha<<24;
294  int32_t x0 = cgo.TargetX + rcBounds.x + iLeftOff,
295  y0 = cgo.TargetY + rcBounds.y + iTopOff,
296  x1 = cgo.TargetX + rcBounds.x + rcBounds.Wdt - 1,
297  y1 = cgo.TargetY + rcBounds.y + rcBounds.Hgt - 1;
298  if (fDrawTop) pDraw->DrawLineDw(cgo.Surface, (float)x0,(float)y0,(float)x1,(float)y0, C4GUI_BorderColor1 | dwAlpha);
299  if (fDrawLeft) pDraw->DrawLineDw(cgo.Surface, (float)x0,(float)y0,(float)x0,(float)y1, C4GUI_BorderColor1 | dwAlpha);
300  if (fDrawTop) pDraw->DrawLineDw(cgo.Surface, (float)(x0+1),(float)(y0+1),(float)(x1-1),(float)(y0+1), C4GUI_BorderColor2 | dwAlpha);
301  if (fDrawLeft) pDraw->DrawLineDw(cgo.Surface, (float)(x0+1),(float)(y0+1),(float)(x0+1),(float)(y1-1), C4GUI_BorderColor2 | dwAlpha);
302  pDraw->DrawLineDw(cgo.Surface, (float)x0,(float)y1,(float)x1,(float)y1, C4GUI_BorderColor3 | dwAlpha);
303  pDraw->DrawLineDw(cgo.Surface, (float)x1,(float)y0,(float)x1,(float)y1, C4GUI_BorderColor3 | dwAlpha);
304  pDraw->DrawLineDw(cgo.Surface, (float)(x0+1),(float)(y1-1),(float)(x1-1),(float)(y1-1), C4GUI_BorderColor1 | dwAlpha);
305  pDraw->DrawLineDw(cgo.Surface, (float)(x1-1),(float)(y0+1),(float)(x1-1),(float)(y1-1), C4GUI_BorderColor1 | dwAlpha);
306  }
307 
309  {
310  if (rcBounds.Hgt == rFacets.fctMiddle.Hgt)
311  {
312  // exact bar
313  int32_t x0=cgo.TargetX+rcBounds.x, y0=cgo.TargetY+rcBounds.y;
314  int32_t iX = rFacets.fctBegin.Wdt, w=rFacets.fctMiddle.Wdt, wLeft=rFacets.fctBegin.Wdt, wRight=rFacets.fctEnd.Wdt;
315  int32_t iRightShowLength = wRight/3;
316  bool fOverflow = (wLeft > rcBounds.Wdt);
317  if (fOverflow) rFacets.fctBegin.Wdt = rcBounds.Wdt;
318  rFacets.fctBegin.Draw(cgo.Surface, x0,y0);
319  if (fOverflow) rFacets.fctBegin.Wdt = wLeft;
320  while (iX < rcBounds.Wdt-iRightShowLength)
321  {
322  int32_t w2=std::min(w, rcBounds.Wdt-iRightShowLength-iX); rFacets.fctMiddle.Wdt=w2;
323  rFacets.fctMiddle.Draw(cgo.Surface, x0+iX, y0);
324  iX += w;
325  }
326  rFacets.fctMiddle.Wdt=w;
327  fOverflow = (wRight > rcBounds.Wdt);
328  if (fOverflow)
329  {
330  rFacets.fctEnd.X += wRight - rcBounds.Wdt;
331  rFacets.fctEnd.Wdt = rcBounds.Wdt;
332  }
333  rFacets.fctEnd.Draw(cgo.Surface, x0+rcBounds.Wdt-rFacets.fctEnd.Wdt, y0);
334  if (fOverflow)
335  {
336  rFacets.fctEnd.X -= wRight - rcBounds.Wdt;
337  rFacets.fctEnd.Wdt = wRight;
338  }
339  }
340  else
341  {
342  // zoomed bar
343  float fZoom = (float) rcBounds.Hgt / rFacets.fctMiddle.Hgt;
344  int32_t x0=cgo.TargetX+rcBounds.x, y0=cgo.TargetY+rcBounds.y;
345  int32_t iX = int32_t(fZoom*rFacets.fctBegin.Wdt), w=int32_t(fZoom*rFacets.fctMiddle.Wdt), wOld=rFacets.fctMiddle.Wdt;
346  int32_t iRightShowLength = rFacets.fctEnd.Wdt/3;
347  rFacets.fctBegin.DrawX(cgo.Surface, x0,y0,int32_t(fZoom*rFacets.fctBegin.Wdt),rcBounds.Hgt);
348  while (iX < rcBounds.Wdt-(fZoom*iRightShowLength))
349  {
350  int32_t w2=std::min<int32_t>(w, rcBounds.Wdt-int32_t(fZoom*iRightShowLength)-iX); rFacets.fctMiddle.Wdt=long(float(w2)/fZoom);
351  rFacets.fctMiddle.DrawX(cgo.Surface, x0+iX, y0, w2,rcBounds.Hgt);
352  iX += w;
353  }
354  rFacets.fctMiddle.Wdt=wOld;
355  rFacets.fctEnd.DrawX(cgo.Surface, x0+rcBounds.Wdt-int32_t(fZoom*rFacets.fctEnd.Wdt), y0,int32_t(fZoom*rFacets.fctEnd.Wdt),rcBounds.Hgt);
356  }
357  }
358 
360  {
361  C4DrawTransform trf(1);
362  DrawHVBar(cgo, rFacets, trf, rcBounds.Hgt);
363  }
364 
366  {
367  C4DrawTransform trf;
368  float fOffX = cgo.TargetX + rcBounds.x + rcBounds.Hgt/2;
369  float fOffY = cgo.TargetY + rcBounds.y + rcBounds.Hgt/2;
370  trf.SetRotate(-90.0f, fOffX, fOffY);
371 
372  DrawHVBar(cgo, rFacets, trf, rcBounds.Wdt);
373  }
374 
375  void Element::DrawHVBar(C4TargetFacet &cgo, DynBarFacet &rFacets, C4DrawTransform &trf, int32_t iMiddleLength)
376  {
377  int32_t y0 = cgo.TargetY + rcBounds.y;
378  int32_t x0 = cgo.TargetX + rcBounds.x;
379 
380  // draw up arrow
381  rFacets.fctBegin.DrawT(cgo.Surface, x0, y0, 0, 0, &trf);
382 
383  // draw middle part
384  int32_t h = rFacets.fctMiddle.Hgt;
385  int32_t barHeight = iMiddleLength - (rFacets.fctBegin.Hgt + rFacets.fctEnd.Hgt);
386 
387  for (int32_t iY = 0; iY <= barHeight; iY += h)
388  {
389  int32_t h2 = std::min(h, barHeight - iY);
390  rFacets.fctMiddle.Hgt = h2;
391  rFacets.fctMiddle.DrawT(cgo.Surface, x0, y0 + rFacets.fctBegin.Hgt + iY, 0, 0, &trf);
392  }
393  rFacets.fctMiddle.Hgt = h;
394 
395  // draw lower arrow
396  rFacets.fctEnd.DrawT(cgo.Surface, x0, y0 + iMiddleLength - rFacets.fctEnd.Hgt, 0, 0, &trf);
397  }
398 
399  C4Rect Element::GetToprightCornerRect(int32_t iWidth, int32_t iHeight, int32_t iHIndent, int32_t iVIndent, int32_t iIndexX)
400  {
401  // bounds by topright corner of element
402  C4Rect rtBounds = (GetContainer() != this) ? GetClientRect() : GetContainedClientRect();
403  rtBounds.x += rtBounds.Wdt - (iWidth + iHIndent) * (iIndexX + 1);
404  rtBounds.y += iVIndent;
405  rtBounds.Wdt = rtBounds.Hgt = iHeight;
406  return rtBounds;
407  }
408 
409  void Element::SetToolTip(const char *szNewTooltip, bool is_immediate)
410  {
411  // store tooltip
412  if (szNewTooltip) ToolTip.Copy(szNewTooltip); else ToolTip.Clear();
413  // store immediate flag
414  is_immediate_tooltip = is_immediate;
415  }
416 
418  {
419  if (!pContextHandler) return false;
420  return pContextHandler->OnContext(this, rcBounds.Wdt/2, rcBounds.Hgt/2);
421  }
422 
423  const char *Element::GetToolTip()
424  {
425  // fallback to parent tooltip, if own is not assigned
426  return (!pParent || !ToolTip.isNull()) ? ToolTip.getData() : pParent->GetToolTip();
427  }
428 
430  {
431  // fallback to parent context, if own is not assigned
433  }
434 
435  bool Element::IsInActiveDlg(bool fForKeyboard)
436  {
437  // get dlg
438  Dialog *pDlg=GetDlg();
439  if (!pDlg) return false;
440  // check if dlg is active
441  return pDlg->IsActive(fForKeyboard);
442  }
443 
444 
445 // --------------------------------------------------
446 // CMouse
447 
448  CMouse::CMouse(int32_t iX, int32_t iY) : fActive(true), fActiveInput(false)
449  {
450  // set pos
451  x=iX; y=iY;
452  // reset fields
453  LDown=MDown=RDown=false;
454  dwKeys=0;
456  pDragElement = nullptr;
458  // LDownX/Y initialized upon need
459  }
460 
461  CMouse::~CMouse() = default;
462 
463  void CMouse::Input(int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyParam)
464  {
465  // pos changed or click issued?
466  if (iButton || iX!=x || iY!=y)
467  {
468  // then hide tooltips for a while
470  // and mark as active input device
471  fActiveInput = true;
472  }
473  // copy fields
474  x=iX; y=iY; dwKeys=dwKeyParam;
475  // update buttons
476  switch (iButton)
477  {
478  case C4MC_Button_LeftDown: LDown=true; LDownX=x; LDownY=y; break;
479  case C4MC_Button_LeftUp: LDown=false; break;
480  case C4MC_Button_RightDown: RDown=true; break;
481  case C4MC_Button_RightUp: RDown=false; break;
482  }
483  }
484 
485  void CMouse::Draw(C4TargetFacet &cgo, TooltipShowState draw_tool_tips)
486  {
487  // only if owned
488  if (!fActive) return;
489 
490  // Make sure to draw the cursor without zoom.
491  ZoomData GuiZoom;
492  pDraw->GetZoom(&GuiZoom);
493  const float oldZoom = GuiZoom.Zoom;
494  GuiZoom.Zoom = 1.0;
495  pDraw->SetZoom(GuiZoom);
496 
497  int32_t iOffsetX = -GfxR->fctMouseCursor.Wdt/2;
498  int32_t iOffsetY = -GfxR->fctMouseCursor.Hgt/2;
499  GfxR->fctMouseCursor.Draw(cgo.Surface,x+iOffsetX,y+iOffsetY,0);
500  // ToolTip
501  if (pMouseOverElement && draw_tool_tips != TTST_None)
502  {
503  if (draw_tool_tips == TTST_All || pMouseOverElement->IsImmediateToolTip())
504  {
505  const char *szTip = pMouseOverElement->GetToolTip();
506  if (szTip && *szTip)
507  {
508  C4TargetFacet cgoTip; cgoTip.Set(cgo.Surface, cgo.X, cgo.Y, cgo.Wdt, cgo.Hgt);
509  Screen::DrawToolTip(szTip, cgoTip, x, y);
510  }
511  }
512  }
513 
514  // And restore old zoom settings.
515  GuiZoom.Zoom = oldZoom;
516  pDraw->SetZoom(GuiZoom);
517  }
518 
520  {
521  // release MouseOver
523  // release drag
524  if (pDragElement)
525  {
526  int32_t iX, iY; DWORD dwKeys;
527  GetLastXY(iX, iY, dwKeys);
529  pDragElement->StopDragging(*this, iX, iY, dwKeys);
530  }
532  }
533 
535  {
536  // clear ptr
537  if (pMouseOverElement == pChild)
538  {
539  pMouseOverElement->MouseLeave(*this); // do leave callback so any tooltip is cleared!
540  pMouseOverElement = nullptr;
541  }
542  if (pPrevMouseOverElement == pChild) pPrevMouseOverElement = nullptr;
543  if (pDragElement == pChild) pDragElement = nullptr;
544  }
545 
547  {
548  // clear ptr
549  RemoveElement(pChild);
550  }
551 
552 
553 // --------------------------------------------------
554 // Screen
555 
557  {
558  // inherited
559  Window::RemoveElement(pChild);
560  // clear ptrs
561  if (pActiveDlg == pChild) { pActiveDlg = nullptr; Mouse.ResetElements(); }
562  Mouse.RemoveElement(pChild);
563  if (pContext)
564  {
565  if (pContext == pChild) pContext=nullptr;
566  else pContext->RemoveElement(pChild);
567  }
568  }
569 
570  Screen::Screen() : Window(), Mouse(0, 0)
571  {
572  // no dialog active
573  pActiveDlg = nullptr;
574  // set static var
575  pScreen = this;
576  }
577 
578  void Screen::Init(int32_t tx, int32_t ty, int32_t twdt, int32_t thgt)
579  {
580  Mouse.x = tx+twdt/2;
581  Mouse.y = ty+thgt/2;
582  fZoom = 1.0f;
583  // set size - calcs client area as well
584  SetBounds(C4Rect(tx,ty,twdt,thgt));
585  SetPreferredDlgRect(C4Rect(0,0,twdt,thgt));
586  }
587 
589  {
591  // dtor: Close context menu
592  AbortContext(false);
593  // fields reset
594  fExclusive = true;
595  fZoom = 1.0f;
596  }
597 
599  {
600  // clear singleton
601  if (this == pScreen) pScreen = nullptr;
602  }
603 
605  {
606  // redraw fullscreen BG if dlgs are dragged around in shared mode
607  if (!IsExclusive())
609  }
610 
611  void Screen::ShowDialog(Dialog *pDlg, bool fFade)
612  {
613  assert(pDlg);
614  // do place console mode dialogs
615  if (!Application.isEditor || pDlg->IsViewportDialog())
616  // exclusive or free dlg: center pos
617  // evaluate own placement proc first
618  if (!pDlg->DoPlacement(this, PreferredDlgRect))
619  {
620  if (pDlg->IsFreePlaceDialog())
621  pDlg->SetPos((GetWidth() - pDlg->GetWidth()) / 2, (GetHeight() - pDlg->GetHeight()) / 2 + pDlg->IsBottomPlacementDialog()*GetHeight()/3);
622  else if (IsExclusive())
623  pDlg->SetPos((GetWidth() - pDlg->GetWidth()) / 2, (GetHeight() - pDlg->GetHeight()) / 2);
624  else
625  // non-exclusive mode at preferred viewport pos
627  }
628  // add to local component list at correct ordering
629  int32_t iNewZ = pDlg->GetZOrdering(); Element *pEl; Dialog *pOtherDlg;
630  for (pEl = GetFirst(); pEl; pEl = pEl->GetNext())
631  if ((pOtherDlg = pEl->GetDlg()))
632  if (pOtherDlg->GetZOrdering() > iNewZ)
633  break;
634  InsertElement(pDlg, pEl);
635  // set as active, if not fading and on top
636  if (!fFade && !pEl)
637  // but not viewport dialogs!
638  if (!pDlg->IsExternalDrawDialog())
639  pActiveDlg = pDlg;
640  // show it
641  pDlg->fOK = false;
642  pDlg->fShow = true;
643  // mouse focus might have changed
645  }
646 
648  {
649  // no change?
650  if (pActiveDlg == pDlg) return;
651  // in single-mode: release any MouseOver/Drag of previous dlg
652  if (IsExclusive())
654  // close any context menu
655  AbortContext(false);
656  // set as active dlg
657  pActiveDlg = pDlg;
658  // ensure it's last in the list, if it's not a specially ordered dlg
659  if (!pDlg->GetZOrdering() && pDlg->GetNext())
660  MakeLastElement(pDlg);
661  }
662 
663  void Screen::CloseDialog(Dialog *pDlg, bool fFade)
664  {
665  // hide dlg
666  if (!fFade) pDlg->fShow = false;
667  // kill from active
668  if (pActiveDlg == pDlg)
669  {
670  // release any MouseOver/Drag of previous dlg
672  // close context menu: probably belonging to closed dlg anyway
673  AbortContext(false);
674  // set new active dlg
676  // do not set yet if it's fading
677  if (pActiveDlg && pActiveDlg->IsFading()) pActiveDlg = nullptr;
678  }
679  // redraw background; clip update
681  }
682 
684  {
685  Dialog *pNewTop = GetTopDialog();
686  if (pActiveDlg == pNewTop) return;
688  // do not set yet if it's fading
689  if (pActiveDlg && pActiveDlg->IsFading()) pActiveDlg = nullptr;
690  }
691 
693  {
694  // search backwards in component list
695  Dialog *pDlg;
696  for (Element *pEl = pLast; pEl; pEl = pEl->GetPrev())
697  if ((pDlg = pEl->GetDlg()))
698  if (pDlg->IsShown())
699  return pDlg;
700  // no dlg found
701  return nullptr;
702  }
703 
704  void Screen::CloseAllDialogs(bool fWithOK)
705  {
706  while (pActiveDlg) pActiveDlg->Close(fWithOK);
707  }
708 #ifdef USE_WIN32_WINDOWS
709  Dialog *Screen::GetDialog(HWND hWindow)
710  {
711  // get dialog with matching handle
712  Dialog *pDlg;
713  for (Element *pEl = pLast; pEl; pEl = pEl->GetPrev())
714  if ((pDlg = pEl->GetDlg()))
715  if (pDlg->pWindow && pDlg->pWindow->hWindow == hWindow)
716  return pDlg;
717  return nullptr;
718  }
719 #endif
721  {
722  // get dialog with matching window
723  Dialog *pDlg;
724  for (Element *pEl = pLast; pEl; pEl = pEl->GetPrev())
725  if ( (pDlg = pEl->GetDlg()) != nullptr)
726  if (pDlg->pWindow == pWindow)
727  return pDlg;
728  return nullptr;
729  }
730  void Screen::Render(bool fDoBG)
731  {
732  // get output cgo
733  C4TargetFacet cgo;
735  // draw to it
736  Draw(cgo, fDoBG);
737  }
738 
740  {
741  // draw mouse cursor
742  // All tool tips hidden during keyboard input. Immediate tooltips hidden if mouse was moving recently.
744  }
745 
746  void Screen::Draw(C4TargetFacet &cgo, bool fDoBG)
747  {
748  // draw bg, if this won't be done by a fullscreen dialog
749  if (fDoBG)
750  {
751  Dialog *pFSDlg = GetFullscreenDialog(false);
752  if (!pFSDlg || !pFSDlg->HasBackground())
753  {
755  ::GraphicsSystem.pLoaderScreen->Draw(cgo, C4LoaderScreen::Flag::BACKGROUND);
756  else
757  // loader not yet loaded: black BG
758  pDraw->DrawBoxDw(cgo.Surface, 0,0, cgo.Wdt+1, cgo.Hgt+1, 0x00000000);
759  }
760  }
761  // draw contents (if GUI-gfx are loaded, which is assumed in GUI-drawing-functions)
763  {
764  Window::Draw(cgo);
765  if (pContext) pContext->Draw(cgo);
766  }
767  // draw mouse cursor
768  if (!Application.isEditor) RenderMouse(cgo);
769  }
770 
772  {
773  // mark keystroke in mouse
775  // key not yet processed
776  return false;
777  }
778 
779  bool Screen::CharIn(const char * c)
780  {
781  // Special: Tab chars are ignored, because they are always handled as focus advance
782  if (c[0] == 0x09) return false;
783  // mark in mouse
785  // no processing if focus is not set
786  if (!HasKeyboardFocus()) return false;
787  // always return true in exclusive mode (which means: key processed)
788  bool fResult = IsExclusive();
789  // context menu: forward to context
790  if (pContext) return pContext->CharIn(c) || fResult;
791  // no active dlg?
792  if (!pActiveDlg || !pActiveDlg->IsVisible()) return fResult;
793  // forward to dialog
794  return pActiveDlg->CharIn(c) || fResult;
795  }
796 
797  void Screen::MouseMove(int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyParam, class C4Viewport *pVP)
798  {
799  // Special: Pass to MouseControl if dragging and button is not upped
800  if (IsActive() && !::MouseControl.IsDragging())
801  {
802  bool fResult = MouseInput(iButton, iX, iY, dwKeyParam, nullptr, pVP);
803  if (HasMouseFocus()) { SetMouseInGUI(true, true); return; }
804  // non-exclusive GUI: inform mouse-control about GUI-result
805  SetMouseInGUI(fResult, true);
806  // abort if GUI processed it
807  if (fResult) return;
808  }
809  else
810  // no GUI: mouse is not in GUI
811  SetMouseInGUI(false, true);
812  // mouse control enabled?
813  if (!::MouseControl.IsActive())
814  {
815  // enable mouse in GUI, if a mouse-only-dlg is displayed
817  SetMouseInGUI(true, true);
818  return;
819  }
820  // Pass on to mouse controlled viewport
821  ::Viewports.MouseMoveToViewport(iButton, iX, iY, dwKeyParam);
822  }
823 
824  void Screen::SetMouseInGUI(bool fInGUI, bool fByMouse)
825  {
826  // inform mouse control and GUI
827  Mouse.SetOwnedMouse(fInGUI);
828  // initial movement to ensure mouse control pos is correct
829  if (!::MouseControl.IsMouseOwned() && !fInGUI && !fByMouse)
830  {
833  }
834  ::MouseControl.SetOwnedMouse(!fInGUI);
835  }
836 
837  bool Screen::MouseInput(int32_t iButton, int32_t iPxX, int32_t iPxY, DWORD dwKeyParam, Dialog *pForDlg, class C4Viewport *pForVP)
838  {
839  // convert from screen pixel coordinates to GUI coordinates
840  float fZoom = pForDlg ? 1.0f : GetZoom(); // Developer mode dialogs are currently drawn unzoomed
841  float fX = float(iPxX) / fZoom;
842  float fY = float(iPxY) / fZoom;
843  // forward to mouse
844  Mouse.Input(iButton, fX, fY, dwKeyParam);
845 
846  // dragging
847  if (Mouse.pDragElement)
848  {
849  int32_t iX2=fX, iY2=fY;
851  if (!Mouse.IsLDown())
852  {
853  // stop dragging
854  Mouse.pDragElement->StopDragging(Mouse, iX2, iY2, dwKeyParam);
855  Mouse.pDragElement = nullptr;
856  }
857  else
858  {
859  // continue dragging
860  Mouse.pDragElement->DoDragging(Mouse, iX2, iY2, dwKeyParam);
861  }
862  }
863  // backup previous MouseOver-element
865  Mouse.pMouseOverElement = nullptr;
866  bool fProcessed = false;
867  // active context menu?
868  if (!pForVP && pContext && pContext->CtxMouseInput(Mouse, iButton, fX, fY, dwKeyParam))
869  {
870  // processed by context menu: OK!
871  }
872  // otherwise: active dlg and inside screen? (or direct forward to specific dlg/viewport dlg)
873  else if (rcBounds.Contains(fX, fY) || pForDlg || pForVP)
874  {
875  // context menu open but mouse down command issued? close context then
876  if (pContext && (iButton == C4MC_Button_LeftDown || iButton == C4MC_Button_RightDown))
877  AbortContext(true);
878  // get client pos
879  if (!pForDlg && !pForVP)
880  {
881  C4Rect &rcClientArea = GetClientRect();
882  fX -= rcClientArea.x; fY -= rcClientArea.y;
883  }
884  // exclusive mode: process active dialog only
885  if (IsExclusive() && !pForDlg && !pForVP)
886  {
888  {
889  // bounds check to dlg: only if not dragging
890  C4Rect &rcDlgBounds = pActiveDlg->GetBounds();
891  if (Mouse.IsLDown() || rcDlgBounds.Contains(fX, fY))
892  // forward to active dialog
893  pActiveDlg->MouseInput(Mouse, iButton, fX - rcDlgBounds.x, fY - rcDlgBounds.y, dwKeyParam);
894  else
895  Mouse.pMouseOverElement = nullptr;
896  }
897  else
898  // outside dialog: own handling (for screen context menu)
899  Window::MouseInput(Mouse, iButton, fX, fY, dwKeyParam);
900  }
901  else
902  {
903  // non-exclusive mode: process all dialogs; make them active on left-click
904  Dialog *pDlg;
905  for (Element *pEl = pLast; pEl; pEl = pEl->GetPrev())
906  if ((pDlg = pEl->GetDlg()))
907  if (pDlg->IsShown())
908  {
909  // if specified: process specified dlg only
910  if (pForDlg && pDlg != pForDlg) continue;
911  // if specified: process specified viewport only
912  bool fIsExternalDrawDialog = pDlg->IsExternalDrawDialog();
913  C4Viewport *pVP = fIsExternalDrawDialog ? pDlg->GetViewport() : nullptr;
914  if (pForVP && pForVP != pVP) continue;
915  // calc offset
916  C4Rect &rcDlgBounds = pDlg->GetBounds();
917  int32_t iOffX=0, iOffY=0;
918  // special handling for viewport dialogs
919  if (fIsExternalDrawDialog)
920  {
921  // ignore external drawing dialogs without a viepwort assigned
922  if (!pVP) continue;
923  // always clip to viewport bounds
924  C4Rect rcOut(pVP->GetOutputRect());
925  if (!rcOut.Contains(fX + rcBounds.x, fY + rcBounds.y)) continue;
926  // viewport dialogs: Offset determined by viewport position
927  iOffX = rcOut.x; iOffY = rcOut.y;
928  }
929  // hit test; or special: dragging possible outside active dialog
930  if (rcDlgBounds.Contains(fX-iOffX, fY-iOffY) || (pDlg == pActiveDlg && Mouse.pDragElement && Mouse.pDragElement->GetDlg() == pDlg))
931  {
932  // Okay; do input
933  pDlg->MouseInput(Mouse, iButton, fX - rcDlgBounds.x - iOffX, fY - rcDlgBounds.y - iOffY, dwKeyParam);
934  // CAUTION: pDlg may be invalid now!
935  // set processed-flag manually
936  fProcessed = true;
937  // inactive dialogs get activated by clicks
938  if (Mouse.IsLDown() && pDlg != pActiveDlg)
939  // but not viewport dialogs!
940  if (!pDlg->IsExternalDrawDialog())
941  ActivateDialog(pDlg);
942  // one dlg only; break loop here
943  break;
944  }
945  }
946  }
947  }
948 
949  // check if MouseOver has changed
951  {
952  // send events
955  }
956  // return whether anything processed it
957  return fProcessed || Mouse.pDragElement || (Mouse.pMouseOverElement && Mouse.pMouseOverElement!=this) || pContext;
958  }
959 
961  {
962  return MouseInput(C4MC_Button_None, Mouse.x, Mouse.y, Mouse.dwKeys, nullptr, nullptr);
963  }
964 
966  {
967  // when exclusive mode has changed: Make sure mouse clip is correct
969  }
970 
971  void Screen::DoContext(ContextMenu *pNewCtx, Element *pAtElement, int32_t iX, int32_t iY)
972  {
973  assert(pNewCtx); assert(pNewCtx != pContext);
974  // close previous context menu
975  AbortContext(false);
976  // element offset
977  if (pAtElement) pAtElement->ClientPos2ScreenPos(iX, iY);
978  // usually open bottom right
979  // check bottom bounds
980  if (iY + pNewCtx->GetBounds().Hgt >= GetBounds().Hgt)
981  {
982  // bottom too narrow: open to top, if height is sufficient
983  // otherwise, open to top from bottom screen pos
984  if (iY < pNewCtx->GetBounds().Hgt) iY = GetBounds().Hgt;
985  iY -= pNewCtx->GetBounds().Hgt;
986  }
987  // check right bounds likewise
988  if (iX + pNewCtx->GetBounds().Wdt >= GetBounds().Wdt)
989  {
990  // bottom too narrow: open to top, if height is sufficient
991  // otherwise, open to top from bottom screen pos
992  if (iX < pNewCtx->GetBounds().Wdt) iX = GetBounds().Wdt;
993  iX -= pNewCtx->GetBounds().Wdt;
994  }
995  // open new
996  (pContext = pNewCtx)->Open(pAtElement, iX, iY);
997  }
998 
1000  {
1001  Dialog *pDlg; int32_t iResult=0;
1002  for (Element *pEl = GetFirst(); pEl; pEl = pEl->GetNext())
1003  if ((pDlg = pEl->GetDlg()))
1004  if (pDlg->IsShown() && pDlg->IsMouseControlled())
1005  ++iResult;
1006  return iResult;
1007  }
1008 
1009  void Screen::DrawToolTip(const char *szTip, C4TargetFacet &cgo, float x, float y)
1010  {
1011  CStdFont *pUseFont = &(::GraphicsResource.TooltipFont);
1012  StdStrBuf sText;
1013  pUseFont->BreakMessage(szTip, std::min<int32_t>(C4GUI_MaxToolTipWdt, std::max<int32_t>(cgo.Wdt, 50)), &sText, true);
1014  // get tooltip rect
1015  int32_t tWdt,tHgt;
1016  if (pUseFont->GetTextExtent(sText.getData(), tWdt, tHgt, true))
1017  {
1018  tWdt+=6; tHgt+=4;
1019  int32_t tX, tY;
1020  if (y < cgo.Y+cgo.TargetY+tHgt+5) tY = std::min<int32_t>(y+5, cgo.TargetY+cgo.Hgt-tHgt); else tY = y-tHgt-5;
1021  tX = Clamp<int32_t>(x-tWdt/2, cgo.TargetX+cgo.X, cgo.TargetX+cgo.Wdt-tWdt);
1022  // draw tooltip box
1023  pDraw->DrawBoxDw(cgo.Surface, tX,tY,tX+tWdt-1,tY+tHgt-2, C4GUI_ToolTipBGColor);
1024  pDraw->DrawFrameDw(cgo.Surface, tX,tY,tX+tWdt-1,tY+tHgt-1, C4GUI_ToolTipFrameColor);
1025  // draw tooltip
1026  pDraw->TextOut(sText.getData(), *pUseFont, 1.0f, cgo.Surface, tX+3,tY+1, C4GUI_ToolTipColor, ALeft);
1027  // while there's a tooltip, redraw the bg, because it might overlap
1029  }
1030  }
1031 
1032  bool Screen::HasFullscreenDialog(bool fIncludeFading)
1033  {
1034  return !!GetFullscreenDialog(fIncludeFading);
1035  }
1036 
1037  Dialog *Screen::GetFullscreenDialog(bool fIncludeFading)
1038  {
1039  Dialog *pDlg;
1040  for (Element *pEl = GetFirst(); pEl; pEl = pEl->GetNext())
1041  if ((pDlg = pEl->GetDlg()))
1042  if (pDlg->IsVisible())
1043  if (pDlg->IsFullscreenDialog())
1044  if (fIncludeFading || !pDlg->IsFading())
1045  return pDlg;
1046  return nullptr;
1047  }
1048 
1050  {
1051  // Gamepad is always kept open now.
1052  }
1053 
1055 
1056 // --------------------------------------------------
1057 // ComponentAligner
1058 
1059  bool ComponentAligner::GetFromTop(int32_t iHgt, int32_t iWdt, C4Rect &rcOut)
1060  {
1061  rcOut.x = rcClientArea.x + iMarginX;
1062  rcOut.y = rcClientArea.y + iMarginY;
1063  rcOut.Wdt = rcClientArea.Wdt - iMarginX * 2;
1064  rcOut.Hgt = iHgt;
1065  int32_t d = iHgt + iMarginY * 2;
1066  rcClientArea.y += d; rcClientArea.Hgt -= d;
1067  // get centered in width as specified
1068  if (iWdt >= 0)
1069  {
1070  rcOut.x += (rcOut.Wdt - iWdt) / 2;
1071  rcOut.Wdt = iWdt;
1072  }
1073  return rcClientArea.Hgt >= 0;
1074  }
1075 
1076  bool ComponentAligner::GetFromLeft(int32_t iWdt, int32_t iHgt, C4Rect &rcOut)
1077  {
1078  rcOut.x = rcClientArea.x + iMarginX;
1079  rcOut.y = rcClientArea.y + iMarginY;
1080  rcOut.Wdt = iWdt;
1081  rcOut.Hgt = rcClientArea.Hgt - iMarginY * 2;
1082  int32_t d = iWdt + iMarginX * 2;
1083  rcClientArea.x += d; rcClientArea.Wdt -= d;
1084  // get centered in height as specified
1085  if (iHgt >= 0)
1086  {
1087  rcOut.y += (rcOut.Hgt - iHgt) / 2;
1088  rcOut.Hgt = iHgt;
1089  }
1090  return rcClientArea.Wdt >= 0;
1091  }
1092 
1093  bool ComponentAligner::GetFromRight(int32_t iWdt, int32_t iHgt, C4Rect &rcOut)
1094  {
1095  rcOut.x = rcClientArea.x + rcClientArea.Wdt - iWdt - iMarginX;
1096  rcOut.y = rcClientArea.y + iMarginY;
1097  rcOut.Wdt = iWdt;
1098  rcOut.Hgt = rcClientArea.Hgt - iMarginY * 2;
1099  rcClientArea.Wdt -= iWdt + iMarginX * 2;
1100  // get centered in height as specified
1101  if (iHgt >= 0)
1102  {
1103  rcOut.y += (rcOut.Hgt - iHgt) / 2;
1104  rcOut.Hgt = iHgt;
1105  }
1106  return rcClientArea.Wdt >= 0;
1107  }
1108 
1109  bool ComponentAligner::GetFromBottom(int32_t iHgt, int32_t iWdt, C4Rect &rcOut)
1110  {
1111  rcOut.x = rcClientArea.x + iMarginX;
1112  rcOut.y = rcClientArea.y + rcClientArea.Hgt - iHgt - iMarginY;
1113  rcOut.Wdt = rcClientArea.Wdt - iMarginX * 2;
1114  rcOut.Hgt = iHgt;
1115  rcClientArea.Hgt -= iHgt + iMarginY * 2;
1116  // get centered in width as specified
1117  if (iWdt >= 0)
1118  {
1119  rcOut.x += (rcOut.Wdt - iWdt) / 2;
1120  rcOut.Wdt = iWdt;
1121  }
1122  return rcClientArea.Hgt >= 0;
1123  }
1124 
1126  {
1127  rcOut.x = rcClientArea.x + iMarginX;
1128  rcOut.y = rcClientArea.y + iMarginY;
1129  rcOut.Wdt = rcClientArea.Wdt - iMarginX * 2;
1130  rcOut.Hgt = rcClientArea.Hgt - iMarginY * 2;
1131  }
1132 
1133  bool ComponentAligner::GetCentered(int32_t iWdt, int32_t iHgt, C4Rect &rcOut)
1134  {
1135  rcOut.x = rcClientArea.GetMiddleX() - iWdt/2;
1136  rcOut.y = rcClientArea.GetMiddleY() - iHgt/2;
1137  rcOut.Wdt = iWdt;
1138  rcOut.Hgt = iHgt;
1139  // range check
1140  return rcOut.Wdt+iMarginX*2 <= rcClientArea.Wdt && rcOut.Hgt+iMarginY*2 <= rcClientArea.Hgt;
1141  }
1142 
1143  void ComponentAligner::LogIt(const char *szName)
1144  {
1145  LogF("ComponentAligner %s: (%d,%d)+(%d,%d), Margin (%d,%d)", szName, rcClientArea.x, rcClientArea.y, rcClientArea.Wdt, rcClientArea.Hgt, iMarginX, iMarginY);
1146  }
1147 
1148  C4Rect &ComponentAligner::GetGridCell(int32_t iSectX, int32_t iSectXMax, int32_t iSectY, int32_t iSectYMax, int32_t iSectSizeX, int32_t iSectSizeY, bool fCenterPos, int32_t iSectNumX, int32_t iSectNumY)
1149  {
1150  int32_t iSectSizeXO = iSectSizeX, iSectSizeYO = iSectSizeY;
1151  int32_t iSectSizeXMax = (rcClientArea.Wdt-iMarginX) / iSectXMax - iMarginX;
1152  int32_t iSectSizeYMax = (rcClientArea.Hgt-iMarginY) / iSectYMax - iMarginY;
1153  if (iSectSizeX<0 || fCenterPos) iSectSizeX=iSectSizeXMax; else iSectSizeX=std::min<int32_t>(iSectSizeX, iSectSizeXMax);
1154  if (iSectSizeY<0 || fCenterPos) iSectSizeY=iSectSizeYMax; else iSectSizeY=std::min<int32_t>(iSectSizeY, iSectSizeYMax);
1155  rcTemp.x = iSectX * (iSectSizeX+iMarginX) + iMarginX + rcClientArea.x;
1156  rcTemp.y = iSectY * (iSectSizeY+iMarginY) + iMarginY + rcClientArea.y;
1157  rcTemp.Wdt = iSectSizeX * iSectNumX + iMarginX*(iSectNumX-1); rcTemp.Hgt = iSectSizeY * iSectNumY + iMarginY*(iSectNumY-1);
1158  if (iSectSizeXO>=0 && fCenterPos)
1159  {
1160  rcTemp.x += (iSectSizeX - iSectSizeXO)/2;
1161  rcTemp.Wdt = iSectSizeXO;
1162  }
1163  if (iSectSizeYO>=0 && fCenterPos)
1164  {
1165  rcTemp.y += (iSectSizeY - iSectSizeYO)/2;
1166  rcTemp.Hgt = iSectSizeYO;
1167  }
1168  return rcTemp;
1169  }
1170 
1171 
1172 // --------------------------------------------------
1173 // Global stuff
1174 
1175  void GUISound(const char *szSound)
1176  {
1177  if (Config.Sound.FESamples)
1178  StartSoundEffect(szSound);
1179  }
1180 
1181 
1182 // --------------------------------------------------
1183 // Static vars
1184 
1186  Screen *Screen::pScreen;
1187 
1188 
1189 } // end of namespace
1190 
C4Config Config
Definition: C4Config.cpp:930
C4Draw * pDraw
Definition: C4Draw.cpp:42
C4Application Application
Definition: C4Globals.cpp:44
C4MouseControl MouseControl
Definition: C4Globals.cpp:47
C4FullScreen FullScreen
Definition: C4Globals.cpp:46
C4GraphicsSystem GraphicsSystem
Definition: C4Globals.cpp:51
C4GraphicsResource GraphicsResource
#define GfxR
int iResult
Definition: C4GroupMain.cpp:40
C4GUIScreen * pGUI
Definition: C4Gui.cpp:1191
#define C4GUI_ToolTipBGColor
Definition: C4Gui.h:72
#define C4GUI_ToolTipColor
Definition: C4Gui.h:74
#define C4GUI_ToolTipFrameColor
Definition: C4Gui.h:73
#define C4GUI_MaxToolTipWdt
Definition: C4Gui.h:140
#define C4GUI_BorderColor2
Definition: C4Gui.h:86
#define C4GUI_BorderColor1
Definition: C4Gui.h:85
#define C4GUI_BorderColor3
Definition: C4Gui.h:87
const char * LoadResStr(const char *id)
Definition: C4Language.h:83
bool LogF(const char *strMessage,...)
Definition: C4Log.cpp:262
#define b
const int32_t C4MC_Button_None
const int32_t C4MC_Button_RightDown
const int32_t C4MC_Button_RightUp
const int32_t C4MC_Button_LeftUp
const int32_t C4MC_Button_LeftDown
C4SoundInstance * StartSoundEffect(const char *szSndName, bool fLoop, int32_t iVolume, C4Object *pObj, int32_t iCustomFalloffDistance, int32_t iPitch, C4SoundModifier *modifier)
const int ALeft
Definition: C4Surface.h:41
C4ViewportList Viewports
uint8_t BYTE
uint32_t DWORD
uint32_t GetNextCharacter(const char **pszString)
Definition: Standard.h:84
bool Inside(T ival, U lbound, V rbound)
Definition: Standard.h:43
void SetRotate(float iAngle, float fOffX, float fOffY)
C4ConfigSound Sound
Definition: C4Config.h:258
int32_t FESamples
Definition: C4Config.h:129
void DrawFrameDw(C4Surface *sfcDest, int x1, int y1, int x2, int y2, DWORD dwClr, float width=1.0f)
Definition: C4Draw.cpp:635
void GetZoom(ZoomData *r)
Definition: C4Draw.h:197
void DrawBoxDw(C4Surface *sfcDest, int iX1, int iY1, int iX2, int iY2, DWORD dwClr)
Definition: C4Draw.cpp:840
void DrawLineDw(C4Surface *sfcTarget, float x1, float y1, float x2, float y2, DWORD dwClr, float width=1.0f)
Definition: C4Draw.cpp:608
void SetZoom(float X, float Y, float Zoom)
Definition: C4Draw.cpp:773
bool TextOut(const char *szText, CStdFont &rFont, float fZoom, C4Surface *sfcDest, float iTx, float iTy, DWORD dwFCol=0xffffffff, BYTE byForm=ALeft, bool fDoMarkup=true)
Definition: C4Draw.cpp:561
void Set(C4Surface &rSfc)
Definition: C4Facet.cpp:459
void DrawT(C4Surface *sfcTarget, float iX, float iY, int32_t iPhaseX, int32_t iPhaseY, C4DrawTransform *pTransform)
Definition: C4Facet.cpp:76
C4Surface * Surface
Definition: C4Facet.h:117
float Hgt
Definition: C4Facet.h:118
float Wdt
Definition: C4Facet.h:118
void Draw(C4Facet &cgo, bool fAspect=true, int32_t iPhaseX=0, int32_t iPhaseY=0, bool fTransparent=true)
Definition: C4Facet.cpp:154
void DrawX(C4Surface *sfcTarget, float iX, float iY, float iWdt, float iHgt, int32_t iPhaseX=0, int32_t iPhaseY=0) const
Definition: C4Facet.cpp:358
float Y
Definition: C4Facet.h:118
float X
Definition: C4Facet.h:118
bool IsActiveInput()
Definition: C4Gui.h:2581
bool LDown
Definition: C4Gui.h:2536
bool fActive
Definition: C4Gui.h:2539
bool IsLDown()
Definition: C4Gui.h:2565
bool MDown
Definition: C4Gui.h:2536
void ResetToolTipTime()
Definition: C4Gui.h:2578
void ReleaseElements()
Definition: C4Gui.cpp:519
@ TTST_Immediate
Definition: C4Gui.h:2550
int32_t LDownX
Definition: C4Gui.h:2537
void ResetElements()
Definition: C4Gui.h:2569
void Input(int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyParam)
Definition: C4Gui.cpp:463
Element * pMouseOverElement
Definition: C4Gui.h:2555
Element * pDragElement
Definition: C4Gui.h:2556
int32_t y
Definition: C4Gui.h:2535
void OnElementGetsInvisible(Element *pChild)
Definition: C4Gui.cpp:546
Element * pPrevMouseOverElement
Definition: C4Gui.h:2555
void ResetActiveInput()
Definition: C4Gui.h:2580
int32_t LDownY
Definition: C4Gui.h:2537
void Draw(C4TargetFacet &cgo, TooltipShowState draw_tool_tips)
Definition: C4Gui.cpp:485
void RemoveElement(Element *pChild)
Definition: C4Gui.cpp:534
int32_t x
Definition: C4Gui.h:2535
CMouse(int32_t iX, int32_t iY)
Definition: C4Gui.cpp:448
bool IsMouseStill()
Definition: C4Gui.h:2579
bool fActiveInput
Definition: C4Gui.h:2545
bool RDown
Definition: C4Gui.h:2536
void SetOwnedMouse(bool fToVal)
Definition: C4Gui.h:2576
DWORD dwKeys
Definition: C4Gui.h:2538
void GetLastXY(int32_t &rX, int32_t &rY, DWORD &rdwKeys)
Definition: C4Gui.h:2567
bool GetFromLeft(int32_t iWdt, int32_t iHgt, C4Rect &rcOut)
Definition: C4Gui.cpp:1076
static C4Rect rcTemp
Definition: C4Gui.h:2780
C4Rect & GetAll()
Definition: C4Gui.h:2798
bool GetCentered(int32_t iWdt, int32_t iHgt, C4Rect &rcOut)
Definition: C4Gui.cpp:1133
bool GetFromRight(int32_t iWdt, int32_t iHgt, C4Rect &rcOut)
Definition: C4Gui.cpp:1093
bool GetFromTop(int32_t iHgt, int32_t iWdt, C4Rect &rcOut)
Definition: C4Gui.cpp:1059
void LogIt(const char *szName)
Definition: C4Gui.cpp:1143
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)
Definition: C4Gui.cpp:1148
bool GetFromBottom(int32_t iHgt, int32_t iWdt, C4Rect &rcOut)
Definition: C4Gui.cpp:1109
void RemoveElement(Element *pChild) override
virtual void ElementPosChanged(Element *pOfElement)
Definition: C4Gui.h:754
virtual void ElementSizeChanged(Element *pOfElement)
Definition: C4Gui.h:753
void MakeLastElement(Element *pChild)
Element * pLast
Definition: C4Gui.h:750
Element * GetFirst()
Definition: C4Gui.h:829
void InsertElement(Element *pChild, Element *pInsertBefore)
virtual void ApplyInvElementOffset(int32_t &riX, int32_t &riY)
Definition: C4Gui.h:841
virtual void ApplyElementOffset(int32_t &riX, int32_t &riY)
Definition: C4Gui.h:840
virtual bool OnContext(Element *pOnElement, int32_t iX, int32_t iY)=0
void Draw(C4TargetFacet &cgo) override
Definition: C4GuiMenu.cpp:460
void RemoveElement(Element *pChild) override
Definition: C4GuiMenu.cpp:364
virtual bool CharIn(const char *c)
Definition: C4GuiMenu.cpp:453
bool CtxMouseInput(CMouse &rMouse, int32_t iButton, int32_t iScreenX, int32_t iScreenY, DWORD dwKeyParam)
Definition: C4GuiMenu.cpp:441
virtual bool CharIn(const char *c)
bool IsViewportDialog()
Definition: C4Gui.h:2173
virtual C4Viewport * GetViewport()
Definition: C4Gui.h:2172
void MouseInput(CMouse &rMouse, int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyParam) override
bool fShow
Definition: C4Gui.h:2082
void Close(bool fOK)
virtual bool IsBottomPlacementDialog()
Definition: C4Gui.h:2162
bool IsFading()
Definition: C4Gui.h:2152
virtual bool IsFullscreenDialog()
Definition: C4Gui.h:2154
bool IsExternalDrawDialog() override
Definition: C4Gui.h:2179
virtual bool HasBackground()
Definition: C4Gui.h:2155
bool IsShown()
Definition: C4Gui.h:2148
bool IsActive(bool fForKeyboard)
bool fOK
Definition: C4Gui.h:2083
virtual int32_t GetZOrdering()
Definition: C4Gui.h:2182
virtual bool IsMouseControlled()
Definition: C4Gui.h:2169
DialogWindow * pWindow
Definition: C4Gui.h:2089
Dialog * GetDlg() override
Definition: C4Gui.h:2117
virtual bool DoPlacement(Screen *pOnScreen, const C4Rect &rPreferredDlgRect)
Definition: C4Gui.h:2176
virtual bool IsFreePlaceDialog()
Definition: C4Gui.h:2159
bool DoContext()
Definition: C4Gui.cpp:417
Element * GetPrev() const
Definition: C4Gui.h:450
virtual void SetVisibility(bool fToValue)
Definition: C4Gui.cpp:207
bool IsVisible()
Definition: C4Gui.cpp:201
virtual void RemoveElement(Element *pChild)
Definition: C4Gui.cpp:173
C4Rect rcBounds
Definition: C4Gui.h:385
virtual Container * GetContainer()
Definition: C4Gui.h:410
C4Rect GetToprightCornerRect(int32_t iWidth=16, int32_t iHeight=16, int32_t iHIndent=4, int32_t iVIndent=4, int32_t iIndexX=0)
Definition: C4Gui.cpp:399
void DrawVBar(C4TargetFacet &cgo, DynBarFacet &rFacets)
Definition: C4Gui.cpp:359
virtual Screen * GetScreen()
Definition: C4Gui.cpp:289
Element * GetNext() const
Definition: C4Gui.h:449
C4Rect GetContainedClientRect()
Definition: C4Gui.h:448
int32_t iDragY
Definition: C4Gui.h:379
bool IsInActiveDlg(bool fForKeyboard)
Definition: C4Gui.cpp:435
virtual void MouseInput(CMouse &rMouse, int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyParam)
Definition: C4Gui.cpp:244
virtual ~Element()
Definition: C4Gui.cpp:161
virtual void UpdateSize()
Definition: C4Gui.cpp:185
virtual C4Rect & GetClientRect()
Definition: C4Gui.h:447
int32_t GetWidth()
Definition: C4Gui.h:443
void SetBounds(const C4Rect &rcNewBound)
Definition: C4Gui.h:446
virtual void StopDragging(CMouse &rMouse, int32_t iX, int32_t iY, DWORD dwKeyParam)
Definition: C4Gui.cpp:282
virtual ContextHandler * GetContextHandler()
Definition: C4Gui.cpp:429
Container * GetParent()
Definition: C4Gui.h:429
int32_t iDragX
Definition: C4Gui.h:379
void DrawBar(C4TargetFacet &cgo, DynBarFacet &rFacets)
Definition: C4Gui.cpp:308
virtual bool IsMenu()
Definition: C4Gui.h:403
void DrawHBarByVGfx(C4TargetFacet &cgo, DynBarFacet &rFacets)
Definition: C4Gui.cpp:365
virtual void StartDragging(CMouse &rMouse, int32_t iX, int32_t iY, DWORD dwKeyParam)
Definition: C4Gui.cpp:259
virtual void UpdatePos()
Definition: C4Gui.cpp:193
bool fVisible
Definition: C4Gui.h:383
virtual void MouseEnter(CMouse &rMouse)
Definition: C4Gui.h:413
Container * pParent
Definition: C4Gui.h:376
virtual class Dialog * GetDlg()
Definition: C4Gui.cpp:288
void DrawHVBar(C4TargetFacet &cgo, DynBarFacet &rFacets, C4DrawTransform &trf, int32_t iMiddleLength)
Definition: C4Gui.cpp:375
void SetToolTip(const char *szNewTooltip, bool is_immediate=false)
Definition: C4Gui.cpp:409
void ClientPos2ScreenPos(int32_t &riX, int32_t &riY)
Definition: C4Gui.cpp:231
Window * pDragTarget
Definition: C4Gui.h:378
const char * GetToolTip()
Definition: C4Gui.cpp:423
virtual void DoDragging(CMouse &rMouse, int32_t iX, int32_t iY, DWORD dwKeyParam)
Definition: C4Gui.cpp:269
ContextHandler * pContextHandler
Definition: C4Gui.h:381
C4Rect & GetBounds()
Definition: C4Gui.h:445
bool fDragging
Definition: C4Gui.h:380
bool IsImmediateToolTip() const
Definition: C4Gui.h:441
int32_t GetHeight()
Definition: C4Gui.h:444
virtual void MouseLeave(CMouse &rMouse)
Definition: C4Gui.h:414
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)
Definition: C4Gui.cpp:291
virtual void UpdateOwnPos()
Definition: C4Gui.h:434
void ScreenPos2ClientPos(int32_t &riX, int32_t &riY)
Definition: C4Gui.cpp:218
Dialog * GetFullscreenDialog(bool fIncludeFading)
Definition: C4Gui.cpp:1037
static Screen * GetScreenS()
Definition: C4Gui.h:2629
void SetPreferredDlgRect(const C4Rect &rtNewPref)
Definition: C4Gui.h:2651
static void DrawToolTip(const char *szTip, C4TargetFacet &cgo, float guix, float guiy)
Definition: C4Gui.cpp:1009
void UpdateMouseFocus()
Definition: C4Gui.cpp:965
~Screen() override
Definition: C4Gui.cpp:598
void ShowDialog(Dialog *pDlg, bool fFade)
Definition: C4Gui.cpp:611
CMouse Mouse
Definition: C4Gui.h:2590
void RecheckActiveDialog()
Definition: C4Gui.cpp:683
bool HasMouseFocus()
Definition: C4Gui.h:2678
void Clear()
Definition: C4Gui.cpp:588
void Render(bool fDoBG)
Definition: C4Gui.cpp:730
bool RecheckMouseInput()
Definition: C4Gui.cpp:960
virtual bool CharIn(const char *c)
Definition: C4Gui.cpp:779
static Screen * pScreen
Definition: C4Gui.h:2599
void UpdateGamepadGUIControlEnabled()
Definition: C4Gui.cpp:1049
void Init(int32_t tx, int32_t ty, int32_t twdt, int32_t thgt)
Definition: C4Gui.cpp:578
bool fExclusive
Definition: C4Gui.h:2595
bool IsActive()
Definition: C4Gui.h:2633
void MouseInput(CMouse &rMouse, int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyParam) override
void SetMouseInGUI(bool fInGUI, bool fByMouse)
Definition: C4Gui.cpp:824
void RenderMouse(C4TargetFacet &cgo)
Definition: C4Gui.cpp:739
bool HasKeyboardFocus()
Definition: C4Gui.h:2671
void Draw(C4TargetFacet &cgo) override
float GetZoom() const
Definition: C4Gui.h:2631
bool HasFullscreenDialog(bool fIncludeFading)
Definition: C4Gui.cpp:1032
void ActivateDialog(Dialog *pDlg)
Definition: C4Gui.cpp:647
ContextMenu * pContext
Definition: C4Gui.h:2594
Dialog * GetDialog(C4Window *pWindow)
Definition: C4Gui.cpp:720
Dialog * pActiveDlg
Definition: C4Gui.h:2593
void AbortContext(bool fByUser)
Definition: C4Gui.h:2657
void ElementPosChanged(Element *pOfElement) override
Definition: C4Gui.cpp:604
float fZoom
Definition: C4Gui.h:2597
void MouseMove(int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyParam, class C4Viewport *pVP)
Definition: C4Gui.cpp:797
bool KeyAny()
Definition: C4Gui.cpp:771
void CloseDialog(Dialog *pDlg, bool fFade)
Definition: C4Gui.cpp:663
Dialog * GetTopDialog()
Definition: C4Gui.cpp:692
void CloseAllDialogs(bool fWithOK)
Definition: C4Gui.cpp:704
bool IsExclusive()
Definition: C4Gui.h:2670
void RemoveElement(Element *pChild) override
Definition: C4Gui.cpp:556
C4Rect PreferredDlgRect
Definition: C4Gui.h:2596
int32_t GetMouseControlledDialogCount()
Definition: C4Gui.cpp:999
void SetPos(int32_t iXPos, int32_t iYPos)
Definition: C4Gui.h:860
void MouseInput(CMouse &rMouse, int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyParam) override
void Draw(C4TargetFacet &cgo) override
C4Rect & GetClientRect() override
Definition: C4Gui.h:864
C4LoaderScreen * pLoaderScreen
void Draw(C4Facet &cgo, Flag options=Flag::ALL, int iProgress=0, class C4LogBuffer *pLog=nullptr, int Process=0)
void SetOwnedMouse(bool fToVal)
Definition: C4Rect.h:28
int32_t y
Definition: C4Rect.h:30
int32_t GetMiddleX() const
Definition: C4Rect.h:56
int32_t Hgt
Definition: C4Rect.h:30
int32_t Wdt
Definition: C4Rect.h:30
int32_t GetMiddleY() const
Definition: C4Rect.h:57
int32_t x
Definition: C4Rect.h:30
bool Contains(int32_t iX, int32_t iY) const
Definition: C4Rect.h:40
void Set(int32_t iX, int32_t iY, int32_t iWdt, int32_t iHgt)
Definition: C4Rect.cpp:86
int Wdt
Definition: C4Surface.h:65
int Hgt
Definition: C4Surface.h:65
float TargetY
Definition: C4Facet.h:165
float TargetX
Definition: C4Facet.h:165
void Set(const C4Facet &cpy)
Definition: C4Facet.h:182
C4Rect GetOutputRect()
Definition: C4Viewport.h:67
void MouseMoveToViewport(int32_t button, int32_t x, int32_t y, DWORD key_param)
C4Surface * pSurface
Definition: C4Window.h:275
std::tuple< std::string, int > BreakMessage(const char *szMsg, int iWdt, bool fCheckMarkup, float fZoom=1.0f)
bool GetTextExtent(const char *szText, int32_t &rsx, int32_t &rsy, bool fCheckMarkup=true)
void AppendFormat(const char *szFmt,...) GNUC_FORMAT_ATTRIBUTE_O
Definition: StdBuf.cpp:190
const char * getData() const
Definition: StdBuf.h:442
bool isNull() const
Definition: StdBuf.h:441
void AppendChar(char cChar)
Definition: StdBuf.h:588
void Copy()
Definition: StdBuf.h:467
void Clear()
Definition: StdBuf.h:466
void Take(char *pnData)
Definition: StdBuf.h:457
float GetZoom()
Definition: C4Gui.h:2831
Screen TheScreen
Definition: C4Gui.cpp:1054
DWORD MakeColorReadableOnBlack(DWORD &rdwClr)
Definition: C4Gui.cpp:98
bool ExpandHotkeyMarkup(StdStrBuf &sText, uint32_t &rcHotkey, bool for_tooltip)
Definition: C4Gui.cpp:38
void GUISound(const char *szSound)
Definition: C4Gui.cpp:1175
void SetHorizontal(C4Surface &rBySfc, int iHeight=0, int iBorderWidth=0)
Definition: C4Gui.cpp:119
C4Facet fctEnd
Definition: C4Gui.h:351
C4Facet fctMiddle
Definition: C4Gui.h:351
C4Facet fctBegin
Definition: C4Gui.h:351
C4Facet fctScrollPin
Definition: C4Gui.h:362
void Set(const C4Facet &rByFct, int32_t iPinIndex=0)
Definition: C4Gui.cpp:136
C4Facet fctScrollDBottom
Definition: C4Gui.h:362
DynBarFacet barScroll
Definition: C4Gui.h:361
C4Facet fctScrollDTop
Definition: C4Gui.h:362
float Zoom
Definition: C4Draw.h:70