fltk_evented/
blocking.rs

1use crate::base::BaseListener;
2use fltk::enums::Event;
3use fltk::prelude::{WidgetBase, WidgetExt};
4use std::cell::{Cell, RefCell};
5use std::collections::HashMap;
6use std::rc::Rc;
7
8type EventMap<T> = HashMap<i32, Option<Box<dyn FnMut(&mut T)>>>;
9
10#[derive(Clone)]
11pub struct Trig<T> {
12    triggered: Rc<Cell<bool>>,
13    event: Rc<Cell<Event>>,
14    events: Rc<RefCell<EventMap<T>>>,
15}
16
17/// The blocking widget listener recieves both `triggered: bool` from [`Listener<T>::triggered()`],
18/// and [`Event`] from [`Listener<T>::event()`].
19pub type Listener<T> = BaseListener<T, Trig<T>>;
20
21/// core constructor
22impl<T: WidgetBase + WidgetExt + 'static> From<T> for Listener<T> {
23    fn from(mut wid: T) -> Self {
24        let triggered = Rc::new(Cell::new(false));
25        wid.set_callback({
26            let triggered = triggered.clone();
27            move |_| {
28                triggered.set(true);
29            }
30        });
31        let event = Rc::new(Cell::new(Event::NoEvent));
32        let events: EventMap<T> = HashMap::new();
33        let events = Rc::from(RefCell::from(events));
34        wid.handle({
35            let event = event.clone();
36            let events = events.clone();
37            move |w, evt| {
38                let ret = if !events.borrow().is_empty() {
39                    if let Some(Some(cb)) = events.borrow_mut().get_mut(&(evt.bits())) {
40                        cb(w);
41                        w.redraw();
42                        true
43                    } else {
44                        false
45                    }
46                } else {
47                    event.set(evt);
48                    false
49                };
50                ret
51            }
52        });
53        let trig = Trig {
54            triggered,
55            event,
56            events,
57        };
58        Self { wid, trig }
59    }
60}
61
62/// core implementation
63impl<T: WidgetBase + WidgetExt> Listener<T> {
64    /// Check whether a widget was triggered
65    pub fn triggered(&self) -> bool {
66        self.trig.triggered.replace(false)
67    }
68
69    /// Get an event the widget received,
70    /// returns [`Event::NoEvent`] if no events received
71    pub fn event(&self) -> Event {
72        self.trig.event.replace(Event::NoEvent)
73    }
74
75    /// What the widget should do on a custom event
76    pub fn on(&mut self, ev: Event, cb: impl FnMut(&mut T) + 'static) {
77        self.trig
78            .events
79            .borrow_mut()
80            .insert(ev.bits(), Some(Box::new(cb)));
81    }
82
83    /// What the widget should do on hover
84    pub fn on_hover(&mut self, cb: impl FnMut(&mut T) + 'static) {
85        self.on(Event::Enter, cb);
86    }
87
88    /// What the widget should do on leave
89    pub fn on_leave(&mut self, cb: impl FnMut(&mut T) + 'static) {
90        self.on(Event::Leave, cb);
91    }
92
93    /// What the widget should do on click
94    pub fn on_click(&mut self, cb: impl FnMut(&mut T) + 'static) {
95        self.on(Event::Push, cb);
96    }
97
98    /// What the widget should do on release
99    pub fn on_release(&mut self, cb: impl FnMut(&mut T) + 'static) {
100        self.on(Event::Released, cb);
101    }
102
103    /// What the widget should do on drag
104    pub fn on_drag(&mut self, cb: impl FnMut(&mut T) + 'static) {
105        self.on(Event::Drag, cb);
106    }
107
108    /// What the widget should do on focus
109    pub fn on_focus(&mut self, cb: impl FnMut(&mut T) + 'static) {
110        self.on(Event::Focus, cb);
111    }
112
113    /// What the widget should do on unfocus
114    pub fn on_unfocus(&mut self, cb: impl FnMut(&mut T) + 'static) {
115        self.on(Event::Unfocus, cb);
116    }
117
118    /// What the widget should do on keydown
119    pub fn on_keydown(&mut self, cb: impl FnMut(&mut T) + 'static) {
120        self.on(Event::KeyDown, cb);
121    }
122
123    /// What the widget should do on keyup
124    pub fn on_keyup(&mut self, cb: impl FnMut(&mut T) + 'static) {
125        self.on(Event::KeyUp, cb);
126    }
127
128    /// What the widget should do on close
129    pub fn on_close(&mut self, cb: impl FnMut(&mut T) + 'static) {
130        self.on(Event::Close, cb);
131    }
132
133    /// What the widget should do on move
134    pub fn on_move(&mut self, cb: impl FnMut(&mut T) + 'static) {
135        self.on(Event::Move, cb);
136    }
137
138    /// What the widget should do on shortcut
139    pub fn on_shortcut(&mut self, cb: impl FnMut(&mut T) + 'static) {
140        self.on(Event::Shortcut, cb);
141    }
142
143    /// What the widget should do on deactivate
144    pub fn on_deactivate(&mut self, cb: impl FnMut(&mut T) + 'static) {
145        self.on(Event::Deactivate, cb);
146    }
147
148    /// What the widget should do on activate
149    pub fn on_activate(&mut self, cb: impl FnMut(&mut T) + 'static) {
150        self.on(Event::Activate, cb);
151    }
152
153    /// What the widget should do on hide
154    pub fn on_hide(&mut self, cb: impl FnMut(&mut T) + 'static) {
155        self.on(Event::Hide, cb);
156    }
157
158    /// What the widget should do on show
159    pub fn on_show(&mut self, cb: impl FnMut(&mut T) + 'static) {
160        self.on(Event::Show, cb);
161    }
162
163    /// What the widget should do on paste
164    pub fn on_paste(&mut self, cb: impl FnMut(&mut T) + 'static) {
165        self.on(Event::Paste, cb);
166    }
167
168    /// What the widget should do on selection_clear
169    pub fn on_selection_clear(&mut self, cb: impl FnMut(&mut T) + 'static) {
170        self.on(Event::SelectionClear, cb);
171    }
172
173    /// What the widget should do on mousewheel
174    pub fn on_mousewheel(&mut self, cb: impl FnMut(&mut T) + 'static) {
175        self.on(Event::MouseWheel, cb);
176    }
177
178    /// What the widget should do on dnd_enter
179    pub fn on_dnd_enter(&mut self, cb: impl FnMut(&mut T) + 'static) {
180        self.on(Event::DndEnter, cb);
181    }
182
183    /// What the widget should do on dnd_drag
184    pub fn on_dnd_drag(&mut self, cb: impl FnMut(&mut T) + 'static) {
185        self.on(Event::DndDrag, cb);
186    }
187
188    /// What the widget should do on dnd_leave
189    pub fn on_dnd_leave(&mut self, cb: impl FnMut(&mut T) + 'static) {
190        self.on(Event::DndLeave, cb);
191    }
192
193    /// What the widget should do on dnd_release
194    pub fn on_dnd_release(&mut self, cb: impl FnMut(&mut T) + 'static) {
195        self.on(Event::DndRelease, cb);
196    }
197
198    /// What the widget should do on screen_config_changed
199    pub fn on_screen_config_changed(&mut self, cb: impl FnMut(&mut T) + 'static) {
200        self.on(Event::ScreenConfigChanged, cb);
201    }
202
203    /// What the widget should do on fullscreen
204    pub fn on_fullscreen(&mut self, cb: impl FnMut(&mut T) + 'static) {
205        self.on(Event::Fullscreen, cb);
206    }
207
208    /// What the widget should do on zoom_gesture
209    pub fn on_zoom_gesture(&mut self, cb: impl FnMut(&mut T) + 'static) {
210        self.on(Event::ZoomGesture, cb);
211    }
212
213    /// What the widget should do on zoom
214    pub fn on_zoom(&mut self, cb: impl FnMut(&mut T) + 'static) {
215        self.on(Event::ZoomEvent, cb);
216    }
217
218    /// What the widget should do on resize
219    pub fn on_resize(&mut self, cb: impl FnMut(&mut T) + 'static) {
220        self.on(Event::Resize, cb);
221    }
222}