From a5b50d1fadc9ac0a86bae715ba325818d196ff30 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Tue, 15 May 2007 17:54:08 +0000 Subject: [PATCH] Refactoring. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21145 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../layout/widget_layout_test/CheckBox.cpp | 122 ++ .../layout/widget_layout_test/CheckBox.h | 44 + .../layout/widget_layout_test/GroupView.cpp | 410 +++++ .../layout/widget_layout_test/GroupView.h | 99 ++ .../layout/widget_layout_test/Jamfile | 8 + .../layout/widget_layout_test/StringView.cpp | 125 ++ .../layout/widget_layout_test/StringView.h | 44 + .../TwoDimensionalSliderView.cpp | 119 ++ .../TwoDimensionalSliderView.h | 44 + .../layout/widget_layout_test/View.cpp | 487 ++++++ .../layout/widget_layout_test/View.h | 101 ++ .../widget_layout_test/ViewContainer.cpp | 170 ++ .../layout/widget_layout_test/ViewContainer.h | 52 + .../widget_layout_test/WidgetLayoutTest.cpp | 1361 +---------------- .../layout/widget_layout_test/WrapperView.cpp | 108 ++ .../layout/widget_layout_test/WrapperView.h | 43 + 16 files changed, 1985 insertions(+), 1352 deletions(-) create mode 100644 src/tests/kits/interface/layout/widget_layout_test/CheckBox.cpp create mode 100644 src/tests/kits/interface/layout/widget_layout_test/CheckBox.h create mode 100644 src/tests/kits/interface/layout/widget_layout_test/GroupView.cpp create mode 100644 src/tests/kits/interface/layout/widget_layout_test/GroupView.h create mode 100644 src/tests/kits/interface/layout/widget_layout_test/StringView.cpp create mode 100644 src/tests/kits/interface/layout/widget_layout_test/StringView.h create mode 100644 src/tests/kits/interface/layout/widget_layout_test/TwoDimensionalSliderView.cpp create mode 100644 src/tests/kits/interface/layout/widget_layout_test/TwoDimensionalSliderView.h create mode 100644 src/tests/kits/interface/layout/widget_layout_test/View.cpp create mode 100644 src/tests/kits/interface/layout/widget_layout_test/View.h create mode 100644 src/tests/kits/interface/layout/widget_layout_test/ViewContainer.cpp create mode 100644 src/tests/kits/interface/layout/widget_layout_test/ViewContainer.h create mode 100644 src/tests/kits/interface/layout/widget_layout_test/WrapperView.cpp create mode 100644 src/tests/kits/interface/layout/widget_layout_test/WrapperView.h diff --git a/src/tests/kits/interface/layout/widget_layout_test/CheckBox.cpp b/src/tests/kits/interface/layout/widget_layout_test/CheckBox.cpp new file mode 100644 index 0000000000..24833f7982 --- /dev/null +++ b/src/tests/kits/interface/layout/widget_layout_test/CheckBox.cpp @@ -0,0 +1,122 @@ +/* + * Copyright 2007, Ingo Weinhold . + * All rights reserved. Distributed under the terms of the MIT License. + */ + +#include "CheckBox.h" + +#include + + +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(); + } +} diff --git a/src/tests/kits/interface/layout/widget_layout_test/CheckBox.h b/src/tests/kits/interface/layout/widget_layout_test/CheckBox.h new file mode 100644 index 0000000000..1bd9894324 --- /dev/null +++ b/src/tests/kits/interface/layout/widget_layout_test/CheckBox.h @@ -0,0 +1,44 @@ +/* + * Copyright 2007, Ingo Weinhold . + * 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 + +#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 diff --git a/src/tests/kits/interface/layout/widget_layout_test/GroupView.cpp b/src/tests/kits/interface/layout/widget_layout_test/GroupView.cpp new file mode 100644 index 0000000000..4a9767fec8 --- /dev/null +++ b/src/tests/kits/interface/layout/widget_layout_test/GroupView.cpp @@ -0,0 +1,410 @@ +/* + * Copyright 2007, Ingo Weinhold . + * All rights reserved. Distributed under the terms of the MIT License. + */ + +#include "GroupView.h" + +#include + + +// #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) +{ +} diff --git a/src/tests/kits/interface/layout/widget_layout_test/GroupView.h b/src/tests/kits/interface/layout/widget_layout_test/GroupView.h new file mode 100644 index 0000000000..09a2aa3a01 --- /dev/null +++ b/src/tests/kits/interface/layout/widget_layout_test/GroupView.h @@ -0,0 +1,99 @@ +/* + * Copyright 2007, Ingo Weinhold . + * 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 diff --git a/src/tests/kits/interface/layout/widget_layout_test/Jamfile b/src/tests/kits/interface/layout/widget_layout_test/Jamfile index 0cf2a5860e..30835bd4b1 100644 --- a/src/tests/kits/interface/layout/widget_layout_test/Jamfile +++ b/src/tests/kits/interface/layout/widget_layout_test/Jamfile @@ -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 ; diff --git a/src/tests/kits/interface/layout/widget_layout_test/StringView.cpp b/src/tests/kits/interface/layout/widget_layout_test/StringView.cpp new file mode 100644 index 0000000000..2f3db7985e --- /dev/null +++ b/src/tests/kits/interface/layout/widget_layout_test/StringView.cpp @@ -0,0 +1,125 @@ +/* + * Copyright 2007, Ingo Weinhold . + * All rights reserved. Distributed under the terms of the MIT License. + */ + +#include "StringView.h" + +#include + +#include + + +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()); +} diff --git a/src/tests/kits/interface/layout/widget_layout_test/StringView.h b/src/tests/kits/interface/layout/widget_layout_test/StringView.h new file mode 100644 index 0000000000..4c931dfb98 --- /dev/null +++ b/src/tests/kits/interface/layout/widget_layout_test/StringView.h @@ -0,0 +1,44 @@ +/* + * Copyright 2007, Ingo Weinhold . + * 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 + +#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 diff --git a/src/tests/kits/interface/layout/widget_layout_test/TwoDimensionalSliderView.cpp b/src/tests/kits/interface/layout/widget_layout_test/TwoDimensionalSliderView.cpp new file mode 100644 index 0000000000..12e720b5c1 --- /dev/null +++ b/src/tests/kits/interface/layout/widget_layout_test/TwoDimensionalSliderView.cpp @@ -0,0 +1,119 @@ +/* + * Copyright 2007, Ingo Weinhold . + * All rights reserved. Distributed under the terms of the MIT License. + */ + +#include "TwoDimensionalSliderView.h" + +#include + + +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); +} diff --git a/src/tests/kits/interface/layout/widget_layout_test/TwoDimensionalSliderView.h b/src/tests/kits/interface/layout/widget_layout_test/TwoDimensionalSliderView.h new file mode 100644 index 0000000000..9e58efc6d2 --- /dev/null +++ b/src/tests/kits/interface/layout/widget_layout_test/TwoDimensionalSliderView.h @@ -0,0 +1,44 @@ +/* + * Copyright 2007, Ingo Weinhold . + * 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 + +#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 diff --git a/src/tests/kits/interface/layout/widget_layout_test/View.cpp b/src/tests/kits/interface/layout/widget_layout_test/View.cpp new file mode 100644 index 0000000000..9d522cf448 --- /dev/null +++ b/src/tests/kits/interface/layout/widget_layout_test/View.cpp @@ -0,0 +1,487 @@ +/* + * Copyright 2007, Ingo Weinhold . + * All rights reserved. Distributed under the terms of the MIT License. + */ + +#include "View.h" + +#include + +#include +#include + + +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(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(®ion); + + // 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(®ion); + } + + // 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(); + } +} diff --git a/src/tests/kits/interface/layout/widget_layout_test/View.h b/src/tests/kits/interface/layout/widget_layout_test/View.h new file mode 100644 index 0000000000..0096aea77a --- /dev/null +++ b/src/tests/kits/interface/layout/widget_layout_test/View.h @@ -0,0 +1,101 @@ +/* + * Copyright 2007, Ingo Weinhold . + * All rights reserved. Distributed under the terms of the MIT License. + */ +#ifndef WIDGET_LAYOUT_TEST_VIEW_H +#define WIDGET_LAYOUT_TEST_VIEW_H + + +#include +#include +#include + + +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 diff --git a/src/tests/kits/interface/layout/widget_layout_test/ViewContainer.cpp b/src/tests/kits/interface/layout/widget_layout_test/ViewContainer.cpp new file mode 100644 index 0000000000..67d8508724 --- /dev/null +++ b/src/tests/kits/interface/layout/widget_layout_test/ViewContainer.cpp @@ -0,0 +1,170 @@ +/* + * Copyright 2007, Ingo Weinhold . + * All rights reserved. Distributed under the terms of the MIT License. + */ + +#include "ViewContainer.h" + +#include +#include + + +// 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; + } +} diff --git a/src/tests/kits/interface/layout/widget_layout_test/ViewContainer.h b/src/tests/kits/interface/layout/widget_layout_test/ViewContainer.h new file mode 100644 index 0000000000..11072843dd --- /dev/null +++ b/src/tests/kits/interface/layout/widget_layout_test/ViewContainer.h @@ -0,0 +1,52 @@ +/* + * Copyright 2007, Ingo Weinhold . + * 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 + +#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 diff --git a/src/tests/kits/interface/layout/widget_layout_test/WidgetLayoutTest.cpp b/src/tests/kits/interface/layout/widget_layout_test/WidgetLayoutTest.cpp index e600355272..c567d1f51a 100644 --- a/src/tests/kits/interface/layout/widget_layout_test/WidgetLayoutTest.cpp +++ b/src/tests/kits/interface/layout/widget_layout_test/WidgetLayoutTest.cpp @@ -3,30 +3,29 @@ * All rights reserved. Distributed under the terms of the MIT License. */ -#include #include #include #include -#include -#include -#include -#include -#include -#include #include +#include "CheckBox.h" +#include "GroupView.h" +#include "StringView.h" +#include "TwoDimensionalSliderView.h" +#include "View.h" +#include "ViewContainer.h" +#include "WrapperView.h" + // internal messages enum { - MSG_LAYOUT_CONTAINER = 'layc', MSG_2D_SLIDER_VALUE_CHANGED = '2dsv', MSG_UNLIMITED_MAX_SIZE_CHANGED = 'usch', }; -// missing operators in BPoint - +// helpful operator BPoint operator+(const BPoint& p, const BSize& size) { @@ -34,1348 +33,6 @@ operator+(const BPoint& p, const BSize& size) } -// View -class View { -public: - View() - : fFrame(0, 0, 0, 0), - fContainer(NULL), - fParent(NULL), - fChildren(), - fViewColor(B_TRANSPARENT_32_BIT), - fLayoutValid(false) - { - } - - View(BRect frame) - : fFrame(frame), - fContainer(NULL), - fParent(NULL), - fChildren(), - fViewColor(B_TRANSPARENT_32_BIT), - fLayoutValid(false) - { - } - - virtual ~View() - { - // delete children - for (int32 i = CountChildren() - 1; i >= 0; i--) - delete RemoveChild(i); - } - - virtual void 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 Frame() const - { - return fFrame; - } - - BRect Bounds() const - { - return BRect(fFrame).OffsetToCopy(B_ORIGIN); - } - - void SetLocation(BPoint location) - { - SetFrame(fFrame.OffsetToCopy(location)); - } - - BPoint Location() const - { - return fFrame.LeftTop(); - } - - void SetSize(BSize size) - { - BRect frame(fFrame); - frame.right = frame.left + size.width; - frame.bottom = frame.top + size.height; - SetFrame(frame); - } - - BSize Size() const - { - return Frame().Size(); - } - - virtual BSize MinSize() - { - return BSize(-1, -1); - } - - virtual BSize MaxSize() - { - return BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED); - } - - virtual BSize PreferredSize() - { - return MinSize(); - } - - virtual BAlignment Alignment() - { - return BAlignment(B_ALIGN_HORIZONTAL_CENTER, B_ALIGN_VERTICAL_CENTER); - } - - BPoint LocationInContainer() const - { - BPoint location = fFrame.LeftTop(); - return (fParent ? fParent->LocationInContainer() + location : location); - } - - BRect FrameInContainer() const - { - BRect frame(fFrame); - return frame.OffsetToCopy(LocationInContainer()); - } - - BPoint ConvertFromContainer(BPoint point) const - { - return point - LocationInContainer(); - } - - BRect ConvertFromContainer(BRect rect) const - { - return rect.OffsetBySelf(-LocationInContainer()); - } - - BPoint ConvertToContainer(BPoint point) const - { - return point + LocationInContainer(); - } - - BRect ConvertToContainer(BRect rect) const - { - return rect.OffsetBySelf(LocationInContainer()); - } - - View* Parent() const - { - return fParent; - } - - BView* Container() const - { - return fContainer; - } - - bool 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 RemoveChild(View* child) - { - if (!child) - return false; - - return RemoveChild(IndexOfChild(child)); - } - - 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 CountChildren() const - { - return fChildren.CountItems(); - } - - View* ChildAt(int32 index) const - { - return (View*)fChildren.ItemAt(index); - } - - View* ChildAt(BPoint point) const - { - for (int32 i = 0; View* child = ChildAt(i); i++) { - if (child->Frame().Contains(point)) - return child; - } - - return NULL; - } - - View* AncestorAt(BPoint point, BPoint* localPoint = NULL) const - { - if (!Bounds().Contains(point)) - return NULL; - - View* view = const_cast(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 IndexOfChild(View* child) const - { - return (child ? fChildren.IndexOf(child) : -1); - } - - void Invalidate(BRect rect) - { - if (fContainer) { - rect = rect & Bounds(); - fContainer->Invalidate(rect.OffsetByCopy(LocationInContainer())); - } - } - - void Invalidate() - { - Invalidate(Bounds()); - } - - virtual void InvalidateLayout() - { - if (fLayoutValid) { - fLayoutValid = false; - if (fParent) - fParent->InvalidateLayout(); - } - } - - bool IsLayoutValid() const - { - return fLayoutValid; - } - - void SetViewColor(rgb_color color) - { - fViewColor = 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() - { - // simply trigger relayouting the children - for (int32 i = 0; View* child = ChildAt(i); i++) - child->SetFrame(child->Frame()); - } - -protected: - virtual void _AddedToParent(View* parent) - { - fParent = parent; - - if (parent->Container()) { - Invalidate(); - _AddedToContainer(parent->Container()); - } - } - - virtual void _RemovingFromParent() - { - if (fContainer) - _RemovingFromContainer(); - - fParent = NULL; - } - - virtual void _AddedToContainer(BView* container) - { - fContainer = container; - - AddedToContainer(); - - for (int32 i = 0; View* child = ChildAt(i); i++) - child->_AddedToContainer(fContainer); - } - - virtual void _RemovingFromContainer() - { - for (int32 i = 0; View* child = ChildAt(i); i++) - child->_RemovingFromContainer(); - - RemovingFromContainer(); - - fContainer = NULL; - } - - void _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(®ion); - - // 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(®ion); - } - - // 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(); - } - } - -private: - BRect fFrame; - BView* fContainer; - View* fParent; - BList fChildren; - rgb_color fViewColor; - bool fLayoutValid; -}; - - -// ViewContainer -class ViewContainer : public BView, public View { -public: - 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); - } - - virtual void InvalidateLayout() - { - if (View::IsLayoutValid()) { - View::InvalidateLayout(); - - // trigger asynchronous re-layout - if (Window()) - Window()->PostMessage(MSG_LAYOUT_CONTAINER, this); - } - } - - virtual void MessageReceived(BMessage* message) - { - switch (message->what) { - case MSG_LAYOUT_CONTAINER: - View::Layout(); - break; - default: - BView::MessageReceived(message); - break; - } - } - - virtual void AllAttached() - { - Window()->PostMessage(MSG_LAYOUT_CONTAINER, this); - } - - virtual void Draw(BRect updateRect) - { - View::_Draw(this, updateRect); - } - - virtual void 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); - } - } - - virtual void 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; - } - - virtual void 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); - } - } - - 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) - { - 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; - } - } - -private: - View* fMouseFocus; -}; - - -// TwoDimensionalSliderView -class TwoDimensionalSliderView : public View, public BInvoker { -public: - TwoDimensionalSliderView(BMessage* message = NULL, - BMessenger target = BMessenger()) - : 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 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 MinLocation() const - { - return fMinLocation; - } - - BPoint MaxLocation() const - { - return fMaxLocation; - } - - BPoint Value() const - { - return Location() - fMinLocation; - } - - void 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); - } - } - } - - virtual void MouseDown(BPoint where, uint32 buttons, int32 modifiers) - { - if (fDragging) - return; - - fOriginalLocation = Frame().LeftTop(); - fOriginalPoint = ConvertToContainer(where); - fDragging = true; - } - - virtual void MouseUp(BPoint where, uint32 buttons, int32 modifiers) - { - if (!fDragging || (buttons & B_PRIMARY_MOUSE_BUTTON)) - return; - - fDragging = false; - } - - virtual void MouseMoved(BPoint where, uint32 buttons, int32 modifiers) - { - if (!fDragging) - return; - - BPoint moved = ConvertToContainer(where) - fOriginalPoint; - SetValue(fOriginalLocation - fMinLocation + moved); - } - -private: - BPoint fMinLocation; - BPoint fMaxLocation; - bool fDragging; - BPoint fOriginalPoint; - BPoint fOriginalLocation; -}; - - -// WrapperView -class WrapperView : public View { -public: - WrapperView(BView* view) - : View(), - fView(view), - fInsets(1, 1, 1, 1) - { - SetViewColor((rgb_color){255, 0, 0, 255}); - } - - BView* GetView() const - { - return fView; - } - - virtual BSize MinSize() - { - return _FromViewSize(fView->MinSize()); - } - - virtual BSize MaxSize() - { - return _FromViewSize(fView->MaxSize()); - } - - virtual BSize PreferredSize() - { - return _FromViewSize(fView->PreferredSize()); - } - - virtual void AddedToContainer() - { - _UpdateViewFrame(); - - Container()->AddChild(fView); - } - - virtual void RemovingFromContainer() - { - Container()->RemoveChild(fView); - } - - virtual void FrameChanged(BRect oldFrame, BRect newFrame) - { - _UpdateViewFrame(); - } - -private: - void _UpdateViewFrame() - { - BRect frame(_ViewFrameInContainer()); - fView->MoveTo(frame.LeftTop()); - fView->ResizeTo(frame.Width(), frame.Height()); - } - - BRect _ViewFrame() const - { - BRect viewFrame(Bounds()); - viewFrame.left += fInsets.left; - viewFrame.top += fInsets.top; - viewFrame.right -= fInsets.right; - viewFrame.bottom -= fInsets.bottom; - - return viewFrame; - } - - BRect _ViewFrameInContainer() const - { - return ConvertToContainer(_ViewFrame()); - } - - BSize _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)); - } - -private: - BView* fView; - BRect fInsets; -}; - - -// StringView -class StringView : public View { -public: - 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 SetString(const char* string) - { - fString = string; - - _UpdateStringMetrics(); - Invalidate(); - InvalidateLayout(); - } - - void SetAlignment(alignment align) - { - if (align != fAlignment) { - fAlignment = align; - Invalidate(); - } - } - - void SetTextColor(rgb_color color) - { - fTextColor = color; - Invalidate(); - } - - virtual BSize MinSize() - { - BSize size(fExplicitMinSize); - if (!size.IsWidthSet()) - size.width = fStringWidth - 1; - if (!size.IsHeightSet()) - size.height = fStringAscent + fStringDescent - 1; - return size; - } - - void SetExplicitMinSize(BSize size) - { - fExplicitMinSize = size; - } - - virtual void AddedToContainer() - { - _UpdateStringMetrics(); - } - - virtual void 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); - } - -private: - void _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()); - } - -private: - BString fString; - alignment fAlignment; - rgb_color fTextColor; - float fStringAscent; - float fStringDescent; - float fStringWidth; - BSize fExplicitMinSize; -}; - - -// CheckBox -class CheckBox : public View, public BInvoker { -public: - CheckBox(BMessage* message = NULL, BMessenger target = BMessenger()) - : View(BRect(0, 0, 12, 12)), - BInvoker(message, target), - fSelected(false), - fPressed(false) - { - SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); - } - - void SetSelected(bool selected) - { - if (selected != fSelected) { - fSelected = selected; - Invalidate(); - - // send the message - if (Message()) { - BMessage message(*Message()); - message.AddBool("selected", IsSelected()); - InvokeNotify(&message); - } - } - } - - bool IsSelected() const - { - return fSelected; - } - - virtual BSize MinSize() - { - return BSize(12, 12); - } - - virtual BSize MaxSize() - { - return MinSize(); - } - - virtual void 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()); - } - } - - virtual void MouseDown(BPoint where, uint32 buttons, int32 modifiers) - { - if (fPressed) - return; - - fPressed = true; - fPressedSelected = fSelected; - _PressedUpdate(where); - } - - virtual void MouseUp(BPoint where, uint32 buttons, int32 modifiers) - { - if (!fPressed || (buttons & B_PRIMARY_MOUSE_BUTTON)) - return; - - _PressedUpdate(where); - fPressed = false; - SetSelected(fPressedSelected); - Invalidate(); - } - - virtual void MouseMoved(BPoint where, uint32 buttons, int32 modifiers) - { - if (!fPressed) - return; - - _PressedUpdate(where); - } - -private: - void _PressedUpdate(BPoint where) - { - bool pressedSelected = Bounds().Contains(where) ^ fSelected; - if (pressedSelected != fPressedSelected) { - fPressedSelected = pressedSelected; - Invalidate(); - } - } - -private: - bool fSelected; - bool fPressed; - bool fPressedSelected; -}; - - -// GroupView -class GroupView : public View { -public: - GroupView(enum orientation orientation, int32 lineCount = 1) - : 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; - } - - virtual ~GroupView() - { - delete fColumnInfos; - delete fRowInfos; - } - - void SetSpacing(float horizontal, float vertical) - { - if (horizontal != fColumnSpacing || vertical != fRowSpacing) { - fColumnSpacing = horizontal; - fRowSpacing = vertical; - - InvalidateLayout(); - } - } - - void SetInsets(float left, float top, float right, float bottom) - { - BRect newInsets(left, top, right, bottom); - if (newInsets != fInsets) { - fInsets = newInsets; - InvalidateLayout(); - } - } - - virtual BSize MinSize() - { - _ValidateMinMax(); - return _AddInsetsAndSpacing(BSize(fMinWidth - 1, fMinHeight - 1)); - } - - virtual BSize MaxSize() - { - _ValidateMinMax(); - return _AddInsetsAndSpacing(BSize(fMaxWidth - 1, fMaxHeight - 1)); - } - - virtual BSize PreferredSize() - { - _ValidateMinMax(); - return _AddInsetsAndSpacing(BSize(fPreferredWidth - 1, - fPreferredHeight - 1)); - } - - virtual BAlignment Alignment() - { - return BAlignment(B_ALIGN_USE_FULL_WIDTH, B_ALIGN_USE_FULL_HEIGHT); - } - - - virtual void 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; - } - } - -private: - struct 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; - } - }; - -private: - void _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 _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; - } - } - } - - virtual BSize _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; - } - - virtual BSize _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 _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 _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* _ChildAt(int32 column, int32 row) const - { - if (fOrientation == B_HORIZONTAL) - return ChildAt(column * fLineCount + row); - else - return ChildAt(row * fLineCount + column); - } - -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() - : View() - { - SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); - } -}; - - -// Strut -class Strut : public View { -public: - 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)); - } - - virtual BSize MinSize() - { - return BLayoutUtils::ComposeSize(fSize, BSize(-1, -1)); - } - - virtual BSize MaxSize() - { - return BLayoutUtils::ComposeSize(fSize, - BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED)); - } - -private: - BSize fSize; -}; - - -// HStrut -class HStrut : public Strut { -public: - HStrut(float width) - : Strut(width, -1) - { - } -}; - - -// VStrut -class VStrut : public Strut { -public: - VStrut(float height) - : Strut(-1, height) - { - } -}; - - // TestWindow class TestWindow : public BWindow { public: diff --git a/src/tests/kits/interface/layout/widget_layout_test/WrapperView.cpp b/src/tests/kits/interface/layout/widget_layout_test/WrapperView.cpp new file mode 100644 index 0000000000..57f65646cb --- /dev/null +++ b/src/tests/kits/interface/layout/widget_layout_test/WrapperView.cpp @@ -0,0 +1,108 @@ +/* + * Copyright 2007, Ingo Weinhold . + * All rights reserved. Distributed under the terms of the MIT License. + */ + +#include "WrapperView.h" + +#include +#include + + +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)); +} diff --git a/src/tests/kits/interface/layout/widget_layout_test/WrapperView.h b/src/tests/kits/interface/layout/widget_layout_test/WrapperView.h new file mode 100644 index 0000000000..ecd5308ef5 --- /dev/null +++ b/src/tests/kits/interface/layout/widget_layout_test/WrapperView.h @@ -0,0 +1,43 @@ +/* + * Copyright 2007, Ingo Weinhold . + * 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