Authors: Chris Morgan <cmorgan@wpi.edu>, James Abbatiello <abbeyj@wpi.edu>

Implemented WM_SIZE message support. Optimized drawing to use
precalculated size values rather than recalculating during each call
of MONTHCAL_Refresh.
This commit is contained in:
Alexandre Julliard 2000-01-04 00:30:21 +00:00
parent a4d7ca0f22
commit b7c84d3b22
2 changed files with 653 additions and 549 deletions

View File

@ -11,7 +11,6 @@
*
*
* FIXME: refresh should ask for rect of required length. (?)
* FIXME: we refresh to often; especially in LButtonDown/MouseMove.
* FIXME: handle resources better (doesn't work now); also take care
of internationalization.
* FIXME: keyboard handling.
@ -36,10 +35,10 @@ DEFAULT_DEBUG_CHANNEL(monthcal)
* defined here */
extern int mdays[];
char *monthtxt[] = {"January", "February", "March", "April", "May",
"June", "July", "August", "September", "October",
"November", "December"};
char *daytxt[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
int DayOfWeekTable[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
@ -76,6 +75,7 @@ static int MONTHCAL_ValidateTime (SYSTEMTIME time)
if(time.wMinute > 59) return FALSE;
if(time.wSecond > 59) return FALSE;
if(time.wMilliseconds > 999) return FALSE;
return TRUE;
}
@ -315,11 +315,11 @@ static void MONTHCAL_DrawDay (HDC hdc, MONTHCAL_INFO *infoPtr,
/* CHECKME: For `todays date', do we need to check the locale?*/
/* CHECKME: For `todays date', how do is Y2K handled?*/
static void MONTHCAL_Refresh(HWND hwnd, HDC hdc)
{
MONTHCAL_INFO *infoPtr=MONTHCAL_GetInfoPtr(hwnd);
RECT *rcClient=&infoPtr->rcClient;
RECT *rcDraw=&infoPtr->rcDraw;
RECT *title=&infoPtr->title;
RECT *prev=&infoPtr->titlebtnprev;
RECT *next=&infoPtr->titlebtnnext;
@ -327,15 +327,15 @@ static void MONTHCAL_Refresh (HWND hwnd, HDC hdc)
RECT *titleyear=&infoPtr->titleyear;
RECT *prevmonth=&infoPtr->prevmonth;
RECT *nextmonth=&infoPtr->nextmonth;
RECT *days=&infoPtr->days;
RECT dayrect;
RECT *days=&dayrect;
RECT *weeknums=&infoPtr->weeknums;
RECT *rtoday=&infoPtr->today;
int i, j, m, mask, day, firstDay, weeknum, prevMonth;
int textHeight, textWidth;
int textHeight = infoPtr->textHeight, textWidth = infoPtr->textWidth;
SIZE size;
HBRUSH hbr;
HFONT currentFont;
TEXTMETRICA tm;
/* LOGFONTA logFont; */
char buf[20], *thisMonthtxt;
COLORREF oldTextColor, oldBkColor;
@ -344,69 +344,17 @@ static void MONTHCAL_Refresh (HWND hwnd, HDC hdc)
oldTextColor = SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT));
currentFont = SelectObject (hdc, infoPtr->hFont);
/* FIXME: need a way to determine current font, without setting it */
/*
if (infoPtr->hFont!=currentFont) {
SelectObject (hdc, currentFont);
infoPtr->hFont=currentFont;
GetObjectA (currentFont, sizeof (LOGFONTA), &logFont);
logFont.lfWeight=FW_BOLD;
infoPtr->hBoldFont = CreateFontIndirectA (&logFont);
}
*/
GetTextMetricsA (hdc, &tm);
infoPtr->textHeight=textHeight=tm.tmHeight + tm.tmExternalLeading;
GetTextExtentPoint32A (hdc, "Sun",3, &size);
infoPtr->textWidth=textWidth=size.cx+2;
/* retrieve the controls client rectangle info infoPtr->rcClient */
GetClientRect (hwnd, rcClient);
/* draw control edge */
hbr = CreateSolidBrush(RGB(255, 255, 255));
DrawEdge (hdc, rcClient, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
FillRect(hdc, rcClient, hbr);
DrawEdge(hdc, rcClient, EDGE_SUNKEN, BF_RECT);
DeleteObject(hbr);
/* calculate whole client area & title area */
if (dwStyle & MCS_WEEKNUMBERS)
infoPtr->rcClient.right+=infoPtr->textWidth;
title->top = rcClient->top + 1;
title->bottom = title->top + 2*textHeight + 4;
title->left = rcClient->left + 1;
title->right = rcClient->right - 1;
/* this is correct, the control does NOT expand vertically like it
does horizontally */
infoPtr->rcClient.bottom = title->bottom + (6 * textHeight);
/* recalculate the height and width increments and offsets */
infoPtr->width_increment = (infoPtr->rcClient.right - infoPtr->rcClient.left) / 7.0;
infoPtr->height_increment = (infoPtr->rcClient.bottom - infoPtr->rcClient.top) / 7.0;
infoPtr->left_offset = (infoPtr->rcClient.right - infoPtr->rcClient.left) - (infoPtr->width_increment * 7.0);
infoPtr->top_offset = (infoPtr->rcClient.bottom - infoPtr->rcClient.top) - (infoPtr->height_increment * 7.0);
prssed = FALSE;
/* draw header */
hbr = CreateSolidBrush(infoPtr->titlebk);
FillRect(hdc, title, hbr);
prev->top = next->top = title->top + 6;
prev->bottom = next->bottom = title->top + 2*textHeight - 3;
prev->right = title->left + 28;
prev->left = title->left + 4;
next->left = title->right - 28;
next->right = title->right - 4;
titlemonth->bottom= titleyear->bottom = prev->top + 2*textHeight - 3;
titlemonth->top = titleyear->top = title->top;
titlemonth->left = title->left;
titlemonth->right = title->right;
prssed = FALSE;
/* if the previous button is pressed draw it depressed */
if((infoPtr->status & MC_PREVPRESSED))
DrawFrameControl(hdc, prev, DFC_SCROLL,
@ -427,7 +375,11 @@ static void MONTHCAL_Refresh (HWND hwnd, HDC hdc)
oldBkColor = SetBkColor(hdc, infoPtr->titlebk);
SetTextColor(hdc, infoPtr->titletxt);
SelectObject(hdc, infoPtr->hBoldFont);
currentFont = SelectObject(hdc, infoPtr->hBoldFont);
/* titlemonth->left and right are set in MONTHCAL_UpdateSize */
titlemonth->left = title->left;
titlemonth->right = title->right;
thisMonthtxt = monthtxt[infoPtr->currentMonth - 1];
sprintf(buf, "%s %ld", thisMonthtxt, infoPtr->currentYear);
@ -439,7 +391,6 @@ static void MONTHCAL_Refresh (HWND hwnd, HDC hdc)
* MCM_HitTestInfo wants month & year rects, so prepare these now.
*(no, we can't draw them separately; the whole text is centered)
*/
GetTextExtentPoint32A(hdc, buf, lstrlenA(buf), &size);
titlemonth->left = title->right / 2 - size.cx / 2;
titleyear->right = title->right / 2 + size.cx / 2;
@ -447,25 +398,28 @@ static void MONTHCAL_Refresh (HWND hwnd, HDC hdc)
titlemonth->right = titlemonth->left + size.cx;
titleyear->right = titlemonth->right;
/* draw line under day abbreviatons */
if(dwStyle & MCS_WEEKNUMBERS)
MoveToEx (hdc, rcClient->left+textWidth+3, title->bottom + textHeight + 2, NULL);
MoveToEx(hdc, rcDraw->left + textWidth + 3, title->bottom + textHeight + 2, NULL);
else
MoveToEx (hdc, rcClient->left+3, title->bottom + textHeight + 2, NULL);
MoveToEx(hdc, rcDraw->left + 3, title->bottom + textHeight + 2, NULL);
LineTo (hdc, rcClient->right-3, title->bottom + textHeight + 2);
LineTo(hdc, rcDraw->right - 3, title->bottom + textHeight + 2);
/* draw day abbreviations */
SetBkColor(hdc, infoPtr->monthbk);
SetTextColor(hdc, infoPtr->trailingtxt);
days->left = infoPtr->left_offset;
if (dwStyle & MCS_WEEKNUMBERS) days->left+=textWidth;
days->right = days->left + infoPtr->width_increment;
days->top = title->bottom + 2;
days->bottom = title->bottom + textHeight + 2;
/* copy this rect so we can change the values without changing */
/* the original version */
days->left = infoPtr->days.left;
days->right = infoPtr->days.right;
days->top = infoPtr->days.top;
days->bottom = infoPtr->days.bottom;
i = infoPtr->firstDay;
for(j=0; j<7; j++) {
@ -476,16 +430,13 @@ static void MONTHCAL_Refresh (HWND hwnd, HDC hdc)
days->right+=infoPtr->width_increment;
}
days->left = rcClient->left + j;
days->left = rcDraw->left + j;
if(dwStyle & MCS_WEEKNUMBERS) days->left+=textWidth;
/* FIXME: this may need to be changed now 11/10/99 CMM */
days->right = rcClient->left + (j+1)*textWidth-2;
days->right = rcDraw->left + (j+1) * textWidth - 2;
/* draw day numbers; first, the previous month */
prevmonth->left = 0;
if (dwStyle & MCS_WEEKNUMBERS) prevmonth->left=textWidth;
firstDay = MONTHCAL_CalculateDayOfWeek(1, infoPtr->currentMonth, infoPtr->currentYear);
prevMonth = infoPtr->currentMonth - 1;
@ -505,6 +456,8 @@ static void MONTHCAL_Refresh (HWND hwnd, HDC hdc)
i++;
}
prevmonth->left = 0;
if(dwStyle & MCS_WEEKNUMBERS) prevmonth->left = textWidth;
prevmonth->right = prevmonth->left + i * textWidth;
prevmonth->top = days->bottom;
prevmonth->bottom = prevmonth->top + textHeight;
@ -562,7 +515,7 @@ static void MONTHCAL_Refresh (HWND hwnd, HDC hdc)
* this rect -- HitTest knows about this.*/
nextmonth->left = prevmonth->left + i * textWidth;
nextmonth->right = rcClient->right;
nextmonth->right = rcDraw->right;
nextmonth->top = days->bottom + (j+1) * textHeight;
nextmonth->bottom = nextmonth->top + textHeight;
@ -598,7 +551,7 @@ static void MONTHCAL_Refresh (HWND hwnd, HDC hdc)
MONTHCAL_CalcDayRect(infoPtr, rtoday, offset==textWidth, 6);
sprintf(buf, "Today: %d/%d/%d", infoPtr->todaysDate.wMonth,
infoPtr->todaysDate.wDay, infoPtr->todaysDate.wYear % 100);
rtoday->right = rcClient->right;
rtoday->right = rcDraw->right;
SelectObject(hdc, infoPtr->hBoldFont);
DrawTextA(hdc, buf, lstrlenA(buf), rtoday,
DT_LEFT | DT_VCENTER | DT_SINGLELINE);
@ -959,7 +912,8 @@ MONTHCAL_GetSelRange (HWND hwnd, WPARAM wParam, LPARAM lParam)
if((infoPtr==NULL) ||(lprgSysTimeArray==NULL)) return FALSE;
if ( GetWindowLongA( hwnd, GWL_STYLE) & MCS_MULTISELECT) {
if(GetWindowLongA(hwnd, GWL_STYLE) & MCS_MULTISELECT)
{
MONTHCAL_CopyTime(&infoPtr->maxSel, &lprgSysTimeArray[1]);
MONTHCAL_CopyTime(&infoPtr->minSel, &lprgSysTimeArray[0]);
TRACE("[min,max]=[%d %d]\n", infoPtr->minSel.wDay, infoPtr->maxSel.wDay);
@ -982,7 +936,8 @@ MONTHCAL_SetSelRange (HWND hwnd, WPARAM wParam, LPARAM lParam)
if((infoPtr==NULL) ||(lprgSysTimeArray==NULL)) return FALSE;
if ( GetWindowLongA( hwnd, GWL_STYLE) & MCS_MULTISELECT) {
if(GetWindowLongA( hwnd, GWL_STYLE) & MCS_MULTISELECT)
{
MONTHCAL_CopyTime(&lprgSysTimeArray[1], &infoPtr->maxSel);
MONTHCAL_CopyTime(&lprgSysTimeArray[0], &infoPtr->minSel);
TRACE("[min,max]=[%d %d]\n", infoPtr->minSel.wDay, infoPtr->maxSel.wDay);
@ -1125,7 +1080,7 @@ static void MONTHCAL_GoToNextMonth (HWND hwnd, MONTHCAL_INFO *infoPtr)
{
DWORD dwStyle = GetWindowLongA(hwnd, GWL_STYLE);
TRACE ("\n");
TRACE("MONTHCAL_GoToNextMonth\n");
infoPtr->currentMonth++;
if(infoPtr->currentMonth > 12) {
@ -1155,7 +1110,7 @@ static void MONTHCAL_GoToPrevMonth (HWND hwnd, MONTHCAL_INFO *infoPtr)
{
DWORD dwStyle = GetWindowLongA(hwnd, GWL_STYLE);
TRACE ("\n");
TRACE("MONTHCAL_GoToPrevMonth\n");
infoPtr->currentMonth--;
if(infoPtr->currentMonth < 1) {
@ -1191,6 +1146,7 @@ MONTHCAL_LButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
DWORD hit;
HMENU hMenu;
HWND retval;
BOOL redraw = FALSE;
TRACE("%x %lx\n", wParam, lParam);
@ -1203,11 +1159,13 @@ MONTHCAL_LButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
/*((hit & MCHT_XXX) == MCHT_XXX) b/c some of the flags are */
/* multi-bit */
if(hit & MCHT_NEXT) {
redraw = TRUE;
MONTHCAL_GoToNextMonth(hwnd, infoPtr);
infoPtr->status = MC_NEXTPRESSED;
SetTimer(hwnd, MC_NEXTMONTHTIMER, MC_NEXTMONTHDELAY, 0);
}
if(hit & MCHT_PREV) {
redraw = TRUE;
MONTHCAL_GoToPrevMonth(hwnd, infoPtr);
infoPtr->status = MC_PREVPRESSED;
SetTimer(hwnd, MC_PREVMONTHTIMER, MC_NEXTMONTHDELAY, 0);
@ -1261,15 +1219,23 @@ MONTHCAL_LButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
MONTHCAL_CopyTime(&ht.st, &selArray[1]);
MONTHCAL_SetSelRange(hwnd,0,(LPARAM) &selArray);
/* redraw if the selected day changed */
if(infoPtr->curSelDay != ht.st.wDay) {
redraw = TRUE;
}
infoPtr->firstSelDay = ht.st.wDay;
infoPtr->curSelDay = ht.st.wDay;
infoPtr->status = MC_SEL_LBUTDOWN;
}
/* redraw only if the control changed */
if(redraw) {
hdc = GetDC(hwnd);
MONTHCAL_Refresh(hwnd, hdc);
ReleaseDC(hwnd, hdc);
}
return 0;
}
@ -1281,13 +1247,19 @@ MONTHCAL_LButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
NMSELCHANGE nmsc;
NMHDR nmhdr;
HDC hdc;
BOOL redraw = FALSE;
TRACE("\n");
if (infoPtr->status & MC_NEXTPRESSED)
if(infoPtr->status & MC_NEXTPRESSED) {
KillTimer(hwnd, MC_NEXTMONTHTIMER);
if (infoPtr->status & MC_PREVPRESSED)
redraw = TRUE;
}
if(infoPtr->status & MC_PREVPRESSED) {
KillTimer(hwnd, MC_PREVMONTHTIMER);
redraw = TRUE;
}
infoPtr->status = MC_SEL_LBUTUP;
nmhdr.hwndFrom = hwnd;
@ -1307,9 +1279,12 @@ MONTHCAL_LButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
SendMessageA(GetParent(hwnd), WM_NOTIFY,
(WPARAM)nmsc.nmhdr.idFrom, (LPARAM)&nmsc);
/* redraw if necessary */
if(redraw) {
hdc = GetDC(hwnd);
MONTHCAL_Refresh(hwnd, hdc);
ReleaseDC(hwnd, hdc);
}
return 0;
}
@ -1320,24 +1295,31 @@ MONTHCAL_Timer (HWND hwnd, WPARAM wParam, LPARAM lParam)
{
MONTHCAL_INFO *infoPtr = MONTHCAL_GetInfoPtr(hwnd);
HDC hdc;
BOOL redraw = FALSE;
TRACE(" %d\n", wParam);
if(!infoPtr) return 0;
switch(wParam) {
case MC_NEXTMONTHTIMER:
redraw = TRUE;
MONTHCAL_GoToNextMonth(hwnd, infoPtr);
break;
case MC_PREVMONTHTIMER:
redraw = TRUE;
MONTHCAL_GoToPrevMonth(hwnd, infoPtr);
break;
default:
ERR("got unknown timer\n");
}
/* redraw only if necessary */
if(redraw) {
hdc = GetDC(hwnd);
MONTHCAL_Refresh(hwnd, hdc);
ReleaseDC(hwnd, hdc);
}
return 0;
}
@ -1461,6 +1443,120 @@ MONTHCAL_SetFocus (HWND hwnd, WPARAM wParam, LPARAM lParam)
return 0;
}
/* sets the size information */
static void MONTHCAL_UpdateSize(HWND hwnd)
{
HDC hdc = GetDC(hwnd);
MONTHCAL_INFO *infoPtr = MONTHCAL_GetInfoPtr(hwnd);
RECT *rcClient=&infoPtr->rcClient;
RECT *rcDraw=&infoPtr->rcDraw;
RECT *title=&infoPtr->title;
RECT *prev=&infoPtr->titlebtnprev;
RECT *next=&infoPtr->titlebtnnext;
RECT *titlemonth=&infoPtr->titlemonth;
RECT *titleyear=&infoPtr->titleyear;
RECT *days=&infoPtr->days;
SIZE size;
TEXTMETRICA tm;
DWORD dwStyle = GetWindowLongA(hwnd, GWL_STYLE);
HFONT currentFont;
currentFont = SelectObject(hdc, infoPtr->hFont);
/* FIXME: need a way to determine current font, without setting it */
/*
if(infoPtr->hFont!=currentFont) {
SelectObject(hdc, currentFont);
infoPtr->hFont=currentFont;
GetObjectA(currentFont, sizeof(LOGFONTA), &logFont);
logFont.lfWeight=FW_BOLD;
infoPtr->hBoldFont = CreateFontIndirectA(&logFont);
}
*/
/* get the height and width of each day's text */
GetTextMetricsA(hdc, &tm);
infoPtr->textHeight = tm.tmHeight + tm.tmExternalLeading;
GetTextExtentPoint32A(hdc, "Sun", 3, &size);
infoPtr->textWidth = size.cx + 2;
/* retrieve the controls client rectangle info infoPtr->rcClient */
GetClientRect(hwnd, rcClient);
if(dwStyle & MCS_WEEKNUMBERS)
infoPtr->rcClient.right+=infoPtr->textWidth;
/* rcDraw is the rectangle the control is drawn in */
rcDraw->left = rcClient->left;
rcDraw->right = rcClient->right;
rcDraw->top = rcClient->top;
rcDraw->bottom = rcClient->bottom;
/* use DrawEdge to adjust the size of rcClient such that we */
/* do not overwrite the border when drawing the control */
DrawEdge((HDC)NULL, rcDraw, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
/* this is correct, the control does NOT expand vertically */
/* like it does horizontally */
/* make sure we don't move the controls bottom out of the client */
/* area */
if((rcDraw->top + 8 * infoPtr->textHeight + 5) < rcDraw->bottom) {
rcDraw->bottom = rcDraw->top + 8 * infoPtr->textHeight + 5;
}
/* calculate title area */
title->top = rcClient->top + 1;
title->bottom = title->top + 2 * infoPtr->textHeight + 4;
title->left = rcClient->left + 1;
title->right = rcClient->right - 1;
/* recalculate the height and width increments and offsets */
infoPtr->width_increment = (infoPtr->rcDraw.right - infoPtr->rcDraw.left) / 7.0;
infoPtr->height_increment = (infoPtr->rcDraw.bottom - infoPtr->rcDraw.top) / 7.0;
infoPtr->left_offset = (infoPtr->rcDraw.right - infoPtr->rcDraw.left) - (infoPtr->width_increment * 7.0);
infoPtr->top_offset = (infoPtr->rcDraw.bottom - infoPtr->rcDraw.top) - (infoPtr->height_increment * 7.0);
/* set the dimensions of the next and previous buttons and center */
/* the month text vertically */
prev->top = next->top = title->top + 6;
prev->bottom = next->bottom = title->top + 2 * infoPtr->textHeight - 3;
prev->right = title->left + 28;
prev->left = title->left + 4;
next->left = title->right - 28;
next->right = title->right - 4;
/* titlemonth->left and right change based upon the current month */
/* and are recalculated in refresh as the current month may change */
/* without the control being resized */
titlemonth->bottom = titleyear->bottom = prev->top + 2 * infoPtr->textHeight - 3;
titlemonth->top = titleyear->top = title->top;
/* setup the dimensions of the rectangle we draw the names of the */
/* days of the week in */
days->left = infoPtr->left_offset;
if(dwStyle & MCS_WEEKNUMBERS) days->left+=infoPtr->textWidth;
days->right = days->left + infoPtr->width_increment;
days->top = title->bottom + 2;
days->bottom = title->bottom + infoPtr->textHeight + 2;
/* restore the originally selected font */
SelectObject(hdc, currentFont);
ReleaseDC(hwnd, hdc);
}
static LRESULT MONTHCAL_Size(HWND hwnd, int Width, int Height)
{
TRACE("(hwnd=%x, width=%d, height=%d)\n", hwnd, Width, Height);
MONTHCAL_UpdateSize(hwnd);
/* invalidate client area and erase background */
InvalidateRect(hwnd, NULL, TRUE);
return 0;
}
/* FIXME: check whether dateMin/dateMax need to be adjusted. */
static LRESULT
@ -1507,6 +1603,10 @@ MONTHCAL_Create (HWND hwnd, WPARAM wParam, LPARAM lParam)
infoPtr->bk = GetSysColor(COLOR_WINDOW);
infoPtr->txt = GetSysColor(COLOR_WINDOWTEXT);
/* call MONTHCAL_UpdateSize to set all of the dimensions */
/* of the control */
MONTHCAL_UpdateSize(hwnd);
return 0;
}
@ -1612,6 +1712,9 @@ MONTHCAL_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
case WM_SETFOCUS:
return MONTHCAL_SetFocus(hwnd, wParam, lParam);
case WM_SIZE:
return MONTHCAL_Size(hwnd, (int)SLOWORD(lParam), (int)SHIWORD(lParam));
case WM_CREATE:
return MONTHCAL_Create(hwnd, wParam, lParam);

View File

@ -60,6 +60,7 @@ typedef struct tagMONTHCAL_INFO
SYSTEMTIME maxDate;
RECT rcClient; /* rect for whole client area */
RECT rcDraw; /* rect for drawable portion of client area */
RECT title; /* rect for the header above the calendar */
RECT titlebtnnext; /* the `next month' button in the header */
RECT titlebtnprev; /* the `prev month' button in the header */