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