windows-nt/Source/XPSP1/NT/shell/cpls/utc/clock.c
2020-09-26 16:20:57 +08:00

967 lines
23 KiB
C

/*++
Copyright (c) 1994-1998, Microsoft Corporation All rights reserved.
Module Name:
clock.c
Abstract:
This module implements the clock control for the Date/Time applet.
Revision History:
--*/
//
// Include Files.
//
#include "timedate.h"
#include "rc.h"
#include "clock.h"
//
// Constant Declarations.
//
#define TIMER_ID 1
#define SECONDSCALE 80
#define HHAND TRUE
#define MHAND FALSE
#define MAXBLOBWIDTH 25
#define REPAINT 0
#define HANDPAINT 1
#define OPEN_TLEN 450 /* < half second */
#define MINDESIREDHEIGHT 3
//
// Macro Definitions.
//
#ifdef WIN32
#define MoveTo(hdc, x, y) MoveToEx(hdc, x, y, NULL)
#define GetWindowPtr(w, o) GetWindowLongPtr(w, o)
#define SetWindowPtr(w, o, p) SetWindowLongPtr(w, o, (LPARAM)(p))
#else
#define GetWindowPtr(w, o) GetWindowWord(w, o)
#define SetWindowPtr(w, o, p) SetWindowWord(w, o, p)
#endif
//
// Typedef Declarations.
//
typedef struct
{
int hour; // 0 - 11 hours for analog clock
int minute;
int second;
} TIME;
typedef struct
{
HWND hWnd; // Us.
HWND hwndGetTime; // window to provide get/set time
// Brushes
HBRUSH hbrColorWindow;
HBRUSH hbrBtnHighlight;
HBRUSH hbrForeground;
HBRUSH hbrBlobColor;
// Pens
HPEN hpenForeground;
HPEN hpenBackground;
HPEN hpenBlobHlt;
// Dimensions of clock
RECT clockRect;
int clockRadius;
int HorzRes;
int VertRes;
int aspectD;
int aspectN;
// Position of clock
POINT clockCenter;
TIME oTime;
TIME nTime;
} CLOCKSTR, *PCLOCKSTR;
typedef struct
{
SHORT x;
SHORT y;
} TRIG;
//
// Array containing the sine and cosine values for hand positions.
//
POINT rCircleTable[] =
{
{ 0, -7999},
{ 836, -7956},
{ 1663, -7825},
{ 2472, -7608},
{ 3253, -7308},
{ 3999, -6928},
{ 4702, -6472},
{ 5353, -5945},
{ 5945, -5353},
{ 6472, -4702},
{ 6928, -4000},
{ 7308, -3253},
{ 7608, -2472},
{ 7825, -1663},
{ 7956, -836 },
{ 8000, 0 },
{ 7956, 836 },
{ 7825, 1663 },
{ 7608, 2472 },
{ 7308, 3253 },
{ 6928, 4000 },
{ 6472, 4702 },
{ 5945, 5353 },
{ 5353, 5945 },
{ 4702, 6472 },
{ 3999, 6928 },
{ 3253, 7308 },
{ 2472, 7608 },
{ 1663, 7825 },
{ 836, 7956 },
{ 0, 7999 },
{ -836, 7956 },
{ -1663, 7825 },
{ -2472, 7608 },
{ -3253, 7308 },
{ -4000, 6928 },
{ -4702, 6472 },
{ -5353, 5945 },
{ -5945, 5353 },
{ -6472, 4702 },
{ -6928, 3999 },
{ -7308, 3253 },
{ -7608, 2472 },
{ -7825, 1663 },
{ -7956, 836 },
{ -7999, -0 },
{ -7956, -836 },
{ -7825, -1663},
{ -7608, -2472},
{ -7308, -3253},
{ -6928, -4000},
{ -6472, -4702},
{ -5945, -5353},
{ -5353, -5945},
{ -4702, -6472},
{ -3999, -6928},
{ -3253, -7308},
{ -2472, -7608},
{ -1663, -7825},
{ -836 , -7956},
};
//
// Function prototypes.
//
LRESULT CALLBACK ClockWndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
void ClockCreate(HWND hWnd, PCLOCKSTR np);
void ClockTimer(HWND hWnd, WPARAM idTimer, PCLOCKSTR np);
void ClockPaint(PCLOCKSTR np, HDC hDC, int hint);
void ClockTimerInterval( HWND hWnd, PCLOCKSTR np );
void CompClockDim(HWND hWnd, PCLOCKSTR np);
void CreateTools(PCLOCKSTR np);
void DeleteTools(PCLOCKSTR np);
void DrawFace(HDC hDC, PCLOCKSTR np);
void DrawFatHand( HDC hDC, int pos, HPEN hPen, BOOL hHand, PCLOCKSTR np);
void DrawHand( HDC hDC, int pos, HPEN hPen, int scale, int patMode, PCLOCKSTR np);
////////////////////////////////////////////////////////////////////////////
//
// ClockInit
//
// Registers the clock class.
//
////////////////////////////////////////////////////////////////////////////
TCHAR const c_szClockClass[] = CLOCK_CLASS;
BOOL ClockInit(
HINSTANCE hInstance)
{
WNDCLASS wc;
if (!GetClassInfo(hInstance, c_szClockClass, &wc))
{
wc.cbClsExtra = 0;
wc.cbWndExtra = sizeof(PCLOCKSTR);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = NULL;
wc.hIcon = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = c_szClockClass;
wc.hInstance = hInstance;
wc.style = CS_VREDRAW | CS_HREDRAW ;
wc.lpfnWndProc = ClockWndProc;
return (RegisterClass(&wc));
}
return (TRUE);
}
////////////////////////////////////////////////////////////////////////////
//
// GetTimeClock
//
// Gets the time that we should display on the clock.
// The client could have specified a function to call to get this
// or an HWND to pass a message to to get it from.
//
////////////////////////////////////////////////////////////////////////////
void GetTimeClock(
TIME *pt,
PCLOCKSTR np)
{
SYSTEMTIME st;
//
// Call our time provider or default to GetTime.
//
if (np->hwndGetTime)
{
SendMessage( np->hwndGetTime,
CLM_UPDATETIME,
CLF_GETTIME,
(LPARAM)(LPSYSTEMTIME)&st );
pt->hour = st.wHour % 12;
pt->minute = st.wMinute;
pt->second = st.wSecond;
}
else
{
#ifdef WIN32
GetLocalTime(&st);
pt->hour = st.wHour;
pt->minute = st.wMinute;
pt->second = st.wSecond;
#else
//
// No function call back and no HWND callback.
//
GetTime();
pt->hour = wDateTime[HOUR] % 12;
pt->minute = wDateTime[MINUTE];
pt->second = wDateTime[SECOND];
#endif
}
}
////////////////////////////////////////////////////////////////////////////
//
// CreateTools
//
////////////////////////////////////////////////////////////////////////////
void CreateTools(
PCLOCKSTR np)
{
#define BLOB_COLOR RGB(0, 128, 128)
np->hbrForeground = GetSysColorBrush(COLOR_BTNSHADOW);
np->hbrColorWindow = GetSysColorBrush(COLOR_BTNFACE);
np->hbrBlobColor = CreateSolidBrush( BLOB_COLOR );
np->hbrBtnHighlight = GetSysColorBrush(COLOR_BTNHIGHLIGHT);
np->hpenForeground = CreatePen(0, 1, GetSysColor(COLOR_WINDOWTEXT));
np->hpenBackground = CreatePen(0, 1, GetSysColor(COLOR_BTNFACE));
np->hpenBlobHlt = CreatePen(0, 1, RGB(0, 255, 255));
}
////////////////////////////////////////////////////////////////////////////
//
// DeleteTools
//
////////////////////////////////////////////////////////////////////////////
void DeleteTools(
PCLOCKSTR np)
{
// DeleteObject(np->hbrForeground);
// DeleteObject(np->hbrColorWindow);
DeleteObject(np->hbrBlobColor);
// DeleteObject(np->hbrBtnHighlight);
DeleteObject(np->hpenForeground);
DeleteObject(np->hpenBackground);
DeleteObject(np->hpenBlobHlt);
}
////////////////////////////////////////////////////////////////////////////
//
// CompClockDim
//
// Calculates the clock dimensions.
//
////////////////////////////////////////////////////////////////////////////
void CompClockDim(
HWND hWnd,
PCLOCKSTR np)
{
int i;
int tWidth;
int tHeight;
tWidth = np->clockRect.right - np->clockRect.left;
tHeight = np->clockRect.bottom - np->clockRect.top;
if (tWidth > MulDiv(tHeight,np->aspectD,np->aspectN))
{
i = MulDiv(tHeight, np->aspectD, np->aspectN);
np->clockRect.left += (tWidth - i) / 2;
np->clockRect.right = np->clockRect.left + i;
}
else
{
i = MulDiv(tWidth, np->aspectN, np->aspectD);
np->clockRect.top += (tHeight - i) / 2;
np->clockRect.bottom = np->clockRect.top + i;
}
}
////////////////////////////////////////////////////////////////////////////
//
// ClockTimerInterval
//
// Sets the timer interval. Two things affect this interval:
// 1) if the window is iconic, or
// 2) if seconds option has been disabled
// In both cases, timer ticks occur every half-minute. Otherwise, timer
// every half-second.
//
////////////////////////////////////////////////////////////////////////////
void ClockTimerInterval(
HWND hWnd,
PCLOCKSTR np)
{
//
// Update every 1/2 second in the opened state.
//
KillTimer(hWnd, TIMER_ID);
SetTimer(hWnd, TIMER_ID, OPEN_TLEN, 0L);
}
////////////////////////////////////////////////////////////////////////////
//
// ClockSize
//
// Sizes the clock to the specified size.
//
////////////////////////////////////////////////////////////////////////////
void ClockSize(
PCLOCKSTR np,
int newWidth,
int newHeight)
{
SetRect(&np->clockRect, 0, 0, newWidth, newHeight);
CompClockDim(np->hWnd, np);
ClockTimerInterval(np->hWnd, np);
}
////////////////////////////////////////////////////////////////////////////
//
// DrawFace
//
// Draws the clock face.
//
////////////////////////////////////////////////////////////////////////////
void DrawFace(
HDC hDC,
PCLOCKSTR np)
{
int i;
RECT tRect;
LPPOINT ppt;
int blobHeight, blobWidth;
blobWidth = MulDiv( MAXBLOBWIDTH,
(np->clockRect.right - np->clockRect.left),
np->HorzRes );
blobHeight = MulDiv(blobWidth, np->aspectN, np->aspectD);
if (blobHeight < 2)
{
blobHeight = 1;
}
if (blobWidth < 2)
{
blobWidth = 2;
}
InflateRect(&np->clockRect, -(blobHeight / 2), -(blobWidth / 2));
np->clockRadius = (np->clockRect.right - np->clockRect.left - 8) / 2;
np->clockCenter.y = np->clockRect.top +
((np->clockRect.bottom - np->clockRect.top) / 2) - 1;
np->clockCenter.x = np->clockRect.left + np->clockRadius + 3;
for (i = 0; i < 60; i++)
{
ppt = rCircleTable + i;
tRect.top = MulDiv(ppt->y, np->clockRadius, 8000) + np->clockCenter.y;
tRect.left = MulDiv(ppt->x, np->clockRadius, 8000) + np->clockCenter.x;
if (i % 5)
{
//
// Draw a dot.
//
if (blobWidth > 2 && blobHeight >= 2)
{
tRect.right = tRect.left + 2;
tRect.bottom = tRect.top + 2;
FillRect(hDC, &tRect, GetStockObject(WHITE_BRUSH));
OffsetRect(&tRect, -1, -1);
FillRect(hDC, &tRect, np->hbrForeground);
tRect.left++;
tRect.top++;
FillRect(hDC, &tRect, np->hbrColorWindow);
}
}
else
{
tRect.right = tRect.left + blobWidth;
tRect.bottom = tRect.top + blobHeight;
OffsetRect(&tRect, -(blobWidth / 2) , -(blobHeight / 2));
SelectObject(hDC, GetStockObject(BLACK_PEN));
SelectObject(hDC, np->hbrBlobColor);
Rectangle(hDC, tRect.left, tRect.top, tRect.right, tRect.bottom);
SelectObject(hDC, np->hpenBlobHlt);
MoveTo(hDC, tRect.left, tRect.bottom - 1);
LineTo(hDC, tRect.left, tRect.top);
LineTo(hDC, tRect.right - 1, tRect.top);
}
}
InflateRect(&np->clockRect, blobHeight / 2, blobWidth / 2);
}
////////////////////////////////////////////////////////////////////////////
//
// DrawHand
//
// Draws the hands of the clock.
//
////////////////////////////////////////////////////////////////////////////
void DrawHand(
HDC hDC,
int pos,
HPEN hPen,
int scale,
int patMode,
PCLOCKSTR np)
{
LPPOINT lppt;
int radius;
MoveTo(hDC, np->clockCenter.x, np->clockCenter.y);
radius = MulDiv(np->clockRadius, scale, 100);
lppt = rCircleTable + pos;
SetROP2(hDC, patMode);
SelectObject(hDC, hPen);
LineTo( hDC,
np->clockCenter.x + MulDiv(lppt->x, radius, 8000),
np->clockCenter.y + MulDiv(lppt->y, radius, 8000) );
}
////////////////////////////////////////////////////////////////////////////
//
// Adjust
//
////////////////////////////////////////////////////////////////////////////
void Adjust(
POINT *rgpt,
int cPoint,
int iDelta)
{
int i;
for (i = 0; i < cPoint; i++)
{
rgpt[i].x += iDelta;
rgpt[i].y += iDelta;
}
}
////////////////////////////////////////////////////////////////////////////
//
// DrawFatHand
//
// Draws either hour or minute hand.
//
////////////////////////////////////////////////////////////////////////////
void DrawFatHand(
HDC hDC,
int pos,
HPEN hPen,
BOOL hHand,
PCLOCKSTR np)
{
int m;
int n;
int scale;
TRIG tip;
TRIG stip;
BOOL fErase;
POINT rgpt[4];
HBRUSH hbrInit, hbrControl = NULL;
SetROP2(hDC, 13);
fErase = (hPen == np->hpenBackground);
SelectObject(hDC, hPen);
scale = hHand ? 7 : 5;
n = (pos + 15) % 60;
m = MulDiv(np->clockRadius, scale, 100);
stip.y = (SHORT)MulDiv(rCircleTable[n].y, m, 8000);
stip.x = (SHORT)MulDiv(rCircleTable[n].x, m, 8000);
scale = hHand ? 65 : 80;
tip.y = (SHORT)MulDiv(rCircleTable[pos % 60].y, MulDiv(np->clockRadius, scale, 100), 8000);
tip.x = (SHORT)MulDiv(rCircleTable[pos % 60].x, MulDiv(np->clockRadius, scale, 100), 8000);
rgpt[0].x = np->clockCenter.x + stip.x;
rgpt[0].y = np->clockCenter.y + stip.y;
rgpt[1].x = np->clockCenter.x + tip.x;
rgpt[1].y = np->clockCenter.y + tip.y;
rgpt[2].x = np->clockCenter.x - stip.x;
rgpt[2].y = np->clockCenter.y - stip.y;
scale = hHand ? 15 : 20;
n = (pos + 30) % 60;
m = MulDiv(np->clockRadius, scale, 100);
tip.y = (SHORT)MulDiv(rCircleTable[n].y, m, 8000);
tip.x = (SHORT)MulDiv(rCircleTable[n].x, m, 8000);
rgpt[3].x = np->clockCenter.x + tip.x;
rgpt[3].y = np->clockCenter.y + tip.y;
SelectObject(hDC, GetStockObject(NULL_PEN));
if (fErase)
{
hbrControl = (HBRUSH)SendMessage(GetParent(np->hWnd), WM_CTLCOLORSTATIC, (WPARAM)hDC, (LPARAM)np->hWnd);
hbrInit = SelectObject(hDC, hbrControl ? hbrControl : np->hbrColorWindow);
}
else
{
hbrInit = SelectObject(hDC, np->hbrBtnHighlight);
}
Adjust(rgpt, 4, -2);
Polygon(hDC, rgpt, 4);
if (!fErase)
{
SelectObject(hDC, np->hbrForeground);
}
Adjust(rgpt, 4, 4);
Polygon(hDC, rgpt, 4);
if (!fErase)
{
SelectObject(hDC, np->hbrBlobColor);
}
Adjust(rgpt, 4, -2);
Polygon(hDC, rgpt, 4);
//
// If we selected a brush in, reset it now.
//
if (fErase)
{
SelectObject(hDC, hbrInit);
}
}
////////////////////////////////////////////////////////////////////////////
//
// ClockPaint
//
// Only paints the clock.
//
// It assumes you have set nTime already. This allows it to be called by
// the timer or by the client.
//
////////////////////////////////////////////////////////////////////////////
void ClockPaint(
PCLOCKSTR np,
HDC hDC,
int hint)
{
SetBkMode(hDC, TRANSPARENT);
if (hint == REPAINT)
{
//
// If doing a full repaint, we do not advance the time.
// Otherwise we will create artifacts when there is a clipping
// region.
//
DrawFace(hDC, np);
DrawFatHand(hDC, np->oTime.hour * 5 + (np->oTime.minute / 12), np->hpenForeground, HHAND,np);
DrawFatHand(hDC, np->oTime.minute, np->hpenForeground, MHAND,np);
//
// Draw the second hand.
//
DrawHand(hDC, np->oTime.second, np->hpenBackground, SECONDSCALE, R2_NOT,np);
}
else if (hint == HANDPAINT)
{
DrawHand(hDC, np->oTime.second, np->hpenBackground, SECONDSCALE, R2_NOT, np);
if (np->nTime.minute != np->oTime.minute || np->nTime.hour != np->oTime.hour)
{
DrawFatHand(hDC, np->oTime.minute, np->hpenBackground, MHAND, np);
DrawFatHand(hDC, np->oTime.hour * 5 + (np->oTime.minute / 12), np->hpenBackground, HHAND,np);
DrawFatHand(hDC, np->nTime.minute, np->hpenForeground, MHAND, np);
DrawFatHand(hDC, (np->nTime.hour) * 5 + (np->nTime.minute / 12), np->hpenForeground, HHAND, np);
}
DrawHand(hDC, np->nTime.second, np->hpenBackground, SECONDSCALE, R2_NOT, np);
np->oTime = np->nTime;
}
}
////////////////////////////////////////////////////////////////////////////
//
// ClockTimer
//
// Update the clock. Called on a timer tick.
//
////////////////////////////////////////////////////////////////////////////
void ClockTimer(
HWND hWnd,
UINT_PTR idTimer,
PCLOCKSTR np)
{
HDC hDC;
GetTimeClock(&np->nTime, np);
if ((np->nTime.second == np->oTime.second) &&
(np->nTime.minute == np->oTime.minute) &&
(np->nTime.hour == np->oTime.hour))
{
return;
}
hDC = GetDC(hWnd);
ClockPaint(np, hDC, HANDPAINT);
ReleaseDC(hWnd, hDC);
}
////////////////////////////////////////////////////////////////////////////
//
// ClockCreate
//
////////////////////////////////////////////////////////////////////////////
void ClockCreate(
HWND hWnd,
PCLOCKSTR np)
{
int i;
HDC hDC;
int HorzSize;
int VertSize;
LPPOINT lppt;
hDC = GetDC(hWnd);
np->VertRes = GetDeviceCaps(hDC, VERTRES);
np->HorzRes = GetDeviceCaps(hDC, HORZRES);
VertSize= GetDeviceCaps(hDC, VERTSIZE);
HorzSize= GetDeviceCaps(hDC, HORZSIZE);
ReleaseDC(hWnd, hDC);
np->aspectN = MulDiv(np->VertRes, 100, VertSize);
np->aspectD = MulDiv(np->HorzRes, 100, HorzSize);
//
// Instance stuff.
//
np->hWnd = hWnd;
CreateTools(np);
//
// Scale cosines for aspect ratio if this is the first instance.
//
for (i = 0; i < 60; i++)
{
lppt = rCircleTable + i;
lppt->y = MulDiv(lppt->y, np->aspectN, np->aspectD);
}
}
////////////////////////////////////////////////////////////////////////////
//
// ClockWndProc
//
// Deals with the clock messages.
//
////////////////////////////////////////////////////////////////////////////
LRESULT CALLBACK ClockWndProc(
HWND hWnd,
UINT message,
WPARAM wParam,
LPARAM lParam)
{
PCLOCKSTR np = (PCLOCKSTR)GetWindowPtr(hWnd, 0);
switch (message)
{
case ( WM_DESTROY ) :
{
if (np)
{
KillTimer(hWnd, TIMER_ID);
DeleteTools(np);
LocalFree((HLOCAL)np);
SetWindowPtr(hWnd, 0, 0);
}
break;
}
case ( WM_CREATE ) :
{
//
// Allocate the instance data space.
//
np = (PCLOCKSTR)LocalAlloc(LPTR, sizeof(CLOCKSTR));
if (!np)
{
return (-1);
}
SetWindowPtr(hWnd, 0, np);
ClockCreate(hWnd, np);
SetLayout(GetDC(hWnd), LAYOUT_BITMAPORIENTATIONPRESERVED);
//
// Loop if control panel time being changed.
//
GetTimeClock(&(np->nTime), np);
do
{
GetTimeClock(&(np->oTime), np);
} while (np->nTime.second == np->oTime.second &&
np->nTime.minute == np->oTime.minute &&
np->nTime.hour == np->oTime.hour);
SetTimer(hWnd, TIMER_ID, OPEN_TLEN, 0L);
ClockSize( np,
((LPCREATESTRUCT)lParam)->cx,
((LPCREATESTRUCT)lParam)->cy );
break;
}
case ( WM_SIZE ) :
{
if (np)
{
ClockSize(np, LOWORD(lParam), HIWORD(lParam));
}
break;
}
case ( WM_PAINT ) :
{
PAINTSTRUCT ps;
BeginPaint(hWnd, &ps);
GetTimeClock(&(np->nTime), np);
ClockPaint(np, ps.hdc, REPAINT);
EndPaint(hWnd, &ps);
break;
}
case ( WM_TIMECHANGE ) :
{
//
// I'm not top level - so I wont get this message.
//
InvalidateRect(hWnd, NULL, TRUE);
if (np->hwndGetTime)
{
SYSTEMTIME System;
GetTime();
System.wHour = wDateTime[HOUR];
System.wMinute = wDateTime[MINUTE];
System.wSecond = wDateTime[SECOND];
SendMessage( np->hwndGetTime,
CLM_UPDATETIME,
CLF_SETTIME,
(LPARAM)(LPSYSTEMTIME)&System );
}
// fall thru...
}
case ( WM_TIMER ) :
{
ClockTimer(hWnd, wParam, np);
break;
}
case ( WM_SYSCOLORCHANGE ) :
{
DeleteTools(np);
CreateTools(np);
break;
}
case ( CLM_UPDATETIME ) :
{
//
// Force the clock to repaint. lParam will point to a
// SYSTEMTIME struct.
//
switch (wParam)
{
case ( CLF_SETTIME ) :
{
//
// Caller wants us to reflect a new time.
//
HDC hDC;
LPSYSTEMTIME lpSysTime = (LPSYSTEMTIME)lParam;
np->nTime.hour = lpSysTime->wHour;
np->nTime.minute = lpSysTime->wMinute;
np->nTime.second = lpSysTime->wSecond;
hDC = GetDC(hWnd);
ClockPaint(np, hDC, HANDPAINT);
ReleaseDC(hWnd, hDC);
break;
}
case ( CLF_GETTIME ) :
{
//
// Caller wants to know what we think the time is.
//
LPSYSTEMTIME lpSysTime = (LPSYSTEMTIME)lParam;
lpSysTime->wHour = (WORD)np->nTime.hour;
lpSysTime->wMinute = (WORD)np->nTime.minute;
lpSysTime->wSecond = (WORD)np->nTime.second;
break;
}
}
break;
}
case ( CLM_TIMEHWND ) :
{
//
// Get/Set the HWND that we ask to provide the time.
//
switch (wParam)
{
case ( CLF_SETHWND ) :
{
//
// Caller wants us to reflect a new time.
//
np->hwndGetTime = (HWND)lParam;
break;
}
case ( CLF_GETTIME ) :
{
//
// Caller wants to know what we think the time is.
//
*((HWND *)lParam) = np->hwndGetTime;
break;
}
}
break;
}
default :
{
return ( DefWindowProc(hWnd, message, wParam, lParam) );
}
}
return (0);
}