cursive_extras/views/advanced/
button.rs1use super::ButtonContent;
2use cursive_core::{
3 Cursive, impl_enabled,
4 Printer, Vec2, View, Rect,
5 direction::Direction,
6 view::CannotFocus,
7 event::{
8 Callback,
9 Event,
10 EventResult,
11 Key,
12 MouseButton,
13 MouseEvent
14 },
15 utils::markup::StyledString
16};
17use rust_utils::encapsulated;
18
19#[derive(Clone)]
21#[encapsulated]
22pub struct AdvancedButton<D: Send + Sync + 'static = ()> {
23 title: ButtonContent,
25
26 callback: Callback,
28
29 enabled: bool,
31
32 has_brackets: bool,
34
35 width: usize,
37
38 #[getter(mutable, doc = "Return a reference to the data")]
40 #[setter(doc = "Set the data")]
41 data: D,
42
43 size_cache: Option<Vec2>
45}
46
47impl AdvancedButton {
48 #[must_use]
50 pub fn new<T: Into<StyledString>, F: Fn(&mut Cursive) + Send + Sync + 'static>(title: T, callback: F) -> AdvancedButton {
51 Self::new_with_data(title, (), callback)
52 }
53}
54
55impl<D: Send + Sync + 'static> AdvancedButton<D> {
56 impl_enabled!(self.enabled);
57
58 #[must_use]
60 pub fn new_with_data<T: Into<StyledString>, F: Fn(&mut Cursive) + Send + Sync + 'static>(title: T, data: D, callback: F) -> AdvancedButton<D> {
61 AdvancedButton {
62 title: ButtonContent::new(title),
63 width: 0,
64 callback: Callback::from_fn(callback),
65 has_brackets: false,
66 enabled: true,
67 data,
68 size_cache: None
69 }
70 }
71
72 pub fn show_brackets(&mut self, show: bool) {
74 self.size_cache = None;
75 self.has_brackets = show;
76 }
77
78 #[must_use]
80 pub fn brackets(mut self) -> Self {
81 self.has_brackets = true;
82 self
83 }
84
85 pub fn title(&self) -> &StyledString { self.title.get_content() }
87
88 pub fn set_title<T: Into<StyledString>>(&mut self, title: T) {
90 self.size_cache = None;
91 self.title.set_content(title);
92 }
93
94 pub fn set_callback<F: Fn(&mut Cursive) + Send + Sync + 'static>(&mut self, callback: F) { self.callback = Callback::from_fn(callback); }
96}
97
98impl<D: Send + Sync + 'static> View for AdvancedButton<D> {
99 fn draw(&self, printer: &Printer) {
100 self.title.draw(printer, (0, 0).into(), self.enabled, printer.focused, self.has_brackets);
101 }
102
103 fn required_size(&mut self, bound: Vec2) -> Vec2 {
104 if let Some(size) = self.size_cache {
105 if self.width > 0 { return size; }
106 }
107 self.title.fit_to_width(bound.x);
108 let size = self.title.size(self.has_brackets);
109 self.width = size.x;
110 size
111 }
112
113 fn layout(&mut self, size: Vec2) {
114 self.size_cache = Some(size);
115 self.title.fit_to_width(size.x);
116 }
117
118 fn on_event(&mut self, event: Event) -> EventResult {
119 if !self.enabled {
120 return EventResult::Ignored;
121 }
122
123 match event {
124 Event::Mouse {
125 event: MouseEvent::Release(MouseButton::Left),
126 position,
127 offset
128 } => {
129 let b_rect = Rect::from_size((0, 0),self.title.size(self.has_brackets));
130
131 if let Some(new_pos) = position.checked_sub(offset) {
132 if b_rect.contains(new_pos) {
133 EventResult::Consumed(Some(self.callback.clone()))
134 }
135 else { EventResult::Ignored }
136 }
137 else { EventResult::Ignored }
138 }
139
140 Event::Key(Key::Enter) => EventResult::Consumed(Some(self.callback.clone())),
141
142 Event::WindowResize => {
143 self.size_cache = None;
144 self.width = 0;
145 EventResult::Ignored
146 }
147
148 _ => EventResult::Ignored,
149 }
150 }
151
152 fn take_focus(&mut self, _: Direction) -> Result<EventResult, CannotFocus> { self.enabled.then(EventResult::consumed).ok_or(CannotFocus) }
153}