xref: /haiku/src/kits/interface/RadioButton.cpp (revision 38f832c7eb696038294df0341e08acceca4716b3)
1 //------------------------------------------------------------------------------
2 //	Copyright (c) 2001-2002, OpenBeOS
3 //
4 //	Permission is hereby granted, free of charge, to any person obtaining a
5 //	copy of this software and associated documentation files (the "Software"),
6 //	to deal in the Software without restriction, including without limitation
7 //	the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 //	and/or sell copies of the Software, and to permit persons to whom the
9 //	Software is furnished to do so, subject to the following conditions:
10 //
11 //	The above copyright notice and this permission notice shall be included in
12 //	all copies or substantial portions of the Software.
13 //
14 //	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 //	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 //	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 //	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 //	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 //	FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 //	DEALINGS IN THE SOFTWARE.
21 //
22 //	File Name:		RadioButton.cpp
23 //	Author:			Marc Flerackers (mflerackers@androme.be)
24 //	Description:	BRadioButton represents a single on/off button.  All
25 //                  sibling BRadioButton objects comprise a single
26 //                  "multiple choice" control.
27 //------------------------------------------------------------------------------
28 
29 // Standard Includes -----------------------------------------------------------
30 
31 // System Includes -------------------------------------------------------------
32 #include <RadioButton.h>
33 #include <Errors.h>
34 
35 // Project Includes ------------------------------------------------------------
36 
37 // Local Includes --------------------------------------------------------------
38 
39 // Local Defines ---------------------------------------------------------------
40 
41 // Globals ---------------------------------------------------------------------
42 
43 //------------------------------------------------------------------------------
44 BRadioButton::BRadioButton(BRect frame, const char *name, const char *label,
45 						   BMessage *message, uint32 resizMask, uint32 flags)
46 	:	BControl(frame, name, label, message, resizMask, flags),
47 		fOutlined(false)
48 {
49 	if (Bounds().Height() < 18.0f)
50 		ResizeTo(Bounds().Width(), 18.0f);
51 }
52 //------------------------------------------------------------------------------
53 BRadioButton::BRadioButton(BMessage *archive)
54 	:	BControl(archive),
55 		fOutlined(false)
56 {
57 }
58 //------------------------------------------------------------------------------
59 BRadioButton::~BRadioButton()
60 {
61 }
62 //------------------------------------------------------------------------------
63 BArchivable *BRadioButton::Instantiate(BMessage *archive)
64 {
65 	if (validate_instantiation(archive, "BRadioButton"))
66 		return new BRadioButton(archive);
67 	else
68 		return NULL;
69 }
70 //------------------------------------------------------------------------------
71 status_t BRadioButton::Archive(BMessage *archive, bool deep) const
72 {
73 	return BControl::Archive(archive, deep);
74 }
75 //------------------------------------------------------------------------------
76 void BRadioButton::Draw(BRect updateRect)
77 {
78 	font_height fh;
79 	GetFontHeight(&fh);
80 
81 	// If the focus is changing, just redraw the focus indicator
82 	if (IsFocusChanging())
83 	{
84 		float h = 8.0f + (float)ceil(fh.ascent / 2.0f) + 2.0f;
85 
86 		if (IsFocus())
87 			SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR));
88 		else
89 			SetHighColor(ui_color(B_PANEL_BACKGROUND_COLOR));
90 
91 		StrokeLine(BPoint(20.0f, h), BPoint(20.0f + StringWidth(Label()), h));
92 
93 		return;
94 	}
95 
96 	// Placeholder until sBitmaps is filled in
97 	rgb_color no_tint = ui_color(B_PANEL_BACKGROUND_COLOR),
98 	lighten1 = tint_color(no_tint, B_LIGHTEN_1_TINT),
99 	lightenmax = tint_color(no_tint, B_LIGHTEN_MAX_TINT),
100 	darken1 = tint_color(no_tint, B_DARKEN_1_TINT),
101 	darken2 = tint_color(no_tint, B_DARKEN_2_TINT),
102 	darken3 = tint_color(no_tint, B_DARKEN_3_TINT),
103 	darken4 = tint_color(no_tint, B_DARKEN_4_TINT),
104 	darkenmax = tint_color(no_tint, B_DARKEN_MAX_TINT);
105 
106 	BRect rect(1.0, 3.0, 13.0, 15.0);
107 
108 	if (IsEnabled())
109 	{
110 		// Dot
111 		if (Value() == B_CONTROL_ON)
112 		{
113 			rgb_color kb_color = ui_color(B_KEYBOARD_NAVIGATION_COLOR);
114 
115 			SetHighColor(tint_color(kb_color, B_DARKEN_3_TINT));
116 			FillEllipse(rect);
117 			SetHighColor(kb_color);
118 			FillEllipse(BRect(rect.left + 3, rect.top + 3, rect.right - 4, rect.bottom - 4));
119 			SetHighColor(tint_color(kb_color, B_DARKEN_3_TINT));
120 			StrokeLine(BPoint(rect.right - 5, rect.bottom - 4),
121 				BPoint(rect.right - 4, rect.bottom - 5));
122 			SetHighColor(tint_color(kb_color, B_LIGHTEN_MAX_TINT));
123 			StrokeLine(BPoint(rect.left + 4, rect.top + 5),
124 				BPoint(rect.left + 5, rect.top + 4));
125 
126 		}
127 		else
128 		{
129 			SetHighColor(lightenmax);
130 			FillEllipse(rect);
131 		}
132 
133 		// Outer circle
134 		if (fOutlined)
135 		{
136 			SetHighColor(darken3);
137 			StrokeEllipse(rect);
138 		}
139 		else
140 		{
141 			SetHighColor(darken1);
142 			StrokeArc(rect, 45.0f, 180.0f);
143 			SetHighColor(lightenmax);
144 			StrokeArc(rect, 45.0f, -180.0f);
145 		}
146 
147 		rect.InsetBy(1, 1);
148 
149 		// Inner circle
150 		SetHighColor(darken3);
151 		StrokeArc(rect, 45.0f, 180.0f);
152 		StrokeLine(BPoint(rect.left + 1, rect.top + 1),
153 			BPoint(rect.left + 1, rect.top + 1));
154 		SetHighColor(no_tint);
155 		StrokeArc(rect, 45.0f, -180.0f);
156 		StrokeLine(BPoint(rect.left + 1, rect.bottom - 1),
157 			BPoint(rect.left + 1, rect.bottom - 1));
158 		StrokeLine(BPoint(rect.right - 1, rect.bottom - 1),
159 			BPoint(rect.right - 1, rect.bottom - 1));
160 		StrokeLine(BPoint(rect.right - 1, rect.top + 1),
161 			BPoint(rect.right - 1, rect.top + 1));
162 
163 		// Label
164 		SetHighColor(darkenmax);
165 		DrawString(Label(), BPoint(20.0f, 8.0f + (float)ceil(fh.ascent / 2.0f)));
166 
167 		// Focus
168 		if (IsFocus())
169 		{
170 			float h = 8.0f + (float)ceil(fh.ascent / 2.0f) + 2.0f;
171 
172 			SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR));
173 			StrokeLine(BPoint(20.0f, h), BPoint(20.0f + StringWidth(Label()), h));
174 		}
175 	}
176 	else
177 	{
178 		// Dot
179 		if (Value() == B_CONTROL_ON)
180 		{
181 			rgb_color kb_color = ui_color(B_KEYBOARD_NAVIGATION_COLOR);
182 
183 			SetHighColor(tint_color(kb_color, B_LIGHTEN_2_TINT));
184 			FillEllipse(rect);
185 			SetHighColor(tint_color(kb_color, B_LIGHTEN_MAX_TINT));
186 			StrokeLine(BPoint(rect.left + 4, rect.top + 5),
187 				BPoint(rect.left + 5, rect.top + 4));
188 			SetHighColor(tint_color(kb_color, B_DARKEN_3_TINT));
189 			StrokeArc(BRect(rect.left + 2, rect.top + 2, rect.right - 2, rect.bottom - 2),
190 				45.0f, -180.0f);
191 		}
192 		else
193 		{
194 			SetHighColor(lighten1);
195 			FillEllipse(rect);
196 		}
197 
198 		// Outer circle
199 		SetHighColor(no_tint);
200 		StrokeArc(rect, 45.0f, 180.0f);
201 		SetHighColor(lighten1);
202 		StrokeArc(rect, 45.0f, -180.0f);
203 
204 		rect.InsetBy(1, 1);
205 
206 		// Inner circle
207 		SetHighColor(darken2);
208 		StrokeArc(rect, 45.0f, 180.0f);
209 		StrokeLine(BPoint(rect.left + 1, rect.top + 1),
210 			BPoint(rect.left + 1, rect.top + 1));
211 		SetHighColor(no_tint);
212 		StrokeArc(rect, 45.0f, -180.0f);
213 		StrokeLine(BPoint(rect.left + 1, rect.bottom - 1),
214 			BPoint(rect.left + 1, rect.bottom - 1));
215 		StrokeLine(BPoint(rect.right - 1, rect.bottom - 1),
216 			BPoint(rect.right - 1, rect.bottom - 1));
217 		StrokeLine(BPoint(rect.right - 1, rect.top + 1),
218 			BPoint(rect.right - 1, rect.top + 1));
219 
220 		// Label
221 		SetHighColor(tint_color(no_tint, B_DISABLED_LABEL_TINT));
222 		DrawString(Label(), BPoint(20.0f, 8.0f + (float)ceil(fh.ascent / 2.0f)));
223 	}
224 }
225 //------------------------------------------------------------------------------
226 void BRadioButton::MouseDown(BPoint point)
227 {
228 	if (!IsEnabled())
229 	{
230 		BControl::MouseDown(point);
231 		return;
232 	}
233 
234 	SetMouseEventMask(B_POINTER_EVENTS,	B_NO_POINTER_HISTORY |
235 					  B_SUSPEND_VIEW_FOCUS);
236 
237 	SetTracking(true);
238 	fOutlined = true;
239 	Invalidate();
240 }
241 //------------------------------------------------------------------------------
242 void BRadioButton::AttachedToWindow()
243 {
244 	BControl::AttachedToWindow();
245 }
246 //------------------------------------------------------------------------------
247 void BRadioButton::KeyDown(const char *bytes, int32 numBytes)
248 {
249 	BControl::KeyDown(bytes, numBytes);
250 }
251 //------------------------------------------------------------------------------
252 void BRadioButton::SetValue(int32 value)
253 {
254 	if (BControl::Value() == value)
255 		return;
256 
257 	if (!IsTracking() && value == B_CONTROL_ON)
258 	{
259 		BView *sibling;
260 
261 		for (sibling = PreviousSibling(); sibling != NULL;
262 			sibling = sibling->PreviousSibling())
263 		{
264 			BRadioButton* radio = dynamic_cast<BRadioButton*>(sibling);
265 
266 			if (radio != NULL)
267 				radio->BControl::SetValue(B_CONTROL_OFF);
268 		}
269 
270 		for (sibling = NextSibling(); sibling != NULL;
271 			sibling = sibling->NextSibling())
272 		{
273 			BRadioButton* radio = dynamic_cast<BRadioButton*>(sibling);
274 
275 			if (radio != NULL)
276 				radio->BControl::SetValue(B_CONTROL_OFF);
277 		}
278 	}
279 
280 	BControl::SetValue(value);
281 }
282 //------------------------------------------------------------------------------
283 void BRadioButton::GetPreferredSize(float *width, float *height)
284 {
285 	font_height fh;
286 	GetFontHeight(&fh);
287 
288 	*height = (float)ceil(fh.ascent + fh.descent + fh.leading) + 6.0f;
289 	*width = 22.0f + (float)ceil(StringWidth(Label()));
290 }
291 //------------------------------------------------------------------------------
292 void BRadioButton::ResizeToPreferred()
293 {
294 	BControl::ResizeToPreferred();
295 }
296 //------------------------------------------------------------------------------
297 status_t BRadioButton::Invoke(BMessage *message)
298 {
299 	return BControl::Invoke(message);
300 }
301 //------------------------------------------------------------------------------
302 void BRadioButton::MessageReceived(BMessage *message)
303 {
304 	BControl::MessageReceived(message);
305 }
306 //------------------------------------------------------------------------------
307 void BRadioButton::WindowActivated(bool active)
308 {
309 	BControl::WindowActivated(active);
310 }
311 //------------------------------------------------------------------------------
312 void BRadioButton::MouseUp(BPoint point)
313 {
314 	if (IsEnabled() && IsTracking())
315 	{
316 		fOutlined = false;
317 		SetTracking(false);
318 
319 		if (Bounds().Contains(point))
320 		{
321 			SetValue(B_CONTROL_ON);
322 			Invoke();
323 		}
324 	}
325 	else
326 	{
327 		BControl::MouseUp(point);
328 		return;
329 	}
330 
331 	Invalidate();
332 }
333 //------------------------------------------------------------------------------
334 void BRadioButton::MouseMoved(BPoint point, uint32 transit, const BMessage *message)
335 {
336 	if (IsEnabled() && IsTracking())
337 	{
338 		if (transit == B_EXITED_VIEW)
339 			fOutlined = false;
340 		else if (transit == B_ENTERED_VIEW)
341 			fOutlined = true;
342 
343 		Invalidate();
344 	}
345 	else
346 		BView::MouseMoved(point, transit, message);
347 }
348 //------------------------------------------------------------------------------
349 void BRadioButton::DetachedFromWindow()
350 {
351 	BControl::DetachedFromWindow();
352 }
353 //------------------------------------------------------------------------------
354 void BRadioButton::FrameMoved(BPoint newLocation)
355 {
356 	BControl::FrameMoved(newLocation);
357 }
358 //------------------------------------------------------------------------------
359 void BRadioButton::FrameResized(float width, float height)
360 {
361 	BControl::FrameResized(width, height);
362 }
363 //------------------------------------------------------------------------------
364 BHandler *BRadioButton::ResolveSpecifier(BMessage *message, int32 index,
365 										 BMessage *specifier, int32 what,
366 										 const char *property)
367 {
368 	return ResolveSpecifier(message, index, specifier, what, property);
369 }
370 //------------------------------------------------------------------------------
371 void BRadioButton::MakeFocus(bool focused)
372 {
373 	BControl::MakeFocus(focused);
374 }
375 //------------------------------------------------------------------------------
376 void BRadioButton::AllAttached()
377 {
378 	BControl::AllAttached();
379 }
380 //------------------------------------------------------------------------------
381 void BRadioButton::AllDetached()
382 {
383 	BControl::AllDetached();
384 }
385 //------------------------------------------------------------------------------
386 status_t BRadioButton::GetSupportedSuites(BMessage *message)
387 {
388 	return GetSupportedSuites(message);
389 }
390 //------------------------------------------------------------------------------
391 status_t BRadioButton::Perform(perform_code d, void *arg)
392 {
393 	return B_ERROR;
394 }
395 //------------------------------------------------------------------------------
396 void BRadioButton::_ReservedRadioButton1() {}
397 void BRadioButton::_ReservedRadioButton2() {}
398 //------------------------------------------------------------------------------
399 BRadioButton &BRadioButton::operator=(const BRadioButton &)
400 {
401 	return *this;
402 }
403 //------------------------------------------------------------------------------
404 
405 /*
406  * $Log $
407  *
408  * $Id  $
409  *
410  */
411