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(¶ms);
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(¶ms);
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(¶ms);
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(¶ms);
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(¶ms);
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(¶ms);
294 }
295 params.m_rtPart = pDataInfo->rect;
296 pTheme->DrawBackground(¶ms);
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(¶ms);
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(¶ms);
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(¶ms);
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(¶ms);
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(¶ms);
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