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