OpenClonk
C4GuiComboBox.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 // dropdown box
18 // implemented via context menu
19 
20 #include "C4Include.h"
21 #include "gui/C4Gui.h"
22 
23 #include "graphics/C4Draw.h"
24 #include "graphics/C4FacetEx.h"
26 #include "gui/C4MouseControl.h"
27 
28 namespace C4GUI
29 {
30 
31 // ----------------------------------------------------
32 // ComboBox_FillCB
33 
34  void ComboBox_FillCB::AddEntry(const char *szText, int32_t id)
35  {
36  if (!szText) szText = "";
38  Handler *pHandler = new Handler(pCombo, &ComboBox::OnCtxComboSelect);
39  pHandler->SetExtra(ComboBox::ComboMenuCBStruct(szText, id));
40  pDrop->AddItem(szText, FormatString(LoadResStr("IDS_MSG_SELECT"), szText).getData(), Ico_Empty, pHandler);
41  }
42 
43  bool ComboBox_FillCB::FindEntry(const char *szText)
44  {
45  // check for entry with same name
46  ContextMenu::Entry *pEntry; int32_t idx=0;
47  while ((pEntry = pDrop->GetIndexedEntry(idx++))) if (SEqual(pEntry->GetText(), szText)) return true;
48  return false;
49  }
50 
51  void ComboBox_FillCB::SelectEntry(int32_t iEntry)
52  {
53  pDrop->SelectItem(iEntry);
54  }
55 
57  {
58  pDrop->Clear();
59  }
60 
61 
62 // ----------------------------------------------------
63 // ComboBox
64 
65  ComboBox::ComboBox(const C4Rect &rtBounds) :
66  Control(rtBounds), iOpenMenu(0), pFillCallback(nullptr), fReadOnly(false), fSimple(false), fMouseOver(false),
67  pUseFont(nullptr), dwFontClr(C4GUI_ComboFontClr), dwBGClr(C4GUI_StandardBGColor), dwBorderClr(0), pFctSideArrow(nullptr)
68  {
69  *Text=0;
70  // key callbacks - lots of possibilities to get the dropdown
71  C4CustomKey::CodeList cbKeys;
72  cbKeys.emplace_back(K_DOWN);
73  cbKeys.emplace_back(K_SPACE);
74  cbKeys.emplace_back(K_DOWN, KEYS_Alt);
75  cbKeys.emplace_back(K_SPACE, KEYS_Alt);
77  {
78  ControllerKeys::Ok(cbKeys);
79  ControllerKeys::Down(cbKeys);
80  }
81  pKeyOpenCombo = new C4KeyBinding(cbKeys, "GUIComboOpen", KEYSCOPE_Gui,
82  new ControlKeyCB<ComboBox>(*this, &ComboBox::KeyDropDown), C4CustomKey::PRIO_Ctrl);
83  cbKeys.clear();
84  cbKeys.emplace_back(K_ESCAPE);
86  {
87  ControllerKeys::Cancel(cbKeys);
88  }
89  pKeyCloseCombo = new C4KeyBinding(cbKeys, "GUIComboClose", KEYSCOPE_Gui,
90  new ControlKeyCB<ComboBox>(*this, &ComboBox::KeyAbortDropDown), C4CustomKey::PRIO_Ctrl);
91  }
92 
94  {
95  delete pKeyCloseCombo;
96  delete pKeyOpenCombo;
97  if (pFillCallback) delete pFillCallback;
98  }
99 
100  void ComboBox::SetComboCB(ComboBox_FillCB *pNewFillCallback)
101  {
102  if (pFillCallback) delete pFillCallback;
103  pFillCallback = pNewFillCallback;
104  }
105 
106  bool ComboBox::DoDropdown()
107  {
108  // not if readonly
109  if (fReadOnly) return false;
110  // get dropdown pos
111  int32_t iX = 0;
112  int32_t iY = rcBounds.Hgt;
113  // do dropdown
114  Screen *pScreen = GetScreen();
115  if (!pScreen) return false;
116  // item list as context menu
117  if (!pFillCallback) return false;
118  ContextMenu *pNewMenu = new C4GUI::ContextMenu();
119  // init with minimum size
120  pNewMenu->GetBounds().Wdt = std::max(rcBounds.Wdt, pNewMenu->GetBounds().Wdt);
121  // fill with items
122  pFillCallback->FillDropDown(this, pNewMenu);
123  // open it on screen
124  pScreen->DoContext(pNewMenu, this, iX, iY);
125  // store menu
126  iOpenMenu = pNewMenu->GetMenuIndex();
127  // done, success
128  return true;
129  }
130 
131  bool ComboBox::AbortDropdown(bool fByUser)
132  {
133  // recheck open menu
134  Screen *pScr = GetScreen();
135  if (!pScr || (iOpenMenu != pScr->GetLastContextMenuIndex())) iOpenMenu = 0;
136  if (!iOpenMenu) return false;
137  // abort it
138  pScr->AbortContext(fByUser);
139  return true;
140  }
141 
143  {
144  CStdFont *pUseFont = this->pUseFont ? this->pUseFont : &(::GraphicsResource.TextFont);
145  // recheck open menu
146  Screen *pScr = GetScreen();
147  if (!pScr || (iOpenMenu != pScr->GetContextMenuIndex())) iOpenMenu = 0;
148  // calc drawing bounds
149  int32_t x0 = cgo.TargetX + rcBounds.x, y0 = cgo.TargetY + rcBounds.y;
150  int32_t iRightTextEnd = x0 + rcBounds.Wdt - ::GraphicsResource.fctContext.Wdt - 1;
151  if (!fReadOnly && !fSimple)
152  {
153  // draw background
154  pDraw->DrawBoxDw(cgo.Surface, x0,y0,x0+rcBounds.Wdt-1,y0+rcBounds.Hgt-1,dwBGClr);
155  // draw frame
156  if (dwBorderClr)
157  {
158  int32_t x1=cgo.TargetX+rcBounds.x,y1=cgo.TargetY+rcBounds.y,x2=x1+rcBounds.Wdt,y2=y1+rcBounds.Hgt;
159  pDraw->DrawFrameDw(cgo.Surface, x1, y1, x2, y2-1, dwBorderClr);
160  pDraw->DrawFrameDw(cgo.Surface, x1+1, y1+1, x2-1, y2-2, dwBorderClr);
161  }
162  else
163  // default frame color
164  Draw3DFrame(cgo);
165  // draw button; down (phase 1) if combo is down
166  (pFctSideArrow ? pFctSideArrow : &(::GraphicsResource.fctContext))->Draw(cgo.Surface, iRightTextEnd, y0 + (rcBounds.Hgt-::GraphicsResource.fctContext.Hgt)/2, iOpenMenu ? 1 : 0);
167  }
168  else if (!fReadOnly)
169  {
170  // draw button in simple mode: Left of text
171  (pFctSideArrow ? pFctSideArrow : &(::GraphicsResource.fctContext))->Draw(cgo.Surface, x0, y0 + (rcBounds.Hgt-::GraphicsResource.fctContext.Hgt)/2, iOpenMenu ? 1 : 0);
172  }
173  // draw text
174  if (*Text)
175  {
177  pDraw->SubPrimaryClipper(x0,y0,iRightTextEnd-1,y0+rcBounds.Hgt-1);
178  pDraw->TextOut(Text, *pUseFont, 1.0f, cgo.Surface, x0 + ::GraphicsResource.fctContext.Wdt + 2, y0 + (rcBounds.Hgt-pUseFont->GetLineHeight())/2, dwFontClr, ALeft);
180  }
181  // draw selection highlight
182  if ((HasDrawFocus() || iOpenMenu || fMouseOver) && !fReadOnly)
183  {
186  pDraw->ResetBlitMode();
187  }
188  }
189 
190  void ComboBox::MouseInput(CMouse &rMouse, int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyParam)
191  {
192  // left-click activates menu
193  if (!fReadOnly) if (iButton == C4MC_Button_LeftDown)
194  {
195  // recheck open menu
196  Screen *pScr = GetScreen();
197  if (!pScr || (iOpenMenu != pScr->GetLastContextMenuIndex())) iOpenMenu = 0;
198  if (iOpenMenu)
199  // left-click with combo down: abort has been done by screen; ignore
200  return;
201  else
202  // otherwise, open it
203  if (DoDropdown()) return;
204  }
205  // inherited
206  Control::MouseInput(rMouse, iButton, iX, iY, dwKeyParam);
207  }
208 
210  {
211  fMouseOver = true;
212  Control::MouseEnter(rMouse);
213  }
214 
216  {
217  fMouseOver = false;
218  Control::MouseLeave(rMouse);
219  }
220 
222  {
224  }
225 
226  void ComboBox::SetText(const char *szToText)
227  {
228  // set text without accelerator keys
229  if (szToText)
230  {
231  StdStrBuf sTxt(szToText);
232  sTxt.Replace("&", "");
233  SCopy(sTxt.getData(), Text, C4MaxTitle);
234  }
235  else
236  *Text=0;
237  }
238 
240  {
241  // ignore in readonly
242  if (fReadOnly) return;
243  // do callback
244  if (!pFillCallback || !pFillCallback->OnComboSelChange(this, rNewSel.id))
245  // callback didn't process: default behaviour
246  SetText(rNewSel.sText.getData());
247  // don't do anything else, because this might be deleted
248  }
249 
250 } // namespace C4GUI
C4Config Config
Definition: C4Config.cpp:930
const size_t C4MaxTitle
Definition: C4Constants.h:25
C4Draw * pDraw
Definition: C4Draw.cpp:42
C4GraphicsResource GraphicsResource
#define C4GUI_StandardBGColor
Definition: C4Gui.h:66
#define C4GUI_ComboFontClr
Definition: C4Gui.h:47
@ KEYSCOPE_Gui
@ KEYS_Alt
const char * LoadResStr(const char *id)
Definition: C4Language.h:83
const int32_t C4MC_Button_LeftDown
const int ALeft
Definition: C4Surface.h:41
#define C4GFXBLIT_ADDITIVE
Definition: C4Surface.h:26
uint32_t DWORD
void SCopy(const char *szSource, char *sTarget, size_t iMaxL)
Definition: Standard.cpp:152
bool SEqual(const char *szStr1, const char *szStr2)
Definition: Standard.h:93
StdStrBuf FormatString(const char *szFmt,...)
Definition: StdBuf.cpp:270
int32_t GamepadGuiControl
Definition: C4Config.h:233
C4ConfigControls Controls
Definition: C4Config.h:263
std::vector< C4KeyCodeEx > CodeList
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
bool RestorePrimaryClipper()
Definition: C4Draw.cpp:210
void SetBlitMode(DWORD dwBlitMode)
Definition: C4Draw.h:191
void DrawBoxDw(C4Surface *sfcDest, int iX1, int iY1, int iX2, int iY2, DWORD dwClr)
Definition: C4Draw.cpp:840
bool StorePrimaryClipper()
Definition: C4Draw.cpp:203
void ResetBlitMode()
Definition: C4Draw.h:192
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
float Hgt
Definition: C4Facet.h:118
float Wdt
Definition: C4Facet.h:118
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 AddEntry(const char *szText, int32_t id)
void SelectEntry(int32_t iEntry)
virtual bool OnComboSelChange(ComboBox *pForCombo, int32_t idNewSelection)=0
bool FindEntry(const char *szText)
void FillDropDown(ComboBox *pComboBox, ContextMenu *pDropdownList)
Definition: C4Gui.h:1931
void DrawElement(C4TargetFacet &cgo) override
static int32_t GetDefaultHeight()
void SetComboCB(ComboBox_FillCB *pNewFillCallback)
void OnCtxComboSelect(C4GUI::Element *pListItem, const ComboMenuCBStruct &rNewSel)
void SetText(const char *szToText)
void MouseLeave(CMouse &rMouse) override
void MouseInput(CMouse &rMouse, int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyParam) override
ComboBox(const C4Rect &rtBounds)
~ComboBox() override
void MouseEnter(CMouse &rMouse) override
Definition: C4Gui.h:1792
const char * GetText()
Definition: C4Gui.h:1824
void AddItem(const char *szText, const char *szToolTip=nullptr, Icons icoIcon=Ico_None, MenuHandler *pMenuHandler=nullptr, ContextHandler *pSubmenuHandler=nullptr)
Definition: C4Gui.h:1874
int32_t GetMenuIndex()
Definition: C4Gui.h:1884
Entry * GetIndexedEntry(int32_t iIndex)
Definition: C4Gui.h:1880
void SelectItem(int32_t iIndex)
Definition: C4GuiMenu.cpp:549
void MouseInput(CMouse &rMouse, int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyParam) override
C4Rect rcBounds
Definition: C4Gui.h:385
virtual Screen * GetScreen()
Definition: C4Gui.cpp:289
virtual void MouseEnter(CMouse &rMouse)
Definition: C4Gui.h:413
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
int32_t GetContextMenuIndex()
Definition: C4Gui.h:2658
int32_t GetLastContextMenuIndex()
Definition: C4Gui.h:2659
void DoContext(ContextMenu *pNewCtx, Element *pAtElement, int32_t iX, int32_t iY)
Definition: C4Gui.cpp:971
C4FacetID fctButtonHighlightRound
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
float TargetY
Definition: C4Facet.h:165
float TargetX
Definition: C4Facet.h:165
int GetLineHeight() const
Definition: C4FontLoader.h:125
int Replace(const char *szOld, const char *szNew, size_t iStartSearch=0)
Definition: StdBuf.cpp:284
const char * getData() const
Definition: StdBuf.h:442
@ Ico_Empty
Definition: C4Gui.h:639
void Ok(T &keys)
void Down(T &keys)
void Cancel(T &keys)