btrfs: Attempt to fix GCC2 build.
[haiku.git] / src / kits / interface / StatusBar.cpp
blob0024f632bb2e8f322ee9225a041c2b29ad653d95
1 /*
2 * Copyright 2001-2015, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
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>
12 /*! BStatusBar displays a "percentage-of-completion" gauge. */
13 #include <StatusBar.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
19 #include <ControlLook.h>
20 #include <Layout.h>
21 #include <LayoutUtils.h>
22 #include <Message.h>
23 #include <Region.h>
25 #include <binary_compatibility/Interface.h>
27 enum internalFlags {
28 kCustomBarColor = 1
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),
36 fLabel(label),
37 fTrailingLabel(trailingLabel)
39 _InitObject();
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),
48 fLabel(label),
49 fTrailingLabel(trailingLabel)
51 _InitObject();
55 BStatusBar::BStatusBar(BMessage *archive)
57 BView(archive)
59 _InitObject();
61 archive->FindString("_label", &fLabel);
62 archive->FindString("_tlabel", &fTrailingLabel);
64 archive->FindString("_text", &fText);
65 archive->FindString("_ttext", &fTrailingText);
67 float floatValue;
68 if (archive->FindFloat("_high", &floatValue) == B_OK) {
69 fBarHeight = floatValue;
70 fCustomBarHeight = true;
73 int32 color;
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)
82 fMax = floatValue;
86 BStatusBar::~BStatusBar()
91 BArchivable *
92 BStatusBar::Instantiate(BMessage *archive)
94 if (validate_instantiation(archive, "BStatusBar"))
95 return new BStatusBar(archive);
97 return NULL;
101 status_t
102 BStatusBar::Archive(BMessage *archive, bool deep) const
104 status_t err = BView::Archive(archive, deep);
105 if (err < B_OK)
106 return err;
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);
129 return err;
133 // #pragma mark -
136 void
137 BStatusBar::AttachedToWindow()
139 // resize so that the height fits
140 float width, height;
141 GetPreferredSize(&width, &height);
142 ResizeTo(Bounds().Width(), height);
144 SetViewColor(B_TRANSPARENT_COLOR);
146 AdoptParentColors();
148 fTextDivider = Bounds().Width();
150 if ((fInternalFlags & kCustomBarColor) == 0)
151 fBarColor = ui_color(B_STATUS_BAR_COLOR);
155 void
156 BStatusBar::DetachedFromWindow()
158 BView::DetachedFromWindow();
162 void
163 BStatusBar::AllAttached()
165 BView::AllAttached();
169 void
170 BStatusBar::AllDetached()
172 BView::AllDetached();
176 // #pragma mark -
179 void
180 BStatusBar::WindowActivated(bool state)
182 BView::WindowActivated(state);
186 void
187 BStatusBar::MakeFocus(bool state)
189 BView::MakeFocus(state);
193 // #pragma mark -
196 void
197 BStatusBar::GetPreferredSize(float* _width, float* _height)
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;
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;
216 *_height = labelHeight + BarHeight();
221 BSize
222 BStatusBar::MinSize()
224 float width, height;
225 GetPreferredSize(&width, &height);
227 return BLayoutUtils::ComposeSize(ExplicitMinSize(), BSize(width, height));
231 BSize
232 BStatusBar::MaxSize()
234 float width, height;
235 GetPreferredSize(&width, &height);
237 return BLayoutUtils::ComposeSize(ExplicitMaxSize(),
238 BSize(B_SIZE_UNLIMITED, height));
242 BSize
243 BStatusBar::PreferredSize()
245 float width, height;
246 GetPreferredSize(&width, &height);
248 return BLayoutUtils::ComposeSize(ExplicitPreferredSize(),
249 BSize(width, height));
253 void
254 BStatusBar::ResizeToPreferred()
256 BView::ResizeToPreferred();
260 void
261 BStatusBar::FrameMoved(BPoint newPosition)
263 BView::FrameMoved(newPosition);
267 void
268 BStatusBar::FrameResized(float newWidth, float newHeight)
270 BView::FrameResized(newWidth, newHeight);
271 Invalidate();
275 // #pragma mark -
278 void
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);
292 // Draw labels/texts
294 BRect rect = outerFrame;
295 rect.top = 0;
296 rect.bottom = outerFrame.top - 1;
298 if (updateRect.Intersects(rect)) {
299 // update labels
300 BString leftText;
301 leftText << fLabel << fText;
303 BString rightText;
304 rightText << fTrailingText << fTrailingLabel;
306 float baseLine = ceilf(fontHeight.ascent) + 1;
307 fTextDivider = rect.right;
309 BFont font;
310 GetFont(&font);
312 if (rightText.Length()) {
313 font.TruncateString(&rightText, B_TRUNCATE_BEGINNING,
314 rect.Width());
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);
328 else
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));
341 // Draw bar
343 if (!updateRect.Intersects(outerFrame))
344 return;
346 rect = outerFrame;
348 be_control_look->DrawStatusBar(this, rect, updateRect,
349 backgroundColor, fBarColor, _BarPosition(barFrame));
353 void
354 BStatusBar::MessageReceived(BMessage *message)
356 switch(message->what) {
357 case B_UPDATE_STATUS_BAR:
359 float delta;
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);
368 break;
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);
380 break;
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),
388 &fBarColor);
391 break;
394 default:
395 BView::MessageReceived(message);
396 break;
401 void
402 BStatusBar::MouseDown(BPoint point)
404 BView::MouseDown(point);
408 void
409 BStatusBar::MouseUp(BPoint point)
411 BView::MouseUp(point);
415 void
416 BStatusBar::MouseMoved(BPoint point, uint32 transit, const BMessage *message)
418 BView::MouseMoved(point, transit, message);
422 // #pragma mark -
425 void
426 BStatusBar::SetBarColor(rgb_color color)
428 fInternalFlags |= kCustomBarColor;
429 fBarColor = color;
431 Invalidate();
435 void
436 BStatusBar::SetBarHeight(float barHeight)
438 float oldHeight = BarHeight();
440 fCustomBarHeight = true;
441 fBarHeight = barHeight;
443 if (barHeight == oldHeight)
444 return;
446 // resize so that the height fits
447 if ((Flags() & B_SUPPORTS_LAYOUT) != 0)
448 InvalidateLayout();
449 else {
450 float width, height;
451 GetPreferredSize(&width, &height);
452 ResizeTo(Bounds().Width(), height);
457 void
458 BStatusBar::SetText(const char* string)
460 _SetTextData(fText, string, fLabel, false);
464 void
465 BStatusBar::SetTrailingText(const char* string)
467 _SetTextData(fTrailingText, string, fTrailingLabel, true);
471 void
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
478 fMax = max;
482 void
483 BStatusBar::Update(float delta, const char* text, const char* trailingText)
485 // If any of these are NULL, the existing text remains (BeBook)
486 if (text == NULL)
487 text = fText.String();
488 if (trailingText == NULL)
489 trailingText = fTrailingText.String();
490 BStatusBar::SetTo(fCurrent + delta, text, trailingText);
494 void
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
504 fText = "";
505 fTrailingText = "";
507 fCurrent = 0;
508 fMax = 100;
510 Invalidate();
514 void
515 BStatusBar::SetTo(float value, const char* text, const char* trailingText)
517 SetText(text);
518 SetTrailingText(trailingText);
520 if (value > fMax)
521 value = fMax;
522 else if (value < 0)
523 value = 0;
524 if (value == fCurrent)
525 return;
527 BRect barFrame = _BarFrame();
528 float oldPosition = _BarPosition(barFrame);
530 fCurrent = value;
532 float newPosition = _BarPosition(barFrame);
533 if (oldPosition == newPosition)
534 return;
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);
541 } else {
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);
549 Invalidate(update);
553 float
554 BStatusBar::CurrentValue() const
556 return fCurrent;
560 float
561 BStatusBar::MaxValue() const
563 return fMax;
567 rgb_color
568 BStatusBar::BarColor() const
570 return fBarColor;
574 float
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);
589 const char *
590 BStatusBar::Text() const
592 return fText.String();
596 const char *
597 BStatusBar::TrailingText() const
599 return fTrailingText.String();
603 const char *
604 BStatusBar::Label() const
606 return fLabel.String();
610 const char *
611 BStatusBar::TrailingLabel() const
613 return fTrailingLabel.String();
617 // #pragma mark -
620 BHandler *
621 BStatusBar::ResolveSpecifier(BMessage* message, int32 index,
622 BMessage* specifier, int32 what, const char *property)
624 return BView::ResolveSpecifier(message, index, specifier, what, property);
628 status_t
629 BStatusBar::GetSupportedSuites(BMessage* data)
631 return BView::GetSupportedSuites(data);
635 status_t
636 BStatusBar::Perform(perform_code code, void* _data)
638 switch (code) {
639 case PERFORM_CODE_MIN_SIZE:
640 ((perform_data_min_size*)_data)->return_value
641 = BStatusBar::MinSize();
642 return B_OK;
643 case PERFORM_CODE_MAX_SIZE:
644 ((perform_data_max_size*)_data)->return_value
645 = BStatusBar::MaxSize();
646 return B_OK;
647 case PERFORM_CODE_PREFERRED_SIZE:
648 ((perform_data_preferred_size*)_data)->return_value
649 = BStatusBar::PreferredSize();
650 return B_OK;
651 case PERFORM_CODE_LAYOUT_ALIGNMENT:
652 ((perform_data_layout_alignment*)_data)->return_value
653 = BStatusBar::LayoutAlignment();
654 return B_OK;
655 case PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH:
656 ((perform_data_has_height_for_width*)_data)->return_value
657 = BStatusBar::HasHeightForWidth();
658 return B_OK;
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,
664 &data->preferred);
665 return B_OK;
667 case PERFORM_CODE_SET_LAYOUT:
669 perform_data_set_layout* data = (perform_data_set_layout*)_data;
670 BStatusBar::SetLayout(data->layout);
671 return B_OK;
673 case PERFORM_CODE_LAYOUT_INVALIDATED:
675 perform_data_layout_invalidated* data
676 = (perform_data_layout_invalidated*)_data;
677 BStatusBar::LayoutInvalidated(data->descendants);
678 return B_OK;
680 case PERFORM_CODE_DO_LAYOUT:
682 BStatusBar::DoLayout();
683 return B_OK;
687 return BView::Perform(code, _data);
691 // #pragma mark -
694 extern "C" void
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() {}
707 BStatusBar &
708 BStatusBar::operator=(const BStatusBar& other)
710 return *this;
714 // #pragma mark -
717 void
718 BStatusBar::_InitObject()
720 fMax = 100.0;
721 fCurrent = 0.0;
723 fBarHeight = -1.0;
724 fTextDivider = Bounds().Width();
726 fCustomBarHeight = false;
727 fInternalFlags = 0;
729 SetFlags(Flags() | B_FRAME_EVENTS);
733 void
734 BStatusBar::_SetTextData(BString& text, const char* source,
735 const BString& combineWith, bool rightAligned)
737 if (source == NULL)
738 source = "";
740 // If there were no changes, we don't have to do anything
741 if (text == source)
742 return;
744 bool oldHasText = _HasText();
745 text = source;
747 BString newString;
748 if (rightAligned)
749 newString << text << combineWith;
750 else
751 newString << combineWith << text;
753 if (oldHasText != _HasText())
754 InvalidateLayout();
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.
772 BRect
773 BStatusBar::_BarFrame(const font_height* fontHeight) const
775 float top = 2;
776 if (_HasText()) {
777 if (fontHeight == NULL) {
778 font_height height;
779 GetFontHeight(&height);
780 top = ceilf(height.ascent + height.descent) + 6;
781 } else
782 top = ceilf(fontHeight->ascent + fontHeight->descent) + 6;
785 return BRect(2, top, Bounds().right - 2, top + BarHeight() - 4);
789 float
790 BStatusBar::_BarPosition(const BRect& barFrame) const
792 if (fCurrent == 0)
793 return barFrame.left - 1;
795 return roundf(barFrame.left - 1
796 + (fCurrent * (barFrame.Width() + 3) / fMax));
800 bool
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)
806 return true;
807 return fLabel.Length() > 0 || fTrailingLabel.Length() > 0
808 || fTrailingText.Length() > 0 || fText.Length() > 0;