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