cognitive_frames/
searching.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 searching functionality for `frames::Frame`.
5
6// -------------------------------------------------------------------------------------------------
7
8use qualia::{Direction, Position, SurfaceId};
9use frame::{Frame, Geometry, Mode};
10
11// -------------------------------------------------------------------------------------------------
12
13/// Extension trait for `Frame` adding more search functionality.
14pub trait Searching {
15    /// Returns first found frame upon which `matcher` returned `true`.
16    fn find(&self, matcher: &Fn(&Frame) -> bool) -> Option<Frame>;
17
18    /// Finds first frame suitable for building.
19    /// Returns `self` if `self` has no surface ID set, its parent otherwise.
20    fn find_buildable(&self) -> Option<Frame>;
21
22    /// Finds first trunk which is `Workspace`.
23    fn find_top(&self) -> Option<Frame>;
24
25    /// Finds frame with given surface ID.
26    fn find_with_sid(&self, sid: SurfaceId) -> Option<Frame>;
27
28    /// Finds leaf frame contained in frame `self` containing `point` or the closest one if `point`
29    /// lies outside `self`.
30    fn find_pointed(&self, point: Position) -> Frame;
31
32    /// Returns neighbour in given planar direction. If parent is not aligned in the direction or
33    /// neighbour is not found returns `None`.
34    fn find_neighbouring(&self, direction: Direction) -> Option<Frame>;
35
36    /// Finds top-most frame bordering with frame `self` in given direction.
37    fn find_contiguous(&self, direction: Direction, distance: u32) -> Option<Frame>;
38
39    /// Find find bottom-most frame bordering with frame `self` in given direction.
40    fn find_adjacent(&self, direction: Direction, distance: u32) -> Option<Frame>;
41}
42
43// -------------------------------------------------------------------------------------------------
44
45impl Searching for Frame {
46    fn find(&self, matcher: &Fn(&Frame) -> bool) -> Option<Frame> {
47        if matcher(self) {
48            Some(self.clone())
49        } else {
50            for subsurface in self.space_iter() {
51                let result = subsurface.find(matcher);
52                if result.is_some() {
53                    return result;
54                }
55            }
56            None
57        }
58    }
59
60    fn find_buildable(&self) -> Option<Frame> {
61        if self.get_sid().is_valid() {
62            self.get_parent()
63        } else {
64            Some(self.clone())
65        }
66    }
67
68    fn find_top(&self) -> Option<Frame> {
69        let mut current = Some(self.clone());
70        loop {
71            current = if let Some(ref frame) = current {
72                if frame.is_top() {
73                    return current.clone();
74                }
75                frame.get_parent()
76            } else {
77                return None;
78            }
79        }
80    }
81
82    fn find_with_sid(&self, sid: SurfaceId) -> Option<Frame> {
83        if self.get_sid() == sid {
84            Some(self.clone())
85        } else {
86            for subsurface in self.time_iter() {
87                let result = subsurface.find_with_sid(sid);
88                if result.is_some() {
89                    return result;
90                }
91            }
92            None
93        }
94    }
95
96    fn find_pointed(&self, mut point: Position) -> Frame {
97        let area = self.get_area().rebased();
98        if self.get_mode() != Mode::Root {
99            point = point.casted(&area);
100        }
101
102        for ref frame in self.time_iter() {
103            let area = frame.get_area();
104            if area.contains(&point) {
105                return if self.get_mode().is_leaf() {
106                           frame.clone()
107                       } else {
108                           frame.find_pointed(point - area.pos)
109                       };
110            }
111        }
112        self.clone()
113    }
114
115    fn find_neighbouring(&self, direction: Direction) -> Option<Frame> {
116        if let Some(parent) = self.get_parent() {
117            if parent.get_geometry() == Geometry::Vertical {
118                if direction == Direction::North {
119                    self.get_prev_space()
120                } else if direction == Direction::South {
121                    self.get_next_space()
122                } else {
123                    None
124                }
125            } else if parent.get_geometry() == Geometry::Horizontal {
126                if direction == Direction::West {
127                    self.get_prev_space()
128                } else if direction == Direction::East {
129                    self.get_next_space()
130                } else {
131                    None
132                }
133            } else if parent.get_geometry() == Geometry::Stacked {
134                if direction == Direction::Begin {
135                    self.get_prev_space()
136                } else if direction == Direction::End {
137                    self.get_next_space()
138                } else {
139                    None
140                }
141            } else {
142                None
143            }
144        } else {
145            None
146        }
147    }
148
149    fn find_contiguous(&self, direction: Direction, distance: u32) -> Option<Frame> {
150        // If distance is zero, this is the last step of recurrence
151        if distance == 0 {
152            return Some(self.clone());
153        }
154
155        // Find new frame which is farther
156        let mut frame = self.find_neighbouring(direction);
157
158        // If there is nothing farther go higher. If it is, decrease distance.
159        let new_distance = if frame.is_some() || (direction == Direction::Up) {
160            distance - 1
161        } else {
162            distance
163        };
164        if frame.is_none() {
165            frame = self.get_parent();
166        }
167
168        if let Some(frame) = frame {
169            // Next recurrence step if possible.
170            if frame.is_top() {
171                None
172            } else {
173                frame.find_contiguous(direction, new_distance)
174            }
175        } else {
176            None
177        }
178    }
179
180    fn find_adjacent(&self, direction: Direction, distance: u32) -> Option<Frame> {
181        // Calculate reference position
182        let point = self.get_area().calculate_center();
183
184        // Search for the frame
185        let mut frame = Some(self.clone());
186        for _ in 0..distance {
187            frame = if let Some(ref frame) = frame {
188                frame.find_contiguous(direction, 1)
189            } else {
190                break;
191            };
192            if direction != Direction::Begin || direction != Direction::End {
193                frame = if let Some(ref frame) = frame {
194                    Some(frame.find_pointed(point - frame.get_area().pos))
195                } else {
196                    break;
197                };
198            }
199        }
200        frame
201    }
202}
203
204// -------------------------------------------------------------------------------------------------