1 /*
2  * OpenClonk, http://www.openclonk.org
3  *
4  * Copyright (c) 2005-2009, RedWolf Design GmbH, http://www.clonk.de/
5  * Copyright (c) 2010-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 // checkbox
18 
19 #include "C4Include.h"
20 #include "gui/C4Gui.h"
21 
22 #include "graphics/C4Draw.h"
23 #include "graphics/C4FacetEx.h"
24 #include "graphics/C4GraphicsResource.h"
25 #include "gui/C4MouseControl.h"
26 
27 namespace C4GUI
28 {
29 
30 // ----------------------------------------------------
31 // CheckBox
32 
CheckBox(const C4Rect & rtBounds,const char * szCaption,bool fChecked)33 	CheckBox::CheckBox(const C4Rect &rtBounds, const char *szCaption, bool fChecked)
34 			: Control(rtBounds), fChecked(fChecked), fMouseOn(false), fEnabled(true), pFont(nullptr)
35 			, dwEnabledClr(C4GUI_CheckboxFontClr), dwDisabledClr(C4GUI_CheckboxDisabledFontClr), cHotkey(0)
36 	{
37 		if (szCaption)
38 		{
39 			sCaption.Copy(szCaption);
40 			ExpandHotkeyMarkup(sCaption, cHotkey);
41 		}
42 		// key callbacks: Check/Uncheck on space and primary joy button
43 		C4CustomKey::CodeList Keys;
44 		Keys.emplace_back(K_SPACE);
45 		if (Config.Controls.GamepadGuiControl)
46 		{
47 			ControllerKeys::Ok(Keys);
48 		}
49 		pKeyCheck = new C4KeyBinding(Keys, "GUICheckboxToggle", KEYSCOPE_Gui,
50 		                             new ControlKeyCB<CheckBox>(*this, &CheckBox::KeyCheck), C4CustomKey::PRIO_Ctrl);
51 		pCBHandler = nullptr;
52 	}
53 
~CheckBox()54 	CheckBox::~CheckBox()
55 	{
56 		delete pKeyCheck;
57 		if (pCBHandler) pCBHandler->DeRef();
58 	}
59 
UpdateOwnPos()60 	void CheckBox::UpdateOwnPos()
61 	{
62 	}
63 
OnHotkey(uint32_t cHotkey)64 	bool CheckBox::OnHotkey(uint32_t cHotkey)
65 	{
66 		if (cHotkey != this->cHotkey) return false;
67 		ToggleCheck(true);
68 		return true;
69 	}
70 
ToggleCheck(bool fByUser)71 	void CheckBox::ToggleCheck(bool fByUser)
72 	{
73 		// user can't toggle if disabled
74 		if (fByUser && !fEnabled) return;
75 		// sound
76 		if (fByUser) GUISound("UI::Tick");
77 		// toggle state
78 		fChecked = !fChecked;
79 		// callback (last call; may destroy element)
80 		if (pCBHandler) pCBHandler->DoCall(this);
81 	}
82 
MouseInput(CMouse & rMouse,int32_t iButton,int32_t iX,int32_t iY,DWORD dwKeyParam)83 	void CheckBox::MouseInput(CMouse &rMouse, int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyParam)
84 	{
85 		if (fEnabled)
86 		{
87 			// set mouse-on flag depending on whether mouse is over box area
88 			fMouseOn = Inside<int32_t>(iX, 0, rcBounds.Hgt) && Inside<int32_t>(iY, 0, rcBounds.Hgt);
89 			// left-click within checkbox toggles it
90 			if (iButton == C4MC_Button_LeftDown && fMouseOn)
91 			{
92 				ToggleCheck(true);
93 				return;
94 			}
95 		}
96 		// not recognized; base call
97 		Control::MouseInput(rMouse, iButton, iX, iY, dwKeyParam);
98 	}
99 
MouseEnter(CMouse & rMouse)100 	void CheckBox::MouseEnter(CMouse &rMouse)
101 	{
102 		Control::MouseEnter(rMouse);
103 	}
104 
MouseLeave(CMouse & rMouse)105 	void CheckBox::MouseLeave(CMouse &rMouse)
106 	{
107 		fMouseOn = false;
108 		Control::MouseLeave(rMouse);
109 	}
110 
DrawElement(C4TargetFacet & cgo)111 	void CheckBox::DrawElement(C4TargetFacet &cgo)
112 	{
113 		// left side: check facet (squared)
114 		int x0 = rcBounds.x + cgo.TargetX;
115 		int y0 = rcBounds.y + cgo.TargetY;
116 		::GraphicsResource.fctCheckbox.GetPhase(fChecked + 2*!fEnabled).DrawX(cgo.Surface, x0, y0, rcBounds.Hgt, rcBounds.Hgt);
117 		// right of it: checkbox text
118 		CStdFont *pUseFont = pFont ? pFont : &(::GraphicsResource.TextFont);
119 		int32_t yOff; float fZoom;
120 		if (pUseFont->GetLineHeight() <= rcBounds.Hgt)
121 		{
122 			yOff = std::max<int32_t>(rcBounds.Hgt - pUseFont->GetLineHeight(), 0)/2;
123 			fZoom = 1.0f;
124 		}
125 		else
126 		{
127 			yOff = 0;
128 			fZoom = (float) rcBounds.Hgt / std::max(pUseFont->GetLineHeight(), 1);
129 		}
130 		pDraw->TextOut(sCaption.getData(), *pUseFont, fZoom, cgo.Surface, x0 + rcBounds.Hgt + C4GUI_CheckBoxLabelSpacing, y0 + yOff, fEnabled ? dwEnabledClr : dwDisabledClr, ALeft, true);
131 		// selection marker
132 		if ((fMouseOn && IsInActiveDlg(false)) || HasDrawFocus())
133 		{
134 			pDraw->SetBlitMode(C4GFXBLIT_ADDITIVE);
135 			::GraphicsResource.fctButtonHighlightRound.DrawX(cgo.Surface, x0+rcBounds.Hgt*1/4, y0+rcBounds.Hgt*1/4, rcBounds.Hgt*1/2, rcBounds.Hgt*1/2);
136 			pDraw->ResetBlitMode();
137 		}
138 	}
139 
SetOnChecked(BaseCallbackHandler * pCB)140 	void CheckBox::SetOnChecked(BaseCallbackHandler *pCB)
141 	{
142 		if (pCBHandler) pCBHandler->DeRef();
143 		if ((pCBHandler = pCB)) pCB->Ref();
144 	}
145 
GetStandardCheckBoxSize(int * piWdt,int * piHgt,const char * szForCaptionText,CStdFont * pUseFont)146 	bool CheckBox::GetStandardCheckBoxSize(int *piWdt, int *piHgt, const char *szForCaptionText, CStdFont *pUseFont)
147 	{
148 		// get needed text size
149 		if (!pUseFont) pUseFont = &(::GraphicsResource.TextFont);
150 		int32_t iWdt=100, iHgt=32;
151 		pUseFont->GetTextExtent(szForCaptionText, iWdt, iHgt, true);
152 		// check box height equals text height
153 		// add check box plus indent
154 		if (piWdt) *piWdt = iWdt + iHgt + C4GUI_CheckBoxLabelSpacing;
155 		if (piHgt) *piHgt = iHgt;
156 		return true;
157 	}
158 
159 } // namespace C4GUI
160