Skip to main content

wxdragon/event/
window_events.rs

1//! Window-level events that are common to all widgets.
2
3use crate::event::event_data::{KeyEventData, MouseEventData};
4use crate::event::{Event, EventType};
5use crate::geometry::Size;
6use std::fmt::Debug;
7use wxdragon_sys as ffi;
8
9/// Base window events that are common to all widgets
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub enum WindowEvent {
12    // Mouse events
13    LeftDown,
14    LeftUp,
15    RightDown,
16    RightUp,
17    MiddleDown,
18    MiddleUp,
19    Motion,
20    MouseWheel,
21    EnterWindow,
22    LeaveWindow,
23
24    // Keyboard events
25    KeyDown,
26    KeyUp,
27    Char,
28
29    // Window events
30    Size,
31    Move, // Now implemented in C++ layer
32    Paint,
33    Erase,     // Now implemented in C++ layer
34    SetFocus,  // Now implemented in C++ layer
35    KillFocus, // Now implemented in C++ layer
36    Activate,  // Now implemented in C++ layer
37
38    // Misc events
39    Idle,
40    Close,
41    Destroy,
42}
43
44/// Data for window events that can be converted to appropriate specific event type
45#[derive(Debug)]
46pub enum WindowEventData {
47    MouseButton(MouseButtonEvent),
48    MouseMotion(MouseMotionEvent),
49    MouseEnter(MouseEnterEvent),
50    MouseLeave(MouseLeaveEvent),
51    Keyboard(KeyboardEvent),
52    Size(WindowSizeEvent),
53    Idle(IdleEventData),
54    Activate(ActivateEventData),
55    General(Event),
56}
57
58impl WindowEventData {
59    /// Create a new WindowEventData from an Event, based on the event type
60    pub fn new(event: Event) -> Self {
61        // Replace the unsafe block with a direct call
62        let win_event = event._as_ptr();
63        if win_event.is_null() {
64            return WindowEventData::General(event);
65        }
66
67        // Check for mouse button events
68        if unsafe { wxdragon_sys::wxd_IsMouseButtonEvent(win_event) > 0 } {
69            return WindowEventData::MouseButton(MouseButtonEvent::new(event));
70        }
71
72        // Check for mouse motion events
73        if unsafe { wxdragon_sys::wxd_IsMouseMotionEvent(win_event) > 0 } {
74            return WindowEventData::MouseMotion(MouseMotionEvent::new(event));
75        }
76
77        // Check for keyboard events
78        if unsafe { wxdragon_sys::wxd_IsKeyboardEvent(win_event) > 0 } {
79            return WindowEventData::Keyboard(KeyboardEvent::new(event));
80        }
81
82        // Check for size events and mouse enter/leave events
83        if let Some(event_type) = event.get_event_type() {
84            if event_type == EventType::SIZE {
85                return WindowEventData::Size(WindowSizeEvent::new(event));
86            } else if event_type == EventType::ENTER_WINDOW {
87                return WindowEventData::MouseEnter(MouseEnterEvent::new(event));
88            } else if event_type == EventType::LEAVE_WINDOW {
89                return WindowEventData::MouseLeave(MouseLeaveEvent::new(event));
90            } else if event_type == EventType::IDLE {
91                return WindowEventData::Idle(IdleEventData::new(event));
92            } else if event_type == EventType::ACTIVATE {
93                return WindowEventData::Activate(ActivateEventData::new(event));
94            }
95        }
96
97        // Default to general event
98        WindowEventData::General(event)
99    }
100
101    /// Skip this event, allowing it to propagate to parent handlers
102    pub fn skip(&self, skip: bool) {
103        match self {
104            WindowEventData::MouseButton(event) => event.event.skip(skip),
105            WindowEventData::MouseMotion(event) => event.event.skip(skip),
106            WindowEventData::MouseEnter(event) => event.event.skip(skip),
107            WindowEventData::MouseLeave(event) => event.event.skip(skip),
108            WindowEventData::Keyboard(event) => event.event.skip(skip),
109            WindowEventData::Size(event) => event.event.skip(skip),
110            WindowEventData::Idle(event) => event.event.skip(skip),
111            WindowEventData::Activate(event) => event.event.skip(skip),
112            WindowEventData::General(event) => event.skip(skip),
113        }
114    }
115}
116
117/// Mouse button events (left/right/middle click, up/down)
118#[derive(Debug)]
119pub struct MouseButtonEvent {
120    pub event: MouseEventData,
121}
122
123impl MouseButtonEvent {
124    pub fn new(event: Event) -> Self {
125        Self {
126            event: MouseEventData::new(event),
127        }
128    }
129
130    pub fn get_position(&self) -> Option<crate::geometry::Point> {
131        self.event.get_position()
132    }
133}
134
135/// Mouse motion events
136#[derive(Debug)]
137pub struct MouseMotionEvent {
138    pub event: MouseEventData,
139}
140
141impl MouseMotionEvent {
142    pub fn new(event: Event) -> Self {
143        Self {
144            event: MouseEventData::new(event),
145        }
146    }
147
148    pub fn get_position(&self) -> Option<crate::geometry::Point> {
149        self.event.get_position()
150    }
151}
152
153/// Mouse enter events
154#[derive(Debug)]
155pub struct MouseEnterEvent {
156    pub event: MouseEventData,
157}
158
159impl MouseEnterEvent {
160    pub fn new(event: Event) -> Self {
161        Self {
162            event: MouseEventData::new(event),
163        }
164    }
165
166    pub fn get_position(&self) -> Option<crate::geometry::Point> {
167        self.event.get_position()
168    }
169}
170
171/// Mouse leave events
172#[derive(Debug)]
173pub struct MouseLeaveEvent {
174    pub event: MouseEventData,
175}
176
177impl MouseLeaveEvent {
178    pub fn new(event: Event) -> Self {
179        Self {
180            event: MouseEventData::new(event),
181        }
182    }
183
184    pub fn get_position(&self) -> Option<crate::geometry::Point> {
185        self.event.get_position()
186    }
187}
188
189/// Keyboard events
190#[derive(Debug)]
191pub struct KeyboardEvent {
192    pub event: KeyEventData,
193}
194
195impl KeyboardEvent {
196    pub fn new(event: Event) -> Self {
197        Self {
198            event: KeyEventData::new(event),
199        }
200    }
201
202    pub fn get_key_code(&self) -> Option<i32> {
203        self.event.get_key_code()
204    }
205
206    pub fn get_unicode_key(&self) -> Option<i32> {
207        self.event.get_unicode_key()
208    }
209
210    /// Check if the Control key is pressed during this key event
211    pub fn control_down(&self) -> bool {
212        self.event.control_down()
213    }
214
215    /// Check if the Shift key is pressed during this key event
216    pub fn shift_down(&self) -> bool {
217        self.event.shift_down()
218    }
219
220    /// Check if the Alt key is pressed during this key event
221    pub fn alt_down(&self) -> bool {
222        self.event.alt_down()
223    }
224
225    /// Check if the Meta key is pressed during this key event (Cmd on macOS, Windows key on Windows)
226    pub fn meta_down(&self) -> bool {
227        self.event.meta_down()
228    }
229
230    /// Check if the platform-specific command key is pressed (Cmd on macOS, Ctrl on Windows/Linux)
231    pub fn cmd_down(&self) -> bool {
232        self.event.cmd_down()
233    }
234}
235
236/// Window size events
237#[derive(Debug)]
238pub struct WindowSizeEvent {
239    pub event: Event,
240}
241
242impl WindowSizeEvent {
243    pub fn new(event: Event) -> Self {
244        Self { event }
245    }
246
247    pub fn get_size(&self) -> Option<Size> {
248        if self.event.is_null() {
249            return None;
250        }
251        let c_size = unsafe { ffi::wxd_SizeEvent_GetSize(self.event.0) };
252        if c_size.width == -1 && c_size.height == -1 {
253            return None;
254        }
255        Some(Size {
256            width: c_size.width,
257            height: c_size.height,
258        })
259    }
260}
261
262/// Idle events
263#[derive(Debug)]
264pub struct IdleEventData {
265    pub event: Event,
266}
267
268impl IdleEventData {
269    pub fn new(event: Event) -> Self {
270        Self { event }
271    }
272
273    /// Request more idle events to be sent.
274    /// When `need_more` is true, the system will continue sending idle events.
275    /// When false, idle events will stop until triggered by other activity.
276    pub fn request_more(&self, need_more: bool) {
277        self.event.request_more(need_more);
278    }
279
280    /// Returns true if more idle events have been requested.
281    pub fn more_requested(&self) -> bool {
282        self.event.more_requested()
283    }
284}
285
286/// Activate events (window gaining or losing focus at the OS level)
287#[derive(Debug)]
288pub struct ActivateEventData {
289    pub event: Event,
290}
291
292impl ActivateEventData {
293    pub fn new(event: Event) -> Self {
294        Self { event }
295    }
296
297    /// Returns true if the window is being activated, false if deactivated.
298    pub fn is_active(&self) -> bool {
299        if self.event.is_null() {
300            return false;
301        }
302        unsafe { wxdragon_sys::wxd_ActivateEvent_IsActive(self.event._as_ptr()) }
303    }
304}
305
306// Use the macro to implement the trait
307crate::implement_category_event_handlers!(
308    WindowEvents, WindowEvent, WindowEventData,
309    LeftDown => mouse_left_down, EventType::LEFT_DOWN,
310    LeftUp => mouse_left_up, EventType::LEFT_UP,
311    RightDown => mouse_right_down, EventType::RIGHT_DOWN,
312    RightUp => mouse_right_up, EventType::RIGHT_UP,
313    MiddleDown => mouse_middle_down, EventType::MIDDLE_DOWN,
314    MiddleUp => mouse_middle_up, EventType::MIDDLE_UP,
315    Motion => mouse_motion, EventType::MOTION,
316    MouseWheel => mouse_wheel, EventType::MOUSEWHEEL,
317    EnterWindow => mouse_enter, EventType::ENTER_WINDOW,
318    LeaveWindow => mouse_leave, EventType::LEAVE_WINDOW,
319    KeyDown => key_down, EventType::KEY_DOWN,
320    KeyUp => key_up, EventType::KEY_UP,
321    Char => char, EventType::CHAR,
322    Size => size, EventType::SIZE,
323    Move => move_event, EventType::MOVE,
324    Paint => paint, EventType::PAINT,
325    Erase => erase_background, EventType::ERASE,
326    SetFocus => set_focus, EventType::SET_FOCUS,
327    KillFocus => kill_focus, EventType::KILL_FOCUS,
328    Activate => activate, EventType::ACTIVATE,
329    Idle => idle, EventType::IDLE,
330    Close => close, EventType::CLOSE_WINDOW,
331    Destroy => destroy, EventType::DESTROY
332);