1use super::{ControlBase, ControlHandle};
2use crate::win32::base_helper::{check_hwnd, to_utf16};
3use crate::win32::window_helper as wh;
4use crate::{Font, NwgError};
5use winapi::um::winuser::{WS_DISABLED, WS_TABSTOP, WS_VISIBLE};
6
7const NOT_BOUND: &'static str = "DatePicker is not yet bound to a winapi object";
8const BAD_HANDLE: &'static str = "INTERNAL ERROR: DatePicker handle is not HWND!";
9
10bitflags! {
11
12 pub struct DatePickerFlags: u32 {
21 const VISIBLE = WS_VISIBLE;
22 const DISABLED = WS_DISABLED;
23 const TAB_STOP = WS_TABSTOP;
24 }
25}
26
27#[derive(Clone, Copy, PartialEq, Debug)]
32pub struct DatePickerValue {
33 pub year: u16,
34 pub month: u16,
35 pub day: u16,
36}
37
38#[derive(Default, PartialEq, Eq)]
84pub struct DatePicker {
85 pub handle: ControlHandle,
86}
87
88impl DatePicker {
89 pub fn builder<'a>() -> DatePickerBuilder<'a> {
90 DatePickerBuilder {
91 size: (100, 25),
92 position: (0, 0),
93 focus: false,
94 flags: None,
95 ex_flags: 0,
96 font: None,
97 parent: None,
98 date: None,
99 format: None,
100 range: None,
101 }
102 }
103
104 pub fn set_format<'a>(&self, format: Option<&'a str>) {
134 use winapi::shared::minwindef::LPARAM;
135 use winapi::um::commctrl::DTM_SETFORMATW;
136
137 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
138
139 let (_format, format_ptr) = if format.is_some() {
140 let f = to_utf16(format.unwrap());
141 let fptr = f.as_ptr() as LPARAM;
142 (f, fptr)
143 } else {
144 (Vec::new(), 0)
145 };
146
147 wh::send_message(handle, DTM_SETFORMATW, 0, format_ptr);
148 }
149
150 pub fn checked(&self) -> bool {
157 use winapi::um::winuser::STATE_SYSTEM_CHECKED;
158
159 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
160
161 let info = get_dtp_info(handle);
162
163 match info.stateCheck {
164 STATE_SYSTEM_CHECKED => true,
165 _ => false,
166 }
167 }
168
169 pub fn close_calendar(&self) {
171 use winapi::um::commctrl::DTM_CLOSEMONTHCAL;
172 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
173 wh::send_message(handle, DTM_CLOSEMONTHCAL, 0, 0);
174 }
175
176 pub fn value(&self) -> Option<DatePickerValue> {
182 use std::mem;
183 use winapi::shared::minwindef::LPARAM;
184 use winapi::um::commctrl::{DTM_GETSYSTEMTIME, GDT_VALID};
185 use winapi::um::minwinbase::SYSTEMTIME;
186
187 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
188
189 let mut syst: SYSTEMTIME = unsafe { mem::zeroed() };
190 let syst_ptr = &mut syst as *mut _;
191
192 let r = wh::send_message(handle, DTM_GETSYSTEMTIME, 0, syst_ptr as LPARAM);
193 match r {
194 GDT_VALID => Some(DatePickerValue {
195 year: syst.wYear,
196 month: syst.wMonth,
197 day: syst.wDay,
198 }),
199 _ => None,
200 }
201 }
202
203 pub fn set_value(&self, date: Option<DatePickerValue>) {
208 use winapi::shared::minwindef::{LPARAM, WPARAM};
209 use winapi::um::commctrl::{DTM_SETSYSTEMTIME, GDT_NONE, GDT_VALID};
210 use winapi::um::minwinbase::SYSTEMTIME;
211
212 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
213
214 match date {
215 Some(date) => {
216 let syst: SYSTEMTIME = SYSTEMTIME {
217 wYear: date.year,
218 wMonth: date.month,
219 wDay: date.day,
220 wDayOfWeek: 0,
221 wHour: 0,
222 wMinute: 0,
223 wSecond: 0,
224 wMilliseconds: 0,
225 };
226
227 wh::send_message(
228 handle,
229 DTM_SETSYSTEMTIME,
230 GDT_VALID as WPARAM,
231 &syst as *const SYSTEMTIME as LPARAM,
232 );
233 }
234 None => {
235 wh::send_message(handle, DTM_SETSYSTEMTIME, GDT_NONE as WPARAM, 0);
236 }
237 };
238 }
239
240 pub fn range(&self) -> [DatePickerValue; 2] {
242 use std::mem;
243 use winapi::shared::minwindef::LPARAM;
244 use winapi::um::commctrl::DTM_GETRANGE;
245 use winapi::um::minwinbase::SYSTEMTIME;
246
247 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
248
249 let mut tr: [SYSTEMTIME; 2] = unsafe { mem::zeroed() };
250
251 wh::send_message(
252 handle,
253 DTM_GETRANGE,
254 0,
255 &mut tr as *mut [SYSTEMTIME; 2] as LPARAM,
256 );
257
258 [
259 DatePickerValue {
260 year: tr[0].wYear,
261 month: tr[0].wMonth,
262 day: tr[0].wDay,
263 },
264 DatePickerValue {
265 year: tr[1].wYear,
266 month: tr[1].wMonth,
267 day: tr[1].wDay,
268 },
269 ]
270 }
271
272 pub fn set_range(&self, r: &[DatePickerValue; 2]) {
274 use winapi::shared::minwindef::LPARAM;
275 use winapi::um::commctrl::DTM_SETRANGE;
276 use winapi::um::commctrl::{GDTR_MAX, GDTR_MIN};
277 use winapi::um::minwinbase::SYSTEMTIME;
278
279 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
280
281 let values = [
282 SYSTEMTIME {
283 wYear: r[0].year,
284 wMonth: r[0].month,
285 wDayOfWeek: 0,
286 wDay: r[0].day,
287 wHour: 0,
288 wMinute: 0,
289 wSecond: 0,
290 wMilliseconds: 0,
291 },
292 SYSTEMTIME {
293 wYear: r[1].year,
294 wMonth: r[1].month,
295 wDayOfWeek: 0,
296 wDay: r[1].day,
297 wHour: 0,
298 wMinute: 0,
299 wSecond: 0,
300 wMilliseconds: 0,
301 },
302 ];
303
304 wh::send_message(
305 handle,
306 DTM_SETRANGE,
307 GDTR_MIN | GDTR_MAX,
308 &values as *const [SYSTEMTIME; 2] as LPARAM,
309 );
310 }
311
312 pub fn font(&self) -> Option<Font> {
314 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
315 let font_handle = wh::get_window_font(handle);
316 if font_handle.is_null() {
317 None
318 } else {
319 Some(Font {
320 handle: font_handle,
321 })
322 }
323 }
324
325 pub fn set_font(&self, font: Option<&Font>) {
327 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
328
329 wh::set_window_font(handle, font.map(|f| f.handle), true);
330 }
331
332 pub fn focus(&self) -> bool {
334 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
335 wh::get_focus(handle)
336 }
337
338 pub fn set_focus(&self) {
340 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
341
342 wh::set_focus(handle);
343 }
344
345 pub fn enabled(&self) -> bool {
347 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
348 wh::get_window_enabled(handle)
349 }
350
351 pub fn set_enabled(&self, v: bool) {
353 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
354 wh::set_window_enabled(handle, v)
355 }
356
357 pub fn visible(&self) -> bool {
360 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
361 wh::get_window_visibility(handle)
362 }
363
364 pub fn set_visible(&self, v: bool) {
366 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
367 wh::set_window_visibility(handle, v)
368 }
369
370 pub fn size(&self) -> (u32, u32) {
372 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
373 wh::get_window_size(handle)
374 }
375
376 pub fn set_size(&self, x: u32, y: u32) {
378 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
379 wh::set_window_size(handle, x, y, false)
380 }
381
382 pub fn position(&self) -> (i32, i32) {
384 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
385 wh::get_window_position(handle)
386 }
387
388 pub fn set_position(&self, x: i32, y: i32) {
390 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
391 wh::set_window_position(handle, x, y)
392 }
393
394 pub fn class_name(&self) -> &'static str {
396 "SysDateTimePick32"
397 }
398
399 pub fn flags(&self) -> u32 {
401 WS_VISIBLE | WS_TABSTOP
402 }
403
404 pub fn forced_flags(&self) -> u32 {
406 use winapi::um::commctrl::DTS_SHOWNONE;
407 use winapi::um::winuser::WS_CHILD;
408
409 WS_CHILD | DTS_SHOWNONE
410 }
411}
412
413impl Drop for DatePicker {
414 fn drop(&mut self) {
415 self.handle.destroy();
416 }
417}
418
419pub struct DatePickerBuilder<'a> {
420 size: (i32, i32),
421 position: (i32, i32),
422 flags: Option<DatePickerFlags>,
423 ex_flags: u32,
424 font: Option<&'a Font>,
425 focus: bool,
426 parent: Option<ControlHandle>,
427 date: Option<DatePickerValue>,
428 format: Option<&'a str>,
429 range: Option<[DatePickerValue; 2]>,
430}
431
432impl<'a> DatePickerBuilder<'a> {
433 pub fn flags(mut self, flags: DatePickerFlags) -> DatePickerBuilder<'a> {
434 self.flags = Some(flags);
435 self
436 }
437
438 pub fn ex_flags(mut self, flags: u32) -> DatePickerBuilder<'a> {
439 self.ex_flags = flags;
440 self
441 }
442
443 pub fn size(mut self, size: (i32, i32)) -> DatePickerBuilder<'a> {
444 self.size = size;
445 self
446 }
447
448 pub fn position(mut self, pos: (i32, i32)) -> DatePickerBuilder<'a> {
449 self.position = pos;
450 self
451 }
452
453 pub fn font(mut self, font: Option<&'a Font>) -> DatePickerBuilder<'a> {
454 self.font = font;
455 self
456 }
457
458 pub fn parent<C: Into<ControlHandle>>(mut self, p: C) -> DatePickerBuilder<'a> {
459 self.parent = Some(p.into());
460 self
461 }
462
463 pub fn date(mut self, date: Option<DatePickerValue>) -> DatePickerBuilder<'a> {
464 self.date = date;
465 self
466 }
467
468 pub fn format(mut self, format: Option<&'a str>) -> DatePickerBuilder<'a> {
469 self.format = format;
470 self
471 }
472
473 pub fn range(mut self, range: Option<[DatePickerValue; 2]>) -> DatePickerBuilder<'a> {
474 self.range = range;
475 self
476 }
477
478 pub fn focus(mut self, focus: bool) -> DatePickerBuilder<'a> {
479 self.focus = focus;
480 self
481 }
482
483 pub fn build(self, out: &mut DatePicker) -> Result<(), NwgError> {
484 let flags = self.flags.map(|f| f.bits()).unwrap_or(out.flags());
485
486 let parent = match self.parent {
487 Some(p) => Ok(p),
488 None => Err(NwgError::no_parent("DatePicker")),
489 }?;
490
491 *out = Default::default();
492
493 out.handle = ControlBase::build_hwnd()
494 .class_name(out.class_name())
495 .forced_flags(out.forced_flags())
496 .flags(flags)
497 .ex_flags(self.ex_flags)
498 .size(self.size)
499 .position(self.position)
500 .parent(Some(parent))
501 .build()?;
502
503 if self.font.is_some() {
504 out.set_font(self.font);
505 } else {
506 out.set_font(Font::global_default().as_ref());
507 }
508
509 if self.date.is_some() {
510 out.set_value(self.date)
511 }
512
513 if self.range.is_some() {
514 out.set_range(&self.range.unwrap());
515 }
516
517 if self.format.is_some() {
518 out.set_format(self.format);
519 }
520
521 if self.focus {
522 out.set_focus();
523 }
524
525 Ok(())
526 }
527}
528
529use winapi::shared::windef::HWND;
530use winapi::um::commctrl::DATETIMEPICKERINFO;
531
532fn get_dtp_info(handle: HWND) -> DATETIMEPICKERINFO {
533 use std::mem;
534 use winapi::shared::minwindef::{DWORD, LPARAM};
535 use winapi::um::commctrl::DTM_GETDATETIMEPICKERINFO;
536
537 let mut dtp_info: DATETIMEPICKERINFO = unsafe { mem::zeroed() };
538 dtp_info.cbSize = mem::size_of::<DATETIMEPICKERINFO>() as DWORD;
539 let dtp_info_ptr = &mut dtp_info as *mut _;
540 wh::send_message(handle, DTM_GETDATETIMEPICKERINFO, 0, dtp_info_ptr as LPARAM);
541
542 dtp_info
543}