vfs: check userland buffers before reading them.
[haiku.git] / src / kits / interface / CheckBox.cpp
blob8e20d6bf0c870f4862cc0dabfcd6336bff119656
1 /*
2 * Copyright 2001-2015 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Marc Flerackers (mflerackers@androme.be)
7 * Stephan Aßmus <superstippi@gmx.de>
8 */
11 // BCheckBox displays an on/off control.
14 #include <CheckBox.h>
16 #include <algorithm>
17 #include <new>
19 #include <Bitmap.h>
20 #include <ControlLook.h>
21 #include <LayoutUtils.h>
22 #include <Window.h>
24 #include <binary_compatibility/Interface.h>
27 BCheckBox::BCheckBox(BRect frame, const char* name, const char* label,
28 BMessage* message, uint32 resizingMode, uint32 flags)
30 BControl(frame, name, label, message, resizingMode, flags),
31 fPreferredSize(),
32 fOutlined(false),
33 fPartialToOff(false)
35 // Resize to minimum height if needed
36 font_height fontHeight;
37 GetFontHeight(&fontHeight);
38 float minHeight = (float)ceil(6.0f + fontHeight.ascent
39 + fontHeight.descent);
40 if (Bounds().Height() < minHeight)
41 ResizeTo(Bounds().Width(), minHeight);
45 BCheckBox::BCheckBox(const char* name, const char* label, BMessage* message,
46 uint32 flags)
48 BControl(name, label, message, flags | B_WILL_DRAW | B_NAVIGABLE),
49 fPreferredSize(),
50 fOutlined(false),
51 fPartialToOff(false)
56 BCheckBox::BCheckBox(const char* label, BMessage* message)
58 BControl(NULL, label, message, B_WILL_DRAW | B_NAVIGABLE),
59 fPreferredSize(),
60 fOutlined(false),
61 fPartialToOff(false)
66 BCheckBox::BCheckBox(BMessage* data)
68 BControl(data),
69 fOutlined(false),
70 fPartialToOff(false)
75 BCheckBox::~BCheckBox()
80 // #pragma mark - Archiving methods
83 BArchivable*
84 BCheckBox::Instantiate(BMessage* data)
86 if (validate_instantiation(data, "BCheckBox"))
87 return new(std::nothrow) BCheckBox(data);
89 return NULL;
93 status_t
94 BCheckBox::Archive(BMessage* data, bool deep) const
96 return BControl::Archive(data, deep);
100 // #pragma mark - Hook methods
103 void
104 BCheckBox::Draw(BRect updateRect)
106 rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR);
108 uint32 flags = be_control_look->Flags(this);
109 if (fOutlined)
110 flags |= BControlLook::B_CLICKED;
112 BRect checkBoxRect(_CheckBoxFrame());
113 BRect rect(checkBoxRect);
114 be_control_look->DrawCheckBox(this, rect, updateRect, base, flags);
116 // erase the is control flag before drawing the label so that the label
117 // will get drawn using B_PANEL_TEXT_COLOR
118 flags &= ~BControlLook::B_IS_CONTROL;
120 BRect labelRect(Bounds());
121 labelRect.left = checkBoxRect.right + 1
122 + be_control_look->DefaultLabelSpacing();
124 const BBitmap* icon = IconBitmap(
125 B_INACTIVE_ICON_BITMAP | (IsEnabled() ? 0 : B_DISABLED_ICON_BITMAP));
127 be_control_look->DrawLabel(this, Label(), icon, labelRect, updateRect,
128 base, flags);
132 void
133 BCheckBox::AttachedToWindow()
135 BControl::AttachedToWindow();
139 void
140 BCheckBox::DetachedFromWindow()
142 BControl::DetachedFromWindow();
146 void
147 BCheckBox::AllAttached()
149 BControl::AllAttached();
153 void
154 BCheckBox::AllDetached()
156 BControl::AllDetached();
160 void
161 BCheckBox::FrameMoved(BPoint newPosition)
163 BControl::FrameMoved(newPosition);
167 void
168 BCheckBox::FrameResized(float newWidth, float newHeight)
170 BControl::FrameResized(newWidth, newHeight);
174 void
175 BCheckBox::WindowActivated(bool active)
177 BControl::WindowActivated(active);
181 void
182 BCheckBox::MessageReceived(BMessage* message)
184 BControl::MessageReceived(message);
188 void
189 BCheckBox::KeyDown(const char* bytes, int32 numBytes)
191 if (*bytes == B_ENTER || *bytes == B_SPACE) {
192 if (!IsEnabled())
193 return;
195 SetValue(_NextState());
196 Invoke();
197 } else {
198 // skip the BControl implementation
199 BView::KeyDown(bytes, numBytes);
204 void
205 BCheckBox::MouseDown(BPoint where)
207 if (!IsEnabled())
208 return;
210 fOutlined = true;
212 if (Window()->Flags() & B_ASYNCHRONOUS_CONTROLS) {
213 Invalidate();
214 SetTracking(true);
215 SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);
216 } else {
217 BRect bounds = Bounds();
218 uint32 buttons;
220 Invalidate();
221 Window()->UpdateIfNeeded();
223 do {
224 snooze(40000);
226 GetMouse(&where, &buttons, true);
228 bool inside = bounds.Contains(where);
229 if (fOutlined != inside) {
230 fOutlined = inside;
231 Invalidate();
232 Window()->UpdateIfNeeded();
234 } while (buttons != 0);
236 if (fOutlined) {
237 fOutlined = false;
238 SetValue(_NextState());
239 Invoke();
240 } else {
241 Invalidate();
242 Window()->UpdateIfNeeded();
248 void
249 BCheckBox::MouseUp(BPoint where)
251 if (!IsTracking())
252 return;
254 bool inside = Bounds().Contains(where);
256 if (fOutlined != inside) {
257 fOutlined = inside;
258 Invalidate();
261 if (fOutlined) {
262 fOutlined = false;
263 SetValue(_NextState());
264 Invoke();
265 } else {
266 Invalidate();
269 SetTracking(false);
273 void
274 BCheckBox::MouseMoved(BPoint where, uint32 code,
275 const BMessage* dragMessage)
277 if (!IsTracking())
278 return;
280 bool inside = Bounds().Contains(where);
282 if (fOutlined != inside) {
283 fOutlined = inside;
284 Invalidate();
289 // #pragma mark -
292 void
293 BCheckBox::GetPreferredSize(float* _width, float* _height)
295 _ValidatePreferredSize();
297 if (_width)
298 *_width = fPreferredSize.width;
300 if (_height)
301 *_height = fPreferredSize.height;
305 void
306 BCheckBox::ResizeToPreferred()
308 BControl::ResizeToPreferred();
312 BSize
313 BCheckBox::MinSize()
315 return BLayoutUtils::ComposeSize(ExplicitMinSize(),
316 _ValidatePreferredSize());
320 BSize
321 BCheckBox::MaxSize()
323 return BLayoutUtils::ComposeSize(ExplicitMaxSize(),
324 _ValidatePreferredSize());
328 BSize
329 BCheckBox::PreferredSize()
331 return BLayoutUtils::ComposeSize(ExplicitPreferredSize(),
332 _ValidatePreferredSize());
336 BAlignment
337 BCheckBox::LayoutAlignment()
339 return BLayoutUtils::ComposeAlignment(ExplicitAlignment(),
340 BAlignment(B_ALIGN_LEFT, B_ALIGN_VERTICAL_CENTER));
344 // #pragma mark -
347 void
348 BCheckBox::MakeFocus(bool focused)
350 BControl::MakeFocus(focused);
354 void
355 BCheckBox::SetValue(int32 value)
357 // We only accept three possible values.
358 switch (value) {
359 case B_CONTROL_OFF:
360 case B_CONTROL_ON:
361 case B_CONTROL_PARTIALLY_ON:
362 break;
363 default:
364 value = B_CONTROL_ON;
365 break;
368 if (value != Value()) {
369 BControl::SetValueNoUpdate(value);
370 Invalidate(_CheckBoxFrame());
375 status_t
376 BCheckBox::Invoke(BMessage* message)
378 return BControl::Invoke(message);
382 BHandler*
383 BCheckBox::ResolveSpecifier(BMessage* message, int32 index,
384 BMessage* specifier, int32 what, const char* property)
386 return BControl::ResolveSpecifier(message, index, specifier, what,
387 property);
391 status_t
392 BCheckBox::GetSupportedSuites(BMessage* message)
394 return BControl::GetSupportedSuites(message);
398 status_t
399 BCheckBox::Perform(perform_code code, void* _data)
401 switch (code) {
402 case PERFORM_CODE_MIN_SIZE:
403 ((perform_data_min_size*)_data)->return_value
404 = BCheckBox::MinSize();
405 return B_OK;
406 case PERFORM_CODE_MAX_SIZE:
407 ((perform_data_max_size*)_data)->return_value
408 = BCheckBox::MaxSize();
409 return B_OK;
410 case PERFORM_CODE_PREFERRED_SIZE:
411 ((perform_data_preferred_size*)_data)->return_value
412 = BCheckBox::PreferredSize();
413 return B_OK;
414 case PERFORM_CODE_LAYOUT_ALIGNMENT:
415 ((perform_data_layout_alignment*)_data)->return_value
416 = BCheckBox::LayoutAlignment();
417 return B_OK;
418 case PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH:
419 ((perform_data_has_height_for_width*)_data)->return_value
420 = BCheckBox::HasHeightForWidth();
421 return B_OK;
422 case PERFORM_CODE_GET_HEIGHT_FOR_WIDTH:
424 perform_data_get_height_for_width* data
425 = (perform_data_get_height_for_width*)_data;
426 BCheckBox::GetHeightForWidth(data->width, &data->min, &data->max,
427 &data->preferred);
428 return B_OK;
430 case PERFORM_CODE_SET_LAYOUT:
432 perform_data_set_layout* data = (perform_data_set_layout*)_data;
433 BCheckBox::SetLayout(data->layout);
434 return B_OK;
436 case PERFORM_CODE_LAYOUT_INVALIDATED:
438 perform_data_layout_invalidated* data
439 = (perform_data_layout_invalidated*)_data;
440 BCheckBox::LayoutInvalidated(data->descendants);
441 return B_OK;
443 case PERFORM_CODE_DO_LAYOUT:
445 BCheckBox::DoLayout();
446 return B_OK;
448 case PERFORM_CODE_SET_ICON:
450 perform_data_set_icon* data = (perform_data_set_icon*)_data;
451 return BCheckBox::SetIcon(data->icon, data->flags);
455 return BControl::Perform(code, _data);
459 status_t
460 BCheckBox::SetIcon(const BBitmap* icon, uint32 flags)
462 return BControl::SetIcon(icon, flags | B_CREATE_DISABLED_ICON_BITMAPS);
466 void
467 BCheckBox::LayoutInvalidated(bool descendants)
469 // invalidate cached preferred size
470 fPreferredSize.Set(B_SIZE_UNSET, B_SIZE_UNSET);
474 bool
475 BCheckBox::IsPartialStateToOff() const
477 return fPartialToOff;
481 void
482 BCheckBox::SetPartialStateToOff(bool partialToOff)
484 fPartialToOff = partialToOff;
488 // #pragma mark - FBC padding
491 void BCheckBox::_ReservedCheckBox1() {}
492 void BCheckBox::_ReservedCheckBox2() {}
493 void BCheckBox::_ReservedCheckBox3() {}
496 BRect
497 BCheckBox::_CheckBoxFrame(const font_height& fontHeight) const
499 return BRect(0.0f, 2.0f, ceilf(3.0f + fontHeight.ascent),
500 ceilf(5.0f + fontHeight.ascent));
504 BRect
505 BCheckBox::_CheckBoxFrame() const
507 font_height fontHeight;
508 GetFontHeight(&fontHeight);
509 return _CheckBoxFrame(fontHeight);
513 BSize
514 BCheckBox::_ValidatePreferredSize()
516 if (!fPreferredSize.IsWidthSet()) {
517 font_height fontHeight;
518 GetFontHeight(&fontHeight);
520 BRect rect(_CheckBoxFrame(fontHeight));
521 float width = rect.right + rect.left;
522 float height = rect.bottom + rect.top;
524 const BBitmap* icon = IconBitmap(B_INACTIVE_ICON_BITMAP);
525 if (icon != NULL) {
526 width += be_control_look->DefaultLabelSpacing()
527 + icon->Bounds().Width() + 1;
528 height = std::max(height, icon->Bounds().Height());
531 if (const char* label = Label()) {
532 width += be_control_look->DefaultLabelSpacing()
533 + ceilf(StringWidth(label));
534 height = std::max(height,
535 ceilf(6.0f + fontHeight.ascent + fontHeight.descent));
538 fPreferredSize.Set(width, height);
540 ResetLayoutInvalidation();
543 return fPreferredSize;
547 int32
548 BCheckBox::_NextState() const
550 switch (Value()) {
551 case B_CONTROL_OFF:
552 return B_CONTROL_ON;
553 case B_CONTROL_PARTIALLY_ON:
554 return fPartialToOff ? B_CONTROL_OFF : B_CONTROL_ON;
555 case B_CONTROL_ON:
556 default:
557 return B_CONTROL_OFF;
562 BCheckBox &
563 BCheckBox::operator=(const BCheckBox &)
565 return *this;
569 extern "C" void
570 B_IF_GCC_2(InvalidateLayout__9BCheckBoxb, _ZN9BCheckBox16InvalidateLayoutEb)(
571 BCheckBox* box, bool descendants)
573 perform_data_layout_invalidated data;
574 data.descendants = descendants;
576 box->Perform(PERFORM_CODE_LAYOUT_INVALIDATED, &data);