OpenClonk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros
C4GuiTabular.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 // tab control
18 
19 #include "C4Include.h"
20 #include "gui/C4Gui.h"
21 
22 #include "graphics/C4Draw.h"
23 #include "graphics/C4FacetEx.h"
25 #include "gui/C4MouseControl.h"
26 
27 namespace C4GUI
28 {
29 
30 
31 // ----------------------------------------------------
32 // Tabular::Sheet
33 
34  Tabular::Sheet::Sheet(const char *szTitle, const C4Rect &rcBounds, int32_t icoTitle, bool fHasCloseButton, bool fTitleMarkup)
35  : Window(), icoTitle(icoTitle), cHotkey(0), dwCaptionClr(0u), fHasCloseButton(fHasCloseButton), fCloseButtonHighlighted(false), fTitleMarkup(fTitleMarkup)
36  {
37  // store title
38  if (szTitle)
39  {
40  sTitle.Copy(szTitle);
41  if (fTitleMarkup) ExpandHotkeyMarkup(sTitle, cHotkey);
42  }
43  // set bounds
44  SetBounds(rcBounds);
45  }
46 
47  void Tabular::Sheet::DrawCaption(C4TargetFacet &cgo, int32_t x, int32_t y, int32_t iMaxWdt, bool fLarge, bool fActive, bool fFocus, C4Facet *pfctClip, C4Facet *pfctIcon, CStdFont *pUseFont)
48  {
49  // calculations
50  int32_t iTxtHgt, iTxtWdt;
51  GetCaptionSize(&iTxtWdt, &iTxtHgt, fLarge, fActive, pfctClip, pfctIcon, pUseFont);
52  if (pfctClip) iMaxWdt = iTxtWdt;
53  CStdFont &rUseFont = pUseFont ? *pUseFont : (fLarge ? ::GraphicsResource.CaptionFont : ::GraphicsResource.TextFont);
54  if (pfctClip && pfctIcon)
55  {
56  // tab with clip gfx: Icon on top of text
57  // x and y mark topleft pos; iTxtWdt and iTxtHgt mark overall size
58  pfctClip->Draw(cgo.Surface, x, y);
59  int32_t xCenter = x + iTxtWdt/2, yCenter = y + iTxtHgt/2;
60  int32_t iLabelHgt = rUseFont.GetLineHeight(); int32_t iIconLabelSpacing = 2;
61  int32_t yTop = yCenter - (pfctIcon->Hgt+iIconLabelSpacing+iLabelHgt)/2;
62  pfctIcon->Draw(cgo.Surface, xCenter-pfctIcon->Wdt/2, yTop, icoTitle);
63  pDraw->TextOut(sTitle.getData(), rUseFont, 1.0f, cgo.Surface, xCenter, yTop + pfctIcon->Hgt+iIconLabelSpacing, fActive ? C4GUI_GfxTabCaptActiveClr : C4GUI_GfxTabCaptInactiveClr , ACenter);
64  }
65  // focus highlight
66  if (fFocus)
67  {
69  ::GraphicsResource.fctButtonHighlightRound.DrawX(cgo.Surface, (fLarge ? x : x - iTxtWdt/2)+5, y+3, (fLarge ? iMaxWdt : iTxtWdt)-10, iTxtHgt-6);
71  }
72  if (!(pfctClip && pfctIcon))
73  {
74  // classical tab without clip
75  // icon
76  int32_t xo = x;
77  if (icoTitle>=0)
78  {
79  C4Facet cgoIcon(cgo.Surface, x, y+1, iTxtHgt-2, iTxtHgt-2);
80  if (fLarge)
81  {
82  // large caption: x parameter denotes left pos of icon
83  x += iTxtHgt + 2;
84  }
85  else
86  {
87  // small caption: x parameter denotes drawing center
88  // note that iTxtWdt includes the icon (and close button) as well
89  cgoIcon.X -= iTxtWdt / 2;
90  x += iTxtHgt / 2;
91  }
92  Icon::GetIconFacet((Icons)icoTitle).Draw(cgoIcon);
93  }
94  // text
95  if (!fLarge && fHasCloseButton) x -= iTxtHgt/2;
96  uint32_t dwClr = dwCaptionClr;
97  if (!dwClr) dwClr = fActive ? C4GUI_CaptionFontClr : C4GUI_InactCaptionFontClr;
98  pDraw->TextOut(sTitle.getData(), rUseFont, fLarge ? 1.2f : 1.0f, cgo.Surface, x, y, dwClr, fLarge ? ALeft : ACenter, fTitleMarkup);
99  // close button
100  if (fHasCloseButton)
101  {
102  xo += iTxtWdt / (2 - fLarge) - iTxtHgt + 1;
103  C4Facet cgoCloseBtn(cgo.Surface, xo, y+1, iTxtHgt-2, iTxtHgt-2);
104  if (!fCloseButtonHighlighted) pDraw->ActivateBlitModulation(0x7f7f7f);
105  Icon::GetIconFacet(Ico_Close).Draw(cgoCloseBtn);
106  if (!fCloseButtonHighlighted) pDraw->DeactivateBlitModulation();
107  }
108  }
109  }
110 
111  void Tabular::Sheet::GetCaptionSize(int32_t *piWdt, int32_t *piHgt, bool fLarge, bool fActive, C4Facet *pfctClip, C4Facet *pfctIcon, CStdFont *pUseFont)
112  {
113  // caption by gfx?
114  if (pfctClip && pfctIcon)
115  {
116  if (piWdt) *piWdt = Tabular::GetLeftClipSize(pfctClip);
117  if (piHgt) *piHgt = pfctClip->Hgt;
118  return;
119  }
120  // caption by text
121  int32_t iWdt, iHgt;
122  CStdFont &rUseFont = pUseFont ? *pUseFont : (fLarge ? ::GraphicsResource.CaptionFont : ::GraphicsResource.TextFont);
123  if (!rUseFont.GetTextExtent(sTitle.getData(), iWdt, iHgt, fTitleMarkup))
124  {
125  iWdt=70; iHgt=rUseFont.GetLineHeight();
126  }
127  if (fLarge) { iWdt = iWdt * 6 / 5; iHgt = iHgt * 6 / 5; }
128  // add icon width
129  if (icoTitle>=0) iWdt += iHgt + fLarge*2;
130  // add close button width
131  if (fHasCloseButton) iWdt += iHgt + fLarge*2;
132  // assign output vars
133  if (piWdt) *piWdt = iWdt;
134  if (piHgt) *piHgt = iHgt;
135  }
136 
137  bool Tabular::Sheet::IsPosOnCloseButton(int32_t x, int32_t y, int32_t iCaptWdt, int32_t iCaptHgt, bool fLarge)
138  {
139  // close button is on right end of tab
140  return fHasCloseButton && Inside<int32_t>(x, iCaptWdt-iCaptHgt+1, iCaptWdt-2) && Inside<int32_t>(y, 1, iCaptHgt-2);
141  }
142 
143  void Tabular::Sheet::SetTitle(const char *szNewTitle)
144  {
145  if (sTitle == szNewTitle) return;
146  if (szNewTitle)
147  {
148  sTitle.Copy(szNewTitle);
149  if (fTitleMarkup) ExpandHotkeyMarkup(sTitle, cHotkey);
150  }
151  else
152  {
153  sTitle.Clear();
154  cHotkey = '\0';
155  }
156  Tabular *pTabular = static_cast<Tabular *>(GetParent());
157  if (pTabular) pTabular->SheetsChanged();
158  }
159 
161  {
162  Tabular *pTabular = static_cast<Tabular *>(GetParent());
163  if (pTabular) return pTabular->GetActiveSheet() == this;
164  return false;
165  }
166 
167 // ----------------------------------------------------
168 // Tabular
169 
170  Tabular::Tabular(C4Rect &rtBounds, TabPosition eTabPos) : Control(rtBounds), pActiveSheet(nullptr), eTabPos(eTabPos), iMaxTabWidth(0),
171  iCaptionLengthTotal(0), iCaptionScrollPos(0), fScrollingLeft(false), fScrollingRight(false), fScrollingLeftDown(false),
172  fScrollingRightDown(false), iSheetMargin(4), fDrawSelf(true), pfctBack(nullptr), pfctClip(nullptr), pfctIcons(nullptr), pSheetCaptionFont(nullptr)
173  {
174  // calc client rect
175  UpdateOwnPos();
176  // key bindings for tab selection, if this is not an invisible "blind" tabular
177  if (eTabPos != tbNone)
178  {
179  // Ctrl+(Shift-)Tab works with dialog focus only (assumes max one tabular per dialog)
180  // Arrow keys work if control is focused only
182  Keys.emplace_back(K_UP);
184  {
185  ControllerKeys::Up(Keys);
186  }
187  pKeySelUp = new C4KeyBinding(Keys, "GUITabularSelUp", KEYSCOPE_Gui,
189 
190  Keys.clear();
191  Keys.emplace_back(K_DOWN);
193  {
194  ControllerKeys::Down(Keys);
195  }
196  pKeySelDown = new C4KeyBinding(Keys, "GUITabularSelDown", KEYSCOPE_Gui,
198 
199  pKeySelUp2 = new C4KeyBinding(C4KeyCodeEx(K_TAB, C4KeyShiftState(KEYS_Shift | KEYS_Control)), "GUITabularSelUp2", KEYSCOPE_Gui,
201  pKeySelDown2 = new C4KeyBinding(C4KeyCodeEx(K_TAB, KEYS_Control), "GUITabularSelDown2", KEYSCOPE_Gui,
203  pKeyCloseTab = new C4KeyBinding(C4KeyCodeEx(K_F4, KEYS_Control), "GUITabularCloseTab", KEYSCOPE_Gui,
205  }
206  else
207  {
208  pKeySelUp = pKeySelDown = pKeySelUp2 = pKeySelDown2 = pKeyCloseTab = nullptr;
209  }
210  SheetsChanged();
211  }
212 
214  {
215  if (pKeyCloseTab) delete pKeyCloseTab;
216  if (pKeySelDown2) delete pKeySelDown2;
217  if (pKeySelUp2) delete pKeySelUp2;
218  if (pKeySelDown) delete pKeySelDown;
219  if (pKeySelUp) delete pKeySelUp;
220  }
221 
223  {
224  // keyboard callback: Select previous sheet
225  int32_t iNewSel = GetActiveSheetIndex() - 1;
226  if (iNewSel < 0) iNewSel = GetSheetCount() - 1;
227  if (iNewSel < 0) return false;
228  SelectSheet(iNewSel, true);
229  return true;
230  }
231 
233  {
234  // keyboard callback: Select next sheet
235  int32_t iNewSel = GetActiveSheetIndex() + 1, iSheetCount = GetSheetCount();
236  if (iNewSel >= iSheetCount)
237  {
238  if (!iSheetCount) return false;
239  else iNewSel = 0;
240  }
241  SelectSheet(iNewSel, true);
242  return true;
243  }
244 
246  {
247  // keyboard callback: Close currnet sheet
248  // only for sheets that can be closed
249  Sheet *pCurrentSheet = GetActiveSheet();
250  if (!pCurrentSheet) return false;
251  if (!pCurrentSheet->HasCloseButton()) return false;
252  pCurrentSheet->UserClose();
253  return true;
254  }
255 
256  void Tabular::SelectionChanged(bool fByUser)
257  {
258  Control *pFocusCtrl = nullptr;
259  Dialog *pDlg = GetDlg();
260  if (pDlg) pFocusCtrl = pDlg->GetFocus();
261  // any selection?
262  if (pActiveSheet)
263  {
264  // effect
265  if (fByUser) GUISound("UI::Select");
266  // update in sheet
267  pActiveSheet->OnShown(fByUser);
268  }
269  // make only active sheet visible
270  for (Element *pSheet = GetFirst(); pSheet; pSheet = pSheet->GetNext())
271  {
272  pSheet->SetVisibility(pSheet == pActiveSheet);
273  }
274  // if nothing is selected now, but something was selected before, focus new default control
275  if (pFocusCtrl && !pDlg->GetFocus()) pDlg->SetFocus(pDlg->GetDefaultControl(), fByUser);
276  }
277 
278  void Tabular::SheetsChanged()
279  {
280  Sheet *pSheet;
281  if (eTabPos)
282  {
283  // update iMaxTabWidth by new set of sheet labels
284  iSheetOff = 20;
285  iMaxTabWidth = 20;
286  iSheetSpacing = (eTabPos == tbLeft) ? -10 : 20;
287  int32_t iSheetNum=0, iTotalHgt=iSheetOff;
288  iCaptionLengthTotal = iSheetOff;
289  for (pSheet = (Sheet *) GetFirst(); pSheet; pSheet = (Sheet *) pSheet->GetNext())
290  {
291  int32_t iTabWidth, iTabHeight;
292  pSheet->GetCaptionSize(&iTabWidth, &iTabHeight, HasLargeCaptions(), pSheet == pActiveSheet, pfctClip, pfctIcons, pSheetCaptionFont);
293  iTabWidth += (eTabPos == tbLeft) ? 20 : iSheetSpacing;
294  iMaxTabWidth = std::max(iTabWidth, iMaxTabWidth);
295  if (eTabPos == tbLeft)
296  {
297  iTotalHgt += iTabHeight;
298  if (iSheetNum++) iTotalHgt += iSheetSpacing;
299  }
300  else
301  {
302  iCaptionLengthTotal += iTabWidth;
303  }
304  }
305  // update sheet positioning
306  if (eTabPos == tbLeft && iTotalHgt > rcBounds.Hgt-GetMarginBottom())
307  {
308  // sheet captions dont fit - condense them
309  iSheetSpacing -= (iTotalHgt-rcBounds.Hgt+GetMarginBottom()-iSheetOff) / iSheetNum;
310  iSheetOff = 0;
311  }
312  else if (eTabPos == tbTop)
313  {
314  }
315  }
316  // update all sheet sizes
317  UpdateSize();
318  // update scrolling range/status
319  UpdateScrolling();
320  }
321 
322  void Tabular::UpdateScrolling()
323  {
324  // any scrolling necessary?
325  int32_t iAvailableTabSpace = rcBounds.Wdt;
326  int32_t iScrollPinSize = GetTopSize();
327  if (eTabPos != tbTop || iCaptionLengthTotal <= iAvailableTabSpace || iAvailableTabSpace <= iScrollPinSize*2)
328  {
329  fScrollingLeft = fScrollingRight = fScrollingLeftDown = fScrollingRightDown = false;
330  iCaptionScrollPos = 0;
331  }
332  else
333  {
334  // must scroll; update scrolling parameters
335  fScrollingLeft = !!iCaptionScrollPos;
336  if (!fScrollingLeft)
337  {
338  fScrollingRight = true;
339  fScrollingLeftDown = false;
340  }
341  else
342  {
343  iAvailableTabSpace -= iScrollPinSize;
344  fScrollingRight = (iCaptionLengthTotal - iCaptionScrollPos > iAvailableTabSpace);
345  // do not scroll past right end
346  if (!fScrollingRight)
347  {
348  iCaptionScrollPos = iCaptionLengthTotal - iAvailableTabSpace;
349  fScrollingRightDown = false;
350  }
351  }
352  }
353  }
354 
355  void Tabular::DoCaptionScroll(int32_t iDir)
356  {
357  // store time of scrolling change
358  tLastScrollTime = C4TimeMilliseconds::Now();
359  // change scrolling within max range
360  int32_t iAvailableTabSpace = rcBounds.Wdt;
361  int32_t iScrollPinSize = GetTopSize();
362  iCaptionScrollPos = Clamp<int32_t>(iCaptionScrollPos + iDir*iAvailableTabSpace/2, 0, iCaptionLengthTotal - iAvailableTabSpace + iScrollPinSize);
363  UpdateScrolling();
364  }
365 
367  {
368  if (!fDrawSelf) return;
369  bool fGfx = HasGfx();
370  // execute scrolling
371  bool fCaptionScrollDelayOver = C4TimeMilliseconds::Now() - tLastScrollTime >= C4GUI_TabCaptionScrollTime;
372  if ((fScrollingLeftDown || fScrollingRightDown) && fCaptionScrollDelayOver)
373  DoCaptionScroll(fScrollingRightDown - fScrollingLeftDown);
374  // border
375  if (!fGfx) Draw3DFrame(cgo, false, 1, 0xaf, eTabPos!=tbTop, GetTopSize(), eTabPos!=tbLeft, GetLeftSize());
376  // calc positions
377  int32_t x0 = cgo.TargetX + rcBounds.x + GetLeftSize(),
378  y0 = cgo.TargetY + rcBounds.y + GetTopSize(),
379  x1 = cgo.TargetX + rcBounds.x + rcBounds.Wdt - 1,
380  y1 = cgo.TargetY + rcBounds.y + rcBounds.Hgt - 1;
381  // main area BG
382  if (!fGfx) pDraw->DrawBoxDw(cgo.Surface, x0,y0,x1,y1, C4GUI_StandardBGColor);
383  // no tabs?
384  if (!eTabPos)
385  {
386  if (fGfx)
387  pfctBack->DrawX(cgo.Surface, x0, y0, x1-x0+1, y1-y0+1);
388  return;
389  }
390  bool fLeft = (eTabPos == tbLeft);
391  // top or left bar
392  int32_t d=(fLeft ? y0 : x0)+iSheetOff; // current tab position (leave some space to the left/top)
393  int32_t ad0=0,ad1=0, aCptTxX=0, aCptTxY=0;
394  // scrolling in captions
395  int32_t iScrollSize = GetTopSize();
396  if (fScrollingLeft) d -= iCaptionScrollPos + iScrollSize;
397  // tabs
398  for (Sheet *pSheet = (Sheet *) GetFirst(); pSheet; pSheet = (Sheet *) pSheet->GetNext())
399  {
400  // get tab size
401  int32_t iTabWidth, iTabHeight;
402  pSheet->GetCaptionSize(&iTabWidth, &iTabHeight, HasLargeCaptions(), pSheet == pActiveSheet, pfctClip, pfctIcons, pSheetCaptionFont);
403  // leave some space around caption
404  iTabWidth += fLeft ? 20 : iSheetSpacing;
405  iTabHeight += fLeft ? iSheetSpacing : 10;
406  // draw caption bg
407  if (!fGfx)
408  {
409  float vtx[8];
410  if (fLeft)
411  {
412  vtx[0] = x0; vtx[1] = d;
413  vtx[2] = x0-GetLeftSize(); vtx[3] = d;
414  vtx[4] = x0-GetLeftSize(); vtx[5] = d+iTabHeight;
415  vtx[6] = x0; vtx[7] = d+iTabHeight;
416  }
417  else
418  {
419  vtx[0] = d+1; vtx[1] = y0;
420  vtx[2] = d+4+1; vtx[3] = y0-GetTopSize();
421  vtx[4] = d+iTabWidth-4; vtx[5] = y0-GetTopSize();
422  vtx[6] = d+iTabWidth; vtx[7] = y0;
423  }
424  DWORD dwClr = (pSheet == pActiveSheet) ? C4GUI_ActiveTabBGColor : C4GUI_StandardBGColor;
425  pDraw->DrawQuadDw(cgo.Surface, vtx, dwClr, dwClr, dwClr, dwClr, nullptr);
426  // draw caption frame
427  // TODO: Switch to PerformMultiLines
428  pDraw->DrawLineDw(cgo.Surface, (float)vtx[0]-1 , (float)vtx[1] , (float)vtx[2]-1 ,(float)vtx[3] , C4GUI_BorderColorA1);
429  pDraw->DrawLineDw(cgo.Surface, (float)vtx[2]-1 , (float)vtx[3] , (float)vtx[4]-fLeft,(float)vtx[5] , C4GUI_BorderColorA1);
430  pDraw->DrawLineDw(cgo.Surface, (float)vtx[4] , (float)vtx[5] , (float)vtx[6] ,(float)vtx[7] , C4GUI_BorderColorA1);
431  pDraw->DrawLineDw(cgo.Surface, (float)vtx[0] , (float)vtx[1]+fLeft, (float)vtx[2] ,(float)vtx[3]+fLeft , C4GUI_BorderColorA2);
432  pDraw->DrawLineDw(cgo.Surface, (float)vtx[2]-!fLeft, (float)vtx[3]+1 , (float)vtx[4] ,(float)vtx[5]+!fLeft , C4GUI_BorderColorA2);
433  pDraw->DrawLineDw(cgo.Surface, (float)vtx[4]+1 , (float)vtx[5]+fLeft, (float)vtx[6] ,(float)vtx[7]+fLeft , C4GUI_BorderColorA2);
434  }
435  // draw caption text
436  int32_t iCptTextX = fLeft ? (x0-GetLeftSize()+10) : (d+iTabWidth/2);
437  int32_t iCptTextY = fLeft ? (d+iSheetSpacing/2) : (y0-GetTopSize()+2);
438  if (pSheet == pActiveSheet)
439  {
440  // store active sheet pos for border line or later drawing
441  ad0=d; ad1=d+(fLeft ? iTabHeight : iTabWidth);
442  aCptTxX = iCptTextX; aCptTxY = iCptTextY;
443  // draw active caption
444  if (!fGfx) pSheet->DrawCaption(cgo, iCptTextX, iCptTextY, iMaxTabWidth, fLeft, true, HasDrawFocus(), nullptr, nullptr, nullptr);
445  }
446  else
447  {
448  // draw inactive caption
449  pSheet->DrawCaption(cgo, iCptTextX, iCptTextY, iMaxTabWidth, fLeft, false, false, pfctClip, pfctIcons, pSheetCaptionFont);
450  }
451  // advance position
452  d += (fLeft ? iTabHeight : iTabWidth)+2;
453  }
454  // draw tab border line across everything but active tab
455  if (!fGfx) if (ad0||ad1)
456  {
457  pDraw->DrawLineDw(cgo.Surface, (float)x0 ,(float)y0 ,(float)(fLeft ? x0 : ad0), (float)(fLeft ? ad0 : y0), C4GUI_BorderColorA1);
458  pDraw->DrawLineDw(cgo.Surface, (float)(x0+1),(float)(y0+1),(float)((fLeft ? x0 : ad0)+1), (float)((fLeft ? ad0 : y0)+1) , C4GUI_BorderColorA2);
459  pDraw->DrawLineDw(cgo.Surface, (float)(fLeft ? x0 : ad1), (float)(fLeft ? ad1 : y0), (float)(fLeft ? x0 : x1), (float)(fLeft ? y1 : y0), C4GUI_BorderColorA1);
460  pDraw->DrawLineDw(cgo.Surface, (float)((fLeft ? x0 : ad1)+1), (float)((fLeft ? ad1 : y0)+1), (float)((fLeft ? x0 : x1)+1), (float)((fLeft ? y1 : y0)+1), C4GUI_BorderColorA2);
461  }
462  // main area bg in gfx: Atop inactive tabs
463  if (fGfx)
464  {
465  pfctBack->DrawX(cgo.Surface, x0, y0, x1-x0+1, y1-y0+1);
466  // and active tab on top of that
467  if (pActiveSheet)
468  pActiveSheet->DrawCaption(cgo, aCptTxX, aCptTxY, iMaxTabWidth, fLeft, true, HasDrawFocus(), pfctClip, pfctIcons, pSheetCaptionFont);
469  }
470  // scrolling
471  if (fScrollingLeft) ::GraphicsResource.fctBigArrows.DrawX(cgo.Surface, x0+iSheetOff,y0-iScrollSize, iScrollSize,iScrollSize, fScrollingLeftDown*2);
472  if (fScrollingRight) ::GraphicsResource.fctBigArrows.DrawX(cgo.Surface, x1-iScrollSize,y0-iScrollSize, iScrollSize,iScrollSize, 1+fScrollingRightDown*2);
473  }
474 
475  void Tabular::MouseInput(CMouse &rMouse, int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyParam)
476  {
477  // tabular contains controls?
478  if (eTabPos)
479  {
480  bool fLeft = (eTabPos == tbLeft);
481  bool fInCaptionArea = ((!fLeft && Inside<int32_t>(iY, 0, GetTopSize())) || (fLeft && Inside<int32_t>(iX, 0, GetLeftSize())));
482  if (!fInCaptionArea || iButton == C4MC_Button_LeftUp)
483  {
485  }
486  // then check for mousedown in coloumn area
487  else if ((iButton == C4MC_Button_LeftDown || iButton == C4MC_Button_None) && fInCaptionArea)
488  {
489  int32_t d=iSheetOff;
490  // check inside scrolling buttons
491  bool fProcessed = false;
492  if (fScrollingLeft || fScrollingRight)
493  {
494  int32_t iScrollSize = GetTopSize();
495  if (iButton == C4MC_Button_LeftDown && fScrollingRight && Inside(iX, rcBounds.Wdt-iScrollSize,rcBounds.Wdt))
496  {
497  fProcessed = fScrollingRightDown = true;
498  GUISound("UI::Select");
499  DoCaptionScroll(+1);
500  }
501  else if (fScrollingLeft)
502  {
503  if (iButton == C4MC_Button_LeftDown && Inside(iX, d,d+iScrollSize))
504  {
505  fProcessed = fScrollingLeftDown = true;
506  GUISound("UI::Select");
507  DoCaptionScroll(-1);
508  }
509  d -= iCaptionScrollPos + iScrollSize;
510  }
511  }
512  // check on sheet captions
513  if (!fProcessed) for (Sheet *pSheet = (Sheet *) GetFirst(); pSheet; pSheet = (Sheet *) pSheet->GetNext())
514  {
515  // default: Mouse not on close button
516  pSheet->SetCloseButtonHighlight(false);
517  // get tab width
518  int32_t iCaptWidth,iCaptHeight,iTabWidth,iTabHeight;
519  pSheet->GetCaptionSize(&iCaptWidth, &iCaptHeight, HasLargeCaptions(), pSheet == pActiveSheet, pfctClip, pfctIcons, pSheetCaptionFont);
520  iTabWidth = iCaptWidth + (fLeft ? 20 : iSheetSpacing);
521  iTabHeight = iCaptHeight + (fLeft ? iSheetSpacing : 10);
522  // check containment in this tab (check rect only, may catch some side-clicks...)
523  if ((!fLeft && Inside(iX, d, d+iTabWidth)) || (fLeft && Inside(iY, d, d+iTabHeight)))
524  {
525  // close button
526  if (pSheet->IsPosOnCloseButton(iX-d*!fLeft-(iTabWidth-iCaptWidth)/2, iY-d*fLeft, iCaptWidth, iCaptHeight, HasLargeCaptions()))
527  {
528  if (iButton == C4MC_Button_LeftDown)
529  {
530  // Closing: Callback to sheet
531  pSheet->UserClose();
532  }
533  else
534  // just moving :Highlight
535  pSheet->SetCloseButtonHighlight(true);
536  }
537  // mouse press outside close button area: Switch sheet
538  else if (iButton == C4MC_Button_LeftDown)
539  {
540  if (pSheet != pActiveSheet)
541  {
542  pActiveSheet = pSheet;
543  SelectionChanged(true);
544  }
545  }
546  break;
547  }
548  // next tab
549  d += (fLeft ? iTabHeight : iTabWidth)+2;
550  }
551  }
552  }
553  // inherited
554  Control::MouseInput(rMouse, iButton, iX, iY, dwKeyParam);
555  }
556 
558  {
559  // no more close buttons or scroll buttons highlighted
560  for (Sheet *pSheet = (Sheet *) GetFirst(); pSheet; pSheet = (Sheet *) pSheet->GetNext())
561  {
562  // default: Mouse not on close button
563  pSheet->SetCloseButtonHighlight(false);
564  }
565  if (fScrollingLeftDown || fScrollingRightDown)
566  {
567  // stop scrolling
568  GUISound("UI::Select");
569  fScrollingLeftDown = fScrollingRightDown = false;
570  }
571  }
572 
574  {
576  // inherited
577  Control::MouseLeave(rMouse);
578  }
579 
580  void Tabular::OnGetFocus(bool fByMouse)
581  {
582  // inherited (tooltip)
583  Control::OnGetFocus(fByMouse);
584  }
585 
587  {
588  // inherited
589  Control::RemoveElement(pChild);
590  // clear selection var
591  if (pChild == pActiveSheet)
592  {
593  // select new active sheet
594  pActiveSheet = (Sheet *) GetFirst();
595  SelectionChanged(false);
596  }
597  // update sheet labels
598  SheetsChanged();
599  }
600 
601  Tabular::Sheet *Tabular::AddSheet(const char *szTitle, int32_t icoTitle)
602  {
603  // create new sheet in client area
604  Sheet *pNewSheet = new Sheet(szTitle, GetContainedClientRect(), icoTitle);
605  AddCustomSheet(pNewSheet);
606  // k, new sheet ready!
607  return pNewSheet;
608  }
609 
611  {
612  AddElement(pAddSheet);
613  // select it if it's first
614  pAddSheet->SetVisibility(!pActiveSheet);
615  if (!pActiveSheet) pActiveSheet = pAddSheet;
616  // update sheet labels
617  SheetsChanged();
618  }
619 
621  {
622  // del all sheets
623  Sheet *pSheet;
624  while ((pSheet = GetSheet(0))) delete pSheet;
625  SheetsChanged();
626  }
627 
628  void Tabular::SelectSheet(int32_t iIndex, bool fByUser)
629  {
630  pActiveSheet = GetSheet(iIndex);
631  SelectionChanged(fByUser);
632  }
633 
634  void Tabular::SelectSheet(Sheet *pSelSheet, bool fByUser)
635  {
636  pActiveSheet = pSelSheet;
637  SelectionChanged(fByUser);
638  }
639 
641  {
642  int32_t i=-1;
643  Sheet *pSheet;
644  while ((pSheet = GetSheet(++i))) if (pSheet == pActiveSheet) return i;
645  return -1;
646  }
647 
648  void Tabular::SetGfx(C4Facet *pafctBack, C4Facet *pafctClip, C4Facet *pafctIcons, CStdFont *paSheetCaptionFont, bool fResizeByAspect)
649  {
650  // set gfx files
651  pfctBack=pafctBack;
652  pfctClip=pafctClip;
653  pfctIcons=pafctIcons;
654  pSheetCaptionFont=paSheetCaptionFont;
655  // make sure aspect of background is used correctly
656  if (pfctBack && fResizeByAspect)
657  {
658  int32_t iEffWdt = rcBounds.Wdt - GetLeftSize(), iEffHgt = rcBounds.Hgt - GetTopSize();
659  if (iEffWdt * pfctBack->Hgt > pfctBack->Wdt * iEffHgt)
660  {
661  // control is too wide: center it
662  int32_t iOversize = iEffWdt - pfctBack->Wdt * iEffHgt / pfctBack->Hgt;
663  C4Rect rtBounds = GetBounds();
664  rtBounds.x += iOversize/2;
665  rtBounds.Wdt -= iOversize;
666  SetBounds(rtBounds);
667  }
668  else
669  {
670  // control is too tall: cap at bottom
671  int32_t iOversize = iEffHgt - pfctBack->Hgt * iEffWdt / pfctBack->Wdt;
672  C4Rect rtBounds = GetBounds();
673  rtBounds.y += iOversize;
674  rtBounds.Hgt -= iOversize;
675  SetBounds(rtBounds);
676  }
677  }
678  SheetsChanged();
679  }
680 
682  {
684  // update all sheets
685  for (Sheet *pSheet = static_cast<Sheet *>(GetFirst()); pSheet; pSheet = static_cast<Sheet *>(pSheet->GetNext()))
686  pSheet->SetBounds(GetContainedClientRect());
687  }
688 
689 
690 } // end of namespace
691 
bool HasCloseButton() const
Definition: C4Gui.h:1629
bool IsPosOnCloseButton(int32_t x, int32_t y, int32_t iCaptWdt, int32_t iCaptHgt, bool fLarge)
#define C4GUI_CaptionFontClr
Definition: C4Gui.h:37
#define C4GUI_StandardBGColor
Definition: C4Gui.h:66
C4Config Config
Definition: C4Config.cpp:833
const int32_t C4MC_Button_LeftDown
int GetLineHeight() const
Definition: C4FontLoader.h:125
void GUISound(const char *szSound)
Definition: C4Gui.cpp:1175
void DrawElement(C4TargetFacet &cgo) override
void GetCaptionSize(int32_t *piWdt, int32_t *piHgt, bool fLarge, bool fActive, C4Facet *pfctClip, C4Facet *pfctIcon, CStdFont *pUseFont)
void Up(T &keys)
virtual void UserClose()
Definition: C4Gui.h:1628
void Down(T &keys)
#define C4GUI_GfxTabCaptInactiveClr
Definition: C4Gui.h:57
#define C4GUI_TabCaptionScrollTime
Definition: C4Gui.h:149
void ResetBlitMode()
Definition: C4Draw.h:192
Tabular(C4Rect &rtBounds, TabPosition eTabPos)
void OnGetFocus(bool fByMouse) override
C4KeyShiftState
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:567
#define C4GFXBLIT_ADDITIVE
Definition: C4Surface.h:26
virtual void OnShown(bool fByUser)
Definition: C4Gui.h:1618
static int32_t GetLeftClipSize(C4Facet *pfctForClip)
Definition: C4Gui.h:1712
Definition: C4Rect.h:27
void SetTitle(const char *szNewTitle)
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
bool GetTextExtent(const char *szText, int32_t &rsx, int32_t &rsy, bool fCheckMarkup=true)
int32_t GetTopSize()
Definition: C4Gui.h:1679
void AddElement(Element *pChild)
#define C4GUI_BorderColorA2
Definition: C4Gui.h:89
virtual void UpdateSize()
Definition: C4Gui.cpp:185
C4Rect GetContainedClientRect()
Definition: C4Gui.h:448
StdStrBuf sTitle
Definition: C4Gui.h:1607
C4GraphicsResource GraphicsResource
void SelectSheet(int32_t iIndex, bool fByUser)
void DrawLineDw(C4Surface *sfcTarget, float x1, float y1, float x2, float y2, DWORD dwClr, float width=1.0f)
Definition: C4Draw.cpp:614
~Tabular() override
void SetBlitMode(DWORD dwBlitMode)
Definition: C4Draw.h:191
#define C4GUI_BorderColorA1
Definition: C4Gui.h:88
bool HasLargeCaptions()
Definition: C4Gui.h:1681
int32_t GetSheetCount()
Definition: C4Gui.h:1709
friend class Sheet
Definition: C4Gui.h:1716
int32_t Wdt
Definition: C4Rect.h:30
bool ExpandHotkeyMarkup(StdStrBuf &sText, uint32_t &rcHotkey, bool for_tooltip)
Definition: C4Gui.cpp:38
std::vector< C4KeyCodeEx > CodeList
void MouseLeave(CMouse &rMouse) override
const int32_t C4MC_Button_LeftUp
int32_t y
Definition: C4Rect.h:30
Element * GetFirst()
Definition: C4Gui.h:829
uint32_t cHotkey
Definition: C4Gui.h:1609
const int ACenter
Definition: C4Surface.h:41
virtual void OnGetFocus(bool fByMouse)
Definition: C4Gui.h:1056
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
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)
void DrawBoxDw(C4Surface *sfcDest, int iX1, int iY1, int iX2, int iY2, DWORD dwClr)
Definition: C4Draw.cpp:846
void SetGfx(C4Facet *pafctBack, C4Facet *pafctClip, C4Facet *pafctIcons, CStdFont *paSheetCaptionFont, bool fResizeByAspect)
C4Rect rcBounds
Definition: C4Gui.h:385
void DrawQuadDw(C4Surface *sfcTarget, float *ipVtx, DWORD dwClr1, DWORD dwClr2, DWORD dwClr3, DWORD dwClr4, C4ShaderCall *shader_call)
Definition: C4Draw.cpp:659
C4FacetID fctButtonHighlightRound
#define C4GUI_InactCaptionFontClr
Definition: C4Gui.h:39
void Draw(C4Facet &cgo, bool fAspect=true, int32_t iPhaseX=0, int32_t iPhaseY=0, bool fTransparent=true)
Definition: C4Facet.cpp:154
Container * GetParent()
Definition: C4Gui.h:429
void AddCustomSheet(Sheet *pAddSheet)
C4Draw * pDraw
Definition: C4Draw.cpp:42
Sheet * GetSheet(int32_t iIndex)
Definition: C4Gui.h:1706
int32_t GetMarginBottom() override
Definition: C4Gui.h:1686
#define C4GUI_GfxTabCaptActiveClr
Definition: C4Gui.h:56
C4Rect & GetBounds()
Definition: C4Gui.h:445
virtual class Dialog * GetDlg()
Definition: C4Gui.cpp:288
int32_t GetLeftSize()
Definition: C4Gui.h:1680
Icons
Definition: C4Gui.h:637
void RemoveElement(Element *pChild) override
void RemoveElement(Element *pChild) override
int32_t x
Definition: C4Rect.h:30
int32_t GamepadGuiControl
Definition: C4Config.h:229
Element * GetNext() const
Definition: C4Gui.h:449
float TargetX
Definition: C4Facet.h:165
void SetFocus(Control *pCtrl, bool fByMouse)
C4ConfigControls Controls
Definition: C4Config.h:259
float Hgt
Definition: C4Facet.h:118
void SetBounds(const C4Rect &rcNewBound)
Definition: C4Gui.h:446
Sheet * GetActiveSheet()
Definition: C4Gui.h:1707
void SetVisibility(bool fToValue) override
void UpdateOwnPos() override
void MouseInput(CMouse &rMouse, int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyParam) override
const int ALeft
Definition: C4Surface.h:41
void MouseLeaveCaptionArea()
const int32_t C4MC_Button_None
void DeactivateBlitModulation()
Definition: C4Draw.h:189
Sheet * AddSheet(const char *szTitle, int32_t icoTitle=Ico_None)
void ActivateBlitModulation(DWORD dwWithClr)
Definition: C4Draw.h:188
int32_t Hgt
Definition: C4Rect.h:30
C4Surface * Surface
Definition: C4Facet.h:117
float TargetY
Definition: C4Facet.h:165
#define C4GUI_ActiveTabBGColor
Definition: C4Gui.h:67
uint32_t DWORD
void Copy()
Definition: StdBuf.h:467
float Wdt
Definition: C4Facet.h:118
bool Inside(T ival, U lbound, V rbound)
Definition: Standard.h:43
float X
Definition: C4Facet.h:118
Sheet(const char *szTitle, const C4Rect &rcBounds, int32_t icoTitle=Ico_None, bool fHasCloseButton=false, bool fTitleMarkup=true)
static C4Facet GetIconFacet(Icons icoIconIndex)
virtual class Control * GetDefaultControl()
Definition: C4Gui.h:2129
static C4TimeMilliseconds Now()
virtual void MouseLeave(CMouse &rMouse)
Definition: C4Gui.h:414
void UpdateSize() override
int32_t GetActiveSheetIndex()
Control * GetFocus()
Definition: C4Gui.h:2115
void MouseInput(CMouse &rMouse, int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyParam) override