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}