1 // Copyright 2014 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6 
7 #include "xfa/fwl/cfwl_datetimepicker.h"
8 
9 #include <memory>
10 #include <utility>
11 
12 #include "third_party/base/ptr_util.h"
13 #include "xfa/fwl/cfwl_event.h"
14 #include "xfa/fwl/cfwl_eventselectchanged.h"
15 #include "xfa/fwl/cfwl_formproxy.h"
16 #include "xfa/fwl/cfwl_messagemouse.h"
17 #include "xfa/fwl/cfwl_messagesetfocus.h"
18 #include "xfa/fwl/cfwl_notedriver.h"
19 #include "xfa/fwl/cfwl_themebackground.h"
20 #include "xfa/fwl/cfwl_widgetmgr.h"
21 #include "xfa/fwl/ifwl_themeprovider.h"
22 
23 namespace {
24 
25 const int kDateTimePickerHeight = 20;
26 
27 }  // namespace
CFWL_DateTimePicker(const CFWL_App * app)28 CFWL_DateTimePicker::CFWL_DateTimePicker(const CFWL_App* app)
29     : CFWL_Widget(app, pdfium::MakeUnique<CFWL_WidgetProperties>(), nullptr),
30       m_iBtnState(1),
31       m_iYear(-1),
32       m_iMonth(-1),
33       m_iDay(-1),
34       m_bLBtnDown(false) {
35   m_pProperties->m_dwStyleExes = FWL_STYLEEXT_DTP_ShortDateFormat;
36 
37   auto monthProp = pdfium::MakeUnique<CFWL_WidgetProperties>();
38   monthProp->m_dwStyles = FWL_WGTSTYLE_Popup | FWL_WGTSTYLE_Border;
39   monthProp->m_dwStates = FWL_WGTSTATE_Invisible;
40   monthProp->m_pParent = this;
41   monthProp->m_pThemeProvider = m_pProperties->m_pThemeProvider;
42   m_pMonthCal = pdfium::MakeUnique<CFWL_MonthCalendar>(
43       m_pOwnerApp.Get(), std::move(monthProp), this);
44 
45   m_pMonthCal->SetWidgetRect(
46       CFX_RectF(0, 0, m_pMonthCal->GetAutosizedWidgetRect().Size()));
47 
48   auto editProp = pdfium::MakeUnique<CFWL_WidgetProperties>();
49   editProp->m_pParent = this;
50   editProp->m_pThemeProvider = m_pProperties->m_pThemeProvider;
51 
52   m_pEdit = pdfium::MakeUnique<CFWL_DateTimeEdit>(m_pOwnerApp.Get(),
53                                                   std::move(editProp), this);
54   RegisterEventTarget(m_pMonthCal.get());
55   RegisterEventTarget(m_pEdit.get());
56 }
57 
~CFWL_DateTimePicker()58 CFWL_DateTimePicker::~CFWL_DateTimePicker() {
59   UnregisterEventTarget();
60 }
61 
GetClassID() const62 FWL_Type CFWL_DateTimePicker::GetClassID() const {
63   return FWL_Type::DateTimePicker;
64 }
65 
Update()66 void CFWL_DateTimePicker::Update() {
67   if (m_pWidgetMgr->IsFormDisabled()) {
68     DisForm_Update();
69     return;
70   }
71   if (m_iLock)
72     return;
73   if (!m_pProperties->m_pThemeProvider)
74     m_pProperties->m_pThemeProvider = GetAvailableTheme();
75 
76   m_pEdit->SetThemeProvider(m_pProperties->m_pThemeProvider);
77   m_rtClient = GetClientRect();
78 
79   IFWL_ThemeProvider* theme = GetAvailableTheme();
80   if (!theme)
81     return;
82 
83   float fBtn = theme->GetScrollBarWidth();
84   m_rtBtn = CFX_RectF(m_rtClient.right() - fBtn, m_rtClient.top, fBtn - 1,
85                       m_rtClient.height - 1);
86 
87   CFX_RectF rtEdit(m_rtClient.left, m_rtClient.top, m_rtClient.width - fBtn,
88                    m_rtClient.height);
89   m_pEdit->SetWidgetRect(rtEdit);
90   ResetEditAlignment();
91   m_pEdit->Update();
92   if (!(m_pMonthCal->GetThemeProvider()))
93     m_pMonthCal->SetThemeProvider(m_pProperties->m_pThemeProvider);
94 
95   CFX_RectF rtMonthCal = m_pMonthCal->GetAutosizedWidgetRect();
96   CFX_RectF rtPopUp(rtMonthCal.left, rtMonthCal.top + kDateTimePickerHeight,
97                     rtMonthCal.width, rtMonthCal.height);
98   m_pMonthCal->SetWidgetRect(rtPopUp);
99   m_pMonthCal->Update();
100   return;
101 }
102 
HitTest(const CFX_PointF & point)103 FWL_WidgetHit CFWL_DateTimePicker::HitTest(const CFX_PointF& point) {
104   if (m_pWidgetMgr->IsFormDisabled())
105     return DisForm_HitTest(point);
106   if (m_rtClient.Contains(point))
107     return FWL_WidgetHit::Client;
108   if (IsMonthCalendarVisible()) {
109     CFX_RectF rect = m_pMonthCal->GetWidgetRect();
110     if (rect.Contains(point))
111       return FWL_WidgetHit::Client;
112   }
113   return FWL_WidgetHit::Unknown;
114 }
115 
DrawWidget(CXFA_Graphics * pGraphics,const CFX_Matrix & matrix)116 void CFWL_DateTimePicker::DrawWidget(CXFA_Graphics* pGraphics,
117                                      const CFX_Matrix& matrix) {
118   if (!pGraphics)
119     return;
120   if (!m_pProperties->m_pThemeProvider)
121     return;
122 
123   IFWL_ThemeProvider* pTheme = m_pProperties->m_pThemeProvider;
124   if (HasBorder())
125     DrawBorder(pGraphics, CFWL_Part::Border, pTheme, matrix);
126   if (!m_rtBtn.IsEmpty())
127     DrawDropDownButton(pGraphics, pTheme, &matrix);
128   if (m_pWidgetMgr->IsFormDisabled()) {
129     DisForm_DrawWidget(pGraphics, &matrix);
130     return;
131   }
132 }
133 
SetThemeProvider(IFWL_ThemeProvider * pTP)134 void CFWL_DateTimePicker::SetThemeProvider(IFWL_ThemeProvider* pTP) {
135   m_pProperties->m_pThemeProvider = pTP;
136   m_pMonthCal->SetThemeProvider(pTP);
137 }
138 
GetCurSel(int32_t & iYear,int32_t & iMonth,int32_t & iDay)139 void CFWL_DateTimePicker::GetCurSel(int32_t& iYear,
140                                     int32_t& iMonth,
141                                     int32_t& iDay) {
142   iYear = m_iYear;
143   iMonth = m_iMonth;
144   iDay = m_iDay;
145 }
146 
SetCurSel(int32_t iYear,int32_t iMonth,int32_t iDay)147 void CFWL_DateTimePicker::SetCurSel(int32_t iYear,
148                                     int32_t iMonth,
149                                     int32_t iDay) {
150   if (iYear <= 0 || iYear >= 3000)
151     return;
152   if (iMonth <= 0 || iMonth >= 13)
153     return;
154   if (iDay <= 0 || iDay >= 32)
155     return;
156 
157   m_iYear = iYear;
158   m_iMonth = iMonth;
159   m_iDay = iDay;
160   m_pMonthCal->SetSelect(iYear, iMonth, iDay);
161 }
162 
SetEditText(const WideString & wsText)163 void CFWL_DateTimePicker::SetEditText(const WideString& wsText) {
164   if (!m_pEdit)
165     return;
166 
167   m_pEdit->SetText(wsText);
168   RepaintRect(m_rtClient);
169 
170   CFWL_Event ev(CFWL_Event::Type::EditChanged);
171   DispatchEvent(&ev);
172 }
173 
GetEditText() const174 WideString CFWL_DateTimePicker::GetEditText() const {
175   return m_pEdit ? m_pEdit->GetText() : L"";
176 }
177 
GetBBox() const178 CFX_RectF CFWL_DateTimePicker::GetBBox() const {
179   if (m_pWidgetMgr->IsFormDisabled())
180     return DisForm_GetBBox();
181 
182   CFX_RectF rect = m_pProperties->m_rtWidget;
183   if (!IsMonthCalendarVisible())
184     return rect;
185 
186   CFX_RectF rtMonth = m_pMonthCal->GetWidgetRect();
187   rtMonth.Offset(m_pProperties->m_rtWidget.left, m_pProperties->m_rtWidget.top);
188   rect.Union(rtMonth);
189   return rect;
190 }
191 
ModifyEditStylesEx(uint32_t dwStylesExAdded,uint32_t dwStylesExRemoved)192 void CFWL_DateTimePicker::ModifyEditStylesEx(uint32_t dwStylesExAdded,
193                                              uint32_t dwStylesExRemoved) {
194   m_pEdit->ModifyStylesEx(dwStylesExAdded, dwStylesExRemoved);
195 }
196 
DrawDropDownButton(CXFA_Graphics * pGraphics,IFWL_ThemeProvider * pTheme,const CFX_Matrix * pMatrix)197 void CFWL_DateTimePicker::DrawDropDownButton(CXFA_Graphics* pGraphics,
198                                              IFWL_ThemeProvider* pTheme,
199                                              const CFX_Matrix* pMatrix) {
200   CFWL_ThemeBackground param;
201   param.m_pWidget = this;
202   param.m_iPart = CFWL_Part::DropDownButton;
203   param.m_dwStates = m_iBtnState;
204   param.m_pGraphics = pGraphics;
205   param.m_rtPart = m_rtBtn;
206   if (pMatrix)
207     param.m_matrix.Concat(*pMatrix);
208   pTheme->DrawBackground(&param);
209 }
210 
FormatDateString(int32_t iYear,int32_t iMonth,int32_t iDay)211 WideString CFWL_DateTimePicker::FormatDateString(int32_t iYear,
212                                                  int32_t iMonth,
213                                                  int32_t iDay) {
214   if ((m_pProperties->m_dwStyleExes & FWL_STYLEEXT_DTP_ShortDateFormat) ==
215       FWL_STYLEEXT_DTP_ShortDateFormat) {
216     return WideString::Format(L"%d-%d-%d", iYear, iMonth, iDay);
217   }
218 
219   if ((m_pProperties->m_dwStyleExes & FWL_STYLEEXT_DTP_LongDateFormat) ==
220       FWL_STYLEEXT_DTP_LongDateFormat) {
221     return WideString::Format(L"%d Year %d Month %d Day", iYear, iMonth, iDay);
222   }
223 
224   return WideString();
225 }
226 
ShowMonthCalendar(bool bActivate)227 void CFWL_DateTimePicker::ShowMonthCalendar(bool bActivate) {
228   if (m_pWidgetMgr->IsFormDisabled())
229     return DisForm_ShowMonthCalendar(bActivate);
230   if (IsMonthCalendarVisible() == bActivate)
231     return;
232   if (!m_pForm)
233     InitProxyForm();
234 
235   if (!bActivate) {
236     m_pForm->EndDoModal();
237     return;
238   }
239 
240   CFX_RectF rtMonth = m_pMonthCal->GetWidgetRect();
241 
242   CFX_RectF rtAnchor(0, 0, m_pProperties->m_rtWidget.width,
243                      m_pProperties->m_rtWidget.height);
244   GetPopupPos(0, rtMonth.height, rtAnchor, rtMonth);
245   m_pForm->SetWidgetRect(rtMonth);
246 
247   rtMonth.left = rtMonth.top = 0;
248   if (bActivate)
249     m_pMonthCal->RemoveStates(FWL_WGTSTATE_Invisible);
250   else
251     m_pMonthCal->SetStates(FWL_WGTSTATE_Invisible);
252   m_pMonthCal->SetWidgetRect(rtMonth);
253   m_pMonthCal->Update();
254   m_pForm->DoModal();
255 }
256 
IsMonthCalendarVisible() const257 bool CFWL_DateTimePicker::IsMonthCalendarVisible() const {
258   if (m_pWidgetMgr->IsFormDisabled())
259     return DisForm_IsMonthCalendarVisible();
260   if (!m_pForm)
261     return false;
262   return !(m_pForm->GetStates() & FWL_WGTSTATE_Invisible);
263 }
264 
ResetEditAlignment()265 void CFWL_DateTimePicker::ResetEditAlignment() {
266   if (!m_pEdit)
267     return;
268 
269   uint32_t dwAdd = 0;
270   switch (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_DTP_EditHAlignMask) {
271     case FWL_STYLEEXT_DTP_EditHCenter: {
272       dwAdd |= FWL_STYLEEXT_EDT_HCenter;
273       break;
274     }
275     case FWL_STYLEEXT_DTP_EditHFar: {
276       dwAdd |= FWL_STYLEEXT_EDT_HFar;
277       break;
278     }
279     default: {
280       dwAdd |= FWL_STYLEEXT_EDT_HNear;
281       break;
282     }
283   }
284   switch (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_DTP_EditVAlignMask) {
285     case FWL_STYLEEXT_DTP_EditVCenter: {
286       dwAdd |= FWL_STYLEEXT_EDT_VCenter;
287       break;
288     }
289     case FWL_STYLEEXT_DTP_EditVFar: {
290       dwAdd |= FWL_STYLEEXT_EDT_VFar;
291       break;
292     }
293     default: {
294       dwAdd |= FWL_STYLEEXT_EDT_VNear;
295       break;
296     }
297   }
298   if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_DTP_EditJustified)
299     dwAdd |= FWL_STYLEEXT_EDT_Justified;
300 
301   m_pEdit->ModifyStylesEx(dwAdd, FWL_STYLEEXT_EDT_HAlignMask |
302                                      FWL_STYLEEXT_EDT_HAlignModeMask |
303                                      FWL_STYLEEXT_EDT_VAlignMask);
304 }
305 
ProcessSelChanged(int32_t iYear,int32_t iMonth,int32_t iDay)306 void CFWL_DateTimePicker::ProcessSelChanged(int32_t iYear,
307                                             int32_t iMonth,
308                                             int32_t iDay) {
309   m_iYear = iYear;
310   m_iMonth = iMonth;
311   m_iDay = iDay;
312 
313   WideString wsText = FormatDateString(m_iYear, m_iMonth, m_iDay);
314   m_pEdit->SetText(wsText);
315   m_pEdit->Update();
316   RepaintRect(m_rtClient);
317 
318   CFWL_EventSelectChanged ev(this);
319   ev.iYear = m_iYear;
320   ev.iMonth = m_iMonth;
321   ev.iDay = m_iDay;
322   DispatchEvent(&ev);
323 }
324 
InitProxyForm()325 void CFWL_DateTimePicker::InitProxyForm() {
326   if (m_pForm)
327     return;
328   if (!m_pMonthCal)
329     return;
330 
331   auto prop = pdfium::MakeUnique<CFWL_WidgetProperties>();
332   prop->m_dwStyles = FWL_WGTSTYLE_Popup;
333   prop->m_dwStates = FWL_WGTSTATE_Invisible;
334   prop->m_pOwner = this;
335 
336   m_pForm = pdfium::MakeUnique<CFWL_FormProxy>(
337       m_pOwnerApp.Get(), std::move(prop), m_pMonthCal.get());
338   m_pMonthCal->SetParent(m_pForm.get());
339 }
340 
DisForm_IsMonthCalendarVisible() const341 bool CFWL_DateTimePicker::DisForm_IsMonthCalendarVisible() const {
342   if (!m_pMonthCal)
343     return false;
344   return !(m_pMonthCal->GetStates() & FWL_WGTSTATE_Invisible);
345 }
346 
DisForm_ShowMonthCalendar(bool bActivate)347 void CFWL_DateTimePicker::DisForm_ShowMonthCalendar(bool bActivate) {
348   if (IsMonthCalendarVisible() == bActivate)
349     return;
350 
351   if (bActivate) {
352     CFX_RectF rtMonthCal = m_pMonthCal->GetAutosizedWidgetRect();
353     float fPopupMin = rtMonthCal.height;
354     float fPopupMax = rtMonthCal.height;
355     CFX_RectF rtAnchor(m_pProperties->m_rtWidget);
356     rtAnchor.width = rtMonthCal.width;
357     rtMonthCal.left = m_rtClient.left;
358     rtMonthCal.top = rtAnchor.Height();
359     GetPopupPos(fPopupMin, fPopupMax, rtAnchor, rtMonthCal);
360     m_pMonthCal->SetWidgetRect(rtMonthCal);
361     if (m_iYear > 0 && m_iMonth > 0 && m_iDay > 0)
362       m_pMonthCal->SetSelect(m_iYear, m_iMonth, m_iDay);
363     m_pMonthCal->Update();
364   }
365   if (bActivate)
366     m_pMonthCal->RemoveStates(FWL_WGTSTATE_Invisible);
367   else
368     m_pMonthCal->SetStates(FWL_WGTSTATE_Invisible);
369 
370   if (bActivate) {
371     CFWL_MessageSetFocus msg(m_pEdit.get(), m_pMonthCal.get());
372     m_pEdit->GetDelegate()->OnProcessMessage(&msg);
373   }
374 
375   CFX_RectF rtInvalidate(0, 0, m_pProperties->m_rtWidget.width,
376                          m_pProperties->m_rtWidget.height);
377 
378   CFX_RectF rtCal = m_pMonthCal->GetWidgetRect();
379   rtInvalidate.Union(rtCal);
380   rtInvalidate.Inflate(2, 2);
381   RepaintRect(rtInvalidate);
382 }
383 
DisForm_HitTest(const CFX_PointF & point) const384 FWL_WidgetHit CFWL_DateTimePicker::DisForm_HitTest(
385     const CFX_PointF& point) const {
386   CFX_RectF rect(0, 0, m_pProperties->m_rtWidget.width,
387                  m_pProperties->m_rtWidget.height);
388   if (rect.Contains(point))
389     return FWL_WidgetHit::Edit;
390   if (DisForm_IsNeedShowButton())
391     rect.width += m_fBtn;
392   if (rect.Contains(point))
393     return FWL_WidgetHit::Client;
394   if (IsMonthCalendarVisible()) {
395     if (m_pMonthCal->GetWidgetRect().Contains(point))
396       return FWL_WidgetHit::Client;
397   }
398   return FWL_WidgetHit::Unknown;
399 }
400 
DisForm_IsNeedShowButton() const401 bool CFWL_DateTimePicker::DisForm_IsNeedShowButton() const {
402   return m_pProperties->m_dwStates & FWL_WGTSTATE_Focused ||
403          m_pMonthCal->GetStates() & FWL_WGTSTATE_Focused ||
404          m_pEdit->GetStates() & FWL_WGTSTATE_Focused;
405 }
406 
DisForm_Update()407 void CFWL_DateTimePicker::DisForm_Update() {
408   if (m_iLock)
409     return;
410   if (!m_pProperties->m_pThemeProvider)
411     m_pProperties->m_pThemeProvider = GetAvailableTheme();
412 
413   m_pEdit->SetThemeProvider(m_pProperties->m_pThemeProvider);
414   m_rtClient = GetClientRect();
415   m_pEdit->SetWidgetRect(m_rtClient);
416   ResetEditAlignment();
417   m_pEdit->Update();
418 
419   if (!m_pMonthCal->GetThemeProvider())
420     m_pMonthCal->SetThemeProvider(m_pProperties->m_pThemeProvider);
421 
422   IFWL_ThemeProvider* theme = GetAvailableTheme();
423   if (!theme)
424     return;
425 
426   m_fBtn = theme->GetScrollBarWidth();
427   CFX_RectF rtMonthCal = m_pMonthCal->GetAutosizedWidgetRect();
428   CFX_RectF rtPopUp(rtMonthCal.left, rtMonthCal.top + kDateTimePickerHeight,
429                     rtMonthCal.width, rtMonthCal.height);
430   m_pMonthCal->SetWidgetRect(rtPopUp);
431   m_pMonthCal->Update();
432 }
433 
DisForm_GetBBox() const434 CFX_RectF CFWL_DateTimePicker::DisForm_GetBBox() const {
435   CFX_RectF rect = m_pProperties->m_rtWidget;
436   if (DisForm_IsNeedShowButton())
437     rect.width += m_fBtn;
438   if (!IsMonthCalendarVisible())
439     return rect;
440 
441   CFX_RectF rtMonth = m_pMonthCal->GetWidgetRect();
442   rtMonth.Offset(m_pProperties->m_rtWidget.left, m_pProperties->m_rtWidget.top);
443   rect.Union(rtMonth);
444   return rect;
445 }
446 
DisForm_DrawWidget(CXFA_Graphics * pGraphics,const CFX_Matrix * pMatrix)447 void CFWL_DateTimePicker::DisForm_DrawWidget(CXFA_Graphics* pGraphics,
448                                              const CFX_Matrix* pMatrix) {
449   if (!pGraphics)
450     return;
451   if (m_pEdit) {
452     CFX_RectF rtEdit = m_pEdit->GetWidgetRect();
453 
454     CFX_Matrix mt(1, 0, 0, 1, rtEdit.left, rtEdit.top);
455     if (pMatrix)
456       mt.Concat(*pMatrix);
457     m_pEdit->DrawWidget(pGraphics, mt);
458   }
459   if (!IsMonthCalendarVisible())
460     return;
461 
462   CFX_RectF rtMonth = m_pMonthCal->GetWidgetRect();
463   CFX_Matrix mt(1, 0, 0, 1, rtMonth.left, rtMonth.top);
464   if (pMatrix)
465     mt.Concat(*pMatrix);
466   m_pMonthCal->DrawWidget(pGraphics, mt);
467 }
468 
OnProcessMessage(CFWL_Message * pMessage)469 void CFWL_DateTimePicker::OnProcessMessage(CFWL_Message* pMessage) {
470   if (!pMessage)
471     return;
472 
473   switch (pMessage->GetType()) {
474     case CFWL_Message::Type::SetFocus:
475       OnFocusChanged(pMessage, true);
476       break;
477     case CFWL_Message::Type::KillFocus:
478       OnFocusChanged(pMessage, false);
479       break;
480     case CFWL_Message::Type::Mouse: {
481       CFWL_MessageMouse* pMouse = static_cast<CFWL_MessageMouse*>(pMessage);
482       switch (pMouse->m_dwCmd) {
483         case FWL_MouseCommand::LeftButtonDown:
484           OnLButtonDown(pMouse);
485           break;
486         case FWL_MouseCommand::LeftButtonUp:
487           OnLButtonUp(pMouse);
488           break;
489         case FWL_MouseCommand::Move:
490           OnMouseMove(pMouse);
491           break;
492         case FWL_MouseCommand::Leave:
493           OnMouseLeave(pMouse);
494           break;
495         default:
496           break;
497       }
498       break;
499     }
500     case CFWL_Message::Type::Key: {
501       if (m_pEdit->GetStates() & FWL_WGTSTATE_Focused) {
502         m_pEdit->GetDelegate()->OnProcessMessage(pMessage);
503         return;
504       }
505       break;
506     }
507     default:
508       break;
509   }
510 
511   CFWL_Widget::OnProcessMessage(pMessage);
512 }
513 
OnDrawWidget(CXFA_Graphics * pGraphics,const CFX_Matrix & matrix)514 void CFWL_DateTimePicker::OnDrawWidget(CXFA_Graphics* pGraphics,
515                                        const CFX_Matrix& matrix) {
516   DrawWidget(pGraphics, matrix);
517 }
518 
OnFocusChanged(CFWL_Message * pMsg,bool bSet)519 void CFWL_DateTimePicker::OnFocusChanged(CFWL_Message* pMsg, bool bSet) {
520   if (!pMsg)
521     return;
522   if (m_pWidgetMgr->IsFormDisabled())
523     return DisForm_OnFocusChanged(pMsg, bSet);
524 
525   if (bSet) {
526     m_pProperties->m_dwStates |= (FWL_WGTSTATE_Focused);
527     RepaintRect(m_rtClient);
528   } else {
529     m_pProperties->m_dwStates &= ~(FWL_WGTSTATE_Focused);
530     RepaintRect(m_rtClient);
531   }
532   if (pMsg->m_pSrcTarget == m_pMonthCal.get() && IsMonthCalendarVisible()) {
533     ShowMonthCalendar(false);
534   }
535   RepaintRect(m_rtClient);
536 }
537 
OnLButtonDown(CFWL_MessageMouse * pMsg)538 void CFWL_DateTimePicker::OnLButtonDown(CFWL_MessageMouse* pMsg) {
539   if (!pMsg)
540     return;
541   if ((m_pProperties->m_dwStates & FWL_WGTSTATE_Focused) == 0)
542     SetFocus(true);
543   if (!m_rtBtn.Contains(pMsg->m_pos))
544     return;
545 
546   if (IsMonthCalendarVisible()) {
547     ShowMonthCalendar(false);
548     return;
549   }
550   ShowMonthCalendar(true);
551 
552   m_bLBtnDown = true;
553   RepaintRect(m_rtClient);
554 }
555 
OnLButtonUp(CFWL_MessageMouse * pMsg)556 void CFWL_DateTimePicker::OnLButtonUp(CFWL_MessageMouse* pMsg) {
557   if (!pMsg)
558     return;
559 
560   m_bLBtnDown = false;
561   if (m_rtBtn.Contains(pMsg->m_pos))
562     m_iBtnState = CFWL_PartState_Hovered;
563   else
564     m_iBtnState = CFWL_PartState_Normal;
565   RepaintRect(m_rtBtn);
566 }
567 
OnMouseMove(CFWL_MessageMouse * pMsg)568 void CFWL_DateTimePicker::OnMouseMove(CFWL_MessageMouse* pMsg) {
569   if (!m_rtBtn.Contains(pMsg->m_pos))
570     m_iBtnState = CFWL_PartState_Normal;
571   RepaintRect(m_rtBtn);
572 }
573 
OnMouseLeave(CFWL_MessageMouse * pMsg)574 void CFWL_DateTimePicker::OnMouseLeave(CFWL_MessageMouse* pMsg) {
575   if (!pMsg)
576     return;
577   m_iBtnState = CFWL_PartState_Normal;
578   RepaintRect(m_rtBtn);
579 }
580 
DisForm_OnFocusChanged(CFWL_Message * pMsg,bool bSet)581 void CFWL_DateTimePicker::DisForm_OnFocusChanged(CFWL_Message* pMsg,
582                                                  bool bSet) {
583   CFX_RectF rtInvalidate(m_rtBtn);
584   if (bSet) {
585     m_pProperties->m_dwStates |= FWL_WGTSTATE_Focused;
586     if (m_pEdit && !(m_pEdit->GetStylesEx() & FWL_STYLEEXT_EDT_ReadOnly)) {
587       m_rtBtn = CFX_RectF(m_pProperties->m_rtWidget.width, 0, m_fBtn,
588                           m_pProperties->m_rtWidget.height - 1);
589     }
590     rtInvalidate = m_rtBtn;
591     pMsg->m_pDstTarget = m_pEdit.get();
592     m_pEdit->GetDelegate()->OnProcessMessage(pMsg);
593   } else {
594     m_pProperties->m_dwStates &= ~FWL_WGTSTATE_Focused;
595     m_rtBtn.Reset();
596 
597     if (DisForm_IsMonthCalendarVisible())
598       ShowMonthCalendar(false);
599     if (m_pEdit->GetStates() & FWL_WGTSTATE_Focused) {
600       pMsg->m_pSrcTarget = m_pEdit.get();
601       m_pEdit->GetDelegate()->OnProcessMessage(pMsg);
602     }
603   }
604   rtInvalidate.Inflate(2, 2);
605   RepaintRect(rtInvalidate);
606 }
607