erm/vendor/github.com/lxn/walk/dateedit.go

273 lines
5.6 KiB
Go
Raw Normal View History

2021-07-30 22:29:20 +00:00
// Copyright 2011 The Walk Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build windows
package walk
import (
"strings"
"syscall"
"time"
"unsafe"
"github.com/lxn/win"
)
type DateEdit struct {
WidgetBase
dateChangedPublisher EventPublisher
format string
}
func newDateEdit(parent Container, style uint32) (*DateEdit, error) {
de := new(DateEdit)
if err := InitWidget(
de,
parent,
"SysDateTimePick32",
win.WS_TABSTOP|win.WS_VISIBLE|win.DTS_SHORTDATEFORMAT|style,
0); err != nil {
return nil, err
}
if style&win.DTS_SHOWNONE != 0 {
de.setSystemTime(nil)
}
de.GraphicsEffects().Add(InteractionEffect)
de.GraphicsEffects().Add(FocusEffect)
de.MustRegisterProperty("Date", NewProperty(
func() interface{} {
return de.Date()
},
func(v interface{}) error {
return de.SetDate(assertTimeOr(v, time.Time{}))
},
de.dateChangedPublisher.Event()))
return de, nil
}
func NewDateEdit(parent Container) (*DateEdit, error) {
return newDateEdit(parent, 0)
}
func NewDateEditWithNoneOption(parent Container) (*DateEdit, error) {
return newDateEdit(parent, win.DTS_SHOWNONE)
}
func (de *DateEdit) systemTimeToTime(st *win.SYSTEMTIME) time.Time {
if st == nil || !de.hasStyleBits(win.DTS_SHOWNONE) && st.WYear == 1601 && st.WMonth == 1 && st.WDay == 1 {
return time.Time{}
}
var hour, minute, second int
if de.timeOfDayDisplayed() {
hour = int(st.WHour)
minute = int(st.WMinute)
second = int(st.WSecond)
}
return time.Date(int(st.WYear), time.Month(st.WMonth), int(st.WDay), hour, minute, second, 0, time.Local)
}
func (de *DateEdit) timeToSystemTime(t time.Time) *win.SYSTEMTIME {
if t.Year() < 1601 {
if de.hasStyleBits(win.DTS_SHOWNONE) {
return nil
} else {
return &win.SYSTEMTIME{
WYear: uint16(1601),
WMonth: uint16(1),
WDay: uint16(1),
}
}
}
st := &win.SYSTEMTIME{
WYear: uint16(t.Year()),
WMonth: uint16(t.Month()),
WDay: uint16(t.Day()),
}
if de.timeOfDayDisplayed() {
st.WHour = uint16(t.Hour())
st.WMinute = uint16(t.Minute())
st.WSecond = uint16(t.Second())
}
return st
}
func (de *DateEdit) systemTime() (*win.SYSTEMTIME, error) {
var st win.SYSTEMTIME
switch de.SendMessage(win.DTM_GETSYSTEMTIME, 0, uintptr(unsafe.Pointer(&st))) {
case win.GDT_VALID:
return &st, nil
case win.GDT_NONE:
return nil, nil
}
return nil, newError("SendMessage(DTM_GETSYSTEMTIME)")
}
func (de *DateEdit) setSystemTime(st *win.SYSTEMTIME) error {
var wParam uintptr
if st != nil {
wParam = win.GDT_VALID
} else {
// Ensure today's date is displayed.
de.setSystemTime(de.timeToSystemTime(time.Now()))
wParam = win.GDT_NONE
}
if 0 == de.SendMessage(win.DTM_SETSYSTEMTIME, wParam, uintptr(unsafe.Pointer(st))) {
return newError("SendMessage(DTM_SETSYSTEMTIME)")
}
return nil
}
func (de *DateEdit) timeOfDayDisplayed() bool {
return strings.ContainsAny(de.format, "Hhms")
}
func (de *DateEdit) Format() string {
return de.format
}
func (de *DateEdit) SetFormat(format string) error {
lp := uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(format)))
if 0 == de.SendMessage(win.DTM_SETFORMAT, 0, lp) {
return newError("DTM_SETFORMAT failed")
}
de.format = format
return nil
}
func (de *DateEdit) Range() (min, max time.Time) {
var st [2]win.SYSTEMTIME
ret := de.SendMessage(win.DTM_GETRANGE, 0, uintptr(unsafe.Pointer(&st[0])))
if ret&win.GDTR_MIN > 0 {
min = de.systemTimeToTime(&st[0])
}
if ret&win.GDTR_MAX > 0 {
max = de.systemTimeToTime(&st[1])
}
return
}
func (de *DateEdit) SetRange(min, max time.Time) error {
if !min.IsZero() && !max.IsZero() {
if min.Year() > max.Year() ||
min.Year() == max.Year() && min.Month() > max.Month() ||
min.Year() == max.Year() && min.Month() == max.Month() && min.Day() > max.Day() {
return newError("invalid range")
}
}
var st [2]win.SYSTEMTIME
var wParam uintptr
if !min.IsZero() {
wParam |= win.GDTR_MIN
st[0] = *de.timeToSystemTime(min)
}
if !max.IsZero() {
wParam |= win.GDTR_MAX
st[1] = *de.timeToSystemTime(max)
}
if 0 == de.SendMessage(win.DTM_SETRANGE, wParam, uintptr(unsafe.Pointer(&st[0]))) {
return newError("SendMessage(DTM_SETRANGE)")
}
return nil
}
func (de *DateEdit) Date() time.Time {
st, err := de.systemTime()
if err != nil || st == nil {
return time.Time{}
}
return de.systemTimeToTime(st)
}
func (de *DateEdit) SetDate(date time.Time) error {
stNew := de.timeToSystemTime(date)
stOld, err := de.systemTime()
if err != nil {
return err
} else if stNew == stOld || stNew != nil && stOld != nil && *stNew == *stOld {
return nil
}
if err := de.setSystemTime(stNew); err != nil {
return err
}
de.dateChangedPublisher.Publish()
return nil
}
func (de *DateEdit) DateChanged() *Event {
return de.dateChangedPublisher.Event()
}
func (de *DateEdit) WndProc(hwnd win.HWND, msg uint32, wParam, lParam uintptr) uintptr {
switch msg {
case win.WM_NOTIFY:
switch uint32(((*win.NMHDR)(unsafe.Pointer(lParam))).Code) {
case win.DTN_DATETIMECHANGE:
de.dateChangedPublisher.Publish()
}
}
return de.WidgetBase.WndProc(hwnd, msg, wParam, lParam)
}
func (*DateEdit) NeedsWmSize() bool {
return true
}
func (de *DateEdit) CreateLayoutItem(ctx *LayoutContext) LayoutItem {
return &dateEditLayoutItem{
idealSize: de.dialogBaseUnitsToPixels(Size{80, 12}),
}
}
type dateEditLayoutItem struct {
LayoutItemBase
idealSize Size // in native pixels
}
func (*dateEditLayoutItem) LayoutFlags() LayoutFlags {
return GrowableHorz
}
func (li *dateEditLayoutItem) IdealSize() Size {
return li.idealSize
}
func (li *dateEditLayoutItem) MinSize() Size {
return li.idealSize
}