Skip to main content

cursive_split_panel/
split_panel.rs

1use super::{actions::*, pane::*, which::*};
2
3use cursive::{direction::*, event::*, view::*, views::*, *};
4
5//
6// SplitPanel
7//
8
9/// Split panel.
10///
11/// Contains two panes with an optionally movable divider between them and an optional border.
12/// (Both features are enabled by default.)
13///
14/// Can be oriented horizontally (the default) or vertically.
15///
16/// When [movable_divider](Self::movable_divider) is true will support the following
17/// events (configurable):
18///
19/// * Shift+Left/Shift+Up: move the divider towards the front
20/// * Shift+Right/Shift+Down: move the divider towards the back
21/// * Mouse dragging of the divider
22pub struct SplitPanel {
23    pub(crate) orientation: Orientation,
24    pub(crate) border: bool,
25    pub(crate) movable_divider: bool,
26    pub(crate) front: Pane,
27    pub(crate) back: Pane,
28    pub(crate) divider: Option<usize>,
29    pub(crate) needs_relayout: bool,
30    pub(crate) size: Option<Vec2>,
31    pub(crate) focus: Option<WhichPane>,
32    pub(crate) moving_divider: bool,
33    pub(crate) actions: Actions,
34}
35
36impl SplitPanel {
37    /// Constructor.
38    pub fn new(orientation: Orientation) -> Self {
39        Self {
40            orientation,
41            border: true,
42            movable_divider: true,
43            front: DummyView.into_boxed_view().into(),
44            back: DummyView.into_boxed_view().into(),
45            divider: None,
46            needs_relayout: true,
47            size: None,
48            focus: None,
49            moving_divider: false,
50            actions: Action::defaults(orientation),
51        }
52    }
53
54    /// Constructor.
55    pub fn horizontal() -> Self {
56        Self::new(Orientation::Horizontal)
57    }
58
59    /// Constructor.
60    pub fn vertical() -> Self {
61        Self::new(Orientation::Vertical)
62    }
63
64    /// Orienation.
65    pub fn orientation(&self) -> Orientation {
66        self.orientation
67    }
68
69    /// Set orientation.
70    pub fn set_orientation(&mut self, orientation: Orientation) {
71        let old_orientation = self.orientation;
72        self.orientation = orientation;
73        if self.orientation != old_orientation {
74            self.needs_relayout = true;
75        }
76    }
77
78    /// Set orientation.
79    ///
80    /// Chainable.
81    pub fn with_orientation(self, orientation: Orientation) -> Self {
82        self.with(|self_| self_.set_orientation(orientation))
83    }
84
85    /// Whether to draw a border.
86    pub fn border(&self) -> bool {
87        self.border
88    }
89
90    /// Set whether to draw a border.
91    pub fn set_border(&mut self, border: bool) {
92        let old_border = self.border;
93        self.border = border;
94        if self.border != old_border {
95            self.needs_relayout = true;
96        }
97    }
98
99    /// Set whether to draw a border.
100    ///
101    /// Chainable.
102    pub fn with_border(self, border: bool) -> Self {
103        self.with(|self_| self_.set_border(border))
104    }
105
106    /// Whether to allow the divider to move.
107    pub fn movable_divider(&self) -> bool {
108        self.movable_divider
109    }
110
111    /// Set whether to allow the divider to move.
112    pub fn set_movable_divider(&mut self, movable_divider: bool) {
113        self.movable_divider = movable_divider;
114    }
115
116    /// Set whether to allow the divider to move.
117    ///
118    /// Chainable.
119    pub fn with_movable_divider(self, movable_divider: bool) -> Self {
120        self.with(|self_| self_.set_movable_divider(movable_divider))
121    }
122
123    /// View for front panel.
124    pub fn front(&self) -> &dyn View {
125        self.front.view.as_ref()
126    }
127
128    /// View for front panel.
129    pub fn front_mut(&mut self) -> &mut dyn View {
130        self.front.view.as_mut()
131    }
132
133    /// Set view for front panel.
134    pub fn set_front<ViewT>(&mut self, view: ViewT)
135    where
136        ViewT: 'static + IntoBoxedView,
137    {
138        self.front = view.into();
139        self.needs_relayout = true;
140    }
141
142    /// Set view for front panel.
143    ///
144    /// Chainable.
145    pub fn with_front<ViewT>(self, view: ViewT) -> Self
146    where
147        ViewT: 'static + IntoBoxedView,
148    {
149        self.with(|self_| self_.set_front(view))
150    }
151
152    /// View for back panel.
153    pub fn back(&self) -> &dyn View {
154        self.back.view.as_ref()
155    }
156
157    /// View for back panel.
158    pub fn back_mut(&mut self) -> &mut dyn View {
159        self.back.view.as_mut()
160    }
161
162    /// Set view for back panel.
163    pub fn set_back<ViewT>(&mut self, view: ViewT)
164    where
165        ViewT: 'static + IntoBoxedView,
166    {
167        self.back = view.into();
168        self.needs_relayout = true;
169    }
170
171    /// Set view for back panel.
172    ///
173    /// Chainable.
174    pub fn with_back<ViewT>(self, view: ViewT) -> Self
175    where
176        ViewT: 'static + IntoBoxedView,
177    {
178        self.with(|self_| self_.set_back(view))
179    }
180
181    /// The divider position as the distance from the front border.
182    ///
183    /// Returns [None] if not yet set.
184    pub fn divider(&self) -> Option<usize> {
185        self.divider
186    }
187
188    /// Set divider position as the distance from the front border.
189    ///
190    /// Note that if it doesn't fit it will move during layout.
191    pub fn set_divider(&mut self, divider: usize) {
192        let old_divider = self.divider;
193        self.divider = Some(divider);
194        if self.divider != old_divider {
195            self.needs_relayout = true;
196        }
197    }
198
199    /// Set divider position as the distance from the front border.
200    ///
201    /// Note that if it doesn't fit it will move during layout.
202    ///
203    /// Chainable.
204    pub fn with_divider(self, divider: usize) -> Self {
205        self.with(|self_| self_.set_divider(divider))
206    }
207
208    /// Action map.
209    pub fn actions(&self) -> &Actions {
210        &self.actions
211    }
212
213    /// Action map.
214    pub fn actions_mut(&mut self) -> &mut Actions {
215        &mut self.actions
216    }
217
218    /// Set action map.
219    pub fn set_actions(&mut self, actions: Actions) {
220        self.actions = actions;
221    }
222
223    /// Set action map.
224    ///
225    /// Chainable.
226    pub fn with_actions(self, actions: Actions) -> Self {
227        self.with(|self_| self_.set_actions(actions))
228    }
229
230    /// Set action.
231    pub fn set_action(&mut self, action: Action, event: Event) {
232        self.actions.insert(event, action);
233    }
234
235    /// Set action.
236    ///
237    /// Chainable.
238    pub fn with_action(self, action: Action, event: Event) -> Self {
239        self.with(|self_| self_.set_action(action, event))
240    }
241
242    /// Remove action.
243    ///
244    /// Return true if removed.
245    pub fn remove_action(&mut self, action: Action) -> bool {
246        action.remove(&mut self.actions)
247    }
248
249    /// Remove action.
250    ///
251    /// Chainable.
252    pub fn without_action(self, action: Action) -> Self {
253        self.with(|self_| _ = self_.remove_action(action))
254    }
255}
256
257impl Default for SplitPanel {
258    fn default() -> Self {
259        Self::new(Orientation::Horizontal)
260    }
261}