use super::{ControlBase, ControlHandle};
use crate::win32::base_helper::{check_hwnd, to_utf16};
use crate::win32::window_helper as wh;
use crate::{Font, NwgError};
use winapi::um::winuser::{WS_DISABLED, WS_TABSTOP, WS_VISIBLE};
const NOT_BOUND: &'static str = "DatePicker is not yet bound to a winapi object";
const BAD_HANDLE: &'static str = "INTERNAL ERROR: DatePicker handle is not HWND!";
bitflags! {
pub struct DatePickerFlags: u32 {
const VISIBLE = WS_VISIBLE;
const DISABLED = WS_DISABLED;
const TAB_STOP = WS_TABSTOP;
}
}
#[derive(Clone, Copy, PartialEq, Debug)]
pub struct DatePickerValue {
pub year: u16,
pub month: u16,
pub day: u16,
}
#[derive(Default, PartialEq, Eq)]
pub struct DatePicker {
pub handle: ControlHandle,
}
impl DatePicker {
pub fn builder<'a>() -> DatePickerBuilder<'a> {
DatePickerBuilder {
size: (100, 25),
position: (0, 0),
focus: false,
flags: None,
ex_flags: 0,
font: None,
parent: None,
date: None,
format: None,
range: None,
}
}
pub fn set_format<'a>(&self, format: Option<&'a str>) {
use winapi::shared::minwindef::LPARAM;
use winapi::um::commctrl::DTM_SETFORMATW;
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
let (_format, format_ptr) = if format.is_some() {
let f = to_utf16(format.unwrap());
let fptr = f.as_ptr() as LPARAM;
(f, fptr)
} else {
(Vec::new(), 0)
};
wh::send_message(handle, DTM_SETFORMATW, 0, format_ptr);
}
pub fn checked(&self) -> bool {
use winapi::um::winuser::STATE_SYSTEM_CHECKED;
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
let info = get_dtp_info(handle);
match info.stateCheck {
STATE_SYSTEM_CHECKED => true,
_ => false,
}
}
pub fn close_calendar(&self) {
use winapi::um::commctrl::DTM_CLOSEMONTHCAL;
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
wh::send_message(handle, DTM_CLOSEMONTHCAL, 0, 0);
}
pub fn value(&self) -> Option<DatePickerValue> {
use std::mem;
use winapi::shared::minwindef::LPARAM;
use winapi::um::commctrl::{DTM_GETSYSTEMTIME, GDT_VALID};
use winapi::um::minwinbase::SYSTEMTIME;
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
let mut syst: SYSTEMTIME = unsafe { mem::zeroed() };
let syst_ptr = &mut syst as *mut _;
let r = wh::send_message(handle, DTM_GETSYSTEMTIME, 0, syst_ptr as LPARAM);
match r {
GDT_VALID => Some(DatePickerValue {
year: syst.wYear,
month: syst.wMonth,
day: syst.wDay,
}),
_ => None,
}
}
pub fn set_value(&self, date: Option<DatePickerValue>) {
use winapi::shared::minwindef::{LPARAM, WPARAM};
use winapi::um::commctrl::{DTM_SETSYSTEMTIME, GDT_NONE, GDT_VALID};
use winapi::um::minwinbase::SYSTEMTIME;
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
match date {
Some(date) => {
let syst: SYSTEMTIME = SYSTEMTIME {
wYear: date.year,
wMonth: date.month,
wDay: date.day,
wDayOfWeek: 0,
wHour: 0,
wMinute: 0,
wSecond: 0,
wMilliseconds: 0,
};
wh::send_message(
handle,
DTM_SETSYSTEMTIME,
GDT_VALID as WPARAM,
&syst as *const SYSTEMTIME as LPARAM,
);
}
None => {
wh::send_message(handle, DTM_SETSYSTEMTIME, GDT_NONE as WPARAM, 0);
}
};
}
pub fn range(&self) -> [DatePickerValue; 2] {
use std::mem;
use winapi::shared::minwindef::LPARAM;
use winapi::um::commctrl::DTM_GETRANGE;
use winapi::um::minwinbase::SYSTEMTIME;
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
let mut tr: [SYSTEMTIME; 2] = unsafe { mem::zeroed() };
wh::send_message(
handle,
DTM_GETRANGE,
0,
&mut tr as *mut [SYSTEMTIME; 2] as LPARAM,
);
[
DatePickerValue {
year: tr[0].wYear,
month: tr[0].wMonth,
day: tr[0].wDay,
},
DatePickerValue {
year: tr[1].wYear,
month: tr[1].wMonth,
day: tr[1].wDay,
},
]
}
pub fn set_range(&self, r: &[DatePickerValue; 2]) {
use winapi::shared::minwindef::LPARAM;
use winapi::um::commctrl::DTM_SETRANGE;
use winapi::um::commctrl::{GDTR_MAX, GDTR_MIN};
use winapi::um::minwinbase::SYSTEMTIME;
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
let values = [
SYSTEMTIME {
wYear: r[0].year,
wMonth: r[0].month,
wDayOfWeek: 0,
wDay: r[0].day,
wHour: 0,
wMinute: 0,
wSecond: 0,
wMilliseconds: 0,
},
SYSTEMTIME {
wYear: r[1].year,
wMonth: r[1].month,
wDayOfWeek: 0,
wDay: r[1].day,
wHour: 0,
wMinute: 0,
wSecond: 0,
wMilliseconds: 0,
},
];
wh::send_message(
handle,
DTM_SETRANGE,
GDTR_MIN | GDTR_MAX,
&values as *const [SYSTEMTIME; 2] as LPARAM,
);
}
pub fn font(&self) -> Option<Font> {
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
let font_handle = wh::get_window_font(handle);
if font_handle.is_null() {
None
} else {
Some(Font {
handle: font_handle,
})
}
}
pub fn set_font(&self, font: Option<&Font>) {
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
wh::set_window_font(handle, font.map(|f| f.handle), true);
}
pub fn focus(&self) -> bool {
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
wh::get_focus(handle)
}
pub fn set_focus(&self) {
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
wh::set_focus(handle);
}
pub fn enabled(&self) -> bool {
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
wh::get_window_enabled(handle)
}
pub fn set_enabled(&self, v: bool) {
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
wh::set_window_enabled(handle, v)
}
pub fn visible(&self) -> bool {
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
wh::get_window_visibility(handle)
}
pub fn set_visible(&self, v: bool) {
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
wh::set_window_visibility(handle, v)
}
pub fn size(&self) -> (u32, u32) {
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
wh::get_window_size(handle)
}
pub fn set_size(&self, x: u32, y: u32) {
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
wh::set_window_size(handle, x, y, false)
}
pub fn position(&self) -> (i32, i32) {
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
wh::get_window_position(handle)
}
pub fn set_position(&self, x: i32, y: i32) {
let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
wh::set_window_position(handle, x, y)
}
pub fn class_name(&self) -> &'static str {
"SysDateTimePick32"
}
pub fn flags(&self) -> u32 {
WS_VISIBLE | WS_TABSTOP
}
pub fn forced_flags(&self) -> u32 {
use winapi::um::commctrl::DTS_SHOWNONE;
use winapi::um::winuser::WS_CHILD;
WS_CHILD | DTS_SHOWNONE
}
}
impl Drop for DatePicker {
fn drop(&mut self) {
self.handle.destroy();
}
}
pub struct DatePickerBuilder<'a> {
size: (i32, i32),
position: (i32, i32),
flags: Option<DatePickerFlags>,
ex_flags: u32,
font: Option<&'a Font>,
focus: bool,
parent: Option<ControlHandle>,
date: Option<DatePickerValue>,
format: Option<&'a str>,
range: Option<[DatePickerValue; 2]>,
}
impl<'a> DatePickerBuilder<'a> {
pub fn flags(mut self, flags: DatePickerFlags) -> DatePickerBuilder<'a> {
self.flags = Some(flags);
self
}
pub fn ex_flags(mut self, flags: u32) -> DatePickerBuilder<'a> {
self.ex_flags = flags;
self
}
pub fn size(mut self, size: (i32, i32)) -> DatePickerBuilder<'a> {
self.size = size;
self
}
pub fn position(mut self, pos: (i32, i32)) -> DatePickerBuilder<'a> {
self.position = pos;
self
}
pub fn font(mut self, font: Option<&'a Font>) -> DatePickerBuilder<'a> {
self.font = font;
self
}
pub fn parent<C: Into<ControlHandle>>(mut self, p: C) -> DatePickerBuilder<'a> {
self.parent = Some(p.into());
self
}
pub fn date(mut self, date: Option<DatePickerValue>) -> DatePickerBuilder<'a> {
self.date = date;
self
}
pub fn format(mut self, format: Option<&'a str>) -> DatePickerBuilder<'a> {
self.format = format;
self
}
pub fn range(mut self, range: Option<[DatePickerValue; 2]>) -> DatePickerBuilder<'a> {
self.range = range;
self
}
pub fn focus(mut self, focus: bool) -> DatePickerBuilder<'a> {
self.focus = focus;
self
}
pub fn build(self, out: &mut DatePicker) -> Result<(), NwgError> {
let flags = self.flags.map(|f| f.bits()).unwrap_or(out.flags());
let parent = match self.parent {
Some(p) => Ok(p),
None => Err(NwgError::no_parent("DatePicker")),
}?;
*out = Default::default();
out.handle = ControlBase::build_hwnd()
.class_name(out.class_name())
.forced_flags(out.forced_flags())
.flags(flags)
.ex_flags(self.ex_flags)
.size(self.size)
.position(self.position)
.parent(Some(parent))
.build()?;
if self.font.is_some() {
out.set_font(self.font);
} else {
out.set_font(Font::global_default().as_ref());
}
if self.date.is_some() {
out.set_value(self.date)
}
if self.range.is_some() {
out.set_range(&self.range.unwrap());
}
if self.format.is_some() {
out.set_format(self.format);
}
if self.focus {
out.set_focus();
}
Ok(())
}
}
use winapi::shared::windef::HWND;
use winapi::um::commctrl::DATETIMEPICKERINFO;
fn get_dtp_info(handle: HWND) -> DATETIMEPICKERINFO {
use std::mem;
use winapi::shared::minwindef::{DWORD, LPARAM};
use winapi::um::commctrl::DTM_GETDATETIMEPICKERINFO;
let mut dtp_info: DATETIMEPICKERINFO = unsafe { mem::zeroed() };
dtp_info.cbSize = mem::size_of::<DATETIMEPICKERINFO>() as DWORD;
let dtp_info_ptr = &mut dtp_info as *mut _;
wh::send_message(handle, DTM_GETDATETIMEPICKERINFO, 0, dtp_info_ptr as LPARAM);
dtp_info
}