Add a new layouter 'CollapsingLayouter', which is used by BTwoDimensionalLayout to collapse empty rows or columns. Update BGridLayout so that empty rows/columns are given min/max constraints of B_SIZE_UNSET by default, which allows them to be collapsed. Fixes #6979

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@41252 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Alex Wilson 2011-04-14 23:20:27 +00:00
parent 745e924303
commit de667551ce
5 changed files with 409 additions and 13 deletions

View File

@ -90,7 +90,7 @@ public:
{
if (Info* info = _InfoAt(index))
return info->minSize;
return -1;
return B_SIZE_UNSET;
}
void SetMinSize(int32 index, float size)
@ -103,7 +103,7 @@ public:
{
if (Info* info = _InfoAt(index))
return info->maxSize;
return B_SIZE_UNLIMITED;
return B_SIZE_UNSET;
}
void SetMaxSize(int32 index, float size)
@ -138,8 +138,8 @@ private:
for (int32 i = count; i <= index; i++) {
Info* info = new Info;
info->weight = 1;
info->minSize = 0;
info->maxSize = B_SIZE_UNLIMITED;
info->minSize = B_SIZE_UNSET;
info->maxSize = B_SIZE_UNSET;
fInfos.AddItem(info);
}
}

View File

@ -133,6 +133,7 @@ MergeObject <libbe>interface_kit.o :
WidthBuffer.cpp
# layouter
CollapsingLayouter.cpp
ComplexLayouter.cpp
Layouter.cpp
LayoutOptimizer.cpp

View File

@ -18,9 +18,7 @@
#include <Referenceable.h>
#include "ComplexLayouter.h"
#include "OneElementLayouter.h"
#include "SimpleLayouter.h"
#include "CollapsingLayouter.h"
@ -706,12 +704,7 @@ BTwoDimensionalLayout::CompoundLayouter::ValidateMinMax()
int elementCount = _CountElements();
if (elementCount <= 1)
fLayouter = new OneElementLayouter();
else if (_HasMultiElementItems())
fLayouter = new ComplexLayouter(elementCount, _Spacing());
else
fLayouter = new SimpleLayouter(elementCount, _Spacing());
fLayouter = new CollapsingLayouter(elementCount, _Spacing());
// tell the layouter about our constraints
// TODO: We should probably ignore local layouters whose view is hidden.

View File

