xref: /haiku/src/kits/interface/StatusBar.cpp (revision 22440f4105cafc95cc1d49f9bc65bb395c527d86)
1 /*
2  * Copyright 2001-2008, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Marc Flerackers (mflerackers@androme.be)
7  *		Axel Dörfler, axeld@pinc-software.de
8  *		Stephan Aßmus <superstippi@gmx.de>
9  */
10 
11 /*! BStatusBar displays a "percentage-of-completion" gauge. */
12 #include <StatusBar.h>
13 
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 
18 #include <ControlLook.h>
19 #include <Layout.h>
20 #include <LayoutUtils.h>
21 #include <Message.h>
22 #include <Region.h>
23 
24 #include <binary_compatibility/Interface.h>
25 
26 
27 static const rgb_color kDefaultBarColor = {50, 150, 255, 255};
28 
29 
30 BStatusBar::BStatusBar(BRect frame, const char *name, const char *label,
31 		const char *trailingLabel)
32 	:
33 	BView(frame, name, B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW),
34 	fLabel(label),
35 	fTrailingLabel(trailingLabel)
36 {
37 	_InitObject();
38 }
39 
40 
41 BStatusBar::BStatusBar(const char *name, const char *label,
42 		const char *trailingLabel)
43 	:
44 	BView(BRect(0, 0, -1, -1), name, B_FOLLOW_LEFT | B_FOLLOW_TOP,
45 		B_WILL_DRAW | B_SUPPORTS_LAYOUT),
46 	fLabel(label),
47 	fTrailingLabel(trailingLabel)
48 {
49 	_InitObject();
50 }
51 
52 
53 BStatusBar::BStatusBar(BMessage *archive)
54 	:
55 	BView(archive)
56 {
57 	_InitObject();
58 
59 	archive->FindString("_label", &fLabel);
60 	archive->FindString("_tlabel", &fTrailingLabel);
61 
62 	archive->FindString("_text", &fText);
63 	archive->FindString("_ttext", &fTrailingText);
64 
65 	float floatValue;
66 	if (archive->FindFloat("_high", &floatValue) == B_OK) {
67 		fBarHeight = floatValue;
68 		fCustomBarHeight = true;
69 	}
70 
71 	int32 color;
72 	if (archive->FindInt32("_bcolor", (int32 *)&color) == B_OK)
73 		fBarColor = *(rgb_color *)&color;
74 
75 	if (archive->FindFloat("_val", &floatValue) == B_OK)
76 		fCurrent = floatValue;
77 	if (archive->FindFloat("_max", &floatValue) == B_OK)
78 		fMax = floatValue;
79 }
80 
81 
82 BStatusBar::~BStatusBar()
83 {
84 }
85 
86 
87 BArchivable *
88 BStatusBar::Instantiate(BMessage *archive)
89 {
90 	if (validate_instantiation(archive, "BStatusBar"))
91 		return new BStatusBar(archive);
92 
93 	return NULL;
94 }
95 
96 
97 status_t
98 BStatusBar::Archive(BMessage *archive, bool deep) const
99 {
100 	status_t err = BView::Archive(archive, deep);
101 	if (err < B_OK)
102 		return err;
103 
104 	if (fCustomBarHeight)
105 		err = archive->AddFloat("_high", fBarHeight);
106 
107 	if (err == B_OK && fBarColor != kDefaultBarColor)
108 		err = archive->AddInt32("_bcolor", (const uint32 &)fBarColor);
109 
110 	if (err == B_OK && fCurrent != 0)
111 		err = archive->AddFloat("_val", fCurrent);
112 	if (err == B_OK && fMax != 100 )
113 		err = archive->AddFloat("_max", fMax);
114 
115 	if (err == B_OK && fText.Length())
116 		err = archive->AddString("_text", fText);
117 	if (err == B_OK && fTrailingText.Length())
118 		err = archive->AddString("_ttext", fTrailingText);
119 
120 	if (err == B_OK && fLabel.Length())
121 		err = archive->AddString("_label", fLabel);
122 	if (err == B_OK && fTrailingLabel.Length())
123 		err = archive->AddString ("_tlabel", fTrailingLabel);
124 
125 	return err;
126 }
127 
128 
129 // #pragma mark -
130 
131 
132 void
133 BStatusBar::AttachedToWindow()
134 {
135 	// resize so that the height fits
136 	float width, height;
137 	GetPreferredSize(&width, &height);
138 	ResizeTo(Bounds().Width(), height);
139 
140 	SetViewColor(B_TRANSPARENT_COLOR);
141 	rgb_color lowColor = B_TRANSPARENT_COLOR;
142 
143 	BView* parent = Parent();
144 	if (parent != NULL)
145 		lowColor = parent->ViewColor();
146 
147 	if (lowColor == B_TRANSPARENT_COLOR)
148 		lowColor = ui_color(B_PANEL_BACKGROUND_COLOR);
149 
150 	SetLowColor(lowColor);
151 
152 	fTextDivider = Bounds().Width();
153 }
154 
155 
156 void
157 BStatusBar::DetachedFromWindow()
158 {
159 	BView::DetachedFromWindow();
160 }
161 
162 
163 void
164 BStatusBar::AllAttached()
165 {
166 	BView::AllAttached();
167 }
168 
169 
170 void
171 BStatusBar::AllDetached()
172 {
173 	BView::AllDetached();
174 }
175 
176 
177 // #pragma mark -
178 
179 
180 void
181 BStatusBar::WindowActivated(bool state)
182 {
183 	BView::WindowActivated(state);
184 }
185 
186 
187 void
188 BStatusBar::MakeFocus(bool state)
189 {
190 	BView::MakeFocus(state);
191 }
192 
193 
194 // #pragma mark -
195 
196 
197 void
198 BStatusBar::GetPreferredSize(float* _width, float* _height)
199 {
200 	if (_width) {
201 		// AttachedToWindow() might not have been called yet
202 		*_width = ceilf(StringWidth(fLabel.String()))
203 			+ ceilf(StringWidth(fTrailingLabel.String()))
204 			+ ceilf(StringWidth(fText.String()))
205 			+ ceilf(StringWidth(fTrailingText.String()))
206 			+ 5;
207 	}
208 
209 	if (_height) {
210 		float labelHeight = 0;
211 		if (_HasText()) {
212 			font_height fontHeight;
213 			GetFontHeight(&fontHeight);
214 			labelHeight = ceilf(fontHeight.ascent + fontHeight.descent) + 6;
215 		}
216 
217 		*_height = labelHeight + BarHeight();
218 	}
219 }
220 
221 
222 BSize
223 BStatusBar::MinSize()
224 {
225 	float width, height;
226 	GetPreferredSize(&width, &height);
227 
228 	return BLayoutUtils::ComposeSize(ExplicitMinSize(), BSize(width, height));
229 }
230 
231 
232 BSize
233 BStatusBar::MaxSize()
234 {
235 	float width, height;
236 	GetPreferredSize(&width, &height);
237 
238 	return BLayoutUtils::ComposeSize(ExplicitMaxSize(),
239 		BSize(B_SIZE_UNLIMITED, height));
240 }
241 
242 
243 BSize
244 BStatusBar::PreferredSize()
245 {
246 	float width, height;
247 	GetPreferredSize(&width, &height);
248 
249 	return BLayoutUtils::ComposeSize(ExplicitPreferredSize(),
250 		BSize(width, height));
251 }
252 
253 
254 void
255 BStatusBar::ResizeToPreferred()
256 {
257 	BView::ResizeToPreferred();
258 }
259 
260 
261 void
262 BStatusBar::FrameMoved(BPoint newPosition)
263 {
264 	BView::FrameMoved(newPosition);
265 }
266 
267 
268 void
269 BStatusBar::FrameResized(float newWidth, float newHeight)
270 {
271 	BView::FrameResized(newWidth, newHeight);
272 	Invalidate();
273 }
274 
275 
276 // #pragma mark -
277 
278 
279 void
280 BStatusBar::Draw(BRect updateRect)
281 {
282 	rgb_color backgroundColor = LowColor();
283 
284 	font_height fontHeight;
285 	GetFontHeight(&fontHeight);
286 	BRect barFrame = _BarFrame(&fontHeight);
287 	BRect outerFrame = barFrame.InsetByCopy(-2, -2);
288 
289 	BRegion background(updateRect);
290 	background.Exclude(outerFrame);
291 	FillRegion(&background, B_SOLID_LOW);
292 
293 	// Draw labels/texts
294 
295 	BRect rect = outerFrame;
296 	rect.top = 0;
297 	rect.bottom = outerFrame.top - 1;
298 
299 	if (updateRect.Intersects(rect)) {
300 		// update labels
301 		BString leftText;
302 		leftText << fLabel << fText;
303 
304 		BString rightText;
305 		rightText << fTrailingText << fTrailingLabel;
306 
307 		float baseLine = ceilf(fontHeight.ascent) + 1;
308 		fTextDivider = rect.right;
309 
310 		BFont font;
311 		GetFont(&font);
312 
313 		if (rightText.Length()) {
314 			font.TruncateString(&rightText, B_TRUNCATE_BEGINNING, rect.Width());
315 			fTextDivider -= StringWidth(rightText.String());
316 		}
317 
318 		if (leftText.Length()) {
319 			float width = max_c(0.0, fTextDivider - rect.left);
320 			font.TruncateString(&leftText, B_TRUNCATE_END, width);
321 		}
322 
323 		SetHighColor(ui_color(B_CONTROL_TEXT_COLOR));
324 
325 		if (leftText.Length())
326 			DrawString(leftText.String(), BPoint(rect.left, baseLine));
327 
328 		if (rightText.Length())
329 			DrawString(rightText.String(), BPoint(fTextDivider, baseLine));
330 
331 	}
332 
333 	// Draw bar
334 
335 	if (!updateRect.Intersects(outerFrame))
336 		return;
337 
338 	rect = outerFrame;
339 
340 	if (be_control_look != NULL) {
341 		be_control_look->DrawStatusBar(this, rect, updateRect,
342 			backgroundColor, fBarColor, _BarPosition(barFrame));
343 		return;
344 	}
345 
346 	// First bevel
347 	SetHighColor(tint_color(ui_color ( B_PANEL_BACKGROUND_COLOR ), B_DARKEN_1_TINT));
348 	StrokeLine(rect.LeftBottom(), rect.LeftTop());
349 	StrokeLine(rect.RightTop());
350 
351 	SetHighColor(tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), B_LIGHTEN_2_TINT));
352 	StrokeLine(BPoint(rect.left + 1, rect.bottom), rect.RightBottom());
353 	StrokeLine(BPoint(rect.right, rect.top + 1));
354 
355 	rect.InsetBy(1, 1);
356 
357 	// Second bevel
358 	SetHighColor(tint_color(ui_color ( B_PANEL_BACKGROUND_COLOR ), B_DARKEN_4_TINT));
359 	StrokeLine(rect.LeftBottom(), rect.LeftTop());
360 	StrokeLine(rect.RightTop());
361 
362 	SetHighColor(ui_color(B_PANEL_BACKGROUND_COLOR));
363 	StrokeLine(BPoint(rect.left + 1, rect.bottom), rect.RightBottom());
364 	StrokeLine(BPoint(rect.right, rect.top + 1));
365 
366 	rect = barFrame;
367 	rect.right = _BarPosition(barFrame);
368 
369 	// draw bar itself
370 
371 	if (rect.right >= rect.left) {
372 		// Bevel
373 		SetHighColor(tint_color(fBarColor, B_LIGHTEN_2_TINT));
374 		StrokeLine(rect.LeftBottom(), rect.LeftTop());
375 		StrokeLine(rect.RightTop());
376 
377 		SetHighColor(tint_color(fBarColor, B_DARKEN_2_TINT));
378 		StrokeLine(BPoint(rect.left + 1, rect.bottom), rect.RightBottom());
379 		StrokeLine(BPoint(rect.right, rect.top + 1));
380 
381 		// filling
382 		SetHighColor(fBarColor);
383 		FillRect(rect.InsetByCopy(1, 1));
384 	}
385 
386 	if (rect.right < barFrame.right) {
387 		// empty space
388 		rect.left = rect.right + 1;
389 		rect.right = barFrame.right;
390 		SetHighColor(tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), B_LIGHTEN_MAX_TINT));
391 		FillRect(rect);
392 	}
393 }
394 
395 
396 void
397 BStatusBar::MessageReceived(BMessage *message)
398 {
399 	switch(message->what) {
400 		case B_UPDATE_STATUS_BAR:
401 		{
402 			float delta;
403 			const char *text = NULL, *trailing_text = NULL;
404 
405 			message->FindFloat("delta", &delta);
406 			message->FindString("text", &text);
407 			message->FindString("trailing_text", &trailing_text);
408 
409 			Update(delta, text, trailing_text);
410 
411 			break;
412 		}
413 
414 		case B_RESET_STATUS_BAR:
415 		{
416 			const char *label = NULL, *trailing_label = NULL;
417 
418 			message->FindString("label", &label);
419 			message->FindString("trailing_label", &trailing_label);
420 
421 			Reset(label, trailing_label);
422 
423 			break;
424 		}
425 
426 		default:
427 			BView::MessageReceived(message);
428 			break;
429 	}
430 }
431 
432 
433 void
434 BStatusBar::MouseDown(BPoint point)
435 {
436 	BView::MouseDown(point);
437 }
438 
439 
440 void
441 BStatusBar::MouseUp(BPoint point)
442 {
443 	BView::MouseUp(point);
444 }
445 
446 
447 void
448 BStatusBar::MouseMoved(BPoint point, uint32 transit, const BMessage *message)
449 {
450 	BView::MouseMoved(point, transit, message);
451 }
452 
453 
454 // #pragma mark -
455 
456 
457 void
458 BStatusBar::SetBarColor(rgb_color color)
459 {
460 	fBarColor = color;
461 
462 	Invalidate();
463 }
464 
465 
466 void
467 BStatusBar::SetBarHeight(float barHeight)
468 {
469 	float oldHeight = BarHeight();
470 
471 	fCustomBarHeight = true;
472 	fBarHeight = barHeight;
473 
474 	if (barHeight == oldHeight)
475 		return;
476 
477 	// resize so that the height fits
478 	if ((Flags() & B_SUPPORTS_LAYOUT) != 0)
479 		InvalidateLayout();
480 	else {
481 		float width, height;
482 		GetPreferredSize(&width, &height);
483 		ResizeTo(Bounds().Width(), height);
484 	}
485 }
486 
487 
488 void
489 BStatusBar::SetText(const char* string)
490 {
491 	_SetTextData(fText, string, fLabel, false);
492 }
493 
494 
495 void
496 BStatusBar::SetTrailingText(const char* string)
497 {
498 	_SetTextData(fTrailingText, string, fTrailingLabel, true);
499 }
500 
501 
502 void
503 BStatusBar::SetMaxValue(float max)
504 {
505 	// R5 and/or Zeta's SetMaxValue does not trigger an invalidate here.
506 	// this is probably not ideal behavior, but it does break apps in some cases
507 	// as observed with SpaceMonitor.
508 	// TODO: revisit this when we break binary compatibility
509 	fMax = max;
510 }
511 
512 
513 void
514 BStatusBar::Update(float delta, const char* text, const char* trailingText)
515 {
516 	// If any of these are NULL, the existing text remains (BeBook)
517 	if (text == NULL)
518 		text = fText.String();
519 	if (trailingText == NULL)
520 		trailingText = fTrailingText.String();
521 	BStatusBar::SetTo(fCurrent + delta, text, trailingText);
522 }
523 
524 
525 void
526 BStatusBar::Reset(const char *label, const char *trailingLabel)
527 {
528 	// Reset replaces the label and trailing label with copies of the
529 	// strings passed as arguments. If either argument is NULL, the
530 	// label or trailing label will be deleted and erased.
531 	fLabel = label ? label : "";
532 	fTrailingLabel = trailingLabel ? trailingLabel : "";
533 
534 	// Reset deletes and erases any text or trailing text
535 	fText = "";
536 	fTrailingText = "";
537 
538 	fCurrent = 0;
539 	fMax = 100;
540 
541 	Invalidate();
542 }
543 
544 
545 void
546 BStatusBar::SetTo(float value, const char* text, const char* trailingText)
547 {
548 	SetText(text);
549 	SetTrailingText(trailingText);
550 
551 	if (value > fMax)
552 		value = fMax;
553 	else if (value < 0)
554 		value = 0;
555 	if (value == fCurrent)
556 		return;
557 
558 	BRect barFrame = _BarFrame();
559 	float oldPosition = _BarPosition(barFrame);
560 
561 	fCurrent = value;
562 
563 	float newPosition = _BarPosition(barFrame);
564 	if (oldPosition == newPosition)
565 		return;
566 
567 	// update only the part of the status bar with actual changes
568 	BRect update = barFrame;
569 	if (oldPosition < newPosition) {
570 		update.left = floorf(max_c(oldPosition - 1, update.left));
571 		update.right = ceilf(newPosition);
572 	} else {
573 		update.left = floorf(max_c(newPosition - 1, update.left));
574 		update.right = ceilf(oldPosition);
575 	}
576 
577 	// TODO: Ask the BControlLook in the first place about dirty rect.
578 	if (be_control_look != NULL)
579 		update.InsetBy(-1, -1);
580 
581 	Invalidate(update);
582 }
583 
584 
585 float
586 BStatusBar::CurrentValue() const
587 {
588 	return fCurrent;
589 }
590 
591 
592 float
593 BStatusBar::MaxValue() const
594 {
595 	return fMax;
596 }
597 
598 
599 rgb_color
600 BStatusBar::BarColor() const
601 {
602 	return fBarColor;
603 }
604 
605 
606 float
607 BStatusBar::BarHeight() const
608 {
609 	if (!fCustomBarHeight && fBarHeight == -1) {
610 		// the default bar height is as height as the label
611 		font_height fontHeight;
612 		GetFontHeight(&fontHeight);
613 		const_cast<BStatusBar *>(this)->fBarHeight = fontHeight.ascent
614 			+ fontHeight.descent + 5;
615 	}
616 
617 	return ceilf(fBarHeight);
618 }
619 
620 
621 const char *
622 BStatusBar::Text() const
623 {
624 	return fText.String();
625 }
626 
627 
628 const char *
629 BStatusBar::TrailingText() const
630 {
631 	return fTrailingText.String();
632 }
633 
634 
635 const char *
636 BStatusBar::Label() const
637 {
638 	return fLabel.String();
639 }
640 
641 
642 const char *
643 BStatusBar::TrailingLabel() const
644 {
645 	return fTrailingLabel.String();
646 }
647 
648 
649 // #pragma mark -
650 
651 
652 BHandler *
653 BStatusBar::ResolveSpecifier(BMessage* message, int32 index,
654 	BMessage* specifier, int32 what, const char *property)
655 {
656 	return BView::ResolveSpecifier(message, index, specifier, what, property);
657 }
658 
659 
660 status_t
661 BStatusBar::GetSupportedSuites(BMessage* data)
662 {
663 	return BView::GetSupportedSuites(data);
664 }
665 
666 
667 status_t
668 BStatusBar::Perform(perform_code code, void* _data)
669 {
670 	switch (code) {
671 		case PERFORM_CODE_MIN_SIZE:
672 			((perform_data_min_size*)_data)->return_value
673 				= BStatusBar::MinSize();
674 			return B_OK;
675 		case PERFORM_CODE_MAX_SIZE:
676 			((perform_data_max_size*)_data)->return_value
677 				= BStatusBar::MaxSize();
678 			return B_OK;
679 		case PERFORM_CODE_PREFERRED_SIZE:
680 			((perform_data_preferred_size*)_data)->return_value
681 				= BStatusBar::PreferredSize();
682 			return B_OK;
683 		case PERFORM_CODE_LAYOUT_ALIGNMENT:
684 			((perform_data_layout_alignment*)_data)->return_value
685 				= BStatusBar::LayoutAlignment();
686 			return B_OK;
687 		case PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH:
688 			((perform_data_has_height_for_width*)_data)->return_value
689 				= BStatusBar::HasHeightForWidth();
690 			return B_OK;
691 		case PERFORM_CODE_GET_HEIGHT_FOR_WIDTH:
692 		{
693 			perform_data_get_height_for_width* data
694 				= (perform_data_get_height_for_width*)_data;
695 			BStatusBar::GetHeightForWidth(data->width, &data->min, &data->max,
696 				&data->preferred);
697 			return B_OK;
698 		}
699 		case PERFORM_CODE_SET_LAYOUT:
700 		{
701 			perform_data_set_layout* data = (perform_data_set_layout*)_data;
702 			BStatusBar::SetLayout(data->layout);
703 			return B_OK;
704 		}
705 		case PERFORM_CODE_LAYOUT_INVALIDATED:
706 		{
707 			perform_data_layout_invalidated* data
708 				= (perform_data_layout_invalidated*)_data;
709 			BStatusBar::LayoutInvalidated(data->descendants);
710 			return B_OK;
711 		}
712 		case PERFORM_CODE_DO_LAYOUT:
713 		{
714 			BStatusBar::DoLayout();
715 			return B_OK;
716 		}
717 	}
718 
719 	return BView::Perform(code, _data);
720 }
721 
722 
723 // #pragma mark -
724 
725 
726 extern "C" void
727 _ReservedStatusBar1__10BStatusBar(BStatusBar* self, float value,
728 	const char* text, const char* trailingText)
729 {
730 	self->BStatusBar::SetTo(value, text, trailingText);
731 }
732 
733 
734 void BStatusBar::_ReservedStatusBar2() {}
735 void BStatusBar::_ReservedStatusBar3() {}
736 void BStatusBar::_ReservedStatusBar4() {}
737 
738 
739 BStatusBar &
740 BStatusBar::operator=(const BStatusBar& other)
741 {
742 	return *this;
743 }
744 
745 
746 // #pragma mark -
747 
748 
749 void
750 BStatusBar::_InitObject()
751 {
752 	fMax = 100.0;
753 	fCurrent = 0.0;
754 
755 	fBarHeight = -1.0;
756 	fTextDivider = Bounds().Width();
757 
758 	fBarColor = kDefaultBarColor;
759 	fCustomBarHeight = false;
760 
761 	SetFlags(Flags() | B_FRAME_EVENTS);
762 }
763 
764 
765 void
766 BStatusBar::_SetTextData(BString& text, const char* source,
767 	const BString& combineWith, bool rightAligned)
768 {
769 	if (source == NULL)
770 		source = "";
771 
772 	// If there were no changes, we don't have to do anything
773 	if (text == source)
774 		return;
775 
776 	bool oldHasText = _HasText();
777 	text = source;
778 
779 	BString newString;
780 	if (rightAligned)
781 		newString << text << combineWith;
782 	else
783 		newString << combineWith << text;
784 
785 	if (oldHasText != _HasText())
786 		InvalidateLayout();
787 
788 	font_height fontHeight;
789 	GetFontHeight(&fontHeight);
790 
791 //	Invalidate(BRect(position, 0, position + invalidateWidth,
792 //		ceilf(fontHeight.ascent) + ceilf(fontHeight.descent)));
793 // TODO: redrawing the entire area takes care of the edge case
794 // where the left side string changes because of truncation and
795 // part of it needs to be redrawn as well.
796 	Invalidate(BRect(0, 0, Bounds().right,
797 		ceilf(fontHeight.ascent) + ceilf(fontHeight.descent)));
798 }
799 
800 
801 /*!
802 	Returns the inner bar frame without the surrounding bevel.
803 */
804 BRect
805 BStatusBar::_BarFrame(const font_height* fontHeight) const
806 {
807 	float top = 2;
808 	if (_HasText()) {
809 		if (fontHeight == NULL) {
810 			font_height height;
811 			GetFontHeight(&height);
812 			top = ceilf(height.ascent + height.descent) + 6;
813 		} else
814 			top = ceilf(fontHeight->ascent + fontHeight->descent) + 6;
815 	}
816 
817 	return BRect(2, top, Bounds().right - 2, top + BarHeight() - 4);
818 }
819 
820 
821 float
822 BStatusBar::_BarPosition(const BRect& barFrame) const
823 {
824 	if (fCurrent == 0)
825 		return barFrame.left - 1;
826 
827 	return roundf(barFrame.left - 1
828 		+ (fCurrent * (barFrame.Width() + 3) / fMax));
829 }
830 
831 
832 bool
833 BStatusBar::_HasText() const
834 {
835 	// Force BeOS behavior where the size of the BStatusBar always included
836 	// room for labels, even when there weren't any.
837 	if ((Flags() & B_SUPPORTS_LAYOUT) == 0)
838 		return true;
839 	return fLabel.Length() > 0 || fTrailingLabel.Length() > 0
840 		|| fTrailingText.Length() > 0 || fText.Length() > 0;
841 }
842