⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 monthcal.c

📁 ReactOS是一些高手根据Windows XP的内核编写出的类XP。内核实现机理和API函数调用几乎相同。甚至可以兼容XP的程序。喜欢研究系统内核的人可以看一看。
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
 * PROJECT:     ReactOS Timedate Control Panel
 * LICENSE:     GPL - See COPYING in the top level directory
 * FILE:        lib/cpl/timedate/monthcal.c
 * PURPOSE:     Calander implementation
 * COPYRIGHT:   Copyright 2006 Thomas Weidenmueller <w3seek@reactos.com>
 *
 */

#include <timedate.h>

static const WCHAR szMonthCalWndClass[] = L"MonthCalWnd";

#define MONTHCAL_HEADERBG   COLOR_INACTIVECAPTION
#define MONTHCAL_HEADERFG   COLOR_INACTIVECAPTIONTEXT
#define MONTHCAL_CTRLBG     COLOR_WINDOW
#define MONTHCAL_CTRLFG     COLOR_WINDOWTEXT
#define MONTHCAL_SELBG      COLOR_ACTIVECAPTION
#define MONTHCAL_SELFG      COLOR_CAPTIONTEXT
#define MONTHCAL_DISABLED_HEADERBG  COLOR_INACTIVECAPTION
#define MONTHCAL_DISABLED_HEADERFG  COLOR_INACTIVECAPTIONTEXT
#define MONTHCAL_DISABLED_CTRLBG    COLOR_WINDOW
#define MONTHCAL_DISABLED_CTRLFG    COLOR_WINDOWTEXT
#define MONTHCAL_DISABLED_SELBG     COLOR_INACTIVECAPTION
#define MONTHCAL_DISABLED_SELFG     COLOR_INACTIVECAPTIONTEXT

#define ID_DAYTIMER 1

typedef struct _MONTHCALWND
{
    HWND hSelf;
    HWND hNotify;
    WORD Day;
    WORD Month;
    WORD Year;
    WORD FirstDayOfWeek;
    BYTE Days[6][7];
    WCHAR Week[7];
    SIZE CellSize;
    SIZE ClientSize;

    HFONT hFont;
    HBRUSH hbHeader;
    HBRUSH hbSelection;

    DWORD UIState;
    UINT Changed : 1;
    UINT DayTimerSet : 1;
    UINT Enabled : 1;
    UINT HasFocus : 1;
} MONTHCALWND, *PMONTHCALWND;

static LRESULT
MonthCalNotifyControlParent(IN PMONTHCALWND infoPtr,
                            IN UINT code,
                            IN OUT PVOID data)
{
    LRESULT Ret = 0;

    if (infoPtr->hNotify != NULL)
    {
        LPNMHDR pnmh = (LPNMHDR)data;

        pnmh->hwndFrom = infoPtr->hSelf;
        pnmh->idFrom = GetWindowLongPtrW(infoPtr->hSelf,
                                         GWLP_ID);
        pnmh->code = code;

        Ret = SendMessageW(infoPtr->hNotify,
                           WM_NOTIFY,
                           (WPARAM)pnmh->idFrom,
                           (LPARAM)pnmh);
    }

    return Ret;
}

static WORD
MonthCalMonthLength(IN WORD Month,
                    IN WORD Year)
{
    const BYTE MonthDays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0};

    if(Month == 2)
        return MonthDays[Month - 1] + ((Year % 400 == 0) ? 1 : ((Year % 100 != 0) && (Year % 4 == 0)) ? 1 : 0);
    else
        return MonthDays[Month - 1];
}

static WORD
MonthCalWeekInMonth(IN WORD Day,
                    IN WORD DayOfWeek)
{
    return (Day - DayOfWeek + 5) / 7;
}

