dateedit.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. // Copyright 2011 The Walk Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. // +build windows
  5. package walk
  6. import (
  7. "strings"
  8. "syscall"
  9. "time"
  10. "unsafe"
  11. )
  12. import (
  13. "github.com/lxn/win"
  14. )
  15. type DateEdit struct {
  16. WidgetBase
  17. dateChangedPublisher EventPublisher
  18. format string
  19. }
  20. func newDateEdit(parent Container, style uint32) (*DateEdit, error) {
  21. de := new(DateEdit)
  22. if err := InitWidget(
  23. de,
  24. parent,
  25. "SysDateTimePick32",
  26. win.WS_TABSTOP|win.WS_VISIBLE|win.DTS_SHORTDATEFORMAT|style,
  27. 0); err != nil {
  28. return nil, err
  29. }
  30. de.MustRegisterProperty("Date", NewProperty(
  31. func() interface{} {
  32. return de.Date()
  33. },
  34. func(v interface{}) error {
  35. return de.SetDate(v.(time.Time))
  36. },
  37. de.dateChangedPublisher.Event()))
  38. return de, nil
  39. }
  40. func NewDateEdit(parent Container) (*DateEdit, error) {
  41. return newDateEdit(parent, 0)
  42. }
  43. func NewDateEditWithNoneOption(parent Container) (*DateEdit, error) {
  44. return newDateEdit(parent, win.DTS_SHOWNONE)
  45. }
  46. func (*DateEdit) LayoutFlags() LayoutFlags {
  47. return GrowableHorz
  48. }
  49. func (de *DateEdit) MinSizeHint() Size {
  50. return de.dialogBaseUnitsToPixels(Size{80, 12})
  51. }
  52. func (de *DateEdit) SizeHint() Size {
  53. return de.MinSizeHint()
  54. }
  55. func (de *DateEdit) systemTimeToTime(st *win.SYSTEMTIME) time.Time {
  56. if st == nil || !de.hasStyleBits(win.DTS_SHOWNONE) && st.WYear == 1601 && st.WMonth == 1 && st.WDay == 1 {
  57. return time.Time{}
  58. }
  59. var hour, minute, second int
  60. if de.timeOfDayDisplayed() {
  61. hour = int(st.WHour)
  62. minute = int(st.WMinute)
  63. second = int(st.WSecond)
  64. }
  65. return time.Date(int(st.WYear), time.Month(st.WMonth), int(st.WDay), hour, minute, second, 0, time.Local)
  66. }
  67. func (de *DateEdit) timeToSystemTime(t time.Time) *win.SYSTEMTIME {
  68. if t.Year() < 1601 {
  69. if de.hasStyleBits(win.DTS_SHOWNONE) {
  70. return nil
  71. } else {
  72. return &win.SYSTEMTIME{
  73. WYear: uint16(1601),
  74. WMonth: uint16(1),
  75. WDay: uint16(1),
  76. }
  77. }
  78. }
  79. st := &win.SYSTEMTIME{
  80. WYear: uint16(t.Year()),
  81. WMonth: uint16(t.Month()),
  82. WDay: uint16(t.Day()),
  83. }
  84. if de.timeOfDayDisplayed() {
  85. st.WHour = uint16(t.Hour())
  86. st.WMinute = uint16(t.Minute())
  87. st.WSecond = uint16(t.Second())
  88. }
  89. return st
  90. }
  91. func (de *DateEdit) systemTime() (*win.SYSTEMTIME, error) {
  92. var st win.SYSTEMTIME
  93. switch de.SendMessage(win.DTM_GETSYSTEMTIME, 0, uintptr(unsafe.Pointer(&st))) {
  94. case win.GDT_VALID:
  95. return &st, nil
  96. case win.GDT_NONE:
  97. return nil, nil
  98. }
  99. return nil, newError("SendMessage(DTM_GETSYSTEMTIME)")
  100. }
  101. func (de *DateEdit) setSystemTime(st *win.SYSTEMTIME) error {
  102. var wParam uintptr
  103. if st != nil {
  104. wParam = win.GDT_VALID
  105. } else {
  106. // Ensure today's date is displayed.
  107. de.setSystemTime(de.timeToSystemTime(time.Now()))
  108. wParam = win.GDT_NONE
  109. }
  110. if 0 == de.SendMessage(win.DTM_SETSYSTEMTIME, wParam, uintptr(unsafe.Pointer(st))) {
  111. return newError("SendMessage(DTM_SETSYSTEMTIME)")
  112. }
  113. de.dateChangedPublisher.Publish()
  114. return nil
  115. }
  116. func (de *DateEdit) timeOfDayDisplayed() bool {
  117. return strings.ContainsAny(de.format, "Hhms")
  118. }
  119. func (de *DateEdit) Format() string {
  120. return de.format
  121. }
  122. func (de *DateEdit) SetFormat(format string) error {
  123. lp := uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(format)))
  124. if 0 == de.SendMessage(win.DTM_SETFORMAT, 0, lp) {
  125. return newErr("DTM_SETFORMAT failed")
  126. }
  127. de.format = format
  128. return nil
  129. }
  130. func (de *DateEdit) Range() (min, max time.Time) {
  131. var st [2]win.SYSTEMTIME
  132. ret := de.SendMessage(win.DTM_GETRANGE, 0, uintptr(unsafe.Pointer(&st[0])))
  133. if ret&win.GDTR_MIN > 0 {
  134. min = de.systemTimeToTime(&st[0])
  135. }
  136. if ret&win.GDTR_MAX > 0 {
  137. max = de.systemTimeToTime(&st[1])
  138. }
  139. return
  140. }
  141. func (de *DateEdit) SetRange(min, max time.Time) error {
  142. if !min.IsZero() && !max.IsZero() {
  143. if min.Year() > max.Year() ||
  144. min.Year() == max.Year() && min.Month() > max.Month() ||
  145. min.Year() == max.Year() && min.Month() == max.Month() && min.Day() > max.Day() {
  146. return newError("invalid range")
  147. }
  148. }
  149. var st [2]win.SYSTEMTIME
  150. var wParam uintptr
  151. if !min.IsZero() {
  152. wParam |= win.GDTR_MIN
  153. st[0] = *de.timeToSystemTime(min)
  154. }
  155. if !max.IsZero() {
  156. wParam |= win.GDTR_MAX
  157. st[1] = *de.timeToSystemTime(max)
  158. }
  159. if 0 == de.SendMessage(win.DTM_SETRANGE, wParam, uintptr(unsafe.Pointer(&st[0]))) {
  160. return newError("SendMessage(DTM_SETRANGE)")
  161. }
  162. return nil
  163. }
  164. func (de *DateEdit) Date() time.Time {
  165. st, err := de.systemTime()
  166. if err != nil {
  167. return time.Time{}
  168. }
  169. if st == nil {
  170. return time.Time{}
  171. }
  172. return de.systemTimeToTime(st)
  173. }
  174. func (de *DateEdit) SetDate(date time.Time) error {
  175. return de.setSystemTime(de.timeToSystemTime(date))
  176. }
  177. func (de *DateEdit) DateChanged() *Event {
  178. return de.dateChangedPublisher.Event()
  179. }
  180. func (de *DateEdit) WndProc(hwnd win.HWND, msg uint32, wParam, lParam uintptr) uintptr {
  181. switch msg {
  182. case win.WM_NOTIFY:
  183. switch uint32(((*win.NMHDR)(unsafe.Pointer(lParam))).Code) {
  184. case win.DTN_DATETIMECHANGE:
  185. de.dateChangedPublisher.Publish()
  186. }
  187. }
  188. return de.WidgetBase.WndProc(hwnd, msg, wParam, lParam)
  189. }