1use winapi::um::winuser::{WS_DISABLED, WS_VISIBLE, WS_TABSTOP, WS_CHILD, SBS_HORZ, SBS_VERT};
2use crate::win32::window_helper as wh;
3use crate::win32::base_helper::check_hwnd;
4use crate::{NwgError, RawEventHandler};
5use super::{ControlBase, ControlHandle};
6use std::{mem, cell::RefCell, ops::Range};
7
8const NOT_BOUND: &'static str = "Scroll bar is not yet bound to a winapi object";
9const BAD_HANDLE: &'static str = "INTERNAL ERROR: Scroll bar handle is not HWND!";
10
11
12bitflags! {
13 pub struct ScrollBarFlags: u32 {
24 const NONE = 0;
25 const VISIBLE = WS_VISIBLE;
26 const DISABLED = WS_DISABLED;
27 const TAB_STOP = WS_TABSTOP;
28 const HORIZONTAL = SBS_HORZ;
29 const VERTICAL = SBS_VERT;
30 }
31}
32
33#[derive(Default)]
69pub struct ScrollBar {
70 pub handle: ControlHandle,
71 handler0: RefCell<Option<RawEventHandler>>,
72 handler1: RefCell<Option<RawEventHandler>>,
73}
74
75impl ScrollBar {
76
77 pub fn builder<'a>() -> ScrollBarBuilder {
78 ScrollBarBuilder {
79 size: (25, 100),
80 position: (0, 0),
81 enabled: true,
82 flags: None,
83 ex_flags: 0,
84 parent: None,
85 focus: false,
86 range: None,
87 pos: None
88 }
89 }
90
91 pub fn pos(&self) -> usize {
94 use winapi::um::winuser::SBM_GETPOS;
95
96 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
97 wh::send_message(handle, SBM_GETPOS, 0, 0) as usize
98 }
99
100 pub fn set_pos(&self, p: usize) {
102 use winapi::um::winuser::SBM_SETPOS;
103
104 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
105 wh::send_message(handle, SBM_SETPOS, p, 1);
106 }
107
108 pub fn range(&self) -> Range<usize> {
110 use winapi::um::winuser::SBM_GETRANGE;
111
112 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
113
114 let mut min: u32 = 0;
115 let mut max: u32 = 0;
116
117 wh::send_message(handle, SBM_GETRANGE,
118 &mut min as *mut u32 as _,
119 &mut max as *mut u32 as _
120 );
121
122 (min as usize)..(max as usize)
123 }
124
125 pub fn set_range(&self, range: Range<usize>) {
127 use winapi::um::winuser::SBM_SETRANGE;
128
129 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
130 wh::send_message(handle, SBM_SETRANGE,
131 range.start as _,
132 range.end as _,
133 );
134 }
135
136 pub fn focus(&self) -> bool {
138 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
139 unsafe { wh::get_focus(handle) }
140 }
141
142 pub fn set_focus(&self) {
144 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
145 unsafe { wh::set_focus(handle); }
146 }
147
148 pub fn enabled(&self) -> bool {
150 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
151 unsafe { wh::get_window_enabled(handle) }
152 }
153
154 pub fn set_enabled(&self, v: bool) {
156 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
157 unsafe { wh::set_window_enabled(handle, v) }
158 }
159
160 pub fn visible(&self) -> bool {
163 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
164 unsafe { wh::get_window_visibility(handle) }
165 }
166
167 pub fn set_visible(&self, v: bool) {
169 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
170 unsafe { wh::set_window_visibility(handle, v) }
171 }
172
173 pub fn size(&self) -> (u32, u32) {
175 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
176 unsafe { wh::get_window_size(handle) }
177 }
178
179 pub fn set_size(&self, x: u32, y: u32) {
181 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
182 unsafe { wh::set_window_size(handle, x, y, false) }
183 }
184
185 pub fn position(&self) -> (i32, i32) {
187 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
188 unsafe { wh::get_window_position(handle) }
189 }
190
191 pub fn set_position(&self, x: i32, y: i32) {
193 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
194 unsafe { wh::set_window_position(handle, x, y) }
195 }
196
197 pub fn class_name(&self) -> &'static str {
199 "SCROLLBAR"
200 }
201
202 pub fn flags(&self) -> u32 {
204 WS_VISIBLE | WS_TABSTOP | SBS_VERT
205 }
206
207 pub fn forced_flags(&self) -> u32 {
209 WS_CHILD
210 }
211
212 unsafe fn hook_scrollbar_controls(&self) {
214 use crate::bind_raw_event_handler_inner;
215 use winapi::um::winuser::{WM_HSCROLL, WM_VSCROLL, SIF_ALL, SB_CTL, SIF_POS, SB_TOP, SB_BOTTOM, SB_PAGEUP, SB_PAGEDOWN,
216 SB_LINERIGHT, SB_LINELEFT, SB_PAGELEFT, SB_PAGERIGHT, SB_THUMBTRACK, SB_LINEUP, SB_LINEDOWN, WM_MOUSEWHEEL,
217 GET_WHEEL_DELTA_WPARAM, SCROLLINFO, GetScrollInfo, SetScrollInfo};
218 use winapi::shared::{minwindef::{TRUE, LOWORD}, windef::HWND};
219
220 if self.handle.blank() { panic!("{}", NOT_BOUND); }
221 let handle = self.handle.hwnd().expect(BAD_HANDLE);
222 let parent_handle = ControlHandle::Hwnd(wh::get_window_parent(handle));
223
224 let handler1 = bind_raw_event_handler_inner(&parent_handle, handle as _, move |_hwnd, msg, w, l| {
225 let mut si: SCROLLINFO = mem::zeroed();
226 match msg {
227 WM_HSCROLL => {
228 if (l as HWND) != handle { return None; }
229
230 si.cbSize = mem::size_of::<SCROLLINFO>() as u32;
231 si.fMask = SIF_ALL;
232 GetScrollInfo(handle, SB_CTL as i32, &mut si);
233
234 let event = LOWORD(w as u32) as isize;
235 match event {
236 SB_LINELEFT => { si.nPos -= 1; },
237 SB_LINERIGHT => { si.nPos += 1; },
238 SB_PAGELEFT => { si.nPos -= si.nPage as i32; },
239 SB_PAGERIGHT => { si.nPos += si.nPage as i32; },
240 SB_THUMBTRACK => { si.nPos = si.nTrackPos; },
241 _ => {},
242 }
243
244 si.fMask = SIF_POS;
245 SetScrollInfo(handle, SB_CTL as _, &si, TRUE);
246 },
248 WM_VSCROLL => {
249 if (l as HWND) != handle { return None; }
250
251 si.cbSize = mem::size_of::<SCROLLINFO>() as u32;
252 si.fMask = SIF_ALL;
253 GetScrollInfo(handle, SB_CTL as i32, &mut si);
254
255 let event = LOWORD(w as u32) as isize;
256 match event {
257 SB_TOP => { si.nPos = si.nMin; },
258 SB_BOTTOM => { si.nPos = si.nMax; },
259 SB_LINEUP => { si.nPos -= 1; },
260 SB_LINEDOWN => { si.nPos += 1; },
261 SB_PAGEUP => { si.nPos -= si.nPage as i32; },
262 SB_PAGEDOWN => { si.nPos += si.nPage as i32; },
263 SB_THUMBTRACK => { si.nPos = si.nTrackPos; },
264 _ => {},
265 }
266
267 si.fMask = SIF_POS;
268 SetScrollInfo(handle, SB_CTL as _, &si, TRUE);
269 },
271 _ => {}
272 }
273
274 None
275 });
276
277 let handler2 = bind_raw_event_handler_inner(&self.handle, 0, move |_hwnd, msg, w, _l| {
278 match msg {
279 WM_MOUSEWHEEL => {
280 let mut si: SCROLLINFO = mem::zeroed();
281
282 si.cbSize = mem::size_of::<SCROLLINFO>() as u32;
283 si.fMask = SIF_ALL;
284 GetScrollInfo(handle, SB_CTL as i32, &mut si);
285
286 let delta = GET_WHEEL_DELTA_WPARAM(w);
287 match delta > 0 {
288 true => { si.nPos -= 1; },
289 false => { si.nPos += 1; }
290 }
291
292 si.fMask = SIF_POS;
293 SetScrollInfo(handle, SB_CTL as _, &si, TRUE);
294 return Some(0)
295 },
296 _ => {}
297 }
298
299 None
300 });
301
302 *self.handler0.borrow_mut() = Some(handler1.unwrap());
303 *self.handler1.borrow_mut() = Some(handler2.unwrap());
304 }
305
306}
307
308impl Drop for ScrollBar {
309 fn drop(&mut self) {
310 use crate::unbind_raw_event_handler;
311
312 let handler = self.handler0.borrow();
313 if let Some(h) = handler.as_ref() {
314 drop(unbind_raw_event_handler(h));
315 }
316
317 let handler = self.handler1.borrow();
318 if let Some(h) = handler.as_ref() {
319 drop(unbind_raw_event_handler(h));
320 }
321
322 self.handle.destroy();
323 }
324}
325
326pub struct ScrollBarBuilder {
327 size: (i32, i32),
328 position: (i32, i32),
329 enabled: bool,
330 flags: Option<ScrollBarFlags>,
331 ex_flags: u32,
332 parent: Option<ControlHandle>,
333 focus: bool,
334 range: Option<Range<usize>>,
335 pos: Option<usize>,
336}
337
338impl ScrollBarBuilder {
339
340 pub fn flags(mut self, flags: ScrollBarFlags) -> ScrollBarBuilder {
341 self.flags = Some(flags);
342 self
343 }
344
345 pub fn ex_flags(mut self, flags: u32) -> ScrollBarBuilder {
346 self.ex_flags = flags;
347 self
348 }
349
350 pub fn size(mut self, size: (i32, i32)) -> ScrollBarBuilder {
351 self.size = size;
352 self
353 }
354
355 pub fn position(mut self, pos: (i32, i32)) -> ScrollBarBuilder {
356 self.position = pos;
357 self
358 }
359
360 pub fn enabled(mut self, e: bool) -> ScrollBarBuilder {
361 self.enabled = e;
362 self
363 }
364
365 pub fn focus(mut self, focus: bool) -> ScrollBarBuilder {
366 self.focus = focus;
367 self
368 }
369
370 pub fn range(mut self, range: Option<Range<usize>>) -> ScrollBarBuilder {
371 self.range = range;
372 self
373 }
374
375 pub fn pos(mut self, pos: Option<usize>) -> ScrollBarBuilder {
376 self.pos = pos;
377 self
378 }
379
380 pub fn parent<C: Into<ControlHandle>>(mut self, p: C) -> ScrollBarBuilder {
381 self.parent = Some(p.into());
382 self
383 }
384
385 pub fn build(self, out: &mut ScrollBar) -> Result<(), NwgError> {
386 let flags = self.flags.map(|f| f.bits()).unwrap_or(out.flags());
387
388 let parent = match self.parent {
389 Some(p) => Ok(p),
390 None => Err(NwgError::no_parent("ScrollBar"))
391 }?;
392
393 *out = Default::default();
394
395 out.handle = ControlBase::build_hwnd()
396 .class_name(out.class_name())
397 .forced_flags(out.forced_flags())
398 .flags(flags)
399 .ex_flags(self.ex_flags)
400 .size(self.size)
401 .position(self.position)
402 .parent(Some(parent))
403 .build()?;
404
405 out.set_enabled(self.enabled);
406
407 if let Some(range) = self.range {
408 out.set_range(range);
409 }
410
411 if let Some(pos) = self.pos {
412 out.set_pos(pos);
413 }
414
415 if self.focus {
416 out.set_focus();
417 }
418
419 unsafe {
420 out.hook_scrollbar_controls();
421 }
422
423 Ok(())
424 }
425
426
427}
428
429impl PartialEq for ScrollBar {
430 fn eq(&self, other: &Self) -> bool {
431 self.handle == other.handle
432 }
433}