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_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
     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 
     58 CFWL_DateTimePicker::~CFWL_DateTimePicker() {
     59   UnregisterEventTarget();
     60 }
     61 
     62 FWL_Type CFWL_DateTimePicker::GetClassID() const {
     63   return FWL_Type::DateTimePicker;
     64 }
     65 
     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 
    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 
    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 
    134 void CFWL_DateTimePicker::SetThemeProvider(IFWL_ThemeProvider* pTP) {
    135   m_pProperties->m_pThemeProvider = pTP;
    136   m_pMonthCal->SetThemeProvider(pTP);
    137 }
    138 
    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 
    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 
    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 
    174 WideString CFWL_DateTimePicker::GetEditText() const {
    175   return m_pEdit ? m_pEdit->GetText() : L"";
    176 }
    177 
    178 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 
    192 void CFWL_DateTimePicker::ModifyEditStylesEx(uint32_t dwStylesExAdded,
    193                                              uint32_t dwStylesExRemoved) {
    194   m_pEdit->ModifyStylesEx(dwStylesExAdded, dwStylesExRemoved);
    195 }
    196 
    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 
    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 
    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 
    257 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 
    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 
    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 
    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 
    341 bool CFWL_DateTimePicker::DisForm_IsMonthCalendarVisible() const {
    342   if (!m_pMonthCal)
    343     return false;
    344   return !(m_pMonthCal->GetStates() & FWL_WGTSTATE_Invisible);
    345 }
    346 
    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 
    384 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 
    401 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 
    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 
    434 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 
    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 
    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 
    514 void CFWL_DateTimePicker::OnDrawWidget(CXFA_Graphics* pGraphics,
    515                                        const CFX_Matrix& matrix) {
    516   DrawWidget(pGraphics, matrix);
    517 }
    518 
    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 
    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 
    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 
    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 
    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 
    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