1 /*
2 	GWEN
3 	Copyright (c) 2010 Facepunch Studios
4 	See license in Gwen.h
5 */
6 
7 #include "Gwen/Utility.h"
8 #include "Gwen/Controls/ColorControls.h"
9 
10 using namespace Gwen;
11 using namespace Gwen::Controls;
12 
13 //Find a place to put these...
HSVToColor(float h,float s,float v)14 Color HSVToColor(float h, float s, float v)
15 {
16 	if (h < 0.0f) h += 360.0f;
17 	if (h > 360.0f) h -= 360.0f;
18 
19 	s *= 255.0f;
20 	v *= 255.0f;
21 
22 	float r, g, b;
23 
24 	if (!h && !s)
25 	{
26 		r = g = b = v;
27 	}
28 	double min, max, delta, hue;
29 
30 	max = v;
31 	delta = (max * s) / 255.0;
32 	min = max - delta;
33 
34 	hue = h;
35 	if (h > 300 || h <= 60)
36 	{
37 		r = (int)max;
38 		if (h > 300)
39 		{
40 			g = (int)min;
41 			hue = (hue - 360.0) / 60.0;
42 			b = (int)((hue * delta - min) * -1);
43 		}
44 		else
45 		{
46 			b = (int)min;
47 			hue = hue / 60.0;
48 			g = (int)(hue * delta + min);
49 		}
50 	}
51 	else if (h > 60 && h < 180)
52 	{
53 		g = (int)max;
54 		if (h < 120)
55 		{
56 			b = (int)min;
57 			hue = (hue / 60.0 - 2.0) * delta;
58 			r = (int)(min - hue);
59 		}
60 		else
61 		{
62 			r = (int)min;
63 			hue = (hue / 60 - 2.0) * delta;
64 			b = (int)(min + hue);
65 		}
66 	}
67 	else
68 	{
69 		b = (int)max;
70 		if (h < 240)
71 		{
72 			r = (int)min;
73 			hue = (hue / 60.0 - 4.0) * delta;
74 			g = (int)(min - hue);
75 		}
76 		else
77 		{
78 			g = (int)min;
79 			hue = (hue / 60 - 4.0) * delta;
80 			r = (int)(min + hue);
81 		}
82 	}
83 
84 	return Color(r, g, b, 255);
85 }
86 
RGBtoHSV(int r,int g,int b)87 HSV RGBtoHSV(int r, int g, int b)
88 {
89 	double min, max, delta, temp;
90 	min = GwenUtil_Min(r, GwenUtil_Min(g, b));
91 	max = GwenUtil_Max(r, GwenUtil_Max(g, b));
92 	delta = max - min;
93 
94 	HSV hsv;
95 	hsv.v = (int)max;
96 	if (!delta)
97 	{
98 		hsv.h = hsv.s = 0;
99 	}
100 	else
101 	{
102 		temp = delta / max;
103 		hsv.s = (int)(temp * 255);
104 
105 		if (r == (int)max)
106 		{
107 			temp = (double)(g - b) / delta;
108 		}
109 		else if (g == (int)max)
110 		{
111 			temp = 2.0 + ((double)(b - r) / delta);
112 		}
113 		else
114 		{
115 			temp = 4.0 + ((double)(r - g) / delta);
116 		}
117 		temp *= 60;
118 		if (temp < 0)
119 		{
120 			temp += 360;
121 		}
122 		if (temp == 360)
123 		{
124 			temp = 0;
125 		}
126 		hsv.h = (int)temp;
127 	}
128 
129 	hsv.s /= 255.0f;
130 	hsv.v /= 255.0f;
131 
132 	return hsv;
133 }
134 
GWEN_CONTROL_CONSTRUCTOR(ColorLerpBox)135 GWEN_CONTROL_CONSTRUCTOR(ColorLerpBox)
136 {
137 	SetColor(Gwen::Color(255, 128, 0, 255));
138 	SetSize(128, 128);
139 	SetMouseInputEnabled(true);
140 	m_bDepressed = false;
141 }
142 
143 //Find a place to put this? color member?
LerpColor(Gwen::Color & toColor,Gwen::Color & fromColor,float amount)144 Gwen::Color LerpColor(Gwen::Color& toColor, Gwen::Color& fromColor, float amount)
145 {
146 	Gwen::Color colorDelta = toColor - fromColor;
147 
148 	colorDelta.r *= amount;
149 	colorDelta.g *= amount;
150 	colorDelta.b *= amount;
151 
152 	Gwen::Color newColor = fromColor + colorDelta;
153 	return newColor;
154 }
155 
GetSelectedColor()156 Gwen::Color ColorLerpBox::GetSelectedColor()
157 {
158 	return GetColorAtPos(cursorPos.x, cursorPos.y);
159 }
160 
SetColor(Gwen::Color color,bool onlyHue)161 void ColorLerpBox::SetColor(Gwen::Color color, bool onlyHue)
162 {
163 	HSV hsv = RGBtoHSV(color.r, color.g, color.b);
164 	m_Hue = hsv.h;
165 	if (!onlyHue)
166 	{
167 		cursorPos.x = hsv.s * Width();
168 		cursorPos.y = (1 - hsv.v) * Height();
169 	}
170 
171 	onSelectionChanged.Call(this);
172 }
173 
OnMouseMoved(int x,int y,int,int)174 void ColorLerpBox::OnMouseMoved(int x, int y, int /*deltaX*/, int /*deltaY*/)
175 {
176 	if (m_bDepressed)
177 	{
178 		cursorPos = CanvasPosToLocal(Gwen::Point(x, y));
179 		//Do we have clamp?
180 		if (cursorPos.x < 0)
181 			cursorPos.x = 0;
182 		if (cursorPos.x > Width())
183 			cursorPos.x = Width();
184 
185 		if (cursorPos.y < 0)
186 			cursorPos.y = 0;
187 		if (cursorPos.y > Height())
188 			cursorPos.y = Height();
189 
190 		onSelectionChanged.Call(this);
191 	}
192 }
193 
OnMouseClickLeft(int x,int y,bool bDown)194 void ColorLerpBox::OnMouseClickLeft(int x, int y, bool bDown)
195 {
196 	m_bDepressed = bDown;
197 	if (bDown)
198 		Gwen::MouseFocus = this;
199 	else
200 		Gwen::MouseFocus = NULL;
201 
202 	OnMouseMoved(x, y, 0, 0);
203 }
204 
GetColorAtPos(int x,int y)205 Gwen::Color ColorLerpBox::GetColorAtPos(int x, int y)
206 {
207 	float xPercent = ((float)x / (float)Width());
208 	float yPercent = 1 - ((float)y / (float)Height());
209 
210 	Gwen::Color result = HSVToColor(m_Hue, xPercent, yPercent);
211 
212 	result.a = 255;
213 
214 	return result;
215 }
Render(Gwen::Skin::Base * skin)216 void ColorLerpBox::Render(Gwen::Skin::Base* skin)
217 {
218 	//Is there any way to move this into skin? Not for now, no idea how we'll "actually" render these
219 	BaseClass::Render(skin);
220 	for (int x = 0; x < Width(); x++)
221 	{
222 		for (int y = 0; y < Height(); y++)
223 		{
224 			skin->GetRender()->SetDrawColor(GetColorAtPos(x, y));
225 			skin->GetRender()->DrawPixel(x, y);
226 		}
227 	}
228 
229 	skin->GetRender()->SetDrawColor(Gwen::Color(0, 0, 0, 255));
230 	skin->GetRender()->DrawLinedRect(GetRenderBounds());
231 
232 	Gwen::Color selected = GetSelectedColor();
233 	if ((selected.r + selected.g + selected.b) / 3 < 170)
234 		skin->GetRender()->SetDrawColor(Gwen::Color(255, 255, 255, 255));
235 	else
236 		skin->GetRender()->SetDrawColor(Gwen::Color(0, 0, 0, 255));
237 
238 	Gwen::Rect testRect = Gwen::Rect(cursorPos.x - 3, cursorPos.y - 3, 6, 6);
239 
240 	skin->GetRender()->DrawShavedCornerRect(testRect);
241 }
242 
GWEN_CONTROL_CONSTRUCTOR(ColorSlider)243 GWEN_CONTROL_CONSTRUCTOR(ColorSlider)
244 {
245 	SetSize(32, 128);
246 	SetMouseInputEnabled(true);
247 	m_bDepressed = false;
248 }
249 
Render(Gwen::Skin::Base * skin)250 void ColorSlider::Render(Gwen::Skin::Base* skin)
251 {
252 	//Is there any way to move this into skin? Not for now, no idea how we'll "actually" render these
253 	int y = 0;
254 	for (y = 0; y < Height(); y++)
255 	{
256 		float yPercent = (float)y / (float)Height();
257 		skin->GetRender()->SetDrawColor(HSVToColor(yPercent * 360, 1, 1));
258 		skin->GetRender()->DrawFilledRect(Gwen::Rect(5, y, Width() - 10, 1));
259 	}
260 
261 	int drawHeight = m_iSelectedDist - 3;
262 
263 	//Draw our selectors
264 	skin->GetRender()->SetDrawColor(Gwen::Color(0, 0, 0, 255));
265 	skin->GetRender()->DrawFilledRect(Gwen::Rect(0, drawHeight + 2, Width(), 1));
266 	skin->GetRender()->DrawFilledRect(Gwen::Rect(0, drawHeight, 5, 5));
267 	skin->GetRender()->DrawFilledRect(Gwen::Rect(Width() - 5, drawHeight, 5, 5));
268 	skin->GetRender()->SetDrawColor(Gwen::Color(255, 255, 255, 255));
269 	skin->GetRender()->DrawFilledRect(Gwen::Rect(1, drawHeight + 1, 3, 3));
270 	skin->GetRender()->DrawFilledRect(Gwen::Rect(Width() - 4, drawHeight + 1, 3, 3));
271 }
272 
OnMouseClickLeft(int x,int y,bool bDown)273 void ColorSlider::OnMouseClickLeft(int x, int y, bool bDown)
274 {
275 	m_bDepressed = bDown;
276 	if (bDown)
277 		Gwen::MouseFocus = this;
278 	else
279 		Gwen::MouseFocus = NULL;
280 
281 	OnMouseMoved(x, y, 0, 0);
282 }
283 
GetColorAtHeight(int y)284 Gwen::Color ColorSlider::GetColorAtHeight(int y)
285 {
286 	float yPercent = (float)y / (float)Height();
287 	return HSVToColor(yPercent * 360, 1, 1);
288 }
OnMouseMoved(int x,int y,int,int)289 void ColorSlider::OnMouseMoved(int x, int y, int /*deltaX*/, int /*deltaY*/)
290 {
291 	if (m_bDepressed)
292 	{
293 		Gwen::Point cursorPos = CanvasPosToLocal(Gwen::Point(x, y));
294 
295 		if (cursorPos.y < 0)
296 			cursorPos.y = 0;
297 		if (cursorPos.y > Height())
298 			cursorPos.y = Height();
299 
300 		m_iSelectedDist = cursorPos.y;
301 		onSelectionChanged.Call(this);
302 	}
303 }
304 
SetColor(Gwen::Color color)305 void ColorSlider::SetColor(Gwen::Color color)
306 {
307 	HSV hsv = RGBtoHSV(color.r, color.g, color.b);
308 
309 	m_iSelectedDist = hsv.h / 360 * Height();
310 
311 	onSelectionChanged.Call(this);
312 }
313 
GetSelectedColor()314 Gwen::Color ColorSlider::GetSelectedColor()
315 {
316 	return GetColorAtHeight(m_iSelectedDist);
317 }
318