cursive_core/view/view_trait.rs
1use crate::direction::Direction;
2use crate::event::{AnyCb, Event, EventResult};
3use crate::rect::Rect;
4use crate::view::{AnyView, Selector};
5use crate::Printer;
6use crate::Vec2;
7use std::any::Any;
8
9/// Error indicating a view was not found.
10#[derive(Debug)]
11pub struct ViewNotFound;
12
13/// Error indicating a view could not take focus.
14#[derive(Debug)]
15pub struct CannotFocus;
16
17impl std::fmt::Display for ViewNotFound {
18 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
19 write!(f, "View could not be found")
20 }
21}
22
23impl std::fmt::Display for CannotFocus {
24 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
25 write!(f, "View does not take focus")
26 }
27}
28
29impl std::error::Error for ViewNotFound {}
30
31/// Main trait defining a view behaviour.
32///
33/// This is what you should implement to define a custom View.
34pub trait View: Any + AnyView + Send + Sync {
35 /// Draws the view with the given printer (includes bounds) and focus.
36 ///
37 /// This is the only *required* method to implement.
38 fn draw(&self, printer: &Printer);
39
40 /// Called once the size for this view has been decided.
41 ///
42 /// It can be used to pre-compute the configuration of child views.
43 ///
44 /// View groups should propagate the information to their children.
45 ///
46 /// At this point, the given size is final and cannot be negotiated.
47 /// It is guaranteed to be the size available for the call to `draw()`.
48 fn layout(&mut self, _: Vec2) {}
49
50 /// Should return `true` if the view content changed since the last call
51 /// to `layout()`.
52 ///
53 /// This is mostly an optimisation for views where the layout phase is
54 /// expensive.
55 ///
56 /// * Views can ignore it and always return true (default implementation).
57 /// They will always be assumed to have changed.
58 /// * View Groups can ignore it and always re-layout their children.
59 /// * If they call `required_size` or `layout` with stable parameters,
60 /// the children may cache the result themselves and speed up the
61 /// process anyway.
62 fn needs_relayout(&self) -> bool {
63 true
64 }
65
66 /// Returns the minimum size the view requires with the given restrictions.
67 ///
68 /// This is the main way a view communicate its size to its parent.
69 ///
70 /// Some views have a fixed size, and will ignore the `constraint`
71 /// parameter entirely.
72 ///
73 /// Some views are flexible, and may adapt fully or partially to the
74 /// constraints.
75 ///
76 /// Default implementation always return `(1,1)`.
77 fn required_size(&mut self, constraint: Vec2) -> Vec2 {
78 let _ = constraint;
79 Vec2::new(1, 1)
80 }
81
82 /// Called when an event is received (key press, mouse event, ...).
83 ///
84 /// You can return an `EventResult`:
85 /// * `EventResult::Ignored` means the event was not processed and may be
86 /// sent to another view.
87 /// * `EventResult::Consumed` means the event was consumed and should not
88 /// be sent to any other view. It may in addition include a callback
89 /// to be run.
90 ///
91 /// The default implementation just ignores any event.
92 fn on_event(&mut self, _: Event) -> EventResult {
93 EventResult::Ignored
94 }
95
96 /// Runs a closure on the view identified by the given selector.
97 ///
98 /// See [`Finder::call_on`] for a nicer interface, implemented for all
99 /// views.
100 ///
101 /// [`Finder::call_on`]: crate::view::Finder::call_on
102 ///
103 /// If the selector doesn't find a match, the closure will not be run.
104 ///
105 /// View groups should implement this to forward the call to each children.
106 ///
107 /// Default implementation is a no-op.
108 fn call_on_any(&mut self, _: &Selector, _: AnyCb) {}
109
110 /// Moves the focus to the view identified by the given selector.
111 ///
112 /// Returns `Ok(_)` if the view was found and selected.
113 /// A callback may be included, it should be run on `&mut Cursive`.
114 ///
115 /// Default implementation simply returns `Err(ViewNotFound)`.
116 fn focus_view(&mut self, _: &Selector) -> Result<EventResult, ViewNotFound> {
117 Err(ViewNotFound)
118 }
119
120 /// Attempt to give this view the focus.
121 ///
122 /// `source` indicates where the focus comes from.
123 /// When the source is unclear (for example mouse events),
124 /// `Direction::none()` can be used.
125 ///
126 /// Returns `Ok(_)` if the focus was taken.
127 /// Returns `Err(_)` if this view does not take focus (default implementation).
128 fn take_focus(&mut self, source: Direction) -> Result<EventResult, CannotFocus> {
129 let _ = source;
130
131 Err(CannotFocus)
132 }
133
134 /// What part of the view is important and should be visible?
135 ///
136 /// When only part of this view can be visible, this helps
137 /// determine which part.
138 ///
139 /// It is given the view size (same size given to `layout`).
140 ///
141 /// Default implementation return the entire view.
142 fn important_area(&self, view_size: Vec2) -> Rect {
143 Rect::from_size((0, 0), view_size)
144 }
145
146 /// Returns the type of this view.
147 ///
148 /// Useful when you have a `&dyn View`.
149 ///
150 /// View implementation don't usually have to override this.
151 fn type_name(&self) -> &'static str {
152 std::any::type_name::<Self>()
153 }
154}
155
156impl dyn View {
157 /// Attempts to downcast `self` to a concrete type.
158 pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
159 self.as_any().downcast_ref()
160 }
161
162 /// Attempts to downcast `self` to a concrete type.
163 pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
164 self.as_any_mut().downcast_mut()
165 }
166
167 /// Attempts to downcast `Box<Self>` to a concrete type.
168 pub fn downcast<T: Any>(self: Box<Self>) -> Result<Box<T>, Box<Self>> {
169 // Do the check here + unwrap, so the error
170 // value is `Self` and not `dyn Any`.
171 if self.as_any().is::<T>() {
172 Ok(self.as_boxed_any().downcast().unwrap())
173 } else {
174 Err(self)
175 }
176 }
177
178 /// Checks if this view is of type `T`.
179 pub fn is<T: Any>(&self) -> bool {
180 self.as_any().is::<T>()
181 }
182}