xref: /haiku/src/libs/alm/RowColumnManager.cpp (revision 0bd511a33133366456af89fe027fde758b01d60c)
1 /*
2  * Copyright 2011, Haiku, Inc. All rights reserved.
3  * Copyright 2011, Clemens Zeidler <haiku@clemens-zeidler.de>
4  * Distributed under the terms of the MIT License.
5  */
6 
7 
8 #include "RowColumnManager.h"
9 
10 
11 #include <LayoutItem.h>
12 
13 
14 using namespace LinearProgramming;
15 
16 
17 namespace BALM {
18 
19 
20 RowColumnManager::RowColumnManager(LinearSpec* spec)
21 	:
22 	fLinearSpec(spec)
23 {
24 
25 }
26 
27 
28 RowColumnManager::~RowColumnManager()
29 {
30 	for (int32 i = 0; i < fRows.CountItems(); i++)
31 		delete fRows.ItemAt(i)->fPrefSizeConstraint;
32 
33 	for (int32 i = 0; i < fColumns.CountItems(); i++)
34 		delete fColumns.ItemAt(i)->fPrefSizeConstraint;
35 }
36 
37 
38 void
39 RowColumnManager::AddArea(Area* area)
40 {
41 	Row* row = _FindRowFor(area);
42 	if (row == NULL) {
43 		row = new Row(fLinearSpec, area->Top(), area->Bottom());
44 		fRows.AddItem(row);
45 	}
46 	area->fRow = row;
47 	row->fAreas.AddItem(area);
48 
49 	Column* column = _FindColumnFor(area);
50 	if (column == NULL) {
51 		column = new Column(fLinearSpec, area->Left(), area->Right());
52 		fColumns.AddItem(column);
53 	}
54 	area->fColumn = column;
55 	column->fAreas.AddItem(area);
56 
57 	_UpdateConstraints(row);
58 	_UpdateConstraints(column);
59 }
60 
61 
62 void
63 RowColumnManager::RemoveArea(Area* area)
64 {
65 	Row* row = area->fRow;
66 	if (row) {
67 		row->fAreas.RemoveItem(area);
68 		area->fRow = NULL;
69 		if (row->fAreas.CountItems() == 0) {
70 			fRows.RemoveItem(row);
71 			delete row;
72 		} else
73 			_UpdateConstraints(row);
74 	}
75 
76 	Column* column = area->fColumn;
77 	if (column) {
78 		column->fAreas.RemoveItem(area);
79 		area->fColumn = NULL;
80 		if (column->fAreas.CountItems() == 0) {
81 			fColumns.RemoveItem(column);
82 			delete column;
83 		} else
84 			_UpdateConstraints(column);
85 	}
86 }
87 
88 
89 void
90 RowColumnManager::UpdateConstraints()
91 {
92 	for (int32 i = 0; i < fRows.CountItems(); i++)
93 		_UpdateConstraints(fRows.ItemAt(i));
94 	for (int32 i = 0; i < fColumns.CountItems(); i++)
95 		_UpdateConstraints(fColumns.ItemAt(i));
96 }
97 
98 
99 void
100 RowColumnManager::TabsChanged(Area* area)
101 {
102 	RemoveArea(area);
103 	AddArea(area);
104 }
105 
106 
107 Row*
108 RowColumnManager::_FindRowFor(Area* area)
109 {
110 	for (int32 i = 0; i < fRows.CountItems(); i++) {
111 		Row* row = fRows.ItemAt(i);
112 		if (row->fTop.Get() == area->Top()
113 			&& row->fBottom.Get() == area->Bottom())
114 			return row;
115 	}
116 	return NULL;
117 }
118 
119 
120 Column*
121 RowColumnManager::_FindColumnFor(Area* area)
122 {
123 	for (int32 i = 0; i < fColumns.CountItems(); i++) {
124 		Column* column = fColumns.ItemAt(i);
125 		if (column->fLeft.Get() == area->Left()
126 			&& column->fRight.Get() == area->Right())
127 			return column;
128 	}
129 	return NULL;
130 }
131 
132 
133 double
134 RowColumnManager::_PreferredHeight(Row* row, double& weight)
135 {
136 	weight = 0;
137 	int nAreas = 0;
138 	double pref = 0;
139 	for (int32 i = 0; i < row->fAreas.CountItems(); i++) {
140 		BSize prefSize = row->fAreas.ItemAt(i)->Item()->PreferredSize();
141 		if (prefSize.height > 0) {
142 			nAreas++;
143 			pref += prefSize.height;
144 		}
145 		double negPen = row->fAreas.ItemAt(i)->ShrinkPenalties().height;
146 		if (negPen > 0)
147 			weight += negPen;
148 	}
149 	if (nAreas == 0) {
150 		pref = 0;
151 		weight = 1;
152 	} else {
153 		pref /= nAreas;
154 		weight /= nAreas;
155 	}
156 	return pref;
157 }
158 
159 
160 double
161 RowColumnManager::_PreferredWidth(Column* column, double& weight)
162 {
163 	weight = 0;
164 	int nAreas = 0;
165 	double pref = 0;
166 	for (int32 i = 0; i < column->fAreas.CountItems(); i++) {
167 		BSize prefSize = column->fAreas.ItemAt(i)->Item()->PreferredSize();
168 		if (prefSize.width > 0) {
169 			nAreas++;
170 			pref += prefSize.width;
171 		}
172 		double negPen = column->fAreas.ItemAt(i)->ShrinkPenalties().height;
173 		if (negPen > 0)
174 			weight += negPen;
175 	}
176 	if (nAreas == 0) {
177 		pref = 0;
178 		weight = 1;
179 	} else {
180 		pref /= nAreas;
181 		weight /= nAreas;
182 	}
183 	return pref;
184 }
185 
186 
187 void
188 RowColumnManager::_UpdateConstraints(Row* row)
189 {
190 	double weight;
191 	double prefSize = _PreferredHeight(row, weight);
192 	if (prefSize >= 0) {
193 		if (row->fPrefSizeConstraint == NULL) {
194 			row->fPrefSizeConstraint = fLinearSpec->AddConstraint(1,
195 			row->fBottom, -1, row->fTop, kEQ, prefSize, weight, weight);
196 		} else {
197 			row->fPrefSizeConstraint->SetRightSide(prefSize);
198 			row->fPrefSizeConstraint->SetPenaltyNeg(weight);
199 			row->fPrefSizeConstraint->SetPenaltyPos(weight);
200 		}
201 	} else {
202 		delete row->fPrefSizeConstraint;
203 		row->fPrefSizeConstraint = NULL;
204 	}
205 }
206 
207 
208 void
209 RowColumnManager::_UpdateConstraints(Column* column)
210 {
211 	double weight;
212 	double prefSize = _PreferredWidth(column, weight);
213 	if (prefSize >= 0) {
214 		if (column->fPrefSizeConstraint == NULL) {
215 			column->fPrefSizeConstraint = fLinearSpec->AddConstraint(1,
216 				column->fRight, -1, column->fLeft, kEQ, prefSize, weight,
217 				weight);
218 		} else {
219 			column->fPrefSizeConstraint->SetRightSide(prefSize);
220 			column->fPrefSizeConstraint->SetPenaltyNeg(weight);
221 			column->fPrefSizeConstraint->SetPenaltyPos(weight);
222 		}
223 	} else {
224 		delete column->fPrefSizeConstraint;
225 		column->fPrefSizeConstraint = NULL;
226 	}
227 }
228 
229 
230 } // end BALM namespace
231 
232