* Copyright 2006-2010, Ingo Weinhold <ingo_weinhold@gmx.de>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include <TwoDimensionalLayout.h>
#include <stdio.h>
#include <ControlLook.h>
#include <LayoutContext.h>
#include <LayoutItem.h>
#include <LayoutUtils.h>
#include <List.h>
#include <Message.h>
#include <View.h>
#include <Referenceable.h>
#include "CollapsingLayouter.h"
class BTwoDimensionalLayout::CompoundLayouter : public BReferenceable {
public:
CompoundLayouter(orientation orientation);
virtual ~CompoundLayouter();
orientation Orientation();
virtual Layouter* GetLayouter(bool minMax);
LayoutInfo* GetLayoutInfo();
void AddLocalLayouter(LocalLayouter* localLayouter);
void RemoveLocalLayouter(
LocalLayouter* localLayouter);
status_t AddAlignedLayoutsToArchive(BArchiver* archiver,
LocalLayouter* requestedBy);
void AbsorbCompoundLayouter(CompoundLayouter* other);
virtual void InvalidateLayout();
bool IsMinMaxValid();
void ValidateMinMax();
void Layout(float size, LocalLayouter* localLayouter,
BLayoutContext* context);
protected:
virtual void DoLayout(float size,
LocalLayouter* localLayouter,
BLayoutContext* context);
Layouter* fLayouter;
LayoutInfo* fLayoutInfo;
orientation fOrientation;
BList fLocalLayouters;
BLayoutContext* fLayoutContext;
float fLastLayoutSize;
void _PrepareItems();
int32 _CountElements();
bool _HasMultiElementItems();
void _AddConstraints(Layouter* layouter);
float _Spacing();
};
class BTwoDimensionalLayout::VerticalCompoundLayouter
: public CompoundLayouter, private BLayoutContextListener {
public:
VerticalCompoundLayouter();
virtual Layouter* GetLayouter(bool minMax);
virtual void InvalidateLayout();
void InvalidateHeightForWidth();
void InternalGetHeightForWidth(
LocalLayouter* localLayouter,
BLayoutContext* context,
bool realLayout, float* minHeight,
float* maxHeight, float* preferredHeight);
protected:
virtual void DoLayout(float size,
LocalLayouter* localLayouter,
BLayoutContext* context);
private:
Layouter* fHeightForWidthLayouter;
float fCachedMinHeightForWidth;
float fCachedMaxHeightForWidth;
float fCachedPreferredHeightForWidth;
BLayoutContext* fHeightForWidthLayoutContext;
bool _HasHeightForWidth();
bool _SetHeightForWidthLayoutContext(
BLayoutContext* context);
virtual void LayoutContextLeft(BLayoutContext* context);
};
class BTwoDimensionalLayout::LocalLayouter : private BLayoutContextListener {
public:
LocalLayouter(BTwoDimensionalLayout* layout);
~LocalLayouter();
BSize MinSize();
BSize MaxSize();
BSize PreferredSize();
void InvalidateLayout();
void Layout(BSize size);
BRect ItemFrame(Dimensions itemDimensions);
void ValidateMinMax();
void DoHorizontalLayout(float width);
void InternalGetHeightForWidth(float width,
float* minHeight, float* maxHeight,
float* preferredHeight);
void AlignWith(LocalLayouter* other,
orientation orientation);
status_t AddAlignedLayoutsToArchive(BArchiver* archiver);
status_t AddOwnerToArchive(BArchiver* archiver,
CompoundLayouter* requestedBy,
bool& _wasAvailable);
status_t AlignLayoutsFromArchive(BUnarchiver* unarchiver,
orientation posture);
void PrepareItems(
CompoundLayouter* compoundLayouter);
int32 CountElements(
CompoundLayouter* compoundLayouter);
bool HasMultiElementItems(
CompoundLayouter* compoundLayouter);
void AddConstraints(
CompoundLayouter* compoundLayouter,
Layouter* layouter);
float Spacing(CompoundLayouter* compoundLayouter);
bool HasHeightForWidth();
bool AddHeightForWidthConstraints(
VerticalCompoundLayouter* compoundLayouter,
Layouter* layouter,
BLayoutContext* context);
void SetHeightForWidthConstraintsAdded(bool added);
void SetCompoundLayouter(
CompoundLayouter* compoundLayouter,
orientation orientation);
void InternalInvalidateLayout(
CompoundLayouter* compoundLayouter);
private:
BTwoDimensionalLayout* fLayout;
CompoundLayouter* fHLayouter;
VerticalCompoundLayouter* fVLayouter;
BList fHeightForWidthItems;
BLayoutContext* fHorizontalLayoutContext;
float fHorizontalLayoutWidth;
bool fHeightForWidthConstraintsAdded;
void _SetHorizontalLayoutContext(
BLayoutContext* context, float width);
virtual void LayoutContextLeft(BLayoutContext* context);
};
namespace {
const char* const kHAlignedLayoutField = "BTwoDimensionalLayout:"
"halignedlayout";
const char* const kVAlignedLayoutField = "BTwoDimensionalLayout:"
"valignedlayout";
const char* const kInsetsField = "BTwoDimensionalLayout:insets";
const char* const kSpacingField = "BTwoDimensionalLayout:spacing";
}
BTwoDimensionalLayout::BTwoDimensionalLayout()
:
fLeftInset(0),
fRightInset(0),
fTopInset(0),
fBottomInset(0),
fHSpacing(0),
fVSpacing(0),
fLocalLayouter(new LocalLayouter(this))
{
}
BTwoDimensionalLayout::BTwoDimensionalLayout(BMessage* from)
:
BAbstractLayout(from),
fLeftInset(0),
fRightInset(0),
fTopInset(0),
fBottomInset(0),
fHSpacing(0),
fVSpacing(0),
fLocalLayouter(new LocalLayouter(this))
{
BRect insets;
from->FindRect(kInsetsField, &insets);
SetInsets(insets.left, insets.top, insets.right, insets.bottom);
from->FindFloat(kSpacingField, 0, &fHSpacing);
from->FindFloat(kSpacingField, 1, &fVSpacing);
}
BTwoDimensionalLayout::~BTwoDimensionalLayout()
{
delete fLocalLayouter;
}
void
BTwoDimensionalLayout::SetInsets(float left, float top, float right,
float bottom)
{
fLeftInset = BControlLook::ComposeSpacing(left);
fTopInset = BControlLook::ComposeSpacing(top);
fRightInset = BControlLook::ComposeSpacing(right);
fBottomInset = BControlLook::ComposeSpacing(bottom);
InvalidateLayout();
}
void
BTwoDimensionalLayout::SetInsets(float horizontal, float vertical)
{
fLeftInset = BControlLook::ComposeSpacing(horizontal);
fRightInset = fLeftInset;
fTopInset = BControlLook::ComposeSpacing(vertical);
fBottomInset = fTopInset;
InvalidateLayout();
}
void
BTwoDimensionalLayout::SetInsets(float insets)
{
fLeftInset = BControlLook::ComposeSpacing(insets);
fRightInset = fLeftInset;
fTopInset = fLeftInset;
fBottomInset = fLeftInset;
InvalidateLayout();
}
void
BTwoDimensionalLayout::GetInsets(float* left, float* top, float* right,
float* bottom) const
{
if (left)
*left = fLeftInset;
if (top)
*top = fTopInset;
if (right)
*right = fRightInset;
if (bottom)
*bottom = fBottomInset;
}
void
BTwoDimensionalLayout::AlignLayoutWith(BTwoDimensionalLayout* other,
orientation orientation)
{
if (!other || other == this)
return;
fLocalLayouter->AlignWith(other->fLocalLayouter, orientation);
InvalidateLayout();
}
BSize
BTwoDimensionalLayout::BaseMinSize()
{
_ValidateMinMax();
return AddInsets(fLocalLayouter->MinSize());
}
BSize
BTwoDimensionalLayout::BaseMaxSize()
{
_ValidateMinMax();
return AddInsets(fLocalLayouter->MaxSize());
}
BSize
BTwoDimensionalLayout::BasePreferredSize()
{
_ValidateMinMax();
return AddInsets(fLocalLayouter->PreferredSize());
}
BAlignment
BTwoDimensionalLayout::BaseAlignment()
{
return BAbstractLayout::BaseAlignment();
}
bool
BTwoDimensionalLayout::HasHeightForWidth()
{
_ValidateMinMax();
return fLocalLayouter->HasHeightForWidth();
}
void
BTwoDimensionalLayout::GetHeightForWidth(float width, float* min, float* max,
float* preferred)
{
if (!HasHeightForWidth())
return;
float outerSpacing = fLeftInset + fRightInset - 1;
fLocalLayouter->InternalGetHeightForWidth(BLayoutUtils::SubtractDistances(
width, outerSpacing), min, max, preferred);
AddInsets(min, max, preferred);
}
void
BTwoDimensionalLayout::SetFrame(BRect frame)
{
BAbstractLayout::SetFrame(frame);
}
status_t
BTwoDimensionalLayout::Archive(BMessage* into, bool deep) const
{
BArchiver archiver(into);
status_t err = BAbstractLayout::Archive(into, deep);
if (err == B_OK) {
BRect insets(fLeftInset, fTopInset, fRightInset, fBottomInset);
err = into->AddRect(kInsetsField, insets);
}
if (err == B_OK)
err = into->AddFloat(kSpacingField, fHSpacing);
if (err == B_OK)
err = into->AddFloat(kSpacingField, fVSpacing);
return archiver.Finish(err);
}
status_t
BTwoDimensionalLayout::AllArchived(BMessage* into) const
{
BArchiver archiver(into);
status_t err = BLayout::AllArchived(into);
if (err == B_OK)
err = fLocalLayouter->AddAlignedLayoutsToArchive(&archiver);
return err;
}
status_t
BTwoDimensionalLayout::AllUnarchived(const BMessage* from)
{
status_t err = BLayout::AllUnarchived(from);
if (err != B_OK)
return err;
BUnarchiver unarchiver(from);
err = fLocalLayouter->AlignLayoutsFromArchive(&unarchiver, B_HORIZONTAL);
if (err == B_OK)
err = fLocalLayouter->AlignLayoutsFromArchive(&unarchiver, B_VERTICAL);
return err;
}
status_t
BTwoDimensionalLayout::ItemArchived(BMessage* into, BLayoutItem* item,
int32 index) const
{
return BAbstractLayout::ItemArchived(into, item, index);
}
status_t
BTwoDimensionalLayout::ItemUnarchived(const BMessage* from, BLayoutItem* item,
int32 index)
{
return BAbstractLayout::ItemUnarchived(from, item, index);
}
void
BTwoDimensionalLayout::LayoutInvalidated(bool children)
{
fLocalLayouter->InvalidateLayout();
}
void
BTwoDimensionalLayout::DoLayout()
{
_ValidateMinMax();
BSize size(SubtractInsets(LayoutArea().Size()));
#ifdef DEBUG_LAYOUT
printf("BTwoDimensionalLayout::DerivedLayoutItems(): view: %p"
" size: (%.1f, %.1f)\n", View(), size.Width(), size.Height());
#endif
fLocalLayouter->Layout(size);
BPoint itemOffset(LayoutArea().LeftTop());
int itemCount = CountItems();
for (int i = 0; i < itemCount; i++) {
BLayoutItem* item = ItemAt(i);
if (item->IsVisible()) {
Dimensions itemDimensions;
GetItemDimensions(item, &itemDimensions);
BRect frame = fLocalLayouter->ItemFrame(itemDimensions);
frame.left += fLeftInset;
frame.top += fTopInset;
frame.right += fLeftInset;
frame.bottom += fTopInset;
frame.OffsetBy(itemOffset);
{
#ifdef DEBUG_LAYOUT
printf(" frame for item %2d (view: %p): ", i, item->View());
frame.PrintToStream();
#endif
}
item->AlignInFrame(frame);
}
}
}
BSize
BTwoDimensionalLayout::AddInsets(BSize size)
{
size.width = BLayoutUtils::AddDistances(size.width,
fLeftInset + fRightInset - 1);
size.height = BLayoutUtils::AddDistances(size.height,
fTopInset + fBottomInset - 1);
return size;
}
void
BTwoDimensionalLayout::AddInsets(float* minHeight, float* maxHeight,
float* preferredHeight)
{
float insets = fTopInset + fBottomInset - 1;
if (minHeight)
*minHeight = BLayoutUtils::AddDistances(*minHeight, insets);
if (maxHeight)
*maxHeight = BLayoutUtils::AddDistances(*maxHeight, insets);
if (preferredHeight)
*preferredHeight = BLayoutUtils::AddDistances(*preferredHeight, insets);
}
BSize
BTwoDimensionalLayout::SubtractInsets(BSize size)
{
size.width = BLayoutUtils::SubtractDistances(size.width,
fLeftInset + fRightInset - 1);
size.height = BLayoutUtils::SubtractDistances(size.height,
fTopInset + fBottomInset - 1);
return size;
}
void
BTwoDimensionalLayout::PrepareItems(orientation orientation)
{
}
bool
BTwoDimensionalLayout::HasMultiColumnItems()
{
return false;
}
bool
BTwoDimensionalLayout::HasMultiRowItems()
{
return false;
}
void
BTwoDimensionalLayout::_ValidateMinMax()
{
fLocalLayouter->ValidateMinMax();
}
BTwoDimensionalLayout::CompoundLayouter::CompoundLayouter(
orientation orientation)
:
fLayouter(NULL),
fLayoutInfo(NULL),
fOrientation(orientation),
fLocalLayouters(10),
fLayoutContext(NULL),
fLastLayoutSize(-1)
{
}
BTwoDimensionalLayout::CompoundLayouter::~CompoundLayouter()
{
delete fLayouter;
delete fLayoutInfo;
}
orientation
BTwoDimensionalLayout::CompoundLayouter::Orientation()
{
return fOrientation;
}
Layouter*
BTwoDimensionalLayout::CompoundLayouter::GetLayouter(bool minMax)
{
return fLayouter;
}
LayoutInfo*
BTwoDimensionalLayout::CompoundLayouter::GetLayoutInfo()
{
return fLayoutInfo;
}
void
BTwoDimensionalLayout::CompoundLayouter::AddLocalLayouter(
LocalLayouter* localLayouter)
{
if (localLayouter) {
if (!fLocalLayouters.HasItem(localLayouter)) {
fLocalLayouters.AddItem(localLayouter);
InvalidateLayout();
}
}
}
void
BTwoDimensionalLayout::CompoundLayouter::RemoveLocalLayouter(
LocalLayouter* localLayouter)
{
if (fLocalLayouters.RemoveItem(localLayouter))
InvalidateLayout();
}
status_t
BTwoDimensionalLayout::CompoundLayouter::AddAlignedLayoutsToArchive(
BArchiver* archiver, LocalLayouter* requestedBy)
{
if (requestedBy != fLocalLayouters.ItemAt(0))
return B_OK;
status_t err;
for (int32 i = fLocalLayouters.CountItems() - 1; i > 0; i--) {
LocalLayouter* layouter = (LocalLayouter*)fLocalLayouters.ItemAt(i);
bool wasAvailable;
err = layouter->AddOwnerToArchive(archiver, this, wasAvailable);
if (err != B_OK && wasAvailable)
return err;
}
return B_OK;
}
void
BTwoDimensionalLayout::CompoundLayouter::AbsorbCompoundLayouter(
CompoundLayouter* other)
{
if (other == this)
return;
int32 count = other->fLocalLayouters.CountItems();
for (int32 i = count - 1; i >= 0; i--) {
LocalLayouter* layouter
= (LocalLayouter*)other->fLocalLayouters.ItemAt(i);
AddLocalLayouter(layouter);
layouter->SetCompoundLayouter(this, fOrientation);
}
InvalidateLayout();
}
void
BTwoDimensionalLayout::CompoundLayouter::InvalidateLayout()
{
if (!fLayouter)
return;
delete fLayouter;
delete fLayoutInfo;
fLayouter = NULL;
fLayoutInfo = NULL;
fLayoutContext = NULL;
int32 count = fLocalLayouters.CountItems();
for (int32 i = 0; i < count; i++) {
LocalLayouter* layouter = (LocalLayouter*)fLocalLayouters.ItemAt(i);
layouter->InternalInvalidateLayout(this);
}
}
bool
BTwoDimensionalLayout::CompoundLayouter::IsMinMaxValid()
{
return (fLayouter != NULL);
}
void
BTwoDimensionalLayout::CompoundLayouter::ValidateMinMax()
{
if (IsMinMaxValid())
return;
fLastLayoutSize = -1;
_PrepareItems();
int elementCount = _CountElements();
fLayouter = new CollapsingLayouter(elementCount, _Spacing());
_AddConstraints(fLayouter);
fLayoutInfo = fLayouter->CreateLayoutInfo();
}
void
BTwoDimensionalLayout::CompoundLayouter::Layout(float size,
LocalLayouter* localLayouter, BLayoutContext* context)
{
ValidateMinMax();
if (context != fLayoutContext || fLastLayoutSize != size) {
DoLayout(size, localLayouter, context);
fLayoutContext = context;
fLastLayoutSize = size;
}
}
void
BTwoDimensionalLayout::CompoundLayouter::DoLayout(float size,
LocalLayouter* localLayouter, BLayoutContext* context)
{
fLayouter->Layout(fLayoutInfo, size);
}
void
BTwoDimensionalLayout::CompoundLayouter::_PrepareItems()
{
int32 count = fLocalLayouters.CountItems();
for (int32 i = 0; i < count; i++) {
LocalLayouter* layouter = (LocalLayouter*)fLocalLayouters.ItemAt(i);
layouter->PrepareItems(this);
}
}
int32
BTwoDimensionalLayout::CompoundLayouter::_CountElements()
{
int32 elementCount = 0;
int32 count = fLocalLayouters.CountItems();
for (int32 i = 0; i < count; i++) {
LocalLayouter* layouter = (LocalLayouter*)fLocalLayouters.ItemAt(i);
int32 layouterCount = layouter->CountElements(this);
elementCount = max_c(elementCount, layouterCount);
}
return elementCount;
}
bool
BTwoDimensionalLayout::CompoundLayouter::_HasMultiElementItems()
{
int32 count = fLocalLayouters.CountItems();
for (int32 i = 0; i < count; i++) {
LocalLayouter* layouter = (LocalLayouter*)fLocalLayouters.ItemAt(i);
if (layouter->HasMultiElementItems(this))
return true;
}
return false;
}
void
BTwoDimensionalLayout::CompoundLayouter::_AddConstraints(Layouter* layouter)
{
int32 count = fLocalLayouters.CountItems();
for (int32 i = 0; i < count; i++) {
LocalLayouter* localLayouter = (LocalLayouter*)fLocalLayouters.ItemAt(i);
localLayouter->AddConstraints(this, layouter);
}
}
float
BTwoDimensionalLayout::CompoundLayouter::_Spacing()
{
if (!fLocalLayouters.IsEmpty())
return ((LocalLayouter*)fLocalLayouters.ItemAt(0))->Spacing(this);
return 0;
}
BTwoDimensionalLayout::VerticalCompoundLayouter::VerticalCompoundLayouter()
:
CompoundLayouter(B_VERTICAL),
fHeightForWidthLayouter(NULL),
fCachedMinHeightForWidth(0),
fCachedMaxHeightForWidth(0),
fCachedPreferredHeightForWidth(0),
fHeightForWidthLayoutContext(NULL)
{
}
Layouter*
BTwoDimensionalLayout::VerticalCompoundLayouter::GetLayouter(bool minMax)
{
return (minMax || !_HasHeightForWidth()
? fLayouter : fHeightForWidthLayouter);
}
void
BTwoDimensionalLayout::VerticalCompoundLayouter::InvalidateLayout()
{
CompoundLayouter::InvalidateLayout();
InvalidateHeightForWidth();
}
void
BTwoDimensionalLayout::VerticalCompoundLayouter::InvalidateHeightForWidth()
{
if (fHeightForWidthLayouter != NULL) {
delete fHeightForWidthLayouter;
fHeightForWidthLayouter = NULL;
fLastLayoutSize = -1;
int32 count = fLocalLayouters.CountItems();
for (int32 i = 0; i < count; i++) {
LocalLayouter* layouter = (LocalLayouter*)fLocalLayouters.ItemAt(i);
layouter->SetHeightForWidthConstraintsAdded(false);
}
}
}
void
BTwoDimensionalLayout::VerticalCompoundLayouter::InternalGetHeightForWidth(
LocalLayouter* localLayouter, BLayoutContext* context, bool realLayout,
float* minHeight, float* maxHeight, float* preferredHeight)
{
bool updateCachedInfo = false;
if (_SetHeightForWidthLayoutContext(context)
|| fHeightForWidthLayouter == NULL) {
delete fHeightForWidthLayouter;
delete fLayoutInfo;
fHeightForWidthLayouter = fLayouter->CloneLayouter();
fLayoutInfo = fHeightForWidthLayouter->CreateLayoutInfo();
int32 count = fLocalLayouters.CountItems();
for (int32 i = 0; i < count; i++) {
LocalLayouter* layouter = (LocalLayouter*)fLocalLayouters.ItemAt(i);
if (layouter->HasHeightForWidth()) {
layouter->AddHeightForWidthConstraints(this,
fHeightForWidthLayouter, context);
}
}
updateCachedInfo = true;
} else if (localLayouter->HasHeightForWidth()) {
updateCachedInfo = localLayouter->AddHeightForWidthConstraints(this,
fHeightForWidthLayouter, context);
}
if (updateCachedInfo) {
fCachedMinHeightForWidth = fHeightForWidthLayouter->MinSize();
fCachedMaxHeightForWidth = fHeightForWidthLayouter->MaxSize();
fCachedPreferredHeightForWidth
= fHeightForWidthLayouter->PreferredSize();
}
if (minHeight)
*minHeight = fCachedMinHeightForWidth;
if (maxHeight)
*maxHeight = fCachedMaxHeightForWidth;
if (preferredHeight)
*preferredHeight = fCachedPreferredHeightForWidth;
}
void
BTwoDimensionalLayout::VerticalCompoundLayouter::DoLayout(float size,
LocalLayouter* localLayouter, BLayoutContext* context)
{
Layouter* layouter;
if (_HasHeightForWidth()) {
float minHeight, maxHeight, preferredHeight;
InternalGetHeightForWidth(localLayouter, context, true, &minHeight,
&maxHeight, &preferredHeight);
size = max_c(size, minHeight);
layouter = fHeightForWidthLayouter;
} else
layouter = fLayouter;
layouter->Layout(fLayoutInfo, size);
}
bool
BTwoDimensionalLayout::VerticalCompoundLayouter::_HasHeightForWidth()
{
int32 count = fLocalLayouters.CountItems();
for (int32 i = 0; i < count; i++) {
LocalLayouter* layouter = (LocalLayouter*)fLocalLayouters.ItemAt(i);
if (layouter->HasHeightForWidth())
return true;
}
return false;
}
bool
BTwoDimensionalLayout::VerticalCompoundLayouter
::_SetHeightForWidthLayoutContext(BLayoutContext* context)
{
if (context == fHeightForWidthLayoutContext)
return false;
if (fHeightForWidthLayoutContext != NULL) {
fHeightForWidthLayoutContext->RemoveListener(this);
fHeightForWidthLayoutContext = NULL;
}
if (fLocalLayouters.CountItems() <= 1)
return false;
fHeightForWidthLayoutContext = context;
if (fHeightForWidthLayoutContext != NULL)
fHeightForWidthLayoutContext->AddListener(this);
InvalidateHeightForWidth();
return true;
}
void
BTwoDimensionalLayout::VerticalCompoundLayouter::LayoutContextLeft(
BLayoutContext* context)
{
fHeightForWidthLayoutContext = NULL;
}
BTwoDimensionalLayout::LocalLayouter::LocalLayouter(
BTwoDimensionalLayout* layout)
:
fLayout(layout),
fHLayouter(new CompoundLayouter(B_HORIZONTAL)),
fVLayouter(new VerticalCompoundLayouter),
fHeightForWidthItems(),
fHorizontalLayoutContext(NULL),
fHorizontalLayoutWidth(0),
fHeightForWidthConstraintsAdded(false)
{
fHLayouter->AddLocalLayouter(this);
fVLayouter->AddLocalLayouter(this);
}
BTwoDimensionalLayout::LocalLayouter::~LocalLayouter()
{
if (fHLayouter != NULL) {
fHLayouter->RemoveLocalLayouter(this);
fHLayouter->ReleaseReference();
}
if (fVLayouter != NULL) {
fVLayouter->RemoveLocalLayouter(this);
fVLayouter->ReleaseReference();
}
}
BSize
BTwoDimensionalLayout::LocalLayouter::MinSize()
{
return BSize(fHLayouter->GetLayouter(true)->MinSize(),
fVLayouter->GetLayouter(true)->MinSize());
}
BSize
BTwoDimensionalLayout::LocalLayouter::MaxSize()
{
return BSize(fHLayouter->GetLayouter(true)->MaxSize(),
fVLayouter->GetLayouter(true)->MaxSize());
}
BSize
BTwoDimensionalLayout::LocalLayouter::PreferredSize()
{
return BSize(fHLayouter->GetLayouter(true)->PreferredSize(),
fVLayouter->GetLayouter(true)->PreferredSize());
}
void
BTwoDimensionalLayout::LocalLayouter::InvalidateLayout()
{
fHLayouter->InvalidateLayout();
fVLayouter->InvalidateLayout();
}
void
BTwoDimensionalLayout::LocalLayouter::Layout(BSize size)
{
DoHorizontalLayout(size.width);
fVLayouter->Layout(size.height, this, fLayout->LayoutContext());
}
BRect
BTwoDimensionalLayout::LocalLayouter::ItemFrame(Dimensions itemDimensions)
{
LayoutInfo* hLayoutInfo = fHLayouter->GetLayoutInfo();
LayoutInfo* vLayoutInfo = fVLayouter->GetLayoutInfo();
float x = hLayoutInfo->ElementLocation(itemDimensions.x);
float y = vLayoutInfo->ElementLocation(itemDimensions.y);
float width = hLayoutInfo->ElementRangeSize(itemDimensions.x,
itemDimensions.width);
float height = vLayoutInfo->ElementRangeSize(itemDimensions.y,
itemDimensions.height);
return BRect(x, y, x + width, y + height);
}
void
BTwoDimensionalLayout::LocalLayouter::ValidateMinMax()
{
if (fHLayouter->IsMinMaxValid() && fVLayouter->IsMinMaxValid())
return;
if (!fHLayouter->IsMinMaxValid())
fHeightForWidthItems.MakeEmpty();
_SetHorizontalLayoutContext(NULL, -1);
fHLayouter->ValidateMinMax();
fVLayouter->ValidateMinMax();
fLayout->ResetLayoutInvalidation();
}
void
BTwoDimensionalLayout::LocalLayouter::DoHorizontalLayout(float width)
{
BLayoutContext* context = fLayout->LayoutContext();
if (fHorizontalLayoutContext != context
|| width != fHorizontalLayoutWidth) {
_SetHorizontalLayoutContext(context, width);
fHLayouter->Layout(width, this, context);
fVLayouter->InvalidateHeightForWidth();
}
}
void
BTwoDimensionalLayout::LocalLayouter::InternalGetHeightForWidth(float width,
float* minHeight, float* maxHeight, float* preferredHeight)
{
DoHorizontalLayout(width);
fVLayouter->InternalGetHeightForWidth(this, fHorizontalLayoutContext, false,
minHeight, maxHeight, preferredHeight);
}
void
BTwoDimensionalLayout::LocalLayouter::AlignWith(LocalLayouter* other,
orientation orientation)
{
if (orientation == B_HORIZONTAL)
other->fHLayouter->AbsorbCompoundLayouter(fHLayouter);
else
other->fVLayouter->AbsorbCompoundLayouter(fVLayouter);
}
status_t
BTwoDimensionalLayout::LocalLayouter::AddAlignedLayoutsToArchive(
BArchiver* archiver)
{
status_t err = fHLayouter->AddAlignedLayoutsToArchive(archiver, this);
if (err == B_OK)
err = fVLayouter->AddAlignedLayoutsToArchive(archiver, this);
return err;
}
status_t
BTwoDimensionalLayout::LocalLayouter::AddOwnerToArchive(BArchiver* archiver,
CompoundLayouter* requestedBy, bool& _wasAvailable)
{
const char* field = kHAlignedLayoutField;
if (requestedBy == fVLayouter)
field = kVAlignedLayoutField;
if ((_wasAvailable = archiver->IsArchived(fLayout)))
return archiver->AddArchivable(field, fLayout);
return B_NAME_NOT_FOUND;
}
status_t
BTwoDimensionalLayout::LocalLayouter::AlignLayoutsFromArchive(
BUnarchiver* unarchiver, orientation posture)
{
const char* field = kHAlignedLayoutField;
if (posture == B_VERTICAL)
field = kVAlignedLayoutField;
int32 count;
status_t err = unarchiver->ArchiveMessage()->GetInfo(field, NULL, &count);
if (err == B_NAME_NOT_FOUND)
return B_OK;
BTwoDimensionalLayout* retriever;
for (int32 i = 0; i < count && err == B_OK; i++) {
err = unarchiver->FindObject(field, i,
BUnarchiver::B_DONT_ASSUME_OWNERSHIP, retriever);
if (err == B_OK)
retriever->AlignLayoutWith(fLayout, posture);
}
return err;
}
void
BTwoDimensionalLayout::LocalLayouter::PrepareItems(
CompoundLayouter* compoundLayouter)
{
fLayout->PrepareItems(compoundLayouter->Orientation());
}
int32
BTwoDimensionalLayout::LocalLayouter::CountElements(
CompoundLayouter* compoundLayouter)
{
if (compoundLayouter->Orientation() == B_HORIZONTAL)
return fLayout->InternalCountColumns();
else
return fLayout->InternalCountRows();
}
bool
BTwoDimensionalLayout::LocalLayouter::HasMultiElementItems(
CompoundLayouter* compoundLayouter)
{
if (compoundLayouter->Orientation() == B_HORIZONTAL)
return fLayout->HasMultiColumnItems();
else
return fLayout->HasMultiRowItems();
}
void
BTwoDimensionalLayout::LocalLayouter::AddConstraints(
CompoundLayouter* compoundLayouter, Layouter* layouter)
{
enum orientation orientation = compoundLayouter->Orientation();
int itemCount = fLayout->CountItems();
if (itemCount > 0) {
for (int i = 0; i < itemCount; i++) {
BLayoutItem* item = fLayout->ItemAt(i);
if (item->IsVisible()) {
Dimensions itemDimensions;
fLayout->GetItemDimensions(item, &itemDimensions);
BSize min = item->MinSize();
BSize max = item->MaxSize();
BSize preferred = item->PreferredSize();
if (orientation == B_HORIZONTAL) {
layouter->AddConstraints(
itemDimensions.x,
itemDimensions.width,
min.width,
max.width,
preferred.width);
if (item->HasHeightForWidth())
fHeightForWidthItems.AddItem(item);
} else {
layouter->AddConstraints(
itemDimensions.y,
itemDimensions.height,
min.height,
max.height,
preferred.height);
}
}
}
ColumnRowConstraints constraints;
int elementCount = CountElements(compoundLayouter);
for (int element = 0; element < elementCount; element++) {
fLayout->GetColumnRowConstraints(orientation, element,
&constraints);
layouter->SetWeight(element, constraints.weight);
layouter->AddConstraints(element, 1, constraints.min,
constraints.max, constraints.min);
}
}
}
float
BTwoDimensionalLayout::LocalLayouter::Spacing(
CompoundLayouter* compoundLayouter)
{
return (compoundLayouter->Orientation() == B_HORIZONTAL
? fLayout->fHSpacing : fLayout->fVSpacing);
}
bool
BTwoDimensionalLayout::LocalLayouter::HasHeightForWidth()
{
return !fHeightForWidthItems.IsEmpty();
}
bool
BTwoDimensionalLayout::LocalLayouter::AddHeightForWidthConstraints(
VerticalCompoundLayouter* compoundLayouter, Layouter* layouter,
BLayoutContext* context)
{
if (context != fHorizontalLayoutContext)
return false;
if (fHeightForWidthConstraintsAdded)
return false;
LayoutInfo* hLayoutInfo = fHLayouter->GetLayoutInfo();
int32 itemCount = fHeightForWidthItems.CountItems();
for (int32 i = 0; i < itemCount; i++) {
BLayoutItem* item = (BLayoutItem*)fHeightForWidthItems.ItemAt(i);
Dimensions itemDimensions;
fLayout->GetItemDimensions(item, &itemDimensions);
float minHeight, maxHeight, preferredHeight;
item->GetHeightForWidth(
hLayoutInfo->ElementRangeSize(itemDimensions.x,
itemDimensions.width),
&minHeight, &maxHeight, &preferredHeight);
layouter->AddConstraints(
itemDimensions.y,
itemDimensions.height,
minHeight,
maxHeight,
preferredHeight);
}
SetHeightForWidthConstraintsAdded(true);
return true;
}
void
BTwoDimensionalLayout::LocalLayouter::SetHeightForWidthConstraintsAdded(
bool added)
{
fHeightForWidthConstraintsAdded = added;
}
void
BTwoDimensionalLayout::LocalLayouter::SetCompoundLayouter(
CompoundLayouter* compoundLayouter, orientation orientation)
{
CompoundLayouter* oldCompoundLayouter;
if (orientation == B_HORIZONTAL) {
oldCompoundLayouter = fHLayouter;
fHLayouter = compoundLayouter;
} else {
oldCompoundLayouter = fVLayouter;
fVLayouter = static_cast<VerticalCompoundLayouter*>(compoundLayouter);
}
if (compoundLayouter == oldCompoundLayouter)
return;
if (oldCompoundLayouter != NULL) {
oldCompoundLayouter->RemoveLocalLayouter(this);
oldCompoundLayouter->ReleaseReference();
}
if (compoundLayouter != NULL)
compoundLayouter->AcquireReference();
InternalInvalidateLayout(compoundLayouter);
}
void
BTwoDimensionalLayout::LocalLayouter::InternalInvalidateLayout(
CompoundLayouter* compoundLayouter)
{
_SetHorizontalLayoutContext(NULL, -1);
fLayout->BLayout::InvalidateLayout();
}
void
BTwoDimensionalLayout::LocalLayouter::_SetHorizontalLayoutContext(
BLayoutContext* context, float width)
{
if (context != fHorizontalLayoutContext) {
if (fHorizontalLayoutContext != NULL)
fHorizontalLayoutContext->RemoveListener(this);
fHorizontalLayoutContext = context;
if (fHorizontalLayoutContext != NULL)
fHorizontalLayoutContext->AddListener(this);
}
fHorizontalLayoutWidth = width;
}
void
BTwoDimensionalLayout::LocalLayouter::LayoutContextLeft(BLayoutContext* context)
{
fHorizontalLayoutContext = NULL;
fHorizontalLayoutWidth = -1;
}
status_t
BTwoDimensionalLayout::Perform(perform_code code, void* _data)
{
return BAbstractLayout::Perform(code, _data);
}
void BTwoDimensionalLayout::_ReservedTwoDimensionalLayout1() {}
void BTwoDimensionalLayout::_ReservedTwoDimensionalLayout2() {}
void BTwoDimensionalLayout::_ReservedTwoDimensionalLayout3() {}
void BTwoDimensionalLayout::_ReservedTwoDimensionalLayout4() {}
void BTwoDimensionalLayout::_ReservedTwoDimensionalLayout5() {}
void BTwoDimensionalLayout::_ReservedTwoDimensionalLayout6() {}
void BTwoDimensionalLayout::_ReservedTwoDimensionalLayout7() {}
void BTwoDimensionalLayout::_ReservedTwoDimensionalLayout8() {}
void BTwoDimensionalLayout::_ReservedTwoDimensionalLayout9() {}
void BTwoDimensionalLayout::_ReservedTwoDimensionalLayout10() {}