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