limn_layout/
solver.rs

1use std::collections::{HashMap, HashSet, VecDeque};
2use std::fmt::Write;
3
4use cassowary;
5use cassowary::strength::*;
6use cassowary::{Variable, Constraint, Expression};
7use cassowary::WeightedRelation::*;
8
9use super::{LayoutId, Layout, VarType, LayoutVars, EditVariable, Rect, Point, Size};
10
11pub struct LimnSolver {
12    pub solver: cassowary::Solver,
13    pub strict: bool,
14    layouts: LayoutManager,
15}
16
17impl LimnSolver {
18    pub fn new() -> Self {
19        LimnSolver {
20            solver: cassowary::Solver::new(),
21            strict: false,
22            layouts: LayoutManager::new(),
23        }
24    }
25
26    pub fn update_layout(&mut self, layout: &mut Layout) {
27
28        let registered = self.layouts.layouts.contains_key(&layout.id);
29        if !registered {
30            self.layouts.register_layout(layout);
31        }
32        self.layouts.update_layout(layout);
33
34        for child in layout.get_removed_children() {
35            self.remove_layout(child);
36        }
37        for constraint in layout.get_removed_constraints() {
38            self.layouts.remove_constraint(&constraint);
39            self.remove_constraint(&constraint);
40        }
41        if !registered {
42            for constraint in self.layouts.dequeue_constraints(layout) {
43                self.add_constraint(constraint.clone());
44            }
45        }
46
47        if layout.hidden && !self.layouts.layout_hidden(layout.id) {
48            self.hide_layout(layout.id);
49        } else if !layout.hidden && self.layouts.layout_hidden(layout.id) {
50            self.unhide_layout(layout.id);
51        }
52        for constraint in layout.get_constraints() {
53            if self.layouts.add_constraint(&constraint) {
54                self.add_constraint(constraint.clone());
55            }
56        }
57        for edit_var in layout.get_edit_vars() {
58            self.update_edit_var(&edit_var);
59            self.layouts.update_edit_var(layout.id, edit_var);
60        }
61    }
62    fn update_edit_var(&mut self, edit_var: &EditVariable) {
63        let &EditVariable { var, val, strength } = edit_var;
64        if !self.solver.has_edit_variable(&var) {
65            debug!("add edit_var {}", self.layouts.fmt_variable(var));
66            self.solver.add_edit_variable(var, strength).unwrap();
67        }
68        if val.is_finite() {
69            self.solver.suggest_value(var, val).unwrap();
70            debug!("suggest edit_var {} {}", self.layouts.fmt_variable(var), val);
71        } else {
72            debug!("invalid edit_var {} {}", self.layouts.fmt_variable(var), val);
73        }
74    }
75    fn add_constraint(&mut self, constraint: Constraint) {
76        debug!("adding constraint {}", self.layouts.fmt_constraint(&constraint));
77        if self.solver.add_constraint(constraint.clone()).is_err() {
78            eprintln!("Failed to add constraint {}", self.layouts.fmt_constraint(&constraint));
79            self.debug_associated_constraints(&constraint);
80            if self.strict {
81                panic!("Solver unsatisfiable");
82            }
83        }
84    }
85
86    fn remove_constraint(&mut self, constraint: &Constraint) {
87        debug!("removing constraint {}", self.layouts.fmt_constraint(constraint));
88        if self.solver.has_constraint(constraint) {
89            self.solver.remove_constraint(constraint).unwrap();
90        }
91    }
92
93    pub fn remove_layout(&mut self, id: LayoutId) {
94        if let Some(layout) = self.layouts.layouts.remove(&id) {
95            for constraint in layout.constraints {
96                self.remove_constraint(&constraint);
97            }
98            for var in layout.vars.array().iter() {
99                self.layouts.var_ids.remove(&var);
100            }
101        }
102    }
103
104    pub fn hide_layout(&mut self, id: LayoutId) {
105        if !self.layouts.layout_hidden(id) {
106            for constraint in self.layouts.layouts[&id].constraints.clone() {
107                self.remove_constraint(&constraint);
108            }
109            {
110                let layout = self.layouts.layouts.get_mut(&id).unwrap();
111                if layout.hidden_constraints.len() == 0 {
112                    layout.hidden_constraints.extend(vec![
113                        layout.vars.width | EQ(REQUIRED) | 0.0, layout.vars.height | EQ(REQUIRED) | 0.0,
114                        layout.vars.left | EQ(REQUIRED) | 0.0, layout.vars.top | EQ(REQUIRED) | 0.0,
115                        layout.vars.right | EQ(REQUIRED) | 0.0, layout.vars.bottom | EQ(REQUIRED) | 0.0,
116                    ]);
117                }
118                layout.hidden = true;
119            }
120            for constraint in self.layouts.layouts[&id].hidden_constraints.clone() {
121                self.add_constraint(constraint.clone());
122            }
123        }
124        let children = self.layouts.layouts[&id].children.clone();
125        for child in children {
126            self.hide_layout(child);
127        }
128    }
129    pub fn unhide_layout(&mut self, id: LayoutId) {
130        if self.layouts.layout_hidden(id) {
131            for constraint in self.layouts.layouts[&id].hidden_constraints.clone() {
132                self.remove_constraint(&constraint);
133            }
134            for constraint in self.layouts.layouts[&id].constraints.clone() {
135                if !self.solver.has_constraint(&constraint) {
136                    let mut hidden = false;
137                    for layout_id in self.layouts.dependent_layouts(&constraint) {
138                        if layout_id != id && self.layouts.layout_hidden(layout_id) {
139                            hidden = true;
140                            break;
141                        }
142                    }
143                    if !hidden {
144                        self.add_constraint(constraint.clone());
145                    }
146                }
147            }
148            let layout = self.layouts.layouts.get_mut(&id).unwrap();
149            layout.hidden = false;
150        }
151        let children = self.layouts.layouts[&id].children.clone();
152        for child in children {
153            self.unhide_layout(child);
154        }
155    }
156    pub fn update_solver<F>(&mut self, f: F)
157        where F: Fn(&mut cassowary::Solver)
158    {
159        f(&mut self.solver);
160    }
161
162    pub fn has_edit_variable(&mut self, v: &Variable) -> bool {
163        self.solver.has_edit_variable(v)
164    }
165    pub fn has_constraint(&self, constraint: &Constraint) -> bool {
166        self.solver.has_constraint(constraint)
167    }
168
169    pub fn fetch_changes(&mut self) -> Vec<(LayoutId, VarType, f64)> {
170        let mut changes = Vec::new();
171        for &(var, val) in self.solver.fetch_changes() {
172            debug!("solver {} = {}", self.layouts.fmt_variable(var), val);
173            if let Some(layout_id) = self.layouts.var_ids.get(&var) {
174                let var_type = self.layouts.layouts[&layout_id].vars.var_type(var);
175                changes.push((*layout_id, var_type, val));
176            }
177        }
178        changes
179    }
180
181    pub fn debug_variables(&self) {
182        println!("VARIABLES");
183        for var in self.layouts.var_ids.keys() {
184            println!("{}", self.layouts.fmt_variable(*var));
185        }
186    }
187
188    pub fn debug_constraints(&self) {
189        println!("CONSTRAINTS");
190        let mut shown_constraints = HashSet::new();
191        let mut layouts = VecDeque::new();
192        layouts.push_front(self.layouts.root);
193        while let Some(layout) = layouts.pop_front() {
194            println!("{}", self.layouts.layout_name(layout).to_uppercase());
195            for constraint in &self.layouts.layouts[&layout].constraints {
196                if !shown_constraints.contains(constraint) && self.solver.has_constraint(constraint) {
197                    self.debug_constraint(constraint);
198                    shown_constraints.insert(constraint.clone());
199                }
200            }
201            println!("EDIT_VARS");
202            for (_, edit_var) in &self.layouts.layouts[&layout].edit_vars {
203                println!("{}", self.layouts.fmt_edit_variable(edit_var));
204            }
205            layouts.extend(self.layouts.children(layout));
206        }
207    }
208
209    pub fn debug_constraint(&self, constraint: &Constraint) {
210        println!("{}", self.layouts.fmt_constraint(constraint));
211    }
212
213    pub fn debug_associated_constraints(&self, constraint: &Constraint) {
214        let mut visited_constraints = HashSet::new();
215        let mut new_constraints = HashSet::new();
216        new_constraints.insert(constraint.clone());
217
218        loop {
219            if new_constraints.len() == 0 {
220                break;
221            }
222            let mut newer_constraints = HashSet::new();
223            for constraint in new_constraints.drain() {
224                for var in constraint_vars(&constraint) {
225                    for constraint in self.layouts.constraints_for(var) {
226                        if constraint.strength() >= REQUIRED &&
227                            !visited_constraints.contains(constraint) &&
228                                self.solver.has_constraint(&constraint) {
229                            newer_constraints.insert(constraint.clone());
230                        }
231                    }
232                }
233                visited_constraints.insert(constraint);
234            }
235            new_constraints = newer_constraints;
236        }
237        for constraint in visited_constraints {
238            self.debug_constraint(&constraint);
239        }
240    }
241
242    pub fn debug_layouts(&self) {
243        println!("LAYOUTS");
244        let mut layouts = VecDeque::new();
245        layouts.push_front(self.layouts.root);
246        while let Some(layout) = layouts.pop_front() {
247            self.debug_layout(layout);
248            layouts.extend(self.layouts.children(layout));
249        }
250    }
251
252    pub fn debug_layout(&self, id: LayoutId) {
253        let bounds = {
254            let get_val = |var| self.solver.get_value(var) as f32;
255            let vars = &self.layouts.layouts[&id].vars;
256            let origin = Point::new(get_val(vars.left), get_val(vars.top));
257            let size = Size::new(get_val(vars.width), get_val(vars.height));
258            Rect::new(origin, size)
259        };
260        println!("{} {}", self.layouts.layout_name(id), bounds);
261    }
262}
263
264fn constraint_vars(constraint: &Constraint) -> Vec<Variable> {
265    constraint.expr().terms.iter().map(|term| term.variable).collect()
266}
267
268struct LayoutInternal {
269    vars: LayoutVars,
270    name: Option<String>,
271    associated_vars: HashMap<Variable, String>,
272    edit_vars: HashMap<Variable, EditVariable>,
273    constraints: HashSet<Constraint>,
274    children: Vec<LayoutId>,
275    hidden: bool,
276    hidden_constraints: Vec<Constraint>,
277}
278pub struct LayoutManager {
279    root: LayoutId,
280    var_ids: HashMap<Variable, LayoutId>,
281    layouts: HashMap<LayoutId, LayoutInternal>,
282    constraints: HashMap<Variable, HashSet<Constraint>>,
283
284    pending_constraints: HashMap<Variable, Vec<Constraint>>,
285    missing_vars: HashMap<Constraint, usize>,
286}
287
288impl LayoutManager {
289
290    pub fn new() -> Self {
291        LayoutManager {
292            root: 0,
293            var_ids: HashMap::new(),
294            layouts: HashMap::new(),
295            constraints: HashMap::new(),
296            pending_constraints: HashMap::new(),
297            missing_vars: HashMap::new(),
298        }
299    }
300
301    pub fn register_layout(&mut self, layout: &mut Layout) {
302        let id = layout.id;
303
304        for var in layout.vars.array().iter() {
305            self.var_ids.insert(*var, id);
306        }
307        let layout = LayoutInternal {
308            vars: layout.vars.clone(),
309            name: layout.name.clone(),
310            associated_vars: HashMap::new(),
311            edit_vars: HashMap::new(),
312            constraints: HashSet::new(),
313            children: layout.children.clone(),
314            hidden: false,
315            hidden_constraints: Vec::new(),
316        };
317        self.layouts.insert(id, layout);
318    }
319
320    pub fn update_layout(&mut self, layout: &mut Layout) {
321        let internal_layout = self.layouts.get_mut(&layout.id).unwrap();
322        for (var, name) in layout.get_associated_vars() {
323            self.var_ids.insert(var, layout.id);
324            internal_layout.associated_vars.insert(var, name);
325        }
326        internal_layout.name = layout.name.clone();
327    }
328
329    pub fn add_constraint(&mut self, constraint: &Constraint) -> bool {
330        let mut missing_layouts = false;
331        for term in &constraint.expr().terms {
332            self.constraints.entry(term.variable).or_insert_with(HashSet::new).insert(constraint.clone());
333            if self.var_ids.contains_key(&term.variable) {
334                let layout_id = self.var_ids[&term.variable];
335                self.layouts.get_mut(&layout_id).unwrap().constraints.insert(constraint.clone());
336            } else {
337                missing_layouts = true;
338                self.queue_constraint(term.variable, constraint.clone());
339            }
340        }
341        !missing_layouts
342    }
343
344    pub fn remove_constraint(&mut self, constraint: &Constraint) {
345        for term in &constraint.expr().terms {
346            self.constraints.entry(term.variable).or_insert_with(HashSet::new).remove(constraint);
347            if self.var_ids.contains_key(&term.variable) {
348                let layout_id = self.var_ids[&term.variable];
349                self.layouts.get_mut(&layout_id).unwrap().constraints.remove(constraint);
350            }
351        }
352    }
353    fn update_edit_var(&mut self, layout_id: LayoutId, edit_var: EditVariable) {
354        self.layouts.get_mut(&layout_id).unwrap().edit_vars.insert(edit_var.var, edit_var);
355    }
356
357    fn constraints_for(&self, variable: Variable) -> &HashSet<Constraint> {
358        &self.constraints[&variable]
359    }
360
361    // if constraint added for non-registered variable, add to pending and increment counter
362    // of missing variables for that constraint
363    pub fn queue_constraint(&mut self, variable: Variable, constraint: Constraint) {
364        *self.missing_vars.entry(constraint.clone()).or_insert(0) += 1;
365        self.pending_constraints.entry(variable).or_insert_with(Vec::new)
366            .push(constraint);
367    }
368    // when new layout registered, if there are any pending constraints for it's variables
369    // and no other variables are missing for them, add those constraints
370    pub fn dequeue_constraints(&mut self, layout: &mut Layout) -> Vec<Constraint> {
371        let constraints = {
372            let mut constraints = Vec::new();
373            for var in self.layout_vars(layout.id) {
374                if let Some(pending) = self.pending_constraints.remove(&var) {
375                    for constraint in pending {
376                        *self.missing_vars.get_mut(&constraint).unwrap() -= 1;
377                        if self.missing_vars[&constraint] == 0 {
378                            self.missing_vars.remove(&constraint);
379                            constraints.push(constraint);
380                        }
381                    }
382                }
383            }
384            constraints
385        };
386        for constraint in &constraints {
387            for term in &constraint.expr().terms {
388                let layout_id = self.var_ids[&term.variable];
389                self.layouts.get_mut(&layout_id).unwrap().constraints.insert(constraint.clone());
390            }
391        }
392        constraints
393    }
394
395    pub fn layout_hidden(&self, id: LayoutId) -> bool {
396        self.layouts[&id].hidden
397    }
398
399    pub fn layout_name(&self, id: LayoutId) -> String {
400        self.layouts[&id].name.clone().unwrap_or("unknown".to_owned())
401    }
402
403    fn dependent_layouts(&self, constraint: &Constraint) -> Vec<LayoutId> {
404        constraint.expr().terms.iter().map(|term| self.var_ids[&term.variable]).collect()
405    }
406
407    pub fn children(&self, id: LayoutId) -> Vec<LayoutId> {
408        self.layouts[&id].children.clone()
409    }
410    pub fn layout_vars(&self, id: LayoutId) -> Vec<Variable> {
411        let layout = &self.layouts[&id];
412        layout.vars.array().iter().chain(layout.associated_vars.keys()).map(|var| *var).collect()
413    }
414
415    pub fn fmt_variable(&self, var: Variable) -> String {
416        let id = self.var_ids[&var];
417        let layout = &self.layouts[&id];
418        let layout_name = layout.name.clone().unwrap_or("unknown".to_owned());
419        let var_type = layout.vars.var_type(var);
420        let var_type = if let VarType::Other = var_type {
421            layout.associated_vars[&var].to_owned()
422        } else {
423            format!("{:?}", var_type).to_lowercase()
424        };
425        format!("{}.{}", layout_name, var_type)
426    }
427
428    pub fn fmt_edit_variable(&self, edit_var: &EditVariable) -> String {
429        format!("{} {} == {}", strength_desc(edit_var.strength), self.fmt_variable(edit_var.var), edit_var.val)
430    }
431
432    pub fn fmt_constraint(&self, constraint: &Constraint) -> String {
433        format!("{} {}", strength_desc(constraint.strength()), self.fmt_expression(&constraint.expr(), constraint.op()))
434    }
435
436    fn fmt_expression(&self, expression: &Expression, op: cassowary::RelationalOperator) -> String {
437        let (mut neg_terms, mut pos_terms) = (Vec::new(), Vec::new());
438        for term in expression.terms.iter() {
439            let neg = term.coefficient < 0.0;
440            let coef = term.coefficient.abs();
441            let coef = if coef == 1.0 { "".to_owned() } else { coef.to_string() };
442            let desc = format!("{}{}", coef, self.fmt_variable(term.variable));
443            if neg { neg_terms.push(desc) } else { pos_terms.push(desc) }
444        }
445        if expression.constant != 0.0 {
446            let neg = expression.constant < 0.0;
447            let desc = expression.constant.abs().to_string();
448            if neg { neg_terms.push(desc) } else { pos_terms.push(desc) }
449        }
450        let mut out = String::new();
451        if pos_terms.len() == 0 {
452            write!(out, "0").unwrap();
453        } else {
454            let mut terms = pos_terms.iter();
455            let term = terms.next().unwrap();
456            write!(out, "{}", term).unwrap();
457            for term in terms {
458                write!(out, " + {}", term).unwrap();
459            }
460        }
461        write!(out, " {} ", op).unwrap();
462        if neg_terms.len() == 0 {
463            write!(out, "0").unwrap();
464        } else {
465            let mut terms = neg_terms.iter();
466            let term = terms.next().unwrap();
467            write!(out, "{}", term).unwrap();
468            for term in terms {
469                write!(out, " + {}", term).unwrap();
470            }
471        }
472        out
473    }
474}
475
476/// Creates a printable string value for a given strength
477fn strength_desc(strength: f64) -> &'static str {
478    if strength < WEAK { "WEAK-" }
479    else if strength == WEAK { "WEAK " }
480    else if strength < MEDIUM { "WEAK+" }
481    else if strength == MEDIUM { "MED  " }
482    else if strength < STRONG { "MED+ " }
483    else if strength == STRONG { "STR  " }
484    else if strength < REQUIRED { "STR+ " }
485    else if strength == REQUIRED { "REQD " }
486    else { "REQD+" }
487}