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