OpenClonk
C4GuiContainers.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 // grouping elements and control base classes
18 
19 #include "C4Include.h"
20 #include "gui/C4Gui.h"
21 
22 #include "graphics/C4Draw.h"
24 #include "gui/C4MouseControl.h"
25 
26 namespace C4GUI
27 {
28 
29 // --------------------------------------------------
30 // Container
31 
33  {
34  // self visible?
35  if (!IsVisible()) return;
36  // then draw all visible child elements
37  for (Element *pEl = pFirst; pEl; pEl = pEl->pNext)
38  if (pEl->fVisible)
39  {
40  // skip viewport dialogs
41  if (!pEl->IsExternalDrawDialog())
42  {
43  if (pEl->GetDialogWindow())
44  pEl->GetDialogWindow()->RequestUpdate();
45  else
46  pEl->Draw(cgo);
47  }
48  }
49  }
50 
52  {
53  // zero fields
54  pFirst = pLast = nullptr;
55  }
56 
58  {
59  // empty
60  Clear();
61  }
62 
64  {
65  ClearChildren();
66  }
67 
69  {
70  // delete all items; dtor will update list
71  while (pFirst)
72  {
73  if (pFirst->IsOwnPtrElement())
74  {
75  // unlink from list
76  Element *pANext = pFirst->pNext;
77  pFirst->pPrev = pFirst->pNext = nullptr;
78  pFirst->pParent = nullptr;
79  if ((pFirst = pANext))
80  pFirst->pPrev = nullptr;
81  else
82  pLast = nullptr;
83  }
84  else
85  delete pFirst;
86  }
87  }
88 
90  {
91  // safety
92  if (!pChild) return;
93  // inherited
94  Element::RemoveElement(pChild);
95  // must be from same container
96  if (pChild->pParent != this) return;
97  // unlink from list
98  if (pChild->pPrev) pChild->pPrev->pNext = pChild->pNext; else pFirst = pChild->pNext;
99  if (pChild->pNext) pChild->pNext->pPrev = pChild->pPrev; else pLast = pChild->pPrev;
100  // unset parent; invalidates pPrev/pNext
101  pChild->pParent = nullptr;
102  // element has been removed
104  }
105 
107  {
108  // must be from same container
109  if (pChild->pParent != this) return;
110  // unlink from list
111  if (pChild->pPrev) pChild->pPrev->pNext = pChild->pNext; else pFirst = pChild->pNext;
112  if (pChild->pNext) pChild->pNext->pPrev = pChild->pPrev; else pLast = pChild->pPrev;
113  // readd to front of list
114  if (pLast) pLast->pNext = pChild; else pFirst = pChild;
115  pChild->pPrev = pLast; pChild->pNext = nullptr; pLast = pChild;
116  }
117 
119  {
120  // safety
121  if (!pChild) return;
122  // remove from any previous container
123  if (pChild->pParent) pChild->pParent->RemoveElement(pChild);
124  // add to end of list
125  if (pLast) pLast->pNext = pChild; else pFirst = pChild;
126  pChild->pPrev = pLast; pChild->pNext = nullptr; pLast = pChild;
127  pChild->pParent = this;
128 
129  assert(pChild->pNext != pChild);
130  assert(pChild->pPrev != pChild);
131  assert(pChild->pParent != pChild);
132  }
133 
135  {
136  // safety
137  if (!pChild || pChild->pParent != this) return;
138  // remove from any previous container
139  if (pChild->pPrev) pChild->pPrev->pNext = pChild->pNext; else pFirst = pChild->pNext;
140  if (pChild->pNext) pChild->pNext->pPrev = pChild->pPrev; else pLast = pChild->pPrev;
141  // add to end of list
142  if (pLast) pLast->pNext = pChild; else pFirst = pChild;
143  pChild->pPrev = pLast; pChild->pNext = nullptr; pLast = pChild;
144 
145  assert(pChild->pNext != pChild);
146  assert(pChild->pPrev != pChild);
147  assert(pChild->pParent != pChild);
148  }
149 
150  void Container::InsertElement(Element *pChild, Element *pInsertBefore)
151  {
152  // add?
153  if (!pInsertBefore) { AddElement(pChild); return; }
154  // safety
155  if (!pChild || pInsertBefore->pParent != this) return;
156  // remove from any previous container
157  if (pChild->pParent) pChild->pParent->RemoveElement(pChild);
158  // add before given element
159  if ((pChild->pPrev = pInsertBefore->pPrev))
160  pInsertBefore->pPrev->pNext = pChild;
161  else
162  pFirst = pChild;
163  pChild->pNext = pInsertBefore; pInsertBefore->pPrev = pChild;
164  pChild->pParent = this;
165 
166  assert(pChild->pNext != pChild);
167  assert(pChild->pPrev != pChild);
168  assert(pChild->pParent != pChild);
169  }
170 
171  Element *Container::GetNextNestedElement(Element *pPrevElement, bool fBackwards)
172  {
173  if (fBackwards)
174  {
175  // this is last
176  if (pPrevElement == this) return nullptr;
177  // no previous given?
178  if (!pPrevElement)
179  // then use last nested for backwards search
180  return GetFirstNestedElement(true);
181  // get nested, previous element if present
182  if (pPrevElement->pPrev) return pPrevElement->pPrev->GetFirstNestedElement(true);
183  // if not, return parent (could be this)
184  return pPrevElement->pParent;
185  }
186  else
187  {
188  // forward search: first element is this
189  if (!pPrevElement) return this;
190  // check next nested
191  Element *pEl;
192  if ((pEl = pPrevElement->GetFirstContained())) return pEl;
193  // check next in list, going upwards until this container is reached
194  while (pPrevElement && pPrevElement != this)
195  {
196  if ((pEl = pPrevElement->pNext)) return pEl;
197  pPrevElement = pPrevElement->pParent;
198  }
199  // nothing found
200  }
201  return nullptr;
202  }
203 
205  {
206  // get first/last in own list
207  if (pFirst) return (fBackwards ? pLast : pFirst)->GetFirstNestedElement(fBackwards);
208  // no own list: return this one
209  return this;
210  }
211 
212  bool Container::OnHotkey(uint32_t cHotkey)
213  {
214  if (!IsVisible()) return false;
215  // check all nested elements
216  for (Element *pEl = pFirst; pEl; pEl=pEl->pNext)
217  if (pEl->fVisible)
218  if (pEl->OnHotkey(cHotkey)) return true;
219  // no match found
220  return false;
221  }
222 
224  {
225  // get next until end of list or queried index is reached
226  // if i is negative or equal or larger than childcount, the loop will never break and nullptr returned
227  Element *pEl;
228  for (pEl = pFirst; i-- && pEl; pEl=pEl->pNext) {}
229  return pEl;
230  }
231 
233  {
234  int32_t cnt=0;
235  for (Element *pEl = pFirst; pEl; pEl=pEl->pNext) ++cnt;
236  return cnt;
237  }
238 
240  {
241  // return whether this is the parent container (directly or recursively) of the passed element
242  for (Container *pC = pEl->GetParent(); pC; pC = pC->GetParent())
243  if (pC == this) return true;
244  return false;
245  }
246 
247  void Container::SetVisibility(bool fToValue)
248  {
249  // inherited
250  Element::SetVisibility(fToValue);
251  // remove focus from contained elements
252  if (!fToValue)
253  {
254  Dialog *pDlg = GetDlg();
255  if (pDlg)
256  {
257  Control *pFocus = pDlg->GetFocus();
258  if (pFocus)
259  {
260  if (IsParentOf(pFocus))
261  {
262  pDlg->SetFocus(nullptr, false);
263  }
264  }
265  }
266  }
267  }
268 
269 
270 // --------------------------------------------------
271 // Window
272 
273  void Window::MouseInput(CMouse &rMouse, int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyParam)
274  {
275  // invisible?
276  if (!IsVisible()) return;
277  // inherited
278  Container::MouseInput(rMouse, iButton, iX, iY, dwKeyParam);
279  // get client pos
281  iX -= rcClientRect.x - rcBounds.x; iY -= rcClientRect.y - rcBounds.y;
282  // forward to topmost child element
283  for (Element *pChild = pLast; pChild; pChild = pChild->GetPrev())
284  if (pChild->fVisible && pChild->GetBounds().Contains(iX, iY))
285  {
286  // forward
287  pChild->MouseInput(rMouse, iButton, iX - pChild->GetBounds().x, iY - pChild->GetBounds().y, dwKeyParam);
288  // forward to one control only
289  break;
290  }
291  }
292 
294  {
295  // invisible?
296  if (!IsVisible()) return;
297  // draw window itself
298  DrawElement(cgo);
299  // get target area
302  // clip to window area
303  int clx1, cly1, clx2, cly2;
304  pDraw->GetPrimaryClipper(clx1, cly1, clx2, cly2);
305  float nclx1 = cgo.TargetX+rcClipArea.x, ncly1 = cgo.TargetY+rcClipArea.y, nclx2 = cgo.TargetX+rcClipArea.x+rcClipArea.Wdt-1, ncly2 = cgo.TargetY+rcClipArea.y+rcClipArea.Hgt-1;
306  pDraw->ApplyZoom(nclx1, ncly1);
307  pDraw->ApplyZoom(nclx2, ncly2);
308  pDraw->SubPrimaryClipper(nclx1, ncly1, nclx2, ncly2);
309  // update target area
310  cgo.TargetX += rcClientRect.x; cgo.TargetY += rcClientRect.y;
311  // draw contents
312  Container::Draw(cgo);
313  // reset target area
314  cgo.TargetX -= rcClientRect.x; cgo.TargetY -= rcClientRect.y;
315  // reset clipper
316  pDraw->SetPrimaryClipper(clx1, cly1, clx2, cly2);
317  }
318 
320  {
321  UpdateOwnPos();
322  }
323 
325  {
327  // set client rect
328  int32_t iMarginL=GetMarginLeft(), iMarginT=GetMarginTop();
329  rcClientRect.Set(rcBounds.x + iMarginL, rcBounds.y + iMarginT, std::max<int32_t>(rcBounds.Wdt - iMarginL - GetMarginRight(), 0), std::max<int32_t>(rcBounds.Hgt - iMarginT - GetMarginBottom(), 0));
330  }
331 
332 
333 // --------------------------------------------------
334 // ScrollBar
335 
336  ScrollBar::ScrollBar(C4Rect &rcBounds, ScrollWindow *pWin) : fAutoHide(false), fHorizontal(false), iCBMaxRange(100), pScrollCallback(nullptr), pCustomGfx(nullptr)
337  {
338  // set bounds
339  this->rcBounds = rcBounds;
340  // set initial values
341  pScrollWindow = pWin;
342  fScrolling = false;
344  iScrollPos = 0;
345  fTopDown = fBottomDown = false;
346  // update scroll bar pos
347  Update();
348  }
349 
350  ScrollBar::ScrollBar(C4Rect &rcBounds, bool fHorizontal, BaseParCallbackHandler<int32_t> *pCB, int32_t iCBMaxRange) : fAutoHide(false), fHorizontal(fHorizontal), iCBMaxRange(iCBMaxRange), pScrollWindow(nullptr), pCustomGfx(nullptr)
351  {
352  // set bounds
353  this->rcBounds = rcBounds;
354  // set initial values
355  if ((pScrollCallback = pCB)) pScrollCallback->Ref();
356  fScrolling = true;
358  iScrollPos = 0;
359  fTopDown = fBottomDown = false;
360  }
361 
363  {
364  if (pScrollWindow) { pScrollWindow->pScrollBar = nullptr; }
366  }
367 
369  {
370  // check associated control
371  if (pScrollWindow)
372  {
373  int32_t iVisHgt = pScrollWindow->GetBounds().Hgt;
374  int32_t iClientHgt = pScrollWindow->GetClientRect().Hgt;
375  if ((fScrolling = (iVisHgt < iClientHgt)))
376  {
377  // scrolling necessary
378  // get vertical scroll pos
379  int32_t iMaxWinScroll = iClientHgt - iVisHgt;
380  int32_t iMaxBarScroll = GetBounds().Hgt - 2*C4GUI_ScrollArrowHgt - iScrollThumbSize;
381  int32_t iWinScroll = pScrollWindow->iScrollY;
382  // scroll thumb height is currently hardcoded
383  // calc scroll pos
384  iScrollPos = Clamp<int32_t>(iMaxBarScroll * iWinScroll / iMaxWinScroll, 0, iMaxBarScroll);
385  }
386  }
387  else fScrolling = !!pScrollCallback;
388  // reset buttons
389  if (!fScrolling)
390  fTopDown = fBottomDown = false;
391  // set visibility by scroll status
393  }
394 
396  {
397  int32_t iMaxBarScroll = GetMaxScroll();
398  if (!iMaxBarScroll) iMaxBarScroll=1;
399  // CB - passes scroll pos
400  if (pScrollCallback) pScrollCallback->DoCall(Clamp<int32_t>(iScrollPos * (iCBMaxRange-1) / iMaxBarScroll, 0, (iCBMaxRange-1)));
401  // safety
402  if (!pScrollWindow || !fScrolling) return;
403  // get scrolling values
404  assert(!fHorizontal); // nyi
405  int32_t iVisHgt = pScrollWindow->GetBounds().Hgt;
406  int32_t iClientHgt = pScrollWindow->GetClientRect().Hgt;
407  int32_t iMaxWinScroll = iClientHgt - iVisHgt;
408  int32_t iWinScroll = pScrollWindow->iScrollY;
409  // calc new window scrolling
410  int32_t iNewWinScroll = Clamp<int32_t>(iMaxWinScroll * iScrollPos / iMaxBarScroll, 0, iMaxWinScroll);
411  // apply it, if it is different
412  if (iWinScroll != iNewWinScroll)
413  pScrollWindow->SetScroll(iNewWinScroll);
414  }
415 
416  void ScrollBar::MouseInput(CMouse &rMouse, int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyParam)
417  {
418  // inherited
419  Element::MouseInput(rMouse, iButton, iX, iY, dwKeyParam);
420  // not if scrolling is disabled
421  if (!fScrolling) return;
422  // reset arrow states
423  bool fPrevDown = fTopDown || fBottomDown;
424  fTopDown = fBottomDown = false;
425  // not if dragging
426  if (rMouse.pDragElement) return;
427  // left mouse button down?
428  if (rMouse.IsLDown())
429  // non-scroll-direction area check
430  if (fHorizontal ? Inside<int32_t>(iY, 0, C4GUI_ScrollBarHgt) : Inside<int32_t>(iX, 0, C4GUI_ScrollBarWdt))
431  {
432  // scroll-direction area check: up/left arrow
433  if (fHorizontal ? Inside<int32_t>(iX, 0, C4GUI_ScrollArrowWdt-1) : Inside<int32_t>(iY, 0, C4GUI_ScrollArrowHgt-1))
434  fTopDown = true;
435  // check down arrow
436  else if (fHorizontal ? Inside<int32_t>(iX, GetBounds().Wdt-C4GUI_ScrollArrowWdt, GetBounds().Wdt-1)
437  : Inside<int32_t>(iY, GetBounds().Hgt-C4GUI_ScrollArrowHgt, GetBounds().Hgt-1))
438  fBottomDown = true;
439  else if (HasPin() && (fHorizontal ? Inside<int32_t>(iX, C4GUI_ScrollArrowWdt, GetBounds().Wdt-C4GUI_ScrollArrowWdt-1)
440  : Inside<int32_t>(iY, C4GUI_ScrollArrowHgt, GetBounds().Hgt-C4GUI_ScrollArrowHgt-1)))
441  {
442  // move thumb here
443  iScrollPos = GetScrollByPos(iX, iY);
444  // reflect movement in associated window or do CB
445  OnPosChanged();
446  // start dragging
447  rMouse.pDragElement = this;
448  GUISound("UI::Select");
449  }
450  }
451  // sound effekt when buttons are pressed
452  if ((fTopDown || fBottomDown) != fPrevDown) GUISound("UI::Tick");
453  }
454 
455  void ScrollBar::DoDragging(CMouse &rMouse, int32_t iX, int32_t iY, DWORD dwKeyParam)
456  {
457  // move thumb
458  iScrollPos = GetScrollByPos(iX, iY);
459  // reflect movement in associated window
460  OnPosChanged();
461  }
462 
464  {
465  // inherited
466  Element::MouseLeave(rMouse);
467  // reset button states
468  fTopDown = fBottomDown = false;
469  }
470 
472  {
473  // do scrolling
474  // not quite perfect; but there's no OnIdle, and it's be a bit of overkill starting a timer
475  if (fTopDown && fScrolling && iScrollPos>0)
476  { --iScrollPos; OnPosChanged(); }
477  if (fBottomDown && fScrolling)
478  {
480  }
481  // draw bar
483  DynBarFacet bar = rUseGfx.barScroll;
484  if (fTopDown) bar.fctBegin = rUseGfx.fctScrollDTop;
485  if (fBottomDown) bar.fctEnd = rUseGfx.fctScrollDBottom;
486  if (fHorizontal)
487  DrawHBarByVGfx(cgo, bar);
488  else
489  DrawVBar(cgo, bar);
490  // draw scroll pin
491  if (fScrolling && HasPin())
492  {
493  if (fHorizontal)
495  else
497  }
498  }
499 
500 
501 // --------------------------------------------------
502 // ScrollWindow
503 
505  : Window(), pScrollBar(nullptr), iScrollY(0), iClientHeight(0), fHasBar(true), iFrozen(0)
506  {
507  // place within client rect
508  C4Rect rtBounds = pParentWindow->GetClientRect();
509  rtBounds.x = rtBounds.y = 0;
510  rtBounds.Wdt -= C4GUI_ScrollBarWdt;
511  SetBounds(rtBounds);
512  // create scroll bar
513  rtBounds.x += rtBounds.Wdt; rtBounds.Wdt = C4GUI_ScrollBarWdt;
514  pScrollBar = new ScrollBar(rtBounds, this);
515  // add self and scroll bar to window
516  if (pParentWindow != this)
517  {
518  pParentWindow->AddElement(this);
519  pParentWindow->AddElement(pScrollBar);
520  }
521  }
522 
524  {
525  // not if window is being refilled
526  if (iFrozen) return;
527  // do not scroll outside range
528  iScrollY = Clamp<int32_t>(iScrollY, 0, std::max<int32_t>(iClientHeight - GetBounds().Hgt, 0));
529  // update client rect
530  rcClientRect.x = 0;
534  // update scroll bar
535  if (pScrollBar) pScrollBar->Update();
536  }
537 
538  void ScrollWindow::SetScroll(int32_t iToScroll)
539  {
540  // set values
541  rcClientRect.y = -(iScrollY = iToScroll);
542  }
543 
545  {
546  int32_t iVisHgt = GetBounds().Hgt;
547  int32_t iClientHgt = GetClientRect().Hgt;
548  int32_t iMaxScroll = iClientHgt - iVisHgt;
549  if (iScrollY < iMaxScroll)
550  {
551  // scrolling possible: do it
552  iScrollY = iMaxScroll;
553  // update (self + bar)
554  Update();
555  }
556  }
557 
558  void ScrollWindow::ScrollPages(int iPageCount)
559  {
560  int32_t iVisHgt = GetBounds().Hgt;
561  ScrollBy(iPageCount * iVisHgt);
562  }
563 
564  void ScrollWindow::ScrollBy(int iAmount)
565  {
566  int32_t iVisHgt = GetBounds().Hgt;
567  int32_t iClientHgt = GetClientRect().Hgt;
568  int32_t iMaxScroll = iClientHgt - iVisHgt;
569  int iNewScrollY = Clamp<int>(iScrollY + iAmount, 0, iMaxScroll);
570  if (iScrollY != iNewScrollY)
571  {
572  // scrolling possible: do it
573  iScrollY = iNewScrollY;
574  // update (self + bar)
575  Update();
576  }
577  }
578 
579  void ScrollWindow::ScrollRangeInView(int32_t iY, int32_t iHgt)
580  {
581  // safety bounds
582  if (iY<0) iY=0;
583  int32_t iClientHgt = GetClientRect().Hgt;
584  if (iY+iHgt > iClientHgt) { ScrollToBottom(); return; }
585  // check top
586  if (iScrollY > iY)
587  {
588  iScrollY = iY;
589  Update(); // update (self+bar)
590  }
591  else
592  {
593  // check bottom
594  int32_t iVisHgt = GetBounds().Hgt;
595  // if no height is given, scroll given Y-pos to top
596  if (!iHgt) iHgt = iVisHgt;
597  if (iScrollY + iVisHgt < iY + iHgt)
598  {
599  iScrollY = iY + iHgt - iVisHgt;
600  Update(); // update (self+bar)
601  }
602  }
603  }
604 
605  bool ScrollWindow::IsRangeInView(int32_t iY, int32_t iHgt)
606  {
607  // returns whether scrolling range is in view
608  // check top
609  if (iScrollY > iY) return false;
610  // check height
611  return iScrollY + GetBounds().Hgt >= iY+iHgt;
612  }
613 
615  {
616  if (!GetParent()) { Update(); return; }
617  // place within client rect
618  C4Rect rtBounds = GetParent()->GetContainedClientRect();
619  rtBounds.x = rtBounds.y = 0;
620  if (fHasBar) rtBounds.Wdt -= C4GUI_ScrollBarWdt;
621  if (GetBounds() != rtBounds)
622  {
623  SetBounds(rtBounds);
624  // scroll bar
625  if (fHasBar)
626  {
627  rtBounds.x += rtBounds.Wdt; rtBounds.Wdt = C4GUI_ScrollBarWdt;
628  pScrollBar->SetBounds(rtBounds);
629  }
630  }
631  // standard updates
632  Update();
633  }
634 
635  void ScrollWindow::SetScrollBarEnabled(bool fToVal, bool noAutomaticPositioning)
636  {
637  if (fHasBar == fToVal) return;
638  pScrollBar->SetVisibility(fHasBar = fToVal);
639  // in some cases the windows will already care for the correct positioning themselves (see C4ScriptGuiWindow)
640  if (!noAutomaticPositioning)
641  UpdateOwnPos();
642  }
643 
644  void ScrollWindow::MouseInput(CMouse &rMouse, int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyParam)
645  {
646  // process wheel: Scroll
647  if (iButton == C4MC_Button_Wheel)
648  {
649  short iDelta = (short)(dwKeyParam >> 16);
650  ScrollBy(-iDelta);
651  return;
652  }
653  // other mouse input: inherited (forward to children)
654  Window::MouseInput(rMouse, iButton, iX, iY, dwKeyParam);
655  }
656 
657 
658 // --------------------------------------------------
659 // GroupBox
660 
661  CStdFont *GroupBox::GetTitleFont() const
662  {
663  // get font; fallback to GUI caption font
664  return pFont ? pFont : &(::GraphicsResource.CaptionFont);
665  }
666 
668  {
669  // draw background
670  if (dwBackClr != 0xffffffff)
671  {
673  }
674  // draw title label
675  int32_t iBorderYOff = 0;
676  int32_t iTitleGapX = 0;
677  int32_t iTitleGapWdt = 0;
678  if (HasTitle())
679  {
680  CStdFont *pTitleFont = GetTitleFont();
681  iBorderYOff = pTitleFont->GetLineHeight()/2;
682  pTitleFont->GetTextExtent(sTitle.getData(), iTitleGapWdt, iTitleGapX, true);
683  iTitleGapX = 7; iTitleGapWdt += 4;
684  pDraw->TextOut(sTitle.getData(), *pTitleFont, 1.0f, cgo.Surface, cgo.TargetX+rcBounds.x+iTitleGapX+2, cgo.TargetY+rcBounds.y, dwTitleClr);
685  }
686  // draw frame
687  if (dwFrameClr)
688  {
689  int32_t x1=cgo.TargetX+rcBounds.x,y1=cgo.TargetY+rcBounds.y+iBorderYOff,x2=x1+rcBounds.Wdt,y2=y1+rcBounds.Hgt-iBorderYOff;
690  if (iTitleGapWdt)
691  {
692  for (int i=0; i<2; ++i)
693  {
694  pDraw->DrawLineDw(cgo.Surface, (float) x1+i, (float)y1, (float)(x1+i), (float)(y2-1), dwFrameClr); // left
695  pDraw->DrawLineDw(cgo.Surface, (float) (x1+2), (float)(y1+i), (float)(x1+iTitleGapX), (float)(y1+i), dwFrameClr); // top - left side
696  pDraw->DrawLineDw(cgo.Surface, (float) (x1+iTitleGapX+iTitleGapWdt), (float)(y1+i), (float)(x2-3), (float)(y1+i), dwFrameClr); // top - right side
697  pDraw->DrawLineDw(cgo.Surface, (float) (x2-1-i), (float)y1, (float)(x2-1-i), (float)(y2-1), dwFrameClr); // right
698  pDraw->DrawLineDw(cgo.Surface, (float) (x1+2), (float)(y2-1-i), (float)(x2-3), (float)(y2-1-i), dwFrameClr); // bottom
699  }
700  }
701  else
702  {
703  pDraw->DrawFrameDw(cgo.Surface, x1, y1, x2, (y2-1), dwFrameClr);
704  pDraw->DrawFrameDw(cgo.Surface, (x1+1), (y1+1), (x2-1), (y2-2), dwFrameClr);
705  }
706  }
707  else
708  // default frame color
709  // 2do: Make this work with titled group boxes
710  Draw3DFrame(cgo);
711  }
712 
713 
714 // --------------------------------------------------
715 // Control
716 
717  Control::Control(const C4Rect &rtBounds) : Window()
718  {
719  // set bounds
720  SetBounds(rtBounds);
721  // context menu key binding
722  pKeyContext = new C4KeyBinding(C4KeyCodeEx(K_MENU), "GUIContext", KEYSCOPE_Gui,
724  }
725 
727  {
728  delete pKeyContext;
729  }
730 
731  void Control::MouseInput(CMouse &rMouse, int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyParam)
732  {
733  if (!IsVisible()) return;
734  // left down on click=focus-components?
735  if (IsFocusOnClick() && IsFocusElement()) if (iButton == C4MC_Button_LeftDown && !HasFocus())
736  {
737  // then set focus
738  Dialog *pParentDlg = GetDlg();
739  if (pParentDlg)
740  {
741  // but do not set focus to this if a child control has it already
742  Control *pActiveCtrl = pParentDlg->GetFocus();
743  if (!pActiveCtrl || !IsParentOf(pActiveCtrl))
744  pParentDlg->SetFocus(this, true);
745  }
746  }
747  // inherited - processing child elements
748  Window::MouseInput(rMouse, iButton, iX, iY, dwKeyParam);
749  }
750 
752  {
753  // has focus at all?
754  if (!HasFocus()) return false;
755  // is screen ready and not in context?
756  if (GetScreen() && GetScreen()->HasContext()) return false;
757  // get dlg
758  Dialog *pDlg=GetDlg();
759  // dlg-less control has focus, OK (shouldn't happen)
760  if (!pDlg) return true;
761  // check if dlg is active
762  return pDlg->IsActive(true);
763  }
764 
766  {
767  // has it any focus at all?
768  if (!HasFocus()) return;
769  // then de-focus it
770  Dialog *pDlg=GetDlg();
771  if (!pDlg) return;
772  pDlg->AdvanceFocus(true);
773  }
774 
775 } // end of namespace
776 
C4Draw * pDraw
Definition: C4Draw.cpp:42
C4GraphicsResource GraphicsResource
#define C4GUI_ScrollArrowHgt
Definition: C4Gui.h:105
#define C4GUI_ScrollBarWdt
Definition: C4Gui.h:103
#define C4GUI_ScrollThumbWdt
Definition: C4Gui.h:108
#define C4GUI_ScrollThumbHgt
Definition: C4Gui.h:107
#define C4GUI_ScrollBarHgt
Definition: C4Gui.h:104
#define C4GUI_ScrollArrowWdt
Definition: C4Gui.h:106
@ KEYSCOPE_Gui
const int32_t C4MC_Button_LeftDown
const int32_t C4MC_Button_Wheel
uint32_t DWORD
bool SubPrimaryClipper(int iX1, int iY1, int iX2, int iY2)
Definition: C4Draw.cpp:196
void DrawFrameDw(C4Surface *sfcDest, int x1, int y1, int x2, int y2, DWORD dwClr, float width=1.0f)
Definition: C4Draw.cpp:635
void DrawBoxDw(C4Surface *sfcDest, int iX1, int iY1, int iX2, int iY2, DWORD dwClr)
Definition: C4Draw.cpp:840
bool GetPrimaryClipper(int &rX1, int &rY1, int &rX2, int &rY2)
Definition: C4Draw.cpp:716
void DrawLineDw(C4Surface *sfcTarget, float x1, float y1, float x2, float y2, DWORD dwClr, float width=1.0f)
Definition: C4Draw.cpp:608
bool SetPrimaryClipper(int iX1, int iY1, int iX2, int iY2)
Definition: C4Draw.cpp:217
void ApplyZoom(float &X, float &Y)
Definition: C4Draw.cpp:778
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
C4Surface * Surface
Definition: C4Facet.h:117
void Draw(C4Facet &cgo, bool fAspect=true, int32_t iPhaseX=0, int32_t iPhaseY=0, bool fTransparent=true)
Definition: C4Facet.cpp:154
void DoCall(class Element *pElement) override
Definition: C4Gui.h:321
bool IsLDown()
Definition: C4Gui.h:2565
Element * pDragElement
Definition: C4Gui.h:2556
int32_t x
Definition: C4Gui.h:2535
void AddElement(Element *pChild)
void RemoveElement(Element *pChild) override
Element * GetElementByIndex(int32_t i)
void MakeLastElement(Element *pChild)
Element * pFirst
Definition: C4Gui.h:750
Element * pLast
Definition: C4Gui.h:750
void ReaddElement(Element *pChild)
virtual void AfterElementRemoval()
Definition: C4Gui.h:756
void InsertElement(Element *pChild, Element *pInsertBefore)
bool OnHotkey(uint32_t cHotkey) override
Element * GetNextNestedElement(Element *pPrevElement, bool fBackwards)
void Draw(C4TargetFacet &cgo) override
void SetVisibility(bool fToValue) override
bool IsParentOf(Element *pEl) override
friend class ScrollWindow
Definition: C4Gui.h:844
Element * GetFirstNestedElement(bool fBackwards) override
bool KeyContext()
Definition: C4Gui.h:1059
bool HasFocus()
Definition: C4Gui.h:1067
Control(const C4Rect &rtBounds)
Control * IsFocusElement() override
Definition: C4Gui.h:1055
void MouseInput(CMouse &rMouse, int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyParam) override
virtual bool IsFocusOnClick()
Definition: C4Gui.h:1054
void SetFocus(Control *pCtrl, bool fByMouse)
bool IsActive(bool fForKeyboard)
void AdvanceFocus(bool fBackwards)
Control * GetFocus()
Definition: C4Gui.h:2116
virtual void DrawElement(C4TargetFacet &cgo)
Definition: C4Gui.h:388
virtual bool IsOwnPtrElement()
Definition: C4Gui.h:401
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
void DrawVBar(C4TargetFacet &cgo, DynBarFacet &rFacets)
Definition: C4Gui.cpp:359
virtual Screen * GetScreen()
Definition: C4Gui.cpp:289
C4Rect GetContainedClientRect()
Definition: C4Gui.h:448
virtual void MouseInput(CMouse &rMouse, int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyParam)
Definition: C4Gui.cpp:244
void SetBounds(const C4Rect &rcNewBound)
Definition: C4Gui.h:446
Element * pPrev
Definition: C4Gui.h:377
Container * GetParent()
Definition: C4Gui.h:429
void DrawHBarByVGfx(C4TargetFacet &cgo, DynBarFacet &rFacets)
Definition: C4Gui.cpp:365
Container * pParent
Definition: C4Gui.h:376
virtual class Dialog * GetDlg()
Definition: C4Gui.cpp:288
Element * pNext
Definition: C4Gui.h:377
virtual Element * GetFirstNestedElement(bool fBackwards)
Definition: C4Gui.h:451
virtual Element * GetFirstContained()
Definition: C4Gui.h:452
C4Rect & GetBounds()
Definition: C4Gui.h:445
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 DrawElement(C4TargetFacet &cgo) override
bool HasTitle() const
Definition: C4Gui.h:1021
void MouseInput(CMouse &rMouse, int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyParam) override
int32_t iScrollThumbSize
Definition: C4Gui.h:885
void MouseLeave(CMouse &rMouse) override
bool fTopDown
Definition: C4Gui.h:887
ScrollBar(C4Rect &rcBounds, ScrollWindow *pWin)
void DrawElement(C4TargetFacet &cgo) override
bool HasPin()
Definition: C4Gui.h:902
ScrollWindow * pScrollWindow
Definition: C4Gui.h:891
void DoDragging(CMouse &rMouse, int32_t iX, int32_t iY, DWORD dwKeyParam) override
int32_t GetScrollByPos(int32_t iX, int32_t iY)
Definition: C4Gui.h:912
bool fBottomDown
Definition: C4Gui.h:887
ScrollBarFacets * pCustomGfx
Definition: C4Gui.h:894
BaseParCallbackHandler< int32_t > * pScrollCallback
Definition: C4Gui.h:892
int32_t iScrollPos
Definition: C4Gui.h:886
bool fHorizontal
Definition: C4Gui.h:888
int32_t GetMaxScroll()
Definition: C4Gui.h:907
int32_t iCBMaxRange
Definition: C4Gui.h:889
bool fScrolling
Definition: C4Gui.h:883
bool fAutoHide
Definition: C4Gui.h:884
int32_t iFrozen
Definition: C4Gui.h:946
void MouseInput(CMouse &rMouse, int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyParam) override
friend class ScrollBar
Definition: C4Gui.h:995
bool IsRangeInView(int32_t iY, int32_t iHgt)
void SetScrollBarEnabled(bool fToVal, bool noAutomaticPositioning=false)
int32_t iScrollY
Definition: C4Gui.h:943
void ScrollPages(int iPageCount)
void ScrollBy(int iAmount)
void ScrollRangeInView(int32_t iY, int32_t iHgt)
ScrollBar * pScrollBar
Definition: C4Gui.h:942
int32_t iClientHeight
Definition: C4Gui.h:944
void UpdateOwnPos() override
void SetScroll(int32_t iToScroll)
virtual int32_t GetMarginRight()
Definition: C4Gui.h:875
virtual int32_t GetMarginTop()
Definition: C4Gui.h:873
C4Rect rcClientRect
Definition: C4Gui.h:851
void UpdateOwnPos() override
void MouseInput(CMouse &rMouse, int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyParam) override
virtual int32_t GetMarginLeft()
Definition: C4Gui.h:874
void Draw(C4TargetFacet &cgo) override
C4Rect & GetClientRect() override
Definition: C4Gui.h:864
virtual int32_t GetMarginBottom()
Definition: C4Gui.h:876
virtual bool IsComponentOutsideClientArea()
Definition: C4Gui.h:870
C4GUI::ScrollBarFacets sfctScroll
Definition: C4Rect.h:28
int32_t y
Definition: C4Rect.h:30
int32_t Hgt
Definition: C4Rect.h:30
int32_t Wdt
Definition: C4Rect.h:30
int32_t x
Definition: C4Rect.h:30
void Set(int32_t iX, int32_t iY, int32_t iWdt, int32_t iHgt)
Definition: C4Rect.cpp:86
float TargetY
Definition: C4Facet.h:165
float TargetX
Definition: C4Facet.h:165
int GetLineHeight() const
Definition: C4FontLoader.h:125
bool GetTextExtent(const char *szText, int32_t &rsx, int32_t &rsy, bool fCheckMarkup=true)
const char * getData() const
Definition: StdBuf.h:442
void GUISound(const char *szSound)
Definition: C4Gui.cpp:1175
C4Facet fctEnd
Definition: C4Gui.h:351
C4Facet fctBegin
Definition: C4Gui.h:351
C4Facet fctScrollPin
Definition: C4Gui.h:362
C4Facet fctScrollDBottom
Definition: C4Gui.h:362
DynBarFacet barScroll
Definition: C4Gui.h:361
C4Facet fctScrollDTop
Definition: C4Gui.h:362