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