2 * Copyright 2001-2015, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
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>
12 /*! BStatusBar displays a "percentage-of-completion" gauge. */
13 #include <StatusBar.h>
19 #include <ControlLook.h>
21 #include <LayoutUtils.h>
25 #include <binary_compatibility/Interface.h>
32 BStatusBar::BStatusBar(BRect frame
, const char *name
, const char *label
,
33 const char *trailingLabel
)
35 BView(frame
, name
, B_FOLLOW_LEFT
| B_FOLLOW_TOP
, B_WILL_DRAW
),
37 fTrailingLabel(trailingLabel
)
43 BStatusBar::BStatusBar(const char *name
, const char *label
,
44 const char *trailingLabel
)
46 BView(BRect(0, 0, -1, -1), name
, B_FOLLOW_LEFT
| B_FOLLOW_TOP
,
47 B_WILL_DRAW
| B_SUPPORTS_LAYOUT
),
49 fTrailingLabel(trailingLabel
)
55 BStatusBar::BStatusBar(BMessage
*archive
)
61 archive
->FindString("_label", &fLabel
);
62 archive
->FindString("_tlabel", &fTrailingLabel
);
64 archive
->FindString("_text", &fText
);
65 archive
->FindString("_ttext", &fTrailingText
);
68 if (archive
->FindFloat("_high", &floatValue
) == B_OK
) {
69 fBarHeight
= floatValue
;
70 fCustomBarHeight
= true;
74 if (archive
->FindInt32("_bcolor", (int32
*)&color
) == B_OK
) {
75 fBarColor
= *(rgb_color
*)&color
;
76 fInternalFlags
|= kCustomBarColor
;
79 if (archive
->FindFloat("_val", &floatValue
) == B_OK
)
80 fCurrent
= floatValue
;
81 if (archive
->FindFloat("_max", &floatValue
) == B_OK
)
86 BStatusBar::~BStatusBar()
92 BStatusBar::Instantiate(BMessage
*archive
)
94 if (validate_instantiation(archive
, "BStatusBar"))
95 return new BStatusBar(archive
);
102 BStatusBar::Archive(BMessage
*archive
, bool deep
) const
104 status_t err
= BView::Archive(archive
, deep
);
108 if (fCustomBarHeight
)
109 err
= archive
->AddFloat("_high", fBarHeight
);
111 if (err
== B_OK
&& fInternalFlags
& kCustomBarColor
)
112 err
= archive
->AddInt32("_bcolor", (const uint32
&)fBarColor
);
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
);
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
);
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
);
137 BStatusBar::AttachedToWindow()
139 // resize so that the height fits
141 GetPreferredSize(&width
, &height
);
142 ResizeTo(Bounds().Width(), height
);
144 SetViewColor(B_TRANSPARENT_COLOR
);
148 fTextDivider
= Bounds().Width();
150 if ((fInternalFlags
& kCustomBarColor
) == 0)
151 fBarColor
= ui_color(B_STATUS_BAR_COLOR
);
156 BStatusBar::DetachedFromWindow()
158 BView::DetachedFromWindow();
163 BStatusBar::AllAttached()
165 BView::AllAttached();
170 BStatusBar::AllDetached()
172 BView::AllDetached();
180 BStatusBar::WindowActivated(bool state
)
182 BView::WindowActivated(state
);
187 BStatusBar::MakeFocus(bool state
)
189 BView::MakeFocus(state
);
197 BStatusBar::GetPreferredSize(float* _width
, float* _height
)
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()))
209 float labelHeight
= 0;
211 font_height fontHeight
;
212 GetFontHeight(&fontHeight
);
213 labelHeight
= ceilf(fontHeight
.ascent
+ fontHeight
.descent
) + 6;
216 *_height
= labelHeight
+ BarHeight();
222 BStatusBar::MinSize()
225 GetPreferredSize(&width
, &height
);
227 return BLayoutUtils::ComposeSize(ExplicitMinSize(), BSize(width
, height
));
232 BStatusBar::MaxSize()
235 GetPreferredSize(&width
, &height
);
237 return BLayoutUtils::ComposeSize(ExplicitMaxSize(),
238 BSize(B_SIZE_UNLIMITED
, height
));
243 BStatusBar::PreferredSize()
246 GetPreferredSize(&width
, &height
);
248 return BLayoutUtils::ComposeSize(ExplicitPreferredSize(),
249 BSize(width
, height
));
254 BStatusBar::ResizeToPreferred()
256 BView::ResizeToPreferred();
261 BStatusBar::FrameMoved(BPoint newPosition
)
263 BView::FrameMoved(newPosition
);
268 BStatusBar::FrameResized(float newWidth
, float newHeight
)
270 BView::FrameResized(newWidth
, newHeight
);
279 BStatusBar::Draw(BRect updateRect
)
281 rgb_color backgroundColor
= LowColor();
283 font_height fontHeight
;
284 GetFontHeight(&fontHeight
);
285 BRect barFrame
= _BarFrame(&fontHeight
);
286 BRect outerFrame
= barFrame
.InsetByCopy(-2, -2);
288 BRegion
background(updateRect
);
289 background
.Exclude(outerFrame
);
290 FillRegion(&background
, B_SOLID_LOW
);
294 BRect rect
= outerFrame
;
296 rect
.bottom
= outerFrame
.top
- 1;
298 if (updateRect
.Intersects(rect
)) {
301 leftText
<< fLabel
<< fText
;
304 rightText
<< fTrailingText
<< fTrailingLabel
;
306 float baseLine
= ceilf(fontHeight
.ascent
) + 1;
307 fTextDivider
= rect
.right
;
312 if (rightText
.Length()) {
313 font
.TruncateString(&rightText
, B_TRUNCATE_BEGINNING
,
315 fTextDivider
-= StringWidth(rightText
.String());
318 if (leftText
.Length()) {
319 float width
= max_c(0.0, fTextDivider
- rect
.left
);
320 font
.TruncateString(&leftText
, B_TRUNCATE_END
, width
);
323 rgb_color textColor
= ui_color(B_PANEL_TEXT_COLOR
);
325 if (backgroundColor
!= ui_color(B_PANEL_BACKGROUND_COLOR
)) {
326 if (backgroundColor
.Brightness() > 100)
327 textColor
= make_color(0, 0, 0, 255);
329 textColor
= make_color(255, 255, 255, 255);
332 SetHighColor(textColor
);
334 if (leftText
.Length())
335 DrawString(leftText
.String(), BPoint(rect
.left
, baseLine
));
337 if (rightText
.Length())
338 DrawString(rightText
.String(), BPoint(fTextDivider
, baseLine
));
343 if (!updateRect
.Intersects(outerFrame
))
348 be_control_look
->DrawStatusBar(this, rect
, updateRect
,
349 backgroundColor
, fBarColor
, _BarPosition(barFrame
));
354 BStatusBar::MessageReceived(BMessage
*message
)
356 switch(message
->what
) {
357 case B_UPDATE_STATUS_BAR
:
360 const char *text
= NULL
, *trailing_text
= NULL
;
362 message
->FindFloat("delta", &delta
);
363 message
->FindString("text", &text
);
364 message
->FindString("trailing_text", &trailing_text
);
366 Update(delta
, text
, trailing_text
);
371 case B_RESET_STATUS_BAR
:
373 const char *label
= NULL
, *trailing_label
= NULL
;
375 message
->FindString("label", &label
);
376 message
->FindString("trailing_label", &trailing_label
);
378 Reset(label
, trailing_label
);
383 case B_COLORS_UPDATED
:
385 // Change the bar color IF we don't have an application-set color.
386 if ((fInternalFlags
& kCustomBarColor
) == 0) {
387 message
->FindColor(ui_color_name(B_STATUS_BAR_COLOR
),
395 BView::MessageReceived(message
);
402 BStatusBar::MouseDown(BPoint point
)
404 BView::MouseDown(point
);
409 BStatusBar::MouseUp(BPoint point
)
411 BView::MouseUp(point
);
416 BStatusBar::MouseMoved(BPoint point
, uint32 transit
, const BMessage
*message
)
418 BView::MouseMoved(point
, transit
, message
);
426 BStatusBar::SetBarColor(rgb_color color
)
428 fInternalFlags
|= kCustomBarColor
;
436 BStatusBar::SetBarHeight(float barHeight
)
438 float oldHeight
= BarHeight();
440 fCustomBarHeight
= true;
441 fBarHeight
= barHeight
;
443 if (barHeight
== oldHeight
)
446 // resize so that the height fits
447 if ((Flags() & B_SUPPORTS_LAYOUT
) != 0)
451 GetPreferredSize(&width
, &height
);
452 ResizeTo(Bounds().Width(), height
);
458 BStatusBar::SetText(const char* string
)
460 _SetTextData(fText
, string
, fLabel
, false);
465 BStatusBar::SetTrailingText(const char* string
)
467 _SetTextData(fTrailingText
, string
, fTrailingLabel
, true);
472 BStatusBar::SetMaxValue(float max
)
474 // R5 and/or Zeta's SetMaxValue does not trigger an invalidate here.
475 // this is probably not ideal behavior, but it does break apps in some cases
476 // as observed with SpaceMonitor.
477 // TODO: revisit this when we break binary compatibility
483 BStatusBar::Update(float delta
, const char* text
, const char* trailingText
)
485 // If any of these are NULL, the existing text remains (BeBook)
487 text
= fText
.String();
488 if (trailingText
== NULL
)
489 trailingText
= fTrailingText
.String();
490 BStatusBar::SetTo(fCurrent
+ delta
, text
, trailingText
);
495 BStatusBar::Reset(const char *label
, const char *trailingLabel
)
497 // Reset replaces the label and trailing label with copies of the
498 // strings passed as arguments. If either argument is NULL, the
499 // label or trailing label will be deleted and erased.
500 fLabel
= label
? label
: "";
501 fTrailingLabel
= trailingLabel
? trailingLabel
: "";
503 // Reset deletes and erases any text or trailing text
515 BStatusBar::SetTo(float value
, const char* text
, const char* trailingText
)
518 SetTrailingText(trailingText
);
524 if (value
== fCurrent
)
527 BRect barFrame
= _BarFrame();
528 float oldPosition
= _BarPosition(barFrame
);
532 float newPosition
= _BarPosition(barFrame
);
533 if (oldPosition
== newPosition
)
536 // update only the part of the status bar with actual changes
537 BRect update
= barFrame
;
538 if (oldPosition
< newPosition
) {
539 update
.left
= floorf(max_c(oldPosition
- 1, update
.left
));
540 update
.right
= ceilf(newPosition
);
542 update
.left
= floorf(max_c(newPosition
- 1, update
.left
));
543 update
.right
= ceilf(oldPosition
);
546 // TODO: Ask the BControlLook in the first place about dirty rect.
547 update
.InsetBy(-1, -1);
554 BStatusBar::CurrentValue() const
561 BStatusBar::MaxValue() const
568 BStatusBar::BarColor() const
575 BStatusBar::BarHeight() const
577 if (!fCustomBarHeight
&& fBarHeight
== -1) {
578 // the default bar height is as height as the label
579 font_height fontHeight
;
580 GetFontHeight(&fontHeight
);
581 const_cast<BStatusBar
*>(this)->fBarHeight
= fontHeight
.ascent
582 + fontHeight
.descent
+ 5;
585 return ceilf(fBarHeight
);
590 BStatusBar::Text() const
592 return fText
.String();
597 BStatusBar::TrailingText() const
599 return fTrailingText
.String();
604 BStatusBar::Label() const
606 return fLabel
.String();
611 BStatusBar::TrailingLabel() const
613 return fTrailingLabel
.String();
621 BStatusBar::ResolveSpecifier(BMessage
* message
, int32 index
,
622 BMessage
* specifier
, int32 what
, const char *property
)
624 return BView::ResolveSpecifier(message
, index
, specifier
, what
, property
);
629 BStatusBar::GetSupportedSuites(BMessage
* data
)
631 return BView::GetSupportedSuites(data
);
636 BStatusBar::Perform(perform_code code
, void* _data
)
639 case PERFORM_CODE_MIN_SIZE
:
640 ((perform_data_min_size
*)_data
)->return_value
641 = BStatusBar::MinSize();
643 case PERFORM_CODE_MAX_SIZE
:
644 ((perform_data_max_size
*)_data
)->return_value
645 = BStatusBar::MaxSize();
647 case PERFORM_CODE_PREFERRED_SIZE
:
648 ((perform_data_preferred_size
*)_data
)->return_value
649 = BStatusBar::PreferredSize();
651 case PERFORM_CODE_LAYOUT_ALIGNMENT
:
652 ((perform_data_layout_alignment
*)_data
)->return_value
653 = BStatusBar::LayoutAlignment();
655 case PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH
:
656 ((perform_data_has_height_for_width
*)_data
)->return_value
657 = BStatusBar::HasHeightForWidth();
659 case PERFORM_CODE_GET_HEIGHT_FOR_WIDTH
:
661 perform_data_get_height_for_width
* data
662 = (perform_data_get_height_for_width
*)_data
;
663 BStatusBar::GetHeightForWidth(data
->width
, &data
->min
, &data
->max
,
667 case PERFORM_CODE_SET_LAYOUT
:
669 perform_data_set_layout
* data
= (perform_data_set_layout
*)_data
;
670 BStatusBar::SetLayout(data
->layout
);
673 case PERFORM_CODE_LAYOUT_INVALIDATED
:
675 perform_data_layout_invalidated
* data
676 = (perform_data_layout_invalidated
*)_data
;
677 BStatusBar::LayoutInvalidated(data
->descendants
);
680 case PERFORM_CODE_DO_LAYOUT
:
682 BStatusBar::DoLayout();
687 return BView::Perform(code
, _data
);
695 _ReservedStatusBar1__10BStatusBar(BStatusBar
* self
, float value
,
696 const char* text
, const char* trailingText
)
698 self
->BStatusBar::SetTo(value
, text
, trailingText
);
702 void BStatusBar::_ReservedStatusBar2() {}
703 void BStatusBar::_ReservedStatusBar3() {}
704 void BStatusBar::_ReservedStatusBar4() {}
708 BStatusBar::operator=(const BStatusBar
& other
)
718 BStatusBar::_InitObject()
724 fTextDivider
= Bounds().Width();
726 fCustomBarHeight
= false;
729 SetFlags(Flags() | B_FRAME_EVENTS
);
734 BStatusBar::_SetTextData(BString
& text
, const char* source
,
735 const BString
& combineWith
, bool rightAligned
)
740 // If there were no changes, we don't have to do anything
744 bool oldHasText
= _HasText();
749 newString
<< text
<< combineWith
;
751 newString
<< combineWith
<< text
;
753 if (oldHasText
!= _HasText())
756 font_height fontHeight
;
757 GetFontHeight(&fontHeight
);
759 // Invalidate(BRect(position, 0, position + invalidateWidth,
760 // ceilf(fontHeight.ascent) + ceilf(fontHeight.descent)));
761 // TODO: redrawing the entire area takes care of the edge case
762 // where the left side string changes because of truncation and
763 // part of it needs to be redrawn as well.
764 Invalidate(BRect(0, 0, Bounds().right
,
765 ceilf(fontHeight
.ascent
) + ceilf(fontHeight
.descent
)));
770 Returns the inner bar frame without the surrounding bevel.
773 BStatusBar::_BarFrame(const font_height
* fontHeight
) const
777 if (fontHeight
== NULL
) {
779 GetFontHeight(&height
);
780 top
= ceilf(height
.ascent
+ height
.descent
) + 6;
782 top
= ceilf(fontHeight
->ascent
+ fontHeight
->descent
) + 6;
785 return BRect(2, top
, Bounds().right
- 2, top
+ BarHeight() - 4);
790 BStatusBar::_BarPosition(const BRect
& barFrame
) const
793 return barFrame
.left
- 1;
795 return roundf(barFrame
.left
- 1
796 + (fCurrent
* (barFrame
.Width() + 3) / fMax
));
801 BStatusBar::_HasText() const
803 // Force BeOS behavior where the size of the BStatusBar always included
804 // room for labels, even when there weren't any.
805 if ((Flags() & B_SUPPORTS_LAYOUT
) == 0)
807 return fLabel
.Length() > 0 || fTrailingLabel
.Length() > 0
808 || fTrailingText
.Length() > 0 || fText
.Length() > 0;