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}