400 lines
14 KiB
C
400 lines
14 KiB
C
|
#define CAL_COLOR_TODAY 0x000000ff
|
||
|
|
||
|
#define CALMONTHMAX 12
|
||
|
#define CALROWMAX 6
|
||
|
#define CALCOLMAX 7
|
||
|
#define CAL_DEF_SELMAX 7
|
||
|
|
||
|
// Bug#94368 - these metrics do not scale with user settings
|
||
|
#define CALBORDER 6
|
||
|
|
||
|
// The formulas for DX_ARROWMARGIN and D[XY]_CALARROW are chosen so on most
|
||
|
// systems they come out approximately equal to the values you got
|
||
|
// in IE4. (The IE4 values were hard-coded and therefore incompatible
|
||
|
// with accessibility.)
|
||
|
|
||
|
#define DX_ARROWMARGIN (5 * g_cxBorder)
|
||
|
#define DX_CALARROW (g_cyHScroll * 4 / 3)
|
||
|
#define DY_CALARROW g_cyHScroll
|
||
|
|
||
|
#define DXRING_SPIRAL 8
|
||
|
#define DXEDGE_SPIRAL 8
|
||
|
|
||
|
// Bug#94368 - msecautospin should scale on doubleclicktime
|
||
|
#define CAL_MSECAUTOSPIN 350
|
||
|
#define CAL_SECTODAYTIMER (2 * 60)
|
||
|
#define CAL_IDAUTOSPIN 1
|
||
|
#define CAL_TODAYTIMER 2
|
||
|
|
||
|
#define CCHMAXMONTH 42
|
||
|
#define CCHMAXABBREVDAY 11
|
||
|
#define CCHMAXMARK 10
|
||
|
|
||
|
#define SEL_BEGIN 1
|
||
|
#define SEL_END 2
|
||
|
#define SEL_DOT 3
|
||
|
#define SEL_MID 4
|
||
|
|
||
|
//
|
||
|
// For each month we display, we have to compute a bunch of metrics
|
||
|
// to track the stuff we put into the header area.
|
||
|
//
|
||
|
// The five values represent the following points in the string:
|
||
|
//
|
||
|
// Mumble January Mumble 1999 Mumble
|
||
|
// | | | | |
|
||
|
// | | MonthEnd | YearEnd
|
||
|
// Start MonthStart YearStart
|
||
|
//
|
||
|
// Note that it is possible for YearStart to be less than MonthStart if the
|
||
|
// year comes before the month. (e.g., "1999 January")
|
||
|
//
|
||
|
// These values already take RTL mirroring into account.
|
||
|
//
|
||
|
// NOTE! IMM_MONTHSTART and IMM_YEARSTART are also used as flags,
|
||
|
// so they both need to be powers of 2.
|
||
|
//
|
||
|
#define IMM_START 0
|
||
|
#define IMM_DATEFIRST 1
|
||
|
#define IMM_MONTHSTART 1
|
||
|
#define IMM_YEARSTART 2
|
||
|
#define IMM_MONTHEND 3
|
||
|
#define IMM_YEAREND 4
|
||
|
#define IMM_DATELAST 4
|
||
|
#define DMM_STARTEND 2 // Difference between START and END
|
||
|
#define CCH_MARKERS 4 // There are four markers
|
||
|
|
||
|
typedef struct MONTHMETRICS {
|
||
|
int rgi[5];
|
||
|
} MONTHMETRICS, *PMONTHMETRICS;
|
||
|
|
||
|
// This stuff used to be global
|
||
|
typedef struct tagLOCALEINFO {
|
||
|
TCHAR szToday[32]; // "Today:"
|
||
|
TCHAR szGoToToday[64]; // "&Go to today"
|
||
|
|
||
|
TCHAR szMonthFmt[8]; // "MMMM"
|
||
|
TCHAR szMonthYearFmt[16+CCH_MARKERS]; // "\1MMMM\3 \2yyyy\4" -- see MCInsertMarkers
|
||
|
|
||
|
TCHAR rgszMonth[12][CCHMAXMONTH];
|
||
|
TCHAR rgszDay[7][CCHMAXABBREVDAY];
|
||
|
int dowStartWeek; // LOCALE_IFIRSTDAYOFWEEK (0 = mon, 1 = tue, 6 = sat)
|
||
|
int firstWeek; // LOCALE_IFIRSTWEEKOFYEAR
|
||
|
|
||
|
TCHAR *rgpszMonth[12]; // pointers into rgszMonth
|
||
|
TCHAR *rgpszDay[7]; // pointers into rgszDay
|
||
|
} LOCALEINFO, *PLOCALEINFO, *LPLOCALEINFO;
|
||
|
|
||
|
|
||
|
//
|
||
|
// SUBEDITCONTROL stuff
|
||
|
//
|
||
|
|
||
|
//
|
||
|
// Note: SECIncrFocus assumes that SUBEDIT_NONE is numerical value -1
|
||
|
//
|
||
|
#define SUBEDIT_NONE -1 // no field is being edited
|
||
|
#define SUBEDIT_ALL -2 // all fields are being edited (DTS_APPCANPARSE)
|
||
|
enum {
|
||
|
SE_ERA = 1,
|
||
|
SE_YEAR,
|
||
|
SE_YEARALT, // see SEGetTimeDateFormat
|
||
|
SE_MONTH,
|
||
|
SE_MONTHALT, // see SEGetTimeDateFormat
|
||
|
SE_DAY,
|
||
|
SE_DATELAST = SE_DAY,
|
||
|
SE_MARK, // "AM" or "PM" indicator
|
||
|
SE_HOUR,
|
||
|
SE_MINUTE,
|
||
|
SE_SECOND,
|
||
|
SE_STATIC,
|
||
|
SE_APP,
|
||
|
SE_MAX
|
||
|
};
|
||
|
|
||
|
#define SE_YEARLIKE(s) ((s) == SE_YEAR || (s) == SE_YEARALT)
|
||
|
#define SE_DATELIKE(s) InRange(s, SE_ERA, SE_DATELAST)
|
||
|
|
||
|
#include <pshpack8.h>
|
||
|
typedef struct tagSUBEDIT {
|
||
|
int id; // SE_ value above
|
||
|
RECT rc; // bounding box for display
|
||
|
|
||
|
LPWORD pval; // current value (in a SYSTEMTIME struct)
|
||
|
UINT min; // min value
|
||
|
UINT max; // max value
|
||
|
int cIncrement; // increment value
|
||
|
|
||
|
int cchMax; // max allowed chars
|
||
|
int cchEdit; // current number chars entered so far
|
||
|
UINT valEdit; // value entered so far
|
||
|
UINT flDrawText; // flags for DrawText
|
||
|
|
||
|
LPCTSTR pv; // formatting string
|
||
|
|
||
|
BOOL fReadOnly; // can this subedit be edited (receive focus)?
|
||
|
} SUBEDIT, * PSUBEDIT, *LPSUBEDIT;
|
||
|
#include <poppack.h>
|
||
|
|
||
|
//
|
||
|
// There are three types of calendars we support
|
||
|
//
|
||
|
// - Gregorian (Western). Any calendar not otherwise supported is forced
|
||
|
// into Gregorian mode.
|
||
|
//
|
||
|
// - Offset. The year is merely a fixed offset from the Gregorian year.
|
||
|
// This is the style used by the Korean and Thai calendars.
|
||
|
//
|
||
|
// - Era. The calendar consists of multiple eras, and the year is
|
||
|
// relative to the start of the enclosing era. This is the style
|
||
|
// used by the Japan and Taiwan calendars. Eras are strangest because
|
||
|
// an era need not start on January 1!
|
||
|
//
|
||
|
typedef struct tagCALENDARTYPE {
|
||
|
CALID calid; // Calendar id number (CAL_GREGORIAN, etc.)
|
||
|
LCID lcid; // Usually LOCALE_USER_DEFAULT, but forced to US for unsupported calendars
|
||
|
int dyrOffset; // The calendar offset (0 for Gregorian and Era)
|
||
|
HDPA hdpaYears; // If fEra, then array of year info
|
||
|
HDPA hdpaEras; // If fEra, then array of era names
|
||
|
} CALENDARTYPE, *PCALENDARTYPE;
|
||
|
|
||
|
#define BUDDHIST_BIAS 543
|
||
|
#define KOREAN_BIAS 2333
|
||
|
|
||
|
#define ISERACALENDAR(pct) ((pct)->hdpaEras)
|
||
|
|
||
|
#define GregorianToOther(pct, yr) ((yr) + (pct)->dyrOffset)
|
||
|
#define OtherToGregorian(pct, yr) ((yr) - (pct)->dyrOffset)
|
||
|
|
||
|
typedef struct tagSUBEDITCONTROL {
|
||
|
LPCCONTROLINFO pci; // looks like this guy needs access to the hwnd
|
||
|
BOOL fNone; // allow scrolling into SUBEDIT_NONE
|
||
|
HFONT hfont; // font to draw text with
|
||
|
RECT rc; // rect for subedits
|
||
|
int xScroll; // amount pse array is scrolled
|
||
|
int iseCur; // subedit with current selection (SUBEDIT_NONE for no selection)
|
||
|
int cse; // count of subedits in pse array
|
||
|
SYSTEMTIME st; // current time pse represents (pse points into this)
|
||
|
LPTSTR szFormat; // format string as parsed (pse points into this)
|
||
|
PSUBEDIT pse; // subedit array
|
||
|
TCHAR cDelimeter; // delimiter between subedits (parsed from fmt string)
|
||
|
TCHAR szDelimeters[15]; // delimiters between date/time fields (from resfile)
|
||
|
CALENDARTYPE ct; // information about the calendar
|
||
|
BITBOOL fMirrorSEC:1; // Whether or not to mirror the SubEditControls
|
||
|
BITBOOL fSwapTimeMarker:1; // Whether we need to swap the AM/PM symbol around or not
|
||
|
} SUBEDITCONTROL, * PSUBEDITCONTROL, *LPSUBEDITCONTROL;
|
||
|
|
||
|
#define SECYBORDER 2
|
||
|
#define SECXBORDER 2
|
||
|
|
||
|
/*
|
||
|
* Multiple Month Calendar Control
|
||
|
*/
|
||
|
typedef struct tagMONTHCAL {
|
||
|
CCONTROLINFO ci; // all controls start with this
|
||
|
LOCALEINFO li; // stuff that used to be global
|
||
|
|
||
|
HINSTANCE hinstance;
|
||
|
|
||
|
HWND hwndEdit; // non-NULL iff dealing with user-click on year
|
||
|
HWND hwndUD; // UpDown control associated with the hwndEdit
|
||
|
|
||
|
HPEN hpen;
|
||
|
HBRUSH hbrushToday;
|
||
|
|
||
|
HFONT hfont; // stock font, don't destroy
|
||
|
HFONT hfontBold; // created font, so we need to destroy
|
||
|
|
||
|
COLORREF clr[MCSC_COLORCOUNT];
|
||
|
|
||
|
int dxCol; // font info, based on bold to insure that we get enough space
|
||
|
int dyRow;
|
||
|
int dxMonth;
|
||
|
int dyMonth;
|
||
|
int dxYearMax;
|
||
|
int dyToday;
|
||
|
int dxToday;
|
||
|
|
||
|
int dxArrowMargin;
|
||
|
int dxCalArrow;
|
||
|
int dyCalArrow;
|
||
|
|
||
|
HMENU hmenuCtxt;
|
||
|
HMENU hmenuMonth;
|
||
|
|
||
|
SYSTEMTIME stMin; // minimum selectable date
|
||
|
SYSTEMTIME stMax; // maximum selectable date
|
||
|
|
||
|
DWORD cSelMax;
|
||
|
|
||
|
SYSTEMTIME stToday;
|
||
|
SYSTEMTIME st; // the selection if not multiselect
|
||
|
// the beginning of the selection if multiselect
|
||
|
SYSTEMTIME stEndSel; // the end of the selection if multiselect
|
||
|
SYSTEMTIME stStartPrev; // prev selection beginning (only in multiselect)
|
||
|
SYSTEMTIME stEndPrev; // prev selection end (only in multiselect)
|
||
|
|
||
|
SYSTEMTIME stAnchor; // anchor date in shift-click selection
|
||
|
|
||
|
SYSTEMTIME stViewFirst; // first visible date (DAYSTATE - grayed out)
|
||
|
SYSTEMTIME stViewLast; // last visible date (DAYSTATE - grayed out)
|
||
|
|
||
|
SYSTEMTIME stMonthFirst; // first month (stMin adjusted)
|
||
|
SYSTEMTIME stMonthLast; // last month (stMax adjusted)
|
||
|
int nMonths; // number of months being shown (stMonthFirst..stMonthLast)
|
||
|
|
||
|
UINT_PTR idTimer;
|
||
|
UINT_PTR idTimerToday;
|
||
|
|
||
|
int nViewRows; // number of rows of months shown
|
||
|
int nViewCols; // number of columns of months shown
|
||
|
|
||
|
RECT rcPrev; // rect for prev month button (in window coords)
|
||
|
RECT rcNext; // rect for next month button (in window coords)
|
||
|
|
||
|
RECT rcMonthName; // rect for the month name (in relative coords)
|
||
|
// (actually, the rect for the titlebar area of
|
||
|
// each month).
|
||
|
|
||
|
RECT rcDow; // rect for days of week (in relative coords)
|
||
|
RECT rcWeekNum; // rect for week numbers (in relative coords)
|
||
|
RECT rcDayNum; // rect for day numbers (in relative coords)
|
||
|
|
||
|
int iMonthToday;
|
||
|
int iRowToday;
|
||
|
int iColToday;
|
||
|
|
||
|
RECT rcDayCur; // rect for the current selected day
|
||
|
RECT rcDayOld;
|
||
|
|
||
|
RECT rc; // window rc.
|
||
|
RECT rcCentered; // rect containing the centered months
|
||
|
|
||
|
// The following 4 ranges hold info about the displayed (DAYSTATE) months:
|
||
|
// They are filled in from 0 to nMonths+1 by MCUpdateStartEndDates
|
||
|
// NOTE: These are _one_ based indexed arrays of the displayed months
|
||
|
int rgcDay[CALMONTHMAX + 2]; // # days in this month
|
||
|
int rgnDayUL[CALMONTHMAX + 2]; // last day in this month NOT visible when viewing next month
|
||
|
|
||
|
int dsMonth; // first month stored in rgdayState
|
||
|
int dsYear; // first year stored in rgdayState
|
||
|
int cds; // number of months stored in rgdayState
|
||
|
MONTHDAYSTATE rgdayState[CALMONTHMAX + 2];
|
||
|
|
||
|
int nMonthDelta; // the amount to move on button press
|
||
|
|
||
|
BOOL fControl;
|
||
|
BOOL fShift;
|
||
|
|
||
|
CALENDARTYPE ct; // information about the calendar
|
||
|
|
||
|
WORD fFocus:1;
|
||
|
WORD fEnabled:1;
|
||
|
WORD fCapture:1; // mouse captured
|
||
|
|
||
|
WORD fSpinPrev:1;
|
||
|
WORD fFocusDrawn:1; // is focus rect currently drawn?
|
||
|
WORD fToday:1; // today's date currently visible in calendar
|
||
|
WORD fNoNotify:1; // don't notify parent window
|
||
|
WORD fMultiSelecting:1; // Are we actually in the process of selecting?
|
||
|
WORD fForwardSelect:1;
|
||
|
WORD fFirstDowSet:1;
|
||
|
WORD fTodaySet:1;
|
||
|
WORD fMinYrSet:1; // stMin has been set
|
||
|
WORD fMaxYrSet:1; // stMax has been set
|
||
|
WORD fMonthDelta:1; // nMonthDelta has been set
|
||
|
WORD fHeaderRTL:1; // Is header string RTL ?
|
||
|
HTHEME hThemeScroll;
|
||
|
|
||
|
//
|
||
|
// Metrics for each month we display.
|
||
|
//
|
||
|
MONTHMETRICS rgmm[CALMONTHMAX];
|
||
|
|
||
|
} MONTHCAL, * PMONTHCAL, *LPMONTHCAL;
|
||
|
|
||
|
|
||
|
#define MonthCal_GetPtr(hwnd) (MONTHCAL*)GetWindowPtr(hwnd, 0)
|
||
|
#define MonthCal_SetPtr(hwnd, p) (MONTHCAL*)SetWindowPtr(hwnd, 0, p)
|
||
|
|
||
|
#define MonthCal_IsMultiSelect(pmc) ((pmc)->ci.style & MCS_MULTISELECT)
|
||
|
#define MonthCal_IsDayState(pmc) ((pmc)->ci.style & MCS_DAYSTATE)
|
||
|
#define MonthCal_ShowWeekNumbers(pmc) ((pmc)->ci.style & MCS_WEEKNUMBERS)
|
||
|
#define MonthCal_ShowTodayCircle(pmc) (!((pmc)->ci.style & MCS_NOTODAYCIRCLE))
|
||
|
#define MonthCal_ShowToday(pmc) (!((pmc)->ci.style & MCS_NOTODAY))
|
||
|
|
||
|
|
||
|
//
|
||
|
// DATEPICK stuff
|
||
|
//
|
||
|
|
||
|
#define DPYBORDER 2
|
||
|
#define DPXBUFFER 2
|
||
|
#define DP_DXBUTTON 15
|
||
|
#define DP_DYBUTTON 15
|
||
|
#define DP_IDAUTOSPIN 1
|
||
|
#define DP_MSECAUTOSPIN 200
|
||
|
#define DATEPICK_UPDOWN 1000
|
||
|
|
||
|
#define DTP_FORMATLENGTH 128
|
||
|
|
||
|
enum {
|
||
|
DP_SEL_DOW = 0,
|
||
|
DP_SEL_YEAR,
|
||
|
DP_SEL_MONTH,
|
||
|
DP_SEL_DAY,
|
||
|
DP_SEL_SEP1,
|
||
|
DP_SEL_SEP2,
|
||
|
DP_SEL_NODATE,
|
||
|
DP_SEL_MAX
|
||
|
};
|
||
|
|
||
|
typedef struct tagDATEPICK
|
||
|
{
|
||
|
CCONTROLINFO ci; // all controls start with this
|
||
|
|
||
|
HWND hwndUD;
|
||
|
HWND hwndMC;
|
||
|
HFONT hfontMC; // font for drop down cal
|
||
|
|
||
|
COLORREF clr[MCSC_COLORCOUNT];
|
||
|
|
||
|
// HACK! stMin and stMax must remain in order and adjacent
|
||
|
SYSTEMTIME stMin; // minimum date we allow
|
||
|
SYSTEMTIME stMax; // maximum date we allow
|
||
|
SYSTEMTIME stPrev; // most recent date notified
|
||
|
SUBEDITCONTROL sec; // current date
|
||
|
|
||
|
RECT rcCheck; // location of checkbox iff fShowNone
|
||
|
RECT rc; // size of SEC space
|
||
|
RECT rcBtn; // location of dropdown or updown
|
||
|
int iseLastActive; // which subedit was active when we were last active?
|
||
|
WPARAM gdtr; // Did app set min and/or max? (GDTR_MIN|GDTR_MAX)
|
||
|
|
||
|
BITBOOL fEnabled:1;
|
||
|
BITBOOL fUseUpDown:1;
|
||
|
BITBOOL fFocus:1;
|
||
|
BITBOOL fNoNotify:1;
|
||
|
BITBOOL fCapture:1;
|
||
|
BITBOOL fShow:1; // TRUE iff we should continue to show MonthCal
|
||
|
|
||
|
BITBOOL fCheck:1; // TRUE iff the checkbox is checked
|
||
|
BITBOOL fCheckFocus:1; // TRUE iff the checkbox has focus
|
||
|
|
||
|
BITBOOL fLocale:1; // TRUE iff the format string is LOCALE dependent
|
||
|
BITBOOL fHasMark:1; // true iff has am/pm in current format
|
||
|
BITBOOL fFreeEditing:1; // TRUE if in the middle of a free-format edit
|
||
|
HTHEME hThemeCombo;
|
||
|
HTHEME hThemeCheck;
|
||
|
} DATEPICK, * PDATEPICK, *LPDATEPICK;
|
||
|
|
||
|
#define DatePick_ShowCheck(pdp) ((pdp)->ci.style & DTS_SHOWNONE)
|
||
|
#define DatePick_AppCanParse(pdp) ((pdp)->ci.style & DTS_APPCANPARSE)
|
||
|
#define DatePick_RightAlign(pdp) ((pdp)->ci.style & DTS_RIGHTALIGN)
|
||
|
|
||
|
#define DatePick_GetPtr(hwnd) (DATEPICK*)GetWindowPtr(hwnd, 0)
|
||
|
#define DatePick_SetPtr(hwnd, p) (DATEPICK*)SetWindowPtr(hwnd, 0, p)
|
||
|
|
||
|
#define CopyDate(stS, stD) ((stD).wYear = (stS).wYear,(stD).wMonth = (stS).wMonth,(stD).wDay = (stS).wDay)
|
||
|
#define CopyTime(stS, stD) ((stD).wHour = (stS).wHour,(stD).wMinute = (stS).wMinute,(stD).wSecond = (stS).wSecond)
|