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:
parent
745e924303
commit
de667551ce
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -133,6 +133,7 @@ MergeObject <libbe>interface_kit.o :
|
||||
WidthBuffer.cpp
|
||||
|
||||
# layouter
|
||||
CollapsingLayouter.cpp
|
||||
ComplexLayouter.cpp
|
||||
Layouter.cpp
|
||||
LayoutOptimizer.cpp
|
||||
|
@ -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.
|
||||
|
334
src/kits/interface/layouter/CollapsingLayouter.cpp
Normal file
334
src/kits/interface/layouter/CollapsingLayouter.cpp
Normal 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);
|
||||
}
|
||||
}
|
68
src/kits/interface/layouter/CollapsingLayouter.h
Normal file
68
src/kits/interface/layouter/CollapsingLayouter.h
Normal 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
|
Loading…
x
Reference in New Issue
Block a user