7#include "xfa/fwl/cfwl_monthcalendar.h"
13#include "core/fxcrt/cfx_datetime.h"
14#include "core/fxcrt/stl_util.h"
15#include "third_party/base/check.h"
16#include "third_party/base/containers/contains.h"
17#include "third_party/base/notreached.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"
28constexpr float kMonthCalHSepHeight = 1.0f;
29constexpr float kMonthCalHMargin = 3.0f;
30constexpr float kMonthCalVMargin = 2.0f;
31constexpr float kMonthCalRows = 9.0f;
32constexpr float kMonthCalColumns = 7.0f;
33constexpr float kMonthCalHeaderBtnVMargin = 7.0f;
34constexpr float kMonthCalHeaderBtnHMargin = 5.0f;
36WideString GetAbbreviatedDayOfWeek(
int day) {
53 NOTREACHED_NORETURN();
57WideString GetMonth(
int month) {
84 NOTREACHED_NORETURN();
90CFWL_MonthCalendar::CFWL_MonthCalendar(CFWL_App* app,
102 CFX_SizeF fs = CalcSize();
103 CFX_RectF rect(0, 0, fs.width, fs.height);
112 if (!m_bInitialized) {
114 m_bInitialized =
true;
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);
146 ChangeToMonth(iYear, iMonth);
170 params.m_dwStates = m_iLBtnPartStates;
179 params.m_dwStates = m_iRBtnPartStates;
188 textParam.m_wsText = GetHeadText(m_iCurYear, m_iCurMonth);
189 m_HeadSize = CalcTextSize(textParam.m_wsText,
false);
213 int32_t iCount = fxcrt::CollectionSize<int32_t>(m_DateArray);
214 for (int32_t j = 0; j < iCount; j++) {
215 DATEINFO* pDataInfo = m_DateArray[j].get();
216 if (pDataInfo->bSelected) {
218 if (pDataInfo->bFlagged) {
221 }
else if (j == m_iHovered - 1) {
223 }
else if (pDataInfo->bFlagged) {
242 for (int32_t i = 0; i < 7; ++i) {
243 rtDayOfWeek = CFX_RectF(
244 m_WeekRect.left + i * (m_CellSize.width + kMonthCalHMargin * 2),
245 m_WeekRect.top, m_CellSize);
248 params.m_wsText = GetAbbreviatedDayOfWeek(i);
257 params.m_wsText = GetTodayText(m_iYear, m_iMonth, m_iDay);
258 m_TodaySize = CalcTextSize(params.m_wsText,
false);
273 int32_t iCount = fxcrt::CollectionSize<int32_t>(m_DateArray);
274 for (int32_t j = 0; j < iCount; j++) {
275 DATEINFO* pDataInfo = m_DateArray[j].get();
276 params.m_wsText = pDataInfo->wsDay;
278 params.m_dwStates = pDataInfo->AsPartStateMask();
279 if (j + 1 == m_iHovered)
297 if (m_iMonth != m_iCurMonth || m_iYear != m_iCurYear)
300 if (m_iDay < 1 || m_iDay > fxcrt::CollectionSize<int32_t>(m_DateArray))
303 DATEINFO* pDate = m_DateArray[m_iDay - 1].get();
314CFX_SizeF CFWL_MonthCalendar::CalcSize() {
315 float fMaxWeekW = 0.0f;
316 float fMaxWeekH = 0.0f;
317 for (
int i = 0; i < 7; ++i) {
318 CFX_SizeF sz = CalcTextSize(GetAbbreviatedDayOfWeek(i),
false);
319 fMaxWeekW = (fMaxWeekW >= sz.width) ? fMaxWeekW : sz.width;
320 fMaxWeekH = (fMaxWeekH >= sz.height) ? fMaxWeekH : sz.height;
322 float fDayMaxW = 0.0f;
323 float fDayMaxH = 0.0f;
324 for (
int day = 10; day <= 31; day++) {
325 CFX_SizeF sz = CalcTextSize(WideString::FormatInteger(day),
false);
326 fDayMaxW = (fDayMaxW >= sz.width) ? fDayMaxW : sz.width;
327 fDayMaxH = (fDayMaxH >= sz.height) ? fDayMaxH : sz.height;
330 static_cast<
int>(0.5 + (fMaxWeekW >= fDayMaxW ? fMaxWeekW : fDayMaxW));
331 m_CellSize.height = fMaxWeekH >= fDayMaxH ? fMaxWeekH : fDayMaxH;
334 fs.width = m_CellSize.width * kMonthCalColumns +
335 kMonthCalHMargin * kMonthCalColumns * 2 +
336 kMonthCalHeaderBtnHMargin * 2;
338 float fMonthMaxW = 0.0f;
339 float fMonthMaxH = 0.0f;
340 for (
int i = 0; i < 12; ++i) {
341 CFX_SizeF sz = CalcTextSize(GetMonth(i),
false);
342 fMonthMaxW = (fMonthMaxW >= sz.width) ? fMonthMaxW : sz.width;
343 fMonthMaxH = (fMonthMaxH >= sz.height) ? fMonthMaxH : sz.height;
346 CFX_SizeF szYear = CalcTextSize(GetHeadText(m_iYear, m_iMonth),
false);
347 fMonthMaxH =
std::max(fMonthMaxH, szYear.height);
348 m_HeadSize = CFX_SizeF(fMonthMaxW + szYear.width, fMonthMaxH);
350 m_HeadSize.width + kMonthCalHeaderBtnHMargin * 2 + m_CellSize.width * 2;
351 fs.width =
std::max(fs.width, fMonthMaxW);
353 m_wsToday = GetTodayText(m_iYear, m_iMonth, m_iDay);
354 m_TodaySize = CalcTextSize(m_wsToday,
false);
355 m_TodaySize.height = (m_TodaySize.height >= m_CellSize.height)
358 fs.height = m_CellSize.width + m_CellSize.height * (kMonthCalRows - 2) +
359 m_TodaySize.height + kMonthCalVMargin * kMonthCalRows * 2 +
360 kMonthCalHeaderBtnVMargin * 4;
364void CFWL_MonthCalendar::CalcHeadSize() {
365 float fHeadHMargin = (m_ClientRect.width - m_HeadSize.width) / 2;
366 float fHeadVMargin = (m_CellSize.width - m_HeadSize.height) / 2;
367 m_HeadTextRect = CFX_RectF(m_ClientRect.left + fHeadHMargin,
368 m_ClientRect.top + kMonthCalHeaderBtnVMargin +
369 kMonthCalVMargin + fHeadVMargin,
373void CFWL_MonthCalendar::CalcTodaySize() {
374 m_TodayFlagRect = CFX_RectF(
375 m_ClientRect.left + kMonthCalHeaderBtnHMargin + kMonthCalHMargin,
376 m_DatesRect.bottom() + kMonthCalHeaderBtnVMargin + kMonthCalVMargin,
377 m_CellSize.width, m_TodaySize.height);
378 m_TodayRect = CFX_RectF(
379 m_ClientRect.left + kMonthCalHeaderBtnHMargin + m_CellSize.width +
380 kMonthCalHMargin * 2,
381 m_DatesRect.bottom() + kMonthCalHeaderBtnVMargin + kMonthCalVMargin,
385void CFWL_MonthCalendar::Layout() {
388 m_HeadRect = CFX_RectF(
389 m_ClientRect.left + kMonthCalHeaderBtnHMargin, m_ClientRect.top,
390 m_ClientRect.width - kMonthCalHeaderBtnHMargin * 2,
391 m_CellSize.width + (kMonthCalHeaderBtnVMargin + kMonthCalVMargin) * 2);
392 m_WeekRect = CFX_RectF(m_ClientRect.left + kMonthCalHeaderBtnHMargin,
394 m_ClientRect.width - kMonthCalHeaderBtnHMargin * 2,
395 m_CellSize.height + kMonthCalVMargin * 2);
396 m_LBtnRect = CFX_RectF(m_ClientRect.left + kMonthCalHeaderBtnHMargin,
397 m_ClientRect.top + kMonthCalHeaderBtnVMargin,
398 m_CellSize.width, m_CellSize.width);
399 m_RBtnRect = CFX_RectF(m_ClientRect.left + m_ClientRect.width -
400 kMonthCalHeaderBtnHMargin - m_CellSize.width,
401 m_ClientRect.top + kMonthCalHeaderBtnVMargin,
402 m_CellSize.width, m_CellSize.width);
404 m_ClientRect
.left + kMonthCalHeaderBtnHMargin + kMonthCalHMargin
,
406 m_ClientRect
.width - (kMonthCalHeaderBtnHMargin + kMonthCalHMargin) * 2
,
407 kMonthCalHSepHeight
);
408 m_DatesRect = CFX_RectF(m_ClientRect.left + kMonthCalHeaderBtnHMargin,
410 m_ClientRect.width - kMonthCalHeaderBtnHMargin * 2,
411 m_CellSize.height * (kMonthCalRows - 3) +
412 kMonthCalVMargin * (kMonthCalRows - 3) * 2);
417void CFWL_MonthCalendar::CalDateItem() {
418 bool bNewWeek =
false;
419 int32_t iWeekOfMonth = 0;
420 float fLeft = m_DatesRect
.left;
421 float fTop = m_DatesRect
.top;
422 for (
const auto& pDateInfo : m_DateArray) {
427 pDateInfo->rect = CFX_RectF(
429 pDateInfo->iDayOfWeek * (m_CellSize.width + (kMonthCalHMargin * 2)),
430 fTop + iWeekOfMonth * (m_CellSize.height + (kMonthCalVMargin * 2)),
431 m_CellSize.width + (kMonthCalHMargin * 2),
432 m_CellSize.height + (kMonthCalVMargin * 2));
433 if (pDateInfo->iDayOfWeek >= 6)
438void CFWL_MonthCalendar::InitDate() {
444 m_iCurYear = m_iYear;
445 m_iCurMonth = m_iMonth;
447 m_wsToday = GetTodayText(m_iYear, m_iMonth, m_iDay);
448 m_wsHead = GetHeadText(m_iCurYear, m_iCurMonth);
449 m_dtMin = DATE(1500, 12, 1);
450 m_dtMax = DATE(2200, 1, 1);
453void CFWL_MonthCalendar::ClearDateItem() {
457void CFWL_MonthCalendar::ResetDateItem() {
461 for (int32_t i = 0; i < iDays; ++i, ++iDayOfWeek) {
465 const bool bFlagged =
466 m_iYear == m_iCurYear && m_iMonth == m_iCurMonth && m_iDay == i + 1;
467 const bool bSelected = pdfium::Contains(m_SelDayArray, i + 1);
468 m_DateArray.push_back(
469 std::make_unique<DATEINFO>(i + 1, iDayOfWeek, bFlagged, bSelected,
470 WideString::FormatInteger(i + 1)));
474void CFWL_MonthCalendar::NextMonth() {
475 int32_t iYear = m_iCurYear;
476 int32_t iMonth = m_iCurMonth;
483 DATE dt(m_iCurYear, m_iCurMonth, 1);
487 m_iCurYear = iYear, m_iCurMonth = iMonth;
488 ChangeToMonth(m_iCurYear, m_iCurMonth);
491void CFWL_MonthCalendar::PrevMonth() {
492 int32_t iYear = m_iCurYear;
493 int32_t iMonth = m_iCurMonth;
501 DATE dt(m_iCurYear, m_iCurMonth, 1);
505 m_iCurYear = iYear, m_iCurMonth = iMonth;
506 ChangeToMonth(m_iCurYear, m_iCurMonth);
509void CFWL_MonthCalendar::ChangeToMonth(int32_t iYear, int32_t iMonth) {
511 m_iCurMonth = iMonth;
517 m_wsHead = GetHeadText(m_iCurYear, m_iCurMonth);
520void CFWL_MonthCalendar::RemoveSelDay() {
521 int32_t iDatesCount = fxcrt::CollectionSize<int32_t>(m_DateArray);
522 for (int32_t iSelDay : m_SelDayArray) {
523 if (iSelDay <= iDatesCount)
524 m_DateArray[iSelDay - 1]->bSelected =
false;
526 m_SelDayArray.clear();
529void CFWL_MonthCalendar::AddSelDay(int32_t iDay) {
531 if (!pdfium::Contains(m_SelDayArray, iDay))
535 if (iDay <= fxcrt::CollectionSize<int32_t>(m_DateArray))
536 m_DateArray[iDay - 1]->bSelected =
true;
538 m_SelDayArray.push_back(iDay);
541void CFWL_MonthCalendar::JumpToToday() {
542 if (m_iYear != m_iCurYear || m_iMonth != m_iCurMonth) {
543 m_iCurYear = m_iYear;
544 m_iCurMonth = m_iMonth;
545 ChangeToMonth(m_iYear, m_iMonth);
550 if (!pdfium::Contains(m_SelDayArray, m_iDay))
554WideString CFWL_MonthCalendar::GetHeadText(int32_t iYear, int32_t iMonth) {
558 static const wchar_t*
const pMonth[] = {L"January", L"February", L"March",
559 L"April", L"May", L"June",
560 L"July", L"August", L"September",
561 L"October", L"November", L"December"};
562 return WideString
::Format(L"%ls, %d"
, pMonth[iMonth - 1]
, iYear
);
565WideString CFWL_MonthCalendar::GetTodayText(int32_t iYear,
568 return WideString
::Format(L"Today, %d/%d/%d"
, iDay
, iMonth
, iYear
);
571int32_t CFWL_MonthCalendar::GetDayAtPoint(
const CFX_PointF& point)
const {
573 for (
const auto& pDateInfo : m_DateArray) {
574 if (pDateInfo->rect.Contains(point))
581CFX_RectF CFWL_MonthCalendar::GetDayRect(int32_t iDay) {
582 if (iDay <= 0 || iDay > fxcrt::CollectionSize<int32_t>(m_DateArray))
585 DATEINFO* pDateInfo = m_DateArray[iDay - 1].get();
593 GetOuter()->GetDelegate()->OnProcessMessage(pMessage);
598 CFWL_MessageMouse* pMouse =
static_cast<CFWL_MessageMouse*>(pMessage);
601 OnLButtonDown(pMouse);
610 OnMouseLeave(pMouse);
630void CFWL_MonthCalendar::OnLButtonDown(CFWL_MessageMouse* pMsg) {
631 if (m_LBtnRect.Contains(pMsg->m_pos)) {
632 m_iLBtnPartStates = CFWL_PartState::kPressed;
635 }
else if (m_RBtnRect.Contains(pMsg->m_pos)) {
636 m_iRBtnPartStates |= CFWL_PartState::kPressed;
639 }
else if (m_TodayRect.Contains(pMsg->m_pos)) {
645void CFWL_MonthCalendar::OnLButtonUp(CFWL_MessageMouse* pMsg) {
646 if (m_LBtnRect.Contains(pMsg->m_pos)) {
647 m_iLBtnPartStates = CFWL_PartState::kNormal;
651 if (m_RBtnRect.Contains(pMsg->m_pos)) {
652 m_iRBtnPartStates = CFWL_PartState::kNormal;
656 if (m_TodayRect.Contains(pMsg->m_pos))
660 if (!m_SelDayArray.empty())
661 iOldSel = m_SelDayArray[0];
663 int32_t iCurSel = GetDayAtPoint(pMsg->m_pos);
665 DATEINFO* pDateInfo = m_DateArray[iCurSel - 1].get();
667 if (iOldSel > 0 && iOldSel <= fxcrt::CollectionSize<int32_t>(m_DateArray)) {
668 pDateInfo = m_DateArray[iOldSel - 1].get();
669 rtInvalidate
.Union(pDateInfo->rect
);
672 CFWL_DateTimePicker* pDateTime =
673 static_cast<CFWL_DateTimePicker*>(
GetOuter());
679void CFWL_MonthCalendar::OnMouseMove(CFWL_MessageMouse* pMsg) {
680 bool bRepaint =
false;
682 if (m_DatesRect.Contains(pMsg->m_pos)) {
683 int32_t iHover = GetDayAtPoint(pMsg->m_pos);
684 bRepaint = m_iHovered != iHover;
687 rtInvalidate
= GetDayRect(m_iHovered);
691 rtInvalidate
= rtDay;
698 bRepaint = m_iHovered > 0;
700 rtInvalidate
= GetDayRect(m_iHovered);
708void CFWL_MonthCalendar::OnMouseLeave(CFWL_MessageMouse* pMsg) {
712 CFX_RectF rtInvalidate = GetDayRect(m_iHovered);
718CFWL_MonthCalendar::DATEINFO::DATEINFO(int32_t day,
722 const WideString& wsday)
724 iDayOfWeek(dayofweek),
729CFWL_MonthCalendar::DATEINFO::~DATEINFO() =
default;
uint8_t FX_DaysInMonth(int32_t iYear, uint8_t iMonth)
void ProcessSelChanged(int32_t iYear, int32_t iMonth, int32_t iDay)
const MouseCommand m_dwCmd
CFWL_Widget * GetDstTarget() const
void DrawWidget(CFGAS_GEGraphics *pGraphics, const CFX_Matrix &matrix) override
~CFWL_MonthCalendar() override
void SetSelect(int32_t iYear, int32_t iMonth, int32_t iDay)
void OnDrawWidget(CFGAS_GEGraphics *pGraphics, const CFX_Matrix &matrix) override
CFX_RectF GetAutosizedWidgetRect() override
void OnProcessMessage(CFWL_Message *pMessage) override
FWL_Type GetClassID() const override
FDE_TextStyle m_dwTTOStyles
FDE_TextAlignment m_iTTOAlign
static CFX_DateTime Now()
int32_t GetDayOfWeek() const
CFX_DateTime(int32_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second, uint16_t millisecond)
CFX_Matrix & operator=(const CFX_Matrix &other)=default
CFX_RectF(const CFX_RectF &other)=default
constexpr CFX_RectF()=default
CFX_RectF & operator=(const CFX_RectF &other)=default
constexpr CFX_RectF(float dst_left, float dst_top, float dst_width, float dst_height)
void Union(const CFX_RectF &rt)
virtual void DrawBackground(const CFWL_ThemeBackground &pParams)=0
virtual void DrawText(const CFWL_ThemeText &pParams)=0
static WideString Format(const wchar_t *pFormat,...)