@ -0,0 +1,334 @@
/*
* Copyright 2011, Haiku, Inc.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "CollapsingLayouter.h"
#include "ComplexLayouter.h"
#include "OneElementLayouter.h"
#include "SimpleLayouter.h"
#include <ObjectList.h>
#include <Size.h>
class CollapsingLayouter::ProxyLayoutInfo : public LayoutInfo {
public:
ProxyLayoutInfo(LayoutInfo* target, int32 elementCount)
:
fTarget(target),
fElementCount(elementCount)
{
fElements = new int32[elementCount];
}
~ProxyLayoutInfo()
{
delete[] fElements;
delete fTarget;
}
void
LayoutTarget(Layouter* layouter, float size)
{
if (layouter)
layouter->Layout(fTarget, size);
}
void
SetElementPosition(int32 element, int32 position)
{
fElements[element] = position;
}
float
ElementLocation(int32 element)
{
if (element < 0 || element >= fElementCount || fElements[element] < 0)
return 0;
return fTarget->ElementLocation(fElements[element]);
}
float
ElementSize(int32 element)
{
if (element < 0 || element >= fElementCount || fElements[element] < 0)
return 0;
return fTarget->ElementSize(fElements[element]);
}
float
ElementRangeSize(int32 element, int32 length)
{
if (element < 0 || element >= fElementCount || fElements[element] < 0)
return 0;
return fTarget->ElementRangeSize(fElements[element], length);
}
private:
int32* fElements;
LayoutInfo* fTarget;
int32 fElementCount;
};
struct CollapsingLayouter::Constraint {
int32 length;
float min;
float max;
float preferred;
};
struct CollapsingLayouter::ElementInfo {
float weight;
int32 position;
bool valid;
BObjectList<Constraint> constraints;
ElementInfo()
:
weight(0),
position(-1),
valid(false),
constraints(5, true)
{
}
~ElementInfo()
{
}
void SetTo(const ElementInfo& other)
{
weight = other.weight;
position = other.position;
valid = other.valid;
for (int32 i = other.constraints.CountItems() - 1; i >= 0; i--)
constraints.AddItem(new Constraint(*other.constraints.ItemAt(i)));
}
int32 LengthOfLongestConstraint()
{
int32 length = 0;
for (int32 i = constraints.CountItems() - 1; i >= 0; i--)
length = max_c(length, constraints.ItemAt(i)->length);
return length;
}
};
CollapsingLayouter::CollapsingLayouter(int32 elementCount, float spacing)
:
fElementCount(elementCount),
fElements(new ElementInfo[elementCount]),
fValidElementCount(0),
fHaveMultiElementConstraints(false),
fSpacing(spacing),
fLayouter(NULL)
{
}
CollapsingLayouter::~CollapsingLayouter()
{
delete[] fElements;
delete fLayouter;
}
void
CollapsingLayouter::AddConstraints(int32 element, int32 length, float min,
float max, float preferred)
{
if (min == B_SIZE_UNSET && max == B_SIZE_UNSET)
return;
if (element < 0 || length <= 0 || element + length > fElementCount)
return;
Constraint* constraint = new Constraint();
constraint->length = length;
constraint->min = min;
constraint->max = max;
constraint->preferred = preferred;
if (length > 1)
fHaveMultiElementConstraints = true;
int32 validElements = fValidElementCount;
for (int32 i = element; i < element + length; i++) {
if (fElements[i].valid == false) {
fElements[i].valid = true;
fValidElementCount++;
}
}
fElements[element].constraints.AddItem(constraint);
if (fValidElementCount > validElements) {
delete fLayouter;
fLayouter = NULL;
}
if (fLayouter)
_AddConstraints(element, constraint);
}
void
CollapsingLayouter::SetWeight(int32 element, float weight)
{
if (element < 0 || element >= fElementCount)
return;
ElementInfo& elementInfo = fElements[element];
elementInfo.weight = weight;
if (fLayouter && elementInfo.position >= 0)
fLayouter->SetWeight(elementInfo.position, weight);
}
float
CollapsingLayouter::MinSize()
{
_ValidateLayouter();
return fLayouter->MinSize();
}
float
CollapsingLayouter::MaxSize()
{
_ValidateLayouter();
return fLayouter->MaxSize();
}
float
CollapsingLayouter::PreferredSize()
{
_ValidateLayouter();
return fLayouter->PreferredSize();
}
LayoutInfo*
CollapsingLayouter::CreateLayoutInfo()
{
_ValidateLayouter();
return new ProxyLayoutInfo(fLayouter->CreateLayoutInfo(), fElementCount);
}
void
CollapsingLayouter::Layout(LayoutInfo* layoutInfo, float size)
{
_ValidateLayouter();
ProxyLayoutInfo* info = static_cast<ProxyLayoutInfo*>(layoutInfo);
for (int32 i = 0; i < fElementCount; i++) {
info->SetElementPosition(i, fElements[i].position);
}
info->LayoutTarget(fLayouter, size);
}
Layouter*
CollapsingLayouter::CloneLayouter()
{
CollapsingLayouter* clone = new CollapsingLayouter(fElementCount, fSpacing);
for (int32 i = 0; i < fElementCount; i++)
clone->fElements[i].SetTo(fElements[i]);
clone->fValidElementCount = fValidElementCount;
clone->fHaveMultiElementConstraints = fHaveMultiElementConstraints;
if (fLayouter)
clone->fLayouter = fLayouter->CloneLayouter();
return clone;
}
void
CollapsingLayouter::_ValidateLayouter()
{
if (fLayouter)
return;
_CreateLayouter();
_DoCollapse();
_AddConstraints();
_SetWeights();
}
Layouter*
CollapsingLayouter::_CreateLayouter()
{
if (fLayouter)
return fLayouter;
if (fValidElementCount == 0) {
fLayouter = NULL;
} else if (fValidElementCount == 1) {
fLayouter = new OneElementLayouter();
} else if (fHaveMultiElementConstraints) {
fLayouter = new ComplexLayouter(fValidElementCount, fSpacing);
} else {
fLayouter = new SimpleLayouter(fValidElementCount, fSpacing);
}
return fLayouter;
}
void
CollapsingLayouter::_DoCollapse()
{
int32 shift = 0;
for (int32 i = 0; i < fElementCount; i++) {
ElementInfo& element = fElements[i];
if (!element.valid) {
shift++;
element.position = -1;
continue;
} else {
element.position = i - shift;
}
}
}
void
CollapsingLayouter::_AddConstraints()
{
if (fLayouter == NULL)
return;
for (int32 i = 0; i < fElementCount; i++) {
ElementInfo& element = fElements[i];
for (int32 i = element.constraints.CountItems() - 1; i >= 0; i--)
_AddConstraints(element.position, element.constraints.ItemAt(i));
}
}
void
CollapsingLayouter::_AddConstraints(int32 position, const Constraint* c)
{
fLayouter->AddConstraints(position, c->length, c->min, c->max,
c->preferred);
}
void
CollapsingLayouter::_SetWeights()
{
for (int32 i = 0; i < fElementCount; i++) {
fLayouter->SetWeight(fElements[i].position, fElements[i].weight);
}
}

View File

@ -0,0 +1,68 @@
/*
* Copyright 2011, Haiku, Inc.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef COLLAPSING_LAYOUTER_H
#define COLLAPSING_LAYOUTER_H
#include "Layouter.h"
namespace BPrivate {
namespace Layout {
/* This layouter wraps either a Compound, Simple or OneElement layouter, and
* removes elements which have no constraints, or min/max constraints of
* B_SIZE_UNSET. The child layouter is given only the constraints for the
* remaining elements. When using the LayoutInfo of this layouter,
* collapsed (removed) elements are given no space on screen.
*/
class CollapsingLayouter : public Layouter {
public:
CollapsingLayouter(int32 elementCount,
float spacing);
virtual ~CollapsingLayouter();
virtual void AddConstraints(int32 element, int32 length,
float min, float max, float preferred);
virtual void SetWeight(int32 element, float weight);
virtual float MinSize();
virtual float MaxSize();
virtual float PreferredSize();
virtual LayoutInfo* CreateLayoutInfo();
virtual void Layout(LayoutInfo* layoutInfo, float size);
virtual Layouter* CloneLayouter();
private:
class ProxyLayoutInfo;
struct Constraint;
struct ElementInfo;
void _ValidateLayouter();
Layouter* _CreateLayouter();
void _DoCollapse();
void _AddConstraints();
void _AddConstraints(int32 position,
const Constraint* c);
void _SetWeights();
int32 fElementCount;
ElementInfo* fElements;
int32 fValidElementCount;
bool fHaveMultiElementConstraints;
float fSpacing;
Layouter* fLayouter;
};
} // namespace Layout
} // namespace BPrivate
using BPrivate::Layout::CollapsingLayouter;
#endif // COLLAPSING_LAYOUTER_H