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