diff --git a/headers/os/interface/SeparatorView.h b/headers/os/interface/SeparatorView.h new file mode 100644 index 0000000000..b0269ddb61 --- /dev/null +++ b/headers/os/interface/SeparatorView.h @@ -0,0 +1,106 @@ +/* + * Copyright 2001-2009, Stephan Aßmus + * Copyright 2001-2009, Ingo Weinhold + * All rights reserved. Distributed under the terms of the MIT license. + */ +#ifndef _SEPARATOR_VIEW_H +#define _SEPARATOR_VIEW_H + +#include +#include +#include + + +class BSeparatorView : public BView { +public: + BSeparatorView(enum orientation orientation, + border_style border = B_FANCY_BORDER); + BSeparatorView(const char* name, + const char* label, + enum orientation orientation + = B_HORIZONTAL, + border_style border = B_FANCY_BORDER, + const BAlignment& alignment + = BAlignment(B_ALIGN_HORIZONTAL_CENTER, + B_ALIGN_VERTICAL_CENTER)); + BSeparatorView(const char* name, + BView* labelView, + enum orientation orientation + = B_HORIZONTAL, + border_style border = B_FANCY_BORDER, + const BAlignment& alignment + = BAlignment(B_ALIGN_HORIZONTAL_CENTER, + B_ALIGN_VERTICAL_CENTER)); + BSeparatorView(const char* label = NULL, + enum orientation orientation + = B_HORIZONTAL, + border_style border = B_FANCY_BORDER, + const BAlignment& alignment + = BAlignment(B_ALIGN_HORIZONTAL_CENTER, + B_ALIGN_VERTICAL_CENTER)); + BSeparatorView(BView* labelView, + enum orientation orientation + = B_HORIZONTAL, + border_style border = B_FANCY_BORDER, + const BAlignment& alignment + = BAlignment(B_ALIGN_HORIZONTAL_CENTER, + B_ALIGN_VERTICAL_CENTER)); + + BSeparatorView(BMessage* archive); + + virtual ~BSeparatorView(); + + static BArchivable* Instantiate(BMessage* archive); + virtual status_t Archive(BMessage* into, + bool deep = true) const; + + virtual void Draw(BRect updateRect); + virtual void GetPreferredSize(float* width, float* height); + + virtual BSize MinSize(); + virtual BSize MaxSize(); + virtual BSize PreferredSize(); + + void SetOrientation(enum orientation orientation); + void SetAlignment(const BAlignment& aligment); + void SetBorderStyle(border_style border); + + void SetLabel(const char* label); + void SetLabel(BView* view, bool deletePrevious); + + virtual status_t Perform(perform_code code, void* data); + +protected: + virtual void DoLayout(); + +private: + virtual void _ReservedSeparatorView1(); + virtual void _ReservedSeparatorView2(); + virtual void _ReservedSeparatorView3(); + virtual void _ReservedSeparatorView4(); + virtual void _ReservedSeparatorView5(); + virtual void _ReservedSeparatorView6(); + virtual void _ReservedSeparatorView7(); + virtual void _ReservedSeparatorView8(); + virtual void _ReservedSeparatorView9(); + virtual void _ReservedSeparatorView10(); + +private: + void _Init(const char* label, BView* labelView, + enum orientation orientation, + BAlignment alignment, border_style border); + + float _BorderSize() const; + BRect _MaxLabelBounds() const; + + BString fLabel; + BView* fLabelView; + + orientation fOrientation; + BAlignment fAlignment; + border_style fBorder; + + uint32 _reserved[10]; +}; + +#endif // _SEPARATOR_VIEW_H diff --git a/src/kits/interface/SeparatorView.cpp b/src/kits/interface/SeparatorView.cpp new file mode 100644 index 0000000000..d487928fe0 --- /dev/null +++ b/src/kits/interface/SeparatorView.cpp @@ -0,0 +1,501 @@ +/* + * 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(enum 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, + enum 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, + enum 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, + enum 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, + enum 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) +{ + // TODO: Test this. + if (archive == NULL) + return; + + 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 ret = BView::Archive(into, deep); + if (ret != B_OK) + return ret; + + if (fLabelView != NULL) + ret = into->AddString("_labelview", fLabelView->Name()); + else + ret = into->AddString("_label", fLabel.String()); + + if (ret == B_OK) + ret = into->AddInt32("_orientation", fOrientation); + + if (ret == B_OK) + ret = into->AddInt32("_halignment", fAlignment.horizontal); + + if (ret == B_OK) + ret = into->AddInt32("_valignment", fAlignment.vertical); + + if (ret == B_OK) + ret = into->AddInt32("_border", fBorder); + + return ret; +} + + +// #pragma mark - + + +void +BSeparatorView::Draw(BRect updateRect) +{ + rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR); + if (BView* parent = Parent()) { + if (parent->ViewColor() != B_TRANSPARENT_COLOR) + base = parent->ViewColor(); + } + + 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) { + default: + case B_ALIGN_LEFT: + 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) { + default: + case B_ALIGN_TOP: + 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, base, + 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, base, + fBorder, 0, BControlLook::B_LEFT_BORDER); + } + if (labelBounds.IsValid()) + region.Include(labelBounds); + ConstrainClippingRegion(®ion); + } + + SetLowColor(base); + FillRect(updateRect, B_SOLID_LOW); + + if (fLabel.CountChars() > 0) { + font_height fontHeight; + GetFontHeight(&fontHeight); + + SetHighColor(0, 0, 0, 255); + + 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)); + } + } +} + +// GetPreferredSize +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(enum 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, + enum 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 3.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() {} +