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