7#include "xfa/fwl/cfwl_monthcalendar.h"
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"
30constexpr float kMonthCalHSepHeight = 1.0f;
31constexpr float kMonthCalHMargin = 3.0f;
32constexpr float kMonthCalVMargin = 2.0f;
33constexpr float kMonthCalRows = 9.0f;
34constexpr float kMonthCalColumns = 7.0f;
35constexpr float kMonthCalHeaderBtnVMargin = 7.0f;
36constexpr float kMonthCalHeaderBtnHMargin = 5.0f;
92CFWL_MonthCalendar::CFWL_MonthCalendar(CFWL_App* app,
105 CFX_RectF rect(0, 0, fs.width, fs.height);
114 if (!m_bInitialized) {
116 m_bInitialized =
true;
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);
148 ChangeToMonth(iYear, iMonth);
172 params.m_dwStates = m_iLBtnPartStates;
181 params.m_dwStates = m_iRBtnPartStates;
190 textParam.m_wsText = GetHeadText(m_iCurYear, m_iCurMonth);
191 m_HeadSize = CalcTextSize(textParam.m_wsText,
false);
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) {
220 if (pDataInfo->bFlagged) {
223 }
else if (j == m_iHovered - 1) {
225 }
else if (pDataInfo->bFlagged) {
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);
250 params.m_wsText = GetAbbreviatedDayOfWeek(i);
259 params.m_wsText = GetTodayText(m_iYear, m_iMonth, m_iDay);
260 m_TodaySize = CalcTextSize(params.m_wsText,
false);
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;
280 params.m_dwStates = pDataInfo->AsPartStateMask();
281 if (j + 1 == m_iHovered)
299 if (m_iMonth != m_iCurMonth || m_iYear != m_iCurYear)
302 if (m_iDay < 1 || m_iDay > fxcrt::CollectionSize<int32_t>(m_DateArray))
305 DATEINFO* pDate = m_DateArray[m_iDay - 1].get();
316CFX_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;
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;
332 static_cast<
int>(0.5 + (fMaxWeekW >= fDayMaxW ? fMaxWeekW : fDayMaxW));
333 m_CellSize.height = fMaxWeekH >= fDayMaxH ? fMaxWeekH : fDayMaxH;
336 fs.width = m_CellSize.width * kMonthCalColumns +
337 kMonthCalHMargin * kMonthCalColumns * 2 +
338 kMonthCalHeaderBtnHMargin * 2;
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;
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);
352 m_HeadSize.width + kMonthCalHeaderBtnHMargin * 2 + m_CellSize.width * 2;
353 fs.width =
std::max(fs.width, fMonthMaxW);
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)
360 fs.height = m_CellSize.width + m_CellSize.height * (kMonthCalRows - 2) +
361 m_TodaySize.height + kMonthCalVMargin * kMonthCalRows * 2 +
362 kMonthCalHeaderBtnVMargin * 4;
366void 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,
375void 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,
387void CFWL_MonthCalendar::Layout() {
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,
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);
406 m_ClientRect
.left + kMonthCalHeaderBtnHMargin + kMonthCalHMargin
,
408 m_ClientRect
.width - (kMonthCalHeaderBtnHMargin + kMonthCalHMargin) * 2
,
409 kMonthCalHSepHeight
);
410 m_DatesRect = CFX_RectF(m_ClientRect.left + kMonthCalHeaderBtnHMargin,
412 m_ClientRect.width - kMonthCalHeaderBtnHMargin * 2,
413 m_CellSize.height * (kMonthCalRows - 3) +
414 kMonthCalVMargin * (kMonthCalRows - 3) * 2);
419void 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) {
429 pDateInfo->rect = CFX_RectF(
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)
440void CFWL_MonthCalendar::InitDate() {
446 m_iCurYear = m_iYear;
447 m_iCurMonth = m_iMonth;
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);
455void CFWL_MonthCalendar::ClearDateItem() {
459void CFWL_MonthCalendar::ResetDateItem() {
463 for (int32_t i = 0; i < iDays; ++i, ++iDayOfWeek) {
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)));
476void CFWL_MonthCalendar::NextMonth() {
477 int32_t iYear = m_iCurYear;
478 int32_t iMonth = m_iCurMonth;
485 DATE dt(m_iCurYear, m_iCurMonth, 1);
489 m_iCurYear = iYear, m_iCurMonth = iMonth;
490 ChangeToMonth(m_iCurYear, m_iCurMonth);
493void CFWL_MonthCalendar::PrevMonth() {
494 int32_t iYear = m_iCurYear;
495 int32_t iMonth = m_iCurMonth;
503 DATE dt(m_iCurYear, m_iCurMonth, 1);
507 m_iCurYear = iYear, m_iCurMonth = iMonth;
508 ChangeToMonth(m_iCurYear, m_iCurMonth);
511void CFWL_MonthCalendar::ChangeToMonth(int32_t iYear, int32_t iMonth) {
513 m_iCurMonth = iMonth;
519 m_wsHead = GetHeadText(m_iCurYear, m_iCurMonth);
522void 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;
528 m_SelDayArray.clear();
531void CFWL_MonthCalendar::AddSelDay(int32_t iDay) {
533 if (!Contains(m_SelDayArray, iDay)) {
538 if (iDay <= fxcrt::CollectionSize<int32_t>(m_DateArray))
539 m_DateArray[iDay - 1]->bSelected =
true;
541 m_SelDayArray.push_back(iDay);
544void 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);
553 if (!Contains(m_SelDayArray, m_iDay)) {
558WideString 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"}};
565WideString CFWL_MonthCalendar::GetTodayText(int32_t 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,
724 iDayOfWeek(dayofweek),
729CFWL_MonthCalendar::DATEINFO::~DATEINFO() =
default;
uint8_t FX_DaysInMonth(int32_t iYear, uint8_t iMonth)
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)
static WideString Format(const wchar_t *pFormat,...)
static WideString FromASCII(ByteStringView str)
void ProcessSelChanged(int32_t iYear, int32_t iMonth, int32_t iDay)
const MouseCommand m_dwCmd
CFWL_Widget * GetDstTarget() const
void SetSelect(int32_t iYear, int32_t iMonth, int32_t iDay)
FWL_Type GetClassID() const override
~CFWL_MonthCalendar() override
void DrawWidget(CFGAS_GEGraphics *pGraphics, const CFX_Matrix &matrix) override
void OnDrawWidget(CFGAS_GEGraphics *pGraphics, const CFX_Matrix &matrix) override
void OnProcessMessage(CFWL_Message *pMessage) override
CFX_RectF GetAutosizedWidgetRect() override
FDE_TextStyle m_dwTTOStyles
FDE_TextAlignment m_iTTOAlign
virtual void DrawText(const CFWL_ThemeText &pParams)=0
virtual void DrawBackground(const CFWL_ThemeBackground &pParams)=0
CFX_PTemplate< float > CFX_PointF
CFX_STemplate< float > CFX_SizeF
#define NOTREACHED_NORETURN()
fxcrt::WideString WideString