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 // that which can be pressed 18 19 #include "C4Include.h" 20 #include "gui/C4Gui.h" 21 22 #include "graphics/C4Draw.h" 23 #include "graphics/C4GraphicsResource.h" 24 #include "gui/C4MouseControl.h" 25 26 namespace C4GUI 27 { 28 29 30 // -------------------------------------------------- 31 // Button 32 Button(const char * szBtnText,const C4Rect & rtBounds)33 Button::Button(const char *szBtnText, const C4Rect &rtBounds) 34 : Control(rtBounds), pCustomGfx(nullptr), pCustomGfxDown(nullptr), fDown(false), fMouseOver(false), fEnabled(true), 35 dwCustomFontClr(0), pCustomFont(nullptr) 36 { 37 // key callbacks 38 C4CustomKey::CodeList keys; 39 keys.emplace_back(K_SPACE); 40 keys.emplace_back(K_RETURN); 41 if (Config.Controls.GamepadGuiControl) 42 ControllerKeys::Ok(keys); 43 pKeyButton = new C4KeyBinding(keys, "GUIButtonPress", KEYSCOPE_Gui, 44 new ControlKeyCB<Button>(*this, &Button::KeyButtonDown, &Button::KeyButtonUp), C4CustomKey::PRIO_Ctrl); 45 sText = ""; 46 // set new button text 47 SetText(szBtnText); 48 } 49 ~Button()50 Button::~Button() 51 { 52 delete pKeyButton; 53 } 54 SetText(const char * szToText)55 void Button::SetText(const char *szToText) 56 { 57 // set new button text 58 if (szToText) 59 { 60 sText.Copy(szToText); 61 // expand hotkey markup 62 ExpandHotkeyMarkup(sText, cHotkey); 63 } 64 else 65 { 66 sText=""; 67 cHotkey=0; 68 } 69 } 70 OnHotkey(uint32_t cHotkey)71 bool Button::OnHotkey(uint32_t cHotkey) 72 { 73 // if hotkey matches, press the button 74 if (this->cHotkey == cHotkey && fEnabled) 75 { 76 OnPress(); 77 return true; 78 } 79 else return false; 80 } 81 DrawElement(C4TargetFacet & cgo)82 void Button::DrawElement(C4TargetFacet &cgo) 83 { 84 // draw base 85 if (fDown) 86 // pressed 87 DrawBar(cgo, pCustomGfxDown ? *pCustomGfxDown : ::GraphicsResource.barButtonD); 88 else 89 // released 90 DrawBar(cgo, pCustomGfx ? *pCustomGfx : ::GraphicsResource.barButton); 91 // get text pos 92 int32_t x0 = cgo.TargetX + rcBounds.x, y0 = cgo.TargetY + rcBounds.y, x1 = cgo.TargetX + rcBounds.x + rcBounds.Wdt - 1, y1 = cgo.TargetY + rcBounds.y + rcBounds.Hgt - 1; 93 int32_t iTxtOff = fDown ? 1 : 0; 94 // draw selection highlight 95 if (fEnabled) if (HasDrawFocus() || (fMouseOver && IsInActiveDlg(false))) 96 { 97 pDraw->SetBlitMode(C4GFXBLIT_ADDITIVE); 98 ::GraphicsResource.fctButtonHighlight.DrawX(cgo.Surface, x0+5, y0+3, rcBounds.Wdt-10, rcBounds.Hgt-6); 99 pDraw->ResetBlitMode(); 100 } 101 // draw text 102 int32_t iTextHgt = rcBounds.Hgt-2; 103 CStdFont &rUseFont = 104 (::GraphicsResource.TitleFont.GetLineHeight() > iTextHgt ? 105 (::GraphicsResource.CaptionFont.GetLineHeight() > iTextHgt ? 106 ::GraphicsResource.TextFont : 107 ::GraphicsResource.CaptionFont) : 108 ::GraphicsResource.TitleFont); 109 iTextHgt = rUseFont.GetLineHeight(); 110 pDraw->TextOut(sText.getData(), rUseFont, 1.0f, cgo.Surface, (x0+x1)/2 + iTxtOff, (y0+y1-iTextHgt)/2 + iTxtOff, C4GUI_ButtonFontClr, ACenter, true); 111 } 112 KeyButtonDown()113 bool Button::KeyButtonDown() 114 { 115 // not on disabled 116 if (!fEnabled) return false; 117 // space downs button 118 SetDown(); 119 return true; 120 } 121 KeyButtonUp()122 bool Button::KeyButtonUp() 123 { 124 // space press activates button 125 if (!fDown) return false; 126 SetUp(true); 127 if (fEnabled) OnPress(); 128 return true; 129 } 130 MouseInput(CMouse & rMouse,int32_t iButton,int32_t iX,int32_t iY,DWORD dwKeyParam)131 void Button::MouseInput(CMouse &rMouse, int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyParam) 132 { 133 // inherited 134 Control::MouseInput(rMouse, iButton, iX, iY, dwKeyParam); 135 // process left down and up 136 if (fEnabled) switch (iButton) 137 { 138 case C4MC_Button_LeftDown: 139 140 // mark button as being down 141 SetDown(); 142 // remember drag target 143 // no dragging movement will be done w/o drag component assigned 144 // but it should be remembered if the user leaves the button with the mouse down 145 // and then re-enters w/o having released the button 146 if (!rMouse.pDragElement) rMouse.pDragElement = this; 147 break; 148 149 case C4MC_Button_LeftUp: 150 // only if button was down... (might have dragged here) 151 if (fDown) 152 { 153 // it's now up :) 154 SetUp(true); 155 // process event 156 OnPress(); 157 } 158 break; 159 }; 160 } 161 MouseEnter(CMouse & rMouse)162 void Button::MouseEnter(CMouse &rMouse) 163 { 164 Control::MouseEnter(rMouse); 165 // remember mouse state for button highlight 166 fMouseOver = true; 167 // mouse re-enters with left button down? 168 if (rMouse.pDragElement == this) if (fEnabled) SetDown(); 169 } 170 MouseLeave(CMouse & rMouse)171 void Button::MouseLeave(CMouse &rMouse) 172 { 173 Control::MouseLeave(rMouse); 174 // mouse left 175 fMouseOver = false; 176 // reset down-state if mouse leves with button down 177 if (rMouse.pDragElement == this) if (fEnabled) SetUp(false); 178 } 179 OnPress()180 void Button::OnPress() 181 { 182 // nothing in base 183 } 184 SetDown()185 void Button::SetDown() 186 { 187 // already down? 188 if (fDown) return; 189 // play sound 190 GUISound("UI::Tick"); 191 // set down 192 fDown = true; 193 } 194 SetUp(bool fPress)195 void Button::SetUp(bool fPress) 196 { 197 // already up? 198 if (!fDown) return; 199 // play sound 200 GUISound(fPress ? "UI::Click" : "UI::Tick"); 201 // set up 202 fDown = false; 203 } 204 205 206 // -------------------------------------------------------- 207 // IconButton 208 DrawElement(C4TargetFacet & cgo)209 void IconButton::DrawElement(C4TargetFacet &cgo) 210 { 211 // get drawing bounds 212 int32_t x0 = cgo.TargetX + rcBounds.x, y0 = cgo.TargetY + rcBounds.y; 213 // draw selection highlight 214 if (fEnabled) if (fHighlight || HasDrawFocus() || (fMouseOver && IsInActiveDlg(false))) 215 { 216 pDraw->SetBlitMode(C4GFXBLIT_ADDITIVE); 217 ::GraphicsResource.fctButtonHighlightRound.DrawX(cgo.Surface, x0, y0, rcBounds.Wdt, rcBounds.Hgt); 218 pDraw->ResetBlitMode(); 219 } 220 // draw the icon 221 if (fHasClr && fctIcon.Surface) fctIcon.Surface->SetClr(dwClr); 222 fctIcon.DrawX(cgo.Surface, x0, y0, rcBounds.Wdt, rcBounds.Hgt); 223 // "button" down? 224 if (fEnabled) if (fDown || fHighlight) 225 { 226 pDraw->SetBlitMode(C4GFXBLIT_ADDITIVE); 227 ::GraphicsResource.fctButtonHighlightRound.DrawX(cgo.Surface, x0, y0, rcBounds.Wdt, rcBounds.Hgt); 228 pDraw->ResetBlitMode(); 229 } 230 // some icon buttons have captions. draw caption below button 231 if (sText.getLength()) 232 { 233 CStdFont &rUseFont = pCustomFont ? *pCustomFont : ::GraphicsResource.TextFont; 234 pDraw->TextOut(sText.getData(), rUseFont, 1.0f, cgo.Surface, x0+rcBounds.Wdt/2, y0+rcBounds.Hgt, pCustomFont ? dwCustomFontClr : C4GUI_CaptionFontClr, ACenter); 235 } 236 } 237 IconButton(Icons eUseIcon,const C4Rect & rtBounds,char caHotkey,const char * tooltip_text)238 IconButton::IconButton(Icons eUseIcon, const C4Rect &rtBounds, char caHotkey, const char *tooltip_text) 239 : Button("", rtBounds), dwClr(0u), fHasClr(false), fHighlight(false) 240 { 241 // ctor 242 cHotkey = caHotkey; 243 SetIcon(eUseIcon); 244 // set tooltip and expand hotkey 245 if (tooltip_text) 246 { 247 StdStrBuf tooltip_text_buf(tooltip_text); 248 if (!cHotkey) ExpandHotkeyMarkup(tooltip_text_buf, cHotkey, true); 249 SetToolTip(tooltip_text_buf.getData(), true); 250 } 251 } 252 SetIcon(Icons eUseIcon)253 void IconButton::SetIcon(Icons eUseIcon) 254 { 255 if (eUseIcon>=0) fctIcon = Icon::GetIconFacet(eUseIcon); else fctIcon.Surface=nullptr; 256 } 257 258 259 260 // -------------------------------------------------------- 261 // ArrowButton 262 ArrowButton(ArrowFct eDir,const C4Rect & rtBounds,char cHotkey)263 ArrowButton::ArrowButton(ArrowFct eDir, const C4Rect &rtBounds, char cHotkey) 264 : Button("", rtBounds), eDir(eDir) 265 { 266 // ctor 267 this->cHotkey = cHotkey; 268 } 269 DrawElement(C4TargetFacet & cgo)270 void ArrowButton::DrawElement(C4TargetFacet &cgo) 271 { 272 // get drawing bounds 273 int32_t x0 = cgo.TargetX + rcBounds.x, y0 = cgo.TargetY + rcBounds.y; 274 // draw selection highlight 275 if (fEnabled) if (HasDrawFocus() || (fMouseOver && IsInActiveDlg(false))) 276 { 277 pDraw->SetBlitMode(C4GFXBLIT_ADDITIVE); 278 ::GraphicsResource.fctButtonHighlightRound.DrawX(cgo.Surface, x0, y0, rcBounds.Wdt, rcBounds.Hgt); 279 pDraw->ResetBlitMode(); 280 } 281 // draw the arrow - down if pressed 282 int32_t iFctIdx = eDir; 283 if (fDown) iFctIdx += Down; 284 ::GraphicsResource.fctBigArrows.GetPhase(iFctIdx).DrawX(cgo.Surface, x0, y0, rcBounds.Wdt, rcBounds.Hgt); 285 } 286 287 GetDefaultWidth()288 int32_t ArrowButton::GetDefaultWidth() 289 { 290 // default by gfx size 291 return ::GraphicsResource.fctBigArrows.Wdt; 292 } 293 GetDefaultHeight()294 int32_t ArrowButton::GetDefaultHeight() 295 { 296 // default by gfx size 297 return ::GraphicsResource.fctBigArrows.Hgt; 298 } 299 300 301 // -------------------------------------------------------- 302 // FacetButton 303 FacetButton(const C4Facet & rBaseFct,const C4Facet & rHighlightFct,const FLOAT_RECT & rtfBounds,char cHotkey)304 FacetButton::FacetButton(const C4Facet &rBaseFct, const C4Facet &rHighlightFct, const FLOAT_RECT &rtfBounds, char cHotkey) 305 : Button("", C4Rect(rtfBounds)), fctBase(rBaseFct), fctHighlight(rHighlightFct), dwTextClrInact(0x7f000000), dwTextClrAct(0xff000000), rcfDrawBounds(rtfBounds), pFont(nullptr), fFontZoom(1.0f) 306 { 307 // ctor 308 this->cHotkey = cHotkey; 309 iTxtOffX=iTxtOffY=0; 310 byTxtAlign=ALeft; 311 } 312 DrawElement(C4TargetFacet & cgo)313 void FacetButton::DrawElement(C4TargetFacet &cgo) 314 { 315 // get drawing bounds 316 float x0 = rcfDrawBounds.left + cgo.TargetX, y0 = rcfDrawBounds.top + cgo.TargetY; 317 // draw button or highlight facet 318 uint32_t dwTextClr; 319 if ((HasDrawFocus() || (fMouseOver && IsInActiveDlg(false))) && fEnabled) 320 { 321 fctHighlight.DrawXFloat(cgo.Surface, x0, y0, rcfDrawBounds.right-rcfDrawBounds.left, rcfDrawBounds.bottom-rcfDrawBounds.top); 322 dwTextClr = dwTextClrAct; 323 } 324 else 325 { 326 fctBase.DrawXFloat(cgo.Surface, x0, y0, rcfDrawBounds.right-rcfDrawBounds.left, rcfDrawBounds.bottom-rcfDrawBounds.top); 327 dwTextClr = dwTextClrInact; 328 } 329 // draw caption text 330 if (sText.getLength()>0) 331 { 332 CStdFont *pUseFont = pFont ? pFont : &(::GraphicsResource.GetFontByHeight(rcBounds.Hgt, &fFontZoom)); 333 pDraw->TextOut(sText.getData(), *pUseFont, fFontZoom, cgo.Surface, (int)(x0+iTxtOffX), (int)(y0+iTxtOffY), dwTextClr, byTxtAlign, true); 334 } 335 /* 336 if (fEnabled) if (fMouseOver && IsInActiveDlg(false)) 337 { 338 pDraw->SetBlitMode(C4GFXBLIT_ADDITIVE); 339 GetRes()->fctButtonHighlight.DrawXFloat(cgo.Surface, x0, y0, rcfDrawBounds.right-rcfDrawBounds.left, rcfDrawBounds.bottom-rcfDrawBounds.top); 340 pDraw->ResetBlitMode(); 341 }*/ 342 } 343 344 345 } // end of namespace 346 347