/* * Copyright 2001-2009, Stephan Aßmus * Copyright 2001-2009, Ingo Weinhold * All rights reserved. Distributed under the terms of the MIT license. */ #include "SeparatorView.h" #include #include #include #include #include #include static const float kMinBorderLength = 5.0f; // TODO: Actually implement alignment support! // TODO: More testing, especially archiving. BSeparatorView::BSeparatorView(orientation orientation, border_style border) : BView(NULL, B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE) { _Init(NULL, NULL, orientation, BAlignment(B_ALIGN_HORIZONTAL_CENTER, B_ALIGN_VERTICAL_CENTER), border); } BSeparatorView::BSeparatorView(const char* name, const char* label, orientation orientation, border_style border, const BAlignment& alignment) : BView(name, B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE) { _Init(label, NULL, orientation, alignment, border); } BSeparatorView::BSeparatorView(const char* name, BView* labelView, orientation orientation, border_style border, const BAlignment& alignment) : BView(name, B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE) { _Init(NULL, labelView, orientation, alignment, border); } BSeparatorView::BSeparatorView(const char* label, orientation orientation, border_style border, const BAlignment& alignment) : BView("", B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE) { _Init(label, NULL, orientation, alignment, border); } BSeparatorView::BSeparatorView(BView* labelView, orientation orientation, border_style border, const BAlignment& alignment) : BView("", B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE) { _Init(NULL, labelView, orientation, alignment, border); } BSeparatorView::BSeparatorView(BMessage* archive) : BView(archive), fLabel(), fLabelView(NULL), fOrientation(B_HORIZONTAL), fAlignment(BAlignment(B_ALIGN_HORIZONTAL_CENTER, B_ALIGN_VERTICAL_CENTER)), fBorder(B_FANCY_BORDER) { // NULL archives will be caught by BView. const char* label; if (archive->FindString("_labelview", &label) == B_OK) { fLabelView = FindView(label); } else if (archive->FindString("_label", &label) == B_OK) { fLabel.SetTo(label); } int32 orientation; if (archive->FindInt32("_orientation", &orientation) == B_OK) fOrientation = (enum orientation)orientation; int32 hAlignment; int32 vAlignment; if (archive->FindInt32("_halignment", &hAlignment) == B_OK && archive->FindInt32("_valignment", &vAlignment) == B_OK) { fAlignment.horizontal = (alignment)hAlignment; fAlignment.vertical = (vertical_alignment)vAlignment; } int32 borderStyle; if (archive->FindInt32("_border", &borderStyle) != B_OK) fBorder = (border_style)borderStyle; } BSeparatorView::~BSeparatorView() { } // #pragma mark - Archiving BArchivable* BSeparatorView::Instantiate(BMessage* archive) { if (validate_instantiation(archive, "BSeparatorView")) return new (std::nothrow) BSeparatorView(archive); return NULL; } status_t BSeparatorView::Archive(BMessage* into, bool deep) const { // TODO: Test this. status_t result = BView::Archive(into, deep); if (result != B_OK) return result; if (fLabelView != NULL) result = into->AddString("_labelview", fLabelView->Name()); else result = into->AddString("_label", fLabel.String()); if (result == B_OK) result = into->AddInt32("_orientation", fOrientation); if (result == B_OK) result = into->AddInt32("_halignment", fAlignment.horizontal); if (result == B_OK) result = into->AddInt32("_valignment", fAlignment.vertical); if (result == B_OK) result = into->AddInt32("_border", fBorder); return result; } // #pragma mark - void BSeparatorView::Draw(BRect updateRect) { rgb_color bgColor = ui_color(B_PANEL_BACKGROUND_COLOR); rgb_color highColor = ui_color(B_PANEL_TEXT_COLOR); if (BView* parent = Parent()) { if (parent->ViewColor() != B_TRANSPARENT_COLOR) { bgColor = parent->ViewColor(); highColor = parent->HighColor(); } } BRect labelBounds; if (fLabelView != NULL) { labelBounds = fLabelView->Frame(); } else if (fLabel.CountChars() > 0) { labelBounds = _MaxLabelBounds(); float labelWidth = StringWidth(fLabel.String()); if (fOrientation == B_HORIZONTAL) { switch (fAlignment.horizontal) { case B_ALIGN_LEFT: default: labelBounds.right = labelBounds.left + labelWidth; break; case B_ALIGN_RIGHT: labelBounds.left = labelBounds.right - labelWidth; break; case B_ALIGN_CENTER: labelBounds.left = (labelBounds.left + labelBounds.right - labelWidth) / 2; labelBounds.right = labelBounds.left + labelWidth; break; } } else { switch (fAlignment.vertical) { case B_ALIGN_TOP: default: labelBounds.bottom = labelBounds.top + labelWidth; break; case B_ALIGN_BOTTOM: labelBounds.top = labelBounds.bottom - labelWidth; break; case B_ALIGN_MIDDLE: labelBounds.top = (labelBounds.top + labelBounds.bottom - labelWidth) / 2; labelBounds.bottom = labelBounds.top + labelWidth; break; } } } BRect bounds = Bounds(); BRegion region(bounds); if (labelBounds.IsValid()) { region.Exclude(labelBounds); ConstrainClippingRegion(®ion); } float borderSize = _BorderSize(); if (borderSize > 0.0f) { if (fOrientation == B_HORIZONTAL) { bounds.top = floorf((bounds.top + bounds.bottom + 1 - borderSize) / 2); bounds.bottom = bounds.top + borderSize - 1; region.Exclude(bounds); be_control_look->DrawBorder(this, bounds, updateRect, bgColor, fBorder, 0, BControlLook::B_TOP_BORDER); } else { bounds.left = floorf((bounds.left + bounds.right + 1 - borderSize) / 2); bounds.right = bounds.left + borderSize - 1; region.Exclude(bounds); be_control_look->DrawBorder(this, bounds, updateRect, bgColor, fBorder, 0, BControlLook::B_LEFT_BORDER); } if (labelBounds.IsValid()) region.Include(labelBounds); ConstrainClippingRegion(®ion); } SetLowColor(bgColor); FillRect(updateRect, B_SOLID_LOW); if (fLabel.CountChars() > 0) { font_height fontHeight; GetFontHeight(&fontHeight); SetHighColor(highColor); if (fOrientation == B_HORIZONTAL) { DrawString(fLabel.String(), BPoint(labelBounds.left, labelBounds.top + ceilf(fontHeight.ascent))); } else { DrawString(fLabel.String(), BPoint(labelBounds.left + ceilf(fontHeight.ascent), labelBounds.bottom)); } } } void BSeparatorView::GetPreferredSize(float* _width, float* _height) { float width = 0.0f; float height = 0.0f; if (fLabelView != NULL) { fLabelView->GetPreferredSize(&width, &height); } else if (fLabel.CountChars() > 0) { width = StringWidth(fLabel.String()); font_height fontHeight; GetFontHeight(&fontHeight); height = ceilf(fontHeight.ascent) + ceilf(fontHeight.descent); if (fOrientation == B_VERTICAL) { // swap width and height float temp = height; height = width; width = temp; } } float borderSize = _BorderSize(); // Add some room for the border if (fOrientation == B_HORIZONTAL) { width += kMinBorderLength * 2.0f; height = max_c(height, borderSize - 1.0f); } else { height += kMinBorderLength * 2.0f; width = max_c(width, borderSize - 1.0f); } if (_width != NULL) *_width = width; if (_height != NULL) *_height = height; } BSize BSeparatorView::MinSize() { BSize size; GetPreferredSize(&size.width, &size.height); return BLayoutUtils::ComposeSize(ExplicitMinSize(), size); } BSize BSeparatorView::MaxSize() { BSize size(MinSize()); if (fOrientation == B_HORIZONTAL) size.width = B_SIZE_UNLIMITED; else size.height = B_SIZE_UNLIMITED; return BLayoutUtils::ComposeSize(ExplicitMaxSize(), size); } BSize BSeparatorView::PreferredSize() { BSize size; GetPreferredSize(&size.width, &size.height); return BLayoutUtils::ComposeSize(ExplicitPreferredSize(), size); } // #pragma mark - void BSeparatorView::SetOrientation(orientation orientation) { if (orientation == fOrientation) return; fOrientation = orientation; BFont font; GetFont(&font); if (fOrientation == B_VERTICAL) font.SetRotation(90.0f); SetFont(&font); Invalidate(); InvalidateLayout(); } void BSeparatorView::SetAlignment(const BAlignment& aligment) { if (aligment == fAlignment) return; fAlignment = aligment; Invalidate(); InvalidateLayout(); } void BSeparatorView::SetBorderStyle(border_style border) { if (border == fBorder) return; fBorder = border; Invalidate(); } void BSeparatorView::SetLabel(const char* label) { if (label == NULL) label = ""; if (fLabel == label) return; fLabel.SetTo(label); Invalidate(); InvalidateLayout(); } void BSeparatorView::SetLabel(BView* view, bool deletePrevious) { if (fLabelView == view) return; if (fLabelView != NULL) { fLabelView->RemoveSelf(); if (deletePrevious) delete fLabelView; } fLabelView = view; if (fLabelView != NULL) AddChild(view); } status_t BSeparatorView::Perform(perform_code code, void* data) { return BView::Perform(code, data); } // #pragma mark - protected/private void BSeparatorView::DoLayout() { BView::DoLayout(); if (fLabelView == NULL) return; BRect bounds = _MaxLabelBounds(); BRect frame = BLayoutUtils::AlignInFrame(bounds, fLabelView->MaxSize(), fAlignment); fLabelView->MoveTo(frame.LeftTop()); fLabelView->ResizeTo(frame.Width(), frame.Height()); } void BSeparatorView::_Init(const char* label, BView* labelView, orientation orientation, BAlignment alignment, border_style border) { fLabel = ""; fLabelView = NULL; fOrientation = B_HORIZONTAL; fAlignment = alignment; fBorder = border; SetFont(be_bold_font); SetViewColor(B_TRANSPARENT_32_BIT); SetLabel(label); SetLabel(labelView, true); SetOrientation(orientation); } float BSeparatorView::_BorderSize() const { // TODO: Get these values from the BControlLook class. switch (fBorder) { case B_PLAIN_BORDER: return 1.0f; case B_FANCY_BORDER: return 2.0f; case B_NO_BORDER: default: return 0.0f; } } BRect BSeparatorView::_MaxLabelBounds() const { BRect bounds = Bounds(); if (fOrientation == B_HORIZONTAL) bounds.InsetBy(kMinBorderLength, 0.0f); else bounds.InsetBy(0.0f, kMinBorderLength); return bounds; } // #pragma mark - FBC padding void BSeparatorView::_ReservedSeparatorView1() {} void BSeparatorView::_ReservedSeparatorView2() {} void BSeparatorView::_ReservedSeparatorView3() {} void BSeparatorView::_ReservedSeparatorView4() {} void BSeparatorView::_ReservedSeparatorView5() {} void BSeparatorView::_ReservedSeparatorView6() {} void BSeparatorView::_ReservedSeparatorView7() {} void BSeparatorView::_ReservedSeparatorView8() {} void BSeparatorView::_ReservedSeparatorView9() {} void BSeparatorView::_ReservedSeparatorView10() {}