static WORD
MonthCalDayOfWeek(IN PMONTHCALWND infoPtr,
                  IN WORD Day,
                  IN WORD Month,
                  IN WORD Year)
{
    const BYTE DayOfWeek[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
    WORD Ret;

    Year -= (Month < 3);
    Ret = (Year + (Year / 4) - (Year / 100) + (Year / 400) + DayOfWeek[Month - 1] + Day + 6) % 7;

    return (7 + Ret - infoPtr->FirstDayOfWeek) % 7;
}

static WORD
MonthCalFirstDayOfWeek(VOID)
{
    WCHAR szBuf[2] = {0};
    WORD Ret = 0;

    if (GetLocaleInfoW(LOCALE_USER_DEFAULT,
                       LOCALE_IFIRSTDAYOFWEEK,
                       szBuf,
                       sizeof(szBuf) / sizeof(szBuf[0])) != 0)
    {
        Ret = (WORD)(szBuf[0] - TEXT('0'));
    }

    return Ret;
}

static BOOL
MonthCalValidDate(IN WORD Day,
                  IN WORD Month,
                  IN WORD Year)
{
    if (Month < 1 || Month > 12 ||
        Day == 0 || Day > MonthCalMonthLength(Month,
                                              Year) ||
        Year < 1980 || Year > 2099)
    {
        return FALSE;
    }

    return TRUE;
}

static VOID
MonthCalUpdate(IN PMONTHCALWND infoPtr)
{
    PBYTE pDay, pDayEnd;
    WORD DayOfWeek, MonthLength, d = 0;
    SIZE NewCellSize;
    BOOL RepaintHeader = FALSE;

    NewCellSize.cx = infoPtr->ClientSize.cx / 7;
    NewCellSize.cy = infoPtr->ClientSize.cy / 7;

    if (infoPtr->CellSize.cx != NewCellSize.cx ||
        infoPtr->CellSize.cy != NewCellSize.cy)
    {
        infoPtr->CellSize = NewCellSize;
        RepaintHeader = TRUE;
    }

    /* update the days layout of the current month */
    ZeroMemory(infoPtr->Days,
               sizeof(infoPtr->Days));

    DayOfWeek = MonthCalDayOfWeek(infoPtr,
                                  1,
                                  infoPtr->Month,
                                  infoPtr->Year);

    MonthLength = MonthCalMonthLength(infoPtr->Month,
                                      infoPtr->Year);

    pDay = &infoPtr->Days[0][DayOfWeek];
    pDayEnd = pDay + MonthLength;
    while (pDay != pDayEnd)
    {
        *(pDay++) = (BYTE)++d;
    }

    /* repaint the control */
    if (RepaintHeader)
    {
        InvalidateRect(infoPtr->hSelf,
                       NULL,
                       TRUE);
    }
    else
    {
        RECT rcClient;

        rcClient.left = 0;
        rcClient.top = infoPtr->CellSize.cy;
        rcClient.right = infoPtr->ClientSize.cx;
        rcClient.bottom = infoPtr->ClientSize.cy;

        InvalidateRect(infoPtr->hSelf,
                       &rcClient,
                       TRUE);
    }
}

static VOID
MonthCalSetupDayTimer(IN PMONTHCALWND infoPtr)
{
    SYSTEMTIME LocalTime = {0};
    UINT uElapse;

    /* update the current date */
    GetLocalTime(&LocalTime);

    /* calculate the number of remaining milliseconds until midnight */
    uElapse = 1000 - (UINT)LocalTime.wMilliseconds;
    uElapse += (59 - (UINT)LocalTime.wSecond) * 1000;
    uElapse += (59 - (UINT)LocalTime.wMinute) * 60 * 1000;
    uElapse += (23 - (UINT)LocalTime.wHour) * 60 * 60 * 1000;

    if (uElapse < USER_TIMER_MINIMUM || uElapse > USER_TIMER_MAXIMUM)
        uElapse = 1000;
    else
        uElapse += 100; /* Add a delay of 0.1 seconds */

    /* setup the new timer */
    if (SetTimer(infoPtr->hSelf,
                 ID_DAYTIMER,
                 uElapse,
                 NULL) != 0)
    {
        infoPtr->DayTimerSet = TRUE;
    }
}

static VOID
MonthCalReload(IN PMONTHCALWND infoPtr)
{
    WCHAR szBuf[64];
    UINT i;

    infoPtr->UIState = (DWORD)SendMessageW(GetAncestor(infoPtr->hSelf,
                                                       GA_PARENT),
                                            WM_QUERYUISTATE,
                                            0,
                                            0);

    /* cache the configuration */
    infoPtr->FirstDayOfWeek = MonthCalFirstDayOfWeek();

    infoPtr->hbHeader = GetSysColorBrush(infoPtr->Enabled ? MONTHCAL_HEADERBG : MONTHCAL_DISABLED_HEADERBG);
    infoPtr->hbSelection = GetSysColorBrush(infoPtr->Enabled ? MONTHCAL_SELBG : MONTHCAL_DISABLED_SELBG);

    for (i = 0; i < 7; i++)
    {
        if (GetLocaleInfoW(LOCALE_USER_DEFAULT,
                           LOCALE_SABBREVDAYNAME1 +
                               ((i + infoPtr->FirstDayOfWeek) % 7),
                           szBuf,
                           sizeof(szBuf) / sizeof(szBuf[0])) != 0)
        {
            infoPtr->Week[i] = szBuf[0];
        }
    }

    /* update the control */
    MonthCalUpdate(infoPtr);
}

static BOOL
MonthCalGetDayRect(IN PMONTHCALWND infoPtr,
                   IN WORD Day,
                   OUT RECT *rcCell)
{
    if (Day >= 1 && Day <= MonthCalMonthLength(infoPtr->Month,
                                               infoPtr->Year))
    {
        WORD DayOfWeek;

        DayOfWeek = MonthCalDayOfWeek(infoPtr,
                                      Day,
                                      infoPtr->Month,
                                      infoPtr->Year);

        rcCell->left = DayOfWeek * infoPtr->CellSize.cx;
        rcCell->top = (MonthCalWeekInMonth(Day,
                                           DayOfWeek) + 1) * infoPtr->CellSize.cy;
        rcCell->right = rcCell->left + infoPtr->CellSize.cx;
        rcCell->bottom = rcCell->top + infoPtr->CellSize.cy;

        return TRUE;
    }

    return FALSE;
}

static VOID
MonthCalChange(IN PMONTHCALWND infoPtr)
{
    infoPtr->Changed = TRUE;

    /* kill the day timer */
    if (infoPtr->DayTimerSet)
    {
        KillTimer(infoPtr->hSelf,
                  ID_DAYTIMER);
        infoPtr->DayTimerSet = FALSE;
    }
}


static BOOL
MonthCalSetDate(IN PMONTHCALWND infoPtr,
                IN WORD Day,
                IN WORD Month,
                IN WORD Year)
{
    NMMCCSELCHANGE sc;
    BOOL Ret = FALSE;

    sc.OldDay = infoPtr->Day;
    sc.OldMonth = infoPtr->Month;
    sc.OldYear = infoPtr->Year;
    sc.NewDay = Day;
    sc.NewMonth = Month;
    sc.NewYear = Year;

    /* notify the parent */
    if (!MonthCalNotifyControlParent(infoPtr,
                                     MCCN_SELCHANGE,
                                     &sc))
    {
        /* check if we actually need to update */
        if (infoPtr->Month != sc.NewMonth ||
            infoPtr->Year != sc.NewYear)
        {
            infoPtr->Day = sc.NewDay;
            infoPtr->Month = sc.NewMonth;
            infoPtr->Year = sc.NewYear;

            MonthCalChange(infoPtr);

            /* repaint the entire control */
            MonthCalUpdate(infoPtr);

            Ret = TRUE;
        }
        else if (infoPtr->Day != sc.NewDay)
        {
            RECT rcUpdate;

            infoPtr->Day = sc.NewDay;

            MonthCalChange(infoPtr);

            if (MonthCalGetDayRect(infoPtr,
                                   sc.OldDay,
                                   &rcUpdate))
            {
                /* repaint the day cells that need to be updated */
                InvalidateRect(infoPtr->hSelf,
                               &rcUpdate,
                               TRUE);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -