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) visible_divider: bool,
26    pub(crate) movable_divider: bool,
27    pub(crate) front: Pane,
28    pub(crate) back: Pane,
29    pub(crate) divider: Option<usize>,
30    pub(crate) needs_relayout: bool,
31    pub(crate) size: Option<Vec2>,
32    pub(crate) focus: Option<WhichPane>,
33    pub(crate) moving_divider: bool,
34    pub(crate) actions: Actions,
35}
36
37impl SplitPanel {
38    /// Constructor.
39    pub fn new(orientation: Orientation) -> Self {
40        Self {
41            orientation,
42            border: true,
43            visible_divider: true,
44            movable_divider: true,
45            front: DummyView.into_boxed_view().into(),
46            back: DummyView.into_boxed_view().into(),
47            divider: None,
48            needs_relayout: true,
49            size: None,
50            focus: None,
51            moving_divider: false,
52            actions: Action::defaults(orientation),
53        }
54    }
55
56    /// Constructor.
57    pub fn horizontal() -> Self {
58        Self::new(Orientation::Horizontal)
59    }
60
61    /// Constructor.
62    pub fn vertical() -> Self {
63        Self::new(Orientation::Vertical)
64    }
65
66    /// Orienation.
67    pub fn orientation(&self) -> Orientation {
68        self.orientation
69    }
70
71    /// Set orientation.
72    pub fn set_orientation(&mut self, orientation: Orientation) {
73        let old_orientation = self.orientation;
74        self.orientation = orientation;
75        if self.orientation != old_orientation {
76            self.needs_relayout = true;
77        }
78    }
79
80    /// Set orientation.
81    ///
82    /// Chainable.
83    pub fn with_orientation(self, orientation: Orientation) -> Self {
84        self.with(|self_| self_.set_orientation(orientation))
85    }
86
87    /// Whether to draw a border.
88    pub fn border(&self) -> bool {
89        self.border
90    }
91
92    /// Set whether to draw a border.
93    pub fn set_border(&mut self, border: bool) {
94        let old_border = self.border;
95        self.border = border;
96        if self.border != old_border {
97            self.needs_relayout = true;
98        }
99    }
100
101    /// Set whether to draw a border.
102    ///
103    /// Chainable.
104    pub fn with_border(self, border: bool) -> Self {
105        self.with(|self_| self_.set_border(border))
106    }
107
108    /// Whether the divider is visible.
109    pub fn visible_divider(&self) -> bool {
110        self.visible_divider
111    }
112
113    /// Set whether the divider is visible.
114    pub fn set_visible_divider(&mut self, visible_divider: bool) {
115        let old_visible_divider = self.border;
116        self.visible_divider = visible_divider;
117        if self.visible_divider != old_visible_divider {
118            self.needs_relayout = true;
119        }
120    }
121
122    /// Set whether the divider is visible.
123    ///
124    /// Chainable.
125    pub fn with_visible_divider(self, visible_divider: bool) -> Self {
126        self.with(|self_| self_.set_visible_divider(visible_divider))
127    }
128
129    /// Whether to allow the divider to move.
130    pub fn movable_divider(&self) -> bool {
131        self.movable_divider
132    }
133
134    /// Set whether to allow the divider to move.
135    pub fn set_movable_divider(&mut self, movable_divider: bool) {
136        self.movable_divider = movable_divider;
137    }
138
139    /// Set whether to allow the divider to move.
140    ///
141    /// Chainable.
142    pub fn with_movable_divider(self, movable_divider: bool) -> Self {
143        self.with(|self_| self_.set_movable_divider(movable_divider))
144    }
145
146    /// View for front panel.
147    pub fn front(&self) -> &dyn View {
148        self.front.view.as_ref()
149    }
150
151    /// View for front panel.
152    pub fn front_mut(&mut self) -> &mut dyn View {
153        self.front.view.as_mut()
154    }
155
156    /// Set view for front panel.
157    pub fn set_front<ViewT>(&mut self, view: ViewT)
158    where
159        ViewT: 'static + IntoBoxedView,
160    {
161        self.front = view.into();
162        self.needs_relayout = true;
163    }
164
165    /// Set view for front panel.
166    ///
167    /// Chainable.
168    pub fn with_front<ViewT>(self, view: ViewT) -> Self
169    where
170        ViewT: 'static + IntoBoxedView,
171    {
172        self.with(|self_| self_.set_front(view))
173    }
174
175    /// View for back panel.
176    pub fn back(&self) -> &dyn View {
177        self.back.view.as_ref()
178    }
179
180    /// View for back panel.
181    pub fn back_mut(&mut self) -> &mut dyn View {
182        self.back.view.as_mut()
183    }
184
185    /// Set view for back panel.
186    pub fn set_back<ViewT>(&mut self, view: ViewT)
187    where
188        ViewT: 'static + IntoBoxedView,
189    {
190        self.back = view.into();
191        self.needs_relayout = true;
192    }
193
194    /// Set view for back panel.
195    ///
196    /// Chainable.
197    pub fn with_back<ViewT>(self, view: ViewT) -> Self
198    where
199        ViewT: 'static + IntoBoxedView,
200    {
201        self.with(|self_| self_.set_back(view))
202    }
203
204    /// The divider position as the distance from the front border.
205    ///
206    /// Returns [None] if not yet set.
207    pub fn divider(&self) -> Option<usize> {
208        self.divider
209    }
210
211    /// Set divider position as the distance from the front border.
212    ///
213    /// Note that if it doesn't fit it will move during layout.
214    pub fn set_divider(&mut self, divider: usize) {
215        let old_divider = self.divider;
216        self.divider = Some(divider);
217        if self.divider != old_divider {
218            self.needs_relayout = true;
219        }
220    }
221
222    /// Set divider position as the distance from the front border.
223    ///
224    /// Note that if it doesn't fit it will move during layout.
225    ///
226    /// Chainable.
227    pub fn with_divider(self, divider: usize) -> Self {
228        self.with(|self_| self_.set_divider(divider))
229    }
230
231    /// Action map.
232    pub fn actions(&self) -> &Actions {
233        &self.actions
234    }
235
236    /// Action map.
237    pub fn actions_mut(&mut self) -> &mut Actions {
238        &mut self.actions
239    }
240
241    /// Set action map.
242    pub fn set_actions(&mut self, actions: Actions) {
243        self.actions = actions;
244    }
245
246    /// Set action map.
247    ///
248    /// Chainable.
249    pub fn with_actions(self, actions: Actions) -> Self {
250        self.with(|self_| self_.set_actions(actions))
251    }
252
253    /// Set action.
254    ///
255    /// Note that actions can be associated with more than one event.
256    pub fn set_action<EventT>(&mut self, action: Action, event: EventT)
257    where
258        EventT: Into<Event>,
259    {
260        self.actions.insert(event.into(), action);
261    }
262
263    /// Set action.
264    ///
265    /// Note that actions can be associated with more than one event.
266    ///
267    /// Chainable.
268    pub fn with_action<EventT>(self, action: Action, event: EventT) -> Self
269    where
270        EventT: Into<Event>,
271    {
272        self.with(|self_| self_.set_action(action, event))
273    }
274
275    /// Remove action.
276    ///
277    /// Will remove all associated events.
278    ///
279    /// Return true if removed.
280    pub fn remove_action(&mut self, action: Action) -> bool {
281        action.remove(&mut self.actions)
282    }
283
284    /// Remove action.
285    ///
286    /// Will remove all associated events.
287    ///
288    /// Chainable.
289    pub fn without_action(self, action: Action) -> Self {
290        self.with(|self_| _ = self_.remove_action(action))
291    }
292}
293
294impl Default for SplitPanel {
295    fn default() -> Self {
296        Self::new(Orientation::Horizontal)
297    }
298}