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