native_windows_gui/events.rs
1//! All the events that can be dispatched by the built-in controls of native-windows-gui
2
3
4#[derive(Clone, Copy, Debug, PartialEq, Eq)]
5#[repr(u8)]
6pub enum MousePressEvent {
7 MousePressLeftUp,
8 MousePressLeftDown,
9 MousePressRightUp,
10 MousePressRightDown
11}
12
13/// Events are identifiers that are sent by controls on user interaction
14/// Some events also have data that can be further processed by the event loop. See `EventData`
15#[derive(Clone, Copy, Debug, PartialEq, Eq)]
16#[repr(usize)]
17pub enum Event {
18 /// Undefined / not implemented event. This can be dispatched by the bigger controls such as ListView and TreeView
19 Unknown,
20
21 /// Generic mouse press events that can be generated by most window controls
22 OnMousePress(MousePressEvent),
23
24 /// Generic mouse move event that can be generated by most window controls
25 OnMouseMove,
26
27 /// Generic mouse wheel event that can be generated by most window controls
28 /// Read the delta value with `EventData::OnMouseWheel` to check which key.
29 OnMouseWheel,
30
31 /// Generic window event when the user right clicks a window
32 OnContextMenu,
33
34 /// When a top level window control is created.
35 OnInit,
36
37 /// When a control needs to be redrawn
38 OnPaint,
39
40 /// When a key is pressed on a keyboard. Unlike OnKeyDown, this returns a char (ex: 'c') in a EventData::OnChar.
41 OnChar,
42
43 /// When a key is pressed on a keyboard. Use `EventData::OnKey` to check which key.
44 OnKeyPress,
45
46 /// When a key is released on a keyboard. Use EventData::OnKey to check which key.
47 OnKeyRelease,
48
49 /// When a system key is pressed on a keyboard. Use `EventData::OnKey` to check which key.
50 OnSysKeyPress,
51
52 /// When a system key is released on a keyboard. Use EventData::OnKey to check which key.
53 OnSysKeyRelease,
54
55 /// When Enter is pressed.
56 OnKeyEnter,
57
58 /// When Esc key is pressed.
59 OnKeyEsc,
60
61 /// Sent to a window when the size or position of the window is about to change.
62 /// An application can use the event data `EventData::OnMinMaxInfo` to override the minimum or maximum size.
63 OnMinMaxInfo,
64
65 /// When a control is resized by the user.
66 /// This is typically applied to top level windows but it also applies to children when layouts are used.
67 OnResize,
68
69 /// When a control is about to be resized by the user.
70 /// This does not trigger on maximize
71 OnResizeBegin,
72
73 /// When a control stops being resized
74 /// This does not trigger on maximize
75 OnResizeEnd,
76
77 // When a window control is maximized
78 OnWindowMaximize,
79
80 // When a window control is minimized
81 OnWindowMinimize,
82
83 /// When a control is moved by the user. This is typically applied to top level windows.
84 /// This is typically applied to top level windows but it also applies to children when layouts are used.
85 OnMove,
86
87 /// When a bar-like control value is changed.
88 OnVerticalScroll,
89
90 /// When a bar-like control value is changed.
91 OnHorizontalScroll,
92
93 /// When a file is dropped into a control
94 OnFileDrop,
95
96 /// When a button is clicked. Similar to a MouseUp event, but only for button control
97 OnButtonClick,
98
99 /// When a button is clicked twice rapidly
100 OnButtonDoubleClick,
101
102 /// When a label is clicked
103 OnLabelClick,
104
105 /// When a label is clicked twice rapidly
106 OnLabelDoubleClick,
107
108 /// When an ImageFrame is clicked
109 OnImageFrameClick,
110
111 /// When an ImageFrame is clicked twice rapidly
112 OnImageFrameDoubleClick,
113
114 /// When TextInput value is changed
115 OnTextInput,
116
117 /// When the list of a combobox is closed
118 OnComboBoxClosed,
119
120 /// When the list of a combobox is about to be visible
121 OnComboBoxDropdown,
122
123 /// When the current selection of the combobox was changed
124 OnComboxBoxSelection,
125
126 /// When the date select dropdown is expanded
127 OnDatePickerDropdown,
128
129 /// When the date select dropdown is closed
130 OnDatePickerClosed,
131
132 /// When the value of the date select is changed
133 OnDatePickerChanged,
134
135 /// When an item on a list box is clicked twice
136 OnListBoxDoubleClick,
137
138 /// When an item on a list box is selected
139 OnListBoxSelect,
140
141 /// The selected tab of a TabsContainer changed
142 TabsContainerChanged,
143
144 /// The selected tab of a TabsContainer is about to be changed
145 TabsContainerChanging,
146
147 /// When the trackbar thumb is released by the user
148 TrackBarUpdated,
149
150 /// When a menu control is opened
151 OnMenuOpen,
152
153 /// When the user enters the menu modal loop
154 OnMenuEnter,
155
156 /// When the user exits the menu modal loop
157 OnMenuExit,
158
159 /// When a menu is hovered (either through mouse or keyboard)
160 OnMenuHover,
161
162 /// When the user selects on a menu item
163 OnMenuItemSelected,
164
165 /// When the user hovers over a callback tooltip
166 /// The callback will also receive a `EventData::OnTooltipText`
167 OnTooltipText,
168
169 /// When the user has clicked the left mouse button within the control.
170 OnTreeViewClick,
171
172 /// When the user has clicked the left mouse button within the control twice rapidly.
173 OnTreeViewDoubleClick,
174
175 /// When the user has clicked the right mouse button within the control.
176 OnTreeViewRightClick,
177
178 /// When begins in-place editing of the specified item's text.
179 OnTreeViewBeginItemEdit,
180
181 /// When ends the editing of a treeview item's label.
182 OnTreeViewEndItemEdit,
183
184 /// When the control has lost the input focus
185 OnTreeFocusLost,
186
187 /// When the control has acquired the input focus
188 OnTreeFocus,
189
190 /// When an item is removed from the treeview. The item being deleted is passed in `EventData::OnTreeItemDelete`
191 OnTreeItemDelete,
192
193 /// When an item is expanded. Generates a `EventData::OnTreeItemDelete`
194 OnTreeItemExpanded,
195
196 /// When the state of a tree item is changed.
197 OnTreeItemChanged,
198
199 /// When the selected tree item is changed.
200 OnTreeItemSelectionChanged,
201
202 /// When all the items in a list view are destroyed
203 /// Do not add, delete, or rearrange items in the list view while processing this notification code.
204 OnListViewClear,
205
206 /// When an item is about to be removed from the list view
207 /// Do not add, delete, or rearrange items in the list view while processing this notification code.
208 /// Generates an `EventData::ListViewItemIndex`
209 OnListViewItemRemoved,
210
211 /// When a new item is inserted in the list view
212 /// This is only triggered when an ietm is added to a new ROW
213 OnListViewItemInsert,
214
215 /// When an item in the list view is activated by the user
216 /// An item is activated when the user clicks it twice
217 /// Generates an `EventData::ListViewItemIndex`
218 OnListViewItemActivated,
219
220 /// When the user has clicked the left mouse button within the control
221 /// Generates an `EventData::ListViewItemIndex`
222 OnListViewClick,
223
224 /// When the user has clicked the right mouse button within the control
225 /// Generates an `EventData::ListViewItemIndex`
226 OnListViewRightClick,
227
228 /// When the user has clicked the left mouse button within the control twice rapidly
229 /// Generates an `EventData::ListViewItemIndex`
230 OnListViewDoubleClick,
231
232 /// When the user has clicked the left mouse button on ListView header column
233 /// Generates an `EventData::ListViewItemIndex`
234 OnListViewColumnClick,
235
236 /// When an item is selected/unselected in the listview
237 /// See `EventData::OnListViewItemChanged` to differentiate the two
238 OnListViewItemChanged,
239
240 /// When the control has acquired the input focus
241 OnListViewFocus,
242
243 /// When the control has lost the input focus
244 OnListViewFocusLost,
245
246 /// When a TrayNotification info popup (not the tooltip) is shown
247 OnTrayNotificationShow,
248
249 /// When a TrayNotification info popup (not the tooltip) is hidden
250 OnTrayNotificationHide,
251
252 /// When a TrayNotification is closed due to a timeout
253 OnTrayNotificationTimeout,
254
255 /// When a TrayNotification is closed due to a user click
256 OnTrayNotificationUserClose,
257
258 /// When a timer delay is elapsed
259 OnTimerTick,
260
261 /// When a timer end condition is reached
262 OnTimerStop,
263
264 /// When a notice is... noticed
265 OnNotice,
266
267 /// When a user clicks on the X button of a window
268 OnWindowClose,
269}
270
271
272/// Events data sent by the controls.
273#[derive(Debug)]
274pub enum EventData {
275 /// The event has no data
276 NoData,
277
278 /// Sets if the window should be closed after the event
279 OnWindowClose(WindowCloseData),
280
281 /// Contains the default maximized position and dimensions, and the default minimum and maximum tracking sizes.
282 /// An application can override the defaults by setting the members of this event.
283 OnMinMaxInfo(MinMaxInfo),
284
285 /// Sets the text of a tooltip.
286 /// The method `on_tooltip_text` should be used to access the inner data
287 OnTooltipText(ToolTipTextData),
288
289 /// The character entered by a user by an `OnChar` event
290 OnChar(char),
291
292 /// The windows key code entered by a user. See the `nwg::keys` module
293 OnKey(u32),
294
295 /// Hold resources that will most likely be used during painting.
296 OnPaint(PaintData),
297
298 /// The delta value of a mouse wheel event. A positive value indicates that the wheel was rotated to the right;
299 /// a negative value indicates that the wheel was rotated to the left.
300 OnMouseWheel(i32),
301
302 /// The path to one or more files that were dropped in the application
303 OnFileDrop(DropFiles),
304
305 /// The handle to the item being deleted. The item is still valid.
306 #[cfg(feature="tree-view")]
307 OnTreeItemDelete(crate::TreeItem),
308
309 /// The handle to the item being changed.
310 #[cfg(feature="tree-view")]
311 OnTreeItemUpdate{ item: crate::TreeItem, action: crate::TreeItemAction },
312
313 /// When ends the editing of a treeview item's label.
314 #[cfg(feature="tree-view")]
315 OnTreeViewEndItemEdit{ f_cancel: bool, new_text: String },
316
317 /// The handles the the old item and the new item.
318 #[cfg(feature="tree-view")]
319 OnTreeItemSelectionChanged{ old: crate::TreeItem, new: crate::TreeItem },
320
321 /// Row index and column index of the list view item that raised the event
322 /// `row_index` `0xFFF...` means the absence of an item
323 #[cfg(feature="list-view")]
324 OnListViewItemIndex { row_index: usize, column_index: usize },
325
326 /// Row index, column index, and selected state of the list view item that raised the event
327 #[cfg(feature="list-view")]
328 OnListViewItemChanged { row_index: usize, column_index: usize, selected: bool },
329}
330
331impl EventData {
332
333 /// Unwraps event data into a `&PaintData`. Panics if it's not the right type.
334 pub fn on_paint(&self) -> &PaintData {
335 match self {
336 EventData::OnPaint(p) => p,
337 d => panic!("Wrong data type: {:?}", d)
338 }
339 }
340
341 /// Unwraps event data into a `&MinMaxInfo`. Panics if it's not the right type.
342 pub fn on_min_max(&self) -> &MinMaxInfo {
343 match self {
344 EventData::OnMinMaxInfo(i) => i,
345 d => panic!("Wrong data type: {:?}", d)
346 }
347 }
348
349 /// Unwraps event data into a `char`. Panics if it's not the right type.
350 pub fn on_char(&self) -> char {
351 match self {
352 EventData::OnChar(c) => *c,
353 d => panic!("Wrong data type: {:?}", d)
354 }
355 }
356
357 /// Unwraps event data into a `&ToolTipTextData`. Panics if it's not the right type.
358 pub fn on_tooltip_text(&self) -> &ToolTipTextData {
359 match self {
360 EventData::OnTooltipText(d) => d,
361 d => panic!("Wrong data type: {:?}", d)
362 }
363 }
364
365 /// Unwraps event data into a `&DragData`. Panics if it's not the right type.
366 pub fn on_file_drop(&self) -> &DropFiles {
367 match self {
368 EventData::OnFileDrop(d) => d,
369 d => panic!("Wrong data type: {:?}", d)
370 }
371 }
372
373 /// Unwraps event data into the virtual key code for `OnKeyPress` and `OnKeyRelease`
374 pub fn on_key(&self) -> u32 {
375 match self {
376 EventData::OnKey(key) => *key,
377 d => panic!("Wrong data type: {:?}", d)
378 }
379 }
380
381 /// unwraps event data into the removed tree item
382 #[cfg(feature="tree-view")]
383 pub fn on_tree_item_delete(&self) -> &crate::TreeItem {
384 match self {
385 EventData::OnTreeItemDelete(item) => item,
386 d => panic!("Wrong data type: {:?}", d)
387 }
388 }
389
390 /// unwraps event data into the update tree view item and the action
391 #[cfg(feature="tree-view")]
392 pub fn on_tree_item_update(&self) -> (&crate::TreeItem, crate::TreeItemAction) {
393 match self {
394 EventData::OnTreeItemUpdate { item, action } => (item, *action),
395 d => panic!("Wrong data type: {:?}", d)
396 }
397 }
398
399 /// unwraps event data into the removed tree item
400 #[cfg(feature="tree-view")]
401 pub fn on_tree_item_selection_changed(&self) -> (&crate::TreeItem, &crate::TreeItem) {
402 match self {
403 EventData::OnTreeItemSelectionChanged { old, new } => (old, new),
404 d => panic!("Wrong data type: {:?}", d)
405 }
406 }
407
408 /// unwraps event data into f_cancel, new_text.
409 /// f_cancel indicates the editing is cancel or not.
410 /// new_text is the new input text when editing is not cancel.
411 #[cfg(feature="tree-view")]
412 pub fn on_tree_view_end_item_edit(&self) -> (bool, String) {
413 match self {
414 EventData::OnTreeViewEndItemEdit { f_cancel, new_text} => (*f_cancel, new_text.to_string()),
415 d => panic!("Wrong data type: {:?}", d)
416 }
417 }
418
419 /// unwraps event data into the indices of a list view index (row_index, column_index)
420 #[cfg(feature="list-view")]
421 pub fn on_list_view_item_index(&self) -> (usize, usize) {
422 match self {
423 &EventData::OnListViewItemIndex { row_index, column_index } => (row_index, column_index),
424 d => panic!("Wrong data type: {:?}", d)
425 }
426 }
427
428 /// unwraps event data into the indices of a list view index (row_index, column_index, selected)
429 #[cfg(feature="list-view")]
430 pub fn on_list_view_item_changed(&self) -> (usize, usize, bool) {
431 match self {
432 &EventData::OnListViewItemChanged { row_index, column_index, selected} => (row_index, column_index, selected),
433 d => panic!("Wrong data type: {:?}", d)
434 }
435 }
436
437}
438
439//
440// Events data structures
441//
442
443use winapi::um::commctrl::NMTTDISPINFOW;
444use winapi::um::winuser::{PAINTSTRUCT, MINMAXINFO, BeginPaint, EndPaint};
445use winapi::um::shellapi::{HDROP, DragFinish};
446use winapi::shared::windef::{HWND, POINT};
447use std::fmt;
448
449/// A wrapper structure that sets the tooltip text on an `OnTooltipText` callback
450pub struct ToolTipTextData {
451 pub(crate) data: *mut NMTTDISPINFOW
452}
453
454impl ToolTipTextData {
455
456 /// Tells the application to save the text value of the callback
457 /// The `OnTooltipText` will not be called a second time for the associated control
458 pub fn keep(&self, keep: bool) {
459 use ::winapi::um::commctrl::TTF_DI_SETITEM;
460
461 let data = unsafe { &mut *self.data };
462 match keep {
463 true => { data.uFlags |= TTF_DI_SETITEM; },
464 false => { data.uFlags &= !TTF_DI_SETITEM; }
465 }
466 }
467
468 /// Sets the text of the callback. This function will copy the text.
469 /// WINAPI does not easily allow tooltips with more than 79 characters (80 with NULL)
470 /// With a text > 79 characters, this method will do nothing.
471 pub fn set_text<'b>(&self, text: &'b str) {
472 use crate::win32::base_helper::to_utf16;
473 use std::ptr;
474
475 let text_len = text.len();
476 if text_len > 79 {
477 return;
478 }
479
480 self.clear();
481 unsafe {
482 let data = &mut *self.data;
483 let local_text = to_utf16(text);
484 ptr::copy_nonoverlapping(local_text.as_ptr(), data.szText.as_mut_ptr(), text_len);
485 }
486 }
487
488 fn clear(&self) {
489 use winapi::um::winnt::WCHAR;
490 use std::{ptr, mem};
491
492 unsafe {
493 let data = &mut *self.data;
494 ptr::write(&mut data.szText as *mut [WCHAR; 80], mem::zeroed());
495 }
496 }
497
498}
499
500impl fmt::Debug for ToolTipTextData {
501 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
502 write!(f, "ToolTipTextData")
503 }
504}
505
506
507/// Opaque type that manages if a window should be closed after an OnClose event
508pub struct WindowCloseData {
509 pub(crate) data: *mut bool
510}
511
512impl WindowCloseData {
513
514 /// Sets if the window should close after the event
515 pub fn close(&self, value: bool) {
516 unsafe{ *self.data = value; }
517 }
518
519 /// Returns true if the window will close after the event or false otherwise
520 pub fn closing(&self) -> bool {
521 unsafe{ *self.data }
522 }
523}
524
525impl fmt::Debug for WindowCloseData {
526 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
527 write!(f, "WindowCloseData({})", self.closing())
528 }
529}
530
531
532/// Opaque type over a paint event's data
533#[derive(Debug)]
534pub struct PaintData {
535 pub(crate) hwnd: HWND
536}
537
538impl PaintData {
539
540 /// Wrapper over BeginPaint
541 pub fn begin_paint(&self) -> PAINTSTRUCT {
542 unsafe {
543 let mut paint: PAINTSTRUCT = ::std::mem::zeroed();
544 BeginPaint(self.hwnd, &mut paint);
545 paint
546 }
547 }
548
549 /// Wrapper over EndPaint
550 pub fn end_paint(&self, p: &PAINTSTRUCT) {
551 unsafe {
552 EndPaint(self.hwnd, p);
553 }
554 }
555
556}
557
558
559/// Opaque type over one or more dragged files.
560pub struct DropFiles {
561 pub(crate) drop: HDROP,
562}
563
564impl DropFiles {
565
566 /// Retrieves the position of the mouse pointer at the time a file was dropped during a drag-and-drop operation.
567 /// The coordinates are local to the control. Ex: (0, 0) is the top left corner of the control.
568 pub fn point(&self) -> [i32; 2] {
569 use winapi::um::shellapi::DragQueryPoint;
570
571 unsafe {
572 let mut pt = POINT { x: 0, y: 0 };
573 DragQueryPoint(self.drop, &mut pt);
574 [pt.x, pt.y]
575 }
576 }
577
578 /// Return the number of files dropped
579 pub fn len(&self) -> usize {
580 use winapi::um::shellapi::DragQueryFileW;
581 use std::ptr;
582
583 unsafe {
584 DragQueryFileW(self.drop, 0xFFFFFFFF, ptr::null_mut(), 0) as usize
585 }
586 }
587
588 /// Return the files path dropped into the app
589 pub fn files(&self) -> Vec<String> {
590 use winapi::um::shellapi::DragQueryFileW;
591 use crate::win32::base_helper::from_utf16;
592 use std::ptr;
593
594 let len = self.len();
595 let mut files = Vec::with_capacity(len);
596 unsafe {
597 for i in 0..len {
598 // Need to add a +1 here for some reason
599 let buffer_size = (DragQueryFileW(self.drop, i as _, ptr::null_mut(), 0) + 1) as usize;
600
601 let mut buffer: Vec<u16> = Vec::with_capacity(buffer_size);
602 buffer.set_len(buffer_size);
603
604 DragQueryFileW(self.drop, i as _, buffer.as_mut_ptr(), buffer_size as _);
605
606 files.push(from_utf16(&buffer));
607 }
608 }
609
610 files
611 }
612
613}
614
615impl fmt::Debug for DropFiles {
616 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
617 write!(f, "DragData {{ point: {:?}, files: {:?} }}", self.point(), self.files())
618 }
619}
620
621impl Drop for DropFiles {
622
623 fn drop(&mut self) {
624 if !self.drop.is_null() {
625 unsafe { DragFinish(self.drop) }
626 }
627 }
628
629}
630
631
632pub struct MinMaxInfo {
633 pub(crate) inner: *mut MINMAXINFO,
634}
635
636impl MinMaxInfo {
637
638 /// The maximized width and the maximized height of the window. For top-level windows, this value is based on the width of the primary monitor.
639 pub fn set_maximized_size(&self, width: i32, height: i32) {
640 let info = unsafe { &mut *self.inner };
641 let (x, y) = unsafe { crate::win32::high_dpi::logical_to_physical(width as i32, height as i32) };
642 info.ptMaxSize = POINT { x, y };
643 }
644
645 /// Returns the maximized width and the maximized height of the window. For top-level windows, this value is based on the width of the primary monitor.
646 pub fn maximized_size(&self) -> [i32; 2] {
647 let info = unsafe { &mut *self.inner };
648 let (w, h) = unsafe { crate::win32::high_dpi::physical_to_logical(info.ptMaxSize.x, info.ptMaxSize.y) };
649 [w, h]
650 }
651
652 /// Sets the position of the left side of the maximized window and the position of the top of the maximized window. For top-level windows, this value is based on the position of the primary monitor.
653 pub fn set_maximized_pos(&self, x: i32, y: i32) {
654 let info = unsafe { &mut *self.inner };
655 let (x, y) = unsafe { crate::win32::high_dpi::logical_to_physical(x, y) };
656 info.ptMaxPosition = POINT { x, y };
657 }
658
659 /// Returns the position of the left side of the maximized window and the position of the top of the maximized window. For top-level windows, this value is based on the position of the primary monitor.
660 pub fn maximized_pos(&self) -> [i32; 2] {
661 let info = unsafe { &mut *self.inner };
662 let (x, y) = unsafe { crate::win32::high_dpi::physical_to_logical(info.ptMaxPosition.x, info.ptMaxPosition.y) };
663
664 [x, y]
665 }
666
667 /// Sets the maximum size of the window
668 pub fn set_max_size(&self, width: i32, height: i32) {
669 let info = unsafe { &mut *self.inner };
670 let (x, y) = unsafe { crate::win32::high_dpi::logical_to_physical(width, height) };
671 info.ptMaxTrackSize = POINT { x, y };
672 }
673
674 /// Returns the maximum size of the window
675 pub fn max_size(&self) -> [i32; 2] {
676 let info = unsafe { &mut *self.inner };
677 let (w, h) = unsafe { crate::win32::high_dpi::physical_to_logical(info.ptMaxTrackSize.x, info.ptMaxTrackSize.y) };
678 [w, h]
679 }
680
681 /// Sets the maximum size of the window
682 pub fn set_min_size(&self, width: i32, height: i32) {
683 let info = unsafe { &mut *self.inner };
684 let (x, y) = unsafe { crate::win32::high_dpi::logical_to_physical(width as i32, height as i32) };
685 info.ptMinTrackSize = POINT { x, y };
686 }
687
688 /// Returns the minimum size of the window
689 pub fn min_size(&self) -> [i32; 2] {
690 let info = unsafe { &mut *self.inner };
691 let (w, h) = unsafe { crate::win32::high_dpi::physical_to_logical(info.ptMinTrackSize.x, info.ptMinTrackSize.y) };
692 [w, h]
693 }
694}
695
696impl fmt::Debug for MinMaxInfo {
697 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
698 write!(f,
699 "MinMaxInfo {{ maximized_size: {:?}, maximized_pos: {:?}, max_size: {:?}, min_size: {:?} }}",
700 self.maximized_size(), self.maximized_pos(), self.max_size(), self.min_size()
701 )
702 }
703}
704