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/check.h"
14 #include "third_party/base/notreached.h"
15 #include "third_party/base/stl_util.h"
16 #include "xfa/fde/cfde_textout.h"
17 #include "xfa/fwl/cfwl_datetimepicker.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_HMARGIN 3
26 #define MONTHCAL_VMARGIN 2
27 #define MONTHCAL_ROWS 9
28 #define MONTHCAL_COLUMNS 7
29 #define MONTHCAL_HEADER_BTN_VMARGIN 7
30 #define MONTHCAL_HEADER_BTN_HMARGIN 5
31
32 namespace {
33
GetAbbreviatedDayOfWeek(int day)34 WideString GetAbbreviatedDayOfWeek(int day) {
35 switch (day) {
36 case 0:
37 return L"Sun";
38 case 1:
39 return L"Mon";
40 case 2:
41 return L"Tue";
42 case 3:
43 return L"Wed";
44 case 4:
45 return L"Thu";
46 case 5:
47 return L"Fri";
48 case 6:
49 return L"Sat";
50 default:
51 NOTREACHED();
52 return L"";
53 }
54 }
55
GetMonth(int month)56 WideString GetMonth(int month) {
57 switch (month) {
58 case 0:
59 return L"January";
60 case 1:
61 return L"February";
62 case 2:
63 return L"March";
64 case 3:
65 return L"April";
66 case 4:
67 return L"May";
68 case 5:
69 return L"June";
70 case 6:
71 return L"July";
72 case 7:
73 return L"August";
74 case 8:
75 return L"September";
76 case 9:
77 return L"October";
78 case 10:
79 return L"November";
80 case 11:
81 return L"December";
82 default:
83 NOTREACHED();
84 return L"";
85 }
86 }
87
88 } // namespace
89
CFWL_MonthCalendar(CFWL_App * app,const Properties & properties,CFWL_Widget * pOuter)90 CFWL_MonthCalendar::CFWL_MonthCalendar(CFWL_App* app,
91 const Properties& properties,
92 CFWL_Widget* pOuter)
93 : CFWL_Widget(app, properties, pOuter) {}
94
95 CFWL_MonthCalendar::~CFWL_MonthCalendar() = default;
96
GetClassID() const97 FWL_Type CFWL_MonthCalendar::GetClassID() const {
98 return FWL_Type::MonthCalendar;
99 }
100
GetAutosizedWidgetRect()101 CFX_RectF CFWL_MonthCalendar::GetAutosizedWidgetRect() {
102 CFX_SizeF fs = CalcSize();
103 CFX_RectF rect(0, 0, fs.width, fs.height);
104 InflateWidgetRect(rect);
105 return rect;
106 }
107
Update()108 void CFWL_MonthCalendar::Update() {
109 if (IsLocked())
110 return;
111
112 if (!m_bInitialized) {
113 InitDate();
114 m_bInitialized = true;
115 }
116 ClearDateItem();
117 ResetDateItem();
118 Layout();
119 }
120
DrawWidget(CFGAS_GEGraphics * pGraphics,const CFX_Matrix & matrix)121 void CFWL_MonthCalendar::DrawWidget(CFGAS_GEGraphics* pGraphics,
122 const CFX_Matrix& matrix) {
123 if (!pGraphics)
124 return;
125
126 if (HasBorder())
127 DrawBorder(pGraphics, CFWL_Part::Border, matrix);
128
129 DrawBackground(pGraphics, &matrix);
130 DrawHeadBK(pGraphics, &matrix);
131 DrawLButton(pGraphics, &matrix);
132 DrawRButton(pGraphics, &matrix);
133 DrawSeparator(pGraphics, &matrix);
134 DrawDatesInBK(pGraphics, &matrix);
135 DrawDatesInCircle(pGraphics, &matrix);
136 DrawCaption(pGraphics, &matrix);
137 DrawWeek(pGraphics, &matrix);
138 DrawDatesIn(pGraphics, &matrix);
139 DrawDatesOut(pGraphics, &matrix);
140 DrawToday(pGraphics, &matrix);
141 }
142
SetSelect(int32_t iYear,int32_t iMonth,int32_t iDay)143 void CFWL_MonthCalendar::SetSelect(int32_t iYear,
144 int32_t iMonth,
145 int32_t iDay) {
146 ChangeToMonth(iYear, iMonth);
147 AddSelDay(iDay);
148 }
149
DrawBackground(CFGAS_GEGraphics * pGraphics,const CFX_Matrix * pMatrix)150 void CFWL_MonthCalendar::DrawBackground(CFGAS_GEGraphics* pGraphics,
151 const CFX_Matrix* pMatrix) {
152 CFWL_ThemeBackground params;
153 params.m_pWidget = this;
154 params.m_iPart = CFWL_Part::Background;
155 params.m_pGraphics = pGraphics;
156 params.m_dwStates = CFWL_PartState_Normal;
157 params.m_PartRect = m_ClientRect;
158 if (pMatrix)
159 params.m_matrix.Concat(*pMatrix);
160 GetThemeProvider()->DrawBackground(params);
161 }
162
DrawHeadBK(CFGAS_GEGraphics * pGraphics,const CFX_Matrix * pMatrix)163 void CFWL_MonthCalendar::DrawHeadBK(CFGAS_GEGraphics* pGraphics,
164 const CFX_Matrix* pMatrix) {
165 CFWL_ThemeBackground params;
166 params.m_pWidget = this;
167 params.m_iPart = CFWL_Part::Header;
168 params.m_pGraphics = pGraphics;
169 params.m_dwStates = CFWL_PartState_Normal;
170 params.m_PartRect = m_HeadRect;
171 if (pMatrix)
172 params.m_matrix.Concat(*pMatrix);
173 GetThemeProvider()->DrawBackground(params);
174 }
175
DrawLButton(CFGAS_GEGraphics * pGraphics,const CFX_Matrix * pMatrix)176 void CFWL_MonthCalendar::DrawLButton(CFGAS_GEGraphics* pGraphics,
177 const CFX_Matrix* pMatrix) {
178 CFWL_ThemeBackground params;
179 params.m_pWidget = this;
180 params.m_iPart = CFWL_Part::LBtn;
181 params.m_pGraphics = pGraphics;
182 params.m_dwStates = m_iLBtnPartStates;
183 params.m_PartRect = m_LBtnRect;
184 if (pMatrix)
185 params.m_matrix.Concat(*pMatrix);
186 GetThemeProvider()->DrawBackground(params);
187 }
188
DrawRButton(CFGAS_GEGraphics * pGraphics,const CFX_Matrix * pMatrix)189 void CFWL_MonthCalendar::DrawRButton(CFGAS_GEGraphics* pGraphics,
190 const CFX_Matrix* pMatrix) {
191 CFWL_ThemeBackground params;
192 params.m_pWidget = this;
193 params.m_iPart = CFWL_Part::RBtn;
194 params.m_pGraphics = pGraphics;
195 params.m_dwStates = m_iRBtnPartStates;
196 params.m_PartRect = m_RBtnRect;
197 if (pMatrix)
198 params.m_matrix.Concat(*pMatrix);
199 GetThemeProvider()->DrawBackground(params);
200 }
201
DrawCaption(CFGAS_GEGraphics * pGraphics,const CFX_Matrix * pMatrix)202 void CFWL_MonthCalendar::DrawCaption(CFGAS_GEGraphics* pGraphics,
203 const CFX_Matrix* pMatrix) {
204 CFWL_ThemeText textParam;
205 textParam.m_pWidget = this;
206 textParam.m_iPart = CFWL_Part::Caption;
207 textParam.m_dwStates = CFWL_PartState_Normal;
208 textParam.m_pGraphics = pGraphics;
209 textParam.m_wsText = GetHeadText(m_iCurYear, m_iCurMonth);
210 m_HeadSize = CalcTextSize(textParam.m_wsText, false);
211 CalcHeadSize();
212 textParam.m_PartRect = m_HeadTextRect;
213 textParam.m_dwTTOStyles.single_line_ = true;
214 textParam.m_iTTOAlign = FDE_TextAlignment::kCenter;
215 if (pMatrix)
216 textParam.m_matrix.Concat(*pMatrix);
217 GetThemeProvider()->DrawText(textParam);
218 }
219
DrawSeparator(CFGAS_GEGraphics * pGraphics,const CFX_Matrix * pMatrix)220 void CFWL_MonthCalendar::DrawSeparator(CFGAS_GEGraphics* pGraphics,
221 const CFX_Matrix* pMatrix) {
222 CFWL_ThemeBackground params;
223 params.m_pWidget = this;
224 params.m_iPart = CFWL_Part::HSeparator;
225 params.m_pGraphics = pGraphics;
226 params.m_dwStates = CFWL_PartState_Normal;
227 params.m_PartRect = m_HSepRect;
228 if (pMatrix)
229 params.m_matrix.Concat(*pMatrix);
230 GetThemeProvider()->DrawBackground(params);
231 }
232
DrawDatesInBK(CFGAS_GEGraphics * pGraphics,const CFX_Matrix * pMatrix)233 void CFWL_MonthCalendar::DrawDatesInBK(CFGAS_GEGraphics* pGraphics,
234 const CFX_Matrix* pMatrix) {
235 CFWL_ThemeBackground params;
236 params.m_pWidget = this;
237 params.m_iPart = CFWL_Part::DateInBK;
238 params.m_pGraphics = pGraphics;
239 if (pMatrix)
240 params.m_matrix.Concat(*pMatrix);
241
242 IFWL_ThemeProvider* pTheme = GetThemeProvider();
243 int32_t iCount = pdfium::CollectionSize<int32_t>(m_DateArray);
244 for (int32_t j = 0; j < iCount; j++) {
245 DATEINFO* pDataInfo = m_DateArray[j].get();
246 if (pDataInfo->dwStates & FWL_ITEMSTATE_MCD_Selected) {
247 params.m_dwStates |= CFWL_PartState_Selected;
248 if (pDataInfo->dwStates & FWL_ITEMSTATE_MCD_Flag) {
249 params.m_dwStates |= CFWL_PartState_Flagged;
250 }
251 } else if (j == m_iHovered - 1) {
252 params.m_dwStates |= CFWL_PartState_Hovered;
253 } else if (pDataInfo->dwStates & FWL_ITEMSTATE_MCD_Flag) {
254 params.m_dwStates = CFWL_PartState_Flagged;
255 pTheme->DrawBackground(params);
256 }
257 params.m_PartRect = pDataInfo->rect;
258 pTheme->DrawBackground(params);
259 params.m_dwStates = 0;
260 }
261 }
262
DrawWeek(CFGAS_GEGraphics * pGraphics,const CFX_Matrix * pMatrix)263 void CFWL_MonthCalendar::DrawWeek(CFGAS_GEGraphics* pGraphics,
264 const CFX_Matrix* pMatrix) {
265 CFWL_ThemeText params;
266 params.m_pWidget = this;
267 params.m_iPart = CFWL_Part::Week;
268 params.m_pGraphics = pGraphics;
269 params.m_dwStates = CFWL_PartState_Normal;
270 params.m_iTTOAlign = FDE_TextAlignment::kCenter;
271 params.m_dwTTOStyles.single_line_ = true;
272
273 if (pMatrix)
274 params.m_matrix.Concat(*pMatrix);
275
276 IFWL_ThemeProvider* pTheme = GetThemeProvider();
277 CFX_RectF rtDayOfWeek;
278 for (int32_t i = 0; i < 7; ++i) {
279 rtDayOfWeek = CFX_RectF(
280 m_WeekRect.left + i * (m_CellSize.width + MONTHCAL_HMARGIN * 2),
281 m_WeekRect.top, m_CellSize);
282
283 params.m_PartRect = rtDayOfWeek;
284 params.m_wsText = GetAbbreviatedDayOfWeek(i);
285 pTheme->DrawText(params);
286 }
287 }
288
DrawToday(CFGAS_GEGraphics * pGraphics,const CFX_Matrix * pMatrix)289 void CFWL_MonthCalendar::DrawToday(CFGAS_GEGraphics* pGraphics,
290 const CFX_Matrix* pMatrix) {
291 CFWL_ThemeText params;
292 params.m_pWidget = this;
293 params.m_iPart = CFWL_Part::Today;
294 params.m_pGraphics = pGraphics;
295 params.m_dwStates = CFWL_PartState_Normal;
296 params.m_iTTOAlign = FDE_TextAlignment::kCenterLeft;
297 params.m_wsText = GetTodayText(m_iYear, m_iMonth, m_iDay);
298 m_TodaySize = CalcTextSize(params.m_wsText, false);
299 CalcTodaySize();
300 params.m_PartRect = m_TodayRect;
301 params.m_dwTTOStyles.single_line_ = true;
302 if (pMatrix)
303 params.m_matrix.Concat(*pMatrix);
304 GetThemeProvider()->DrawText(params);
305 }
306
DrawDatesIn(CFGAS_GEGraphics * pGraphics,const CFX_Matrix * pMatrix)307 void CFWL_MonthCalendar::DrawDatesIn(CFGAS_GEGraphics* pGraphics,
308 const CFX_Matrix* pMatrix) {
309 CFWL_ThemeText params;
310 params.m_pWidget = this;
311 params.m_iPart = CFWL_Part::DatesIn;
312 params.m_pGraphics = pGraphics;
313 params.m_dwStates = CFWL_PartState_Normal;
314 params.m_iTTOAlign = FDE_TextAlignment::kCenter;
315 if (pMatrix)
316 params.m_matrix.Concat(*pMatrix);
317
318 IFWL_ThemeProvider* pTheme = GetThemeProvider();
319 int32_t iCount = pdfium::CollectionSize<int32_t>(m_DateArray);
320 for (int32_t j = 0; j < iCount; j++) {
321 DATEINFO* pDataInfo = m_DateArray[j].get();
322 params.m_wsText = pDataInfo->wsDay;
323 params.m_PartRect = pDataInfo->rect;
324 params.m_dwStates = pDataInfo->dwStates;
325 if (j + 1 == m_iHovered)
326 params.m_dwStates |= CFWL_PartState_Hovered;
327
328 params.m_dwTTOStyles.single_line_ = true;
329 pTheme->DrawText(params);
330 }
331 }
332
DrawDatesOut(CFGAS_GEGraphics * pGraphics,const CFX_Matrix * pMatrix)333 void CFWL_MonthCalendar::DrawDatesOut(CFGAS_GEGraphics* pGraphics,
334 const CFX_Matrix* pMatrix) {
335 CFWL_ThemeText params;
336 params.m_pWidget = this;
337 params.m_iPart = CFWL_Part::DatesOut;
338 params.m_pGraphics = pGraphics;
339 params.m_dwStates = CFWL_PartState_Normal;
340 params.m_iTTOAlign = FDE_TextAlignment::kCenter;
341 if (pMatrix)
342 params.m_matrix.Concat(*pMatrix);
343 GetThemeProvider()->DrawText(params);
344 }
345
DrawDatesInCircle(CFGAS_GEGraphics * pGraphics,const CFX_Matrix * pMatrix)346 void CFWL_MonthCalendar::DrawDatesInCircle(CFGAS_GEGraphics* pGraphics,
347 const CFX_Matrix* pMatrix) {
348 if (m_iMonth != m_iCurMonth || m_iYear != m_iCurYear)
349 return;
350
351 if (m_iDay < 1 || m_iDay > pdfium::CollectionSize<int32_t>(m_DateArray))
352 return;
353
354 DATEINFO* pDate = m_DateArray[m_iDay - 1].get();
355 if (!pDate)
356 return;
357
358 CFWL_ThemeBackground params;
359 params.m_pWidget = this;
360 params.m_iPart = CFWL_Part::DateInCircle;
361 params.m_pGraphics = pGraphics;
362 params.m_PartRect = pDate->rect;
363 params.m_dwStates = CFWL_PartState_Normal;
364 if (pMatrix)
365 params.m_matrix.Concat(*pMatrix);
366 GetThemeProvider()->DrawBackground(params);
367 }
368
CalcSize()369 CFX_SizeF CFWL_MonthCalendar::CalcSize() {
370 float fMaxWeekW = 0.0f;
371 float fMaxWeekH = 0.0f;
372 for (int i = 0; i < 7; ++i) {
373 CFX_SizeF sz = CalcTextSize(GetAbbreviatedDayOfWeek(i), false);
374 fMaxWeekW = (fMaxWeekW >= sz.width) ? fMaxWeekW : sz.width;
375 fMaxWeekH = (fMaxWeekH >= sz.height) ? fMaxWeekH : sz.height;
376 }
377 float fDayMaxW = 0.0f;
378 float fDayMaxH = 0.0f;
379 for (int day = 10; day <= 31; day++) {
380 CFX_SizeF sz = CalcTextSize(WideString::Format(L"%d", day), false);
381 fDayMaxW = (fDayMaxW >= sz.width) ? fDayMaxW : sz.width;
382 fDayMaxH = (fDayMaxH >= sz.height) ? fDayMaxH : sz.height;
383 }
384 m_CellSize.width =
385 static_cast<int>(0.5 + (fMaxWeekW >= fDayMaxW ? fMaxWeekW : fDayMaxW));
386 m_CellSize.height = fMaxWeekH >= fDayMaxH ? fMaxWeekH : fDayMaxH;
387
388 CFX_SizeF fs;
389 fs.width = m_CellSize.width * MONTHCAL_COLUMNS +
390 MONTHCAL_HMARGIN * MONTHCAL_COLUMNS * 2 +
391 MONTHCAL_HEADER_BTN_HMARGIN * 2;
392
393 float fMonthMaxW = 0.0f;
394 float fMonthMaxH = 0.0f;
395 for (int i = 0; i < 12; ++i) {
396 CFX_SizeF sz = CalcTextSize(GetMonth(i), false);
397 fMonthMaxW = (fMonthMaxW >= sz.width) ? fMonthMaxW : sz.width;
398 fMonthMaxH = (fMonthMaxH >= sz.height) ? fMonthMaxH : sz.height;
399 }
400
401 CFX_SizeF szYear = CalcTextSize(GetHeadText(m_iYear, m_iMonth), false);
402 fMonthMaxH = std::max(fMonthMaxH, szYear.height);
403 m_HeadSize = CFX_SizeF(fMonthMaxW + szYear.width, fMonthMaxH);
404 fMonthMaxW =
405 m_HeadSize.width + MONTHCAL_HEADER_BTN_HMARGIN * 2 + m_CellSize.width * 2;
406 fs.width = std::max(fs.width, fMonthMaxW);
407
408 m_wsToday = GetTodayText(m_iYear, m_iMonth, m_iDay);
409 m_TodaySize = CalcTextSize(m_wsToday, false);
410 m_TodaySize.height = (m_TodaySize.height >= m_CellSize.height)
411 ? m_TodaySize.height
412 : m_CellSize.height;
413 fs.height = m_CellSize.width + m_CellSize.height * (MONTHCAL_ROWS - 2) +
414 m_TodaySize.height + MONTHCAL_VMARGIN * MONTHCAL_ROWS * 2 +
415 MONTHCAL_HEADER_BTN_VMARGIN * 4;
416 return fs;
417 }
418
CalcHeadSize()419 void CFWL_MonthCalendar::CalcHeadSize() {
420 float fHeadHMargin = (m_ClientRect.width - m_HeadSize.width) / 2;
421 float fHeadVMargin = (m_CellSize.width - m_HeadSize.height) / 2;
422 m_HeadTextRect = CFX_RectF(m_ClientRect.left + fHeadHMargin,
423 m_ClientRect.top + MONTHCAL_HEADER_BTN_VMARGIN +
424 MONTHCAL_VMARGIN + fHeadVMargin,
425 m_HeadSize);
426 }
427
CalcTodaySize()428 void CFWL_MonthCalendar::CalcTodaySize() {
429 m_TodayFlagRect = CFX_RectF(
430 m_ClientRect.left + MONTHCAL_HEADER_BTN_HMARGIN + MONTHCAL_HMARGIN,
431 m_DatesRect.bottom() + MONTHCAL_HEADER_BTN_VMARGIN + MONTHCAL_VMARGIN,
432 m_CellSize.width, m_TodaySize.height);
433 m_TodayRect = CFX_RectF(
434 m_ClientRect.left + MONTHCAL_HEADER_BTN_HMARGIN + m_CellSize.width +
435 MONTHCAL_HMARGIN * 2,
436 m_DatesRect.bottom() + MONTHCAL_HEADER_BTN_VMARGIN + MONTHCAL_VMARGIN,
437 m_TodaySize);
438 }
439
Layout()440 void CFWL_MonthCalendar::Layout() {
441 m_ClientRect = GetClientRect();
442
443 m_HeadRect = CFX_RectF(
444 m_ClientRect.left + MONTHCAL_HEADER_BTN_HMARGIN, m_ClientRect.top,
445 m_ClientRect.width - MONTHCAL_HEADER_BTN_HMARGIN * 2,
446 m_CellSize.width + (MONTHCAL_HEADER_BTN_VMARGIN + MONTHCAL_VMARGIN) * 2);
447 m_WeekRect = CFX_RectF(m_ClientRect.left + MONTHCAL_HEADER_BTN_HMARGIN,
448 m_HeadRect.bottom(),
449 m_ClientRect.width - MONTHCAL_HEADER_BTN_HMARGIN * 2,
450 m_CellSize.height + MONTHCAL_VMARGIN * 2);
451 m_LBtnRect = CFX_RectF(m_ClientRect.left + MONTHCAL_HEADER_BTN_HMARGIN,
452 m_ClientRect.top + MONTHCAL_HEADER_BTN_VMARGIN,
453 m_CellSize.width, m_CellSize.width);
454 m_RBtnRect = CFX_RectF(m_ClientRect.left + m_ClientRect.width -
455 MONTHCAL_HEADER_BTN_HMARGIN - m_CellSize.width,
456 m_ClientRect.top + MONTHCAL_HEADER_BTN_VMARGIN,
457 m_CellSize.width, m_CellSize.width);
458 m_HSepRect = CFX_RectF(
459 m_ClientRect.left + MONTHCAL_HEADER_BTN_HMARGIN + MONTHCAL_HMARGIN,
460 m_WeekRect.bottom() - MONTHCAL_VMARGIN,
461 m_ClientRect.width - (MONTHCAL_HEADER_BTN_HMARGIN + MONTHCAL_HMARGIN) * 2,
462 MONTHCAL_HSEP_HEIGHT);
463 m_DatesRect = CFX_RectF(m_ClientRect.left + MONTHCAL_HEADER_BTN_HMARGIN,
464 m_WeekRect.bottom(),
465 m_ClientRect.width - MONTHCAL_HEADER_BTN_HMARGIN * 2,
466 m_CellSize.height * (MONTHCAL_ROWS - 3) +
467 MONTHCAL_VMARGIN * (MONTHCAL_ROWS - 3) * 2);
468
469 CalDateItem();
470 }
471
CalDateItem()472 void CFWL_MonthCalendar::CalDateItem() {
473 bool bNewWeek = false;
474 int32_t iWeekOfMonth = 0;
475 float fLeft = m_DatesRect.left;
476 float fTop = m_DatesRect.top;
477 for (const auto& pDateInfo : m_DateArray) {
478 if (bNewWeek) {
479 iWeekOfMonth++;
480 bNewWeek = false;
481 }
482 pDateInfo->rect = CFX_RectF(
483 fLeft +
484 pDateInfo->iDayOfWeek * (m_CellSize.width + (MONTHCAL_HMARGIN * 2)),
485 fTop + iWeekOfMonth * (m_CellSize.height + (MONTHCAL_VMARGIN * 2)),
486 m_CellSize.width + (MONTHCAL_HMARGIN * 2),
487 m_CellSize.height + (MONTHCAL_VMARGIN * 2));
488 if (pDateInfo->iDayOfWeek >= 6)
489 bNewWeek = true;
490 }
491 }
492
InitDate()493 void CFWL_MonthCalendar::InitDate() {
494 CFX_DateTime now = CFX_DateTime::Now();
495
496 m_iYear = now.GetYear();
497 m_iMonth = now.GetMonth();
498 m_iDay = now.GetDay();
499 m_iCurYear = m_iYear;
500 m_iCurMonth = m_iMonth;
501
502 m_wsToday = GetTodayText(m_iYear, m_iMonth, m_iDay);
503 m_wsHead = GetHeadText(m_iCurYear, m_iCurMonth);
504 m_dtMin = DATE(1500, 12, 1);
505 m_dtMax = DATE(2200, 1, 1);
506 }
507
ClearDateItem()508 void CFWL_MonthCalendar::ClearDateItem() {
509 m_DateArray.clear();
510 }
511
ResetDateItem()512 void CFWL_MonthCalendar::ResetDateItem() {
513 int32_t iDays = FX_DaysInMonth(m_iCurYear, m_iCurMonth);
514 int32_t iDayOfWeek =
515 CFX_DateTime(m_iCurYear, m_iCurMonth, 1, 0, 0, 0, 0).GetDayOfWeek();
516 for (int32_t i = 0; i < iDays; i++) {
517 if (iDayOfWeek >= 7)
518 iDayOfWeek = 0;
519
520 uint32_t dwStates = 0;
521 if (m_iYear == m_iCurYear && m_iMonth == m_iCurMonth && m_iDay == (i + 1))
522 dwStates |= FWL_ITEMSTATE_MCD_Flag;
523 if (pdfium::Contains(m_SelDayArray, i + 1))
524 dwStates |= FWL_ITEMSTATE_MCD_Selected;
525
526 CFX_RectF rtDate;
527 m_DateArray.push_back(std::make_unique<DATEINFO>(
528 i + 1, iDayOfWeek, dwStates, rtDate, WideString::Format(L"%d", i + 1)));
529 iDayOfWeek++;
530 }
531 }
532
NextMonth()533 void CFWL_MonthCalendar::NextMonth() {
534 int32_t iYear = m_iCurYear;
535 int32_t iMonth = m_iCurMonth;
536 if (iMonth >= 12) {
537 iMonth = 1;
538 iYear++;
539 } else {
540 iMonth++;
541 }
542 DATE dt(m_iCurYear, m_iCurMonth, 1);
543 if (!(dt < m_dtMax))
544 return;
545
546 m_iCurYear = iYear, m_iCurMonth = iMonth;
547 ChangeToMonth(m_iCurYear, m_iCurMonth);
548 }
549
PrevMonth()550 void CFWL_MonthCalendar::PrevMonth() {
551 int32_t iYear = m_iCurYear;
552 int32_t iMonth = m_iCurMonth;
553 if (iMonth <= 1) {
554 iMonth = 12;
555 iYear--;
556 } else {
557 iMonth--;
558 }
559
560 DATE dt(m_iCurYear, m_iCurMonth, 1);
561 if (!(dt > m_dtMin))
562 return;
563
564 m_iCurYear = iYear, m_iCurMonth = iMonth;
565 ChangeToMonth(m_iCurYear, m_iCurMonth);
566 }
567
ChangeToMonth(int32_t iYear,int32_t iMonth)568 void CFWL_MonthCalendar::ChangeToMonth(int32_t iYear, int32_t iMonth) {
569 m_iCurYear = iYear;
570 m_iCurMonth = iMonth;
571 m_iHovered = -1;
572
573 ClearDateItem();
574 ResetDateItem();
575 CalDateItem();
576 m_wsHead = GetHeadText(m_iCurYear, m_iCurMonth);
577 }
578
RemoveSelDay()579 void CFWL_MonthCalendar::RemoveSelDay() {
580 int32_t iDatesCount = pdfium::CollectionSize<int32_t>(m_DateArray);
581 for (int32_t iSelDay : m_SelDayArray) {
582 if (iSelDay <= iDatesCount)
583 m_DateArray[iSelDay - 1]->dwStates &= ~FWL_ITEMSTATE_MCD_Selected;
584 }
585 m_SelDayArray.clear();
586 }
587
AddSelDay(int32_t iDay)588 void CFWL_MonthCalendar::AddSelDay(int32_t iDay) {
589 DCHECK(iDay > 0);
590 if (!pdfium::Contains(m_SelDayArray, iDay))
591 return;
592
593 RemoveSelDay();
594 if (iDay <= pdfium::CollectionSize<int32_t>(m_DateArray))
595 m_DateArray[iDay - 1]->dwStates |= FWL_ITEMSTATE_MCD_Selected;
596
597 m_SelDayArray.push_back(iDay);
598 }
599
JumpToToday()600 void CFWL_MonthCalendar::JumpToToday() {
601 if (m_iYear != m_iCurYear || m_iMonth != m_iCurMonth) {
602 m_iCurYear = m_iYear;
603 m_iCurMonth = m_iMonth;
604 ChangeToMonth(m_iYear, m_iMonth);
605 AddSelDay(m_iDay);
606 return;
607 }
608
609 if (!pdfium::Contains(m_SelDayArray, m_iDay))
610 AddSelDay(m_iDay);
611 }
612
GetHeadText(int32_t iYear,int32_t iMonth)613 WideString CFWL_MonthCalendar::GetHeadText(int32_t iYear, int32_t iMonth) {
614 DCHECK(iMonth > 0);
615 DCHECK(iMonth < 13);
616
617 static const wchar_t* const pMonth[] = {L"January", L"February", L"March",
618 L"April", L"May", L"June",
619 L"July", L"August", L"September",
620 L"October", L"November", L"December"};
621 return WideString::Format(L"%ls, %d", pMonth[iMonth - 1], iYear);
622 }
623
GetTodayText(int32_t iYear,int32_t iMonth,int32_t iDay)624 WideString CFWL_MonthCalendar::GetTodayText(int32_t iYear,
625 int32_t iMonth,
626 int32_t iDay) {
627 return WideString::Format(L"Today, %d/%d/%d", iDay, iMonth, iYear);
628 }
629
GetDayAtPoint(const CFX_PointF & point) const630 int32_t CFWL_MonthCalendar::GetDayAtPoint(const CFX_PointF& point) const {
631 int i = 1; // one-based day values.
632 for (const auto& pDateInfo : m_DateArray) {
633 if (pDateInfo->rect.Contains(point))
634 return i;
635 ++i;
636 }
637 return -1;
638 }
639
GetDayRect(int32_t iDay)640 CFX_RectF CFWL_MonthCalendar::GetDayRect(int32_t iDay) {
641 if (iDay <= 0 || iDay > pdfium::CollectionSize<int32_t>(m_DateArray))
642 return CFX_RectF();
643
644 DATEINFO* pDateInfo = m_DateArray[iDay - 1].get();
645 return pDateInfo ? pDateInfo->rect : CFX_RectF();
646 }
647
OnProcessMessage(CFWL_Message * pMessage)648 void CFWL_MonthCalendar::OnProcessMessage(CFWL_Message* pMessage) {
649 switch (pMessage->GetType()) {
650 case CFWL_Message::Type::kSetFocus:
651 case CFWL_Message::Type::kKillFocus:
652 GetOuter()->GetDelegate()->OnProcessMessage(pMessage);
653 break;
654 case CFWL_Message::Type::kKey:
655 break;
656 case CFWL_Message::Type::kMouse: {
657 CFWL_MessageMouse* pMouse = static_cast<CFWL_MessageMouse*>(pMessage);
658 switch (pMouse->m_dwCmd) {
659 case FWL_MouseCommand::LeftButtonDown:
660 OnLButtonDown(pMouse);
661 break;
662 case FWL_MouseCommand::LeftButtonUp:
663 OnLButtonUp(pMouse);
664 break;
665 case FWL_MouseCommand::Move:
666 OnMouseMove(pMouse);
667 break;
668 case FWL_MouseCommand::Leave:
669 OnMouseLeave(pMouse);
670 break;
671 default:
672 break;
673 }
674 break;
675 }
676 default:
677 break;
678 }
679 // Dst target could be |this|, continue only if not destroyed by above.
680 if (pMessage->GetDstTarget())
681 CFWL_Widget::OnProcessMessage(pMessage);
682 }
683
OnDrawWidget(CFGAS_GEGraphics * pGraphics,const CFX_Matrix & matrix)684 void CFWL_MonthCalendar::OnDrawWidget(CFGAS_GEGraphics* pGraphics,
685 const CFX_Matrix& matrix) {
686 DrawWidget(pGraphics, matrix);
687 }
688
OnLButtonDown(CFWL_MessageMouse * pMsg)689 void CFWL_MonthCalendar::OnLButtonDown(CFWL_MessageMouse* pMsg) {
690 if (m_LBtnRect.Contains(pMsg->m_pos)) {
691 m_iLBtnPartStates = CFWL_PartState_Pressed;
692 PrevMonth();
693 RepaintRect(m_ClientRect);
694 } else if (m_RBtnRect.Contains(pMsg->m_pos)) {
695 m_iRBtnPartStates |= CFWL_PartState_Pressed;
696 NextMonth();
697 RepaintRect(m_ClientRect);
698 } else if (m_TodayRect.Contains(pMsg->m_pos)) {
699 JumpToToday();
700 RepaintRect(m_ClientRect);
701 }
702 }
703
OnLButtonUp(CFWL_MessageMouse * pMsg)704 void CFWL_MonthCalendar::OnLButtonUp(CFWL_MessageMouse* pMsg) {
705 if (m_LBtnRect.Contains(pMsg->m_pos)) {
706 m_iLBtnPartStates = 0;
707 RepaintRect(m_LBtnRect);
708 return;
709 }
710 if (m_RBtnRect.Contains(pMsg->m_pos)) {
711 m_iRBtnPartStates = 0;
712 RepaintRect(m_RBtnRect);
713 return;
714 }
715 if (m_TodayRect.Contains(pMsg->m_pos))
716 return;
717
718 int32_t iOldSel = 0;
719 if (!m_SelDayArray.empty())
720 iOldSel = m_SelDayArray[0];
721
722 int32_t iCurSel = GetDayAtPoint(pMsg->m_pos);
723 if (iCurSel > 0) {
724 DATEINFO* lpDatesInfo = m_DateArray[iCurSel - 1].get();
725 CFX_RectF rtInvalidate(lpDatesInfo->rect);
726 if (iOldSel > 0 &&
727 iOldSel <= pdfium::CollectionSize<int32_t>(m_DateArray)) {
728 lpDatesInfo = m_DateArray[iOldSel - 1].get();
729 rtInvalidate.Union(lpDatesInfo->rect);
730 }
731 AddSelDay(iCurSel);
732 CFWL_DateTimePicker* pDateTime =
733 static_cast<CFWL_DateTimePicker*>(GetOuter());
734 pDateTime->ProcessSelChanged(m_iCurYear, m_iCurMonth, iCurSel);
735 pDateTime->ShowMonthCalendar(false);
736 }
737 }
738
OnMouseMove(CFWL_MessageMouse * pMsg)739 void CFWL_MonthCalendar::OnMouseMove(CFWL_MessageMouse* pMsg) {
740 bool bRepaint = false;
741 CFX_RectF rtInvalidate;
742 if (m_DatesRect.Contains(pMsg->m_pos)) {
743 int32_t iHover = GetDayAtPoint(pMsg->m_pos);
744 bRepaint = m_iHovered != iHover;
745 if (bRepaint) {
746 if (m_iHovered > 0)
747 rtInvalidate = GetDayRect(m_iHovered);
748 if (iHover > 0) {
749 CFX_RectF rtDay = GetDayRect(iHover);
750 if (rtInvalidate.IsEmpty())
751 rtInvalidate = rtDay;
752 else
753 rtInvalidate.Union(rtDay);
754 }
755 }
756 m_iHovered = iHover;
757 } else {
758 bRepaint = m_iHovered > 0;
759 if (bRepaint)
760 rtInvalidate = GetDayRect(m_iHovered);
761
762 m_iHovered = -1;
763 }
764 if (bRepaint && !rtInvalidate.IsEmpty())
765 RepaintRect(rtInvalidate);
766 }
767
OnMouseLeave(CFWL_MessageMouse * pMsg)768 void CFWL_MonthCalendar::OnMouseLeave(CFWL_MessageMouse* pMsg) {
769 if (m_iHovered <= 0)
770 return;
771
772 CFX_RectF rtInvalidate = GetDayRect(m_iHovered);
773 m_iHovered = -1;
774 if (!rtInvalidate.IsEmpty())
775 RepaintRect(rtInvalidate);
776 }
777
DATEINFO(int32_t day,int32_t dayofweek,uint32_t dwSt,CFX_RectF rc,const WideString & wsday)778 CFWL_MonthCalendar::DATEINFO::DATEINFO(int32_t day,
779 int32_t dayofweek,
780 uint32_t dwSt,
781 CFX_RectF rc,
782 const WideString& wsday)
783 : iDay(day),
784 iDayOfWeek(dayofweek),
785 dwStates(dwSt),
786 rect(rc),
787 wsDay(wsday) {}
788
789 CFWL_MonthCalendar::DATEINFO::~DATEINFO() = default;
790