• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_monthcalendar.h"
8 
9 #include <algorithm>
10 #include <memory>
11 #include <utility>
12 
13 #include "third_party/base/ptr_util.h"
14 #include "third_party/base/stl_util.h"
15 #include "xfa/fde/tto/fde_textout.h"
16 #include "xfa/fwl/cfwl_datetimepicker.h"
17 #include "xfa/fwl/cfwl_formproxy.h"
18 #include "xfa/fwl/cfwl_messagemouse.h"
19 #include "xfa/fwl/cfwl_notedriver.h"
20 #include "xfa/fwl/cfwl_themebackground.h"
21 #include "xfa/fwl/cfwl_themetext.h"
22 #include "xfa/fwl/ifwl_themeprovider.h"
23 
24 #define MONTHCAL_HSEP_HEIGHT 1
25 #define MONTHCAL_VSEP_WIDTH 1
26 #define MONTHCAL_HMARGIN 3
27 #define MONTHCAL_VMARGIN 2
28 #define MONTHCAL_ROWS 9
29 #define MONTHCAL_COLUMNS 7
30 #define MONTHCAL_HEADER_BTN_VMARGIN 7
31 #define MONTHCAL_HEADER_BTN_HMARGIN 5
32 
33 namespace {
34 
GetCapacityForDay(IFWL_ThemeProvider * pTheme,CFWL_ThemePart & params,uint32_t day)35 CFX_WideString GetCapacityForDay(IFWL_ThemeProvider* pTheme,
36                                  CFWL_ThemePart& params,
37                                  uint32_t day) {
38   ASSERT(day < 7);
39 
40   if (day == 0)
41     return L"Sun";
42   if (day == 1)
43     return L"Mon";
44   if (day == 2)
45     return L"Tue";
46   if (day == 3)
47     return L"Wed";
48   if (day == 4)
49     return L"Thu";
50   if (day == 5)
51     return L"Fri";
52   return L"Sat";
53 }
54 
GetCapacityForMonth(IFWL_ThemeProvider * pTheme,CFWL_ThemePart & params,uint32_t month)55 CFX_WideString GetCapacityForMonth(IFWL_ThemeProvider* pTheme,
56                                    CFWL_ThemePart& params,
57                                    uint32_t month) {
58   ASSERT(month < 12);
59 
60   if (month == 0)
61     return L"January";
62   if (month == 1)
63     return L"February";
64   if (month == 2)
65     return L"March";
66   if (month == 3)
67     return L"April";
68   if (month == 4)
69     return L"May";
70   if (month == 5)
71     return L"June";
72   if (month == 6)
73     return L"July";
74   if (month == 7)
75     return L"August";
76   if (month == 8)
77     return L"September";
78   if (month == 9)
79     return L"October";
80   if (month == 10)
81     return L"November";
82   return L"December";
83 }
84 
85 }  // namespace
86 
CFWL_MonthCalendar(const CFWL_App * app,std::unique_ptr<CFWL_WidgetProperties> properties,CFWL_Widget * pOuter)87 CFWL_MonthCalendar::CFWL_MonthCalendar(
88     const CFWL_App* app,
89     std::unique_ptr<CFWL_WidgetProperties> properties,
90     CFWL_Widget* pOuter)
91     : CFWL_Widget(app, std::move(properties), pOuter),
92       m_bInitialized(false),
93       m_pDateTime(new CFX_DateTime),
94       m_iCurYear(2011),
95       m_iCurMonth(1),
96       m_iYear(2011),
97       m_iMonth(1),
98       m_iDay(1),
99       m_iHovered(-1),
100       m_iLBtnPartStates(CFWL_PartState_Normal),
101       m_iRBtnPartStates(CFWL_PartState_Normal),
102       m_bFlag(false) {
103   m_rtHead.Reset();
104   m_rtWeek.Reset();
105   m_rtLBtn.Reset();
106   m_rtRBtn.Reset();
107   m_rtDates.Reset();
108   m_rtHSep.Reset();
109   m_rtHeadText.Reset();
110   m_rtToday.Reset();
111   m_rtTodayFlag.Reset();
112   m_rtClient.Reset();
113   m_rtWeekNum.Reset();
114   m_rtWeekNumSep.Reset();
115 }
116 
~CFWL_MonthCalendar()117 CFWL_MonthCalendar::~CFWL_MonthCalendar() {
118   ClearDateItem();
119   m_arrSelDays.clear();
120 }
121 
GetClassID() const122 FWL_Type CFWL_MonthCalendar::GetClassID() const {
123   return FWL_Type::MonthCalendar;
124 }
125 
GetAutosizedWidgetRect()126 CFX_RectF CFWL_MonthCalendar::GetAutosizedWidgetRect() {
127   CFX_SizeF fs = CalcSize();
128   CFX_RectF rect(0, 0, fs.width, fs.height);
129   InflateWidgetRect(rect);
130   return rect;
131 }
132 
Update()133 void CFWL_MonthCalendar::Update() {
134   if (IsLocked())
135     return;
136   if (!m_pProperties->m_pThemeProvider)
137     m_pProperties->m_pThemeProvider = GetAvailableTheme();
138 
139   GetCapValue();
140   if (!m_bInitialized) {
141     InitDate();
142     m_bInitialized = true;
143   }
144 
145   ClearDateItem();
146   ResetDateItem();
147   Layout();
148 }
149 
DrawWidget(CFX_Graphics * pGraphics,const CFX_Matrix * pMatrix)150 void CFWL_MonthCalendar::DrawWidget(CFX_Graphics* pGraphics,
151                                     const CFX_Matrix* pMatrix) {
152   if (!pGraphics)
153     return;
154   if (!m_pProperties->m_pThemeProvider)
155     m_pProperties->m_pThemeProvider = GetAvailableTheme();
156 
157   IFWL_ThemeProvider* pTheme = m_pProperties->m_pThemeProvider;
158   if (HasBorder())
159     DrawBorder(pGraphics, CFWL_Part::Border, pTheme, pMatrix);
160 
161   DrawBackground(pGraphics, pTheme, pMatrix);
162   DrawHeadBK(pGraphics, pTheme, pMatrix);
163   DrawLButton(pGraphics, pTheme, pMatrix);
164   DrawRButton(pGraphics, pTheme, pMatrix);
165   DrawSeperator(pGraphics, pTheme, pMatrix);
166   DrawDatesInBK(pGraphics, pTheme, pMatrix);
167   DrawDatesInCircle(pGraphics, pTheme, pMatrix);
168   DrawCaption(pGraphics, pTheme, pMatrix);
169   DrawWeek(pGraphics, pTheme, pMatrix);
170   DrawDatesIn(pGraphics, pTheme, pMatrix);
171   DrawDatesOut(pGraphics, pTheme, pMatrix);
172   DrawToday(pGraphics, pTheme, pMatrix);
173 }
174 
SetSelect(int32_t iYear,int32_t iMonth,int32_t iDay)175 void CFWL_MonthCalendar::SetSelect(int32_t iYear,
176                                    int32_t iMonth,
177                                    int32_t iDay) {
178   ChangeToMonth(iYear, iMonth);
179   AddSelDay(iDay);
180 }
181 
DrawBackground(CFX_Graphics * pGraphics,IFWL_ThemeProvider * pTheme,const CFX_Matrix * pMatrix)182 void CFWL_MonthCalendar::DrawBackground(CFX_Graphics* pGraphics,
183                                         IFWL_ThemeProvider* pTheme,
184                                         const CFX_Matrix* pMatrix) {
185   CFWL_ThemeBackground params;
186   params.m_pWidget = this;
187   params.m_iPart = CFWL_Part::Background;
188   params.m_pGraphics = pGraphics;
189   params.m_dwStates = CFWL_PartState_Normal;
190   params.m_rtPart = m_rtClient;
191   if (pMatrix)
192     params.m_matrix.Concat(*pMatrix);
193   pTheme->DrawBackground(&params);
194 }
195 
DrawHeadBK(CFX_Graphics * pGraphics,IFWL_ThemeProvider * pTheme,const CFX_Matrix * pMatrix)196 void CFWL_MonthCalendar::DrawHeadBK(CFX_Graphics* pGraphics,
197                                     IFWL_ThemeProvider* pTheme,
198                                     const CFX_Matrix* pMatrix) {
199   CFWL_ThemeBackground params;
200   params.m_pWidget = this;
201   params.m_iPart = CFWL_Part::Header;
202   params.m_pGraphics = pGraphics;
203   params.m_dwStates = CFWL_PartState_Normal;
204   params.m_rtPart = m_rtHead;
205   if (pMatrix)
206     params.m_matrix.Concat(*pMatrix);
207   pTheme->DrawBackground(&params);
208 }
209 
DrawLButton(CFX_Graphics * pGraphics,IFWL_ThemeProvider * pTheme,const CFX_Matrix * pMatrix)210 void CFWL_MonthCalendar::DrawLButton(CFX_Graphics* pGraphics,
211                                      IFWL_ThemeProvider* pTheme,
212                                      const CFX_Matrix* pMatrix) {
213   CFWL_ThemeBackground params;
214   params.m_pWidget = this;
215   params.m_iPart = CFWL_Part::LBtn;
216   params.m_pGraphics = pGraphics;
217   params.m_dwStates = m_iLBtnPartStates;
218   params.m_rtPart = m_rtLBtn;
219   if (pMatrix)
220     params.m_matrix.Concat(*pMatrix);
221   pTheme->DrawBackground(&params);
222 }
223 
DrawRButton(CFX_Graphics * pGraphics,IFWL_ThemeProvider * pTheme,const CFX_Matrix * pMatrix)224 void CFWL_MonthCalendar::DrawRButton(CFX_Graphics* pGraphics,
225                                      IFWL_ThemeProvider* pTheme,
226                                      const CFX_Matrix* pMatrix) {
227   CFWL_ThemeBackground params;
228   params.m_pWidget = this;
229   params.m_iPart = CFWL_Part::RBtn;
230   params.m_pGraphics = pGraphics;
231   params.m_dwStates = m_iRBtnPartStates;
232   params.m_rtPart = m_rtRBtn;
233   if (pMatrix)
234     params.m_matrix.Concat(*pMatrix);
235   pTheme->DrawBackground(&params);
236 }
237 
DrawCaption(CFX_Graphics * pGraphics,IFWL_ThemeProvider * pTheme,const CFX_Matrix * pMatrix)238 void CFWL_MonthCalendar::DrawCaption(CFX_Graphics* pGraphics,
239                                      IFWL_ThemeProvider* pTheme,
240                                      const CFX_Matrix* pMatrix) {
241   CFWL_ThemeText textParam;
242   textParam.m_pWidget = this;
243   textParam.m_iPart = CFWL_Part::Caption;
244   textParam.m_dwStates = CFWL_PartState_Normal;
245   textParam.m_pGraphics = pGraphics;
246   textParam.m_wsText = GetHeadText(m_iCurYear, m_iCurMonth);
247   m_szHead =
248       CalcTextSize(textParam.m_wsText, m_pProperties->m_pThemeProvider, false);
249   CalcHeadSize();
250   textParam.m_rtPart = m_rtHeadText;
251   textParam.m_dwTTOStyles = FDE_TTOSTYLE_SingleLine;
252   textParam.m_iTTOAlign = FDE_TTOALIGNMENT_Center;
253   if (pMatrix)
254     textParam.m_matrix.Concat(*pMatrix);
255   pTheme->DrawText(&textParam);
256 }
257 
DrawSeperator(CFX_Graphics * pGraphics,IFWL_ThemeProvider * pTheme,const CFX_Matrix * pMatrix)258 void CFWL_MonthCalendar::DrawSeperator(CFX_Graphics* pGraphics,
259                                        IFWL_ThemeProvider* pTheme,
260                                        const CFX_Matrix* pMatrix) {
261   CFWL_ThemeBackground params;
262   params.m_pWidget = this;
263   params.m_iPart = CFWL_Part::HSeparator;
264   params.m_pGraphics = pGraphics;
265   params.m_dwStates = CFWL_PartState_Normal;
266   params.m_rtPart = m_rtHSep;
267   if (pMatrix)
268     params.m_matrix.Concat(*pMatrix);
269   pTheme->DrawBackground(&params);
270 }
271 
DrawDatesInBK(CFX_Graphics * pGraphics,IFWL_ThemeProvider * pTheme,const CFX_Matrix * pMatrix)272 void CFWL_MonthCalendar::DrawDatesInBK(CFX_Graphics* pGraphics,
273                                        IFWL_ThemeProvider* pTheme,
274                                        const CFX_Matrix* pMatrix) {
275   CFWL_ThemeBackground params;
276   params.m_pWidget = this;
277   params.m_iPart = CFWL_Part::DateInBK;
278   params.m_pGraphics = pGraphics;
279   if (pMatrix)
280     params.m_matrix.Concat(*pMatrix);
281 
282   int32_t iCount = pdfium::CollectionSize<int32_t>(m_arrDates);
283   for (int32_t j = 0; j < iCount; j++) {
284     DATEINFO* pDataInfo = m_arrDates[j].get();
285     if (pDataInfo->dwStates & FWL_ITEMSTATE_MCD_Selected) {
286       params.m_dwStates |= CFWL_PartState_Selected;
287       if (pDataInfo->dwStates & FWL_ITEMSTATE_MCD_Flag) {
288         params.m_dwStates |= CFWL_PartState_Flagged;
289       }
290     } else if (j == m_iHovered - 1) {
291       params.m_dwStates |= CFWL_PartState_Hovered;
292     } else if (pDataInfo->dwStates & FWL_ITEMSTATE_MCD_Flag) {
293       params.m_dwStates = CFWL_PartState_Flagged;
294       pTheme->DrawBackground(&params);
295     }
296     params.m_rtPart = pDataInfo->rect;
297     pTheme->DrawBackground(&params);
298     params.m_dwStates = 0;
299   }
300 }
301 
DrawWeek(CFX_Graphics * pGraphics,IFWL_ThemeProvider * pTheme,const CFX_Matrix * pMatrix)302 void CFWL_MonthCalendar::DrawWeek(CFX_Graphics* pGraphics,
303                                   IFWL_ThemeProvider* pTheme,
304                                   const CFX_Matrix* pMatrix) {
305   CFWL_ThemeText params;
306   params.m_pWidget = this;
307   params.m_iPart = CFWL_Part::Week;
308   params.m_pGraphics = pGraphics;
309   params.m_dwStates = CFWL_PartState_Normal;
310   params.m_iTTOAlign = FDE_TTOALIGNMENT_Center;
311   CFX_RectF rtDayOfWeek;
312   if (pMatrix)
313     params.m_matrix.Concat(*pMatrix);
314 
315   for (int32_t i = 0; i < 7; i++) {
316     rtDayOfWeek =
317         CFX_RectF(m_rtWeek.left + i * (m_szCell.width + MONTHCAL_HMARGIN * 2),
318                   m_rtWeek.top, m_szCell);
319 
320     params.m_rtPart = rtDayOfWeek;
321     params.m_wsText = GetCapacityForDay(pTheme, params, i);
322     params.m_dwTTOStyles = FDE_TTOSTYLE_SingleLine;
323     pTheme->DrawText(&params);
324   }
325 }
326 
DrawToday(CFX_Graphics * pGraphics,IFWL_ThemeProvider * pTheme,const CFX_Matrix * pMatrix)327 void CFWL_MonthCalendar::DrawToday(CFX_Graphics* pGraphics,
328                                    IFWL_ThemeProvider* pTheme,
329                                    const CFX_Matrix* pMatrix) {
330   CFWL_ThemeText params;
331   params.m_pWidget = this;
332   params.m_iPart = CFWL_Part::Today;
333   params.m_pGraphics = pGraphics;
334   params.m_dwStates = CFWL_PartState_Normal;
335   params.m_iTTOAlign = FDE_TTOALIGNMENT_CenterLeft;
336   params.m_wsText = L"Today" + GetTodayText(m_iYear, m_iMonth, m_iDay);
337 
338   m_szToday =
339       CalcTextSize(params.m_wsText, m_pProperties->m_pThemeProvider, false);
340   CalcTodaySize();
341   params.m_rtPart = m_rtToday;
342   params.m_dwTTOStyles = FDE_TTOSTYLE_SingleLine;
343   if (pMatrix)
344     params.m_matrix.Concat(*pMatrix);
345   pTheme->DrawText(&params);
346 }
347 
DrawDatesIn(CFX_Graphics * pGraphics,IFWL_ThemeProvider * pTheme,const CFX_Matrix * pMatrix)348 void CFWL_MonthCalendar::DrawDatesIn(CFX_Graphics* pGraphics,
349                                      IFWL_ThemeProvider* pTheme,
350                                      const CFX_Matrix* pMatrix) {
351   CFWL_ThemeText params;
352   params.m_pWidget = this;
353   params.m_iPart = CFWL_Part::DatesIn;
354   params.m_pGraphics = pGraphics;
355   params.m_dwStates = CFWL_PartState_Normal;
356   params.m_iTTOAlign = FDE_TTOALIGNMENT_Center;
357   if (pMatrix)
358     params.m_matrix.Concat(*pMatrix);
359 
360   int32_t iCount = pdfium::CollectionSize<int32_t>(m_arrDates);
361   for (int32_t j = 0; j < iCount; j++) {
362     DATEINFO* pDataInfo = m_arrDates[j].get();
363     params.m_wsText = pDataInfo->wsDay;
364     params.m_rtPart = pDataInfo->rect;
365     params.m_dwStates = pDataInfo->dwStates;
366     if (j + 1 == m_iHovered)
367       params.m_dwStates |= CFWL_PartState_Hovered;
368     params.m_dwTTOStyles = FDE_TTOSTYLE_SingleLine;
369     pTheme->DrawText(&params);
370   }
371 }
372 
DrawDatesOut(CFX_Graphics * pGraphics,IFWL_ThemeProvider * pTheme,const CFX_Matrix * pMatrix)373 void CFWL_MonthCalendar::DrawDatesOut(CFX_Graphics* pGraphics,
374                                       IFWL_ThemeProvider* pTheme,
375                                       const CFX_Matrix* pMatrix) {
376   CFWL_ThemeText params;
377   params.m_pWidget = this;
378   params.m_iPart = CFWL_Part::DatesOut;
379   params.m_pGraphics = pGraphics;
380   params.m_dwStates = CFWL_PartState_Normal;
381   params.m_iTTOAlign = FDE_TTOALIGNMENT_Center;
382   if (pMatrix)
383     params.m_matrix.Concat(*pMatrix);
384   pTheme->DrawText(&params);
385 }
386 
DrawDatesInCircle(CFX_Graphics * pGraphics,IFWL_ThemeProvider * pTheme,const CFX_Matrix * pMatrix)387 void CFWL_MonthCalendar::DrawDatesInCircle(CFX_Graphics* pGraphics,
388                                            IFWL_ThemeProvider* pTheme,
389                                            const CFX_Matrix* pMatrix) {
390   if (m_iMonth != m_iCurMonth || m_iYear != m_iCurYear)
391     return;
392 
393   if (m_iDay < 1 || m_iDay > pdfium::CollectionSize<int32_t>(m_arrDates))
394     return;
395 
396   DATEINFO* pDate = m_arrDates[m_iDay - 1].get();
397   if (!pDate)
398     return;
399 
400   CFWL_ThemeBackground params;
401   params.m_pWidget = this;
402   params.m_iPart = CFWL_Part::DateInCircle;
403   params.m_pGraphics = pGraphics;
404   params.m_rtPart = pDate->rect;
405   params.m_dwStates = CFWL_PartState_Normal;
406   if (pMatrix)
407     params.m_matrix.Concat(*pMatrix);
408   pTheme->DrawBackground(&params);
409 }
410 
CalcSize()411 CFX_SizeF CFWL_MonthCalendar::CalcSize() {
412   if (!m_pProperties->m_pThemeProvider)
413     return CFX_SizeF();
414 
415   CFWL_ThemePart params;
416   params.m_pWidget = this;
417   IFWL_ThemeProvider* pTheme = m_pProperties->m_pThemeProvider;
418   FX_FLOAT fMaxWeekW = 0.0f;
419   FX_FLOAT fMaxWeekH = 0.0f;
420 
421   for (uint32_t i = 0; i < 7; ++i) {
422     CFX_SizeF sz = CalcTextSize(GetCapacityForDay(pTheme, params, i),
423                                 m_pProperties->m_pThemeProvider, false);
424     fMaxWeekW = (fMaxWeekW >= sz.width) ? fMaxWeekW : sz.width;
425     fMaxWeekH = (fMaxWeekH >= sz.height) ? fMaxWeekH : sz.height;
426   }
427 
428   FX_FLOAT fDayMaxW = 0.0f;
429   FX_FLOAT fDayMaxH = 0.0f;
430   for (int day = 10; day <= 31; day++) {
431     CFX_WideString wsDay;
432     wsDay.Format(L"%d", day);
433     CFX_SizeF sz = CalcTextSize(wsDay, m_pProperties->m_pThemeProvider, false);
434     fDayMaxW = (fDayMaxW >= sz.width) ? fDayMaxW : sz.width;
435     fDayMaxH = (fDayMaxH >= sz.height) ? fDayMaxH : sz.height;
436   }
437   m_szCell.width = FX_FLOAT((fMaxWeekW >= fDayMaxW) ? (int)(fMaxWeekW + 0.5)
438                                                     : (int)(fDayMaxW + 0.5));
439   m_szCell.height = (fMaxWeekH >= fDayMaxH) ? fMaxWeekH : fDayMaxH;
440 
441   CFX_SizeF fs;
442   fs.width = m_szCell.width * MONTHCAL_COLUMNS +
443              MONTHCAL_HMARGIN * MONTHCAL_COLUMNS * 2 +
444              MONTHCAL_HEADER_BTN_HMARGIN * 2;
445   FX_FLOAT fMonthMaxW = 0.0f;
446   FX_FLOAT fMonthMaxH = 0.0f;
447 
448   for (uint32_t i = 0; i < 12; ++i) {
449     CFX_SizeF sz = CalcTextSize(GetCapacityForMonth(pTheme, params, i),
450                                 m_pProperties->m_pThemeProvider, false);
451     fMonthMaxW = (fMonthMaxW >= sz.width) ? fMonthMaxW : sz.width;
452     fMonthMaxH = (fMonthMaxH >= sz.height) ? fMonthMaxH : sz.height;
453   }
454 
455   CFX_SizeF szYear = CalcTextSize(GetHeadText(m_iYear, m_iMonth),
456                                   m_pProperties->m_pThemeProvider, false);
457   fMonthMaxH = std::max(fMonthMaxH, szYear.height);
458   m_szHead = CFX_SizeF(fMonthMaxW + szYear.width, fMonthMaxH);
459   fMonthMaxW =
460       m_szHead.width + MONTHCAL_HEADER_BTN_HMARGIN * 2 + m_szCell.width * 2;
461   fs.width = std::max(fs.width, fMonthMaxW);
462 
463   CFX_WideString wsToday = GetTodayText(m_iYear, m_iMonth, m_iDay);
464   m_wsToday = L"Today" + wsToday;
465   m_szToday = CalcTextSize(wsToday, m_pProperties->m_pThemeProvider, false);
466   m_szToday.height = (m_szToday.height >= m_szCell.height) ? m_szToday.height
467                                                            : m_szCell.height;
468   fs.height = m_szCell.width + m_szCell.height * (MONTHCAL_ROWS - 2) +
469               m_szToday.height + MONTHCAL_VMARGIN * MONTHCAL_ROWS * 2 +
470               MONTHCAL_HEADER_BTN_VMARGIN * 4;
471   return fs;
472 }
473 
CalcHeadSize()474 void CFWL_MonthCalendar::CalcHeadSize() {
475   FX_FLOAT fHeadHMargin = (m_rtClient.width - m_szHead.width) / 2;
476   FX_FLOAT fHeadVMargin = (m_szCell.width - m_szHead.height) / 2;
477   m_rtHeadText = CFX_RectF(m_rtClient.left + fHeadHMargin,
478                            m_rtClient.top + MONTHCAL_HEADER_BTN_VMARGIN +
479                                MONTHCAL_VMARGIN + fHeadVMargin,
480                            m_szHead);
481 }
482 
CalcTodaySize()483 void CFWL_MonthCalendar::CalcTodaySize() {
484   m_rtTodayFlag = CFX_RectF(
485       m_rtClient.left + MONTHCAL_HEADER_BTN_HMARGIN + MONTHCAL_HMARGIN,
486       m_rtDates.bottom() + MONTHCAL_HEADER_BTN_VMARGIN + MONTHCAL_VMARGIN,
487       m_szCell.width, m_szToday.height);
488   m_rtToday = CFX_RectF(
489       m_rtClient.left + MONTHCAL_HEADER_BTN_HMARGIN + m_szCell.width +
490           MONTHCAL_HMARGIN * 2,
491       m_rtDates.bottom() + MONTHCAL_HEADER_BTN_VMARGIN + MONTHCAL_VMARGIN,
492       m_szToday);
493 }
494 
Layout()495 void CFWL_MonthCalendar::Layout() {
496   m_rtClient = GetClientRect();
497 
498   m_rtHead = CFX_RectF(
499       m_rtClient.left + MONTHCAL_HEADER_BTN_HMARGIN, m_rtClient.top,
500       m_rtClient.width - MONTHCAL_HEADER_BTN_HMARGIN * 2,
501       m_szCell.width + (MONTHCAL_HEADER_BTN_VMARGIN + MONTHCAL_VMARGIN) * 2);
502   m_rtWeek = CFX_RectF(m_rtClient.left + MONTHCAL_HEADER_BTN_HMARGIN,
503                        m_rtHead.bottom(),
504                        m_rtClient.width - MONTHCAL_HEADER_BTN_HMARGIN * 2,
505                        m_szCell.height + MONTHCAL_VMARGIN * 2);
506   m_rtLBtn = CFX_RectF(m_rtClient.left + MONTHCAL_HEADER_BTN_HMARGIN,
507                        m_rtClient.top + MONTHCAL_HEADER_BTN_VMARGIN,
508                        m_szCell.width, m_szCell.width);
509   m_rtRBtn = CFX_RectF(m_rtClient.left + m_rtClient.width -
510                            MONTHCAL_HEADER_BTN_HMARGIN - m_szCell.width,
511                        m_rtClient.top + MONTHCAL_HEADER_BTN_VMARGIN,
512                        m_szCell.width, m_szCell.width);
513   m_rtHSep = CFX_RectF(
514       m_rtClient.left + MONTHCAL_HEADER_BTN_HMARGIN + MONTHCAL_HMARGIN,
515       m_rtWeek.bottom() - MONTHCAL_VMARGIN,
516       m_rtClient.width - (MONTHCAL_HEADER_BTN_HMARGIN + MONTHCAL_HMARGIN) * 2,
517       MONTHCAL_HSEP_HEIGHT);
518   m_rtDates = CFX_RectF(m_rtClient.left + MONTHCAL_HEADER_BTN_HMARGIN,
519                         m_rtWeek.bottom(),
520                         m_rtClient.width - MONTHCAL_HEADER_BTN_HMARGIN * 2,
521                         m_szCell.height * (MONTHCAL_ROWS - 3) +
522                             MONTHCAL_VMARGIN * (MONTHCAL_ROWS - 3) * 2);
523 
524   CalDateItem();
525 }
526 
CalDateItem()527 void CFWL_MonthCalendar::CalDateItem() {
528   bool bNewWeek = false;
529   int32_t iWeekOfMonth = 0;
530   FX_FLOAT fLeft = m_rtDates.left;
531   FX_FLOAT fTop = m_rtDates.top;
532   for (const auto& pDateInfo : m_arrDates) {
533     if (bNewWeek) {
534       iWeekOfMonth++;
535       bNewWeek = false;
536     }
537     pDateInfo->rect = CFX_RectF(
538         fLeft +
539             pDateInfo->iDayOfWeek * (m_szCell.width + (MONTHCAL_HMARGIN * 2)),
540         fTop + iWeekOfMonth * (m_szCell.height + (MONTHCAL_VMARGIN * 2)),
541         m_szCell.width + (MONTHCAL_HMARGIN * 2),
542         m_szCell.height + (MONTHCAL_VMARGIN * 2));
543     if (pDateInfo->iDayOfWeek >= 6)
544       bNewWeek = true;
545   }
546 }
547 
GetCapValue()548 void CFWL_MonthCalendar::GetCapValue() {
549   if (!m_pProperties->m_pThemeProvider)
550     m_pProperties->m_pThemeProvider = GetAvailableTheme();
551 }
552 
InitDate()553 void CFWL_MonthCalendar::InitDate() {
554   // TODO(dsinclair): These should pull the real today values instead of
555   // pretending it's 2011-01-01.
556   m_iYear = 2011;
557   m_iMonth = 1;
558   m_iDay = 1;
559   m_iCurYear = m_iYear;
560   m_iCurMonth = m_iMonth;
561 
562   m_wsToday = GetTodayText(m_iYear, m_iMonth, m_iDay);
563   m_wsHead = GetHeadText(m_iCurYear, m_iCurMonth);
564   m_dtMin = DATE(1500, 12, 1);
565   m_dtMax = DATE(2200, 1, 1);
566 }
567 
ClearDateItem()568 void CFWL_MonthCalendar::ClearDateItem() {
569   m_arrDates.clear();
570 }
571 
ResetDateItem()572 void CFWL_MonthCalendar::ResetDateItem() {
573   m_pDateTime->Set(m_iCurYear, m_iCurMonth, 1);
574   int32_t iDays = FX_DaysInMonth(m_iCurYear, m_iCurMonth);
575   int32_t iDayOfWeek = m_pDateTime->GetDayOfWeek();
576   for (int32_t i = 0; i < iDays; i++) {
577     if (iDayOfWeek >= 7)
578       iDayOfWeek = 0;
579 
580     CFX_WideString wsDay;
581     wsDay.Format(L"%d", i + 1);
582     uint32_t dwStates = 0;
583     if (m_iYear == m_iCurYear && m_iMonth == m_iCurMonth && m_iDay == (i + 1))
584       dwStates |= FWL_ITEMSTATE_MCD_Flag;
585     if (pdfium::ContainsValue(m_arrSelDays, i + 1))
586       dwStates |= FWL_ITEMSTATE_MCD_Selected;
587 
588     CFX_RectF rtDate;
589     m_arrDates.push_back(pdfium::MakeUnique<DATEINFO>(i + 1, iDayOfWeek,
590                                                       dwStates, rtDate, wsDay));
591     iDayOfWeek++;
592   }
593 }
594 
NextMonth()595 void CFWL_MonthCalendar::NextMonth() {
596   int32_t iYear = m_iCurYear;
597   int32_t iMonth = m_iCurMonth;
598   if (iMonth >= 12) {
599     iMonth = 1;
600     iYear++;
601   } else {
602     iMonth++;
603   }
604   DATE dt(m_iCurYear, m_iCurMonth, 1);
605   if (!(dt < m_dtMax))
606     return;
607 
608   m_iCurYear = iYear, m_iCurMonth = iMonth;
609   ChangeToMonth(m_iCurYear, m_iCurMonth);
610 }
611 
PrevMonth()612 void CFWL_MonthCalendar::PrevMonth() {
613   int32_t iYear = m_iCurYear;
614   int32_t iMonth = m_iCurMonth;
615   if (iMonth <= 1) {
616     iMonth = 12;
617     iYear--;
618   } else {
619     iMonth--;
620   }
621 
622   DATE dt(m_iCurYear, m_iCurMonth, 1);
623   if (!(dt > m_dtMin))
624     return;
625 
626   m_iCurYear = iYear, m_iCurMonth = iMonth;
627   ChangeToMonth(m_iCurYear, m_iCurMonth);
628 }
629 
ChangeToMonth(int32_t iYear,int32_t iMonth)630 void CFWL_MonthCalendar::ChangeToMonth(int32_t iYear, int32_t iMonth) {
631   m_iCurYear = iYear;
632   m_iCurMonth = iMonth;
633   m_iHovered = -1;
634 
635   ClearDateItem();
636   ResetDateItem();
637   CalDateItem();
638   m_wsHead = GetHeadText(m_iCurYear, m_iCurMonth);
639 }
640 
RemoveSelDay()641 void CFWL_MonthCalendar::RemoveSelDay() {
642   int32_t iDatesCount = pdfium::CollectionSize<int32_t>(m_arrDates);
643   for (int32_t iSelDay : m_arrSelDays) {
644     if (iSelDay <= iDatesCount)
645       m_arrDates[iSelDay - 1]->dwStates &= ~FWL_ITEMSTATE_MCD_Selected;
646   }
647   m_arrSelDays.clear();
648 }
649 
AddSelDay(int32_t iDay)650 void CFWL_MonthCalendar::AddSelDay(int32_t iDay) {
651   ASSERT(iDay > 0);
652   if (!pdfium::ContainsValue(m_arrSelDays, iDay))
653     return;
654 
655   RemoveSelDay();
656   if (iDay <= pdfium::CollectionSize<int32_t>(m_arrDates))
657     m_arrDates[iDay - 1]->dwStates |= FWL_ITEMSTATE_MCD_Selected;
658 
659   m_arrSelDays.push_back(iDay);
660 }
661 
JumpToToday()662 void CFWL_MonthCalendar::JumpToToday() {
663   if (m_iYear != m_iCurYear || m_iMonth != m_iCurMonth) {
664     m_iCurYear = m_iYear;
665     m_iCurMonth = m_iMonth;
666     ChangeToMonth(m_iYear, m_iMonth);
667     AddSelDay(m_iDay);
668     return;
669   }
670 
671   if (!pdfium::ContainsValue(m_arrSelDays, m_iDay))
672     AddSelDay(m_iDay);
673 }
674 
GetHeadText(int32_t iYear,int32_t iMonth)675 CFX_WideString CFWL_MonthCalendar::GetHeadText(int32_t iYear, int32_t iMonth) {
676   ASSERT(iMonth > 0 && iMonth < 13);
677   static const FX_WCHAR* const pMonth[] = {
678       L"January",   L"February", L"March",    L"April",
679       L"May",       L"June",     L"July",     L"August",
680       L"September", L"October",  L"November", L"December"};
681   CFX_WideString wsHead;
682   wsHead.Format(L"%s, %d", pMonth[iMonth - 1], iYear);
683   return wsHead;
684 }
685 
GetTodayText(int32_t iYear,int32_t iMonth,int32_t iDay)686 CFX_WideString CFWL_MonthCalendar::GetTodayText(int32_t iYear,
687                                                 int32_t iMonth,
688                                                 int32_t iDay) {
689   CFX_WideString wsToday;
690   wsToday.Format(L", %d/%d/%d", iDay, iMonth, iYear);
691   return wsToday;
692 }
693 
GetDayAtPoint(const CFX_PointF & point) const694 int32_t CFWL_MonthCalendar::GetDayAtPoint(const CFX_PointF& point) const {
695   int i = 1;  // one-based day values.
696   for (const auto& pDateInfo : m_arrDates) {
697     if (pDateInfo->rect.Contains(point))
698       return i;
699     ++i;
700   }
701   return -1;
702 }
703 
GetDayRect(int32_t iDay)704 CFX_RectF CFWL_MonthCalendar::GetDayRect(int32_t iDay) {
705   if (iDay <= 0 || iDay > pdfium::CollectionSize<int32_t>(m_arrDates))
706     return CFX_RectF();
707 
708   DATEINFO* pDateInfo = m_arrDates[iDay - 1].get();
709   return pDateInfo ? pDateInfo->rect : CFX_RectF();
710 }
711 
OnProcessMessage(CFWL_Message * pMessage)712 void CFWL_MonthCalendar::OnProcessMessage(CFWL_Message* pMessage) {
713   if (!pMessage)
714     return;
715 
716   switch (pMessage->GetType()) {
717     case CFWL_Message::Type::SetFocus:
718     case CFWL_Message::Type::KillFocus:
719       GetOuter()->GetDelegate()->OnProcessMessage(pMessage);
720       break;
721     case CFWL_Message::Type::Key:
722       break;
723     case CFWL_Message::Type::Mouse: {
724       CFWL_MessageMouse* pMouse = static_cast<CFWL_MessageMouse*>(pMessage);
725       switch (pMouse->m_dwCmd) {
726         case FWL_MouseCommand::LeftButtonDown:
727           OnLButtonDown(pMouse);
728           break;
729         case FWL_MouseCommand::LeftButtonUp:
730           OnLButtonUp(pMouse);
731           break;
732         case FWL_MouseCommand::Move:
733           OnMouseMove(pMouse);
734           break;
735         case FWL_MouseCommand::Leave:
736           OnMouseLeave(pMouse);
737           break;
738         default:
739           break;
740       }
741       break;
742     }
743     default:
744       break;
745   }
746   CFWL_Widget::OnProcessMessage(pMessage);
747 }
748 
OnDrawWidget(CFX_Graphics * pGraphics,const CFX_Matrix * pMatrix)749 void CFWL_MonthCalendar::OnDrawWidget(CFX_Graphics* pGraphics,
750                                       const CFX_Matrix* pMatrix) {
751   DrawWidget(pGraphics, pMatrix);
752 }
753 
OnLButtonDown(CFWL_MessageMouse * pMsg)754 void CFWL_MonthCalendar::OnLButtonDown(CFWL_MessageMouse* pMsg) {
755   if (m_rtLBtn.Contains(pMsg->m_pos)) {
756     m_iLBtnPartStates = CFWL_PartState_Pressed;
757     PrevMonth();
758     RepaintRect(m_rtClient);
759   } else if (m_rtRBtn.Contains(pMsg->m_pos)) {
760     m_iRBtnPartStates |= CFWL_PartState_Pressed;
761     NextMonth();
762     RepaintRect(m_rtClient);
763   } else if (m_rtToday.Contains(pMsg->m_pos)) {
764     JumpToToday();
765     RepaintRect(m_rtClient);
766   } else {
767     CFWL_DateTimePicker* pIPicker = static_cast<CFWL_DateTimePicker*>(m_pOuter);
768     if (pIPicker->IsMonthCalendarVisible())
769       m_bFlag = true;
770   }
771 }
772 
OnLButtonUp(CFWL_MessageMouse * pMsg)773 void CFWL_MonthCalendar::OnLButtonUp(CFWL_MessageMouse* pMsg) {
774   if (m_pWidgetMgr->IsFormDisabled())
775     return DisForm_OnLButtonUp(pMsg);
776 
777   if (m_rtLBtn.Contains(pMsg->m_pos)) {
778     m_iLBtnPartStates = 0;
779     RepaintRect(m_rtLBtn);
780     return;
781   }
782   if (m_rtRBtn.Contains(pMsg->m_pos)) {
783     m_iRBtnPartStates = 0;
784     RepaintRect(m_rtRBtn);
785     return;
786   }
787   if (m_rtToday.Contains(pMsg->m_pos))
788     return;
789 
790   int32_t iOldSel = 0;
791   if (!m_arrSelDays.empty())
792     iOldSel = m_arrSelDays[0];
793 
794   int32_t iCurSel = GetDayAtPoint(pMsg->m_pos);
795   CFWL_DateTimePicker* pIPicker = static_cast<CFWL_DateTimePicker*>(m_pOuter);
796   if (iCurSel > 0) {
797     DATEINFO* lpDatesInfo = m_arrDates[iCurSel - 1].get();
798     CFX_RectF rtInvalidate(lpDatesInfo->rect);
799     if (iOldSel > 0 && iOldSel <= pdfium::CollectionSize<int32_t>(m_arrDates)) {
800       lpDatesInfo = m_arrDates[iOldSel - 1].get();
801       rtInvalidate.Union(lpDatesInfo->rect);
802     }
803     AddSelDay(iCurSel);
804     if (!m_pOuter)
805       return;
806 
807     pIPicker->ProcessSelChanged(m_iCurYear, m_iCurMonth, iCurSel);
808     pIPicker->ShowMonthCalendar(false);
809   } else if (m_bFlag &&
810              (!CFX_RectF(0, 0, pIPicker->GetFormProxy()->GetWidgetRect().Size())
811                    .Contains(pMsg->m_pos))) {
812     pIPicker->ShowMonthCalendar(false);
813   }
814   m_bFlag = false;
815 }
816 
DisForm_OnLButtonUp(CFWL_MessageMouse * pMsg)817 void CFWL_MonthCalendar::DisForm_OnLButtonUp(CFWL_MessageMouse* pMsg) {
818   if (m_rtLBtn.Contains(pMsg->m_pos)) {
819     m_iLBtnPartStates = 0;
820     RepaintRect(m_rtLBtn);
821     return;
822   }
823   if (m_rtRBtn.Contains(pMsg->m_pos)) {
824     m_iRBtnPartStates = 0;
825     RepaintRect(m_rtRBtn);
826     return;
827   }
828   if (m_rtToday.Contains(pMsg->m_pos))
829     return;
830 
831   int32_t iOldSel = 0;
832   if (!m_arrSelDays.empty())
833     iOldSel = m_arrSelDays[0];
834 
835   int32_t iCurSel = GetDayAtPoint(pMsg->m_pos);
836   if (iCurSel > 0) {
837     DATEINFO* lpDatesInfo = m_arrDates[iCurSel - 1].get();
838     CFX_RectF rtInvalidate(lpDatesInfo->rect);
839     if (iOldSel > 0 && iOldSel <= pdfium::CollectionSize<int32_t>(m_arrDates)) {
840       lpDatesInfo = m_arrDates[iOldSel - 1].get();
841       rtInvalidate.Union(lpDatesInfo->rect);
842     }
843     AddSelDay(iCurSel);
844     CFWL_DateTimePicker* pDateTime =
845         static_cast<CFWL_DateTimePicker*>(m_pOuter);
846     pDateTime->ProcessSelChanged(m_iCurYear, m_iCurMonth, iCurSel);
847     pDateTime->ShowMonthCalendar(false);
848   }
849 }
850 
OnMouseMove(CFWL_MessageMouse * pMsg)851 void CFWL_MonthCalendar::OnMouseMove(CFWL_MessageMouse* pMsg) {
852   bool bRepaint = false;
853   CFX_RectF rtInvalidate;
854   if (m_rtDates.Contains(pMsg->m_pos)) {
855     int32_t iHover = GetDayAtPoint(pMsg->m_pos);
856     bRepaint = m_iHovered != iHover;
857     if (bRepaint) {
858       if (m_iHovered > 0)
859         rtInvalidate = GetDayRect(m_iHovered);
860       if (iHover > 0) {
861         CFX_RectF rtDay = GetDayRect(iHover);
862         if (rtInvalidate.IsEmpty())
863           rtInvalidate = rtDay;
864         else
865           rtInvalidate.Union(rtDay);
866       }
867     }
868     m_iHovered = iHover;
869   } else {
870     bRepaint = m_iHovered > 0;
871     if (bRepaint)
872       rtInvalidate = GetDayRect(m_iHovered);
873 
874     m_iHovered = -1;
875   }
876   if (bRepaint && !rtInvalidate.IsEmpty())
877     RepaintRect(rtInvalidate);
878 }
879 
OnMouseLeave(CFWL_MessageMouse * pMsg)880 void CFWL_MonthCalendar::OnMouseLeave(CFWL_MessageMouse* pMsg) {
881   if (m_iHovered <= 0)
882     return;
883 
884   CFX_RectF rtInvalidate = GetDayRect(m_iHovered);
885   m_iHovered = -1;
886   if (!rtInvalidate.IsEmpty())
887     RepaintRect(rtInvalidate);
888 }
889 
DATEINFO(int32_t day,int32_t dayofweek,uint32_t dwSt,CFX_RectF rc,CFX_WideString & wsday)890 CFWL_MonthCalendar::DATEINFO::DATEINFO(int32_t day,
891                                        int32_t dayofweek,
892                                        uint32_t dwSt,
893                                        CFX_RectF rc,
894                                        CFX_WideString& wsday)
895     : iDay(day),
896       iDayOfWeek(dayofweek),
897       dwStates(dwSt),
898       rect(rc),
899       wsDay(wsday) {}
900 
~DATEINFO()901 CFWL_MonthCalendar::DATEINFO::~DATEINFO() {}
902