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 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 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 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 116 CFWL_MonthCalendar::~CFWL_MonthCalendar() { 117 ClearDateItem(); 118 m_arrSelDays.clear(); 119 } 120 121 FWL_Type CFWL_MonthCalendar::GetClassID() const { 122 return FWL_Type::MonthCalendar; 123 } 124 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 549 void CFWL_MonthCalendar::GetCapValue() { 550 if (!m_pProperties->m_pThemeProvider) 551 m_pProperties->m_pThemeProvider = GetAvailableTheme(); 552 } 553 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 569 void CFWL_MonthCalendar::ClearDateItem() { 570 m_arrDates.clear(); 571 } 572 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 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 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 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 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 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 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 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 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 689 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 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 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 744 void CFWL_MonthCalendar::OnDrawWidget(CXFA_Graphics* pGraphics, 745 const CFX_Matrix& matrix) { 746 DrawWidget(pGraphics, matrix); 747 } 748 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 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 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 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 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 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 896 CFWL_MonthCalendar::DATEINFO::~DATEINFO() {} 897