xref: /haiku/src/kits/interface/CheckBox.cpp (revision d3d8b26997fac34a84981e6d2b649521de2cc45a)
1 /*
2  * Copyright 2001-2006, Haiku Inc.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Marc Flerackers (mflerackers@androme.be)
7  */
8 
9 /*!	BCheckBox displays an on/off control. */
10 
11 
12 #include <CheckBox.h>
13 #include <Window.h>
14 
15 
16 BCheckBox::BCheckBox(BRect frame, const char *name, const char *label,
17 					 BMessage *message, uint32 resizingMode, uint32 flags)
18 	: BControl(frame, name, label, message, resizingMode, flags),
19 	fOutlined(false)
20 {
21 	// Resize to minimum height if needed
22 	font_height fontHeight;
23 	GetFontHeight(&fontHeight);
24 	float minHeight = (float)ceil(6.0f + fontHeight.ascent + fontHeight.descent);
25 	if (Bounds().Height() < minHeight)
26 		ResizeTo(Bounds().Width(), minHeight);
27 }
28 
29 
30 BCheckBox::~BCheckBox()
31 {
32 }
33 
34 
35 BCheckBox::BCheckBox(BMessage *archive)
36 	: BControl(archive),
37 	fOutlined(false)
38 {
39 }
40 
41 
42 BArchivable *
43 BCheckBox::Instantiate(BMessage *archive)
44 {
45 	if (validate_instantiation(archive, "BCheckBox"))
46 		return new BCheckBox(archive);
47 
48 	return NULL;
49 }
50 
51 
52 status_t
53 BCheckBox::Archive(BMessage *archive, bool deep) const
54 {
55 	return BControl::Archive(archive,deep);
56 }
57 
58 
59 void
60 BCheckBox::Draw(BRect updateRect)
61 {
62 	font_height fontHeight;
63 	GetFontHeight(&fontHeight);
64 
65 	// If the focus is changing, just redraw the focus indicator
66 	if (IsFocusChanging()) {
67 		float x = (float)ceil(10.0f + fontHeight.ascent);
68 		float y = 5.0f + (float)ceil(fontHeight.ascent);
69 
70 		if (IsFocus())
71 			SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR));
72 		else
73 			SetHighColor(ui_color(B_PANEL_BACKGROUND_COLOR));
74 
75 		StrokeLine(BPoint(x, y), BPoint(x + StringWidth(Label()), y));
76 
77 		return;
78 	}
79 
80 	rgb_color no_tint = ui_color(B_PANEL_BACKGROUND_COLOR),
81 	lighten1 = tint_color(no_tint, B_LIGHTEN_1_TINT),
82 	lightenmax = tint_color(no_tint, B_LIGHTEN_MAX_TINT),
83 	darken1 = tint_color(no_tint, B_DARKEN_1_TINT),
84 	darken2 = tint_color(no_tint, B_DARKEN_2_TINT),
85 	darken3 = tint_color(no_tint, B_DARKEN_3_TINT),
86 	darken4 = tint_color(no_tint, B_DARKEN_4_TINT),
87 	darkenmax = tint_color(no_tint, B_DARKEN_MAX_TINT);
88 
89 	BRect rect = _CheckBoxFrame();
90 
91 	if (IsEnabled()) {
92 		// Filling
93 		SetHighColor(lightenmax);
94 		FillRect(rect);
95 
96 		// Box
97 		if (fOutlined) {
98 			SetHighColor(darken3);
99 			StrokeRect(rect);
100 
101 			rect.InsetBy(1,1);
102 
103 			BeginLineArray(6);
104 
105 			AddLine(BPoint(rect.left, rect.bottom),
106 					BPoint(rect.left, rect.top), darken2);
107 			AddLine(BPoint(rect.left, rect.top),
108 					BPoint(rect.right, rect.top), darken2);
109 			AddLine(BPoint(rect.left, rect.bottom),
110 					BPoint(rect.right, rect.bottom), darken4);
111 			AddLine(BPoint(rect.right, rect.bottom),
112 					BPoint(rect.right, rect.top), darken4);
113 
114 			EndLineArray();
115 		} else {
116 			BeginLineArray(6);
117 
118 			AddLine(BPoint(rect.left, rect.bottom),
119 					BPoint(rect.left, rect.top), darken1);
120 			AddLine(BPoint(rect.left, rect.top),
121 					BPoint(rect.right, rect.top), darken1);
122 			rect.InsetBy(1,1);
123 			AddLine(BPoint(rect.left, rect.bottom),
124 					BPoint(rect.left, rect.top), darken4);
125 			AddLine(BPoint(rect.left, rect.top),
126 					BPoint(rect.right, rect.top), darken4);
127 			AddLine(BPoint(rect.left + 1.0f, rect.bottom),
128 					BPoint(rect.right, rect.bottom), no_tint);
129 			AddLine(BPoint(rect.right, rect.bottom),
130 					BPoint(rect.right, rect.top + 1.0f), no_tint);
131 
132 			EndLineArray();
133 		}
134 
135 		// Checkmark
136 		if (Value() == B_CONTROL_ON) {
137 			rect.InsetBy(2,2);
138 
139 			SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR));
140 			SetPenSize(2);
141 // Yes, Haiku is differnt because of the anti-aliasing
142 SetDrawingMode(B_OP_OVER);
143 			StrokeLine(BPoint(rect.left, rect.top),
144 					   BPoint(rect.right, rect.bottom));
145 			StrokeLine(BPoint(rect.left, rect.bottom),
146 					   BPoint(rect.right, rect.top));
147 			SetPenSize(1);
148 SetDrawingMode(B_OP_COPY);
149 		}
150 
151 		// Label
152 		SetHighColor(darkenmax);
153 		DrawString(Label(), BPoint((float)ceil(10.0f + fontHeight.ascent),
154 			3.0f + (float)ceil(fontHeight.ascent)));
155 
156 		// Focus
157 		if (IsFocus()) {
158 			float x = (float)ceil(10.0f + fontHeight.ascent);
159 			float y = 5.0f + (float)ceil(fontHeight.ascent);
160 
161 			SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR));
162 			StrokeLine(BPoint(x, y), BPoint(x + StringWidth(Label()), y));
163 		}
164 	} else {
165 		// Filling
166 		SetHighColor(lighten1);
167 		FillRect(rect);
168 
169 		// Box
170 		BeginLineArray(6);
171 
172 		AddLine(BPoint(rect.left, rect.bottom),
173 				BPoint(rect.left, rect.top), no_tint);
174 		AddLine(BPoint(rect.left, rect.top),
175 				BPoint(rect.right, rect.top), no_tint);
176 		rect.InsetBy(1,1);
177 		AddLine(BPoint(rect.left, rect.bottom),
178 				BPoint(rect.left, rect.top), darken2);
179 		AddLine(BPoint(rect.left, rect.top),
180 				BPoint(rect.right, rect.top), darken2);
181 		AddLine(BPoint(rect.left + 1.0f, rect.bottom),
182 				BPoint(rect.right, rect.bottom), darken1);
183 		AddLine(BPoint(rect.right, rect.bottom),
184 				BPoint(rect.right, rect.top + 1.0f), darken1);
185 
186 		EndLineArray();
187 
188 		// Checkmark
189 		if (Value() == B_CONTROL_ON) {
190 			rect.InsetBy(2, 2);
191 
192 			SetHighColor(tint_color(ui_color(B_KEYBOARD_NAVIGATION_COLOR),
193 				B_DISABLED_MARK_TINT));
194 			SetPenSize(2);
195 // Yes, Haiku is differnt because of the anti-aliasing
196 SetDrawingMode(B_OP_OVER);
197 			StrokeLine(BPoint(rect.left, rect.top),
198 					   BPoint(rect.right, rect.bottom));
199 			StrokeLine(BPoint(rect.left, rect.bottom),
200 					   BPoint(rect.right, rect.top));
201 			SetPenSize(1);
202 SetDrawingMode(B_OP_COPY);
203 		}
204 
205 		// Label
206 		SetHighColor(tint_color(no_tint, B_DISABLED_LABEL_TINT));
207 		DrawString(Label(), BPoint((float)ceil(10.0f + fontHeight.ascent),
208 			3.0f + (float)ceil(fontHeight.ascent)));
209 	}
210 }
211 
212 
213 void
214 BCheckBox::AttachedToWindow()
215 {
216 	BControl::AttachedToWindow();
217 }
218 
219 
220 void
221 BCheckBox::MouseDown(BPoint point)
222 {
223 	if (!IsEnabled())
224 		return;
225 
226 	fOutlined = true;
227 
228 	if (Window()->Flags() & B_ASYNCHRONOUS_CONTROLS) {
229 		Invalidate();
230 		SetTracking(true);
231 		SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);
232 	} else {
233 		BRect bounds = Bounds();
234 		uint32 buttons;
235 
236 		Draw(Bounds());
237 		Flush();
238 
239 		do {
240 			snooze(40000);
241 
242 			GetMouse(&point, &buttons, true);
243 
244 			bool inside = bounds.Contains(point);
245 
246 			if (fOutlined != inside) {
247 				fOutlined = inside;
248 				Draw(Bounds());
249 				Flush();
250 			}
251 		} while (buttons != 0);
252 
253 		if (fOutlined) {
254 			fOutlined = false;
255 			SetValue(!Value());
256 			Invoke();
257 		} else {
258 			Draw(Bounds());
259 			Flush();
260 		}
261 	}
262 }
263 
264 
265 void
266 BCheckBox::MessageReceived(BMessage *message)
267 {
268 	BControl::MessageReceived(message);
269 }
270 
271 
272 void
273 BCheckBox::WindowActivated(bool active)
274 {
275 	BControl::WindowActivated(active);
276 }
277 
278 
279 void
280 BCheckBox::KeyDown(const char *bytes, int32 numBytes)
281 {
282 	BControl::KeyDown(bytes, numBytes);
283 }
284 
285 
286 void
287 BCheckBox::MouseUp(BPoint point)
288 {
289 	if (!IsTracking())
290 		return;
291 
292 	bool inside = Bounds().Contains(point);
293 
294 	if (fOutlined != inside) {
295 		fOutlined = inside;
296 		Invalidate();
297 	}
298 
299 	if (fOutlined) {
300 		fOutlined = false;
301 		SetValue(!Value());
302 		Invoke();
303 	} else {
304 		Invalidate();
305 	}
306 
307 	SetTracking(false);
308 }
309 
310 
311 void
312 BCheckBox::MouseMoved(BPoint point, uint32 transit,
313 						   const BMessage *message)
314 {
315 	if (!IsTracking())
316 		return;
317 
318 	bool inside = Bounds().Contains(point);
319 
320 	if (fOutlined != inside) {
321 		fOutlined = inside;
322 		Invalidate();
323 	}
324 }
325 
326 
327 void
328 BCheckBox::DetachedFromWindow()
329 {
330 	BControl::DetachedFromWindow();
331 }
332 
333 
334 void
335 BCheckBox::SetValue(int32 value)
336 {
337 	value = value ? B_CONTROL_ON : B_CONTROL_OFF;
338 		// we only accept boolean values
339 
340 	if (value != Value()) {
341 		BControl::SetValueNoUpdate(value);
342 		Invalidate(_CheckBoxFrame());
343 	}
344 }
345 
346 
347 void
348 BCheckBox::GetPreferredSize(float* _width, float* _height)
349 {
350 	font_height fontHeight;
351 	GetFontHeight(&fontHeight);
352 
353 	if (_width) {
354 		float width = 12.0f + fontHeight.ascent;
355 
356 		if (Label())
357 			width += StringWidth(Label());
358 
359 		*_width = (float)ceil(width);
360 	}
361 
362 	if (_height)
363 		*_height = (float)ceil(6.0f + fontHeight.ascent + fontHeight.descent);
364 }
365 
366 
367 void
368 BCheckBox::ResizeToPreferred()
369 {
370 	BControl::ResizeToPreferred();
371 }
372 
373 
374 status_t
375 BCheckBox::Invoke(BMessage *message)
376 {
377 	return BControl::Invoke(message);
378 }
379 
380 
381 void
382 BCheckBox::FrameMoved(BPoint newLocation)
383 {
384 	BControl::FrameMoved(newLocation);
385 }
386 
387 
388 void
389 BCheckBox::FrameResized(float width, float height)
390 {
391 	BControl::FrameResized(width, height);
392 }
393 
394 
395 BHandler *
396 BCheckBox::ResolveSpecifier(BMessage *message, int32 index,
397 	BMessage *specifier, int32 what, const char *property)
398 {
399 	return BControl::ResolveSpecifier(message, index, specifier, what, property);
400 }
401 
402 
403 status_t
404 BCheckBox::GetSupportedSuites(BMessage *message)
405 {
406 	return BControl::GetSupportedSuites(message);
407 }
408 
409 
410 void
411 BCheckBox::MakeFocus(bool focused)
412 {
413 	BControl::MakeFocus(focused);
414 }
415 
416 
417 void
418 BCheckBox::AllAttached()
419 {
420 	BControl::AllAttached();
421 }
422 
423 
424 void
425 BCheckBox::AllDetached()
426 {
427 	BControl::AllDetached();
428 }
429 
430 
431 status_t
432 BCheckBox::Perform(perform_code d, void *arg)
433 {
434 	return BControl::Perform(d, arg);
435 }
436 
437 
438 void BCheckBox::_ReservedCheckBox1() {}
439 void BCheckBox::_ReservedCheckBox2() {}
440 void BCheckBox::_ReservedCheckBox3() {}
441 
442 
443 BCheckBox &
444 BCheckBox::operator=(const BCheckBox &)
445 {
446 	return *this;
447 }
448 
449 // _CheckBoxFrame
450 BRect
451 BCheckBox::_CheckBoxFrame() const
452 {
453 	font_height fh;
454 	GetFontHeight(&fh);
455 
456 	return BRect(1.0f, 3.0f, ceilf(3.0f + fh.ascent), ceilf(5.0f + fh.ascent));
457 }
458