⛏️ index : haiku.git

/*
 * 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;
	}
}


} // end BALM namespace