xref: /haiku/src/libs/alm/SharedSolver.cpp (revision 681f48fcbccfa556fe01eab457ca1d549736b19e)
1 /*
2  * Copyright 2012, Haiku, Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include "SharedSolver.h"
8 
9 #include <ALMLayout.h>
10 #include <ObjectList.h>
11 
12 
13 using LinearProgramming::LinearSpec;
14 
15 
16 struct SharedSolver::MinSizeValidator {
17 	inline void CallSolverMethod(LinearSpec* spec, VariableList* vars)
18 	{
19 		spec->FindMins(vars);
20 	}
21 
22 	inline void Finalize(BALMLayout* layout, SharedSolver* solver,
23 		ResultType solveResult)
24 	{
25 		if (solveResult == LinearProgramming::kUnbounded) {
26 			solver->SetMinSize(layout, BSize(0, 0));
27 		} else {
28 			solver->SetMinSize(layout, BSize(layout->Right()->Value(),
29 				layout->Bottom()->Value()));
30 		}
31 	}
32 };
33 
34 
35 struct SharedSolver::MaxSizeValidator {
36 	inline void CallSolverMethod(LinearSpec* spec, VariableList* vars)
37 	{
38 		spec->FindMaxs(vars);
39 	}
40 
41 	inline void Finalize(BALMLayout* layout, SharedSolver* solver,
42 		ResultType solveResult)
43 	{
44 		if (solveResult == LinearProgramming::kUnbounded) {
45 			solver->SetMaxSize(layout,
46 				BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED));
47 		} else {
48 			solver->SetMaxSize(layout, BSize(layout->Right()->Value(),
49 				layout->Bottom()->Value()));
50 		}
51 	}
52 };
53 
54 
55 struct SharedSolver::PreferredSizeValidator {
56 	inline void CallSolverMethod(LinearSpec* spec, VariableList* vars)
57 	{
58 		spec->Solve();
59 	}
60 
61 	inline void Finalize(BALMLayout* layout, SharedSolver* solver,
62 		ResultType solveResult)
63 	{
64 		float width = layout->Right()->Value() - layout->Left()->Value();
65 		float height = layout->Top()->Value() - layout->Bottom()->Value();
66 		solver->SetPreferredSize(layout, BSize(width, height));
67 	}
68 };
69 
70 
71 SharedSolver::SharedSolver()
72 	:
73 	fConstraintsValid(false),
74 	fMinValid(false),
75 	fMaxValid(false),
76 	fPreferredValid(false),
77 	fLayoutValid(false),
78 	fLayoutContext(NULL)
79 {
80 }
81 
82 
83 SharedSolver::~SharedSolver()
84 {
85 	if (fLayouts.CountItems() > 0)
86 		debugger("SharedSolver deleted while still in use!");
87 
88 	_SetContext(NULL);
89 }
90 
91 
92 LinearSpec*
93 SharedSolver::Solver() const
94 {
95 	return const_cast<LinearSpec*>(&fLinearSpec);
96 }
97 
98 
99 void
100 SharedSolver::Invalidate(bool children)
101 {
102 	if (!fConstraintsValid && !fMaxValid && !fMinValid && !fLayoutValid)
103 		return;
104 
105 	fConstraintsValid = false;
106 	fMinValid = false;
107 	fMaxValid = false;
108 	fPreferredValid = false;
109 	fLayoutValid = false;
110 
111 	_SetContext(NULL);
112 
113 	for (int32 i = fLayouts.CountItems() - 1; i >= 0; i--)
114 		fLayouts.ItemAt(i)->InvalidateLayout(children);
115 }
116 
117 
118 void
119 SharedSolver::RegisterLayout(BALMLayout* layout)
120 {
121 	fLayouts.AddItem(layout);
122 	Invalidate(false);
123 }
124 
125 
126 void
127 SharedSolver::LayoutLeaving(BALMLayout* layout)
128 {
129 	fLayouts.RemoveItem(layout);
130 	Invalidate(false);
131 }
132 
133 
134 ResultType
135 SharedSolver::ValidateMinSize()
136 {
137 	_Validate<MinSizeValidator>(fMinValid, fMinResult);
138 	return fMinResult;
139 }
140 
141 
142 ResultType
143 SharedSolver::ValidateMaxSize()
144 {
145 	_Validate<MaxSizeValidator>(fMaxValid, fMaxResult);
146 	return fMaxResult;
147 }
148 
149 
150 ResultType
151 SharedSolver::ValidatePreferredSize()
152 {
153 	_Validate<PreferredSizeValidator>(fPreferredValid, fPreferredResult);
154 	return fPreferredResult;
155 }
156 
157 
158 ResultType
159 SharedSolver::ValidateLayout(BLayoutContext* context)
160 {
161 	if (fLayoutValid && fLayoutContext == context)
162 		return fLayoutResult;
163 
164 	_SetContext(context);
165 	_ValidateConstraints();
166 
167 	for (int32 i = fLayouts.CountItems() - 1; i >= 0; i--) {
168 		BALMLayout* layout = fLayouts.ItemAt(i);
169 		BSize size(layout->LayoutArea().Size());
170 		layout->Right()->SetRange(size.width, size.width);
171 		layout->Bottom()->SetRange(size.height, size.height);
172 	}
173 
174 	fLayoutResult = fLinearSpec.Solve();
175 	fLayoutValid = true;
176 	return fLayoutResult;
177 }
178 
179 
180 void
181 SharedSolver::SetMaxSize(BALMLayout* layout, const BSize& max)
182 {
183 	layout->fMaxSize = max;
184 }
185 
186 
187 void
188 SharedSolver::SetMinSize(BALMLayout* layout, const BSize& min)
189 {
190 	layout->fMinSize = min;
191 }
192 
193 
194 void
195 SharedSolver::SetPreferredSize(BALMLayout* layout, const BSize& preferred)
196 {
197 	layout->fPreferredSize = preferred;
198 }
199 
200 
201 void
202 SharedSolver::LayoutContextLeft(BLayoutContext* context)
203 {
204 	_SetContext(NULL);
205 }
206 
207 
208 void
209 SharedSolver::_SetContext(BLayoutContext* context)
210 {
211 	if (fLayoutContext)
212 		fLayoutContext->RemoveListener(this);
213 	fLayoutContext = context;
214 	if (fLayoutContext)
215 		fLayoutContext->AddListener(this);
216 }
217 
218 
219 void
220 SharedSolver::_ValidateConstraints()
221 {
222 	if (!fConstraintsValid) {
223 		for (int32 i = fLayouts.CountItems() - 1; i >= 0; i--) {
224 			fLayouts.ItemAt(i)->UpdateConstraints(fLayoutContext);
225 		}
226 		fConstraintsValid = true;
227 	}
228 }
229 
230 
231 template <class Validator>
232 void
233 SharedSolver::_Validate(bool& isValid, ResultType& result)
234 {
235 	if (isValid)
236 		return;
237 
238 	_ValidateConstraints();
239 
240 	VariableList variables(fLayouts.CountItems() * 2);
241 	Validator validator;
242 
243 	for (int32 i = fLayouts.CountItems() - 1; i >= 0; i--) {
244 		BALMLayout* layout = fLayouts.ItemAt(i);
245 		layout->Right()->SetRange(0, 20000);
246 		layout->Bottom()->SetRange(0, 20000);
247 
248 		variables.AddItem(layout->Right());
249 		variables.AddItem(layout->Bottom());
250 	}
251 
252 	validator.CallSolverMethod(&fLinearSpec, &variables);
253 	result = fLinearSpec.Result();
254 
255 	for (int32 i = fLayouts.CountItems() - 1; i >= 0; i--)
256 		validator.Finalize(fLayouts.ItemAt(i), this, result);
257 
258 	isValid = true;
259 	fLayoutValid = false;
260 }
261