git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@17190 a95241bf-73f2-0310-859d-f6bbb57e9c96
592 lines
11 KiB
C++
592 lines
11 KiB
C++
/*
|
|
* Copyright (c) 2001-2006, Haiku, Inc.
|
|
* Distributed under the terms of the MIT license.
|
|
*
|
|
* Authors:
|
|
* Marc Flerackers ([email protected])
|
|
* Stephan Aßmus <[email protected]>
|
|
* DarkWyrm <[email protected]>
|
|
* Axel Dörfler, [email protected]
|
|
*/
|
|
|
|
|
|
#include <Box.h>
|
|
#include <Message.h>
|
|
#include <Region.h>
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
|
|
BBox::BBox(BRect frame, const char *name, uint32 resizingMode, uint32 flags,
|
|
border_style border)
|
|
: BView(frame, name, resizingMode, flags | B_FRAME_EVENTS),
|
|
fStyle(border)
|
|
{
|
|
SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
|
SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
|
|
|
_InitObject();
|
|
}
|
|
|
|
|
|
BBox::BBox(BMessage *archive)
|
|
: BView(archive)
|
|
{
|
|
_InitObject(archive);
|
|
}
|
|
|
|
|
|
BBox::~BBox()
|
|
{
|
|
_ClearLabel();
|
|
}
|
|
|
|
|
|
BArchivable *
|
|
BBox::Instantiate(BMessage *archive)
|
|
{
|
|
if (validate_instantiation(archive, "BBox"))
|
|
return new BBox(archive);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
status_t
|
|
BBox::Archive(BMessage *archive, bool deep) const
|
|
{
|
|
status_t ret = BView::Archive(archive, deep);
|
|
|
|
if (fLabel && ret == B_OK)
|
|
ret = archive->AddString("_label", fLabel);
|
|
|
|
if (fLabelView && ret == B_OK)
|
|
ret = archive->AddBool("_lblview", true);
|
|
|
|
if (fStyle != B_FANCY_BORDER && ret == B_OK)
|
|
ret = archive->AddInt32("_style", fStyle);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
void
|
|
BBox::SetBorder(border_style border)
|
|
{
|
|
fStyle = border;
|
|
|
|
if (Window() != NULL && LockLooper()) {
|
|
Invalidate();
|
|
UnlockLooper();
|
|
}
|
|
}
|
|
|
|
|
|
border_style
|
|
BBox::Border() const
|
|
{
|
|
return fStyle;
|
|
}
|
|
|
|
|
|
//! This function is not part of the R5 API and is not yet finalized yet
|
|
float
|
|
BBox::TopBorderOffset()
|
|
{
|
|
float labelHeight = 0;
|
|
|
|
if (fLabel != NULL)
|
|
labelHeight = fLabelBox->Height();
|
|
else if (fLabelView != NULL)
|
|
labelHeight = fLabelView->Bounds().Height();
|
|
|
|
return ceilf(labelHeight / 2.0f);
|
|
}
|
|
|
|
|
|
//! This function is not part of the R5 API and is not yet finalized yet
|
|
BRect
|
|
BBox::InnerFrame()
|
|
{
|
|
float borderSize = Border() == B_FANCY_BORDER ? 2.0f
|
|
: Border() == B_PLAIN_BORDER ? 1.0f : 0.0f;
|
|
float labelHeight = 0.0f;
|
|
|
|
if (fLabel != NULL) {
|
|
// fLabelBox doesn't contain the font's descent, but we want it here
|
|
font_height fontHeight;
|
|
GetFontHeight(&fontHeight);
|
|
|
|
labelHeight = ceilf(fontHeight.ascent + fontHeight.descent);
|
|
} else if (fLabelView != NULL)
|
|
labelHeight = fLabelView->Bounds().Height();
|
|
|
|
BRect rect = Bounds().InsetByCopy(borderSize, borderSize);
|
|
if (labelHeight)
|
|
rect.top = Bounds().top + labelHeight;
|
|
|
|
return rect;
|
|
}
|
|
|
|
|
|
void
|
|
BBox::SetLabel(const char *string)
|
|
{
|
|
_ClearLabel();
|
|
|
|
if (string) {
|
|
font_height fontHeight;
|
|
GetFontHeight(&fontHeight);
|
|
|
|
fLabel = strdup(string);
|
|
|
|
// leave 6 pixels of the frame, and have a gap of 4 pixels between
|
|
// the frame and the text on both sides
|
|
fLabelBox = new BRect(6.0f, 0, StringWidth(string) + 14.0f,
|
|
ceilf(fontHeight.ascent));
|
|
}
|
|
|
|
if (Window())
|
|
Invalidate();
|
|
}
|
|
|
|
|
|
status_t
|
|
BBox::SetLabel(BView *viewLabel)
|
|
{
|
|
_ClearLabel();
|
|
|
|
if (viewLabel) {
|
|
fLabelView = viewLabel;
|
|
fLabelView->MoveTo(10.0f, 0.0f);
|
|
AddChild(fLabelView, ChildAt(0));
|
|
}
|
|
|
|
if (Window())
|
|
Invalidate();
|
|
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
const char *
|
|
BBox::Label() const
|
|
{
|
|
return fLabel;
|
|
}
|
|
|
|
|
|
BView *
|
|
BBox::LabelView() const
|
|
{
|
|
return fLabelView;
|
|
}
|
|
|
|
|
|
void
|
|
BBox::Draw(BRect updateRect)
|
|
{
|
|
PushState();
|
|
|
|
BRect labelBox = BRect(0, 0, 0, 0);
|
|
if (fLabel != NULL) {
|
|
labelBox = *fLabelBox;
|
|
BRegion update(updateRect);
|
|
update.Exclude(labelBox);
|
|
|
|
ConstrainClippingRegion(&update);
|
|
} else if (fLabelView != NULL)
|
|
labelBox = fLabelView->Bounds();
|
|
|
|
switch (fStyle) {
|
|
case B_FANCY_BORDER:
|
|
_DrawFancy(labelBox);
|
|
break;
|
|
|
|
case B_PLAIN_BORDER:
|
|
_DrawPlain(labelBox);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (fLabel) {
|
|
ConstrainClippingRegion(NULL);
|
|
|
|
font_height fontHeight;
|
|
GetFontHeight(&fontHeight);
|
|
|
|
SetHighColor(0, 0, 0);
|
|
DrawString(fLabel, BPoint(10.0f, ceilf(fontHeight.ascent)));
|
|
}
|
|
|
|
PopState();
|
|
}
|
|
|
|
|
|
void
|
|
BBox::AttachedToWindow()
|
|
{
|
|
if (Parent()) {
|
|
SetViewColor(Parent()->ViewColor());
|
|
SetLowColor(Parent()->ViewColor());
|
|
}
|
|
|
|
// The box could have been resized in the mean time
|
|
fBounds = Bounds();
|
|
}
|
|
|
|
|
|
void
|
|
BBox::DetachedFromWindow()
|
|
{
|
|
BView::DetachedFromWindow();
|
|
}
|
|
|
|
|
|
void
|
|
BBox::AllAttached()
|
|
{
|
|
BView::AllAttached();
|
|
}
|
|
|
|
|
|
void
|
|
BBox::AllDetached()
|
|
{
|
|
BView::AllDetached();
|
|
}
|
|
|
|
|
|
void
|
|
BBox::FrameResized(float width, float height)
|
|
{
|
|
BRect bounds(Bounds());
|
|
|
|
// invalidate the regions that the app_server did not
|
|
// (for removing the previous or drawing the new border)
|
|
if (fStyle != B_NO_BORDER) {
|
|
|
|
int32 borderSize = fStyle == B_PLAIN_BORDER ? 0 : 1;
|
|
|
|
BRect invalid(bounds);
|
|
if (fBounds.right < bounds.right) {
|
|
// enlarging
|
|
invalid.left = fBounds.right - borderSize;
|
|
invalid.right = fBounds.right;
|
|
|
|
Invalidate(invalid);
|
|
} else if (fBounds.right > bounds.right) {
|
|
// shrinking
|
|
invalid.left = bounds.right - borderSize;
|
|
|
|
Invalidate(invalid);
|
|
}
|
|
|
|
invalid = bounds;
|
|
if (fBounds.bottom < bounds.bottom) {
|
|
// enlarging
|
|
invalid.top = fBounds.bottom - borderSize;
|
|
invalid.bottom = fBounds.bottom;
|
|
|
|
Invalidate(invalid);
|
|
} else if (fBounds.bottom > bounds.bottom) {
|
|
// shrinking
|
|
invalid.top = bounds.bottom - borderSize;
|
|
|
|
Invalidate(invalid);
|
|
}
|
|
}
|
|
|
|
fBounds.right = bounds.right;
|
|
fBounds.bottom = bounds.bottom;
|
|
}
|
|
|
|
|
|
void
|
|
BBox::MessageReceived(BMessage *message)
|
|
{
|
|
BView::MessageReceived(message);
|
|
}
|
|
|
|
|
|
void
|
|
BBox::MouseDown(BPoint point)
|
|
{
|
|
BView::MouseDown(point);
|
|
}
|
|
|
|
|
|
void
|
|
BBox::MouseUp(BPoint point)
|
|
{
|
|
BView::MouseUp(point);
|
|
}
|
|
|
|
|
|
void
|
|
BBox::WindowActivated(bool active)
|
|
{
|
|
BView::WindowActivated(active);
|
|
}
|
|
|
|
|
|
void
|
|
BBox::MouseMoved(BPoint point, uint32 transit, const BMessage *message)
|
|
{
|
|
BView::MouseMoved(point, transit, message);
|
|
}
|
|
|
|
|
|
void
|
|
BBox::FrameMoved(BPoint newLocation)
|
|
{
|
|
BView::FrameMoved(newLocation);
|
|
}
|
|
|
|
|
|
BHandler *
|
|
BBox::ResolveSpecifier(BMessage *message, int32 index,
|
|
BMessage *specifier, int32 what,
|
|
const char *property)
|
|
{
|
|
return BView::ResolveSpecifier(message, index, specifier, what, property);
|
|
}
|
|
|
|
|
|
void
|
|
BBox::ResizeToPreferred()
|
|
{
|
|
BView::ResizeToPreferred();
|
|
}
|
|
|
|
|
|
void
|
|
BBox::GetPreferredSize(float *_width, float *_height)
|
|
{
|
|
float width, height;
|
|
bool label = true;
|
|
|
|
// acount for label
|
|
if (fLabelView) {
|
|
fLabelView->GetPreferredSize(&width, &height);
|
|
width += 10.0;
|
|
// the label view is placed 10 pixels from the left
|
|
} else if (fLabel) {
|
|
font_height fh;
|
|
GetFontHeight(&fh);
|
|
width += ceilf(StringWidth(fLabel));
|
|
height += ceilf(fh.ascent + fh.descent);
|
|
} else {
|
|
label = false;
|
|
width = 0;
|
|
height = 0;
|
|
}
|
|
|
|
// acount for border
|
|
switch (fStyle) {
|
|
case B_NO_BORDER:
|
|
break;
|
|
case B_PLAIN_BORDER:
|
|
// label: (1 pixel for border + 1 pixel for padding) * 2
|
|
// no label: (1 pixel for border) * 2 + 1 pixel for padding
|
|
width += label ? 4 : 3;
|
|
// label: 1 pixel for bottom border + 1 pixel for padding
|
|
// no label: (1 pixel for border) * 2 + 1 pixel for padding
|
|
height += label ? 2 : 3;
|
|
break;
|
|
case B_FANCY_BORDER:
|
|
// label: (2 pixel for border + 1 pixel for padding) * 2
|
|
// no label: (2 pixel for border) * 2 + 1 pixel for padding
|
|
width += label ? 6 : 5;
|
|
// label: 2 pixel for bottom border + 1 pixel for padding
|
|
// no label: (2 pixel for border) * 2 + 1 pixel for padding
|
|
height += label ? 3 : 5;
|
|
break;
|
|
}
|
|
// NOTE: children are ignored, you can use BBox::GetPreferredSize()
|
|
// to get the minimum size of this object, then add the size
|
|
// of your child(ren) plus inner padding for the final size
|
|
|
|
if (_width)
|
|
*_width = width;
|
|
if (_height)
|
|
*_height = height;
|
|
}
|
|
|
|
|
|
void
|
|
BBox::MakeFocus(bool focused)
|
|
{
|
|
BView::MakeFocus(focused);
|
|
}
|
|
|
|
|
|
status_t
|
|
BBox::GetSupportedSuites(BMessage *message)
|
|
{
|
|
return BView::GetSupportedSuites(message);
|
|
}
|
|
|
|
|
|
status_t
|
|
BBox::Perform(perform_code d, void *arg)
|
|
{
|
|
return BView::Perform(d, arg);
|
|
}
|
|
|
|
|
|
void BBox::_ReservedBox1() {}
|
|
void BBox::_ReservedBox2() {}
|
|
|
|
|
|
BBox &
|
|
BBox::operator=(const BBox &)
|
|
{
|
|
return *this;
|
|
}
|
|
|
|
|
|
void
|
|
BBox::_InitObject(BMessage* archive)
|
|
{
|
|
fBounds = Bounds();
|
|
|
|
fLabel = NULL;
|
|
fLabelView = NULL;
|
|
fLabelBox = NULL;
|
|
|
|
int32 flags = 0;
|
|
|
|
BFont font(be_bold_font);
|
|
|
|
if (!archive || !archive->HasString("_fname"))
|
|
flags = B_FONT_FAMILY_AND_STYLE;
|
|
|
|
if (!archive || !archive->HasFloat("_fflt"))
|
|
flags |= B_FONT_SIZE;
|
|
|
|
if (flags != 0)
|
|
SetFont(&font, flags);
|
|
|
|
if (archive != NULL) {
|
|
const char *string;
|
|
if (archive->FindString("_label", &string) == B_OK)
|
|
SetLabel(string);
|
|
|
|
bool fancy;
|
|
int32 style;
|
|
|
|
if (archive->FindBool("_style", &fancy) == B_OK)
|
|
fStyle = fancy ? B_FANCY_BORDER : B_PLAIN_BORDER;
|
|
else if (archive->FindInt32("_style", &style) == B_OK)
|
|
fStyle = (border_style)style;
|
|
|
|
bool hasLabelView;
|
|
if (archive->FindBool("_lblview", &hasLabelView) == B_OK)
|
|
fLabelView = ChildAt(0);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
BBox::_DrawPlain(BRect labelBox)
|
|
{
|
|
BRect rect = Bounds();
|
|
rect.top += TopBorderOffset();
|
|
|
|
rgb_color shadow = tint_color(ViewColor(), B_DARKEN_3_TINT);
|
|
|
|
if (rect.Height() == 0.0 || rect.Width() == 0.0) {
|
|
// used as separator
|
|
SetHighColor(shadow);
|
|
StrokeLine(rect.LeftTop(),rect.RightBottom());
|
|
} else {
|
|
// used as box
|
|
rgb_color light = tint_color(ViewColor(), B_LIGHTEN_MAX_TINT);
|
|
BeginLineArray(4);
|
|
AddLine(BPoint(rect.left, rect.bottom),
|
|
BPoint(rect.left, rect.top), light);
|
|
AddLine(BPoint(rect.left + 1.0f, rect.top),
|
|
BPoint(rect.right, rect.top), light);
|
|
AddLine(BPoint(rect.left + 1.0f, rect.bottom),
|
|
BPoint(rect.right, rect.bottom), shadow);
|
|
AddLine(BPoint(rect.right, rect.bottom - 1.0f),
|
|
BPoint(rect.right, rect.top + 1.0f), shadow);
|
|
EndLineArray();
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
BBox::_DrawFancy(BRect labelBox)
|
|
{
|
|
BRect rect = Bounds();
|
|
rect.top += TopBorderOffset();
|
|
|
|
rgb_color light = tint_color(ViewColor(), B_LIGHTEN_MAX_TINT);
|
|
rgb_color shadow = tint_color(ViewColor(), B_DARKEN_3_TINT);
|
|
|
|
if (rect.Height() == 1.0) {
|
|
// used as horizontal separator
|
|
BeginLineArray(2);
|
|
AddLine(BPoint(rect.left, rect.top),
|
|
BPoint(rect.right, rect.top), shadow);
|
|
AddLine(BPoint(rect.left, rect.bottom),
|
|
BPoint(rect.right, rect.bottom), light);
|
|
EndLineArray();
|
|
} else if (rect.Width() == 1.0) {
|
|
// used as vertical separator
|
|
BeginLineArray(2);
|
|
AddLine(BPoint(rect.left, rect.top),
|
|
BPoint(rect.left, rect.bottom), shadow);
|
|
AddLine(BPoint(rect.right, rect.top),
|
|
BPoint(rect.right, rect.bottom), light);
|
|
EndLineArray();
|
|
} else {
|
|
// used as box
|
|
BeginLineArray(8);
|
|
AddLine(BPoint(rect.left, rect.bottom - 1.0),
|
|
BPoint(rect.left, rect.top), shadow);
|
|
AddLine(BPoint(rect.left + 1.0, rect.top),
|
|
BPoint(rect.right - 1.0, rect.top), shadow);
|
|
AddLine(BPoint(rect.left, rect.bottom),
|
|
BPoint(rect.right, rect.bottom), light);
|
|
AddLine(BPoint(rect.right, rect.bottom - 1.0),
|
|
BPoint(rect.right, rect.top), light);
|
|
|
|
rect.InsetBy(1.0, 1.0);
|
|
|
|
AddLine(BPoint(rect.left, rect.bottom - 1.0),
|
|
BPoint(rect.left, rect.top), light);
|
|
AddLine(BPoint(rect.left + 1.0, rect.top),
|
|
BPoint(rect.right - 1.0, rect.top), light);
|
|
AddLine(BPoint(rect.left, rect.bottom),
|
|
BPoint(rect.right, rect.bottom), shadow);
|
|
AddLine(BPoint(rect.right, rect.bottom - 1.0),
|
|
BPoint(rect.right, rect.top), shadow);
|
|
EndLineArray();
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
BBox::_ClearLabel()
|
|
{
|
|
fBounds.top = 0;
|
|
|
|
if (fLabel) {
|
|
delete fLabelBox;
|
|
free(fLabel);
|
|
fLabel = NULL;
|
|
fLabelBox = NULL;
|
|
} else if (fLabelView) {
|
|
fLabelView->RemoveSelf();
|
|
delete fLabelView;
|
|
fLabelView = NULL;
|
|
}
|
|
}
|