tcp: Fix 64 bit build with debugging features enabled.
[haiku.git] / src / kits / interface / StatusBar.cpp
blob7cd4f74ea0c59d03d45bae316e96379c40e878bc
1 /*
2 * Copyright 2001-2008, 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 */
11 /*! BStatusBar displays a "percentage-of-completion" gauge. */
12 #include <StatusBar.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
18 #include <ControlLook.h>
19 #include <Layout.h>
20 #include <LayoutUtils.h>
21 #include <Message.h>
22 #include <Region.h>
24 #include <binary_compatibility/Interface.h>
27 static const rgb_color kDefaultBarColor = {50, 150, 255, 255};
30 BStatusBar::BStatusBar(BRect frame, const char *name, const char *label,
31 const char *trailingLabel)
33 BView(frame, name, B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW),
34 fLabel(label),
35 fTrailingLabel(trailingLabel)
37 _InitObject();
41 BStatusBar::BStatusBar(const char *name, const char *label,
42 const char *trailingLabel)
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)
49 _InitObject();
53 BStatusBar::BStatusBar(BMessage *archive)
55 BView(archive)
57 _InitObject();
59 archive->FindString("_label", &fLabel);
60 archive->FindString("_tlabel", &fTrailingLabel);
62 archive->FindString("_text", &fText);
63 archive->FindString("_ttext", &fTrailingText);
65 float floatValue;
66 if (archive->FindFloat("_high", &floatValue) == B_OK) {
67 fBarHeight = floatValue;
68 fCustomBarHeight = true;
71 int32 color;
72 if (archive->FindInt32("_bcolor", (int32 *)&color) == B_OK)
73 fBarColor = *(rgb_color *)&color;
75 if (archive->FindFloat("_val", &floatValue) == B_OK)
76 fCurrent = floatValue;
77 if (archive->FindFloat("_max", &floatValue) == B_OK)
78 fMax = floatValue;
82 BStatusBar::~BStatusBar()
87 BArchivable *
88 BStatusBar::Instantiate(BMessage *archive)
90 if (validate_instantiation(archive, "BStatusBar"))
91 return new BStatusBar(archive);
93 return NULL;
97 status_t
98 BStatusBar::Archive(BMessage *archive, bool deep) const
100 status_t err = BView::Archive(archive, deep);
101 if (err < B_OK)
102 return err;
104 if (fCustomBarHeight)
105 err = archive->AddFloat("_high", fBarHeight);
107 if (err == B_OK && fBarColor != kDefaultBarColor)
108 err = archive->AddInt32("_bcolor", (const uint32 &)fBarColor);
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);
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);
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);
125 return err;
129 // #pragma mark -
132 void
133 BStatusBar::AttachedToWindow()
135 // resize so that the height fits
136 float width, height;
137 GetPreferredSize(&width, &height);
138 ResizeTo(Bounds().Width(), height);
140 SetViewColor(B_TRANSPARENT_COLOR);
141 rgb_color lowColor = B_TRANSPARENT_COLOR;
143 BView* parent = Parent();
144 if (parent != NULL)
145 lowColor = parent->ViewColor();
147 if (lowColor == B_TRANSPARENT_COLOR)
148 lowColor = ui_color(B_PANEL_BACKGROUND_COLOR);
150 SetLowColor(lowColor);
152 fTextDivider = Bounds().Width();
156 void
157 BStatusBar::DetachedFromWindow()
159 BView::DetachedFromWindow();
163 void
164 BStatusBar::AllAttached()
166 BView::AllAttached();
170 void
171 BStatusBar::AllDetached()
173 BView::AllDetached();
177 // #pragma mark -
180 void
181 BStatusBar::WindowActivated(bool state)
183 BView::WindowActivated(state);
187 void
188 BStatusBar::MakeFocus(bool state)
190 BView::MakeFocus(state);
194 // #pragma mark -
197 void
198 BStatusBar::GetPreferredSize(float* _width, float* _height)
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;
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;
217 *_height = labelHeight + BarHeight();
222 BSize
223 BStatusBar::MinSize()
225 float width, height;
226 GetPreferredSize(&width, &height);
228 return BLayoutUtils::ComposeSize(ExplicitMinSize(), BSize(width, height));
232 BSize
233 BStatusBar::MaxSize()
235 float width, height;
236 GetPreferredSize(&width, &height);
238 return BLayoutUtils::ComposeSize(ExplicitMaxSize(),
239 BSize(B_SIZE_UNLIMITED, height));
243 BSize
244 BStatusBar::PreferredSize()
246 float width, height;
247 GetPreferredSize(&width, &height);
249 return BLayoutUtils::ComposeSize(ExplicitPreferredSize(),
250 BSize(width, height));
254 void
255 BStatusBar::ResizeToPreferred()
257 BView::ResizeToPreferred();
261 void
262 BStatusBar::FrameMoved(BPoint newPosition)
264 BView::FrameMoved(newPosition);
268 void
269 BStatusBar::FrameResized(float newWidth, float newHeight)
271 BView::FrameResized(newWidth, newHeight);
272 Invalidate();
276 // #pragma mark -
279 void
280 BStatusBar::Draw(BRect updateRect)
282 rgb_color backgroundColor = LowColor();
284 font_height fontHeight;
285 GetFontHeight(&fontHeight);
286 BRect barFrame = _BarFrame(&fontHeight);
287 BRect outerFrame = barFrame.InsetByCopy(-2, -2);
289 BRegion background(updateRect);
290 background.Exclude(outerFrame);
291 FillRegion(&background, B_SOLID_LOW);
293 // Draw labels/texts
295 BRect rect = outerFrame;
296 rect.top = 0;
297 rect.bottom = outerFrame.top - 1;
299 if (updateRect.Intersects(rect)) {
300 // update labels
301 BString leftText;
302 leftText << fLabel << fText;
304 BString rightText;
305 rightText << fTrailingText << fTrailingLabel;
307 float baseLine = ceilf(fontHeight.ascent) + 1;
308 fTextDivider = rect.right;
310 BFont font;
311 GetFont(&font);
313 if (rightText.Length()) {
314 font.TruncateString(&rightText, B_TRUNCATE_BEGINNING, 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 SetHighColor(ui_color(B_CONTROL_TEXT_COLOR));
325 if (leftText.Length())
326 DrawString(leftText.String(), BPoint(rect.left, baseLine));
328 if (rightText.Length())
329 DrawString(rightText.String(), BPoint(fTextDivider, baseLine));
333 // Draw bar
335 if (!updateRect.Intersects(outerFrame))
336 return;
338 rect = outerFrame;
340 if (be_control_look != NULL) {
341 be_control_look->DrawStatusBar(this, rect, updateRect,
342 backgroundColor, fBarColor, _BarPosition(barFrame));
343 return;
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());
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));
355 rect.InsetBy(1, 1);
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());
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));
366 rect = barFrame;
367 rect.right = _BarPosition(barFrame);
369 // draw bar itself
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());
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));
381 // filling
382 SetHighColor(fBarColor);
383 FillRect(rect.InsetByCopy(1, 1));
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);
396 void
397 BStatusBar::MessageReceived(BMessage *message)
399 switch(message->what) {
400 case B_UPDATE_STATUS_BAR:
402 float delta;
403 const char *text = NULL, *trailing_text = NULL;
405 message->FindFloat("delta", &delta);
406 message->FindString("text", &text);
407 message->FindString("trailing_text", &trailing_text);
409 Update(delta, text, trailing_text);
411 break;
414 case B_RESET_STATUS_BAR:
416 const char *label = NULL, *trailing_label = NULL;
418 message->FindString("label", &label);
419 message->FindString("trailing_label", &trailing_label);
421 Reset(label, trailing_label);
423 break;
426 default:
427 BView::MessageReceived(message);
428 break;
433 void
434 BStatusBar::MouseDown(BPoint point)
436 BView::MouseDown(point);
440 void
441 BStatusBar::MouseUp(BPoint point)
443 BView::MouseUp(point);
447 void
448 BStatusBar::MouseMoved(BPoint point, uint32 transit, const BMessage *message)
450 BView::MouseMoved(point, transit, message);
454 // #pragma mark -
457 void
458 BStatusBar::SetBarColor(rgb_color color)
460 fBarColor = color;
462 Invalidate();
466 void
467 BStatusBar::SetBarHeight(float barHeight)
469 float oldHeight = BarHeight();
471 fCustomBarHeight = true;
472 fBarHeight = barHeight;
474 if (barHeight == oldHeight)
475 return;
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);
488 void
489 BStatusBar::SetText(const char* string)
491 _SetTextData(fText, string, fLabel, false);
495 void
496 BStatusBar::SetTrailingText(const char* string)
498 _SetTextData(fTrailingText, string, fTrailingLabel, true);
502 void
503 BStatusBar::SetMaxValue(float max)
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;
513 void
514 BStatusBar::Update(float delta, const char* text, const char* trailingText)
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);
525 void
526 BStatusBar::Reset(const char *label, const char *trailingLabel)
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 : "";
534 // Reset deletes and erases any text or trailing text
535 fText = "";
536 fTrailingText = "";
538 fCurrent = 0;
539 fMax = 100;
541 Invalidate();
545 void
546 BStatusBar::SetTo(float value, const char* text, const char* trailingText)
548 SetText(text);
549 SetTrailingText(trailingText);
551 if (value > fMax)
552 value = fMax;
553 else if (value < 0)
554 value = 0;
555 if (value == fCurrent)
556 return;
558 BRect barFrame = _BarFrame();
559 float oldPosition = _BarPosition(barFrame);
561 fCurrent = value;
563 float newPosition = _BarPosition(barFrame);
564 if (oldPosition == newPosition)
565 return;
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);
577 // TODO: Ask the BControlLook in the first place about dirty rect.
578 if (be_control_look != NULL)
579 update.InsetBy(-1, -1);
581 Invalidate(update);
585 float
586 BStatusBar::CurrentValue() const
588 return fCurrent;
592 float
593 BStatusBar::MaxValue() const
595 return fMax;
599 rgb_color
600 BStatusBar::BarColor() const
602 return fBarColor;
606 float
607 BStatusBar::BarHeight() const
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;
617 return ceilf(fBarHeight);
621 const char *
622 BStatusBar::Text() const
624 return fText.String();
628 const char *
629 BStatusBar::TrailingText() const
631 return fTrailingText.String();
635 const char *
636 BStatusBar::Label() const
638 return fLabel.String();
642 const char *
643 BStatusBar::TrailingLabel() const
645 return fTrailingLabel.String();
649 // #pragma mark -
652 BHandler *
653 BStatusBar::ResolveSpecifier(BMessage* message, int32 index,
654 BMessage* specifier, int32 what, const char *property)
656 return BView::ResolveSpecifier(message, index, specifier, what, property);
660 status_t
661 BStatusBar::GetSupportedSuites(BMessage* data)
663 return BView::GetSupportedSuites(data);
667 status_t
668 BStatusBar::Perform(perform_code code, void* _data)
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:
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;
699 case PERFORM_CODE_SET_LAYOUT:
701 perform_data_set_layout* data = (perform_data_set_layout*)_data;
702 BStatusBar::SetLayout(data->layout);
703 return B_OK;
705 case PERFORM_CODE_LAYOUT_INVALIDATED:
707 perform_data_layout_invalidated* data
708 = (perform_data_layout_invalidated*)_data;
709 BStatusBar::LayoutInvalidated(data->descendants);
710 return B_OK;
712 case PERFORM_CODE_DO_LAYOUT:
714 BStatusBar::DoLayout();
715 return B_OK;
719 return BView::Perform(code, _data);
723 // #pragma mark -
726 extern "C" void
727 _ReservedStatusBar1__10BStatusBar(BStatusBar* self, float value,
728 const char* text, const char* trailingText)
730 self->BStatusBar::SetTo(value, text, trailingText);
734 void BStatusBar::_ReservedStatusBar2() {}
735 void BStatusBar::_ReservedStatusBar3() {}
736 void BStatusBar::_ReservedStatusBar4() {}
739 BStatusBar &
740 BStatusBar::operator=(const BStatusBar& other)
742 return *this;
746 // #pragma mark -
749 void
750 BStatusBar::_InitObject()
752 fMax = 100.0;
753 fCurrent = 0.0;
755 fBarHeight = -1.0;
756 fTextDivider = Bounds().Width();
758 fBarColor = kDefaultBarColor;
759 fCustomBarHeight = false;
761 SetFlags(Flags() | B_FRAME_EVENTS);
765 void
766 BStatusBar::_SetTextData(BString& text, const char* source,
767 const BString& combineWith, bool rightAligned)
769 if (source == NULL)
770 source = "";
772 // If there were no changes, we don't have to do anything
773 if (text == source)
774 return;
776 bool oldHasText = _HasText();
777 text = source;
779 BString newString;
780 if (rightAligned)
781 newString << text << combineWith;
782 else
783 newString << combineWith << text;
785 if (oldHasText != _HasText())
786 InvalidateLayout();
788 font_height fontHeight;
789 GetFontHeight(&fontHeight);
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)));
802 Returns the inner bar frame without the surrounding bevel.
804 BRect
805 BStatusBar::_BarFrame(const font_height* fontHeight) const
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;
817 return BRect(2, top, Bounds().right - 2, top + BarHeight() - 4);
821 float
822 BStatusBar::_BarPosition(const BRect& barFrame) const
824 if (fCurrent == 0)
825 return barFrame.left - 1;
827 return roundf(barFrame.left - 1
828 + (fCurrent * (barFrame.Width() + 3) / fMax));
832 bool
833 BStatusBar::_HasText() const
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;