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