* Copyright 2011, Haiku, Inc. All rights reserved.
* Copyright 2011, Clemens Zeidler <haiku@clemens-zeidler.de>
* Distributed under the terms of the MIT License.
*/
#include "RowColumnManager.h"
#include <LayoutItem.h>
using namespace LinearProgramming;
namespace BALM {
RowColumnManager::RowColumnManager(LinearSpec* spec)
:
fLinearSpec(spec)
{
}
RowColumnManager::~RowColumnManager()
{
for (int32 i = 0; i < fRows.CountItems(); i++)
delete fRows.ItemAt(i)->fPrefSizeConstraint;
for (int32 i = 0; i < fColumns.CountItems(); i++)
delete fColumns.ItemAt(i)->fPrefSizeConstraint;
}
void
RowColumnManager::AddArea(Area* area)
{
Row* row = _FindRowFor(area);
if (row == NULL) {
row = new Row(fLinearSpec, area->Top(), area->Bottom());
fRows.AddItem(row);
}
area->fRow = row;
row->fAreas.AddItem(area);
Column* column = _FindColumnFor(area);
if (column == NULL) {
column = new Column(fLinearSpec, area->Left(), area->Right());
fColumns.AddItem(column);
}
area->fColumn = column;
column->fAreas.AddItem(area);
_UpdateConstraints(row);
_UpdateConstraints(column);
}
void
RowColumnManager::RemoveArea(Area* area)
{
Row* row = area->fRow;
if (row) {
row->fAreas.RemoveItem(area);
area->fRow = NULL;
if (row->fAreas.CountItems() == 0) {
fRows.RemoveItem(row);
delete row;
} else
_UpdateConstraints(row);
}
Column* column = area->fColumn;
if (column) {
column->fAreas.RemoveItem(area);
area->fColumn = NULL;
if (column->fAreas.CountItems() == 0) {
fColumns.RemoveItem(column);
delete column;
} else
_UpdateConstraints(column);
}
}
void
RowColumnManager::UpdateConstraints()
{
for (int32 i = 0; i < fRows.CountItems(); i++)
_UpdateConstraints(fRows.ItemAt(i));
for (int32 i = 0; i < fColumns.CountItems(); i++)
_UpdateConstraints(fColumns.ItemAt(i));
}
void
RowColumnManager::TabsChanged(Area* area)
{
RemoveArea(area);
AddArea(area);
}
Row*
RowColumnManager::_FindRowFor(Area* area)
{
for (int32 i = 0; i < fRows.CountItems(); i++) {
Row* row = fRows.ItemAt(i);
if (row->fTop.Get() == area->Top()
&& row->fBottom.Get() == area->Bottom())
return row;
}
return NULL;
}
Column*
RowColumnManager::_FindColumnFor(Area* area)
{
for (int32 i = 0; i < fColumns.CountItems(); i++) {
Column* column = fColumns.ItemAt(i);
if (column->fLeft.Get() == area->Left()
&& column->fRight.Get() == area->Right())
return column;
}
return NULL;
}
double
RowColumnManager::_PreferredHeight(Row* row, double& weight)
{
weight = 0;
int nAreas = 0;
double pref = 0;
for (int32 i = 0; i < row->fAreas.CountItems(); i++) {
BSize prefSize = row->fAreas.ItemAt(i)->Item()->PreferredSize();
if (prefSize.height <= 0)
continue;
nAreas++;
pref += prefSize.height;
double negPen = row->fAreas.ItemAt(i)->ShrinkPenalties().height;
if (negPen > 0)
weight += negPen;
}
if (nAreas == 0) {
pref = -1;
weight = 1;
} else {
pref /= nAreas;
weight /= nAreas;
}
return pref;
}
double
RowColumnManager::_PreferredWidth(Column* column, double& weight)
{
weight = 0;
int nAreas = 0;
double pref = 0;
for (int32 i = 0; i < column->fAreas.CountItems(); i++) {
BSize prefSize = column->fAreas.ItemAt(i)->Item()->PreferredSize();
if (prefSize.width <= 0)
continue;
nAreas++;
pref += prefSize.width;
double negPen = column->fAreas.ItemAt(i)->ShrinkPenalties().height;
if (negPen > 0)
weight += negPen;
}
if (nAreas == 0) {
pref = -1;
weight = 1;
} else {
pref /= nAreas;
weight /= nAreas;
}
return pref;
}
void
RowColumnManager::_UpdateConstraints(Row* row)
{
double weight;
double prefSize = _PreferredHeight(row, weight);
if (prefSize >= 0) {
if (row->fPrefSizeConstraint == NULL) {
row->fPrefSizeConstraint = fLinearSpec->AddConstraint(1,
row->fBottom, -1, row->fTop, kEQ, prefSize, weight, weight);
row->fPrefSizeConstraint->SetLabel("Pref Height");
} else {
row->fPrefSizeConstraint->SetRightSide(prefSize);
row->fPrefSizeConstraint->SetPenaltyNeg(weight);
row->fPrefSizeConstraint->SetPenaltyPos(weight);
}
} else {
delete row->fPrefSizeConstraint;
row->fPrefSizeConstraint = NULL;
}
}
void
RowColumnManager::_UpdateConstraints(Column* column)
{
double weight;
double prefSize = _PreferredWidth(column, weight);
if (prefSize >= 0) {
if (column->fPrefSizeConstraint == NULL) {
column->fPrefSizeConstraint = fLinearSpec->AddConstraint(1,
column->fRight, -1, column->fLeft, kEQ, prefSize, weight,
weight);
column->fPrefSizeConstraint->SetLabel("Pref Width");
} else {
column->fPrefSizeConstraint->SetRightSide(prefSize);
column->fPrefSizeConstraint->SetPenaltyNeg(weight);
column->fPrefSizeConstraint->SetPenaltyPos(weight);
}
} else {
delete column->fPrefSizeConstraint;
column->fPrefSizeConstraint = NULL;
}
}
}