Refactoring.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21145 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold 2007-05-15 17:54:08 +00:00
parent e8113cabe0
commit a5b50d1fad
16 changed files with 1985 additions and 1352 deletions

View File

@ -0,0 +1,122 @@
/*
* Copyright 2007, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "CheckBox.h"
#include <View.h>
CheckBox::CheckBox(BMessage* message, BMessenger target)
: View(BRect(0, 0, 12, 12)),
BInvoker(message, target),
fSelected(false),
fPressed(false)
{
SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
}
void
CheckBox::SetSelected(bool selected)
{
if (selected != fSelected) {
fSelected = selected;
Invalidate();
// send the message
if (Message()) {
BMessage message(*Message());
message.AddBool("selected", IsSelected());
InvokeNotify(&message);
}
}
}
bool
CheckBox::IsSelected() const
{
return fSelected;
}
BSize
CheckBox::MinSize()
{
return BSize(12, 12);
}
BSize
CheckBox::MaxSize()
{
return MinSize();
}
void
CheckBox::Draw(BView* container, BRect updateRect)
{
BRect rect(Bounds());
if (fPressed)
container->SetHighColor((rgb_color){ 120, 0, 0, 255 });
else
container->SetHighColor((rgb_color){ 0, 0, 0, 255 });
container->StrokeRect(rect);
if (fPressed ? fPressedSelected : fSelected) {
rect.InsetBy(2, 2);
container->StrokeLine(rect.LeftTop(), rect.RightBottom());
container->StrokeLine(rect.RightTop(), rect.LeftBottom());
}
}
void
CheckBox::MouseDown(BPoint where, uint32 buttons, int32 modifiers)
{
if (fPressed)
return;
fPressed = true;
fPressedSelected = fSelected;
_PressedUpdate(where);
}
void
CheckBox::MouseUp(BPoint where, uint32 buttons, int32 modifiers)
{
if (!fPressed || (buttons & B_PRIMARY_MOUSE_BUTTON))
return;
_PressedUpdate(where);
fPressed = false;
SetSelected(fPressedSelected);
Invalidate();
}
void
CheckBox::MouseMoved(BPoint where, uint32 buttons, int32 modifiers)
{
if (!fPressed)
return;
_PressedUpdate(where);
}
void
CheckBox::_PressedUpdate(BPoint where)
{
bool pressedSelected = Bounds().Contains(where) ^ fSelected;
if (pressedSelected != fPressedSelected) {
fPressedSelected = pressedSelected;
Invalidate();
}
}

View File

@ -0,0 +1,44 @@
/*
* Copyright 2007, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef WIDGET_LAYOUT_TEST_CHECK_BOX_H
#define WIDGET_LAYOUT_TEST_CHECK_BOX_H
#include <Invoker.h>
#include "View.h"
class CheckBox : public View, public BInvoker {
public:
CheckBox(BMessage* message = NULL,
BMessenger target = BMessenger());
void SetSelected(bool selected);
bool IsSelected() const;
virtual BSize MinSize();
virtual BSize MaxSize();
virtual void Draw(BView* container, BRect updateRect);
virtual void MouseDown(BPoint where, uint32 buttons,
int32 modifiers);
virtual void MouseUp(BPoint where, uint32 buttons,
int32 modifiers);
virtual void MouseMoved(BPoint where, uint32 buttons,
int32 modifiers);
private:
void _PressedUpdate(BPoint where);
private:
bool fSelected;
bool fPressed;
bool fPressedSelected;
};
#endif // WIDGET_LAYOUT_TEST_CHECK_BOX_H

View File

@ -0,0 +1,410 @@
/*
* Copyright 2007, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "GroupView.h"
#include <LayoutUtils.h>
// #pragma mark - GroupView
struct GroupView::LayoutInfo {
int32 min;
int32 max;
int32 preferred;
int32 size;
LayoutInfo()
: min(0),
max(B_SIZE_UNLIMITED),
preferred(0)
{
}
void AddConstraints(float addMin, float addMax, float addPreferred)
{
if (addMin >= min)
min = (int32)addMin + 1;
if (addMax <= max)
max = (int32)addMax + 1;
if (addPreferred >= preferred)
preferred = (int32)addPreferred + 1;
}
void Normalize()
{
if (max > min)
max = min;
if (preferred < min)
preferred = min;
if (preferred > max)
preferred = max;
}
};
GroupView::GroupView(enum orientation orientation, int32 lineCount)
: View(BRect(0, 0, 0, 0)),
fOrientation(orientation),
fLineCount(lineCount),
fColumnSpacing(0),
fRowSpacing(0),
fInsets(0, 0, 0, 0),
fMinMaxValid(false),
fColumnInfos(NULL),
fRowInfos(NULL)
{
SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
if (fLineCount < 1)
fLineCount = 1;
}
GroupView::~GroupView()
{
delete fColumnInfos;
delete fRowInfos;
}
void
GroupView::SetSpacing(float horizontal, float vertical)
{
if (horizontal != fColumnSpacing || vertical != fRowSpacing) {
fColumnSpacing = horizontal;
fRowSpacing = vertical;
InvalidateLayout();
}
}
void
GroupView::SetInsets(float left, float top, float right, float bottom)
{
BRect newInsets(left, top, right, bottom);
if (newInsets != fInsets) {
fInsets = newInsets;
InvalidateLayout();
}
}
BSize
GroupView::MinSize()
{
_ValidateMinMax();
return _AddInsetsAndSpacing(BSize(fMinWidth - 1, fMinHeight - 1));
}
BSize
GroupView::MaxSize()
{
_ValidateMinMax();
return _AddInsetsAndSpacing(BSize(fMaxWidth - 1, fMaxHeight - 1));
}
BSize
GroupView::PreferredSize()
{
_ValidateMinMax();
return _AddInsetsAndSpacing(BSize(fPreferredWidth - 1,
fPreferredHeight - 1));
}
BAlignment
GroupView::Alignment()
{
return BAlignment(B_ALIGN_USE_FULL_WIDTH, B_ALIGN_USE_FULL_HEIGHT);
}
void
GroupView::Layout()
{
_ValidateMinMax();
// actually a little late already
BSize size = _SubtractInsetsAndSpacing(Size());
_LayoutLine(size.IntegerWidth() + 1, fColumnInfos, fColumnCount);
_LayoutLine(size.IntegerHeight() + 1, fRowInfos, fRowCount);
// layout children
BPoint location = fInsets.LeftTop();
for (int32 column = 0; column < fColumnCount; column++) {
LayoutInfo& columnInfo = fColumnInfos[column];
location.y = fInsets.top;
for (int32 row = 0; row < fRowCount; row++) {
View* child = _ChildAt(column, row);
if (!child)
continue;
// get the grid cell frame
BRect cellFrame(location,
BSize(columnInfo.size - 1, fRowInfos[row].size - 1));
// align the child frame in the grid cell
BRect childFrame = BLayoutUtils::AlignInFrame(cellFrame,
child->MaxSize(), child->Alignment());
// layout child
child->SetFrame(childFrame);
location.y += fRowInfos[row].size + fRowSpacing;
}
location.x += columnInfo.size + fColumnSpacing;
}
}
void
GroupView::_ValidateMinMax()
{
if (fMinMaxValid)
return;
delete fColumnInfos;
delete fRowInfos;
fColumnCount = _ColumnCount();
fRowCount = _RowCount();
fColumnInfos = new LayoutInfo[fColumnCount];
fRowInfos = new LayoutInfo[fRowCount];
// collect the children's min/max constraints
for (int32 column = 0; column < fColumnCount; column++) {
for (int32 row = 0; row < fRowCount; row++) {
View* child = _ChildAt(column, row);
if (!child)
continue;
BSize min = child->MinSize();
BSize max = child->MaxSize();
BSize preferred = child->PreferredSize();
// apply constraints to column/row info
fColumnInfos[column].AddConstraints(min.width, max.width,
preferred.width);
fRowInfos[row].AddConstraints(min.height, max.height,
preferred.height);
}
}
// normalize the column/row constraints and compute sum min/max
fMinWidth = 0;
fMinHeight = 0;
fMaxWidth = 0;
fMaxHeight = 0;
fPreferredWidth = 0;
fPreferredHeight = 0;
for (int32 column = 0; column < fColumnCount; column++) {
fColumnInfos[column].Normalize();
fMinWidth = BLayoutUtils::AddSizesInt32(fMinWidth,
fColumnInfos[column].min);
fMaxWidth = BLayoutUtils::AddSizesInt32(fMaxWidth,
fColumnInfos[column].max);
fPreferredWidth = BLayoutUtils::AddSizesInt32(fPreferredWidth,
fColumnInfos[column].preferred);
}
for (int32 row = 0; row < fRowCount; row++) {
fRowInfos[row].Normalize();
fMinHeight = BLayoutUtils::AddSizesInt32(fMinHeight,
fRowInfos[row].min);
fMaxHeight = BLayoutUtils::AddSizesInt32(fMaxHeight,
fRowInfos[row].max);
fPreferredHeight = BLayoutUtils::AddSizesInt32(fPreferredHeight,
fRowInfos[row].preferred);
}
fMinMaxValid = true;
}
void
GroupView::_LayoutLine(int32 size, LayoutInfo* infos, int32 infoCount)
{
BList infosToLayout;
for (int32 i = 0; i < infoCount; i++) {
infos[i].size = 0;
infosToLayout.AddItem(infos + i);
}
// Distribute the available space over the infos. Each iteration we
// try to distribute the remaining space evenly. We respect min and
// max constraints, though, add up the space we failed to assign
// due to the constraints, and use the sum as remaining space for the
// next iteration (can be negative). Then we ignore infos that can't
// shrink or grow anymore (depending on what would be needed).
while (!infosToLayout.IsEmpty()) {
BList canShrinkInfos;
BList canGrowInfos;
int32 sizeDiff = 0;
int32 infosToLayoutCount = infosToLayout.CountItems();
for (int32 i = 0; i < infosToLayoutCount; i++) {
LayoutInfo* info = (LayoutInfo*)infosToLayout.ItemAt(i);
info->size += (i + 1) * size / infosToLayoutCount
- i * size / infosToLayoutCount;
if (info->size < info->min) {
sizeDiff -= info->min - info->size;
info->size = info->min;
} else if (info->size > info->max) {
sizeDiff += info->size - info->max;
info->size = info->max;
}
if (info->size > info->min)
canShrinkInfos.AddItem(info);
if (info->size < info->max)
canGrowInfos.AddItem(info);
}
size = sizeDiff;
if (size == 0)
break;
if (size > 0)
infosToLayout = canGrowInfos;
else
infosToLayout = canShrinkInfos;
}
// If unassigned space is remaining, that means, that the group has
// been resized beyond its max size. We distribute the excess space
// evenly.
if (size > 0) {
for (int32 i = 0; i < infoCount; i++) {
infos[i].size += (i + 1) * size / infoCount
- i * size / infoCount;
}
}
}
BSize
GroupView::_AddInsetsAndSpacing(BSize size)
{
size.width = BLayoutUtils::AddDistances(size.width,
fInsets.left + fInsets.right - 1
+ (fColumnCount - 1) * fColumnSpacing);
size.height = BLayoutUtils::AddDistances(size.height,
fInsets.top + fInsets.bottom - 1
+ (fRowCount - 1) * fRowSpacing);
return size;
}
BSize
GroupView::_SubtractInsetsAndSpacing(BSize size)
{
size.width = BLayoutUtils::SubtractDistances(size.width,
fInsets.left + fInsets.right - 1
+ (fColumnCount - 1) * fColumnSpacing);
size.height = BLayoutUtils::SubtractDistances(size.height,
fInsets.top + fInsets.bottom - 1
+ (fRowCount - 1) * fRowSpacing);
return size;
}
int32
GroupView::_RowCount() const
{
int32 childCount = CountChildren();
int32 count;
if (fOrientation == B_HORIZONTAL)
count = min_c(fLineCount, childCount);
else
count = (childCount + fLineCount - 1) / fLineCount;
return max_c(count, 1);
}
int32
GroupView::_ColumnCount() const
{
int32 childCount = CountChildren();
int32 count;
if (fOrientation == B_HORIZONTAL)
count = (childCount + fLineCount - 1) / fLineCount;
else
count = min_c(fLineCount, childCount);
return max_c(count, 1);
}
View*
GroupView::_ChildAt(int32 column, int32 row) const
{
if (fOrientation == B_HORIZONTAL)
return ChildAt(column * fLineCount + row);
else
return ChildAt(row * fLineCount + column);
}
// #pragma mark - Glue
Glue::Glue()
: View()
{
SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
}
// #pragma mark - Strut
Strut::Strut(float pixelWidth, float pixelHeight)
: View(),
fSize(pixelWidth >= 0 ? pixelWidth - 1 : B_SIZE_UNSET,
pixelHeight >= 0 ? pixelHeight - 1 : B_SIZE_UNSET)
{
SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
}
BSize
Strut::MinSize()
{
return BLayoutUtils::ComposeSize(fSize, BSize(-1, -1));
}
BSize
Strut::MaxSize()
{
return BLayoutUtils::ComposeSize(fSize,
BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED));
}
// #pragma mark - HStrut
HStrut::HStrut(float width)
: Strut(width, -1)
{
}
// #pragma mark - VStrut
VStrut::VStrut(float height)
: Strut(-1, height)
{
}

View File

@ -0,0 +1,99 @@
/*
* Copyright 2007, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef WIDGET_LAYOUT_TEST_GROUP_VIEW_H
#define WIDGET_LAYOUT_TEST_GROUP_VIEW_H
#include "View.h"
// GroupView
class GroupView : public View {
public:
GroupView(enum orientation orientation,
int32 lineCount = 1);
virtual ~GroupView();
void SetSpacing(float horizontal, float vertical);
void SetInsets(float left, float top, float right,
float bottom);
virtual BSize MinSize();
virtual BSize MaxSize();
virtual BSize PreferredSize();
virtual BAlignment Alignment();
virtual void Layout();
private:
struct LayoutInfo;
private:
void _ValidateMinMax();
void _LayoutLine(int32 size, LayoutInfo* infos,
int32 infoCount);
BSize _AddInsetsAndSpacing(BSize size);
BSize _SubtractInsetsAndSpacing(BSize size);
int32 _RowCount() const;
int32 _ColumnCount() const;
View* _ChildAt(int32 column, int32 row) const;
private:
enum orientation fOrientation;
int32 fLineCount;
float fColumnSpacing;
float fRowSpacing;
BRect fInsets;
bool fMinMaxValid;
int32 fMinWidth;
int32 fMinHeight;
int32 fMaxWidth;
int32 fMaxHeight;
int32 fPreferredWidth;
int32 fPreferredHeight;
LayoutInfo* fColumnInfos;
LayoutInfo* fRowInfos;
int32 fColumnCount;
int32 fRowCount;
};
// Glue
class Glue : public View {
public:
Glue();
};
// Strut
class Strut : public View {
public:
Strut(float pixelWidth, float pixelHeight);
virtual BSize MinSize();
virtual BSize MaxSize();
private:
BSize fSize;
};
// HStrut
class HStrut : public Strut {
public:
HStrut(float width);
};
// VStrut
class VStrut : public Strut {
public:
VStrut(float height);
};
#endif // WIDGET_LAYOUT_TEST_GROUP_VIEW_H

View File

@ -4,6 +4,14 @@ SetSubDirSupportedPlatforms haiku libbe_test ;
SimpleTest WidgetLayoutTest :
WidgetLayoutTest.cpp
CheckBox.cpp
GroupView.cpp
StringView.cpp
TwoDimensionalSliderView.cpp
View.cpp
ViewContainer.cpp
WrapperView.cpp
:
be
;

View File

@ -0,0 +1,125 @@
/*
* Copyright 2007, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "StringView.h"
#include <math.h>
#include <View.h>
StringView::StringView(const char* string)
: View(),
fString(string),
fAlignment(B_ALIGN_LEFT),
fStringAscent(0),
fStringDescent(0),
fStringWidth(0),
fExplicitMinSize(B_SIZE_UNSET, B_SIZE_UNSET)
{
SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
fTextColor = (rgb_color){ 0, 0, 0, 255 };
}
void
StringView::SetString(const char* string)
{
fString = string;
_UpdateStringMetrics();
Invalidate();
InvalidateLayout();
}
void
StringView::SetAlignment(alignment align)
{
if (align != fAlignment) {
fAlignment = align;
Invalidate();
}
}
void
StringView::SetTextColor(rgb_color color)
{
fTextColor = color;
Invalidate();
}
BSize
StringView::MinSize()
{
BSize size(fExplicitMinSize);
if (!size.IsWidthSet())
size.width = fStringWidth - 1;
if (!size.IsHeightSet())
size.height = fStringAscent + fStringDescent - 1;
return size;
}
void
StringView::SetExplicitMinSize(BSize size)
{
fExplicitMinSize = size;
}
void
StringView::AddedToContainer()
{
_UpdateStringMetrics();
}
void
StringView::Draw(BView* container, BRect updateRect)
{
BSize size(Size());
int widthDiff = (int)size.width + 1 - (int)fStringWidth;
int heightDiff = (int)size.height + 1
- (int)(fStringAscent + (int)fStringDescent);
BPoint base;
// horizontal alignment
switch (fAlignment) {
case B_ALIGN_RIGHT:
base.x = widthDiff;
break;
case B_ALIGN_LEFT:
default:
base.x = 0;
break;
}
base.y = heightDiff / 2 + fStringAscent;
container->SetHighColor(fTextColor);
container->DrawString(fString.String(), base);
}
void
StringView::_UpdateStringMetrics()
{
BView* container = Container();
if (!container)
return;
BFont font;
container->GetFont(&font);
font_height fh;
font.GetHeight(&fh);
fStringAscent = ceilf(fh.ascent);
fStringDescent = ceilf(fh.descent);
fStringWidth = font.StringWidth(fString.String());
}

View File

@ -0,0 +1,44 @@
/*
* Copyright 2007, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef WIDGET_LAYOUT_TEST_STRING_VIEW_H
#define WIDGET_LAYOUT_TEST_STRING_VIEW_H
#include <String.h>
#include "View.h"
class StringView : public View {
public:
StringView(const char* string);
void SetString(const char* string);
void SetAlignment(alignment align);
void SetTextColor(rgb_color color);
virtual BSize MinSize();
void SetExplicitMinSize(BSize size);
virtual void AddedToContainer();
virtual void Draw(BView* container, BRect updateRect);
private:
void _UpdateStringMetrics();
private:
BString fString;
alignment fAlignment;
rgb_color fTextColor;
float fStringAscent;
float fStringDescent;
float fStringWidth;
BSize fExplicitMinSize;
};
#endif // WIDGET_LAYOUT_TEST_STRING_VIEW_H

View File

@ -0,0 +1,119 @@
/*
* Copyright 2007, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "TwoDimensionalSliderView.h"
#include <View.h>
TwoDimensionalSliderView::TwoDimensionalSliderView(BMessage* message,
BMessenger target)
: View(BRect(0, 0, 4, 4)),
BInvoker(message, target),
fMinLocation(0, 0),
fMaxLocation(0, 0),
fDragging(false)
{
SetViewColor((rgb_color){0, 120, 0, 255});
}
void
TwoDimensionalSliderView::SetLocationRange(BPoint minLocation,
BPoint maxLocation)
{
if (maxLocation.x < minLocation.x)
maxLocation.x = minLocation.x;
if (maxLocation.y < minLocation.y)
maxLocation.y = minLocation.y;
fMinLocation = minLocation;
fMaxLocation = maxLocation;
// force valid value
SetValue(Value());
}
BPoint
TwoDimensionalSliderView::MinLocation() const
{
return fMinLocation;
}
BPoint
TwoDimensionalSliderView::MaxLocation() const
{
return fMaxLocation;
}
BPoint
TwoDimensionalSliderView::Value() const
{
return Location() - fMinLocation;
}
void
TwoDimensionalSliderView::SetValue(BPoint value)
{
BPoint location = fMinLocation + value;
if (location.x < fMinLocation.x)
location.x = fMinLocation.x;
if (location.y < fMinLocation.y)
location.y = fMinLocation.y;
if (location.x > fMaxLocation.x)
location.x = fMaxLocation.x;
if (location.y > fMaxLocation.y)
location.y = fMaxLocation.y;
if (location != Location()) {
SetFrame(Frame().OffsetToCopy(location));
// send the message
if (Message()) {
BMessage message(*Message());
message.AddPoint("value", Value());
InvokeNotify(&message);
}
}
}
void
TwoDimensionalSliderView::MouseDown(BPoint where, uint32 buttons,
int32 modifiers)
{
if (fDragging)
return;
fOriginalLocation = Frame().LeftTop();
fOriginalPoint = ConvertToContainer(where);
fDragging = true;
}
void
TwoDimensionalSliderView::MouseUp(BPoint where, uint32 buttons, int32 modifiers)
{
if (!fDragging || (buttons & B_PRIMARY_MOUSE_BUTTON))
return;
fDragging = false;
}
void
TwoDimensionalSliderView::MouseMoved(BPoint where, uint32 buttons,
int32 modifiers)
{
if (!fDragging)
return;
BPoint moved = ConvertToContainer(where) - fOriginalPoint;
SetValue(fOriginalLocation - fMinLocation + moved);
}

View File

@ -0,0 +1,44 @@
/*
* Copyright 2007, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef WIDGET_LAYOUT_TEST_TWO_DIMENSIONAL_SLIDER_VIEW_H
#define WIDGET_LAYOUT_TEST_TWO_DIMENSIONAL_SLIDER_VIEW_H
#include <Invoker.h>
#include "View.h"
class TwoDimensionalSliderView : public View, public BInvoker {
public:
TwoDimensionalSliderView(
BMessage* message = NULL,
BMessenger target = BMessenger());
void SetLocationRange(BPoint minLocation,
BPoint maxLocation);
BPoint MinLocation() const;
BPoint MaxLocation() const;
BPoint Value() const;
void SetValue(BPoint value);
virtual void MouseDown(BPoint where, uint32 buttons,
int32 modifiers);
virtual void MouseUp(BPoint where, uint32 buttons,
int32 modifiers);
virtual void MouseMoved(BPoint where, uint32 buttons,
int32 modifiers);
private:
BPoint fMinLocation;
BPoint fMaxLocation;
bool fDragging;
BPoint fOriginalPoint;
BPoint fOriginalLocation;
};
#endif // WIDGET_LAYOUT_TEST_TWO_DIMENSIONAL_SLIDER_VIEW_H

View File

@ -0,0 +1,487 @@
/*
* Copyright 2007, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "View.h"
#include <stdio.h>
#include <Region.h>
#include <View.h>
View::View()
: fFrame(0, 0, 0, 0),
fContainer(NULL),
fParent(NULL),
fChildren(),
fViewColor(B_TRANSPARENT_32_BIT),
fLayoutValid(false)
{
}
View::View(BRect frame)
: fFrame(frame),
fContainer(NULL),
fParent(NULL),
fChildren(),
fViewColor(B_TRANSPARENT_32_BIT),
fLayoutValid(false)
{
}
View::~View()
{
// delete children
for (int32 i = CountChildren() - 1; i >= 0; i--)
delete RemoveChild(i);
}
void
View::SetFrame(BRect frame)
{
if (frame != fFrame && frame.IsValid()) {
BRect oldFrame(frame);
Invalidate();
fFrame = frame;
Invalidate();
FrameChanged(oldFrame, frame);
}
// relayout if necessary
if (!fLayoutValid) {
Layout();
fLayoutValid = true;
}
}
BRect
View::Frame() const
{
return fFrame;
}
BRect
View::Bounds() const
{
return BRect(fFrame).OffsetToCopy(B_ORIGIN);
}
void
View::SetLocation(BPoint location)
{
SetFrame(fFrame.OffsetToCopy(location));
}
BPoint
View::Location() const
{
return fFrame.LeftTop();
}
void
View::SetSize(BSize size)
{
BRect frame(fFrame);
frame.right = frame.left + size.width;
frame.bottom = frame.top + size.height;
SetFrame(frame);
}
BSize
View::Size() const
{
return Frame().Size();
}
BSize
View::MinSize()
{
return BSize(-1, -1);
}
BSize
View::MaxSize()
{
return BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED);
}
BSize
View::PreferredSize()
{
return MinSize();
}
BAlignment
View::Alignment()
{
return BAlignment(B_ALIGN_HORIZONTAL_CENTER, B_ALIGN_VERTICAL_CENTER);
}
BPoint
View::LocationInContainer() const
{
BPoint location = fFrame.LeftTop();
return (fParent ? fParent->LocationInContainer() + location : location);
}
BRect
View::FrameInContainer() const
{
BRect frame(fFrame);
return frame.OffsetToCopy(LocationInContainer());
}
BPoint
View::ConvertFromContainer(BPoint point) const
{
return point - LocationInContainer();
}
BRect
View::ConvertFromContainer(BRect rect) const
{
return rect.OffsetBySelf(-LocationInContainer());
}
BPoint
View::ConvertToContainer(BPoint point) const
{
return point + LocationInContainer();
}
BRect
View::ConvertToContainer(BRect rect) const
{
return rect.OffsetBySelf(LocationInContainer());
}
View*
View::Parent() const
{
return fParent;
}
BView*
View::Container() const
{
return fContainer;
}
bool
View::AddChild(View* child)
{
if (!child)
return false;
if (child->Parent() || child->Container()) {
fprintf(stderr, "View::AddChild(): view %p already has a parent "
"or is the container view\n", child);
return false;
}
if (!fChildren.AddItem(child))
return false;
child->_AddedToParent(this);
child->Invalidate();
InvalidateLayout();
return true;
}
bool
View::RemoveChild(View* child)
{
if (!child)
return false;
return RemoveChild(IndexOfChild(child));
}
View*
View::RemoveChild(int32 index)
{
if (index < 0 || index >= fChildren.CountItems())
return NULL;
View* child = ChildAt(index);
child->Invalidate();
child->_RemovingFromParent();
fChildren.RemoveItem(index);
InvalidateLayout();
return child;
}
int32
View::CountChildren() const
{
return fChildren.CountItems();
}
View*
View::ChildAt(int32 index) const
{
return (View*)fChildren.ItemAt(index);
}
View*
View::ChildAt(BPoint point) const
{
for (int32 i = 0; View* child = ChildAt(i); i++) {
if (child->Frame().Contains(point))
return child;
}
return NULL;
}
View*
View::AncestorAt(BPoint point, BPoint* localPoint) const
{
if (!Bounds().Contains(point))
return NULL;
View* view = const_cast<View*>(this);
// Iterate deeper down the hierarchy, until we reach a view that
// doesn't have a child at the location.
while (true) {
View* child = view->ChildAt(point);
if (!child) {
if (localPoint)
*localPoint = point;
return view;
}
view = child;
point -= view->Frame().LeftTop();
}
}
int32
View::IndexOfChild(View* child) const
{
return (child ? fChildren.IndexOf(child) : -1);
}
void
View::Invalidate(BRect rect)
{
if (fContainer) {
rect = rect & Bounds();
fContainer->Invalidate(rect.OffsetByCopy(LocationInContainer()));
}
}
void
View::Invalidate()
{
Invalidate(Bounds());
}
void
View::InvalidateLayout()
{
if (fLayoutValid) {
fLayoutValid = false;
if (fParent)
fParent->InvalidateLayout();
}
}
bool
View::IsLayoutValid() const
{
return fLayoutValid;
}
void
View::SetViewColor(rgb_color color)
{
fViewColor = color;
}
void
View::Draw(BView* container, BRect updateRect)
{
}
void
View::MouseDown(BPoint where, uint32 buttons, int32 modifiers)
{
}
void
View::MouseUp(BPoint where, uint32 buttons, int32 modifiers)
{
}
void
View::MouseMoved(BPoint where, uint32 buttons, int32 modifiers)
{
}
void
View::AddedToContainer()
{
}
void
View::RemovingFromContainer()
{
}
void
View::FrameChanged(BRect oldFrame, BRect newFrame)
{
}
void
View::Layout()
{
// simply trigger relayouting the children
for (int32 i = 0; View* child = ChildAt(i); i++)
child->SetFrame(child->Frame());
}
void
View::_AddedToParent(View* parent)
{
fParent = parent;
if (parent->Container()) {
Invalidate();
_AddedToContainer(parent->Container());
}
}
void
View::_RemovingFromParent()
{
if (fContainer)
_RemovingFromContainer();
fParent = NULL;
}
void
View::_AddedToContainer(BView* container)
{
fContainer = container;
AddedToContainer();
for (int32 i = 0; View* child = ChildAt(i); i++)
child->_AddedToContainer(fContainer);
}
void
View::_RemovingFromContainer()
{
for (int32 i = 0; View* child = ChildAt(i); i++)
child->_RemovingFromContainer();
RemovingFromContainer();
fContainer = NULL;
}
void
View::_Draw(BView* container, BRect updateRect)
{
// compute the clipping region
BRegion region(Bounds());
for (int32 i = 0; View* child = ChildAt(i); i++)
region.Exclude(child->Frame());
if (region.Frame().IsValid()) {
// set the clipping region
container->ConstrainClippingRegion(&region);
// draw the background, if it isn't transparent
if (fViewColor.alpha != 0) {
container->SetLowColor(fViewColor);
container->FillRect(updateRect, B_SOLID_LOW);
}
// draw this view
Draw(container, updateRect);
// revert the clipping region
region.Set(Bounds());
container->ConstrainClippingRegion(&region);
}
// draw the children
if (CountChildren() > 0) {
container->PushState();
for (int32 i = 0; View* child = ChildAt(i); i++) {
BRect childFrame = child->Frame();
BRect childUpdateRect = updateRect & childFrame;
if (childUpdateRect.IsValid()) {
// set origin
childUpdateRect.OffsetBy(-childFrame.LeftTop());
container->SetOrigin(childFrame.LeftTop());
// draw
child->_Draw(container, childUpdateRect);
}
}
container->PopState();
}
}

View File

@ -0,0 +1,101 @@
/*
* Copyright 2007, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef WIDGET_LAYOUT_TEST_VIEW_H
#define WIDGET_LAYOUT_TEST_VIEW_H
#include <Alignment.h>
#include <List.h>
#include <Rect.h>
class BView;
class View {
public:
View();
View(BRect frame);
virtual ~View();
virtual void SetFrame(BRect frame);
BRect Frame() const;
BRect Bounds() const;
void SetLocation(BPoint location);
BPoint Location() const;
void SetSize(BSize size);
BSize Size() const;
virtual BSize MinSize();
virtual BSize MaxSize();
virtual BSize PreferredSize();
virtual BAlignment Alignment();
BPoint LocationInContainer() const;
BRect FrameInContainer() const;
BPoint ConvertFromContainer(BPoint point) const;
BRect ConvertFromContainer(BRect rect) const;
BPoint ConvertToContainer(BPoint point) const;
BRect ConvertToContainer(BRect rect) const;
View* Parent() const;
BView* Container() const;
bool AddChild(View* child);
bool RemoveChild(View* child);
View* RemoveChild(int32 index);
int32 CountChildren() const;
View* ChildAt(int32 index) const;
View* ChildAt(BPoint point) const;
View* AncestorAt(BPoint point,
BPoint* localPoint = NULL) const;
int32 IndexOfChild(View* child) const;
void Invalidate(BRect rect);
void Invalidate();
virtual void InvalidateLayout();
bool IsLayoutValid() const;
void SetViewColor(rgb_color color);
virtual void Draw(BView* container, BRect updateRect);
virtual void MouseDown(BPoint where, uint32 buttons,
int32 modifiers);
virtual void MouseUp(BPoint where, uint32 buttons,
int32 modifiers);
virtual void MouseMoved(BPoint where, uint32 buttons,
int32 modifiers);
virtual void AddedToContainer();
virtual void RemovingFromContainer();
virtual void FrameChanged(BRect oldFrame, BRect newFrame);
virtual void Layout();
protected:
void _AddedToParent(View* parent);
void _RemovingFromParent();
void _AddedToContainer(BView* container);
void _RemovingFromContainer();
void _Draw(BView* container, BRect updateRect);
private:
BRect fFrame;
BView* fContainer;
View* fParent;
BList fChildren;
rgb_color fViewColor;
bool fLayoutValid;
};
#endif // WIDGET_LAYOUT_TEST_VIEW_H

View File

@ -0,0 +1,170 @@
/*
* Copyright 2007, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "ViewContainer.h"
#include <Message.h>
#include <Window.h>
// internal messages
enum {
MSG_LAYOUT_CONTAINER = 'layc',
};
ViewContainer::ViewContainer(BRect frame)
: BView(frame, "view container", B_FOLLOW_NONE, B_WILL_DRAW),
View(frame.OffsetToCopy(B_ORIGIN)),
fMouseFocus(NULL)
{
BView::SetViewColor(B_TRANSPARENT_32_BIT);
_AddedToContainer(this);
}
void
ViewContainer::MessageReceived(BMessage* message)
{
switch (message->what) {
case MSG_LAYOUT_CONTAINER:
View::Layout();
break;
default:
BView::MessageReceived(message);
break;
}
}
void
ViewContainer::AllAttached()
{
Window()->PostMessage(MSG_LAYOUT_CONTAINER, this);
}
void
ViewContainer::Draw(BRect updateRect)
{
View::_Draw(this, updateRect);
}
void
ViewContainer::MouseDown(BPoint where)
{
// get mouse buttons and modifiers
uint32 buttons;
int32 modifiers;
_GetButtonsAndModifiers(buttons, modifiers);
// get mouse focus
if (!fMouseFocus && (buttons & B_PRIMARY_MOUSE_BUTTON)) {
fMouseFocus = AncestorAt(where);
if (fMouseFocus)
SetMouseEventMask(B_POINTER_EVENTS);
}
// call hook
if (fMouseFocus) {
fMouseFocus->MouseDown(fMouseFocus->ConvertFromContainer(where),
buttons, modifiers);
}
}
void
ViewContainer::MouseUp(BPoint where)
{
if (!fMouseFocus)
return;
// get mouse buttons and modifiers
uint32 buttons;
int32 modifiers;
_GetButtonsAndModifiers(buttons, modifiers);
// call hook
if (fMouseFocus) {
fMouseFocus->MouseUp(fMouseFocus->ConvertFromContainer(where),
buttons, modifiers);
}
// unset the mouse focus when the primary button has been released
if (!(buttons & B_PRIMARY_MOUSE_BUTTON))
fMouseFocus = NULL;
}
void
ViewContainer::MouseMoved(BPoint where, uint32 code, const BMessage* message)
{
if (!fMouseFocus)
return;
// get mouse buttons and modifiers
uint32 buttons;
int32 modifiers;
_GetButtonsAndModifiers(buttons, modifiers);
// call hook
if (fMouseFocus) {
fMouseFocus->MouseMoved(fMouseFocus->ConvertFromContainer(where),
buttons, modifiers);
}
}
void
ViewContainer::InvalidateLayout()
{
if (View::IsLayoutValid()) {
View::InvalidateLayout();
// trigger asynchronous re-layout
if (Window())
Window()->PostMessage(MSG_LAYOUT_CONTAINER, this);
}
}
void
ViewContainer::Draw(BView* container, BRect updateRect)
{
}
void
ViewContainer::MouseDown(BPoint where, uint32 buttons, int32 modifiers)
{
}
void
ViewContainer::MouseUp(BPoint where, uint32 buttons, int32 modifiers)
{
}
void
ViewContainer::MouseMoved(BPoint where, uint32 buttons, int32 modifiers)
{
}
void
ViewContainer::_GetButtonsAndModifiers(uint32& buttons, int32& modifiers)
{
buttons = 0;
modifiers = 0;
if (BMessage* message = Window()->CurrentMessage()) {
if (message->FindInt32("buttons", (int32*)&buttons) != B_OK)
buttons = 0;
if (message->FindInt32("modifiers", modifiers) != B_OK)
modifiers = 0;
}
}

View File

@ -0,0 +1,52 @@
/*
* Copyright 2007, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef WIDGET_LAYOUT_TEST_VIEW_CONTAINER_H
#define WIDGET_LAYOUT_TEST_VIEW_CONTAINER_H
#include <View.h>
#include "View.h"
class ViewContainer : public BView, public View {
public:
ViewContainer(BRect frame);
// BView hooks
virtual void MessageReceived(BMessage* message);
virtual void AllAttached();
virtual void Draw(BRect updateRect);
virtual void MouseDown(BPoint where);
virtual void MouseUp(BPoint where);
virtual void MouseMoved(BPoint where, uint32 code,
const BMessage* message);
// View hooks
virtual void InvalidateLayout();
virtual void Draw(BView* container, BRect updateRect);
virtual void MouseDown(BPoint where, uint32 buttons,
int32 modifiers);
virtual void MouseUp(BPoint where, uint32 buttons,
int32 modifiers);
virtual void MouseMoved(BPoint where, uint32 buttons,
int32 modifiers);
private:
void _GetButtonsAndModifiers(uint32& buttons,
int32& modifiers);
private:
View* fMouseFocus;
};
#endif // WIDGET_LAYOUT_TEST_VIEW_CONTAINER_H

View File

@ -0,0 +1,108 @@
/*
* Copyright 2007, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "WrapperView.h"
#include <LayoutUtils.h>
#include <View.h>
WrapperView::WrapperView(BView* view)
: View(),
fView(view),
fInsets(1, 1, 1, 1)
{
SetViewColor((rgb_color){255, 0, 0, 255});
}
BView*
WrapperView::GetView() const
{
return fView;
}
BSize
WrapperView::MinSize()
{
return _FromViewSize(fView->MinSize());
}
BSize
WrapperView::MaxSize()
{
return _FromViewSize(fView->MaxSize());
}
BSize
WrapperView::PreferredSize()
{
return _FromViewSize(fView->PreferredSize());
}
void
WrapperView::AddedToContainer()
{
_UpdateViewFrame();
Container()->AddChild(fView);
}
void
WrapperView::RemovingFromContainer()
{
Container()->RemoveChild(fView);
}
void
WrapperView::FrameChanged(BRect oldFrame, BRect newFrame)
{
_UpdateViewFrame();
}
void
WrapperView::_UpdateViewFrame()
{
BRect frame(_ViewFrameInContainer());
fView->MoveTo(frame.LeftTop());
fView->ResizeTo(frame.Width(), frame.Height());
}
BRect
WrapperView::_ViewFrame() const
{
BRect viewFrame(Bounds());
viewFrame.left += fInsets.left;
viewFrame.top += fInsets.top;
viewFrame.right -= fInsets.right;
viewFrame.bottom -= fInsets.bottom;
return viewFrame;
}
BRect
WrapperView::_ViewFrameInContainer() const
{
return ConvertToContainer(_ViewFrame());
}
BSize
WrapperView::_FromViewSize(BSize size) const
{
float horizontalInsets = fInsets.left + fInsets.right - 1;
float verticalInsets = fInsets.top + fInsets.bottom - 1;
return BSize(BLayoutUtils::AddDistances(size.width, horizontalInsets),
BLayoutUtils::AddDistances(size.height, verticalInsets));
}

View File

@ -0,0 +1,43 @@
/*
* Copyright 2007, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef WIDGET_LAYOUT_TEST_WRAPPER_VIEW_H
#define WIDGET_LAYOUT_TEST_WRAPPER_VIEW_H
#include "View.h"
class BView;
class WrapperView : public View {
public:
WrapperView(BView* view);
BView* GetView() const;
virtual BSize MinSize();
virtual BSize MaxSize();
virtual BSize PreferredSize();
virtual void AddedToContainer();
virtual void RemovingFromContainer();
virtual void FrameChanged(BRect oldFrame, BRect newFrame);
private:
void _UpdateViewFrame();
BRect _ViewFrame() const;
BRect _ViewFrameInContainer() const;
BSize _FromViewSize(BSize size) const;
private:
BView* fView;
BRect fInsets;
};
#endif // WIDGET_LAYOUT_TEST_WRAPPER_VIEW_H