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