cursive_multiplex/
id.rs

1use crate::error::{AddViewError, RemoveViewError, SwitchError};
2use crate::node::Node;
3use crate::path::SearchPath;
4use crate::{Mux, Orientation, View};
5
6/// Identifier for views in binary tree of mux, typically returned after adding a new view to the multiplexer.
7pub type Id = indextree::NodeId;
8
9impl Mux {
10    /// Removes the given id from the multiplexer, returns an error if not a valid id contained in the tree or the lone root of the tree.
11    /// When successful the Id of the removed Node is returned.
12    /// # Example
13    /// ```
14    /// # fn main () {
15    /// # let mut mux = cursive_multiplex::Mux::new();
16    /// # let node1 = mux.add_right_of(cursive::views::DummyView, mux.root().build().unwrap()).unwrap();
17    /// let new_node = mux.add_below(cursive::views::DummyView, node1).unwrap();
18    /// mux.remove_id(new_node);
19    /// # }
20    /// ```
21    pub fn remove_id(&mut self, id: Id) -> Result<Id, RemoveViewError> {
22        let desc: Vec<Id> = self.root.descendants(&self.tree).collect();
23        if desc.contains(&id) {
24            let sib_id: Id;
25            if id.preceding_siblings(&self.tree).count() > 1 {
26                sib_id = id.preceding_siblings(&self.tree).nth(1).unwrap();
27            } else if id.following_siblings(&self.tree).count() > 1 {
28                sib_id = id.following_siblings(&self.tree).nth(1).unwrap();
29            } else {
30                return Err(RemoveViewError::Generic {});
31            }
32            let parent = id.ancestors(&self.tree).nth(1).unwrap();
33            id.detach(&mut self.tree);
34            self.invalidated = true;
35            if let Some(anker) = parent.ancestors(&self.tree).nth(1) {
36                if anker.children(&self.tree).next().unwrap() == parent {
37                    parent.detach(&mut self.tree);
38                    anker.prepend(sib_id, &mut self.tree);
39                    self.focus = sib_id;
40                    Ok(id)
41                } else {
42                    parent.detach(&mut self.tree);
43                    anker.append(sib_id, &mut self.tree);
44                    self.focus = sib_id;
45                    Ok(id)
46                }
47            } else {
48                self.root = sib_id;
49                self.focus = sib_id;
50                Ok(id)
51            }
52        } else {
53            Err(RemoveViewError::InvalidId { id })
54        }
55    }
56
57    /// Add the given view, below the given Id.
58    /// The new view and the indexed one will share the space previously given to the give Id.
59    /// When successful `Ok()` will contain the assigned `Id`
60    /// # Example
61    /// ```
62    /// # extern crate cursive;
63    /// # fn main () {
64    /// let mut mux = cursive_multiplex::Mux::new();
65    /// let node1 = mux.add_right_of(cursive::views::DummyView, mux.root().build().unwrap()).unwrap();
66    /// let new_node = mux.add_below(cursive::views::DummyView, node1).unwrap();
67    /// # }
68    /// ```
69    pub fn add_below<T>(&mut self, v: T, id: Id) -> Result<Id, AddViewError>
70    where
71        T: View,
72    {
73        self.add_node_id(v, id, Orientation::Vertical, SearchPath::Down)
74    }
75
76    /// Add the given view, above the given Id.
77    /// The new view and the indexed one will share the space previously given to the give Id.
78    /// When successful `Ok()` will contain the assigned `Id`
79    /// # Example
80    /// ```
81    /// # extern crate cursive;
82    /// # fn main () {
83    /// let mut mux = cursive_multiplex::Mux::new();
84    /// let node1 = mux.add_right_of(cursive::views::DummyView, mux.root().build().unwrap()).unwrap();
85    /// let new_node = mux.add_above(cursive::views::DummyView, node1).unwrap();
86    /// # }
87    /// ```
88    pub fn add_above<T>(&mut self, v: T, id: Id) -> Result<Id, AddViewError>
89    where
90        T: View,
91    {
92        self.add_node_id(v, id, Orientation::Vertical, SearchPath::Up)
93    }
94
95    /// Add the given view, left of the given Id.
96    /// The new view and the indexed one will share the space previously given to the give Id.
97    /// When successful `Ok()` will contain the assigned `Id`
98    /// # Example
99    /// ```
100    /// # extern crate cursive;
101    /// # fn main () {
102    /// let mut mux = cursive_multiplex::Mux::new();
103    /// let node1 = mux.add_right_of(cursive::views::DummyView, mux.root().build().unwrap()).unwrap();
104    /// let new_node = mux.add_left_of(cursive::views::DummyView, node1).unwrap();
105    /// # }
106    /// ```
107    pub fn add_left_of<T>(&mut self, v: T, id: Id) -> Result<Id, AddViewError>
108    where
109        T: View,
110    {
111        self.add_node_id(v, id, Orientation::Horizontal, SearchPath::Left)
112    }
113
114    /// Add the given view, right of the given Id.
115    /// The new view and the indexed one will share the space previously given to the give Id.
116    /// When successful `Ok()` will contain the assigned `Id`
117    /// # Example
118    /// ```
119    /// # extern crate cursive;
120    /// # fn main () {
121    /// let mut mux = cursive_multiplex::Mux::new();
122    /// let node1 = mux.add_right_of(cursive::views::DummyView, mux.root().build().unwrap()).unwrap();
123    /// let new_node = mux.add_right_of(cursive::views::DummyView, node1).unwrap();
124    /// # }
125    /// ```
126    pub fn add_right_of<T>(&mut self, v: T, id: Id) -> Result<Id, AddViewError>
127    where
128        T: View,
129    {
130        self.add_node_id(v, id, Orientation::Horizontal, SearchPath::Right)
131    }
132
133    /// Sets the dimensions for partitioning two adjacent panes in the same container.
134    /// ```
135    /// # extern crate cursive;
136    /// # fn main () {
137    /// let mut mux = cursive_multiplex::Mux::new();
138    /// let node1 = mux.add_right_of(cursive::views::DummyView, mux.root().build().unwrap()).unwrap();
139    /// let new_node = mux.add_right_of(cursive::views::DummyView, node1).unwrap();
140    /// mux.set_container_split_ratio(new_node, 0.3).unwrap();
141    /// # }
142    /// ```
143    pub fn set_container_split_ratio<T: Into<f32>>(
144        &mut self,
145        id: Id,
146        input: T,
147    ) -> Result<(), AddViewError> {
148        let ratio = input.into().clamp(0.0, 1.0);
149        if let Some(parent_id) = self
150            .tree
151            .get(id)
152            .ok_or(AddViewError::GenericError {})?
153            .parent()
154        {
155            let parent = self
156                .tree
157                .get_mut(parent_id)
158                .ok_or(AddViewError::GenericError {})?
159                .get_mut();
160            parent.split_ratio = ratio;
161            return Ok(());
162        }
163        Err(AddViewError::GenericError {})
164    }
165
166    fn add_node_id<T>(
167        &mut self,
168        v: T,
169        id: Id,
170        orientation: Orientation,
171        direction: SearchPath,
172    ) -> Result<Id, AddViewError>
173    where
174        T: View,
175    {
176        self.invalidated = true;
177        let new_node = self.tree.new_node(Node::new(v, Orientation::Horizontal));
178
179        let mut node_id;
180        if let Some(parent) = id.ancestors(&self.tree).nth(1) {
181            node_id = parent;
182        } else {
183            node_id = id;
184        }
185
186        if node_id.children(&self.tree).count() < 2
187            && !self.tree.get(node_id).unwrap().get().has_view()
188        {
189            match direction {
190                SearchPath::Up | SearchPath::Left => node_id.prepend(new_node, &mut self.tree),
191                SearchPath::Down | SearchPath::Right => node_id.append(new_node, &mut self.tree),
192            }
193            self.tree.get_mut(node_id).unwrap().get_mut().orientation = orientation;
194        } else {
195            // First element is node itself, second direct parent
196            let parent = node_id;
197            node_id = id;
198
199            let position: SearchPath;
200            if parent.children(&self.tree).next().unwrap() == node_id {
201                position = SearchPath::Left;
202            } else {
203                position = SearchPath::Right;
204            }
205
206            node_id.detach(&mut self.tree);
207
208            let new_intermediate = self
209                .tree
210                .new_node(Node::new_empty(orientation, self.default_split_ratio));
211            match position {
212                SearchPath::Right | SearchPath::Down => {
213                    parent.append(new_intermediate, &mut self.tree);
214                }
215                SearchPath::Left | SearchPath::Up => {
216                    parent.prepend(new_intermediate, &mut self.tree);
217                }
218            }
219            match direction {
220                SearchPath::Up | SearchPath::Left => {
221                    new_intermediate.append(new_node, &mut self.tree);
222                    new_intermediate.append(node_id, &mut self.tree);
223                }
224                SearchPath::Down | SearchPath::Right => {
225                    new_intermediate.append(node_id, &mut self.tree);
226                    new_intermediate.append(new_node, &mut self.tree);
227                }
228            }
229            debug!("Changed order");
230        }
231
232        if self
233            .tree
234            .get_mut(new_node)
235            .unwrap()
236            .get_mut()
237            .take_focus()
238            .is_ok()
239        {
240            // Here we discard the potential callback from the focused view.
241            // Ideally we would bubble it up so it can be processed.
242            self.focus = new_node;
243            debug!("Changed Focus: {}", new_node);
244        }
245        Ok(new_node)
246    }
247
248    /// Allows for position switching of two views, returns error if ids not in multiplexer.
249    /// When successful empty `Ok(())`
250    /// # Example
251    /// ```
252    /// # extern crate cursive;
253    /// # fn main () {
254    /// # let mut mux = cursive_multiplex::Mux::new();
255    /// # let node1 = mux.add_right_of(cursive::views::DummyView, mux.root().build().unwrap()).unwrap();
256    /// let daniel = mux.add_below(cursive::views::DummyView, node1).unwrap();
257    /// let the_cooler_daniel = mux.add_below(cursive::views::DummyView, node1).unwrap();
258    /// // Oops I wanted the cooler daniel in another spot
259    /// mux.switch_views(daniel, the_cooler_daniel);
260    /// # }
261    /// ```
262    pub fn switch_views(&mut self, fst: Id, snd: Id) -> Result<(), SwitchError> {
263        if let Some(parent1) = fst.ancestors(&self.tree).nth(1) {
264            if let Some(parent2) = snd.ancestors(&self.tree).nth(1) {
265                self.invalidated = true;
266                if parent1.children(&self.tree).next().unwrap() == fst {
267                    if parent2.children(&self.tree).next().unwrap() == snd {
268                        fst.detach(&mut self.tree);
269                        snd.detach(&mut self.tree);
270                        parent1.checked_prepend(snd, &mut self.tree)?;
271                        parent2.checked_prepend(fst, &mut self.tree)?;
272                        Ok(())
273                    } else {
274                        fst.detach(&mut self.tree);
275                        snd.detach(&mut self.tree);
276                        parent1.checked_prepend(snd, &mut self.tree)?;
277                        parent2.checked_append(fst, &mut self.tree)?;
278                        Ok(())
279                    }
280                } else if parent2.children(&self.tree).next().unwrap() == snd {
281                    fst.detach(&mut self.tree);
282                    snd.detach(&mut self.tree);
283                    parent1.checked_append(snd, &mut self.tree)?;
284                    parent2.checked_prepend(fst, &mut self.tree)?;
285                    Ok(())
286                } else {
287                    fst.detach(&mut self.tree);
288                    snd.detach(&mut self.tree);
289                    parent1.checked_append(snd, &mut self.tree)?;
290                    parent2.checked_append(fst, &mut self.tree)?;
291                    Ok(())
292                }
293            } else {
294                Err(SwitchError::NoParent { from: snd, to: fst })
295            }
296        } else {
297            Err(SwitchError::NoParent { from: fst, to: snd })
298        }
299    }
300}
301
302#[cfg(test)]
303mod test {
304    use super::Mux;
305    use cursive_core::views::DummyView;
306
307    #[test]
308    fn left_to_right() {
309        let mut mux = Mux::new();
310        let node1 = mux.add_left_of(DummyView, mux.root).unwrap();
311        let node2 = mux.add_left_of(DummyView, node1).unwrap();
312        assert!(mux.switch_views(node1, node2).is_ok());
313    }
314
315    #[test]
316    fn right_to_left() {
317        let mut mux = Mux::new();
318        let node1 = mux.add_right_of(DummyView, mux.root).unwrap();
319        let node2 = mux.add_left_of(DummyView, node1).unwrap();
320        assert!(mux.switch_views(node2, node1).is_ok());
321    }
322}