native_windows_gui2/win32/
cursor.rs

1use crate::Cursor;
2use crate::controls::ControlHandle;
3use crate::win32::high_dpi;
4
5/**
6    A global object that wraps the system cursor.
7    Requires the `cursor` feature.
8
9
10    This object cannot be instanced. The methods should be used this way:
11
12    ```rust
13    use native_windows_gui2 as nwg;
14    let (x,y) = nwg::GlobalCursor::position();
15    ```
16*/
17pub struct GlobalCursor;
18
19impl GlobalCursor {
20    /**
21        Return the cursor position in the screen.
22    */
23    pub fn position() -> (i32, i32) {
24        use winapi::shared::windef::POINT;
25        use winapi::um::winuser::GetCursorPos;
26
27        let mut p = POINT { x: 0, y: 0 };
28        unsafe {
29            GetCursorPos(&mut p);
30        }
31
32        (p.x as i32, p.y as i32)
33    }
34
35    /**
36        Return or map the cursor position relatively to a control.
37        If point is `None`, `Cursor::position` is used.
38    */
39    pub fn local_position<C: Into<ControlHandle>>(
40        control: C,
41        point: Option<(i32, i32)>,
42    ) -> (i32, i32) {
43        use winapi::shared::ntdef::LONG;
44        use winapi::shared::windef::POINT;
45        use winapi::um::winuser::ScreenToClient;
46
47        const MSG: &'static str = "local_position can only be used for window control";
48
49        let control = control.into();
50        if control.blank() {
51            panic!("{}", MSG);
52        }
53        let handle = control.hwnd().expect(MSG);
54
55        let (x, y) = point.unwrap_or(GlobalCursor::position());
56        let mut p = POINT {
57            x: x as LONG,
58            y: y as LONG,
59        };
60
61        unsafe {
62            ScreenToClient(handle, &mut p);
63        }
64
65        (p.x as i32, p.y as i32)
66    }
67
68    /**
69        Return or map the cursor position relatively to a control and convert to logical.
70        If point is `None`, `Cursor::position` is used.
71    */
72    pub fn local_logical_position<C: Into<ControlHandle>>(
73        control: C,
74        point: Option<(i32, i32)>,
75    ) -> (i32, i32) {
76        use winapi::shared::ntdef::LONG;
77        use winapi::shared::windef::POINT;
78        use winapi::um::winuser::ScreenToClient;
79
80        const MSG: &'static str = "local_position can only be used for window control";
81
82        let control = control.into();
83        if control.blank() {
84            panic!("{}", MSG);
85        }
86        let handle = control.hwnd().expect(MSG);
87
88        let (x, y) = point.unwrap_or(GlobalCursor::position());
89        let mut p = POINT {
90            x: x as LONG,
91            y: y as LONG,
92        };
93
94        unsafe {
95            ScreenToClient(handle, &mut p);
96
97            high_dpi::physical_to_logical(p.x as i32, p.y as i32)
98        }
99    }
100
101    /**
102        Set the cursor position in the screen.
103
104        Arguments:
105        • `x`: The new x coordinates of the cursor
106        • `y`: The new y coordinaets of the cursor
107    */
108    pub fn set_position(x: i32, y: i32) {
109        use winapi::ctypes::c_int;
110        use winapi::um::winuser::SetCursorPos;
111
112        unsafe {
113            SetCursorPos(x as c_int, y as c_int);
114        }
115    }
116
117    /**
118        Set the cursor image.
119        If your application must set the cursor while it is in a window, make sure the class cursor
120        for the specified window's class is set to NULL. If the class cursor is not NULL,
121        the system restores the class cursor each time the mouse is moved.
122
123        Arguments:
124        • `cursor`: The id identifying the cursor resource
125    */
126    pub fn set(cursor: &Cursor) {
127        use winapi::shared::windef::HCURSOR;
128        use winapi::um::winuser::SetCursor;
129
130        unsafe {
131            SetCursor(cursor.handle as HCURSOR);
132        }
133    }
134
135    /**
136        Get the cursor image
137
138        Returns `None` if there is no cursor.
139    */
140    pub fn get() -> Option<Cursor> {
141        use winapi::um::winnt::HANDLE;
142        use winapi::um::winuser::GetCursor;
143
144        let cursor = unsafe { GetCursor() };
145
146        match cursor.is_null() {
147            true => None,
148            false => Some(Cursor {
149                handle: cursor as HANDLE,
150                owned: false,
151            }),
152        }
153    }
154
155    /**
156        Capture the mouse for a window-like control. Make sure to call `Cursor::release` to
157        remove the capture. A control that has captured the mouse will receive mouse events
158        even if the mouse is not hovering it.
159
160        Will panic if the control handle passed to the method is not a window or if the control is not yet initialized.
161
162        Arguments:
163        • `control`: The control that will capture the mouse input
164    */
165    pub fn set_capture(control: &ControlHandle) {
166        use winapi::um::winuser::SetCapture;
167        const MSG: &'static str = "Mouse capture can only be set for window control";
168
169        if control.blank() {
170            panic!("{}", MSG);
171        }
172        let handle = control.hwnd().expect(MSG);
173
174        unsafe {
175            SetCapture(handle);
176        }
177    }
178
179    /**
180        Release the cursor if it was captured with `Cursor::set_capture`
181    */
182    pub fn release() {
183        use winapi::um::winuser::ReleaseCapture;
184        unsafe {
185            ReleaseCapture();
186        }
187    }
188
189    /**
190        Return the handle of the control that has captured the mouse. Return `None` if no control captured the cursor.
191
192        Arguments:
193        • `ui`: The Ui holding the cursor resource
194    */
195    pub fn capture() -> Option<ControlHandle> {
196        use winapi::um::winuser::GetCapture;
197
198        let cap = unsafe { GetCapture() };
199        match cap.is_null() {
200            true => None,
201            false => Some(ControlHandle::Hwnd(cap)),
202        }
203    }
204
205    /**
206    Captures the mouse and tracks its movement until the user releases the left button, presses the ESC key, or moves
207    the mouse outside the drag rectangle around the specified point.
208
209    Return `Ok(true)` if the user did not execute the actions mentioned above or `Ok(false)` if it did.
210
211    Will panic if the control handle passed to the method is not a window or if the control is not yet initialized.
212
213    Arguments:
214    • `control`: The control that will capture the mouse input
215    • `point`: A point in screen coordinates where the dragging begins. If `None`, use the `Cursor::position` value.
216
217    ```rust
218        use native_windows_gui2 as nwg;
219        fn dragging(c: &nwg::Window) {
220            if nwg::GlobalCursor::dragging(&c.handle, None) {
221                println!("DRAGGING!")
222            }
223        }
224    ```
225    */
226    pub fn dragging(control: &ControlHandle, point: Option<(i32, i32)>) -> bool {
227        use winapi::shared::ntdef::LONG;
228        use winapi::shared::windef::POINT;
229        use winapi::um::winuser::DragDetect;
230
231        const MSG: &'static str = "Dragging can only be set for window control";
232
233        if control.blank() {
234            panic!("{}", MSG);
235        }
236        let handle = control.hwnd().expect(MSG);
237
238        let (x, y) = point.unwrap_or(GlobalCursor::position());
239        let c_point = POINT {
240            x: x as LONG,
241            y: y as LONG,
242        };
243
244        unsafe { DragDetect(handle, c_point) == 1 }
245    }
246}