xref: /haiku/src/kits/interface/CheckBox.cpp (revision a4f6a81235ca2522c01f532de13cad9b729d4029)
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 	else
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 	if (value != Value()) {
338 		BControl::SetValueNoUpdate(value);
339 		Invalidate(_CheckBoxFrame());
340 	}
341 }
342 
343 
344 void
345 BCheckBox::GetPreferredSize(float* _width, float* _height)
346 {
347 	font_height fontHeight;
348 	GetFontHeight(&fontHeight);
349 
350 	if (_width) {
351 		float width = 12.0f + fontHeight.ascent;
352 
353 		if (Label())
354 			width += StringWidth(Label());
355 
356 		*_width = (float)ceil(width);
357 	}
358 
359 	if (_height)
360 		*_height = (float)ceil(6.0f + fontHeight.ascent + fontHeight.descent);
361 }
362 
363 
364 void
365 BCheckBox::ResizeToPreferred()
366 {
367 	BControl::ResizeToPreferred();
368 }
369 
370 
371 status_t
372 BCheckBox::Invoke(BMessage *message)
373 {
374 	return BControl::Invoke(message);
375 }
376 
377 
378 void
379 BCheckBox::FrameMoved(BPoint newLocation)
380 {
381 	BControl::FrameMoved(newLocation);
382 }
383 
384 
385 void
386 BCheckBox::FrameResized(float width, float height)
387 {
388 	BControl::FrameResized(width, height);
389 }
390 
391 
392 BHandler *
393 BCheckBox::ResolveSpecifier(BMessage *message, int32 index,
394 									  BMessage *specifier, int32 what,
395 									  const char *property)
396 {
397 	return BControl::ResolveSpecifier(message, index, specifier, what, property);
398 }
399 
400 
401 status_t
402 BCheckBox::GetSupportedSuites(BMessage *message)
403 {
404 	return BControl::GetSupportedSuites(message);
405 }
406 
407 
408 void
409 BCheckBox::MakeFocus(bool focused)
410 {
411 	BControl::MakeFocus(focused);
412 }
413 
414 
415 void
416 BCheckBox::AllAttached()
417 {
418 	BControl::AllAttached();
419 }
420 
421 
422 void
423 BCheckBox::AllDetached()
424 {
425 	BControl::AllDetached();
426 }
427 
428 
429 status_t
430 BCheckBox::Perform(perform_code d, void *arg)
431 {
432 	return BControl::Perform(d, arg);
433 }
434 
435 
436 void BCheckBox::_ReservedCheckBox1() {}
437 void BCheckBox::_ReservedCheckBox2() {}
438 void BCheckBox::_ReservedCheckBox3() {}
439 
440 
441 BCheckBox &
442 BCheckBox::operator=(const BCheckBox &)
443 {
444 	return *this;
445 }
446 
447 // _CheckBoxFrame
448 BRect
449 BCheckBox::_CheckBoxFrame() const
450 {
451 	font_height fh;
452 	GetFontHeight(&fh);
453 
454 	return BRect(1.0f, 3.0f, ceilf(3.0f + fh.ascent), ceilf(5.0f + fh.ascent));
455 }
456