xref: /haiku/src/kits/interface/Box.cpp (revision 7a74a5df454197933bc6e80a542102362ee98703)
1 /*
2  * Copyright (c) 2001-2009, Haiku, Inc.
3  * Distributed under the terms of the MIT license.
4  *
5  * Authors:
6  *		Marc Flerackers (mflerackers@androme.be)
7  *		Stephan Aßmus <superstippi@gmx.de>
8  *		DarkWyrm <bpmagic@columbus.rr.com>
9  *		Axel Dörfler, axeld@pinc-software.de
10  */
11 
12 
13 #include <Box.h>
14 
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 
19 #include <ControlLook.h>
20 #include <Layout.h>
21 #include <LayoutUtils.h>
22 #include <Message.h>
23 #include <Region.h>
24 
25 #include <binary_compatibility/Interface.h>
26 
27 
28 struct BBox::LayoutData {
29 	LayoutData()
30 		: valid(false)
31 	{
32 	}
33 
34 	BRect	label_box;		// label box (label string or label view); in case
35 							// of a label string not including descent
36 	BRect	insets;			// insets induced by border and label
37 	BSize	min;
38 	BSize	max;
39 	BSize	preferred;
40 	bool	valid;			// validity the other fields
41 };
42 
43 
44 BBox::BBox(BRect frame, const char *name, uint32 resizingMode, uint32 flags,
45 		border_style border)
46 	: BView(frame, name, resizingMode, flags  | B_WILL_DRAW | B_FRAME_EVENTS),
47 	  fStyle(border)
48 {
49 	SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
50 	SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR));
51 
52 	_InitObject();
53 }
54 
55 
56 BBox::BBox(const char* name, uint32 flags, border_style border, BView* child)
57 	: BView(name, flags | B_WILL_DRAW | B_FRAME_EVENTS),
58 	  fStyle(border)
59 {
60 	SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
61 	SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR));
62 
63 	_InitObject();
64 
65 	if (child)
66 		AddChild(child);
67 }
68 
69 
70 BBox::BBox(border_style border, BView* child)
71 	: BView(NULL, B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE_JUMP),
72 	  fStyle(border)
73 {
74 	SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
75 	SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR));
76 
77 	_InitObject();
78 
79 	if (child)
80 		AddChild(child);
81 }
82 
83 
84 BBox::BBox(BMessage *archive)
85 	: BView(archive),
86 	  fStyle(B_FANCY_BORDER)
87 {
88 	_InitObject(archive);
89 }
90 
91 
92 BBox::~BBox()
93 {
94 	_ClearLabel();
95 
96 	delete fLayoutData;
97 }
98 
99 
100 BArchivable *
101 BBox::Instantiate(BMessage *archive)
102 {
103 	if (validate_instantiation(archive, "BBox"))
104 		return new BBox(archive);
105 
106 	return NULL;
107 }
108 
109 
110 status_t
111 BBox::Archive(BMessage *archive, bool deep) const
112 {
113 	status_t ret = BView::Archive(archive, deep);
114 
115 	if (fLabel && ret == B_OK)
116 		 ret = archive->AddString("_label", fLabel);
117 
118 	if (fLabelView && ret == B_OK)
119 		 ret = archive->AddBool("_lblview", true);
120 
121 	if (fStyle != B_FANCY_BORDER && ret == B_OK)
122 		ret = archive->AddInt32("_style", fStyle);
123 
124 	return ret;
125 }
126 
127 
128 void
129 BBox::SetBorder(border_style border)
130 {
131 	if (border == fStyle)
132 		return;
133 
134 	fStyle = border;
135 
136 	InvalidateLayout();
137 
138 	if (Window() != NULL && LockLooper()) {
139 		Invalidate();
140 		UnlockLooper();
141 	}
142 }
143 
144 
145 border_style
146 BBox::Border() const
147 {
148 	return fStyle;
149 }
150 
151 
152 //! This function is not part of the R5 API and is not yet finalized yet
153 float
154 BBox::TopBorderOffset()
155 {
156 	_ValidateLayoutData();
157 
158 	if (fLabel != NULL || fLabelView != NULL)
159 		return fLayoutData->label_box.Height() / 2;
160 
161 	return 0;
162 }
163 
164 
165 //! This function is not part of the R5 API and is not yet finalized yet
166 BRect
167 BBox::InnerFrame()
168 {
169 	_ValidateLayoutData();
170 
171 	BRect frame(Bounds());
172 	frame.left += fLayoutData->insets.left;
173 	frame.top += fLayoutData->insets.top;
174 	frame.right -= fLayoutData->insets.right;
175 	frame.bottom -= fLayoutData->insets.bottom;
176 
177 	return frame;
178 }
179 
180 
181 void
182 BBox::SetLabel(const char *string)
183 {
184 	_ClearLabel();
185 
186 	if (string)
187 		fLabel = strdup(string);
188 
189 	InvalidateLayout();
190 
191 	if (Window())
192 		Invalidate();
193 }
194 
195 
196 status_t
197 BBox::SetLabel(BView *viewLabel)
198 {
199 	_ClearLabel();
200 
201 	if (viewLabel) {
202 		fLabelView = viewLabel;
203 		fLabelView->MoveTo(10.0f, 0.0f);
204 		AddChild(fLabelView, ChildAt(0));
205 	}
206 
207 	InvalidateLayout();
208 
209 	if (Window())
210 		Invalidate();
211 
212 	return B_OK;
213 }
214 
215 
216 const char *
217 BBox::Label() const
218 {
219 	return fLabel;
220 }
221 
222 
223 BView *
224 BBox::LabelView() const
225 {
226 	return fLabelView;
227 }
228 
229 
230 void
231 BBox::Draw(BRect updateRect)
232 {
233 	_ValidateLayoutData();
234 
235 	PushState();
236 
237 	BRect labelBox = BRect(0, 0, 0, 0);
238 	if (fLabel != NULL) {
239 		labelBox = fLayoutData->label_box;
240 		BRegion update(updateRect);
241 		update.Exclude(labelBox);
242 
243 		ConstrainClippingRegion(&update);
244 	} else if (fLabelView != NULL)
245 		labelBox = fLabelView->Bounds();
246 
247 	switch (fStyle) {
248 		case B_FANCY_BORDER:
249 			_DrawFancy(labelBox);
250 			break;
251 
252 		case B_PLAIN_BORDER:
253 			_DrawPlain(labelBox);
254 			break;
255 
256 		default:
257 			break;
258 	}
259 
260 	if (fLabel) {
261 		ConstrainClippingRegion(NULL);
262 
263 		font_height fontHeight;
264 		GetFontHeight(&fontHeight);
265 
266 		SetHighColor(0, 0, 0);
267 		DrawString(fLabel, BPoint(10.0f, ceilf(fontHeight.ascent)));
268 	}
269 
270 	PopState();
271 }
272 
273 
274 void
275 BBox::AttachedToWindow()
276 {
277 	BView* parent = Parent();
278 	if (parent != NULL) {
279 		// inherit the color from parent
280 		rgb_color color = parent->ViewColor();
281 		if (color == B_TRANSPARENT_COLOR)
282 			color = ui_color(B_PANEL_BACKGROUND_COLOR);
283 
284 		SetViewColor(color);
285 		SetLowColor(color);
286 	}
287 
288 	// The box could have been resized in the mean time
289 	fBounds = Bounds();
290 }
291 
292 
293 void
294 BBox::DetachedFromWindow()
295 {
296 	BView::DetachedFromWindow();
297 }
298 
299 
300 void
301 BBox::AllAttached()
302 {
303 	BView::AllAttached();
304 }
305 
306 
307 void
308 BBox::AllDetached()
309 {
310 	BView::AllDetached();
311 }
312 
313 
314 void
315 BBox::FrameResized(float width, float height)
316 {
317 	BRect bounds(Bounds());
318 
319 	// invalidate the regions that the app_server did not
320 	// (for removing the previous or drawing the new border)
321 	if (fStyle != B_NO_BORDER) {
322 		// TODO: this must be made part of the be_control_look stuff!
323 		int32 borderSize = fStyle == B_PLAIN_BORDER ? 0 : 2;
324 
325 		BRect invalid(bounds);
326 		if (fBounds.right < bounds.right) {
327 			// enlarging
328 			invalid.left = fBounds.right - borderSize;
329 			invalid.right = fBounds.right;
330 
331 			Invalidate(invalid);
332 		} else if (fBounds.right > bounds.right) {
333 			// shrinking
334 			invalid.left = bounds.right - borderSize;
335 
336 			Invalidate(invalid);
337 		}
338 
339 		invalid = bounds;
340 		if (fBounds.bottom < bounds.bottom) {
341 			// enlarging
342 			invalid.top = fBounds.bottom - borderSize;
343 			invalid.bottom = fBounds.bottom;
344 
345 			Invalidate(invalid);
346 		} else if (fBounds.bottom > bounds.bottom) {
347 			// shrinking
348 			invalid.top = bounds.bottom - borderSize;
349 
350 			Invalidate(invalid);
351 		}
352 	}
353 
354 	fBounds.right = bounds.right;
355 	fBounds.bottom = bounds.bottom;
356 }
357 
358 
359 void
360 BBox::MessageReceived(BMessage *message)
361 {
362 	BView::MessageReceived(message);
363 }
364 
365 
366 void
367 BBox::MouseDown(BPoint point)
368 {
369 	BView::MouseDown(point);
370 }
371 
372 
373 void
374 BBox::MouseUp(BPoint point)
375 {
376 	BView::MouseUp(point);
377 }
378 
379 
380 void
381 BBox::WindowActivated(bool active)
382 {
383 	BView::WindowActivated(active);
384 }
385 
386 
387 void
388 BBox::MouseMoved(BPoint point, uint32 transit, const BMessage *message)
389 {
390 	BView::MouseMoved(point, transit, message);
391 }
392 
393 
394 void
395 BBox::FrameMoved(BPoint newLocation)
396 {
397 	BView::FrameMoved(newLocation);
398 }
399 
400 
401 BHandler *
402 BBox::ResolveSpecifier(BMessage *message, int32 index,
403 	BMessage *specifier, int32 what,
404 	const char *property)
405 {
406 	return BView::ResolveSpecifier(message, index, specifier, what, property);
407 }
408 
409 
410 void
411 BBox::ResizeToPreferred()
412 {
413 	float width, height;
414 	GetPreferredSize(&width, &height);
415 
416 	// make sure the box don't get smaller than it already is
417 	if (width < Bounds().Width())
418 		width = Bounds().Width();
419 	if (height < Bounds().Height())
420 		height = Bounds().Height();
421 
422 	BView::ResizeTo(width, height);
423 }
424 
425 
426 void
427 BBox::GetPreferredSize(float *_width, float *_height)
428 {
429 	_ValidateLayoutData();
430 
431 	if (_width)
432 		*_width = fLayoutData->preferred.width;
433 	if (_height)
434 		*_height = fLayoutData->preferred.height;
435 }
436 
437 
438 void
439 BBox::MakeFocus(bool focused)
440 {
441 	BView::MakeFocus(focused);
442 }
443 
444 
445 status_t
446 BBox::GetSupportedSuites(BMessage *message)
447 {
448 	return BView::GetSupportedSuites(message);
449 }
450 
451 
452 status_t
453 BBox::Perform(perform_code code, void* _data)
454 {
455 	switch (code) {
456 		case PERFORM_CODE_MIN_SIZE:
457 			((perform_data_min_size*)_data)->return_value
458 				= BBox::MinSize();
459 			return B_OK;
460 		case PERFORM_CODE_MAX_SIZE:
461 			((perform_data_max_size*)_data)->return_value
462 				= BBox::MaxSize();
463 			return B_OK;
464 		case PERFORM_CODE_PREFERRED_SIZE:
465 			((perform_data_preferred_size*)_data)->return_value
466 				= BBox::PreferredSize();
467 			return B_OK;
468 		case PERFORM_CODE_LAYOUT_ALIGNMENT:
469 			((perform_data_layout_alignment*)_data)->return_value
470 				= BBox::LayoutAlignment();
471 			return B_OK;
472 		case PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH:
473 			((perform_data_has_height_for_width*)_data)->return_value
474 				= BBox::HasHeightForWidth();
475 			return B_OK;
476 		case PERFORM_CODE_GET_HEIGHT_FOR_WIDTH:
477 		{
478 			perform_data_get_height_for_width* data
479 				= (perform_data_get_height_for_width*)_data;
480 			BBox::GetHeightForWidth(data->width, &data->min, &data->max,
481 				&data->preferred);
482 			return B_OK;
483 }
484 		case PERFORM_CODE_SET_LAYOUT:
485 		{
486 			perform_data_set_layout* data = (perform_data_set_layout*)_data;
487 			BBox::SetLayout(data->layout);
488 			return B_OK;
489 		}
490 		case PERFORM_CODE_LAYOUT_INVALIDATED:
491 		{
492 			perform_data_layout_invalidated* data
493 				= (perform_data_layout_invalidated*)_data;
494 			BBox::LayoutInvalidated(data->descendants);
495 			return B_OK;
496 		}
497 		case PERFORM_CODE_DO_LAYOUT:
498 		{
499 			BBox::DoLayout();
500 			return B_OK;
501 		}
502 	}
503 
504 	return BView::Perform(code, _data);
505 }
506 
507 
508 BSize
509 BBox::MinSize()
510 {
511 	_ValidateLayoutData();
512 
513 	BSize size = (GetLayout() ? GetLayout()->MinSize() : fLayoutData->min);
514 	return BLayoutUtils::ComposeSize(ExplicitMinSize(), size);
515 }
516 
517 
518 BSize
519 BBox::MaxSize()
520 {
521 	_ValidateLayoutData();
522 
523 	BSize size = (GetLayout() ? GetLayout()->MaxSize() : fLayoutData->max);
524 	return BLayoutUtils::ComposeSize(ExplicitMaxSize(), size);
525 }
526 
527 
528 BSize
529 BBox::PreferredSize()
530 {
531 	_ValidateLayoutData();
532 
533 	BSize size = (GetLayout() ? GetLayout()->PreferredSize()
534 		: fLayoutData->preferred);
535 	return BLayoutUtils::ComposeSize(ExplicitPreferredSize(), size);
536 }
537 
538 
539 void
540 BBox::LayoutInvalidated(bool descendants)
541 {
542 	fLayoutData->valid = false;
543 }
544 
545 
546 void
547 BBox::DoLayout()
548 {
549 	// Bail out, if we shan't do layout.
550 	if (!(Flags() & B_SUPPORTS_LAYOUT))
551 		return;
552 
553 	BLayout* layout = GetLayout();
554 
555 	// If the user set a layout, let the base class version call its
556 	// hook. In case when we have BView as a label, remove it from child list
557 	// so it won't be layouted with the rest of views and add it again
558 	// after that.
559 	if (layout != NULL) {
560 		if (fLabelView)
561 			RemoveChild(fLabelView);
562 
563 		BView::DoLayout();
564 
565 		if (fLabelView != NULL) {
566 			DisableLayoutInvalidation();
567 				// don't trigger a relayout
568 			AddChild(fLabelView, ChildAt(0));
569 			EnableLayoutInvalidation();
570 		} else
571 			return;
572 	}
573 
574 	_ValidateLayoutData();
575 
576 	// Even if the user set a layout, restore label view to it's
577 	// desired position.
578 
579 	// layout the label view
580 	if (fLabelView != NULL) {
581 		fLabelView->MoveTo(fLayoutData->label_box.LeftTop());
582 		fLabelView->ResizeTo(fLayoutData->label_box.Size());
583 	}
584 
585 	// If we have layout return here and do not layout the child
586 	if (layout != NULL)
587 		return;
588 
589 	// layout the child
590 	if (BView* child = _Child()) {
591 		BRect frame(Bounds());
592 		frame.left += fLayoutData->insets.left;
593 		frame.top += fLayoutData->insets.top;
594 		frame.right -= fLayoutData->insets.right;
595 		frame.bottom -= fLayoutData->insets.bottom;
596 
597 		BLayoutUtils::AlignInFrame(child, frame);
598 	}
599 }
600 
601 
602 void BBox::_ReservedBox1() {}
603 void BBox::_ReservedBox2() {}
604 
605 
606 BBox &
607 BBox::operator=(const BBox &)
608 {
609 	return *this;
610 }
611 
612 
613 void
614 BBox::_InitObject(BMessage* archive)
615 {
616 	fBounds = Bounds();
617 
618 	fLabel = NULL;
619 	fLabelView = NULL;
620 	fLayoutData = new LayoutData;
621 
622 	int32 flags = 0;
623 
624 	BFont font(be_bold_font);
625 
626 	if (!archive || !archive->HasString("_fname"))
627 		flags = B_FONT_FAMILY_AND_STYLE;
628 
629 	if (!archive || !archive->HasFloat("_fflt"))
630 		flags |= B_FONT_SIZE;
631 
632 	if (flags != 0)
633 		SetFont(&font, flags);
634 
635 	if (archive != NULL) {
636 		const char *string;
637 		if (archive->FindString("_label", &string) == B_OK)
638 			SetLabel(string);
639 
640 		bool fancy;
641 		int32 style;
642 
643 		if (archive->FindBool("_style", &fancy) == B_OK)
644 			fStyle = fancy ? B_FANCY_BORDER : B_PLAIN_BORDER;
645 		else if (archive->FindInt32("_style", &style) == B_OK)
646 			fStyle = (border_style)style;
647 
648 		bool hasLabelView;
649 		if (archive->FindBool("_lblview", &hasLabelView) == B_OK)
650 			fLabelView = ChildAt(0);
651 	}
652 }
653 
654 
655 void
656 BBox::_DrawPlain(BRect labelBox)
657 {
658 	BRect rect = Bounds();
659 	rect.top += TopBorderOffset();
660 
661 	float lightTint;
662 	float shadowTint;
663 	if (be_control_look != NULL) {
664 		lightTint = B_LIGHTEN_1_TINT;
665 		shadowTint = B_DARKEN_1_TINT;
666 	} else {
667 		lightTint = B_LIGHTEN_MAX_TINT;
668 		shadowTint = B_DARKEN_3_TINT;
669 	}
670 
671 	if (rect.Height() == 0.0 || rect.Width() == 0.0) {
672 		// used as separator
673 		rgb_color shadow = tint_color(ViewColor(), B_DARKEN_2_TINT);
674 
675 		SetHighColor(shadow);
676 		StrokeLine(rect.LeftTop(),rect.RightBottom());
677 	} else {
678 		// used as box
679 		rgb_color light = tint_color(ViewColor(), lightTint);
680 		rgb_color shadow = tint_color(ViewColor(), shadowTint);
681 
682 		BeginLineArray(4);
683 			AddLine(BPoint(rect.left, rect.bottom),
684 					BPoint(rect.left, rect.top), light);
685 			AddLine(BPoint(rect.left + 1.0f, rect.top),
686 					BPoint(rect.right, rect.top), light);
687 			AddLine(BPoint(rect.left + 1.0f, rect.bottom),
688 					BPoint(rect.right, rect.bottom), shadow);
689 			AddLine(BPoint(rect.right, rect.bottom - 1.0f),
690 					BPoint(rect.right, rect.top + 1.0f), shadow);
691 		EndLineArray();
692 	}
693 }
694 
695 
696 void
697 BBox::_DrawFancy(BRect labelBox)
698 {
699 	BRect rect = Bounds();
700 	rect.top += TopBorderOffset();
701 
702 	if (be_control_look != NULL) {
703 		rgb_color base = ViewColor();
704 		if (rect.Height() == 1.0) {
705 			// used as horizontal separator
706 			be_control_look->DrawGroupFrame(this, rect, rect, base,
707 				BControlLook::B_TOP_BORDER);
708 		} else if (rect.Width() == 1.0) {
709 			// used as vertical separator
710 			be_control_look->DrawGroupFrame(this, rect, rect, base,
711 				BControlLook::B_LEFT_BORDER);
712 		} else {
713 			// used as box
714 			be_control_look->DrawGroupFrame(this, rect, rect, base);
715 		}
716 		return;
717 	}
718 
719 	rgb_color light = tint_color(ViewColor(), B_LIGHTEN_MAX_TINT);
720 	rgb_color shadow = tint_color(ViewColor(), B_DARKEN_3_TINT);
721 
722 	if (rect.Height() == 1.0) {
723 		// used as horizontal separator
724 		BeginLineArray(2);
725 			AddLine(BPoint(rect.left, rect.top),
726 					BPoint(rect.right, rect.top), shadow);
727 			AddLine(BPoint(rect.left, rect.bottom),
728 					BPoint(rect.right, rect.bottom), light);
729 		EndLineArray();
730 	} else if (rect.Width() == 1.0) {
731 		// used as vertical separator
732 		BeginLineArray(2);
733 			AddLine(BPoint(rect.left, rect.top),
734 					BPoint(rect.left, rect.bottom), shadow);
735 			AddLine(BPoint(rect.right, rect.top),
736 					BPoint(rect.right, rect.bottom), light);
737 		EndLineArray();
738 	} else {
739 		// used as box
740 		BeginLineArray(8);
741 			AddLine(BPoint(rect.left, rect.bottom - 1.0),
742 					BPoint(rect.left, rect.top), shadow);
743 			AddLine(BPoint(rect.left + 1.0, rect.top),
744 					BPoint(rect.right - 1.0, rect.top), shadow);
745 			AddLine(BPoint(rect.left, rect.bottom),
746 					BPoint(rect.right, rect.bottom), light);
747 			AddLine(BPoint(rect.right, rect.bottom - 1.0),
748 					BPoint(rect.right, rect.top), light);
749 
750 			rect.InsetBy(1.0, 1.0);
751 
752 			AddLine(BPoint(rect.left, rect.bottom - 1.0),
753 					BPoint(rect.left, rect.top), light);
754 			AddLine(BPoint(rect.left + 1.0, rect.top),
755 					BPoint(rect.right - 1.0, rect.top), light);
756 			AddLine(BPoint(rect.left, rect.bottom),
757 					BPoint(rect.right, rect.bottom), shadow);
758 			AddLine(BPoint(rect.right, rect.bottom - 1.0),
759 					BPoint(rect.right, rect.top), shadow);
760 		EndLineArray();
761 	}
762 }
763 
764 
765 void
766 BBox::_ClearLabel()
767 {
768 	fBounds.top = 0;
769 
770 	if (fLabel) {
771 		free(fLabel);
772 		fLabel = NULL;
773 	} else if (fLabelView) {
774 		fLabelView->RemoveSelf();
775 		delete fLabelView;
776 		fLabelView = NULL;
777 	}
778 }
779 
780 
781 BView*
782 BBox::_Child() const
783 {
784 	for (int32 i = 0; BView* view = ChildAt(i); i++) {
785 		if (view != fLabelView)
786 			return view;
787 	}
788 
789 	return NULL;
790 }
791 
792 
793 void
794 BBox::_ValidateLayoutData()
795 {
796 	if (fLayoutData->valid)
797 		return;
798 
799 	// compute the label box, width and height
800 	bool label = true;
801 	float labelHeight = 0;	// height of the label (pixel count)
802 	if (fLabel) {
803 		// leave 6 pixels of the frame, and have a gap of 4 pixels between
804 		// the frame and the text on either side
805 		font_height fontHeight;
806 		GetFontHeight(&fontHeight);
807 		fLayoutData->label_box.Set(6.0f, 0, 14.0f + StringWidth(fLabel),
808 			ceilf(fontHeight.ascent));
809 		labelHeight = ceilf(fontHeight.ascent + fontHeight.descent) + 1;
810 	} else if (fLabelView) {
811 		// the label view is placed at (0, 10) at its preferred size
812 		BSize size = fLabelView->PreferredSize();
813 		fLayoutData->label_box.Set(10, 0, 10 + size.width, size.height);
814 		labelHeight = size.height + 1;
815 	} else {
816 		label = false;
817 	}
818 
819 	// border
820 	switch (fStyle) {
821 		case B_PLAIN_BORDER:
822 			fLayoutData->insets.Set(1, 1, 1, 1);
823 			break;
824 		case B_FANCY_BORDER:
825 			fLayoutData->insets.Set(3, 3, 3, 3);
826 			break;
827 		case B_NO_BORDER:
828 		default:
829 			fLayoutData->insets.Set(0, 0, 0, 0);
830 			break;
831 	}
832 
833 	// if there's a label, the top inset will be dictated by the label
834 	if (label && labelHeight > fLayoutData->insets.top)
835 		fLayoutData->insets.top = labelHeight;
836 
837 	// total number of pixel the border adds
838 	float addWidth = fLayoutData->insets.left + fLayoutData->insets.right;
839 	float addHeight = fLayoutData->insets.top + fLayoutData->insets.bottom;
840 
841 	// compute the minimal width induced by the label
842 	float minWidth;
843 	if (label)
844 		minWidth = fLayoutData->label_box.right + fLayoutData->insets.right;
845 	else
846 		minWidth = addWidth - 1;
847 
848 	// finally consider the child constraints, if we shall support layout
849 	BView* child = _Child();
850 	if (child && (Flags() & B_SUPPORTS_LAYOUT)) {
851 		BSize min = child->MinSize();
852 		BSize max = child->MaxSize();
853 		BSize preferred = child->PreferredSize();
854 
855 		min.width += addWidth;
856 		min.height += addHeight;
857 		preferred.width += addWidth;
858 		preferred.height += addHeight;
859 		max.width = BLayoutUtils::AddDistances(max.width, addWidth - 1);
860 		max.height = BLayoutUtils::AddDistances(max.height, addHeight - 1);
861 
862 		if (min.width < minWidth)
863 			min.width = minWidth;
864 		BLayoutUtils::FixSizeConstraints(min, max, preferred);
865 
866 		fLayoutData->min = min;
867 		fLayoutData->max = max;
868 		fLayoutData->preferred = preferred;
869 	} else {
870 		fLayoutData->min.Set(minWidth, addHeight - 1);
871 		fLayoutData->max.Set(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED);
872 		fLayoutData->preferred = fLayoutData->min;
873 	}
874 
875 	fLayoutData->valid = true;
876 	ResetLayoutInvalidation();
877 }
878 
879 
880 extern "C" void
881 B_IF_GCC_2(InvalidateLayout__4BBoxb, _ZN4BBox16InvalidateLayoutEb)(
882 	BBox* box, bool descendants)
883 {
884 	perform_data_layout_invalidated data;
885 	data.descendants = descendants;
886 
887 	box->Perform(PERFORM_CODE_LAYOUT_INVALIDATED, &data);
888 }
889 
890