| 1 | use crate::geom::Rect; |
| 2 | use crate::plan::{Config, Group, Plan, plan}; |
| 3 | |
| 4 | /// Plans with each block moving rigidly, for moves whose unit is a whole |
| 5 | /// container such as reordering viewed tags. Blocks must partition the |
| 6 | /// windows, and every window must keep its place inside its block. |
| 7 | pub fn plan_blocks(from: &[Rect], to: &[Rect], blocks: &[Vec<usize>], cfg: &Config) -> Plan { |
| 8 | let bounds = |l: &[Rect]| -> Vec<Rect> { |
| 9 | blocks |
| 10 | .iter() |
| 11 | .map(|b| Rect::bounding(b.iter().map(|&i| &l[i]))) |
| 12 | .collect() |
| 13 | }; |
| 14 | let (bf, bt) = (bounds(from), bounds(to)); |
| 15 | let bp = plan(&bf, &bt, cfg); |
| 16 | let last = bp.keyframes.len() - 1; |
| 17 | let keyframes = bp |
| 18 | .keyframes |
| 19 | .iter() |
| 20 | .enumerate() |
| 21 | .map(|(k, key)| match k { |
| 22 | 0 => from.to_vec(), |
| 23 | k if k == last => to.to_vec(), |
| 24 | _ => { |
| 25 | let mut frame = from.to_vec(); |
| 26 | for (b, members) in blocks.iter().enumerate() { |
| 27 | for &i in members { |
| 28 | frame[i] = reframe(&from[i], &bf[b], &key[b]); |
| 29 | } |
| 30 | } |
| 31 | frame |
| 32 | } |
| 33 | }) |
| 34 | .collect(); |
| 35 | let groups = bp |
| 36 | .groups |
| 37 | .into_iter() |
| 38 | .map(|g| Group { |
| 39 | members: g |
| 40 | .members |
| 41 | .iter() |
| 42 | .flat_map(|&b| blocks[b].iter().copied()) |
| 43 | .collect(), |
| 44 | ..g |
| 45 | }) |
| 46 | .collect(); |
| 47 | Plan { keyframes, groups } |
| 48 | } |
| 49 | |
| 50 | fn reframe(r: &Rect, from: &Rect, to: &Rect) -> Rect { |
| 51 | let scale = |v: f64, len: f64| if len > 0.0 { v / len } else { 0.0 }; |
| 52 | Rect::new( |
| 53 | to.x + scale(r.x - from.x, from.w) * to.w, |
| 54 | to.y + scale(r.y - from.y, from.h) * to.h, |
| 55 | scale(r.w, from.w) * to.w, |
| 56 | scale(r.h, from.h) * to.h, |
| 57 | ) |
| 58 | } |