1use winapi::shared::windef::HWND;
2use winapi::shared::minwindef::{WPARAM, LPARAM};
3use winapi::um::winuser::{LBS_MULTIPLESEL, LBS_NOSEL, WS_VISIBLE, WS_DISABLED, WS_TABSTOP};
4use crate::win32::window_helper as wh;
5use crate::win32::base_helper::{to_utf16, from_utf16, check_hwnd};
6use crate::{Font, NwgError};
7use super::{ControlBase, ControlHandle};
8use std::cell::{Ref, RefMut, RefCell};
9use std::fmt::Display;
10use std::ops::Range;
11use std::mem;
12
13const NOT_BOUND: &'static str = "ListBox is not yet bound to a winapi object";
14const BAD_HANDLE: &'static str = "INTERNAL ERROR: ListBox handle is not HWND!";
15
16
17bitflags! {
18 pub struct ListBoxFlags: u32 {
29 const NONE = 0;
30 const VISIBLE = WS_VISIBLE;
31 const DISABLED = WS_DISABLED;
32 const MULTI_SELECT = LBS_MULTIPLESEL;
33 const NO_SELECT = LBS_NOSEL;
34 const TAB_STOP = WS_TABSTOP;
35 }
36}
37
38#[derive(Default)]
78pub struct ListBox<D: Display+Default> {
79 pub handle: ControlHandle,
80 collection: RefCell<Vec<D>>
81}
82
83impl<D: Display+Default> ListBox<D> {
84
85 pub fn builder<'a>() -> ListBoxBuilder<'a, D> {
86 ListBoxBuilder {
87 size: (100, 300),
88 position: (0, 0),
89 enabled: true,
90 focus: false,
91 flags: None,
92 ex_flags: 0,
93 font: None,
94 collection: None,
95 selected_index: None,
96 multi_selection: Vec::new(),
97 parent: None
98 }
99 }
100
101 pub fn push(&self, item: D) {
103 use winapi::um::winuser::LB_ADDSTRING;
104
105 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
106 let display = format!("{}", item);
107 let display_os = to_utf16(&display);
108
109 unsafe {
110 wh::send_message(handle, LB_ADDSTRING, 0, mem::transmute(display_os.as_ptr()));
111 }
112
113 self.collection.borrow_mut().push(item);
114 }
115
116 pub fn insert(&self, index: usize, item: D) {
121 use winapi::um::winuser::LB_INSERTSTRING;
122
123 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
124 let display = format!("{}", item);
125 let display_os = to_utf16(&display);
126
127 let mut col = self.collection.borrow_mut();
128 if index == std::usize::MAX {
129 col.push(item);
130 } else {
131 col.insert(index, item);
132 }
133
134 unsafe {
135 wh::send_message(handle, LB_INSERTSTRING, index, mem::transmute(display_os.as_ptr()));
136 }
137 }
138
139
140 pub fn remove(&self, index: usize) -> D {
143 use winapi::um::winuser::LB_DELETESTRING;
144
145 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
146 wh::send_message(handle, LB_DELETESTRING, index as WPARAM, 0);
147
148 let mut col_ref = self.collection.borrow_mut();
149 col_ref.remove(index)
150 }
151
152 pub fn selection(&self) -> Option<usize> {
155 use winapi::um::winuser::{LB_GETCURSEL, LB_ERR};
156
157 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
158 let index = wh::send_message(handle, LB_GETCURSEL , 0, 0);
159
160 if index == LB_ERR { None }
161 else { Some(index as usize) }
162 }
163
164 pub fn multi_selection_len(&self) -> usize {
167 use winapi::um::winuser::{LB_GETSELCOUNT, LB_ERR};
168
169 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
170 match wh::send_message(handle, LB_GETSELCOUNT, 0, 0) {
171 LB_ERR => 0,
172 value => value as usize
173 }
174 }
175
176 pub fn multi_selection(&self) -> Vec<usize> {
179 use winapi::um::winuser::{LB_GETSELCOUNT, LB_GETSELITEMS, LB_ERR};
180
181 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
182 let select_count = match wh::send_message(handle, LB_GETSELCOUNT, 0, 0) {
183 LB_ERR => usize::max_value(),
184 value => value as usize
185 };
186
187 if select_count == usize::max_value() || usize::max_value() == 0 {
188 return Vec::new();
189 }
190
191 let mut indices_buffer: Vec<u32> = Vec::with_capacity(select_count);
192 unsafe { indices_buffer.set_len(select_count) };
193
194 wh::send_message(
195 handle,
196 LB_GETSELITEMS,
197 select_count as WPARAM,
198 indices_buffer.as_mut_ptr() as LPARAM
199 );
200
201 indices_buffer.into_iter().map(|i| i as usize).collect()
202 }
203
204 pub fn selection_string(&self) -> Option<String> {
207 use winapi::um::winuser::{LB_GETCURSEL, LB_GETTEXTLEN, LB_GETTEXT, LB_ERR};
208 use winapi::shared::ntdef::WCHAR;
209
210 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
211 let index = wh::send_message(handle, LB_GETCURSEL, 0, 0);
212
213 if index == LB_ERR { None }
214 else {
215 let index = index as usize;
216 let length = (wh::send_message(handle, LB_GETTEXTLEN, index, 0) as usize) + 1; let mut buffer: Vec<WCHAR> = Vec::with_capacity(length);
218 unsafe {
219 buffer.set_len(length);
220 wh::send_message(handle, LB_GETTEXT, index, mem::transmute(buffer.as_ptr()));
221 }
222
223 Some(from_utf16(&buffer))
224 }
225 }
226
227 pub fn set_selection(&self, index: Option<usize>) {
231 use winapi::um::winuser::LB_SETCURSEL;
232
233 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
234 let index = index.unwrap_or(-1isize as usize);
235 wh::send_message(handle, LB_SETCURSEL, index, 0);
236 }
237
238 pub fn multi_add_selection(&self, index: usize) {
240 use winapi::um::winuser::LB_SETSEL;
241 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
242 wh::send_message(handle, LB_SETSEL, 1, index as LPARAM);
243 }
244
245 pub fn multi_remove_selection(&self, index: usize) {
247 use winapi::um::winuser::LB_SETSEL;
248 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
249 wh::send_message(handle, LB_SETSEL, 0, index as LPARAM);
250 }
251
252 pub fn unselect_all(&self) {
254 use winapi::um::winuser::LB_SETSEL;
255 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
256 wh::send_message(handle, LB_SETSEL, 0, -1);
257 }
258
259 pub fn select_all(&self) {
261 use winapi::um::winuser::LB_SETSEL;
262 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
263 wh::send_message(handle, LB_SETSEL, 1, -1);
264 }
265
266 pub fn multi_select_range(&self, range: Range<usize>) {
268 use winapi::um::winuser::LB_SELITEMRANGEEX;
269
270 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
271 let start = range.start as WPARAM;
272 let end = range.end as LPARAM;
273 wh::send_message(handle, LB_SELITEMRANGEEX, start, end);
274 }
275
276 pub fn multi_unselect_range(&self, range: Range<usize>) {
278 use winapi::um::winuser::LB_SELITEMRANGEEX;
279
280 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
281 let start = range.start as LPARAM;
282 let end = range.end as WPARAM;
283 wh::send_message(handle, LB_SELITEMRANGEEX, end, start);
284 }
285
286 pub fn set_selection_string(&self, value: &str) -> Option<usize> {
290 use winapi::um::winuser::{LB_SELECTSTRING, LB_ERR};
291
292 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
293 let os_string = to_utf16(value);
294
295 unsafe {
296 let index = wh::send_message(handle, LB_SELECTSTRING, 0, mem::transmute(os_string.as_ptr()));
297 if index == LB_ERR {
298 None
299 } else {
300 Some(index as usize)
301 }
302 }
303 }
304
305 pub fn selected(&self, index: usize) -> bool {
308 use winapi::um::winuser::LB_GETSEL;
309
310 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
311 wh::send_message(handle, LB_GETSEL, index as WPARAM, 0) > 0
312 }
313
314 pub fn sync(&self) {
317 use winapi::um::winuser::{LB_ADDSTRING, LB_INITSTORAGE};
318
319 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
320
321 self.clear_inner(handle);
322
323 let item_count = self.collection.borrow().len();
324 wh::send_message(handle, LB_INITSTORAGE, item_count as WPARAM, (10*item_count) as LPARAM);
325
326 for item in self.collection.borrow().iter() {
327 let display = format!("{}", item);
328 let display_os = to_utf16(&display);
329
330 unsafe {
331 wh::send_message(handle, LB_ADDSTRING, 0, mem::transmute(display_os.as_ptr()));
332 }
333 }
334 }
335
336 pub fn set_collection(&self, mut col: Vec<D>) -> Vec<D> {
338 use winapi::um::winuser::LB_ADDSTRING;
339
340 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
341
342 self.clear_inner(handle);
343
344 for item in col.iter() {
345 let display = format!("{}", item);
346 let display_os = to_utf16(&display);
347
348 unsafe {
349 wh::send_message(handle, LB_ADDSTRING, 0, mem::transmute(display_os.as_ptr()));
350 }
351 }
352
353 let mut col_ref = self.collection.borrow_mut();
354 mem::swap::<Vec<D>>(&mut col_ref, &mut col);
355
356 col
357 }
358
359 pub fn clear(&self) {
361 self.set_collection(Vec::new());
362 }
363
364 pub fn len(&self) -> usize {
366 use winapi::um::winuser::LB_GETCOUNT;
367 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
368 wh::send_message(handle, LB_GETCOUNT, 0, 0) as usize
369 }
370
371
372 pub fn font(&self) -> Option<Font> {
378 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
379
380 let font_handle = wh::get_window_font(handle);
381 if font_handle.is_null() {
382 None
383 } else {
384 Some(Font { handle: font_handle })
385 }
386 }
387
388 pub fn set_font(&self, font: Option<&Font>) {
390 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
391 unsafe { wh::set_window_font(handle, font.map(|f| f.handle), true); }
392 }
393
394 pub fn focus(&self) -> bool {
396 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
397 unsafe { wh::get_focus(handle) }
398 }
399
400 pub fn set_focus(&self) {
402 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
403 unsafe { wh::set_focus(handle); }
404 }
405
406 pub fn enabled(&self) -> bool {
408 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
409 unsafe { wh::get_window_enabled(handle) }
410 }
411
412 pub fn set_enabled(&self, v: bool) {
414 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
415 unsafe { wh::set_window_enabled(handle, v) }
416 }
417
418 pub fn visible(&self) -> bool {
421 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
422 unsafe { wh::get_window_visibility(handle) }
423 }
424
425 pub fn set_visible(&self, v: bool) {
427 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
428 unsafe { wh::set_window_visibility(handle, v) }
429 }
430
431 pub fn size(&self) -> (u32, u32) {
433 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
434 unsafe { wh::get_window_size(handle) }
435 }
436
437 pub fn set_size(&self, x: u32, y: u32) {
439 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
440 unsafe { wh::set_window_size(handle, x, y, false) }
441 }
442
443 pub fn position(&self) -> (i32, i32) {
445 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
446 unsafe { wh::get_window_position(handle) }
447 }
448
449 pub fn set_position(&self, x: i32, y: i32) {
451 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
452 unsafe { wh::set_window_position(handle, x, y) }
453 }
454
455 pub fn collection(&self) -> Ref<Vec<D>> {
459 self.collection.borrow()
460 }
461
462 pub fn collection_mut(&self) -> RefMut<Vec<D>> {
466 self.collection.borrow_mut()
467 }
468
469 pub fn class_name(&self) -> &'static str {
471 "ListBox"
472 }
473
474 pub fn flags(&self) -> u32 {
476 WS_VISIBLE | WS_TABSTOP
477 }
478
479 pub fn forced_flags(&self) -> u32 {
481 use winapi::um::winuser::{LBS_HASSTRINGS, WS_BORDER, WS_VSCROLL, LBS_NOTIFY, WS_CHILD};
482
483 LBS_HASSTRINGS | LBS_NOTIFY | WS_BORDER | WS_CHILD | WS_VSCROLL
484 }
485
486 fn clear_inner(&self, handle: HWND) {
488 use winapi::um::winuser::LB_RESETCONTENT;
489 wh::send_message(handle, LB_RESETCONTENT, 0, 0);
490 }
491
492}
493
494impl<D: Display+Default> Drop for ListBox<D> {
495 fn drop(&mut self) {
496 self.handle.destroy();
497 }
498}
499
500pub struct ListBoxBuilder<'a, D: Display+Default> {
501 size: (i32, i32),
502 position: (i32, i32),
503 enabled: bool,
504 focus: bool,
505 flags: Option<ListBoxFlags>,
506 ex_flags: u32,
507 font: Option<&'a Font>,
508 collection: Option<Vec<D>>,
509 selected_index: Option<usize>,
510 multi_selection: Vec<usize>,
511 parent: Option<ControlHandle>
512}
513
514impl<'a, D: Display+Default> ListBoxBuilder<'a, D> {
515
516 pub fn flags(mut self, flags: ListBoxFlags) -> ListBoxBuilder<'a, D> {
517 self.flags = Some(flags);
518 self
519 }
520
521 pub fn ex_flags(mut self, flags: u32) -> ListBoxBuilder<'a, D> {
522 self.ex_flags = flags;
523 self
524 }
525
526 pub fn size(mut self, size: (i32, i32)) -> ListBoxBuilder<'a, D> {
527 self.size = size;
528 self
529 }
530
531 pub fn position(mut self, pos: (i32, i32)) -> ListBoxBuilder<'a, D> {
532 self.position = pos;
533 self
534 }
535
536 pub fn font(mut self, font: Option<&'a Font>) -> ListBoxBuilder<'a, D> {
537 self.font = font;
538 self
539 }
540
541 pub fn parent<C: Into<ControlHandle>>(mut self, p: C) -> ListBoxBuilder<'a, D> {
542 self.parent = Some(p.into());
543 self
544 }
545
546 pub fn collection(mut self, collection: Vec<D>) -> ListBoxBuilder<'a, D> {
547 self.collection = Some(collection);
548 self
549 }
550
551 pub fn selected_index(mut self, index: Option<usize>) -> ListBoxBuilder<'a, D> {
552 self.selected_index = index;
553 self
554 }
555
556 pub fn multi_selection(mut self, select: Vec<usize>) -> ListBoxBuilder<'a, D> {
557 self.multi_selection = select;
558 self
559 }
560
561 pub fn enabled(mut self, enabled: bool) -> ListBoxBuilder<'a, D> {
562 self.enabled = enabled;
563 self
564 }
565
566 pub fn focus(mut self, focus: bool) -> ListBoxBuilder<'a, D> {
567 self.focus = focus;
568 self
569 }
570
571 pub fn build(self, out: &mut ListBox<D>) -> Result<(), NwgError> {
572 let flags = self.flags.map(|f| f.bits()).unwrap_or(out.flags());
573
574 let parent = match self.parent {
575 Some(p) => Ok(p),
576 None => Err(NwgError::no_parent("ListBox"))
577 }?;
578
579 *out = Default::default();
580
581 out.handle = ControlBase::build_hwnd()
582 .class_name(out.class_name())
583 .forced_flags(out.forced_flags())
584 .flags(flags)
585 .ex_flags(self.ex_flags)
586 .size(self.size)
587 .position(self.position)
588 .parent(Some(parent))
589 .build()?;
590
591 if self.font.is_some() {
592 out.set_font(self.font);
593 } else {
594 out.set_font(Font::global_default().as_ref());
595 }
596
597 if let Some(col) = self.collection {
598 out.set_collection(col);
599 }
600
601 if flags & LBS_MULTIPLESEL == LBS_MULTIPLESEL {
602 for i in self.multi_selection {
603 out.multi_add_selection(i);
604 }
605 } else {
606 out.set_selection(self.selected_index);
607 }
608
609 if self.focus {
610 out.set_focus();
611 }
612
613 if !self.enabled {
614 out.set_enabled(self.enabled);
615 }
616
617 Ok(())
618 }
619
620}
621
622impl<D: Display+Default> PartialEq for ListBox<D> {
623 fn eq(&self, other: &Self) -> bool {
624 self.handle == other.handle
625 }
626}