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 33namespace { 34 35CFX_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 55CFX_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 87CFWL_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 117CFWL_MonthCalendar::~CFWL_MonthCalendar() { 118 ClearDateItem(); 119 m_arrSelDays.clear(); 120} 121 122FWL_Type CFWL_MonthCalendar::GetClassID() const { 123 return FWL_Type::MonthCalendar; 124} 125 126CFX_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 133void 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 150void 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 175void CFWL_MonthCalendar::SetSelect(int32_t iYear, 176 int32_t iMonth, 177 int32_t iDay) { 178 ChangeToMonth(iYear, iMonth); 179 AddSelDay(iDay); 180} 181 182void 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 196void 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 210void 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 224void 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 238void 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 258void 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 272void 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 302void 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 327void 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 348void 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 373void 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 387void 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 411CFX_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 474void 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 483void 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 495void 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 527void 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 548void CFWL_MonthCalendar::GetCapValue() { 549 if (!m_pProperties->m_pThemeProvider) 550 m_pProperties->m_pThemeProvider = GetAvailableTheme(); 551} 552 553void 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 568void CFWL_MonthCalendar::ClearDateItem() { 569 m_arrDates.clear(); 570} 571 572void 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 595void 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 612void 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 630void 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 641void 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 650void 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 662void 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 675CFX_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 686CFX_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 694int32_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 704CFX_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 712void 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 749void CFWL_MonthCalendar::OnDrawWidget(CFX_Graphics* pGraphics, 750 const CFX_Matrix* pMatrix) { 751 DrawWidget(pGraphics, pMatrix); 752} 753 754void 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 773void 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 817void 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 851void 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 880void 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 890CFWL_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 901CFWL_MonthCalendar::DATEINFO::~DATEINFO() {} 902