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