cognitive_frames/
settling.rs

1// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of
2// the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/
3
4//! This module contains extra settling functionality for `frames::Frame`.
5
6// -------------------------------------------------------------------------------------------------
7
8use qualia::{Area, Direction, Position, Vector, Size, SurfaceAccess, SurfaceId};
9
10use frame::{Frame, Geometry, Mobility, Mode, Side};
11use searching::Searching;
12use packing::Packing;
13
14// -------------------------------------------------------------------------------------------------
15
16/// Extension trait for `Frame` adding more settling functionality.
17pub trait Settling {
18    /// Settle self in buildable of target and relax it.
19    ///
20    /// If `area` is provided settle the surface as floating with given position and size.
21    fn settle(&mut self, target: &mut Frame, area: Option<Area>, sa: &mut SurfaceAccess);
22
23    /// Remove given frame, relax old parent and settle the frame on given target.
24    ///
25    /// If frame is floating and optional position is given it will be used to place the frame.
26    fn resettle(&mut self, target: &mut Frame, position: Option<Position>, sa: &mut SurfaceAccess);
27
28    /// Pop the surface `pop` and its parents inside surface `self`.
29    ///
30    /// After calling this function `pop` will be most recently used frame inside `self`.
31    fn pop_recursively(&mut self, pop: &mut Frame);
32
33    /// Changes frames geometry and resizes all subframe accordingly.
34    fn change_geometry(&mut self, geometry: Geometry, sa: &mut SurfaceAccess);
35
36    /// Adds another container into given place in frame layout if needed.
37    ///
38    /// This method is used when jumping into leaf frame to create container to handle the leaf
39    /// and jumped frame.
40    ///
41    /// Returns
42    ///  - `self` if it is container with one child,
43    ///  - parent if parent has one child
44    ///  - newly created container frame otherwise
45    ///
46    /// Returned frame is guarantied to have exactly one child.
47    fn ramify(&mut self, geometry: Geometry) -> Frame;
48
49    /// Removes unnecessary layers of container frames containing only one container or leaf frame.
50    fn deramify(&mut self);
51
52    /// Places frame `self` on given `side` of `target` frame.
53    fn jumpin(&mut self, side: Side, target: &mut Frame, sa: &mut SurfaceAccess);
54
55    /// Removes frame `self` from frame layout and then places it using `jumpin` method.
56    fn jump(&mut self, side: Side, target: &mut Frame, sa: &mut SurfaceAccess);
57
58    /// Places frame `self` in `target` frame as dock.
59    fn dock(&mut self, target: &mut Frame, size: Size, sa: &mut SurfaceAccess);
60
61    /// Anchorizes floating frame.
62    fn anchorize(&mut self, sa: &mut SurfaceAccess);
63
64    /// Deanchorizes frame. Floating frame must be attached to workspace so it will be resettled if
65    /// necessary.
66    fn deanchorize(&mut self, area: Area, sa: &mut SurfaceAccess);
67
68    /// Resize the frame. `direction` indicates the border which will be moved and `magnitude` is
69    /// move distance in pixels.
70    fn resize(&mut self, direction: Direction, magnitude: isize, sa: &mut SurfaceAccess);
71
72    /// Move the frame and all subframes by given vector.
73    fn move_with_contents(&mut self, vector: Vector);
74
75    /// Removes frame `self`, relaxes old parent and destroys the frame.
76    fn destroy_self(&mut self, sa: &mut SurfaceAccess);
77}
78
79// -------------------------------------------------------------------------------------------------
80
81impl Settling for Frame {
82    fn settle(&mut self, target: &mut Frame, area: Option<Area>, sa: &mut SurfaceAccess) {
83        if let Some(ref mut buildable) = target.find_buildable() {
84            if buildable.get_geometry() == Geometry::Stacked {
85                buildable.prepend(self);
86                if let Some(area) = area {
87                    self.set_plumbing_mobility(Mobility::Floating);
88                    self.set_size(area.size, sa);
89                    self.set_plumbing_position(area.pos);
90                } else {
91                    self.set_plumbing_mobility(Mobility::Anchored);
92                }
93            } else {
94                buildable.append(self);
95                self.set_plumbing_mobility(Mobility::Anchored);
96            }
97            buildable.relax(sa);
98        }
99    }
100
101    fn resettle(&mut self, target: &mut Frame, position: Option<Position>, sa: &mut SurfaceAccess) {
102        let area = {
103            // Preserve area if resettling to another workspace
104            if self.get_mobility().is_floating() && target.get_mode().is_workspace() {
105                let mut area = self.get_area();
106                if let Some(position) = position {
107                    area.pos = position;
108                }
109                Some(area)
110            } else {
111                None
112            }
113        };
114        self.remove_self(sa);
115        self.settle(target, area, sa);
116    }
117
118    fn pop_recursively(&mut self, pop: &mut Frame) {
119        // If we reached `self` we can finish
120        if self.equals_exact(pop) {
121            return;
122        }
123
124        // If there's nothing above we can finish
125        if let Some(ref mut parent) = pop.get_parent() {
126            // If it is `stacked` frame we have to pop it also spatially
127            if parent.get_geometry() == Geometry::Stacked {
128                pop.remove();
129                parent.prepend(pop);
130            }
131
132            // Pop in temporal order
133            pop.pop();
134
135            // Do the same recursively on trunk
136            self.pop_recursively(parent);
137        }
138    }
139
140    fn change_geometry(&mut self, geometry: Geometry, sa: &mut SurfaceAccess) {
141        self.set_plumbing_geometry(geometry);
142        self.homogenize(sa);
143    }
144
145    fn ramify(&mut self, geometry: Geometry) -> Frame {
146        if !self.is_top() {
147            let parent = self.get_parent().expect("should have parent");
148            if self.count_children() == 1 {
149                return self.clone();
150            }
151            if parent.count_children() == 1 {
152                return parent;
153            }
154        }
155
156        let (distancer_mobility, distancer_mode) = if self.is_top() {
157            (self.get_mobility(), self.get_mode())
158        } else {
159            (Mobility::Anchored, Mode::Container)
160        };
161
162        let frame_mode = if self.get_mode().is_leaf() {
163            self.get_mode()
164        } else {
165            Mode::Container
166        };
167
168        let mut distancer = Frame::new(SurfaceId::invalid(),
169                                       geometry,
170                                       distancer_mobility,
171                                       distancer_mode,
172                                       self.get_position(),
173                                       self.get_size(),
174                                       self.get_title());
175        self.prejoin(&mut distancer);
176        self.remove();
177        self.set_plumbing_mobility(Mobility::Anchored);
178        self.set_plumbing_mode(frame_mode);
179        self.set_plumbing_position(Position::default());
180        distancer.prepend(self);
181        distancer
182    }
183
184    fn deramify(&mut self) {
185        let len = self.count_children();
186        if len == 1 {
187            let mut first = self.get_first_time().expect("should have exactly one child");
188            let len = first.count_children();
189            if len == 1 {
190                let mut second = first.get_first_time().expect("should have exactly one child");
191                first.remove();
192                second.remove();
193                self.prepend(&mut second);
194                first.destroy();
195            } else if len == 0 {
196                self.set_plumbing_mode(first.get_mode());
197                self.set_plumbing_sid(first.get_sid());
198                first.remove();
199                first.destroy();
200            }
201        }
202    }
203
204    fn jumpin(&mut self, side: Side, target: &mut Frame, sa: &mut SurfaceAccess) {
205        if let Some(mut target_parent) = target.get_parent() {
206            match side {
207                Side::Before => {
208                    target.prejoin(self);
209                    target_parent.relax(sa);
210                }
211                Side::After => {
212                    target.adjoin(self);
213                    target_parent.relax(sa);
214                }
215                Side::On => {
216                    let mut new_target = {
217                        if !target_parent.is_top() &&
218                           target_parent.count_children() == 1 {
219                            target_parent.clone()
220                        } else if target.get_mode().is_leaf() {
221                            target.ramify(Geometry::Stacked)
222                        } else {
223                            target.clone()
224                        }
225                    };
226
227                    self.settle(&mut new_target, None, sa);
228                }
229            }
230        }
231    }
232
233    fn jump(&mut self, side: Side, target: &mut Frame, sa: &mut SurfaceAccess) {
234        self.remove_self(sa);
235        self.jumpin(side, target, sa);
236    }
237
238    fn dock(&mut self, target: &mut Frame, size: Size, sa: &mut SurfaceAccess) {
239        target.set_plumbing_geometry(Geometry::Vertical);
240        self.set_plumbing_mobility(Mobility::Docked);
241        self.set_plumbing_size(size);
242        self.set_plumbing_position(Position::default());
243        target.prepend(self);
244        target.relax(sa);
245    }
246
247    fn anchorize(&mut self, sa: &mut SurfaceAccess) {
248        if self.is_reanchorizable() && self.get_mobility().is_floating() {
249            // NOTE: Floating surface must be direct child of workspace.
250            let parent = self.get_parent().expect("should have parent");
251            self.set_size(parent.get_size(), sa);
252            self.set_plumbing_position(Position::default());
253            self.set_plumbing_mobility(Mobility::Anchored);
254        }
255    }
256
257    fn deanchorize(&mut self, area: Area, sa: &mut SurfaceAccess) {
258        if self.is_reanchorizable() && self.get_mobility().is_anchored() {
259            let mut workspace = self.find_top().expect("should have toplevel");
260            let parent = self.get_parent().expect("should have parent");
261            if !parent.equals_exact(&workspace) {
262                self.remove_self(sa);
263                workspace.prepend(self);
264            }
265            self.set_size(area.size, sa);
266            self.set_plumbing_position(area.pos);
267            self.set_plumbing_mobility(Mobility::Floating);
268        }
269    }
270
271    fn resize(&mut self, direction: Direction, magnitude: isize, sa: &mut SurfaceAccess) {
272        if direction.is_planar() && !self.is_top() {
273            match self.get_mobility() {
274                Mobility::Floating => {
275                    let move_vector = {
276                        if direction == Direction::North {
277                            Vector::new(0, -magnitude)
278                        } else if direction == Direction::West {
279                            Vector::new(-magnitude, 0)
280                        } else {
281                            Vector::new(0, 0)
282                        }
283                    };
284
285                    let resize_vector = {
286                        if direction == Direction::North || direction == Direction::South {
287                            Vector::new(0, magnitude)
288                        } else if direction == Direction::West || direction == Direction::East {
289                            Vector::new(magnitude, 0)
290                        } else {
291                            Vector::new(0, 0)
292                        }
293                    };
294
295                    let new_size = self.get_size().sized(resize_vector);
296                    self.set_size(new_size, sa);
297                    self.move_with_contents(move_vector);
298                }
299                Mobility::Anchored => {
300                    if let Some(neighbour) = self.find_neighbouring(direction) {
301                        if neighbour.get_mobility().is_anchored() {
302                            let (mut first, mut second) = {
303                                if direction == Direction::North || direction == Direction::West {
304                                    (neighbour.clone(), self.clone())
305                                } else {
306                                    (self.clone(), neighbour.clone())
307                                }
308                            };
309
310                            let (move_vector, resize_vector) = {
311                                if direction == Direction::North {
312                                    (Vector::new(0, -magnitude), Vector::new(0, magnitude))
313                                } else if direction == Direction::East {
314                                    (Vector::new(magnitude, 0), Vector::new(-magnitude, 0))
315                                } else if direction == Direction::South {
316                                    (Vector::new(0, magnitude), Vector::new(0, -magnitude))
317                                } else if direction == Direction::West {
318                                    (Vector::new(-magnitude, 0), Vector::new(magnitude, 0))
319                                } else {
320                                    (Vector::new(0, 0), Vector::new(0, 0))
321                                }
322                            };
323
324                            first.change_size(resize_vector.opposite(), sa);
325                            second.change_size(resize_vector, sa);
326                            second.move_with_contents(move_vector);
327                        }
328                    } else if let Some(mut parent) = self.get_parent() {
329                        parent.resize(direction, magnitude, sa);
330                    }
331                }
332                Mobility::Docked => {
333                    // Nothing to do
334                }
335            }
336        }
337    }
338
339    fn move_with_contents(&mut self, vector: Vector) {
340        // Update frames position
341        let new_position = self.get_position() + vector.clone();
342        self.set_plumbing_position(new_position);
343    }
344
345    fn destroy_self(&mut self, sa: &mut SurfaceAccess) {
346        self.remove_self(sa);
347        self.destroy();
348    }
349}
350
351// -------------------------------------------------------------------------------------------------