cfwl_datetimepicker.cpp revision 33357cad1fd1321a2b38d2963e2585f27ce980a2
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
24namespace {
25
26const int kDateTimePickerHeight = 20;
27
28}  // namespace
29CFWL_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
59CFWL_DateTimePicker::~CFWL_DateTimePicker() {
60  UnregisterEventTarget();
61}
62
63FWL_Type CFWL_DateTimePicker::GetClassID() const {
64  return FWL_Type::DateTimePicker;
65}
66
67void 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
104FWL_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
117void 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
135void CFWL_DateTimePicker::SetThemeProvider(IFWL_ThemeProvider* pTP) {
136  m_pProperties->m_pThemeProvider = pTP;
137  m_pMonthCal->SetThemeProvider(pTP);
138}
139
140void 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
148void 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
164void 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
175CFX_WideString CFWL_DateTimePicker::GetEditText() const {
176  return m_pEdit ? m_pEdit->GetText() : L"";
177}
178
179CFX_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
193void CFWL_DateTimePicker::ModifyEditStylesEx(uint32_t dwStylesExAdded,
194                                             uint32_t dwStylesExRemoved) {
195  m_pEdit->ModifyStylesEx(dwStylesExAdded, dwStylesExRemoved);
196}
197
198void 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
212void 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
225void 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
255bool 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
263void 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
304void 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
324void 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
340bool CFWL_DateTimePicker::DisForm_IsMonthCalendarVisible() const {
341  if (!m_pMonthCal)
342    return false;
343  return !(m_pMonthCal->GetStates() & FWL_WGTSTATE_Invisible);
344}
345
346void 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
383FWL_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
400bool 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
406void 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
433CFX_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
446void 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
468void 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
513void CFWL_DateTimePicker::OnDrawWidget(CFX_Graphics* pGraphics,
514                                       const CFX_Matrix* pMatrix) {
515  DrawWidget(pGraphics, pMatrix);
516}
517
518void 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
537void 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
555void 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
567void 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
573void CFWL_DateTimePicker::OnMouseLeave(CFWL_MessageMouse* pMsg) {
574  if (!pMsg)
575    return;
576  m_iBtnState = CFWL_PartState_Normal;
577  RepaintRect(m_rtBtn);
578}
579
580void 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