Implemented a BSeparatorView. It can be a horizontal or vertical line/border,

or also a label, optionally with a BView for the label. Some aspects of it have
not been exposed to throughrough testing, yet (archiving, label view),
the BAlignment support is also not well tested.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@31846 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stephan Aßmus 2009-07-28 14:15:55 +00:00
parent 483acc4382
commit 79f2db07a8
2 changed files with 607 additions and 0 deletions

View File

@ -0,0 +1,106 @@
/*
* Copyright 2001-2009, Stephan Aßmus <superstippi@gmx.de>
* Copyright 2001-2009, Ingo Weinhold <ingo_weinhold@gmx.de>
* All rights reserved. Distributed under the terms of the MIT license.
*/
#ifndef _SEPARATOR_VIEW_H
#define _SEPARATOR_VIEW_H
#include <Alignment.h>
#include <String.h>
#include <View.h>
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

View File

@ -0,0 +1,501 @@
/*
* Copyright 2001-2009, Stephan Aßmus <superstippi@gmx.de>
* Copyright 2001-2009, Ingo Weinhold <ingo_weinhold@gmx.de>
* All rights reserved. Distributed under the terms of the MIT license.
*/
#include "SeparatorView.h"
#include <new>
#include <math.h>
#include <stdio.h>
#include <ControlLook.h>
#include <LayoutUtils.h>
#include <Region.h>
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(&region);
}
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(&region);
}
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() {}