Home | History | Annotate | Download | only in basewidget
      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/src/foxitlib.h"
      8 #include "xfa/src/fwl/src/core/include/fwl_targetimp.h"
      9 #include "xfa/src/fwl/src/core/include/fwl_noteimp.h"
     10 #include "xfa/src/fwl/src/core/include/fwl_widgetimp.h"
     11 #include "xfa/src/fwl/src/basewidget/include/fwl_monthcalendarimp.h"
     12 #define MONTHCAL_HSEP_HEIGHT 1
     13 #define MONTHCAL_VSEP_WIDTH 1
     14 #define MONTHCAL_HMARGIN 3
     15 #define MONTHCAL_VMARGIN 2
     16 #define MONTHCAL_ROWS 9
     17 #define MONTHCAL_COLUMNS 7
     18 #define MONTHCAL_HEADER_BTN_VMARGIN 7
     19 #define MONTHCAL_HEADER_BTN_HMARGIN 5
     20 
     21 // static
     22 IFWL_MonthCalendar* IFWL_MonthCalendar::Create(
     23     const CFWL_WidgetImpProperties& properties,
     24     IFWL_Widget* pOuter) {
     25   IFWL_MonthCalendar* pMonthCalendar = new IFWL_MonthCalendar;
     26   CFWL_MonthCalendarImp* pMonthCalendarImpl =
     27       new CFWL_MonthCalendarImp(properties, pOuter);
     28   pMonthCalendar->SetImpl(pMonthCalendarImpl);
     29   pMonthCalendarImpl->SetInterface(pMonthCalendar);
     30   return pMonthCalendar;
     31 }
     32 IFWL_MonthCalendar::IFWL_MonthCalendar() {}
     33 int32_t IFWL_MonthCalendar::CountSelect() {
     34   return static_cast<CFWL_MonthCalendarImp*>(GetImpl())->CountSelect();
     35 }
     36 FX_BOOL IFWL_MonthCalendar::GetSelect(int32_t& iYear,
     37                                       int32_t& iMonth,
     38                                       int32_t& iDay,
     39                                       int32_t nIndex) {
     40   return static_cast<CFWL_MonthCalendarImp*>(GetImpl())
     41       ->GetSelect(iYear, iMonth, iDay, nIndex);
     42 }
     43 FX_BOOL IFWL_MonthCalendar::SetSelect(int32_t iYear,
     44                                       int32_t iMonth,
     45                                       int32_t iDay) {
     46   return static_cast<CFWL_MonthCalendarImp*>(GetImpl())
     47       ->SetSelect(iYear, iMonth, iDay);
     48 }
     49 
     50 CFWL_MonthCalendarImp::CFWL_MonthCalendarImp(
     51     const CFWL_WidgetImpProperties& properties,
     52     IFWL_Widget* pOuter)
     53     : CFWL_WidgetImp(properties, pOuter),
     54       m_iCurYear(2011),
     55       m_iCurMonth(1),
     56       m_iYear(2011),
     57       m_iMonth(1),
     58       m_iDay(1),
     59       m_iHovered(-1),
     60       m_iLBtnPartStates(FWL_PARTSTATE_MCD_Normal),
     61       m_iRBtnPartStates(FWL_PARTSTATE_MCD_Normal) {
     62   m_rtHead.Reset();
     63   m_rtWeek.Reset();
     64   m_rtLBtn.Reset();
     65   m_rtRBtn.Reset();
     66   m_rtDates.Reset();
     67   m_rtHSep.Reset();
     68   m_rtHeadText.Reset();
     69   m_rtToday.Reset();
     70   m_rtTodayFlag.Reset();
     71   m_rtClient.Reset();
     72   m_rtWeekNum.Reset();
     73   m_rtWeekNumSep.Reset();
     74   m_szHead.Reset();
     75   m_szCell.Reset();
     76   m_szToday.Reset();
     77   m_pDateTime = new CFX_DateTime;
     78   m_bInit = FALSE;
     79   m_iMaxSel = 1;
     80 }
     81 CFWL_MonthCalendarImp::~CFWL_MonthCalendarImp() {
     82   ClearDateItem();
     83   delete m_pDateTime;
     84   m_arrSelDays.RemoveAll();
     85 }
     86 FWL_ERR CFWL_MonthCalendarImp::GetClassName(CFX_WideString& wsClass) const {
     87   wsClass = FWL_CLASS_MonthCalendar;
     88   return FWL_ERR_Succeeded;
     89 }
     90 FX_DWORD CFWL_MonthCalendarImp::GetClassID() const {
     91   return FWL_CLASSHASH_MonthCalendar;
     92 }
     93 FWL_ERR CFWL_MonthCalendarImp::Initialize() {
     94   if (CFWL_WidgetImp::Initialize() != FWL_ERR_Succeeded)
     95     return FWL_ERR_Indefinite;
     96   m_pDelegate = new CFWL_MonthCalendarImpDelegate(this);
     97   return FWL_ERR_Succeeded;
     98 }
     99 FWL_ERR CFWL_MonthCalendarImp::Finalize() {
    100   delete m_pDelegate;
    101   m_pDelegate = nullptr;
    102   return CFWL_WidgetImp::Finalize();
    103 }
    104 FWL_ERR CFWL_MonthCalendarImp::GetWidgetRect(CFX_RectF& rect,
    105                                              FX_BOOL bAutoSize) {
    106   if (bAutoSize) {
    107     CFX_SizeF fs = CalcSize(TRUE);
    108     rect.Set(0, 0, fs.x, fs.y);
    109     CFWL_WidgetImp::GetWidgetRect(rect, TRUE);
    110   } else {
    111     rect = m_pProperties->m_rtWidget;
    112   }
    113   return FWL_ERR_Succeeded;
    114 }
    115 FWL_ERR CFWL_MonthCalendarImp::Update() {
    116   if (IsLocked()) {
    117     return FWL_ERR_Indefinite;
    118   }
    119   if (!m_pProperties->m_pThemeProvider) {
    120     m_pProperties->m_pThemeProvider = GetAvailableTheme();
    121   }
    122   GetCapValue();
    123   if (!m_bInit) {
    124     m_bInit = InitDate();
    125   }
    126   ClearDateItem();
    127   ReSetDateItem();
    128   LayOut();
    129   return FWL_ERR_Succeeded;
    130 }
    131 FWL_ERR CFWL_MonthCalendarImp::DrawWidget(CFX_Graphics* pGraphics,
    132                                           const CFX_Matrix* pMatrix) {
    133   if (!pGraphics)
    134     return FWL_ERR_Indefinite;
    135   if (m_pProperties->m_pThemeProvider == NULL) {
    136     m_pProperties->m_pThemeProvider = GetAvailableTheme();
    137   }
    138   IFWL_ThemeProvider* pTheme = m_pProperties->m_pThemeProvider;
    139   if (HasBorder()) {
    140     DrawBorder(pGraphics, FWL_PART_MCD_Border, pTheme, pMatrix);
    141   }
    142   if (HasEdge()) {
    143     DrawEdge(pGraphics, FWL_PART_MCD_Edge, pTheme, pMatrix);
    144   }
    145   DrawBkground(pGraphics, pTheme, pMatrix);
    146   DrawHeadBK(pGraphics, pTheme, pMatrix);
    147   DrawLButton(pGraphics, pTheme, pMatrix);
    148   DrawRButton(pGraphics, pTheme, pMatrix);
    149   DrawSeperator(pGraphics, pTheme, pMatrix);
    150   DrawDatesInBK(pGraphics, pTheme, pMatrix);
    151   DrawDatesInCircle(pGraphics, pTheme, pMatrix);
    152   DrawCaption(pGraphics, pTheme, pMatrix);
    153   DrawWeek(pGraphics, pTheme, pMatrix);
    154   DrawDatesIn(pGraphics, pTheme, pMatrix);
    155   DrawDatesOut(pGraphics, pTheme, pMatrix);
    156   DrawToday(pGraphics, pTheme, pMatrix);
    157   if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_MCD_WeekNumbers) {
    158     DrawWeekNumberSep(pGraphics, pTheme, pMatrix);
    159     DrawWeekNumber(pGraphics, pTheme, pMatrix);
    160   }
    161   return FWL_ERR_Succeeded;
    162 }
    163 int32_t CFWL_MonthCalendarImp::CountSelect() {
    164   return m_arrSelDays.GetSize();
    165 }
    166 FX_BOOL CFWL_MonthCalendarImp::GetSelect(int32_t& iYear,
    167                                          int32_t& iMonth,
    168                                          int32_t& iDay,
    169                                          int32_t nIndex) {
    170   if (nIndex >= m_arrSelDays.GetSize()) {
    171     return FALSE;
    172   }
    173   iYear = m_iCurYear;
    174   iMonth = m_iCurMonth;
    175   iDay = m_arrSelDays[nIndex];
    176   return TRUE;
    177 }
    178 FX_BOOL CFWL_MonthCalendarImp::SetSelect(int32_t iYear,
    179                                          int32_t iMonth,
    180                                          int32_t iDay) {
    181   ChangeToMonth(iYear, iMonth);
    182   return AddSelDay(iDay);
    183 }
    184 void CFWL_MonthCalendarImp::DrawBkground(CFX_Graphics* pGraphics,
    185                                          IFWL_ThemeProvider* pTheme,
    186                                          const CFX_Matrix* pMatrix) {
    187   CFWL_ThemeBackground params;
    188   params.m_pWidget = m_pInterface;
    189   params.m_iPart = FWL_PART_MCD_Background;
    190   params.m_pGraphics = pGraphics;
    191   params.m_dwStates = FWL_PARTSTATE_MCD_Normal;
    192   params.m_rtPart = m_rtClient;
    193   if (pMatrix) {
    194     params.m_matrix.Concat(*pMatrix);
    195   }
    196   pTheme->DrawBackground(&params);
    197 }
    198 void CFWL_MonthCalendarImp::DrawHeadBK(CFX_Graphics* pGraphics,
    199                                        IFWL_ThemeProvider* pTheme,
    200                                        const CFX_Matrix* pMatrix) {
    201   CFWL_ThemeBackground params;
    202   params.m_pWidget = m_pInterface;
    203   params.m_iPart = FWL_PART_MCD_Header;
    204   params.m_pGraphics = pGraphics;
    205   params.m_dwStates = FWL_PARTSTATE_MCD_Normal;
    206   params.m_rtPart = m_rtHead;
    207   if (pMatrix) {
    208     params.m_matrix.Concat(*pMatrix);
    209   }
    210   pTheme->DrawBackground(&params);
    211 }
    212 void CFWL_MonthCalendarImp::DrawLButton(CFX_Graphics* pGraphics,
    213                                         IFWL_ThemeProvider* pTheme,
    214                                         const CFX_Matrix* pMatrix) {
    215   CFWL_ThemeBackground params;
    216   params.m_pWidget = m_pInterface;
    217   params.m_iPart = FWL_PART_MCD_LBtn;
    218   params.m_pGraphics = pGraphics;
    219   params.m_dwStates = m_iLBtnPartStates;
    220   params.m_rtPart = m_rtLBtn;
    221   if (pMatrix) {
    222     params.m_matrix.Concat(*pMatrix);
    223   }
    224   pTheme->DrawBackground(&params);
    225 }
    226 void CFWL_MonthCalendarImp::DrawRButton(CFX_Graphics* pGraphics,
    227                                         IFWL_ThemeProvider* pTheme,
    228                                         const CFX_Matrix* pMatrix) {
    229   CFWL_ThemeBackground params;
    230   params.m_pWidget = m_pInterface;
    231   params.m_iPart = FWL_PART_MCD_RBtn;
    232   params.m_pGraphics = pGraphics;
    233   params.m_dwStates = m_iRBtnPartStates;
    234   params.m_rtPart = m_rtRBtn;
    235   if (pMatrix) {
    236     params.m_matrix.Concat(*pMatrix);
    237   }
    238   pTheme->DrawBackground(&params);
    239 }
    240 void CFWL_MonthCalendarImp::DrawCaption(CFX_Graphics* pGraphics,
    241                                         IFWL_ThemeProvider* pTheme,
    242                                         const CFX_Matrix* pMatrix) {
    243   CFWL_ThemeText textParam;
    244   textParam.m_pWidget = m_pInterface;
    245   textParam.m_iPart = FWL_PART_MCD_Caption;
    246   textParam.m_dwStates = FWL_PARTSTATE_MCD_Normal;
    247   textParam.m_pGraphics = pGraphics;
    248   int32_t iYear;
    249   int32_t iMonth;
    250   iYear = m_iCurYear;
    251   iMonth = m_iCurMonth;
    252   CFX_WideString wsCation;
    253   GetHeadText(iYear, iMonth, wsCation);
    254   textParam.m_wsText = wsCation;
    255   m_szHead = CalcTextSize(textParam.m_wsText, m_pProperties->m_pThemeProvider);
    256   CalcHeadSize();
    257   textParam.m_rtPart = m_rtHeadText;
    258   textParam.m_dwTTOStyles = FDE_TTOSTYLE_SingleLine;
    259   textParam.m_iTTOAlign = FDE_TTOALIGNMENT_Center;
    260   if (pMatrix) {
    261     textParam.m_matrix.Concat(*pMatrix);
    262   }
    263   pTheme->DrawText(&textParam);
    264 }
    265 void CFWL_MonthCalendarImp::DrawSeperator(CFX_Graphics* pGraphics,
    266                                           IFWL_ThemeProvider* pTheme,
    267                                           const CFX_Matrix* pMatrix) {
    268   CFWL_ThemeBackground params;
    269   params.m_pWidget = m_pInterface;
    270   params.m_iPart = FWL_PART_MCD_HSeparator;
    271   params.m_pGraphics = pGraphics;
    272   params.m_dwStates = FWL_PARTSTATE_MCD_Normal;
    273   params.m_rtPart = m_rtHSep;
    274   if (pMatrix) {
    275     params.m_matrix.Concat(*pMatrix);
    276   }
    277   pTheme->DrawBackground(&params);
    278 }
    279 void CFWL_MonthCalendarImp::DrawDatesInBK(CFX_Graphics* pGraphics,
    280                                           IFWL_ThemeProvider* pTheme,
    281                                           const CFX_Matrix* pMatrix) {
    282   CFWL_ThemeBackground params;
    283   params.m_pWidget = m_pInterface;
    284   params.m_iPart = FWL_PART_MCD_DateInBK;
    285   params.m_pGraphics = pGraphics;
    286   if (pMatrix) {
    287     params.m_matrix.Concat(*pMatrix);
    288   }
    289   int32_t iCount = m_arrDates.GetSize();
    290   for (int32_t j = 0; j < iCount; j++) {
    291     LPDATEINFO pDataInfo = (LPDATEINFO)m_arrDates.GetAt(j);
    292     if (pDataInfo->dwStates & FWL_ITEMSTATE_MCD_Selected) {
    293       params.m_dwStates |= FWL_PARTSTATE_MCD_Selected;
    294       if (((m_pProperties->m_dwStyleExes & FWL_STYLEEXT_MCD_NoTodayCircle) ==
    295            0) &&
    296           pDataInfo->dwStates & FWL_ITEMSTATE_MCD_Flag) {
    297         params.m_dwStates |= FWL_PARTSTATE_MCD_Flagged;
    298       }
    299       if (pDataInfo->dwStates & FWL_ITEMSTATE_MCD_Focused) {
    300         params.m_dwStates |= FWL_PARTSTATE_MCD_Focused;
    301       }
    302     } else if (j == m_iHovered - 1) {
    303       params.m_dwStates |= FWL_PARTSTATE_MCD_Hovered;
    304     } else if (pDataInfo->dwStates & FWL_ITEMSTATE_MCD_Flag) {
    305       params.m_dwStates = FWL_PARTSTATE_MCD_Flagged;
    306       pTheme->DrawBackground(&params);
    307     }
    308     params.m_rtPart = pDataInfo->rect;
    309     pTheme->DrawBackground(&params);
    310     params.m_dwStates = 0;
    311   }
    312 }
    313 void CFWL_MonthCalendarImp::DrawWeek(CFX_Graphics* pGraphics,
    314                                      IFWL_ThemeProvider* pTheme,
    315                                      const CFX_Matrix* pMatrix) {
    316   CFWL_ThemeText params;
    317   params.m_pWidget = m_pInterface;
    318   params.m_iPart = FWL_PART_MCD_Week;
    319   params.m_pGraphics = pGraphics;
    320   params.m_dwStates = FWL_PARTSTATE_MCD_Normal;
    321   params.m_iTTOAlign = FDE_TTOALIGNMENT_Center;
    322   int32_t iWeek;
    323   iWeek = m_pDateTime->GetDayOfWeek();
    324   CFX_RectF rtDayOfWeek;
    325   if (pMatrix) {
    326     params.m_matrix.Concat(*pMatrix);
    327   }
    328   for (int32_t i = 0; i < 7; i++) {
    329     rtDayOfWeek.Set(m_rtWeek.left + i * (m_szCell.x + MONTHCAL_HMARGIN * 2),
    330                     m_rtWeek.top, m_szCell.x, m_szCell.y);
    331     CFX_WideString* wsWeekDay = static_cast<CFX_WideString*>(
    332         pTheme->GetCapacity(&params, i + FWL_MCCAPACITY_Sun));
    333     params.m_rtPart = rtDayOfWeek;
    334     params.m_wsText = *wsWeekDay;
    335     params.m_dwTTOStyles = FDE_TTOSTYLE_SingleLine;
    336     pTheme->DrawText(&params);
    337   }
    338 }
    339 void CFWL_MonthCalendarImp::DrawWeekNumber(CFX_Graphics* pGraphics,
    340                                            IFWL_ThemeProvider* pTheme,
    341                                            const CFX_Matrix* pMatrix) {
    342   CFWL_ThemeText params;
    343   params.m_pWidget = m_pInterface;
    344   params.m_iPart = FWL_PART_MCD_WeekNum;
    345   params.m_pGraphics = pGraphics;
    346   params.m_dwStates = FWL_PARTSTATE_MCD_Normal;
    347   params.m_iTTOAlign = FDE_TTOALIGNMENT_CenterLeft;
    348   CFX_WideString wsWeekNum;
    349   params.m_dwTTOStyles = FDE_TTOSTYLE_SingleLine;
    350   params.m_iTTOAlign = FDE_TTOALIGNMENT_Center;
    351   if (pMatrix) {
    352     params.m_matrix.Concat(*pMatrix);
    353   }
    354   int32_t iWeekNum = 0;
    355   int32_t iMonthNum = m_pDateTime->GetMonth();
    356   int32_t iDayNum = FX_DaysInMonth(m_iCurYear, iMonthNum);
    357   int32_t iTemp = 0;
    358   FX_FLOAT fVStartPos = m_rtClient.top + m_fHeadHei + m_fHSepHei;
    359   FX_FLOAT fHStartPos = m_rtClient.left;
    360   for (int32_t i = 1; i <= iDayNum; i += 7) {
    361     iTemp++;
    362     iWeekNum = CalWeekNumber(m_iCurYear, iMonthNum, i);
    363     m_rtWeekNum.Set(fHStartPos, fVStartPos + m_fDateCellHei * iTemp,
    364                     m_fWeekNumWid, m_fDateCellHei);
    365     wsWeekNum.Format(L"%d", iWeekNum);
    366     params.m_wsText = wsWeekNum;
    367     params.m_rtPart = m_rtWeekNum;
    368     pTheme->DrawText(&params);
    369   }
    370 }
    371 void CFWL_MonthCalendarImp::DrawWeekNumberSep(CFX_Graphics* pGraphics,
    372                                               IFWL_ThemeProvider* pTheme,
    373                                               const CFX_Matrix* pMatrix) {
    374   CFWL_ThemeBackground params;
    375   params.m_pWidget = m_pInterface;
    376   params.m_iPart = FWL_PART_MCD_WeekNumSep;
    377   params.m_pGraphics = pGraphics;
    378   params.m_dwStates = FWL_PARTSTATE_MCD_Normal;
    379   params.m_rtPart = m_rtWeekNumSep;
    380   if (pMatrix) {
    381     params.m_matrix.Concat(*pMatrix);
    382   }
    383   pTheme->DrawBackground(&params);
    384 }
    385 void CFWL_MonthCalendarImp::DrawToday(CFX_Graphics* pGraphics,
    386                                       IFWL_ThemeProvider* pTheme,
    387                                       const CFX_Matrix* pMatrix) {
    388   if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_MCD_NoToday) {
    389     return;
    390   }
    391   CFWL_ThemeText params;
    392   params.m_pWidget = m_pInterface;
    393   params.m_iPart = FWL_PART_MCD_Today;
    394   params.m_pGraphics = pGraphics;
    395   params.m_dwStates = FWL_PARTSTATE_MCD_Normal;
    396   params.m_iTTOAlign = FDE_TTOALIGNMENT_CenterLeft;
    397   CFX_WideString* wsDay = static_cast<CFX_WideString*>(
    398       pTheme->GetCapacity(&params, FWL_MCCAPACITY_Today));
    399   CFX_WideString wsText;
    400   GetTodayText(m_iYear, m_iMonth, m_iDay, wsText);
    401   params.m_wsText = *wsDay + wsText;
    402   m_szToday = CalcTextSize(params.m_wsText, m_pProperties->m_pThemeProvider);
    403   CalcTodaySize();
    404   params.m_rtPart = m_rtToday;
    405   params.m_dwTTOStyles = FDE_TTOSTYLE_SingleLine;
    406   if (pMatrix) {
    407     params.m_matrix.Concat(*pMatrix);
    408   }
    409   pTheme->DrawText(&params);
    410 }
    411 void CFWL_MonthCalendarImp::DrawDatesIn(CFX_Graphics* pGraphics,
    412                                         IFWL_ThemeProvider* pTheme,
    413                                         const CFX_Matrix* pMatrix) {
    414   CFWL_ThemeText params;
    415   params.m_pWidget = m_pInterface;
    416   params.m_iPart = FWL_PART_MCD_DatesIn;
    417   params.m_pGraphics = pGraphics;
    418   params.m_dwStates = FWL_PARTSTATE_MCD_Normal;
    419   params.m_iTTOAlign = FDE_TTOALIGNMENT_Center;
    420   if (pMatrix) {
    421     params.m_matrix.Concat(*pMatrix);
    422   }
    423   int32_t iCount = m_arrDates.GetSize();
    424   for (int32_t j = 0; j < iCount; j++) {
    425     LPDATEINFO pDataInfo = (LPDATEINFO)m_arrDates.GetAt(j);
    426     params.m_wsText = pDataInfo->wsDay;
    427     params.m_rtPart = pDataInfo->rect;
    428     params.m_dwStates = pDataInfo->dwStates;
    429     if (j + 1 == m_iHovered) {
    430       params.m_dwStates |= FWL_PARTSTATE_MCD_Hovered;
    431     }
    432     params.m_dwTTOStyles = FDE_TTOSTYLE_SingleLine;
    433     pTheme->DrawText(&params);
    434   }
    435 }
    436 void CFWL_MonthCalendarImp::DrawDatesOut(CFX_Graphics* pGraphics,
    437                                          IFWL_ThemeProvider* pTheme,
    438                                          const CFX_Matrix* pMatrix) {
    439   CFWL_ThemeText params;
    440   params.m_pWidget = m_pInterface;
    441   params.m_iPart = FWL_PART_MCD_DatesOut;
    442   params.m_pGraphics = pGraphics;
    443   params.m_dwStates = FWL_PARTSTATE_MCD_Normal;
    444   params.m_iTTOAlign = FDE_TTOALIGNMENT_Center;
    445   if (pMatrix) {
    446     params.m_matrix.Concat(*pMatrix);
    447   }
    448   pTheme->DrawText(&params);
    449 }
    450 void CFWL_MonthCalendarImp::DrawDatesInCircle(CFX_Graphics* pGraphics,
    451                                               IFWL_ThemeProvider* pTheme,
    452                                               const CFX_Matrix* pMatrix) {
    453   if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_MCD_NoTodayCircle) {
    454     return;
    455   }
    456   if (m_iMonth != m_iCurMonth || m_iYear != m_iCurYear) {
    457     return;
    458   }
    459   if (m_iDay < 1 || m_iDay > m_arrDates.GetSize()) {
    460     return;
    461   }
    462   LPDATEINFO pDate = (LPDATEINFO)m_arrDates[m_iDay - 1];
    463   if (!pDate)
    464     return;
    465   CFWL_ThemeBackground params;
    466   params.m_pWidget = m_pInterface;
    467   params.m_iPart = FWL_PART_MCD_DateInCircle;
    468   params.m_pGraphics = pGraphics;
    469   params.m_rtPart = pDate->rect;
    470   params.m_dwStates = FWL_PARTSTATE_MCD_Normal;
    471   if (pMatrix) {
    472     params.m_matrix.Concat(*pMatrix);
    473   }
    474   pTheme->DrawBackground(&params);
    475 }
    476 void CFWL_MonthCalendarImp::DrawTodayCircle(CFX_Graphics* pGraphics,
    477                                             IFWL_ThemeProvider* pTheme,
    478                                             const CFX_Matrix* pMatrix) {
    479   if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_MCD_NoToday) {
    480     return;
    481   }
    482   if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_MCD_NoTodayCircle) {
    483     return;
    484   }
    485   CFWL_ThemeBackground params;
    486   params.m_pWidget = m_pInterface;
    487   params.m_iPart = FWL_PART_MCD_TodayCircle;
    488   params.m_pGraphics = pGraphics;
    489   params.m_dwStates = FWL_PARTSTATE_MCD_Normal;
    490   params.m_rtPart = m_rtTodayFlag;
    491   if (pMatrix) {
    492     params.m_matrix.Concat(*pMatrix);
    493   }
    494   pTheme->DrawBackground(&params);
    495 }
    496 CFX_SizeF CFWL_MonthCalendarImp::CalcSize(FX_BOOL bAutoSize) {
    497   CFX_SizeF fs;
    498   fs.Set(0, 0);
    499   if (!m_pProperties->m_pThemeProvider)
    500     return fs;
    501   if (bAutoSize) {
    502     CFWL_ThemePart params;
    503     params.m_pWidget = m_pInterface;
    504     IFWL_ThemeProvider* pTheme = m_pProperties->m_pThemeProvider;
    505     CFX_WideString* wsText = NULL;
    506     FX_FLOAT fMaxWeekW = 0.0f;
    507     FX_FLOAT fMaxWeekH = 0.0f;
    508     for (FX_DWORD week = FWL_MCCAPACITY_Sun; week <= FWL_MCCAPACITY_Sat;
    509          week++) {
    510       wsText = static_cast<CFX_WideString*>(pTheme->GetCapacity(&params, week));
    511       CFX_SizeF sz = CalcTextSize(*wsText, m_pProperties->m_pThemeProvider);
    512       fMaxWeekW = (fMaxWeekW >= sz.x) ? fMaxWeekW : sz.x;
    513       fMaxWeekH = (fMaxWeekH >= sz.y) ? fMaxWeekH : sz.y;
    514     }
    515     FX_FLOAT fDayMaxW = 0.0f;
    516     FX_FLOAT fDayMaxH = 0.0f;
    517     for (int day = 10; day <= 31; day++) {
    518       CFX_WideString wsDay;
    519       wsDay.Format(L"%d", day);
    520       CFX_SizeF sz = CalcTextSize(wsDay, m_pProperties->m_pThemeProvider);
    521       fDayMaxW = (fDayMaxW >= sz.x) ? fDayMaxW : sz.x;
    522       fDayMaxH = (fDayMaxH >= sz.y) ? fDayMaxH : sz.y;
    523     }
    524     m_szCell.x = FX_FLOAT((fMaxWeekW >= fDayMaxW) ? (int)(fMaxWeekW + 0.5)
    525                                                   : (int)(fDayMaxW + 0.5));
    526     m_szCell.y = (fMaxWeekH >= fDayMaxH) ? fMaxWeekH : fDayMaxH;
    527     fs.x = m_szCell.x * MONTHCAL_COLUMNS +
    528            MONTHCAL_HMARGIN * MONTHCAL_COLUMNS * 2 +
    529            MONTHCAL_HEADER_BTN_HMARGIN * 2;
    530     FX_FLOAT fMonthMaxW = 0.0f;
    531     FX_FLOAT fMonthMaxH = 0.0f;
    532     for (FX_DWORD month = FWL_MCCAPACITY_January;
    533          month <= FWL_MCCAPACITY_December; month++) {
    534       wsText =
    535           static_cast<CFX_WideString*>(pTheme->GetCapacity(&params, month));
    536       CFX_SizeF sz = CalcTextSize(*wsText, m_pProperties->m_pThemeProvider);
    537       fMonthMaxW = (fMonthMaxW >= sz.x) ? fMonthMaxW : sz.x;
    538       fMonthMaxH = (fMonthMaxH >= sz.y) ? fMonthMaxH : sz.y;
    539     }
    540     CFX_WideString wsYear;
    541     GetHeadText(m_iYear, m_iMonth, wsYear);
    542     CFX_SizeF szYear = CalcTextSize(wsYear, m_pProperties->m_pThemeProvider);
    543     fMonthMaxH = (fMonthMaxH >= szYear.y) ? fMonthMaxH : szYear.y;
    544     m_szHead.Set(fMonthMaxW + szYear.x, fMonthMaxH);
    545     fMonthMaxW = m_szHead.x + MONTHCAL_HEADER_BTN_HMARGIN * 2 + m_szCell.x * 2;
    546     fs.x = (fs.x >= fMonthMaxW) ? fs.x : fMonthMaxW;
    547     CFX_WideString wsToday;
    548     GetTodayText(m_iYear, m_iMonth, m_iDay, wsToday);
    549     wsText = static_cast<CFX_WideString*>(
    550         pTheme->GetCapacity(&params, FWL_MCCAPACITY_Today));
    551     m_wsToday = *wsText + wsToday;
    552     m_szToday = CalcTextSize(wsToday, m_pProperties->m_pThemeProvider);
    553     m_szToday.y = (m_szToday.y >= m_szCell.y) ? m_szToday.y : m_szCell.y;
    554     fs.y = m_szCell.x + m_szCell.y * (MONTHCAL_ROWS - 2) + m_szToday.y +
    555            MONTHCAL_VMARGIN * MONTHCAL_ROWS * 2 +
    556            MONTHCAL_HEADER_BTN_VMARGIN * 4;
    557   } else {
    558     GetClientRect(m_rtClient);
    559     fs.Set(m_rtClient.width, m_rtClient.height);
    560   }
    561   return fs;
    562 }
    563 void CFWL_MonthCalendarImp::CalcHeadSize() {
    564   FX_FLOAT fHeadHMargin = (m_rtClient.width - m_szHead.x) / 2;
    565   FX_FLOAT fHeadVMargin = (m_szCell.x - m_szHead.y) / 2;
    566   m_rtHeadText.Set(m_rtClient.left + fHeadHMargin,
    567                    m_rtClient.top + MONTHCAL_HEADER_BTN_VMARGIN +
    568                        MONTHCAL_VMARGIN + fHeadVMargin,
    569                    m_szHead.x, m_szHead.y);
    570 }
    571 void CFWL_MonthCalendarImp::CalcTodaySize() {
    572   m_rtTodayFlag.Set(
    573       m_rtClient.left + MONTHCAL_HEADER_BTN_HMARGIN + MONTHCAL_HMARGIN,
    574       m_rtDates.bottom() + MONTHCAL_HEADER_BTN_VMARGIN + MONTHCAL_VMARGIN,
    575       m_szCell.x, m_szToday.y);
    576   m_rtToday.Set(
    577       m_rtClient.left + MONTHCAL_HEADER_BTN_HMARGIN + m_szCell.x +
    578           MONTHCAL_HMARGIN * 2,
    579       m_rtDates.bottom() + MONTHCAL_HEADER_BTN_VMARGIN + MONTHCAL_VMARGIN,
    580       m_szToday.x, m_szToday.y);
    581 }
    582 void CFWL_MonthCalendarImp::LayOut() {
    583   GetClientRect(m_rtClient);
    584   {
    585     m_rtHead.Set(
    586         m_rtClient.left + MONTHCAL_HEADER_BTN_HMARGIN, m_rtClient.top,
    587         m_rtClient.width - MONTHCAL_HEADER_BTN_HMARGIN * 2,
    588         m_szCell.x + (MONTHCAL_HEADER_BTN_VMARGIN + MONTHCAL_VMARGIN) * 2);
    589     m_rtWeek.Set(m_rtClient.left + MONTHCAL_HEADER_BTN_HMARGIN,
    590                  m_rtHead.bottom(),
    591                  m_rtClient.width - MONTHCAL_HEADER_BTN_HMARGIN * 2,
    592                  m_szCell.y + MONTHCAL_VMARGIN * 2);
    593     m_rtLBtn.Set(m_rtClient.left + MONTHCAL_HEADER_BTN_HMARGIN,
    594                  m_rtClient.top + MONTHCAL_HEADER_BTN_VMARGIN, m_szCell.x,
    595                  m_szCell.x);
    596     m_rtRBtn.Set(m_rtClient.left + m_rtClient.width -
    597                      MONTHCAL_HEADER_BTN_HMARGIN - m_szCell.x,
    598                  m_rtClient.top + MONTHCAL_HEADER_BTN_VMARGIN, m_szCell.x,
    599                  m_szCell.x);
    600     m_rtHSep.Set(
    601         m_rtClient.left + MONTHCAL_HEADER_BTN_HMARGIN + MONTHCAL_HMARGIN,
    602         m_rtWeek.bottom() - MONTHCAL_VMARGIN,
    603         m_rtClient.width - (MONTHCAL_HEADER_BTN_HMARGIN + MONTHCAL_HMARGIN) * 2,
    604         MONTHCAL_HSEP_HEIGHT);
    605     m_rtDates.Set(m_rtClient.left + MONTHCAL_HEADER_BTN_HMARGIN,
    606                   m_rtWeek.bottom(),
    607                   m_rtClient.width - MONTHCAL_HEADER_BTN_HMARGIN * 2,
    608                   m_szCell.y * (MONTHCAL_ROWS - 3) +
    609                       MONTHCAL_VMARGIN * (MONTHCAL_ROWS - 3) * 2);
    610   }
    611   CalDateItem();
    612 }
    613 void CFWL_MonthCalendarImp::CalDateItem() {
    614   FX_BOOL bNewWeek = FALSE;
    615   int32_t iWeekOfMonth = 0;
    616   FX_FLOAT fLeft = m_rtDates.left;
    617   FX_FLOAT fTop = m_rtDates.top;
    618   int32_t iCount = m_arrDates.GetSize();
    619   for (int32_t i = 0; i < iCount; i++) {
    620     LPDATEINFO pDateInfo = (LPDATEINFO)m_arrDates.GetAt(i);
    621     if (bNewWeek) {
    622       iWeekOfMonth++;
    623       bNewWeek = FALSE;
    624     }
    625     pDateInfo->rect.Set(
    626         fLeft + pDateInfo->iDayOfWeek * (m_szCell.x + (MONTHCAL_HMARGIN * 2)),
    627         fTop + iWeekOfMonth * (m_szCell.y + (MONTHCAL_VMARGIN * 2)),
    628         m_szCell.x + (MONTHCAL_HMARGIN * 2),
    629         m_szCell.y + (MONTHCAL_VMARGIN * 2));
    630     if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_MCD_WeekNumbers) {
    631       pDateInfo->rect.Offset(m_fWeekNumWid, 0);
    632     }
    633     if (pDateInfo->iDayOfWeek >= 6) {
    634       bNewWeek = TRUE;
    635     }
    636   }
    637 }
    638 void CFWL_MonthCalendarImp::GetCapValue() {
    639   if (!m_pProperties->m_pThemeProvider) {
    640     m_pProperties->m_pThemeProvider = GetAvailableTheme();
    641   }
    642   IFWL_ThemeProvider* pTheme = m_pProperties->m_pThemeProvider;
    643   CFWL_ThemePart part;
    644   part.m_pWidget = m_pInterface;
    645   m_fHeadWid = *static_cast<FX_FLOAT*>(
    646       pTheme->GetCapacity(&part, FWL_WGTCAPACITY_MC_HEADER_WIDTH));
    647   m_fHeadHei = *static_cast<FX_FLOAT*>(
    648       pTheme->GetCapacity(&part, FWL_WGTCAPACITY_MC_HEADER_Height));
    649   m_fHeadBtnWid = *static_cast<FX_FLOAT*>(
    650       pTheme->GetCapacity(&part, FWL_WGTCAPACITY_MC_HEADER_BTN_WIDTH));
    651   m_fHeadBtnHei = *static_cast<FX_FLOAT*>(
    652       pTheme->GetCapacity(&part, FWL_WGTCAPACITY_MC_HEADER_BTN_HEIGHT));
    653   m_fHeadBtnHMargin = *static_cast<FX_FLOAT*>(
    654       pTheme->GetCapacity(&part, FWL_WGTCAPACITY_MC_HEADER_BTN_HMARGIN));
    655   m_fHeadBtnVMargin = *static_cast<FX_FLOAT*>(
    656       pTheme->GetCapacity(&part, FWL_WGTCAPACITY_MC_HEADER_BTN_VMARGIN));
    657   m_fHeadTextWid = *static_cast<FX_FLOAT*>(
    658       pTheme->GetCapacity(&part, FWL_WGTCAPACITY_MC_HEADER_TEXTWIDHT));
    659   m_fHeadTextHei = *static_cast<FX_FLOAT*>(
    660       pTheme->GetCapacity(&part, FWL_WGTCAPACITY_MC_HEADER_TEXTHEIGHT));
    661   m_fHeadTextHMargin = *static_cast<FX_FLOAT*>(
    662       pTheme->GetCapacity(&part, FWL_WGTCAPACITY_MC_HEADER_TEXT_HMARGIN));
    663   m_fHeadTextVMargin = *static_cast<FX_FLOAT*>(
    664       pTheme->GetCapacity(&part, FWL_WGTCAPACITY_MC_HEADER_TEXT_VMARGIN));
    665   m_fHSepWid = *static_cast<FX_FLOAT*>(
    666       pTheme->GetCapacity(&part, FWL_WGTCAPACITY_MC_HSEP_WIDTH));
    667   m_fHSepHei = *static_cast<FX_FLOAT*>(
    668       pTheme->GetCapacity(&part, FWL_WGTCAPACITY_MC_HSEP_HEIGHT));
    669   m_fWeekNumWid = *static_cast<FX_FLOAT*>(
    670       pTheme->GetCapacity(&part, FWL_WGTCAPACITY_MC_WEEKNUM_WIDTH));
    671   m_fSepDOffset = *static_cast<FX_FLOAT*>(
    672       pTheme->GetCapacity(&part, FWL_WGTCAPACITY_MC_SEP_DOFFSET));
    673   m_fSepX = *static_cast<FX_FLOAT*>(
    674       pTheme->GetCapacity(&part, FWL_WGTCAPACITY_MC_SEP_X));
    675   m_fSepY = *static_cast<FX_FLOAT*>(
    676       pTheme->GetCapacity(&part, FWL_WGTCAPACITY_MC_SEP_Y));
    677   m_fWeekNumHeigh = *static_cast<FX_FLOAT*>(
    678       pTheme->GetCapacity(&part, FWL_WGTCAPACITY_MC_WEEKNUM_HEIGHT));
    679   m_fWeekWid = *static_cast<FX_FLOAT*>(
    680       pTheme->GetCapacity(&part, FWL_WGTCAPACITY_MC_WEEK_WIDTH));
    681   m_fWeekHei = *static_cast<FX_FLOAT*>(
    682       pTheme->GetCapacity(&part, FWL_WGTCAPACITY_MC_WEEK_HEIGHT));
    683   m_fDateCellWid = *static_cast<FX_FLOAT*>(
    684       pTheme->GetCapacity(&part, FWL_WGTCAPACITY_MC_DATES_CELL_WIDTH));
    685   m_fDateCellHei = *static_cast<FX_FLOAT*>(
    686       pTheme->GetCapacity(&part, FWL_WGTCAPACITY_MC_DATES_CELL_HEIGHT));
    687   m_fTodayWid = *static_cast<FX_FLOAT*>(
    688       pTheme->GetCapacity(&part, FWL_WGTCAPACITY_MC_TODAY_WIDHT));
    689   m_fTodayHei = *static_cast<FX_FLOAT*>(
    690       pTheme->GetCapacity(&part, FWL_WGTCAPACITY_MC_TODAY_HEIGHT));
    691   m_fTodayFlagWid = *static_cast<FX_FLOAT*>(
    692       pTheme->GetCapacity(&part, FWL_WGTCAPACITY_MC_TODAY_FLAG_WIDHT));
    693   m_fMCWid = *static_cast<FX_FLOAT*>(
    694       pTheme->GetCapacity(&part, FWL_WGTCAPACITY_MC_WIDTH));
    695   if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_MCD_WeekNumbers) {
    696     m_fMCWid += m_fWeekNumWid;
    697   }
    698   m_fMCHei = *static_cast<FX_FLOAT*>(
    699       pTheme->GetCapacity(&part, FWL_WGTCAPACITY_MC_HEIGHT));
    700 }
    701 int32_t CFWL_MonthCalendarImp::CalWeekNumber(int32_t iYear,
    702                                              int32_t iMonth,
    703                                              int32_t iDay) {
    704   return 0;
    705 }
    706 FX_BOOL CFWL_MonthCalendarImp::GetMinDate(int32_t& iYear,
    707                                           int32_t& iMonth,
    708                                           int32_t& iDay) {
    709   iYear = m_dtMin.iYear;
    710   iMonth = m_dtMin.iMonth;
    711   iDay = m_dtMin.iDay;
    712   return TRUE;
    713 }
    714 FX_BOOL CFWL_MonthCalendarImp::SetMinDate(int32_t iYear,
    715                                           int32_t iMonth,
    716                                           int32_t iDay) {
    717   m_dtMin = DATE(iYear, iMonth, iDay);
    718   return TRUE;
    719 }
    720 FX_BOOL CFWL_MonthCalendarImp::GetMaxDate(int32_t& iYear,
    721                                           int32_t& iMonth,
    722                                           int32_t& iDay) {
    723   iYear = m_dtMax.iYear;
    724   iMonth = m_dtMax.iMonth;
    725   iDay = m_dtMax.iDay;
    726   return TRUE;
    727 }
    728 FX_BOOL CFWL_MonthCalendarImp::SetMaxDate(int32_t iYear,
    729                                           int32_t iMonth,
    730                                           int32_t iDay) {
    731   m_dtMax = DATE(iYear, iMonth, iDay);
    732   return TRUE;
    733 }
    734 FX_BOOL CFWL_MonthCalendarImp::InitDate() {
    735   if (m_pProperties->m_pDataProvider) {
    736     IFWL_MonthCalendarDP* pDateProv =
    737         static_cast<IFWL_MonthCalendarDP*>(m_pProperties->m_pDataProvider);
    738     m_iYear = pDateProv->GetCurYear(m_pInterface);
    739     m_iMonth = pDateProv->GetCurMonth(m_pInterface);
    740     m_iDay = pDateProv->GetCurDay(m_pInterface);
    741     m_iCurYear = m_iYear;
    742     m_iCurMonth = m_iMonth;
    743   } else {
    744     m_iDay = 1;
    745     m_iMonth = 1;
    746     m_iYear = 1;
    747     m_iCurYear = m_iYear;
    748     m_iCurMonth = m_iMonth;
    749   }
    750   GetTodayText(m_iYear, m_iMonth, m_iDay, m_wsToday);
    751   GetHeadText(m_iCurYear, m_iCurMonth, m_wsHead);
    752   m_dtMin = DATE(1500, 12, 1);
    753   m_dtMax = DATE(2200, 1, 1);
    754   return TRUE;
    755 }
    756 void CFWL_MonthCalendarImp::ClearDateItem() {
    757   int32_t iCount = m_arrDates.GetSize();
    758   for (int32_t i = 0; i < iCount; i++) {
    759     LPDATEINFO pData = (LPDATEINFO)m_arrDates.GetAt(i);
    760     delete pData;
    761   }
    762   m_arrDates.RemoveAll();
    763 }
    764 void CFWL_MonthCalendarImp::ReSetDateItem() {
    765   m_pDateTime->Set(m_iCurYear, m_iCurMonth, 1);
    766   int32_t iDays = FX_DaysInMonth(m_iCurYear, m_iCurMonth);
    767   int32_t iDayOfWeek = m_pDateTime->GetDayOfWeek();
    768   for (int32_t i = 0; i < iDays; i++) {
    769     if (iDayOfWeek >= 7) {
    770       iDayOfWeek = 0;
    771     }
    772     CFX_WideString wsDay;
    773     wsDay.Format(L"%d", i + 1);
    774     FX_DWORD dwStates = 0;
    775     if (m_iYear == m_iCurYear && m_iMonth == m_iCurMonth && m_iDay == (i + 1)) {
    776       dwStates |= FWL_ITEMSTATE_MCD_Flag;
    777     }
    778     if (m_arrSelDays.Find(i + 1) != -1) {
    779       dwStates |= FWL_ITEMSTATE_MCD_Selected;
    780     }
    781     CFX_RectF rtDate;
    782     rtDate.Set(0, 0, 0, 0);
    783     LPDATEINFO pData = new DATEINFO(i + 1, iDayOfWeek, dwStates, rtDate, wsDay);
    784     m_arrDates.Add(pData);
    785     iDayOfWeek++;
    786   }
    787 }
    788 FX_BOOL CFWL_MonthCalendarImp::NextMonth() {
    789   int32_t iYear = m_iCurYear, iMonth = m_iCurMonth;
    790   if (iMonth >= 12) {
    791     iMonth = 1;
    792     iYear++;
    793   } else {
    794     iMonth++;
    795   }
    796   DATE dt(m_iCurYear, m_iCurMonth, 1);
    797   if (!(dt < m_dtMax)) {
    798     return FALSE;
    799   }
    800   m_iCurYear = iYear, m_iCurMonth = iMonth;
    801   ChangeToMonth(m_iCurYear, m_iCurMonth);
    802   return TRUE;
    803 }
    804 FX_BOOL CFWL_MonthCalendarImp::PrevMonth() {
    805   int32_t iYear = m_iCurYear, iMonth = m_iCurMonth;
    806   if (iMonth <= 1) {
    807     iMonth = 12;
    808     iYear--;
    809   } else {
    810     iMonth--;
    811   }
    812   DATE dt(m_iCurYear, m_iCurMonth, 1);
    813   if (!(dt > m_dtMin)) {
    814     return FALSE;
    815   }
    816   m_iCurYear = iYear, m_iCurMonth = iMonth;
    817   ChangeToMonth(m_iCurYear, m_iCurMonth);
    818   return TRUE;
    819 }
    820 void CFWL_MonthCalendarImp::ChangeToMonth(int32_t iYear, int32_t iMonth) {
    821   m_iCurYear = iYear;
    822   m_iCurMonth = iMonth;
    823   m_iHovered = -1;
    824   ClearDateItem();
    825   ReSetDateItem();
    826   CalDateItem();
    827   GetHeadText(m_iCurYear, m_iCurMonth, m_wsHead);
    828 }
    829 FX_BOOL CFWL_MonthCalendarImp::RemoveSelDay(int32_t iDay, FX_BOOL bAll) {
    830   if (iDay == -1 && !bAll) {
    831     return FALSE;
    832   }
    833   if (bAll) {
    834     int32_t iCount = m_arrSelDays.GetSize();
    835     int32_t iDatesCount = m_arrDates.GetSize();
    836     for (int32_t i = 0; i < iCount; i++) {
    837       int32_t iSelDay = m_arrSelDays.GetAt(i);
    838       if (iSelDay <= iDatesCount) {
    839         LPDATEINFO pDateInfo = (LPDATEINFO)m_arrDates.GetAt(iSelDay - 1);
    840         pDateInfo->dwStates &= ~FWL_ITEMSTATE_MCD_Selected;
    841       }
    842     }
    843     m_arrSelDays.RemoveAll();
    844   } else {
    845     int32_t index = m_arrSelDays.Find(iDay);
    846     if (index == -1) {
    847       return FALSE;
    848     }
    849     int32_t iSelDay = m_arrSelDays.GetAt(iDay);
    850     int32_t iDatesCount = m_arrDates.GetSize();
    851     if (iSelDay <= iDatesCount) {
    852       LPDATEINFO pDateInfo = (LPDATEINFO)m_arrDates.GetAt(iSelDay - 1);
    853       pDateInfo->dwStates &= ~FWL_ITEMSTATE_MCD_Selected;
    854     }
    855     m_arrSelDays.RemoveAt(index);
    856   }
    857   return TRUE;
    858 }
    859 FX_BOOL CFWL_MonthCalendarImp::AddSelDay(int32_t iDay) {
    860   FXSYS_assert(iDay > 0);
    861   if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_MCD_MultiSelect) {
    862   } else {
    863     if (m_arrSelDays.Find(iDay) == -1) {
    864       RemoveSelDay(-1, TRUE);
    865       if (iDay <= m_arrDates.GetSize()) {
    866         LPDATEINFO pDateInfo = (LPDATEINFO)m_arrDates.GetAt(iDay - 1);
    867         pDateInfo->dwStates |= FWL_ITEMSTATE_MCD_Selected;
    868       }
    869       m_arrSelDays.Add(iDay);
    870     }
    871   }
    872   return TRUE;
    873 }
    874 FX_BOOL CFWL_MonthCalendarImp::JumpToToday() {
    875   if (m_iYear != m_iCurYear || m_iMonth != m_iCurMonth) {
    876     m_iCurYear = m_iYear;
    877     m_iCurMonth = m_iMonth;
    878     ChangeToMonth(m_iYear, m_iMonth);
    879     AddSelDay(m_iDay);
    880   } else {
    881     if (m_arrSelDays.Find(m_iDay) == -1) {
    882       AddSelDay(m_iDay);
    883     }
    884   }
    885   return TRUE;
    886 }
    887 void CFWL_MonthCalendarImp::GetHeadText(int32_t iYear,
    888                                         int32_t iMonth,
    889                                         CFX_WideString& wsHead) {
    890   FXSYS_assert(iMonth > 0 && iMonth < 13);
    891   static const FX_WCHAR* const pMonth[] = {
    892       L"January",   L"February", L"March",    L"April",
    893       L"May",       L"June",     L"July",     L"August",
    894       L"September", L"October",  L"November", L"December"};
    895   wsHead.Format(L"%s, %d", pMonth[iMonth - 1], iYear);
    896 }
    897 void CFWL_MonthCalendarImp::GetTodayText(int32_t iYear,
    898                                          int32_t iMonth,
    899                                          int32_t iDay,
    900                                          CFX_WideString& wsToday) {
    901   wsToday.Format(L", %d/%d/%d", iDay, iMonth, iYear);
    902 }
    903 int32_t CFWL_MonthCalendarImp::GetDayAtPoint(FX_FLOAT x, FX_FLOAT y) {
    904   int32_t iCount = m_arrDates.GetSize();
    905   for (int32_t i = 0; i < iCount; i++) {
    906     LPDATEINFO pDateInfo = (LPDATEINFO)m_arrDates.GetAt(i);
    907     if (pDateInfo->rect.Contains(x, y)) {
    908       return ++i;
    909     }
    910   }
    911   return -1;
    912 }
    913 FX_BOOL CFWL_MonthCalendarImp::GetDayRect(int32_t iDay, CFX_RectF& rtDay) {
    914   if (iDay <= 0 || iDay > m_arrDates.GetSize()) {
    915     return FALSE;
    916   }
    917   LPDATEINFO pDateInfo = (LPDATEINFO)m_arrDates[iDay - 1];
    918   if (!pDateInfo)
    919     return FALSE;
    920   rtDay = pDateInfo->rect;
    921   return TRUE;
    922 }
    923 CFWL_MonthCalendarImpDelegate::CFWL_MonthCalendarImpDelegate(
    924     CFWL_MonthCalendarImp* pOwner)
    925     : m_pOwner(pOwner) {}
    926 int32_t CFWL_MonthCalendarImpDelegate::OnProcessMessage(
    927     CFWL_Message* pMessage) {
    928   if (!pMessage)
    929     return 0;
    930   FX_DWORD dwMsgCode = pMessage->GetClassID();
    931   int32_t iRet = 1;
    932   switch (dwMsgCode) {
    933     case FWL_MSGHASH_SetFocus:
    934     case FWL_MSGHASH_KillFocus: {
    935       OnFocusChanged(pMessage, dwMsgCode == FWL_MSGHASH_SetFocus);
    936       break;
    937     }
    938     case FWL_MSGHASH_Key: {
    939       break;
    940     }
    941     case FWL_MSGHASH_Mouse: {
    942       CFWL_MsgMouse* pMouse = static_cast<CFWL_MsgMouse*>(pMessage);
    943       FX_DWORD dwCmd = pMouse->m_dwCmd;
    944       switch (dwCmd) {
    945         case FWL_MSGMOUSECMD_LButtonDown: {
    946           OnLButtonDown(pMouse);
    947           break;
    948         }
    949         case FWL_MSGMOUSECMD_LButtonUp: {
    950           OnLButtonUp(pMouse);
    951           break;
    952         }
    953         case FWL_MSGMOUSECMD_MouseMove: {
    954           OnMouseMove(pMouse);
    955           break;
    956         }
    957         case FWL_MSGMOUSECMD_MouseLeave: {
    958           OnMouseLeave(pMouse);
    959           break;
    960         }
    961         default: { break; }
    962       }
    963       break;
    964     }
    965     default: {
    966       iRet = 0;
    967       break;
    968     }
    969   }
    970   CFWL_WidgetImpDelegate::OnProcessMessage(pMessage);
    971   return iRet;
    972 }
    973 FWL_ERR CFWL_MonthCalendarImpDelegate::OnDrawWidget(CFX_Graphics* pGraphics,
    974                                                     const CFX_Matrix* pMatrix) {
    975   return m_pOwner->DrawWidget(pGraphics, pMatrix);
    976 }
    977 void CFWL_MonthCalendarImpDelegate::OnActivate(CFWL_Message* pMsg) {
    978   return;
    979 }
    980 void CFWL_MonthCalendarImpDelegate::OnFocusChanged(CFWL_Message* pMsg,
    981                                                    FX_BOOL bSet) {
    982   if (bSet) {
    983     m_pOwner->m_pProperties->m_dwStates |= FWL_WGTSTATE_Focused;
    984   } else {
    985     m_pOwner->m_pProperties->m_dwStates &= ~FWL_WGTSTATE_Focused;
    986   }
    987   m_pOwner->Repaint(&m_pOwner->m_rtClient);
    988 }
    989 void CFWL_MonthCalendarImpDelegate::OnLButtonDown(CFWL_MsgMouse* pMsg) {
    990   if (m_pOwner->m_rtLBtn.Contains(pMsg->m_fx, pMsg->m_fy)) {
    991     m_pOwner->m_iLBtnPartStates = FWL_PARTSTATE_MCD_Pressed;
    992     m_pOwner->PrevMonth();
    993     m_pOwner->Repaint(&m_pOwner->m_rtClient);
    994   } else if (m_pOwner->m_rtRBtn.Contains(pMsg->m_fx, pMsg->m_fy)) {
    995     m_pOwner->m_iRBtnPartStates |= FWL_PARTSTATE_MCD_Pressed;
    996     m_pOwner->NextMonth();
    997     m_pOwner->Repaint(&m_pOwner->m_rtClient);
    998   } else if (m_pOwner->m_rtToday.Contains(pMsg->m_fx, pMsg->m_fy)) {
    999     if ((m_pOwner->m_pProperties->m_dwStyleExes & FWL_STYLEEXT_MCD_NoToday) ==
   1000         0) {
   1001       m_pOwner->JumpToToday();
   1002       m_pOwner->Repaint(&m_pOwner->m_rtClient);
   1003     }
   1004   } else {
   1005     if (m_pOwner->m_pProperties->m_dwStyleExes & FWL_STYLEEXT_MCD_MultiSelect) {
   1006     } else {
   1007       int32_t iOldSel = 0;
   1008       if (m_pOwner->m_arrSelDays.GetSize() > 0) {
   1009         iOldSel = m_pOwner->m_arrSelDays[0];
   1010       } else {
   1011         return;
   1012       }
   1013       int32_t iCurSel = m_pOwner->GetDayAtPoint(pMsg->m_fx, pMsg->m_fy);
   1014       FX_BOOL bSelChanged = iCurSel > 0 && iCurSel != iOldSel;
   1015       if (bSelChanged) {
   1016         LPDATEINFO lpDatesInfo =
   1017             (LPDATEINFO)m_pOwner->m_arrDates.GetAt(iCurSel - 1);
   1018         CFX_RectF rtInvalidate(lpDatesInfo->rect);
   1019         if (iOldSel > 0) {
   1020           lpDatesInfo = (LPDATEINFO)m_pOwner->m_arrDates.GetAt(iOldSel - 1);
   1021           rtInvalidate.Union(lpDatesInfo->rect);
   1022         }
   1023         m_pOwner->AddSelDay(iCurSel);
   1024         CFWL_EvtClick wmClick;
   1025         wmClick.m_pSrcTarget = m_pOwner->m_pInterface;
   1026         m_pOwner->DispatchEvent(&wmClick);
   1027         CFWL_EventMcdDateChanged wmDateSelected;
   1028         wmDateSelected.m_iStartDay = iCurSel;
   1029         wmDateSelected.m_iEndDay = iCurSel;
   1030         wmDateSelected.m_iOldMonth = m_pOwner->m_iCurMonth;
   1031         wmDateSelected.m_iOldYear = m_pOwner->m_iCurYear;
   1032         wmDateSelected.m_pSrcTarget = m_pOwner->m_pInterface;
   1033         m_pOwner->DispatchEvent(&wmDateSelected);
   1034         m_pOwner->Repaint(&rtInvalidate);
   1035       }
   1036     }
   1037   }
   1038 }
   1039 void CFWL_MonthCalendarImpDelegate::OnLButtonUp(CFWL_MsgMouse* pMsg) {
   1040   if (m_pOwner->m_rtLBtn.Contains(pMsg->m_fx, pMsg->m_fy)) {
   1041     m_pOwner->m_iLBtnPartStates = 0;
   1042     m_pOwner->Repaint(&m_pOwner->m_rtLBtn);
   1043   } else if (m_pOwner->m_rtRBtn.Contains(pMsg->m_fx, pMsg->m_fy)) {
   1044     m_pOwner->m_iRBtnPartStates = 0;
   1045     m_pOwner->Repaint(&m_pOwner->m_rtRBtn);
   1046   } else if (m_pOwner->m_rtDates.Contains(pMsg->m_fx, pMsg->m_fy)) {
   1047     int32_t iDay = m_pOwner->GetDayAtPoint(pMsg->m_fx, pMsg->m_fy);
   1048     if (iDay != -1) {
   1049       m_pOwner->AddSelDay(iDay);
   1050     }
   1051   }
   1052 }
   1053 void CFWL_MonthCalendarImpDelegate::OnMouseMove(CFWL_MsgMouse* pMsg) {
   1054   if (m_pOwner->m_pProperties->m_dwStyleExes & FWL_STYLEEXT_MCD_MultiSelect) {
   1055     return;
   1056   }
   1057   FX_BOOL bRepaint = FALSE;
   1058   CFX_RectF rtInvalidate;
   1059   rtInvalidate.Set(0, 0, 0, 0);
   1060   if (m_pOwner->m_rtDates.Contains(pMsg->m_fx, pMsg->m_fy)) {
   1061     int32_t iHover = m_pOwner->GetDayAtPoint(pMsg->m_fx, pMsg->m_fy);
   1062     bRepaint = m_pOwner->m_iHovered != iHover;
   1063     if (bRepaint) {
   1064       if (m_pOwner->m_iHovered > 0) {
   1065         m_pOwner->GetDayRect(m_pOwner->m_iHovered, rtInvalidate);
   1066       }
   1067       if (iHover > 0) {
   1068         CFX_RectF rtDay;
   1069         m_pOwner->GetDayRect(iHover, rtDay);
   1070         if (rtInvalidate.IsEmpty()) {
   1071           rtInvalidate = rtDay;
   1072         } else {
   1073           rtInvalidate.Union(rtDay);
   1074         }
   1075       }
   1076     }
   1077     m_pOwner->m_iHovered = iHover;
   1078   } else {
   1079     bRepaint = m_pOwner->m_iHovered > 0;
   1080     if (bRepaint) {
   1081       m_pOwner->GetDayRect(m_pOwner->m_iHovered, rtInvalidate);
   1082     }
   1083     m_pOwner->m_iHovered = -1;
   1084   }
   1085   if (bRepaint && !rtInvalidate.IsEmpty()) {
   1086     m_pOwner->Repaint(&rtInvalidate);
   1087   }
   1088 }
   1089 void CFWL_MonthCalendarImpDelegate::OnMouseLeave(CFWL_MsgMouse* pMsg) {
   1090   if (m_pOwner->m_iHovered > 0) {
   1091     CFX_RectF rtInvalidate;
   1092     rtInvalidate.Set(0, 0, 0, 0);
   1093     m_pOwner->GetDayRect(m_pOwner->m_iHovered, rtInvalidate);
   1094     m_pOwner->m_iHovered = -1;
   1095     if (!rtInvalidate.IsEmpty()) {
   1096       m_pOwner->Repaint(&rtInvalidate);
   1097     }
   1098   }
   1099 }
   1100