xref: /haiku/src/kits/interface/Box.cpp (revision 922e7ba1f3228e6f28db69b0ded8f86eb32dea17)
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_INVALIDATE_LAYOUT:
491 		{
492 			perform_data_invalidate_layout* data
493 				= (perform_data_invalidate_layout*)_data;
494 			BBox::InvalidateLayout(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::InvalidateLayout(bool descendants)
541 {
542 	fLayoutData->valid = false;
543 	BView::InvalidateLayout(descendants);
544 }
545 
546 
547 void
548 BBox::DoLayout()
549 {
550 	// Bail out, if we shan't do layout.
551 	if (!(Flags() & B_SUPPORTS_LAYOUT))
552 		return;
553 
554 	bool layouted = GetLayout() ? true : false;
555 
556 	// If the user set a layout, let the base class version call its
557 	// hook. In case when we have BView as a label, remove it from child list
558 	// so it won't be layouted with the rest of views and add it again
559 	// after that.
560 	if (layouted) {
561 		if (fLabelView)
562 			RemoveChild(fLabelView);
563 
564 		BView::DoLayout();
565 
566 		if (fLabelView)
567 			AddChild(fLabelView, ChildAt(0));
568 		else
569 			return;
570 	}
571 
572 	_ValidateLayoutData();
573 
574 	// Even if the user set a layout, restore label view to it's
575 	// desired position.
576 
577 	// layout the label view
578 	if (fLabelView) {
579 		fLabelView->MoveTo(fLayoutData->label_box.LeftTop());
580 		fLabelView->ResizeTo(fLayoutData->label_box.Size());
581 	}
582 
583 	// If we have layout return here and do not layout the child
584 	if (layouted)
585 		return;
586 
587 	// layout the child
588 	if (BView* child = _Child()) {
589 		BRect frame(Bounds());
590 		frame.left += fLayoutData->insets.left;
591 		frame.top += fLayoutData->insets.top;
592 		frame.right -= fLayoutData->insets.right;
593 		frame.bottom -= fLayoutData->insets.bottom;
594 
595 		BLayoutUtils::AlignInFrame(child, frame);
596 	}
597 }
598 
599 
600 void BBox::_ReservedBox1() {}
601 void BBox::_ReservedBox2() {}
602 
603 
604 BBox &
605 BBox::operator=(const BBox &)
606 {
607 	return *this;
608 }
609 
610 
611 void
612 BBox::_InitObject(BMessage* archive)
613 {
614 	fBounds = Bounds();
615 
616 	fLabel = NULL;
617 	fLabelView = NULL;
618 	fLayoutData = new LayoutData;
619 
620 	int32 flags = 0;
621 
622 	BFont font(be_bold_font);
623 
624 	if (!archive || !archive->HasString("_fname"))
625 		flags = B_FONT_FAMILY_AND_STYLE;
626 
627 	if (!archive || !archive->HasFloat("_fflt"))
628 		flags |= B_FONT_SIZE;
629 
630 	if (flags != 0)
631 		SetFont(&font, flags);
632 
633 	if (archive != NULL) {
634 		const char *string;
635 		if (archive->FindString("_label", &string) == B_OK)
636 			SetLabel(string);
637 
638 		bool fancy;
639 		int32 style;
640 
641 		if (archive->FindBool("_style", &fancy) == B_OK)
642 			fStyle = fancy ? B_FANCY_BORDER : B_PLAIN_BORDER;
643 		else if (archive->FindInt32("_style", &style) == B_OK)
644 			fStyle = (border_style)style;
645 
646 		bool hasLabelView;
647 		if (archive->FindBool("_lblview", &hasLabelView) == B_OK)
648 			fLabelView = ChildAt(0);
649 	}
650 }
651 
652 
653 void
654 BBox::_DrawPlain(BRect labelBox)
655 {
656 	BRect rect = Bounds();
657 	rect.top += TopBorderOffset();
658 
659 	float lightTint;
660 	float shadowTint;
661 	if (be_control_look != NULL) {
662 		lightTint = B_LIGHTEN_1_TINT;
663 		shadowTint = B_DARKEN_1_TINT;
664 	} else {
665 		lightTint = B_LIGHTEN_MAX_TINT;
666 		shadowTint = B_DARKEN_3_TINT;
667 	}
668 
669 	if (rect.Height() == 0.0 || rect.Width() == 0.0) {
670 		// used as separator
671 		rgb_color shadow = tint_color(ViewColor(), B_DARKEN_2_TINT);
672 
673 		SetHighColor(shadow);
674 		StrokeLine(rect.LeftTop(),rect.RightBottom());
675 	} else {
676 		// used as box
677 		rgb_color light = tint_color(ViewColor(), lightTint);
678 		rgb_color shadow = tint_color(ViewColor(), shadowTint);
679 
680 		BeginLineArray(4);
681 			AddLine(BPoint(rect.left, rect.bottom),
682 					BPoint(rect.left, rect.top), light);
683 			AddLine(BPoint(rect.left + 1.0f, rect.top),
684 					BPoint(rect.right, rect.top), light);
685 			AddLine(BPoint(rect.left + 1.0f, rect.bottom),
686 					BPoint(rect.right, rect.bottom), shadow);
687 			AddLine(BPoint(rect.right, rect.bottom - 1.0f),
688 					BPoint(rect.right, rect.top + 1.0f), shadow);
689 		EndLineArray();
690 	}
691 }
692 
693 
694 void
695 BBox::_DrawFancy(BRect labelBox)
696 {
697 	BRect rect = Bounds();
698 	rect.top += TopBorderOffset();
699 
700 	if (be_control_look != NULL) {
701 		rgb_color base = ViewColor();
702 		if (rect.Height() == 1.0) {
703 			// used as horizontal separator
704 			be_control_look->DrawGroupFrame(this, rect, rect, base,
705 				BControlLook::B_TOP_BORDER);
706 		} else if (rect.Width() == 1.0) {
707 			// used as vertical separator
708 			be_control_look->DrawGroupFrame(this, rect, rect, base,
709 				BControlLook::B_LEFT_BORDER);
710 		} else {
711 			// used as box
712 			be_control_look->DrawGroupFrame(this, rect, rect, base);
713 		}
714 		return;
715 	}
716 
717 	rgb_color light = tint_color(ViewColor(), B_LIGHTEN_MAX_TINT);
718 	rgb_color shadow = tint_color(ViewColor(), B_DARKEN_3_TINT);
719 
720 	if (rect.Height() == 1.0) {
721 		// used as horizontal separator
722 		BeginLineArray(2);
723 			AddLine(BPoint(rect.left, rect.top),
724 					BPoint(rect.right, rect.top), shadow);
725 			AddLine(BPoint(rect.left, rect.bottom),
726 					BPoint(rect.right, rect.bottom), light);
727 		EndLineArray();
728 	} else if (rect.Width() == 1.0) {
729 		// used as vertical separator
730 		BeginLineArray(2);
731 			AddLine(BPoint(rect.left, rect.top),
732 					BPoint(rect.left, rect.bottom), shadow);
733 			AddLine(BPoint(rect.right, rect.top),
734 					BPoint(rect.right, rect.bottom), light);
735 		EndLineArray();
736 	} else {
737 		// used as box
738 		BeginLineArray(8);
739 			AddLine(BPoint(rect.left, rect.bottom - 1.0),
740 					BPoint(rect.left, rect.top), shadow);
741 			AddLine(BPoint(rect.left + 1.0, rect.top),
742 					BPoint(rect.right - 1.0, rect.top), shadow);
743 			AddLine(BPoint(rect.left, rect.bottom),
744 					BPoint(rect.right, rect.bottom), light);
745 			AddLine(BPoint(rect.right, rect.bottom - 1.0),
746 					BPoint(rect.right, rect.top), light);
747 
748 			rect.InsetBy(1.0, 1.0);
749 
750 			AddLine(BPoint(rect.left, rect.bottom - 1.0),
751 					BPoint(rect.left, rect.top), light);
752 			AddLine(BPoint(rect.left + 1.0, rect.top),
753 					BPoint(rect.right - 1.0, rect.top), light);
754 			AddLine(BPoint(rect.left, rect.bottom),
755 					BPoint(rect.right, rect.bottom), shadow);
756 			AddLine(BPoint(rect.right, rect.bottom - 1.0),
757 					BPoint(rect.right, rect.top), shadow);
758 		EndLineArray();
759 	}
760 }
761 
762 
763 void
764 BBox::_ClearLabel()
765 {
766 	fBounds.top = 0;
767 
768 	if (fLabel) {
769 		free(fLabel);
770 		fLabel = NULL;
771 	} else if (fLabelView) {
772 		fLabelView->RemoveSelf();
773 		delete fLabelView;
774 		fLabelView = NULL;
775 	}
776 }
777 
778 
779 BView*
780 BBox::_Child() const
781 {
782 	for (int32 i = 0; BView* view = ChildAt(i); i++) {
783 		if (view != fLabelView)
784 			return view;
785 	}
786 
787 	return NULL;
788 }
789 
790 
791 void
792 BBox::_ValidateLayoutData()
793 {
794 	if (fLayoutData->valid)
795 		return;
796 
797 	// compute the label box, width and height
798 	bool label = true;
799 	float labelHeight = 0;	// height of the label (pixel count)
800 	if (fLabel) {
801 		// leave 6 pixels of the frame, and have a gap of 4 pixels between
802 		// the frame and the text on either side
803 		font_height fontHeight;
804 		GetFontHeight(&fontHeight);
805 		fLayoutData->label_box.Set(6.0f, 0, 14.0f + StringWidth(fLabel),
806 			ceilf(fontHeight.ascent));
807 		labelHeight = ceilf(fontHeight.ascent + fontHeight.descent) + 1;
808 	} else if (fLabelView) {
809 		// the label view is placed at (0, 10) at its preferred size
810 		BSize size = fLabelView->PreferredSize();
811 		fLayoutData->label_box.Set(10, 0, 10 + size.width, size.height);
812 		labelHeight = size.height + 1;
813 	} else {
814 		label = false;
815 	}
816 
817 	// border
818 	switch (fStyle) {
819 		case B_PLAIN_BORDER:
820 			fLayoutData->insets.Set(1, 1, 1, 1);
821 			break;
822 		case B_FANCY_BORDER:
823 			fLayoutData->insets.Set(3, 3, 3, 3);
824 			break;
825 		case B_NO_BORDER:
826 		default:
827 			fLayoutData->insets.Set(0, 0, 0, 0);
828 			break;
829 	}
830 
831 	// if there's a label, the top inset will be dictated by the label
832 	if (label && labelHeight > fLayoutData->insets.top)
833 		fLayoutData->insets.top = labelHeight;
834 
835 	// total number of pixel the border adds
836 	float addWidth = fLayoutData->insets.left + fLayoutData->insets.right;
837 	float addHeight = fLayoutData->insets.top + fLayoutData->insets.bottom;
838 
839 	// compute the minimal width induced by the label
840 	float minWidth;
841 	if (label)
842 		minWidth = fLayoutData->label_box.right + fLayoutData->insets.right;
843 	else
844 		minWidth = addWidth - 1;
845 
846 	// finally consider the child constraints, if we shall support layout
847 	BView* child = _Child();
848 	if (child && (Flags() & B_SUPPORTS_LAYOUT)) {
849 		BSize min = child->MinSize();
850 		BSize max = child->MaxSize();
851 		BSize preferred = child->PreferredSize();
852 
853 		min.width += addWidth;
854 		min.height += addHeight;
855 		preferred.width += addWidth;
856 		preferred.height += addHeight;
857 		max.width = BLayoutUtils::AddDistances(max.width, addWidth - 1);
858 		max.height = BLayoutUtils::AddDistances(max.height, addHeight - 1);
859 
860 		if (min.width < minWidth)
861 			min.width = minWidth;
862 		BLayoutUtils::FixSizeConstraints(min, max, preferred);
863 
864 		fLayoutData->min = min;
865 		fLayoutData->max = max;
866 		fLayoutData->preferred = preferred;
867 	} else {
868 		fLayoutData->min.Set(minWidth, addHeight - 1);
869 		fLayoutData->max.Set(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED);
870 		fLayoutData->preferred = fLayoutData->min;
871 	}
872 
873 	fLayoutData->valid = true;
874 	ResetLayoutInvalidation();
875 }
876 
877