soui 5.0.0.1
Soui5 Doc
 
Loading...
Searching...
No Matches
SCalendar.cpp
Go to the documentation of this file.
1/**
2 * Copyright (C) 2014-2050 SOUI团队
3 * All rights reserved.
4 *
5 * @file SCalendar.cpp
6 * @brief SCalendarCore以及SCalendar类源文件
7 * @version v1.0
8 * @author soui
9 * @date 2014-05-25
10 *
11 * Describe 时间控件相关函数实现
12 */
13#include "souistd.h"
14#include "control/SCalendar.h"
15#include "helper/STime.h"
16
17#ifdef _DEBUG
18#define new DEBUG_NEW
19#undef THIS_FILE
20static char THIS_FILE[] = __FILE__;
21#endif
22
23/////////////////////////////////////////////////////////////////////////////
24// SCalendarCore
25
26SNSBEGIN
27
28extern WORD gLunarMonthDay[];
29extern BYTE gLunarMonth[];
30extern BYTE gLunarHolDay[];
31
32#define REFTYPE_SUJIU 1 //数九
33#define REFTYPE_MEIYU 2 //梅雨
34#define REFTYPE_SANFU 3 //三伏
35
36#define TITLE_HEIGHT 20.f
37#define FOOTER_HEIGHT 20.f
38
39//两个子控件的名字
40#define NAME_BTN_TODAY "btn_today"
41#define NAME_LABEL_TODAY "label_today"
42
43WORD const DayOrdinal[13] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
44WORD const DayOrdinalLeap[13] = { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 };
45
46BOOL SCalendarCore::IsLeapYear(WORD wYear, BOOL &bLeapYear)
47{
48 if (wYear < 1600 || wYear >= 7000) //压缩算法规定了的年份区间(提取器只能导出此区间的数据,Lunar.dll支持-6000到20000(不含20000)之间的年份)
49 {
50 return FALSE;
51 }
52 if (wYear % 4 == 0 && wYear % 100 != 0 || wYear % 400 == 0) //判断闰年的条件
53 {
54 bLeapYear = TRUE;
55 }
56 else
57 {
58 bLeapYear = FALSE;
59 }
60 return TRUE;
61}
62
63BOOL SCalendarCore::GetDaysNumInYear(WORD wYear, WORD wMonth, WORD wDay, WORD &wDays)
64{
65 //从日期算出距离元旦的天数
66 if (DateCheck(wYear, wMonth, wDay) == 0) //对输入的日期进行检查
67 {
68 return FALSE;
69 }
70 BOOL bLeapYear = FALSE;
71 if (!IsLeapYear(wYear, bLeapYear))
72 {
73 return FALSE;
74 }
75 if (bLeapYear == TRUE)
76 {
77 wDays = DayOrdinalLeap[wMonth - 1] + wDay - 1; //元旦为序数0,因此减1
78 }
79 else
80 {
81 wDays = DayOrdinal[wMonth - 1] + wDay - 1;
82 }
83 return TRUE;
84}
85
86BOOL SCalendarCore::GetDateFromDays(WORD wYear, WORD wDays, WORD &wMonth, WORD &wDay)
87{
88 //从距离元旦的天数算出日期
89 if (wDays < 1)
90 {
91 return FALSE;
92 }
93 BOOL bLeapYear = FALSE;
94 if (!IsLeapYear(wYear, bLeapYear))
95 {
96 return FALSE;
97 }
98 if (bLeapYear == TRUE)
99 {
100 if (wDays > 366) //超出了该年的总天数
101 {
102 return FALSE;
103 }
104 }
105 else
106 {
107 if (wDays > 365)
108 {
109 return FALSE;
110 }
111 }
112 wMonth = 0;
113 int i = 0;
114 for (i = 0; i < 12; i++)
115 {
116 if (bLeapYear == TRUE)
117 {
118 if (wDays >= DayOrdinalLeap[i] && wDays < DayOrdinalLeap[i + 1]) //找出月份
119 {
120 wMonth = i + 1;
121 wDay = wDays - DayOrdinalLeap[i]; //计算出“日”
122 break;
123 }
124 }
125 else
126 {
127 if (wDays >= DayOrdinal[i] && wDays < DayOrdinal[i + 1])
128 {
129 wMonth = i + 1;
130 wDay = wDays - DayOrdinal[i];
131 break;
132 }
133 }
134 }
135 return TRUE;
136}
137
138BOOL SCalendarCore::DateCheck(WORD wYear, WORD wMonth, WORD wDay)
139{
140 if (wMonth > 12 || wMonth < 1)
141 return FALSE;
142
143 if (wDay < 1 || wDay > 31)
144 return FALSE;
145
146 if (wMonth == 4 || wMonth == 6 || wMonth == 9 || wMonth == 11)
147 {
148 if (wDay > 30)
149 {
150 return FALSE;
151 }
152 }
153 else if (wMonth == 2)
154 {
155 BOOL bLeapYear = FALSE;
156 IsLeapYear(wYear, bLeapYear);
157 if (bLeapYear == FALSE)
158 {
159 if (wDay > 28)
160 {
161 return FALSE;
162 }
163 }
164 else
165 {
166 if (wDay > 29)
167 {
168 return FALSE;
169 }
170 }
171 }
172
173 return TRUE;
174}
175
176short SCalendarCore::GetDayOfWeek(WORD wYear, WORD wMonth, WORD wDay)
177{
178 WORD uDayOrd = 0;
179 if (GetDaysNumInYear(wYear, wMonth, wDay, uDayOrd) == 0)
180 {
181 return -1;
182 }
183 unsigned int DayofWeek = 0;
184 uDayOrd++; //一年中的第几天,因为GetDaysNumInYear所得到的是索引,因此要加一
185 wYear--;
186 DayofWeek = (wYear + wYear / 4 - wYear / 100 + wYear / 400 + uDayOrd) % 7; //这个只是算星期的通用公式
187 return DayofWeek;
188}
189
190WORD SCalendarCore::GetDaysOfMonth(WORD wYear, WORD wMonth)
191{
192 if (wMonth == 12)
193 {
194 return 31; //这里为了简便,判断12月就直接返回
195 }
196 WORD days1 = 0, days2 = 0;
197 WORD ret = 0;
198 ret = GetDaysNumInYear(wYear, wMonth, 1, days1); //本月1日在年内的序数
199 if (ret == 0)
200 {
201 return ret;
202 }
203 wMonth++;
204 ret = GetDaysNumInYear(wYear, wMonth, 1, days2); //下个月1日的年内序数
205 if (ret == 0)
206 {
207 return ret;
208 }
209 ret = days2 - days1; //下个月1日的序数减本月1日的序数
210 return ret;
211}
212
213SStringT SCalendarCore::FormatYear(WORD iYear)
214{
215 return SStringT().Format(_T("%d"), iYear);
216}
217
218SStringT SCalendarCore::FormatMonth(WORD iMonth)
219{
220 const TCHAR *szText[] = { _T("一"), _T("二"), _T("三"), _T("四"), _T("五"), _T("六"), _T("七"), _T("八"), _T("九"), _T("十"), _T("十一"), _T("十二") };
221 SASSERT(iMonth <= 12 && iMonth >= 1);
222 return szText[iMonth - 1];
223}
224
225SStringT SCalendarCore::FormatDay(WORD iDay)
226{
227 return SStringT().Format(_T("%d"), iDay);
228}
229
230SCalendar::SCalendar(WORD iYeay, WORD iMonth, WORD iDay)
231{
232 Init();
233 if (!SetDate(iYeay, iMonth, iDay))
234 {
235 // STime tm = STime::GetCurrentTime();
236 SetDate(m_Today.wYear, m_Today.wMonth, m_Today.wDay);
237 }
238}
239
241{
242 Init();
244 SetDate(tm.GetYear(), tm.GetMonth(), tm.GetDay());
245}
246
250
252{
253 __baseCls::OnLanguageChanged();
254 for (UINT i = 0; i < 7; i++)
255 {
256 m_strWeek[i].TranslateText();
257 }
258 return S_OK;
259}
260
262{
263 m_pSkinPrev = GETBUILTINSKIN(SKIN_SYS_BTN_PREV);
264 m_pSkinNext = GETBUILTINSKIN(SKIN_SYS_BTN_NEXT);
265
266 m_bFocusable = TRUE;
267 GetLocalTime(&m_Today);
268
269 m_evtSet.addEvent(EVENTID(EventCalendarExChanged));
270
271 m_nYearMonthHeight.setSize(30.f, SLayoutSize::dp);
272 m_nWeekHeight.setSize(20.f, SLayoutSize::dp);
273 m_nFooterHeight.setSize(20.f, SLayoutSize::dp);
274
275 m_crSelText = RGBA(0xFF, 0xFF, 0xFF, 255);
276 m_crSelDayBack = RGBA(0x0, 0x7A, 0xCC, 255);
277 m_crOtherDayText = RGBA(0xA0, 0xA0, 0xA0, 255);
278
279 // 设置 默认 的 背景色 和 悬浮 字体颜色
280 GetStyle().m_crBg = RGBA(255, 255, 255, 255);
281 m_crHoverText = RGBA(0, 0x7A, 0xCC, 255);
282
283 m_pSkinDay = NULL;
284 m_pSkinWeek = NULL;
285 m_pSkinPrev = NULL;
286 m_pSkinNext = NULL;
288
289 TCHAR sztext[][4] = { _T("日"), _T("一"), _T("二"), _T("三"), _T("四"), _T("五"), _T("六") };
290 for (int i = 0; i < 7; i++)
291 {
292 m_strWeek[i].SetText(sztext[i]);
293 }
294}
295
297{
298 int nRet = SWindow::OnCreate(NULL);
299 if (nRet != 0)
300 return nRet;
301 for (int i = 0; i < 7; i++)
302 {
303 m_strWeek[i].SetOwner(this);
304 m_strWeek[i].TranslateText();
305 }
306 return nRet;
307}
308
310{
311 return m_iYear;
312}
313
315{
316 return m_iMonth;
317}
318
320{
322 return 1;
323
324 return m_arrDays[m_nSelItem].iDay;
325}
326
327void SCalendar::GetDate(WORD &iYear, WORD &iMonth, WORD &iDay)
328{
329 iYear = m_iYear;
330 iMonth = m_iMonth;
331 iDay = GetDay();
332}
333
334BOOL SCalendar::SetDate(WORD iYear, WORD iMonth, WORD iDay, int nBtnType, bool bNotify)
335{
336 short iWeek = SCalendarCore::GetDayOfWeek(iYear, iMonth, 1); // 计算出 当月 1号 是星期几
337 if (iWeek < 0)
338 return FALSE;
339
340 WORD nDayCount = SCalendarCore::GetDaysOfMonth(iYear, iMonth);
341
342 if (iWeek > 0) // 如果 不是星期天 先计算 上个月 的最后几天
343 {
344 WORD nFrontDayCount = 0;
345 if (1 == iMonth)
346 nFrontDayCount = SCalendarCore::GetDaysOfMonth(iYear - 1, 12);
347 else
348 nFrontDayCount = SCalendarCore::GetDaysOfMonth(iYear, iMonth - 1);
349
350 for (int i = 0; i < iWeek; ++i)
351 {
352 m_arrDays[i].nType = -1;
353 m_arrDays[i].iDay = nFrontDayCount - iWeek + i + 1;
354 }
355 }
356
357 // 计算 当月 的 天数 位置
358 for (int i = 0; i < nDayCount; ++i)
359 {
360 m_arrDays[iWeek + i].nType = 0;
361 m_arrDays[iWeek + i].iDay = i + 1;
362 }
363
364 int nNextDay = 1;
365 for (int i = iWeek + nDayCount; i < 42; ++i)
366 {
367 m_arrDays[i].nType = 1;
368 m_arrDays[i].iDay = nNextDay++;
369 }
370 m_iYear = iYear;
371 m_iMonth = iMonth;
372
374 m_nSelItem = iWeek % 7 + iDay - 1;
375 Invalidate();
376
377 if (bNotify)
378 {
379 EventCalendarExChanged evt(this);
380 evt.iNewDay = iDay;
381 evt.iNewMonth = m_iMonth;
382 evt.iNewYear = m_iYear;
383 evt.nBtnType = nBtnType;
384 FireEvent(evt);
385 }
386
387 return TRUE;
388}
389void SCalendar::SetShowType(int showType)
390{
391 m_showType = showType;
392}
393
395{
396 if (m_showType == SHOW_YEAR)
397 {
398 for (WORD i = 0; i < 12; i++)
399 {
400 m_arrMonthOrYear[i].iMonthOrYear = i + 1;
401 m_arrMonthOrYear[i].nType = 0;
402 }
403 //计算m_nSelItem
404 m_nSelItem = m_iMonth - 1;
405 }
407 {
408 //年代头年份
409 int decadeFirstYear = m_iYear - m_iYear % 10;
410 //计算 显示
411
412 m_arrMonthOrYear[0].iMonthOrYear = decadeFirstYear - 1;
413 m_arrMonthOrYear[0].nType = -1;
414
415 for (WORD i = 1; i <= 10; i++)
416 {
417 m_arrMonthOrYear[i].iMonthOrYear = decadeFirstYear + i - 1;
418 m_arrMonthOrYear[i].nType = 0;
419 }
420
421 m_arrMonthOrYear[11].iMonthOrYear = decadeFirstYear + 10;
422 m_arrMonthOrYear[11].nType = -1;
423
424 //计算m_nSelItem
425 m_nSelItem = m_iYear % 10 + 1;
426 }
427 else if (m_showType == SHOW_YEAR_CENTURY)
428 {
429 //世纪头 年份 2019 -19 = 2000
430 int centiryFirstYear = m_iYear - m_iYear % 100;
431 //计算 显示
432
433 m_arrMonthOrYear[0].iMonthOrYear = centiryFirstYear - 10;
434 m_arrMonthOrYear[0].nType = -1;
435
436 for (WORD i = 1; i <= 10; i++)
437 {
438 m_arrMonthOrYear[i].iMonthOrYear = centiryFirstYear + (i - 1) * 10;
439 m_arrMonthOrYear[i].nType = 0;
440 }
441
442 m_arrMonthOrYear[11].iMonthOrYear = centiryFirstYear + 100;
443 m_arrMonthOrYear[11].nType = -1;
444
445 //计算m_nSelItem
446 m_nSelItem = m_iYear % 100 / 10 + 1;
447 }
448}
449
451{
452 if (1 == m_iMonth)
453 {
454 m_iMonth = 12;
455 --m_iYear;
456 }
457 else
458 --m_iMonth;
459
460 SetDate(m_iYear, m_iMonth, 1, HIT_LEFT, true);
461}
462
464{
465 if (12 == m_iMonth)
466 {
467 m_iMonth = 1;
468 ++m_iYear;
469 }
470 else
471 ++m_iMonth;
472
473 SetDate(m_iYear, m_iMonth, 1, HIT_RIGHT, true);
474}
475
481
498{
499 if (m_iYear <= 1600)
500 {
501 return;
502 }
503 m_iYear -= 100;
505}
511
512void SCalendar::SetYearMonth(int iYear, int iMonth)
513{
514 m_iYear = iYear;
515 m_iMonth = iMonth;
517}
518
519void SCalendar::DrawYearMonth(IRenderTarget *pRT, const CRect &rect)
520{
521 if (rect.IsRectEmpty())
522 return;
523 int nHeight = m_nYearMonthHeight.toPixelSize(GetScale());
524
525 // 绘制 上一个 按钮
526 DWORD dwPrevState = 0;
527 if (HIT_LEFT == m_nHoverItem)
528 {
529 dwPrevState = 1;
530 }
531
532 if (m_pSkinPrev)
533 {
534 SIZE si = m_pSkinPrev->GetSkinSize();
535 int n = (nHeight - si.cy) / 2;
536 CRect rcItem = rect;
537 rcItem.left += n;
538 rcItem.right = rcItem.left + si.cx;
539 rcItem.top += n;
540 rcItem.bottom = rcItem.top + si.cy;
541 m_pSkinPrev->DrawByIndex(pRT, rcItem, dwPrevState);
542 }
543
544 // 绘制 年月
545 COLORREF crText = pRT->GetTextColor();
546 if (HIT_YEAR == m_nHoverItem)
547 {
549 }
550 else
551 pRT->SetTextColor(crText);
552
553 SStringT szYearMonth;
554 if (m_showType == SHOW_MONTH)
555 {
556 szYearMonth.Format(_T("%04d年%d月"), m_iYear, m_iMonth);
557 }
558 else if (m_showType == SHOW_YEAR)
559 {
560 szYearMonth.Format(_T("%04d年"), m_iYear);
561 }
562 else if (m_showType == SHOW_YEAR_DECADE)
563 {
564 //年代头年份
565 int decadeFirstYear = m_iYear - m_iYear % 10;
566 szYearMonth.Format(_T("%04d-%04d"), decadeFirstYear, decadeFirstYear + 9);
567 }
568 else if (m_showType == SHOW_YEAR_CENTURY)
569 {
570 //世纪头年份
571 int centuryFirstYear = m_iYear - m_iYear % 100;
572 szYearMonth.Format(_T("%04d-%04d"), centuryFirstYear, centuryFirstYear + 99);
573 }
574 CRect rc = rect;
575 pRT->DrawText(szYearMonth, -1, rc, DT_SINGLELINE | DT_VCENTER | DT_CENTER);
576
577 pRT->SetTextColor(crText);
578
579 // 绘制 下一个 按钮
580 DWORD dwNextState = 0;
581 if (HIT_RIGHT == m_nHoverItem)
582 {
583 dwNextState = 1;
584 }
585
586 if (m_pSkinNext)
587 {
588 SIZE si = m_pSkinNext->GetSkinSize();
589 int n = (nHeight - si.cy) / 2;
590 CRect rcItem = rect;
591 rcItem.right -= n;
592 rcItem.left = rcItem.right - si.cx;
593 rcItem.top += n;
594 rcItem.bottom = rcItem.top + si.cy;
595
596 m_pSkinNext->DrawByIndex(pRT, rcItem, dwNextState);
597 }
598}
599
600void SCalendar::DrawWeek(IRenderTarget *pRT, const CRect &rect)
601{
602 if (rect.IsRectEmpty())
603 return;
604 if (m_pSkinWeek)
605 {
606 m_pSkinWeek->DrawByIndex(pRT, rect, 0);
607 }
608 int nWid = rect.Width() / 7;
609 CRect rcItem = rect;
610 rcItem.right = rcItem.left + nWid;
611
612 COLORREF crTxt = pRT->GetTextColor();
613 for (int i = 0; i < 7; i++)
614 {
615 pRT->SetTextColor(crTxt);
616
617 pRT->DrawText(m_strWeek[i].GetText(FALSE), m_strWeek[i].GetText(FALSE).GetLength(), rcItem, DT_SINGLELINE | DT_VCENTER | DT_CENTER);
618 rcItem.OffsetRect(nWid, 0);
619 }
620 pRT->SetTextColor(crTxt);
621}
622
623void SCalendar::DrawDay(IRenderTarget *pRT, CRect &rcDay, int nItem)
624{
625 if (nItem < 0 || nItem >= 42)
626 return;
627
628 wDayInfo &dayInfo = m_arrDays[nItem];
629
630 COLORREF crText = pRT->GetTextColor();
631 CPoint ptRound(1, 1);
632
633 //
634
635 if (0 != dayInfo.nType)
636 {
638 }
639 else if (m_Today.wDay == dayInfo.iDay && m_Today.wYear == m_iYear && m_Today.wMonth == m_iMonth)
640 {
641 // today 框 就用 textcolor
642 pRT->DrawRoundRect(rcDay, ptRound);
643 }
644 DWORD dwState = 0;
645 if (m_nSelItem == nItem)
646 {
647 if (CR_INVALID != m_crSelDayBack)
648 pRT->FillSolidRoundRect(rcDay, ptRound, m_crSelDayBack);
649
650 if (CR_INVALID != m_crSelText)
652
653 dwState = 2;
654 }
655 else if (m_nHoverItem == nItem) //
656 {
658 dwState = 1;
659 }
660
661 if (NULL != m_pSkinDay)
662 m_pSkinDay->DrawByIndex(pRT, rcDay, dwState);
663
664 SStringT sDay;
665 sDay.Format(_T("%d"), dayInfo.iDay);
666 pRT->DrawText(sDay, -1, rcDay, DT_SINGLELINE | DT_VCENTER | DT_CENTER);
667
668 pRT->SetTextColor(crText);
669}
670
671void SCalendar::DrawToday(IRenderTarget *pRT, CRect &rcDay)
672{
673 if (rcDay.IsRectEmpty())
674 return;
675
676 COLORREF crText = pRT->GetTextColor();
677 if (HIT_TODAY == m_nHoverItem)
678 {
680 }
681
682 SStringT szToday;
683 szToday.Format(_T("今天:%04d/%d/%d"), m_Today.wYear, m_Today.wMonth, m_Today.wDay);
684 // CRect rc = rect;
685 m_rcToday = rcDay;
686 // 计算 文本
687 pRT->DrawText(szToday, -1, m_rcToday, DT_SINGLELINE | DT_VCENTER | DT_CENTER | DT_CALCRECT);
688 m_rcToday.bottom = m_rcToday.top + rcDay.Height(); //高度 不变
689 m_rcToday.OffsetRect((rcDay.Width() - m_rcToday.Width()) / 2, 0);
690 pRT->DrawText(szToday, -1, m_rcToday, DT_SINGLELINE | DT_VCENTER | DT_CENTER);
691 pRT->SetTextColor(crText);
692}
693
694void SCalendar::DrawYearDecadeCentury(IRenderTarget *pRT, const CRect &rect, int nItem)
695{
696 if (nItem < 0 || nItem >= 42)
697 return;
698
699 wMonthOrYearInfo &monthYearInfo = m_arrMonthOrYear[nItem];
700
701 COLORREF crText = pRT->GetTextColor();
702 CPoint ptRound(1, 1);
703
704 //
705
706 if (0 != monthYearInfo.nType)
707 {
709 }
710 // else if (m_Today.wDay == dayInfo.iDay && m_Today.wYear == m_iYear && m_Today.wMonth ==
711 // m_iMonth)
712 // {
713 // // today 框 就用 textcolor
714 // pRT->DrawRoundRect(rcDay, ptRound);
715 // }
716 DWORD dwState = 0;
717 if (m_nSelItem == nItem)
718 {
719 if (CR_INVALID != m_crSelDayBack)
720 pRT->FillSolidRoundRect(rect, ptRound, m_crSelDayBack);
721
722 if (CR_INVALID != m_crSelText)
724
725 dwState = 2;
726 }
727 else if (m_nHoverItem == nItem) //
728 {
730 dwState = 1;
731 }
732
733 if (NULL != m_pSkinDay)
734 m_pSkinDay->DrawByIndex(pRT, rect, dwState);
735
736 CRect rcItem = rect;
737 SStringT sDay;
738 if (m_showType == SHOW_YEAR)
739 {
740 sDay.Format(_T("%d月"), monthYearInfo.iMonthOrYear);
741 pRT->DrawText(sDay, sDay.GetLength(), rcItem, DT_SINGLELINE | DT_VCENTER | DT_CENTER);
742 }
743 else if (m_showType == SHOW_YEAR_DECADE)
744 {
745 sDay.Format(_T("%d"), monthYearInfo.iMonthOrYear);
746 pRT->DrawText(sDay, sDay.GetLength(), rcItem, DT_SINGLELINE | DT_VCENTER | DT_CENTER);
747 }
748 else if (m_showType == SHOW_YEAR_CENTURY)
749 {
750 sDay.Format(_T("%d-\n%d"), monthYearInfo.iMonthOrYear, monthYearInfo.iMonthOrYear + 9);
751 CRect rcTxt = rcItem;
752 pRT->DrawText(sDay, sDay.GetLength(), rcTxt, DT_CALCRECT);
753 rcItem.DeflateRect((rcItem.Width() - rcTxt.Width()) / 2, (rcItem.Height() - rcTxt.Height()) / 2);
754 pRT->DrawText(sDay, sDay.GetLength(), rcItem, 0);
755 }
756
757 pRT->SetTextColor(crText);
758}
759
761{
762 // 字体 都用 默认 的
763 if (m_showType == SHOW_MONTH)
764 {
765 OnPaintMonth(pRT);
766 }
768 {
770 }
771}
773{
774 SPainter painter;
775 BeforePaint(pRT, painter);
776
777 CRect rcClient;
778 GetClientRect(&rcClient);
779
780 CRect rcYear(rcClient); // 年月 区域
781 rcYear.bottom = rcYear.top + m_nYearMonthHeight.toPixelSize(GetScale());
782 DrawYearMonth(pRT, rcYear);
783
784 CRect rcWeek(rcClient); // 星期 区域
785 rcWeek.top = rcYear.bottom;
786 rcWeek.bottom = rcWeek.top + m_nWeekHeight.toPixelSize(GetScale());
787 DrawWeek(pRT, rcWeek);
788
789 // 计算 天
790 m_rcDays = rcClient;
791 m_rcDays.top = rcWeek.bottom;
792 m_rcDays.bottom = rcClient.bottom - m_nFooterHeight.toPixelSize(GetScale());
793
794 CRect rcItem;
795 for (int i = 0; i < 42; ++i)
796 {
797 GetItemRect(i, rcItem);
798 DrawDay(pRT, rcItem, i);
799 }
800
801 CRect rcToday(rcClient);
802 rcToday.top = m_rcDays.bottom;
803 DrawToday(pRT, rcToday);
804
805 AfterPaint(pRT, painter);
806}
808{
809 SPainter painter;
810 BeforePaint(pRT, painter);
811
812 CRect rcClient;
813 GetClientRect(&rcClient);
814
815 CRect rcYear(rcClient); // 年月 区域
816 rcYear.bottom = rcYear.top + m_nYearMonthHeight.toPixelSize(GetScale());
817 DrawYearMonth(pRT, rcYear);
818
819 CRect rcMonth(rcClient); // 中间月份 区域
820 rcMonth.top = rcYear.bottom;
821 rcMonth.bottom = rcClient.bottom - m_nFooterHeight.toPixelSize(GetScale());
822
823 CRect rcItem;
824 int iWidth = rcMonth.Width() / 4;
825 int iHeight = rcMonth.Height() / 3;
826 for (int i = 0; i < 12; i++)
827 {
828 rcItem.left = rcMonth.left + i % 4 * iWidth;
829 rcItem.top = rcMonth.top + i / 4 * iHeight;
830 rcItem.right = rcItem.left + iWidth;
831 rcItem.bottom = rcItem.top + iHeight;
832 DrawYearDecadeCentury(pRT, rcItem, i);
833 }
834
835 // 计算 今天
836 CRect rcToday(rcClient);
837 rcToday.top = rcMonth.bottom;
838 DrawToday(pRT, rcToday);
839
840 AfterPaint(pRT, painter);
841}
842
843void SCalendar::OnLButtonDown(UINT nFlags, CPoint point)
844{
845 __baseCls::OnLButtonDown(nFlags, point);
846 int nItem = HitTest(point);
847 if (nItem < 0)
848 {
849 if (HIT_LEFT == nItem)
850 {
851 if (m_showType == SHOW_MONTH)
852 {
853 SetLastMonth();
854 }
855 else if (m_showType == SHOW_YEAR)
856 {
857 SetLastYear();
858 }
859 else if (m_showType == SHOW_YEAR_DECADE)
860 {
862 }
863 else if (m_showType == SHOW_YEAR_CENTURY)
864 {
866 }
867 }
868 else if (HIT_RIGHT == nItem)
869 {
870 if (m_showType == SHOW_MONTH)
871 {
872 SetNextMonth();
873 }
874 else if (m_showType == SHOW_YEAR)
875 {
876 SetNextYear();
877 }
878 else if (m_showType == SHOW_YEAR_DECADE)
879 {
881 }
882 else if (m_showType == SHOW_YEAR_CENTURY)
883 {
885 }
886 }
887 else if (HIT_YEAR == nItem)
888 {
890 {
891 m_showType--;
892 }
894 }
895 }
896 else if (HIT_TODAY == nItem)
897 {
899 SetDate(m_Today.wYear, m_Today.wMonth, m_Today.wDay, HIT_TODAY, true);
900 }
901 else // if (m_nSelItem != nItem)
902 {
904 if (m_showType == SHOW_MONTH)
905 {
906 wDayInfo &dayInfo = m_arrDays[nItem];
907
908 m_nSelItem = nItem;
909 EventCalendarExChanged evt(this);
910 evt.nBtnType = nItem; // 天数 就是 0-41
911 evt.iNewDay = dayInfo.iDay;
912 if (dayInfo.nType < 0) // 点击 上一个月 的天
913 {
914 if (1 == m_iMonth)
915 {
916 m_iMonth = 12;
917 --m_iYear;
918 }
919 else
920 --m_iMonth;
921 }
922 else if (dayInfo.nType > 0) //点击 下一个月 的 天
923 {
924 if (12 == m_iMonth)
925 {
926 m_iMonth = 1;
927 ++m_iYear;
928 }
929 else
930 ++m_iMonth;
931 }
932
933 evt.iNewMonth = m_iMonth;
934 evt.iNewYear = m_iYear;
935 FireEvent(evt);
936 }
937 else
938 {
939 m_nSelItem = nItem;
940 wMonthOrYearInfo &info = m_arrMonthOrYear[nItem];
941
942 int tmpYear = 0, tmpMonth = 0;
943
944 if (m_showType == SHOW_YEAR)
945 {
946 tmpYear = m_iYear;
947 tmpMonth = info.iMonthOrYear;
948 }
949 else if (m_showType == SHOW_YEAR_DECADE)
950 {
951 tmpYear = info.iMonthOrYear;
952 tmpMonth = m_iMonth;
953 }
954 else if (m_showType == SHOW_YEAR_CENTURY)
955 {
956 tmpYear = info.iMonthOrYear;
957 tmpMonth = m_iMonth;
958 }
959 if (m_showType != SHOW_MONTH)
960 {
961 m_showType++;
962 }
963 if (m_showType != SHOW_MONTH)
964 {
965 SetYearMonth(tmpYear, tmpMonth);
966 }
967 else
968 {
969 SetDate(tmpYear, tmpMonth, 1, HIT_NULL);
970 }
971 }
972 }
973 Invalidate();
974}
975
976void SCalendar::OnLButtonUp(UINT nFlags, CPoint point)
977{
978 int nItem = HitTest(point);
979 // 只有在显示天数, 点击天 才 发送 cmd 事件 使dropwnd关闭
980 //其他情况,让event mute静止
981 if (!(m_showType == SHOW_MONTH && m_showTypeLbdown == SHOW_MONTH && nItem >= 0 && nItem < 42))
982 {
983 GetEventSet()->setMutedState(true);
984 }
985
986 __baseCls::OnLButtonUp(nFlags, point);
987
988 if (!(m_showType == SHOW_MONTH && m_showTypeLbdown == SHOW_MONTH && nItem >= 0 && nItem < 42))
989 {
990 GetEventSet()->setMutedState(false);
991 }
992}
993
994void SCalendar::OnMouseMove(UINT nFlags, CPoint pt)
995{
996 int nItem = HitTest(pt);
997 m_nHoverItem = nItem;
998 Invalidate();
999}
1000
1002{
1004 Invalidate();
1005}
1006
1007BOOL SCalendar::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
1008{
1009 if (zDelta > 0) // 上滚 上一个
1010 {
1011 if (m_showType == SHOW_MONTH)
1012 {
1013 SetLastMonth();
1014 }
1015 else if (m_showType == SHOW_YEAR)
1016 {
1017 SetLastYear();
1018 }
1019 else if (m_showType == SHOW_YEAR_DECADE)
1020 {
1022 }
1023 else if (m_showType == SHOW_YEAR_CENTURY)
1024 {
1026 }
1027 }
1028 else // 下滚 下一个
1029 {
1030 if (m_showType == SHOW_MONTH)
1031 {
1032 SetNextMonth();
1033 }
1034 else if (m_showType == SHOW_YEAR)
1035 {
1036 SetNextYear();
1037 }
1038 else if (m_showType == SHOW_YEAR_DECADE)
1039 {
1041 }
1042 else if (m_showType == SHOW_YEAR_CENTURY)
1043 {
1045 }
1046 }
1047
1048 return TRUE;
1049}
1050
1051int SCalendar::HitTest(const CPoint &pt)
1052{
1053 if (m_showType == SHOW_MONTH)
1054 {
1055 if (pt.y < m_rcDays.top) // 小于 表示 在 天 的上面
1056 {
1057 if (pt.y > (m_rcDays.top - m_nWeekHeight.toPixelSize(GetScale())))
1058 return HIT_NULL;
1059
1060 int nYearHei = m_nYearMonthHeight.toPixelSize(GetScale());
1061 if ((pt.x - m_rcDays.left) < nYearHei)
1062 return HIT_LEFT;
1063 else if ((m_rcDays.right - pt.x) < nYearHei)
1064 return HIT_RIGHT;
1065
1066 return HIT_YEAR;
1067 }
1068 else if (pt.y > m_rcDays.bottom)
1069 {
1070 if (m_rcToday.PtInRect(pt))
1071 return HIT_TODAY;
1072
1073 return 43;
1074 }
1075
1076 int nDay_X = pt.x - m_rcDays.left;
1077 int nDay_Y = pt.y - m_rcDays.top;
1078 int nWid = m_rcDays.Width() / 7;
1079 int nHei = m_rcDays.Height() / 6;
1080
1081 int nRow = nDay_X / nWid;
1082 if (nRow > 6) // 处理 边缘
1083 nRow = 6;
1084
1085 return nRow + (nDay_Y / nHei) * 7;
1086 }
1088 {
1089 //多出星期的高度
1090 CRect rcDays = m_rcDays;
1091 rcDays.top = rcDays.top - m_nWeekHeight.toPixelSize(GetScale());
1092
1093 if (pt.y < rcDays.top) // 小于 表示 在 天 的上面
1094 {
1095 int nYearHei = m_nYearMonthHeight.toPixelSize(GetScale());
1096 if ((pt.x - rcDays.left) < nYearHei)
1097 return HIT_LEFT;
1098 else if ((rcDays.right - pt.x) < nYearHei)
1099 return HIT_RIGHT;
1100
1101 return HIT_YEAR;
1102 }
1103 else if (pt.y > rcDays.bottom)
1104 {
1105 if (m_rcToday.PtInRect(pt))
1106 return HIT_TODAY;
1107
1108 return 43;
1109 }
1110
1111 int nDay_X = pt.x - rcDays.left;
1112 int nDay_Y = pt.y - rcDays.top;
1113 int nWid = m_rcDays.Width() / 4;
1114 int nHei = m_rcDays.Height() / 3;
1115
1116 int nRow = nDay_X / nWid;
1117 if (nRow > 3) // 处理 边缘
1118 nRow = 3;
1119
1120 return nRow + (nDay_Y / nHei) * 4;
1121 }
1122 return 43;
1123}
1124
1125void SCalendar::GetItemRect(int nItem, CRect &rcItem)
1126{
1127 int nItemWidth = m_rcDays.Width() / 7;
1128 int nItemHeight = m_rcDays.Height() / 6;
1129
1130 rcItem.left = (nItem % 7) * nItemWidth;
1131 rcItem.right = rcItem.left + nItemWidth;
1132
1133 rcItem.top = (nItem / 7) * nItemHeight;
1134 rcItem.bottom = rcItem.top + nItemHeight;
1135 rcItem.OffsetRect(m_rcDays.TopLeft());
1136}
1137SNSEND
Calendar Control.
#define HIT_LEFT
Definition SCalendar.h:116
#define SHOW_MONTH
Definition SCalendar.h:125
#define HIT_YEAR
Definition SCalendar.h:118
#define SHOW_YEAR_DECADE
Definition SCalendar.h:127
#define SHOW_YEAR_CENTURY
Definition SCalendar.h:128
#define HIT_RIGHT
Definition SCalendar.h:117
#define SHOW_YEAR
Definition SCalendar.h:126
#define HIT_NULL
Definition SCalendar.h:115
#define HIT_TODAY
Definition SCalendar.h:122
static BOOL DateCheck(WORD wYear, WORD wMonth, WORD wDay)
Validates the year, month, and day.
static WORD GetDaysOfMonth(WORD wYear, WORD wMonth)
Returns the number of days in a specified month.
static BOOL GetDaysNumInYear(WORD wYear, WORD wMonth, WORD wDay, WORD &wDays)
Calculates the day number within the year (starting from 0, where 0 is January 1st).
Definition SCalendar.cpp:63
static short GetDayOfWeek(WORD wYear, WORD wMonth, WORD wDay)
Returns the day of the week.
static SStringT FormatYear(WORD iYear)
Formats the year display.
static BOOL GetDateFromDays(WORD wYear, WORD wDays, WORD &wMonth, WORD &wDay)
Calculates the month and day from the day number within the year.
Definition SCalendar.cpp:86
static SStringT FormatDay(WORD iDay)
Formats the day display.
static SStringT FormatMonth(WORD iMonth)
Formats the month display.
static BOOL IsLeapYear(WORD wYear, BOOL &bLeapYear)
Determines if a year is a leap year.
Definition SCalendar.cpp:46
COLORREF m_crSelDayBack
Background color of the selected day.
Definition SCalendar.h:439
void DrawToday(IRenderTarget *pRT, CRect &rcDay)
Draws the "Today" button.
void SetShowType(int showType)
Sets the calendar display type.
SAutoRefPtr< ISkinObj > m_pSkinNext
Skin for the next button.
Definition SCalendar.h:454
void SetYearDecadeCentury()
Sets the year, decade, and century views.
int m_showTypeLbdown
Calendar display state when mouse button is down.
Definition SCalendar.h:528
int m_nSelItem
Selected item.
Definition SCalendar.h:498
SLayoutSize m_nFooterHeight
Height of the "Today" button.
Definition SCalendar.h:424
SAutoRefPtr< ISkinObj > m_pSkinDay
Skin for the day.
Definition SCalendar.h:459
void SetNextYearCentury()
Sets the next century.
SYSTEMTIME m_Today
Current date.
Definition SCalendar.h:518
void SetNextYearDecade()
Sets the next decade.
void SetYearMonth(int iYear, int iMonth)
Sets the year and month.
int m_nHoverItem
Hover item.
Definition SCalendar.h:503
SAutoRefPtr< ISkinObj > m_pSkinPrev
Skin for the previous button.
Definition SCalendar.h:449
WORD m_iYear
Current year.
Definition SCalendar.h:508
void Init()
Initializes the control.
CRect m_rcToday
"Today" button area.
Definition SCalendar.h:493
int HitTest(const CPoint &pt)
Tests the mouse click position.
void SetNextYear()
Sets the next year.
void OnPaint(IRenderTarget *pRT)
Paints the control.
void DrawWeek(IRenderTarget *pRT, const CRect &rect)
Draws the week days.
void SetLastYear()
Sets the previous year.
void DrawYearMonth(IRenderTarget *pRT, const CRect &rect)
Draws the calendar header (year and month).
virtual HRESULT OnLanguageChanged()
Called when the language changes.
COLORREF m_crHoverText
Color of the hover text.
Definition SCalendar.h:444
void OnPaintMonth(IRenderTarget *pRT)
Paints the month view.
BOOL SetDate(WORD iYear, WORD iMonth, WORD iDay, int nBtnType=-1, bool bNotify=false)
Sets the date.
void SetLastYearCentury()
Sets the previous century.
void OnPaintYearDecadeCentury(IRenderTarget *pRT)
Paints the year, decade, and century views.
void GetDate(WORD &iYear, WORD &iMonth, WORD &iDay)
Gets the current date.
~SCalendar()
Destructor.
int m_showType
Calendar display state.
Definition SCalendar.h:523
void OnMouseMove(UINT nFlags, CPoint pt)
Handles mouse move event.
CRect m_rcDays
Date area.
Definition SCalendar.h:488
STrText m_strWeek[7]
Header text.
Definition SCalendar.h:469
SCalendar()
Default constructor.
void SetLastMonth()
Sets the previous month.
SLayoutSize m_nYearMonthHeight
Height of the year and month.
Definition SCalendar.h:414
void OnMouseLeave()
Handles mouse leave event.
void OnLButtonUp(UINT nFlags, CPoint point)
Handles left mouse button up event.
void OnLButtonDown(UINT nFlags, CPoint point)
Handles left mouse button down event.
void SetLastYearDecade()
Sets the previous decade.
wDayInfo m_arrDays[42]
Date information array.
Definition SCalendar.h:483
COLORREF m_crSelText
Selected text color.
Definition SCalendar.h:429
void SetNextMonth()
Sets the next month.
COLORREF m_crOtherDayText
Color of other days' text.
Definition SCalendar.h:434
wMonthOrYearInfo m_arrMonthOrYear[12]
Month or year information array.
Definition SCalendar.h:542
WORD GetMonth()
Gets the current month.
void GetItemRect(int nItem, CRect &rcItem)
Gets the item drawing area.
WORD m_iMonth
Current month.
Definition SCalendar.h:513
SLayoutSize m_nWeekHeight
Height of the week.
Definition SCalendar.h:419
BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
Handles mouse wheel event.
WORD GetDay()
Gets the current day.
SAutoRefPtr< ISkinObj > m_pSkinWeek
Skin for the week.
Definition SCalendar.h:464
WORD GetYear()
Gets the current year.
void DrawYearDecadeCentury(IRenderTarget *pRT, const CRect &rect, int nItem)
Draws the year, decade, and century items.
void DrawDay(IRenderTarget *pRT, CRect &rcDay, int nItem)
Draws the day.
int OnCreate(LPVOID lp)
Called when the control is created.
void setMutedState(BOOL setting)
设置事件集的静音状态
Helper class for painting.
Definition SWnd.h:178
时间类
Definition STime.h:160
static STime GetCurrentTime()
获取当前时间
Definition stime.cpp:184
int GetYear() const
获取年份
Definition stime.cpp:212
int GetDay() const
获取日
Definition stime.cpp:224
int GetMonth() const
获取月份
Definition stime.cpp:218
BOOL FireEvent(IEvtArgs *evt) OVERRIDE
Fires an event.
Definition Swnd.cpp:1540
int GetScale() SCONST OVERRIDE
Retrieves the scale factor of the window.
Definition Swnd.cpp:3266
int OnCreate(LPVOID)
Handles the creation of the window.
Definition Swnd.cpp:1654
virtual CRect GetClientRect() const
Retrieves the client rectangle of the window.
Definition Swnd.cpp:243
virtual void BeforePaint(IRenderTarget *pRT, SPainter &painter)
Prepare rendering environment.
Definition Swnd.cpp:1755
BOOL m_bFocusable
Definition SWnd.h:2609
virtual void AfterPaint(IRenderTarget *pRT, SPainter &painter)
Restore rendering environment.
Definition Swnd.cpp:1776
SEventSet * GetEventSet()
Retrieves the event set associated with the window.
Definition SWnd.h:1290
void Invalidate() OVERRIDE
Invalidates the entire window.
Definition Swnd.cpp:1437
SEventSet m_evtSet
Definition SWnd.h:2581
const SwndStyle & GetStyle() const
Retrieves the style of the window.
Definition Swnd.cpp:716
COLORREF m_crBg
Definition SWndStyle.h:58
Interface for rendering target objects.
Definition SRender-i.h:1440
HRESULT DrawText(LPCTSTR pszText, int cchLen, LPRECT pRc, UINT uFormat) PURE
Draw text within a rectangle.
HRESULT FillSolidRoundRect(LPCRECT pRect, POINT pt, COLORREF cr) PURE
Fill a rounded rectangle with a solid color.
HRESULT DrawRoundRect(LPCRECT pRect, POINT pt) PURE
Draw a rounded rectangle outline.
COLORREF GetTextColor() PURE
Retrieves the current text color.
COLORREF SetTextColor(COLORREF color) PURE
Sets the current text color.
Date information structure.
Definition SCalendar.h:475
Month or year information structure.
Definition SCalendar.h:534