1mod high_dpi {
5 #[allow(deprecated, unused_imports)]
8 pub use nwg::{dpi, scale_factor, set_dpi_awareness};
9
10 #[cfg(not(feature = "nwg_high_dpi"))]
11 pub unsafe fn logical_to_physical(x: i32, y: i32) -> (i32, i32) {
12 (x, y)
13 }
14
15 #[cfg(feature = "nwg_high_dpi")]
16 pub unsafe fn logical_to_physical(x: i32, y: i32) -> (i32, i32) {
17 use muldiv::MulDiv;
18 use windows::Win32::UI::WindowsAndMessaging::USER_DEFAULT_SCREEN_DPI;
19
20 let dpi = dpi();
21 let x = x
22 .mul_div_round(dpi, USER_DEFAULT_SCREEN_DPI as i32)
23 .unwrap_or(x);
24 let y = y
25 .mul_div_round(dpi, USER_DEFAULT_SCREEN_DPI as i32)
26 .unwrap_or(y);
27 (x, y)
28 }
29
30 #[cfg(not(feature = "nwg_high_dpi"))]
31 pub unsafe fn physical_to_logical(x: i32, y: i32) -> (i32, i32) {
32 (x, y)
33 }
34
35 #[cfg(feature = "nwg_high_dpi")]
36 pub unsafe fn physical_to_logical(x: i32, y: i32) -> (i32, i32) {
37 use muldiv::MulDiv;
38 use windows::Win32::UI::WindowsAndMessaging::USER_DEFAULT_SCREEN_DPI;
39
40 let dpi = dpi();
41 let x = x
42 .mul_div_round(USER_DEFAULT_SCREEN_DPI as i32, dpi)
43 .unwrap_or(x);
44 let y = y
45 .mul_div_round(USER_DEFAULT_SCREEN_DPI as i32, dpi)
46 .unwrap_or(y);
47 (x, y)
48 }
49}
50
51mod wh {
52 use windows::{
55 core::PCWSTR,
56 Win32::{
57 Foundation::{BOOL, HWND, LPARAM, POINT, RECT, WPARAM},
58 Graphics::Gdi::{InvalidateRect, ScreenToClient, UpdateWindow, HFONT},
59 UI::{
60 Input::KeyboardAndMouse::{GetFocus, SetFocus},
61 WindowsAndMessaging::{
62 AdjustWindowRectEx, GetClientRect, GetParent, GetWindowLongW, GetWindowRect,
63 GetWindowTextLengthW, GetWindowTextW, SendMessageW, SetWindowPos,
64 SetWindowTextW, ShowWindow, GWL_EXSTYLE, GWL_STYLE, SWP_NOACTIVATE,
65 SWP_NOCOPYBITS, SWP_NOMOVE, SWP_NOOWNERZORDER, SWP_NOSIZE, SWP_NOZORDER,
66 SW_HIDE, SW_SHOW, WINDOW_EX_STYLE, WINDOW_STYLE, WM_GETFONT, WM_SETFONT,
67 WS_DISABLED,
68 },
69 },
70 },
71 };
72
73 use crate::nwg_ext::{from_utf16, to_utf16};
74
75 use super::high_dpi;
76
77 #[inline(always)]
78 #[cfg(target_pointer_width = "64")]
79 pub fn get_window_long(handle: HWND, index: i32) -> isize {
80 use windows::Win32::UI::WindowsAndMessaging::{GetWindowLongPtrW, WINDOW_LONG_PTR_INDEX};
81
82 unsafe { GetWindowLongPtrW(handle, WINDOW_LONG_PTR_INDEX(index)) }
83 }
84
85 #[inline(always)]
86 #[cfg(target_pointer_width = "32")]
87 pub fn get_window_long2(handle: HWND, index: i32) -> i32 {
88 use windows::Win32::UI::WindowsAndMessaging::{GetWindowLongW, WINDOW_LONG_PTR_INDEX};
89 unsafe { GetWindowLongW(handle, WINDOW_LONG_PTR_INDEX(index)) }
90 }
91
92 #[inline(always)]
93 #[cfg(target_pointer_width = "64")]
94 pub fn set_window_long(handle: HWND, index: i32, v: usize) {
95 use windows::Win32::UI::WindowsAndMessaging::{SetWindowLongPtrW, WINDOW_LONG_PTR_INDEX};
96
97 unsafe {
98 SetWindowLongPtrW(handle, WINDOW_LONG_PTR_INDEX(index), v as isize);
99 }
100 }
101
102 #[inline(always)]
103 #[cfg(target_pointer_width = "32")]
104 pub fn set_window_long(handle: HWND, index: i32, v: usize) {
105 use windows::Win32::UI::WindowsAndMessaging::{SetWindowLongW, WINDOW_LONG_PTR_INDEX};
106 unsafe {
107 SetWindowLongW(handle, WINDOW_LONG_PTR_INDEX(index), v as i32);
108 }
109 }
110
111 pub unsafe fn set_window_font(handle: HWND, font_handle: Option<HFONT>, redraw: bool) {
113 let font_handle = font_handle.unwrap_or_default();
114
115 SendMessageW(
116 handle,
117 WM_SETFONT,
118 WPARAM(font_handle.0 as usize),
119 LPARAM(redraw as isize),
120 );
121 }
122
123 pub fn get_window_font(handle: HWND) -> HFONT {
124 unsafe {
125 let h = SendMessageW(handle, WM_GETFONT, WPARAM(0), LPARAM(0));
126 HFONT(h.0 as *mut _)
127 }
128 }
129 pub unsafe fn set_focus(handle: HWND) {
130 _ = SetFocus(handle);
131 }
132
133 pub unsafe fn get_focus(handle: HWND) -> bool {
134 GetFocus() == handle
135 }
136 pub unsafe fn get_window_enabled(handle: HWND) -> bool {
137 let style = get_window_long(handle, GWL_STYLE.0) as u32;
138 (style & WS_DISABLED.0) != WS_DISABLED.0
139 }
140
141 pub unsafe fn set_window_enabled(handle: HWND, enabled: bool) {
142 let old_style = get_window_long(handle, GWL_STYLE.0) as usize;
143 if enabled {
144 set_window_long(handle, GWL_STYLE.0, old_style & (!WS_DISABLED.0 as usize));
145 } else {
146 set_window_long(handle, GWL_STYLE.0, old_style | (WS_DISABLED.0 as usize));
147 }
148
149 let _ = InvalidateRect(handle, None, BOOL::from(true));
151 let _ = UpdateWindow(handle);
152 }
153 pub unsafe fn get_window_text(handle: HWND) -> String {
154 let buffer_size = GetWindowTextLengthW(handle) as usize + 1;
155 if buffer_size == 0 {
156 return String::new();
157 }
158
159 let mut buffer: Vec<u16> = vec![0; buffer_size];
160
161 if GetWindowTextW(handle, &mut buffer) == 0 {
162 String::new()
163 } else {
164 from_utf16(&buffer[..])
165 }
166 }
167 pub unsafe fn set_window_text(handle: HWND, text: &str) {
168 let text = to_utf16(text);
169 let _ = SetWindowTextW(handle, PCWSTR::from_raw(text.as_ptr()));
170 }
171
172 pub unsafe fn set_window_position(handle: HWND, x: i32, y: i32) {
173 nwg::dpi();
174 let (x, y) = high_dpi::logical_to_physical(x, y);
175 let _ = SetWindowPos(
176 handle,
177 HWND::default(),
178 x,
179 y,
180 0,
181 0,
182 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOOWNERZORDER,
183 );
184 }
185 pub unsafe fn get_window_position(handle: HWND) -> (i32, i32) {
186 let mut r = RECT::default();
187 let _ = GetWindowRect(handle, &mut r);
188
189 let parent = GetParent(handle);
190 let (x, y) = if let Ok(parent) = parent {
191 let mut pt = POINT {
192 x: r.left,
193 y: r.top,
194 };
195 let _ = ScreenToClient(parent, &mut pt);
196 (pt.x, pt.y)
197 } else {
198 (r.left, r.top)
199 };
200
201 high_dpi::physical_to_logical(x, y)
202 }
203
204 pub unsafe fn set_window_size(handle: HWND, w: u32, h: u32, fix: bool) {
205 let (mut w, mut h) = high_dpi::logical_to_physical(w as i32, h as i32);
206
207 if fix {
208 let flags = GetWindowLongW(handle, GWL_STYLE) as u32;
209 let ex_flags = GetWindowLongW(handle, GWL_EXSTYLE) as u32;
210 let mut rect = RECT {
211 left: 0,
212 top: 0,
213 right: w,
214 bottom: h,
215 };
216 let _ = AdjustWindowRectEx(
217 &mut rect,
218 WINDOW_STYLE(flags),
219 BOOL::from(false),
220 WINDOW_EX_STYLE(ex_flags),
221 );
222
223 w = rect.right - rect.left;
224 h = rect.bottom - rect.top;
225 }
226
227 let _ = SetWindowPos(
228 handle,
229 HWND::default(),
230 0,
231 0,
232 w,
233 h,
234 SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_NOOWNERZORDER,
235 );
236 }
237
238 pub unsafe fn get_window_size(handle: HWND) -> (u32, u32) {
239 get_window_size_impl(handle, false)
240 }
241
242 #[allow(unused)]
243 pub unsafe fn get_window_physical_size(handle: HWND) -> (u32, u32) {
244 get_window_size_impl(handle, true)
245 }
246
247 unsafe fn get_window_size_impl(handle: HWND, return_physical: bool) -> (u32, u32) {
248 let mut r = RECT::default();
249 let _ = GetClientRect(handle, &mut r);
250
251 let (w, h) = if return_physical {
252 (r.right, r.bottom)
253 } else {
254 high_dpi::physical_to_logical(r.right, r.bottom)
255 };
256
257 (w as u32, h as u32)
258 }
259 pub unsafe fn set_window_visibility(handle: HWND, visible: bool) {
260 let visible = if visible { SW_SHOW } else { SW_HIDE };
261 let _ = ShowWindow(handle, visible);
262 }
263
264 pub unsafe fn get_window_visibility(handle: HWND) -> bool {
265 windows::Win32::UI::WindowsAndMessaging::IsWindowVisible(handle).as_bool()
266 }
267}
268
269use std::{cell::RefCell, cmp::Ordering, rc::Rc};
270
271use nwg::{
272 bind_raw_event_handler, unbind_raw_event_handler, Button, ButtonFlags, ControlBase,
273 ControlHandle, Font, Notice, NumberSelectData, NumberSelectFlags, NwgError, RawEventHandler,
274 TextInput, TextInputFlags,
275};
276use windows::Win32::{
277 Foundation::HWND,
278 Graphics::Gdi::HFONT,
279 UI::WindowsAndMessaging::{
280 BN_CLICKED, WM_COMMAND, WS_BORDER, WS_CHILD, WS_CLIPCHILDREN, WS_EX_CONTROLPARENT,
281 WS_TABSTOP, WS_VISIBLE,
282 },
283};
284
285const NOT_BOUND: &str = "UpDown is not yet bound to a winapi object";
286const BAD_HANDLE: &str = "INTERNAL ERROR: UpDown handle is not HWND!";
287
288fn check_hwnd(handle: &ControlHandle, not_bound: &str, bad_handle: &str) -> HWND {
290 if handle.blank() {
291 panic!("{}", not_bound);
292 }
293 match handle.hwnd() {
294 Some(hwnd) => {
295 if unsafe { windows::Win32::UI::WindowsAndMessaging::IsWindow(HWND(hwnd.cast())) }
296 .as_bool()
297 {
298 HWND(hwnd.cast())
299 } else {
300 panic!("The window handle is no longer valid. This usually means the control was freed by the OS");
301 }
302 }
303 None => {
304 panic!("{}", bad_handle);
305 }
306 }
307}
308
309#[derive(Default)]
353pub struct NumberSelect2 {
354 pub handle: ControlHandle,
355 data: Rc<RefCell<NumberSelectData>>,
356 edit: TextInput,
357 btn_up: Button,
358 btn_down: Button,
359 notice: Notice,
360 handler: Option<RawEventHandler>,
361 edit_handler: Option<RawEventHandler>,
362}
363
364impl NumberSelect2 {
365 pub fn builder<'a>() -> NumberSelectBuilder<'a> {
366 NumberSelectBuilder {
367 size: (100, 25),
368 position: (0, 0),
369 data: NumberSelectData::default(),
370 enabled: true,
371 flags: None,
372 font: None,
373 parent: None,
374 }
375 }
376
377 pub fn data(&self) -> NumberSelectData {
380 *self.data.borrow()
381 }
382
383 pub fn set_data(&self, v: NumberSelectData) {
386 *self.data.borrow_mut() = v;
387 self.edit.set_text(&v.formatted_value());
388 }
389
390 pub fn font(&self) -> Option<Font> {
392 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
393 let font_handle = wh::get_window_font(handle);
394 if font_handle.0.is_null() {
395 None
396 } else {
397 Some(Font {
398 handle: font_handle.0 as *mut _,
399 })
400 }
401 }
402
403 pub fn set_font(&self, font: Option<&Font>) {
405 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
406 unsafe {
407 wh::set_window_font(handle, font.map(|f| HFONT(f.handle.cast())), true);
408 }
409 }
410
411 pub fn focus(&self) -> bool {
413 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
414 unsafe { wh::get_focus(handle) }
415 }
416
417 pub fn set_focus(&self) {
419 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
420 unsafe {
421 wh::set_focus(handle);
422 }
423 }
424
425 pub fn enabled(&self) -> bool {
427 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
428 unsafe { wh::get_window_enabled(handle) }
429 }
430
431 pub fn set_enabled(&self, v: bool) {
433 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
434 unsafe { wh::set_window_enabled(handle, v) }
435 }
436
437 pub fn visible(&self) -> bool {
440 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
441 unsafe { wh::get_window_visibility(handle) }
442 }
443
444 pub fn set_visible(&self, v: bool) {
446 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
447 unsafe { wh::set_window_visibility(handle, v) }
448 }
449
450 pub fn size(&self) -> (u32, u32) {
452 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
453 unsafe { wh::get_window_size(handle) }
454 }
455
456 pub fn set_size(&self, x: u32, y: u32) {
458 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
459 unsafe { wh::set_window_size(handle, x, y, false) }
460 }
461
462 pub fn position(&self) -> (i32, i32) {
464 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
465 unsafe { wh::get_window_position(handle) }
466 }
467
468 pub fn set_position(&self, x: i32, y: i32) {
470 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
471 unsafe { wh::set_window_position(handle, x, y) }
472 }
473
474 pub fn class_name(&self) -> &'static str {
476 "NativeWindowsGuiWindow"
477 }
478
479 pub fn flags(&self) -> u32 {
481 WS_VISIBLE.0
482 }
483
484 pub fn forced_flags(&self) -> u32 {
486 (WS_CHILD | WS_BORDER | WS_CLIPCHILDREN).0
487 }
488}
489
490impl Drop for NumberSelect2 {
491 fn drop(&mut self) {
492 if let Some(h) = self.handler.as_ref() {
493 drop(unbind_raw_event_handler(h));
494 }
495
496 self.handle.destroy();
497 }
498}
499
500pub struct NumberSelectBuilder<'a> {
501 size: (i32, i32),
502 position: (i32, i32),
503 data: NumberSelectData,
504 enabled: bool,
505 flags: Option<NumberSelectFlags>,
506 font: Option<&'a Font>,
507 parent: Option<ControlHandle>,
508}
509
510impl<'a> NumberSelectBuilder<'a> {
511 pub fn flags(mut self, flags: NumberSelectFlags) -> NumberSelectBuilder<'a> {
512 self.flags = Some(flags);
513 self
514 }
515
516 pub fn size(mut self, size: (i32, i32)) -> NumberSelectBuilder<'a> {
517 self.size = size;
518 self
519 }
520
521 pub fn position(mut self, pos: (i32, i32)) -> NumberSelectBuilder<'a> {
522 self.position = pos;
523 self
524 }
525
526 pub fn enabled(mut self, e: bool) -> NumberSelectBuilder<'a> {
527 self.enabled = e;
528 self
529 }
530
531 pub fn font(mut self, font: Option<&'a Font>) -> NumberSelectBuilder<'a> {
532 self.font = font;
533 self
534 }
535
536 pub fn value_int(mut self, v: i64) -> NumberSelectBuilder<'a> {
538 match &mut self.data {
539 NumberSelectData::Int { value, .. } => {
540 *value = v;
541 }
542 data => {
543 *data = NumberSelectData::Int {
544 value: v,
545 step: 1,
546 max: i64::MAX,
547 min: i64::MIN,
548 }
549 }
550 }
551 self
552 }
553
554 pub fn step_int(mut self, v: i64) -> NumberSelectBuilder<'a> {
555 match &mut self.data {
556 NumberSelectData::Int { step, .. } => {
557 *step = v;
558 }
559 data => {
560 *data = NumberSelectData::Int {
561 value: 0,
562 step: v,
563 max: i64::MAX,
564 min: i64::MIN,
565 }
566 }
567 }
568 self
569 }
570
571 pub fn max_int(mut self, v: i64) -> NumberSelectBuilder<'a> {
572 match &mut self.data {
573 NumberSelectData::Int { max, .. } => {
574 *max = v;
575 }
576 data => {
577 *data = NumberSelectData::Int {
578 value: 0,
579 step: 1,
580 max: v,
581 min: i64::MIN,
582 }
583 }
584 }
585 self
586 }
587
588 pub fn min_int(mut self, v: i64) -> NumberSelectBuilder<'a> {
589 match &mut self.data {
590 NumberSelectData::Int { min, .. } => {
591 *min = v;
592 }
593 data => {
594 *data = NumberSelectData::Int {
595 value: 0,
596 step: 1,
597 max: i64::MAX,
598 min: v,
599 }
600 }
601 }
602 self
603 }
604
605 pub fn value_float(mut self, v: f64) -> NumberSelectBuilder<'a> {
607 match &mut self.data {
608 NumberSelectData::Float { value, .. } => {
609 *value = v;
610 }
611 data => {
612 *data = NumberSelectData::Float {
613 value: v,
614 step: 1.0,
615 max: 1000000.0,
616 min: -1000000.0,
617 decimals: 2,
618 }
619 }
620 }
621 self
622 }
623
624 pub fn step_float(mut self, v: f64) -> NumberSelectBuilder<'a> {
625 match &mut self.data {
626 NumberSelectData::Float { step, .. } => {
627 *step = v;
628 }
629 data => {
630 *data = NumberSelectData::Float {
631 value: 0.0,
632 step: v,
633 max: 1000000.0,
634 min: -1000000.0,
635 decimals: 2,
636 }
637 }
638 }
639 self
640 }
641
642 pub fn max_float(mut self, v: f64) -> NumberSelectBuilder<'a> {
643 match &mut self.data {
644 NumberSelectData::Float { max, .. } => {
645 *max = v;
646 }
647 data => {
648 *data = NumberSelectData::Float {
649 value: 0.0,
650 step: 1.0,
651 max: v,
652 min: -1000000.0,
653 decimals: 2,
654 }
655 }
656 }
657 self
658 }
659
660 pub fn min_float(mut self, v: f64) -> NumberSelectBuilder<'a> {
661 match &mut self.data {
662 NumberSelectData::Float { min, .. } => {
663 *min = v;
664 }
665 data => {
666 *data = NumberSelectData::Float {
667 value: 0.0,
668 step: 1.0,
669 max: 1000000.0,
670 min: v,
671 decimals: 2,
672 }
673 }
674 }
675 self
676 }
677
678 pub fn decimals(mut self, v: u8) -> NumberSelectBuilder<'a> {
679 match &mut self.data {
680 NumberSelectData::Float { decimals, .. } => {
681 *decimals = v;
682 }
683 data => {
684 *data = NumberSelectData::Float {
685 value: 0.0,
686 step: 1.0,
687 max: 1000000.0,
688 min: -1000000.0,
689 decimals: v,
690 }
691 }
692 }
693 self
694 }
695
696 pub fn parent<C: Into<ControlHandle>>(mut self, p: C) -> NumberSelectBuilder<'a> {
697 self.parent = Some(p.into());
698 self
699 }
700
701 pub fn build(self, out: &mut NumberSelect2) -> Result<(), NwgError> {
702 let flags = self.flags.map(|f| f.bits()).unwrap_or(out.flags());
703 let (btn_flags, text_flags) = if flags & WS_TABSTOP.0 == WS_TABSTOP.0 {
704 (
705 ButtonFlags::VISIBLE | ButtonFlags::TAB_STOP,
706 TextInputFlags::VISIBLE | TextInputFlags::TAB_STOP,
707 )
708 } else {
709 (ButtonFlags::VISIBLE, TextInputFlags::VISIBLE)
710 };
711
712 let parent = match self.parent {
713 Some(p) => Ok(p),
714 None => Err(NwgError::no_parent("NumberSelect")),
715 }?;
716
717 *out = Default::default();
718
719 let (w, h) = self.size;
720
721 if out.handler.is_some() {
722 unbind_raw_event_handler(out.handler.as_ref().unwrap())?;
723 }
724
725 *out = NumberSelect2::default();
726 *out.data.borrow_mut() = self.data;
727
728 out.handle = ControlBase::build_hwnd()
729 .class_name(out.class_name())
730 .forced_flags(out.forced_flags())
731 .ex_flags(WS_EX_CONTROLPARENT.0)
732 .flags(flags)
733 .size(self.size)
734 .position(self.position)
735 .parent(Some(parent))
736 .build()?;
737
738 TextInput::builder()
739 .text(&self.data.formatted_value())
740 .size((w - 19, h))
741 .parent(out.handle)
742 .flags(text_flags)
743 .build(&mut out.edit)?;
744
745 Button::builder()
746 .text("▴") .size((20, h / 2 + 1))
748 .position((w - 20, -1))
749 .parent(out.handle)
750 .flags(btn_flags)
751 .build(&mut out.btn_up)?;
752
753 Button::builder()
754 .text("▾") .size((20, h / 2 + 1))
756 .position((w - 20, (h / 2) - 1))
757 .parent(out.handle)
758 .flags(btn_flags)
759 .build(&mut out.btn_down)?;
760
761 Notice::builder()
762 .parent(out.handle)
763 .build(&mut out.notice)?;
764
765 if self.font.is_some() {
766 out.btn_up.set_font(self.font);
767 out.btn_down.set_font(self.font);
768 out.edit.set_font(self.font);
769 } else {
770 let font = Font::global_default();
771 let font_ref = font.as_ref();
772 out.btn_up.set_font(font_ref);
773 out.btn_down.set_font(font_ref);
774 out.edit.set_font(font_ref);
775 }
776
777 let plus_button = out.btn_up.handle;
778 let minus_button = out.btn_down.handle;
779 let text_handle = out.edit.handle;
780
781 let set_text = move |text: &str| {
782 let handle = text_handle.hwnd().unwrap();
783 unsafe {
784 wh::set_window_text(HWND(handle.cast()), text);
785 }
786 };
787
788 let handler = bind_raw_event_handler(&out.handle, 0xA4545, {
789 let notifier = out.notice.sender();
790 let handler_data = out.data.clone();
791 move |_hwnd, msg, w, l| {
792 if WM_COMMAND == msg {
793 let handle = ControlHandle::Hwnd(l as _);
794 let message = w as u32 >> 16;
795 if message == windows::Win32::UI::WindowsAndMessaging::EN_CHANGE {
796 let handle = text_handle.hwnd().unwrap();
798 let text = unsafe { wh::get_window_text(HWND(handle.cast())) };
799 let mut data = handler_data.borrow_mut();
800 let mut valid = false;
801 match &mut *data {
802 NumberSelectData::Int {
803 value, max, min, ..
804 } => {
805 if let Ok(new) = text.parse::<i64>() {
806 if *min <= new && new <= *max {
807 *value = new;
808 valid = true;
809 }
810 }
811 }
812 NumberSelectData::Float {
813 value, max, min, ..
814 } => {
815 if let Ok(new) = text.parse::<f64>() {
816 if *min <= new && new <= *max {
817 *value = new;
818 valid = true;
819 }
820 }
821 }
822 }
823 if valid {
824 drop(data);
825 notifier.notice();
826 } else {
827 let text = data.formatted_value();
828 drop(data);
829 set_text(&text);
830 }
831 return None;
832 }
833 let text = if message == BN_CLICKED && handle == plus_button {
834 let mut data = handler_data.borrow_mut();
835 data.increase();
836 data.formatted_value()
837 } else if message == BN_CLICKED && handle == minus_button {
838 let mut data = handler_data.borrow_mut();
839 data.decrease();
840 data.formatted_value()
841 } else {
842 return None;
843 };
844 set_text(&text);
845 notifier.notice();
846 } else if msg == windows::Win32::UI::WindowsAndMessaging::WM_MOUSEWHEEL {
847 let scroll = (w as u32 >> 16) as i16;
848 let mut data = handler_data.borrow_mut();
849 match scroll.cmp(&0) {
850 Ordering::Equal => return None,
851 Ordering::Less => data.decrease(),
852 Ordering::Greater => data.increase(),
853 }
854 let text = data.formatted_value();
855 drop(data);
856 set_text(&text);
857 notifier.notice();
858 }
859 None
860 }
861 });
862 let edit_handler = bind_raw_event_handler(&out.edit.handle, 0xA4545, {
863 let notifier = out.notice.sender();
864 let handler_data = out.data.clone();
865 move |_hwnd, msg, w, _l| {
866 if msg == windows::Win32::UI::WindowsAndMessaging::WM_KEYDOWN {
867 let keycode = w as u32;
869 let text = if keycode == 38 {
870 let mut data = handler_data.borrow_mut();
871 data.increase();
872 data.formatted_value()
873 } else if keycode == 40 {
874 let mut data = handler_data.borrow_mut();
875 data.decrease();
876 data.formatted_value()
877 } else {
878 return None;
879 };
880 set_text(&text);
881 notifier.notice();
882 return Some(0);
884 }
885 None
886 }
887 });
888
889 out.handler = Some(handler.unwrap());
890 out.edit_handler =
891 Some(edit_handler.expect("should create event handler for number select's text box"));
892
893 if !self.enabled {
894 out.set_enabled(self.enabled);
895 }
896
897 Ok(())
898 }
899}
900
901macro_rules! handles {
903 ($control:ty) => {
904 #[allow(deprecated)]
905 impl From<&$control> for ControlHandle {
906 fn from(control: &$control) -> Self {
907 control.handle
908 }
909 }
910
911 #[allow(deprecated)]
912 impl From<&mut $control> for ControlHandle {
913 fn from(control: &mut $control) -> Self {
914 control.handle
915 }
916 }
917
918 #[allow(deprecated)]
919 impl PartialEq<ControlHandle> for $control {
920 fn eq(&self, other: &ControlHandle) -> bool {
921 self.handle == *other || self.notice.handle == *other
922 }
923 }
924
925 #[allow(deprecated)]
926 impl PartialEq<$control> for ControlHandle {
927 fn eq(&self, other: &$control) -> bool {
928 *self == other.handle || *self == other.notice.handle
929 }
930 }
931 };
932}
933handles!(NumberSelect2);