This repository has been archived on 2024-12-16. You can view files and clone it, but cannot push or open issues or pull requests.
CodeBlocksPortable/WATCOM/samples/win/alarm/alarm.c

1047 lines
29 KiB
C

#include <stdio.h>
#include <windows.h>
#include <time.h>
#include "alarm.h"
HINSTANCE MyInstance;
char AlarmClass[32]="AlarmClass";
digit_index NumberOfDigits = DIGITS_WITH_SECONDS;
digit_index DigitsToDraw;
unsigned ScreenWidthInMM;
unsigned ScreenHeightInMM;
/* following variables have units in Pixels */
pixels ScreenWidth;
pixels ScreenHeight;
pixels WidthOfClock;
pixels HeightOfClock;
pixels WidthOfWindow;
pixels HeightOfWindow;
pixels InterSegmentGap;
pixels SegmentHeight;
pixels SegmentWidth;
char Buffer[BUFLEN];
digit ClockDigits[DIGITS_WITH_SECONDS];
unsigned AlarmDigits[DIGITS_WITH_SECONDS];
colon Colons[NUMBER_OF_COLONS];
BOOL AlarmPM = FALSE;
HPEN Pens[NUMBER_OF_PENS];
BOOL FirstAlarmSetting = TRUE;
BOOL TwelveHour = TRUE;
BOOL Setting;
unsigned Tick;
static BOOL AlarmIsRinging;
static BOOL FirstInstance( HINSTANCE this_inst );
static BOOL AnyInstance( HINSTANCE this_inst, int cmdshow );
void CreateSupplies( void );
void DeleteSupplies( void );
static void InitializeTheClock( void );
static void PaintClock( HDC dc );
static void ReSize( pixels width, pixels height, WORD type );
int PASCAL WinMain( HINSTANCE this_inst, HINSTANCE prev_inst,
LPSTR cmdline, int cmdshow )
/***********************************************
Initialization, message loop.
*/
{
MSG msg;
cmdline = cmdline;
MyInstance = this_inst;
#ifdef __WINDOWS_386__
sprintf( AlarmClass,"AlarmClass%d", this_inst );
prev_inst = 0;
#endif
if( !prev_inst ) {
if( !FirstInstance( this_inst ) ) return( FALSE );
}
if( !AnyInstance( this_inst, cmdshow ) ) return( FALSE );
while( GetMessage( &msg, (HWND)0, 0, 0 ) ) {
TranslateMessage( &msg );
DispatchMessage( &msg );
}
return( msg.wParam );
}
long _EXPORT FAR PASCAL WindowProc( HWND, unsigned, UINT, LONG );
static BOOL FirstInstance( HINSTANCE this_inst )
/********************************************
Register window class for the application,
and do any other application initialization.
*/
{
WNDCLASS wc;
BOOL rc;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (LPVOID) WindowProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = this_inst;
wc.hIcon = (HICON)0;
wc.hCursor = LoadCursor( (HINSTANCE)0, IDC_ARROW );
wc.hbrBackground = GetStockObject( WHITE_BRUSH );
wc.lpszMenuName = "AlarmMenu";
wc.lpszClassName = AlarmClass;
rc = RegisterClass( &wc );
return( rc );
}
static BOOL AnyInstance( HINSTANCE this_inst, int cmdshow )
/*******************************************************
Do work required for every instance of the application:
create the window, initialize data.
*/
{
HDC dc;
HWND win_handle;
/*
* create main window
*/
dc = GetDC( (HWND)0 );
ScreenHeight = GetDeviceCaps( dc, VERTRES );
ScreenWidth = GetDeviceCaps( dc, HORZRES );
ScreenHeightInMM = GetDeviceCaps( dc, VERTSIZE );
ScreenWidthInMM = GetDeviceCaps( dc, HORZSIZE );
ReleaseDC( (HWND)0, dc );
CreateSupplies();
win_handle = CreateWindow(
AlarmClass, /* class */
"Alarm Clock", /* caption */
WS_OVERLAPPEDWINDOW, /* style */
CW_USEDEFAULT, /* init. x pos */
CW_USEDEFAULT, /* init. y pos */
CW_USEDEFAULT, /* init. x size */
CW_USEDEFAULT, /* init. y size */
(HWND)0, /* parent window */
(HWND)0, /* menu handle */
this_inst, /* program handle */
NULL /* create parms */
);
if( !win_handle ) return( FALSE );
/*
* display window
*/
ShowWindow( win_handle, cmdshow );
UpdateWindow( win_handle );
if( !SetTimer( win_handle, TIMER_ID, ONE_SECOND/4, 0L ) ) {
MessageBox( (HWND)0, "Too many timers in use", Buffer,
MB_ICONHAND+MB_OK+MB_SYSTEMMODAL );
return( FALSE );
}
return( TRUE );
}
BOOL _EXPORT FAR PASCAL About( HWND win_handle, unsigned msg,
WORD wparam, LONG lparam )
/*********************************************************
Process messages for the about dialog.
*/
{
lparam = lparam; /* turn off warning */
win_handle = win_handle;
switch( msg ) {
case WM_INITDIALOG:
return( TRUE );
case WM_COMMAND:
if( wparam == IDOK ) {
EndDialog( win_handle, TRUE );
return( TRUE );
}
break;
}
return( FALSE );
}
static void TransferClockToAlarm( void )
/***************************************
Transfer the digits from the Clock array to the Alarm array.
*/
{
digit_index i;
for( i = 0; i < DIGITS_WITH_SECONDS; ++i ) {
AlarmDigits[i] = ClockDigits[i].value;
}
}
static void TransferAlarmToClock( void )
/***************************************
Transfer digits from the Alarm array to the Clock array
*/
{
digit_index i;
for( i = 0; i < DIGITS_WITH_SECONDS; ++i ) {
ClockDigits[i].value = AlarmDigits[i];
}
}
static void RePaintTheClock( HWND win_handle )
/*********************************************
Re-paint the entire clock, since it has been invalidated.
*/
{
PAINTSTRUCT ps;
InvalidateRect( win_handle, NULL, TRUE );
BeginPaint( win_handle, &ps );
InitializeTheClock();
PaintClock( ps.hdc );
EndPaint( win_handle, &ps );
}
static void CheckAlarm( void )
/*****************************
See if the alarm has gone off, and pop up a message box if it has.
*/
{
digit_index i;
if( AlarmIsRinging ) return;
for( i = 0; i < DIGITS_WITH_SECONDS; ++i ) {
if( AlarmDigits[i] != ClockDigits[i].value ) return;
}
AlarmIsRinging = TRUE;
MessageBox( (HWND)0, "The alarm clock is ringing!", Buffer,
MB_ICONEXCLAMATION | MB_OK | MB_TASKMODAL );
AlarmIsRinging = FALSE;
}
static void UpdateTheClock( HWND win_handle )
/********************************************
Incrementally update the clock display.
*/
{
HDC dc;
dc = GetDC( win_handle );
PaintClock( dc );
ReleaseDC( win_handle, dc );
}
static void SetNumberOfDigits( digit_index num )
/***********************************************
Set the number of digits to be displayed (4 or 6)
*/
{
NumberOfDigits = num;
DigitsToDraw = num;
}
static void SetAlarm( void )
/***************************
Put the clock into alarm setting mode.
*/
{
if( Setting ) return;
Setting = TRUE;
if( FirstAlarmSetting ) {
TransferClockToAlarm();
if( NumberOfDigits == DIGITS_WITHOUT_SECONDS ) {
AlarmDigits[SEC_TENS] = 0;
AlarmDigits[SEC_ONES] = 0;
}
FirstAlarmSetting = FALSE;
}
TransferAlarmToClock();
}
static void RunTheClock( void )
/******************************
Put the clock into running mode.
*/
{
if( !Setting ) return;
Setting = FALSE;
TransferClockToAlarm();
}
static void Set12HourClock( HWND win_handle )
/********************************************
Put the clock into 12 hour mode.
*/
{
int i;
if( TwelveHour ) return;
TwelveHour = TRUE;
i = AlarmDigits[HOUR_TENS]*10 + AlarmDigits[HOUR_ONES];
if( i > 12 ) {
i -= 12;
AlarmPM = TRUE;
}
AlarmDigits[HOUR_TENS] = i / 10;
AlarmDigits[HOUR_ONES] = i % 10;
if( Setting ) TransferAlarmToClock();
UpdateTheClock( win_handle );
}
static void Set24HourClock( HWND win_handle )
/********************************************
Put the clock into 24 hour mode
*/
{
int i;
if( !TwelveHour ) return;
TwelveHour = FALSE;
i = AlarmDigits[HOUR_TENS]*10 + AlarmDigits[HOUR_ONES];
if( i <= 12 && AlarmPM ) {
i += 12;
AlarmPM = FALSE;
}
AlarmDigits[HOUR_TENS] = i / 10;
AlarmDigits[HOUR_ONES] = i % 10;
if( Setting ) TransferAlarmToClock();
UpdateTheClock( win_handle );
}
static void DisplayAboutBox( HWND win_handle )
/*********************************************
Display the "About ..." box
*/
{
FARPROC proc;
proc = MakeProcInstance( (FARPROC)About, MyInstance );
DialogBox( MyInstance, "AboutBox", win_handle, (DLGPROC)proc );
FreeProcInstance( proc );
}
static void MenuItem( HWND win_handle, WORD wparam )
/***************************************************
Handle a menu item which has been selected by the user.
*/
{
switch( wparam ) {
case MENU_ABOUT:
DisplayAboutBox( win_handle );
break;
case MENU_DISPLAY_SECONDS:
SetNumberOfDigits( DIGITS_WITH_SECONDS );
break;
case MENU_SUPRESS_SECONDS:
SetNumberOfDigits( DIGITS_WITHOUT_SECONDS );
break;
case MENU_SET_ALARM:
SetAlarm();
break;
case MENU_RUN_CLOCK:
RunTheClock();
break;
case MENU_12_HOUR_CLOCK:
Set12HourClock( win_handle );
break;
case MENU_24_HOUR_CLOCK:
Set24HourClock( win_handle );
break;
}
InvalidateRect( win_handle, NULL, TRUE );
}
static int Check[] = { MF_UNCHECKED, MF_CHECKED };
static void InitMenu( HMENU mh )
/*******************************
Initialize the menu display. Disable any items which are not applicable.
*/
{
BOOL on;
CheckMenuItem( mh, MENU_SET_ALARM, Check[ Setting ] );
CheckMenuItem( mh, MENU_RUN_CLOCK, Check[ !Setting ] );
on = ( NumberOfDigits == DIGITS_WITHOUT_SECONDS );
CheckMenuItem( mh, MENU_SUPRESS_SECONDS, Check[ on ] );
CheckMenuItem( mh, MENU_DISPLAY_SECONDS, Check[ !on ] );
CheckMenuItem( mh, MENU_24_HOUR_CLOCK, Check[ !TwelveHour ] );
CheckMenuItem( mh, MENU_12_HOUR_CLOCK, Check[ TwelveHour ] );
}
static unsigned MaximumNumber[] = { 0, 0, 5, 9, 5, 9 };
static void MouseClick( pixels x, pixels y, unsigned msg )
/*********************************************************
Handle a mouse click at position x,y.
*/
{
digit_index i;
TransferAlarmToClock();
if( TwelveHour ) {
MaximumNumber[HOUR_TENS] = 1;
if( ClockDigits[HOUR_TENS].value == 1 ) {
MaximumNumber[HOUR_ONES] = 2;
} else {
MaximumNumber[HOUR_ONES] = 9;
}
} else {
MaximumNumber[HOUR_TENS] = 2;
if( ClockDigits[HOUR_TENS].value == 2 ) {
MaximumNumber[HOUR_ONES] = 4;
} else {
MaximumNumber[HOUR_ONES] = 9;
}
}
for( i = 0; i < NumberOfDigits; ++i ) {
if( x < ClockDigits[i].segment[SEGMENT_0].position.start.x ) continue;
if( x > ClockDigits[i].segment[SEGMENT_6].position.end.x ) continue;
if( y < ClockDigits[i].segment[SEGMENT_0].position.start.y ) continue;
if( y > ClockDigits[i].segment[SEGMENT_6].position.end.y ) continue;
if( msg == WM_LBUTTONDOWN ) {
ClockDigits[i].value++;
} else if( msg == WM_RBUTTONDOWN ) {
ClockDigits[i].value--;
}
if( ClockDigits[i].value > MaximumNumber[ i ] ) {
ClockDigits[i].value = 0;
} else if( ClockDigits[i].value < 0 ) {
ClockDigits[i].value = MaximumNumber[i];
}
}
if( TwelveHour ) {
if( x < ClockDigits[HOUR_TENS].segment[SEGMENT_0].position.start.x &&
y > ClockDigits[HOUR_TENS].segment[SEGMENT_0].position.start.y &&
y < ClockDigits[HOUR_TENS].segment[SEGMENT_6].position.end.y ) {
AlarmPM = !AlarmPM;
}
if( ClockDigits[HOUR_TENS].value == 1 && ClockDigits[HOUR_ONES].value > 2 ) {
ClockDigits[HOUR_ONES].value = 2;
}
if( ClockDigits[HOUR_TENS].value == 0 &&
ClockDigits[HOUR_ONES].value == 0 ) {
ClockDigits[HOUR_ONES].value = 1;
}
} else {
if( ClockDigits[HOUR_TENS].value == 2 &&
ClockDigits[HOUR_ONES].value > 4 ) {
ClockDigits[HOUR_ONES].value = 4;
}
}
TransferClockToAlarm();
}
LONG _EXPORT FAR PASCAL WindowProc( HWND win_handle, unsigned msg,
UINT wparam, LONG lparam )
/**************************************************************
Handle messages for the main application window.
*/
{
switch( msg ) {
case WM_INITMENU:
InitMenu( (HMENU)wparam );
break;
case WM_COMMAND:
MenuItem( win_handle, LOWORD(wparam) );
break;
case WM_SYSCOLORCHANGE:
DeleteSupplies();
CreateSupplies();
break;
case WM_PAINT:
RePaintTheClock( win_handle );
break;
case WM_TIMER:
case WM_TIMECHANGE:
if( Setting ) break;
Tick++;
CheckAlarm();
UpdateTheClock( win_handle );
break;
case WM_SIZE:
ReSize( LOWORD( lparam ), HIWORD( lparam ), wparam );
break;
case WM_DESTROY:
DeleteSupplies();
KillTimer( win_handle, TIMER_ID );
PostQuitMessage( 0 );
break;
case WM_LBUTTONDOWN:
case WM_RBUTTONDOWN:
if( !Setting ) break;
MouseClick( LOWORD( lparam ), HIWORD( lparam ), msg );
UpdateTheClock( win_handle );
break;
default:
return( DefWindowProc( win_handle, msg, wparam, lparam ) );
}
return( 0L );
}
static seg_position SegPosition[ NUMBER_OF_SEGMENTS ] =
/*******************************************************
These are the positions of the start and end points
of each digit segment segments based on the
following co-ordinate system.
(0,0) ---0--- (1,0)
| |
1 2
| |
(0,1) ---3--- (1,1)
| |
4 5
| |
(0,2) ---6--- (1,2)
*/
/* start.x start.y end.x end.y */
{
{ 0, 0, 1, 0 }, /* 0 */
{ 0, 0, 0, 1 }, /* 1 */
{ 1, 0, 1, 1 }, /* 2 */
{ 0, 1, 1, 1 }, /* 3 */
{ 0, 1, 0, 2 }, /* 4 */
{ 1, 1, 1, 2 }, /* 5 */
{ 0, 2, 1, 2 }, /* 6 */
};
/*************************************************************************
The following arrays define the polygon for each digit segment
based on the two end points defined in SegPosition. Each entry
is an (x,y) point based on the start or end point of the line
segment plus some delta in the x and y direction. For example,
START+UP_QUARTER+RITE_HALF means the starting point of the line
segment, moved up 1/4 of a segment width, and rite 1/2 of a
segment width
*/
typedef enum {
START = 0x0001,
END = 0x0002,
DOWN_ONE = 0x0004,
UP_ONE = 0x0008,
DOWN_HALF = 0x0010,
UP_HALF = 0x0020,
DOWN_QUARTER = 0x0040,
UP_QUARTER = 0x0080,
LEFT_ONE = 0x0100,
RITE_ONE = 0x0200,
LEFT_HALF = 0x0400,
RITE_HALF = 0x0800,
LEFT_QUARTER = 0x1000,
RITE_QUARTER = 0x2000
} point_delta;
static point_delta Poly0[] = {
START+UP_QUARTER+RITE_QUARTER,
END+UP_QUARTER+LEFT_QUARTER,
END,
END+DOWN_ONE+LEFT_ONE,
START+DOWN_ONE+RITE_ONE,
START,
0
};
static point_delta Poly1[] = {
START+DOWN_QUARTER+LEFT_QUARTER,
END+UP_QUARTER+LEFT_QUARTER,
END,
END+UP_HALF+RITE_ONE,
START+DOWN_ONE+RITE_ONE,
START,
0
};
static point_delta Poly2[] = {
START+RITE_QUARTER+DOWN_QUARTER,
END+UP_QUARTER+RITE_QUARTER,
END,
END+UP_HALF+LEFT_ONE,
START+DOWN_ONE+LEFT_ONE,
START,
0
};
static point_delta Poly3[] = {
START+UP_HALF+RITE_ONE,
END+UP_HALF+LEFT_ONE,
END,
END+DOWN_HALF+LEFT_ONE,
START+DOWN_HALF+RITE_ONE,
START,
0
};
static point_delta Poly4[] = {
START+DOWN_QUARTER+LEFT_QUARTER,
END+UP_QUARTER+LEFT_QUARTER,
END,
END+UP_ONE+RITE_ONE,
START+DOWN_HALF+RITE_ONE,
START,
0
};
static point_delta Poly5[] = {
START+RITE_QUARTER+DOWN_QUARTER,
END+UP_QUARTER+RITE_QUARTER,
END,
END+UP_ONE+LEFT_ONE,
START+DOWN_HALF+LEFT_ONE,
START,
0
};
static point_delta Poly6[] = {
START+DOWN_QUARTER+RITE_QUARTER,
END+DOWN_QUARTER+LEFT_QUARTER,
END,
END+UP_ONE+LEFT_ONE,
START+UP_ONE+RITE_ONE,
START,
0
};
static point_delta *SegPoly[] =
{
&Poly0, &Poly1, &Poly2, &Poly3, &Poly4, &Poly5, &Poly6
};
static void DrawSegment( HDC dc, pen_type pen,
seg_position *pos, point_delta *delta )
/***************************************************************
Draw the polygon for a segment of a digit.
*/
{
pixels x,y;
pixels one_x,one_y;
pixels half_x,half_y;
pixels quarter_x,quarter_y;
one_y = SegmentHeight;
half_y = SegmentHeight / 2;
quarter_y = SegmentHeight / 4;
if( one_y <= 2 ) one_y = 1;
one_x = SegmentWidth;
half_x = SegmentWidth / 2;
quarter_x = SegmentWidth / 4;
if( one_x <= 2 ) one_x = 1;
SelectObject( dc, Pens[pen] );
MoveToEx( dc, pos->start.x, pos->start.y, NULL );
while( *delta != 0 ) {
if( *delta & START ) {
x = pos->start.x;
y = pos->start.y;
} else if( *delta & END ) {
x = pos->end.x;
y = pos->end.y;
}
if( *delta & UP_QUARTER ) y -= quarter_y;
if( *delta & UP_HALF ) y -= half_y;
if( *delta & UP_ONE ) y -= one_y;
if( *delta & DOWN_QUARTER ) y += quarter_y;
if( *delta & DOWN_HALF ) y += half_y;
if( *delta & DOWN_ONE ) y += one_y;
if( *delta & LEFT_QUARTER ) x -= quarter_x;
if( *delta & LEFT_HALF ) x -= half_x;
if( *delta & LEFT_ONE ) x -= one_x;
if( *delta & RITE_QUARTER ) x += quarter_x;
if( *delta & RITE_HALF ) x += half_x;
if( *delta & RITE_ONE ) x += one_x;
LineTo( dc, x, y );
++delta;
}
LineTo( dc, pos->start.x, pos->start.y );
}
static BOOL SegmentOnInDigit[ 11 ][ NUMBER_OF_SEGMENTS ] =
/*********************************************************
SegmentIsOn[ i ][ j ] indicates whether or not segment number i should
be turned on in the digit j.
*/
{
/* 0 1 2 3 4 5 6 */
{ TRUE, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE }, /* 0 */
{ FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, FALSE }, /* 1 */
{ TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, TRUE }, /* 2 */
{ TRUE, FALSE, TRUE, TRUE, FALSE, TRUE, TRUE }, /* 3 */
{ FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, FALSE }, /* 4 */
{ TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE }, /* 5 */
{ TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE }, /* 6 */
{ TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE }, /* 7 */
{ TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE }, /* 8 */
{ TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE }, /* 9 */
{ FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, /* 10 */
};
static void DrawDigit( HDC dc, digit *p )
/****************************************
Draw one digit of the the clock.
*/
{
segment_index i;
for( i = 0; i < NUMBER_OF_SEGMENTS; ++i ) {
if( SegmentOnInDigit[ p->value ][ i ] ) {
if( !p->segment[i].on ) {
DrawSegment( dc, FOREGROUND,
&p->segment[i].position, SegPoly[i] );
p->segment[i].on = TRUE;
}
} else {
if( p->segment[i].on ) {
DrawSegment( dc, BACKGROUND,
&p->segment[i].position, SegPoly[i] );
p->segment[i].on = FALSE;
}
}
}
}
static void UpdateColon( HDC dc, colon_index i, pen_type *pen )
/**************************************************************
Draw the colon separating the clock digits (and the AM/PM indicator)
*/
{
dot_index j;
for( j = 0; j < NUMBER_OF_DOTS; ++j ) {
if( Colons[i].dot[j].pen != pen[j] ) {
SelectObject( dc, Pens[ pen[j] ] );
Rectangle( dc, Colons[i].dot[j].top_left.x,
Colons[i].dot[j].top_left.y,
Colons[i].dot[j].bot_rite.x,
Colons[i].dot[j].bot_rite.y );
Colons[i].dot[j].pen = pen[j];
}
}
}
static void DrawColon( HDC dc, colon_index i )
/*********************************************
Draw the colon separating the digits. It flashes if seconds are supressed
*/
{
pen_type pen[NUMBER_OF_DOTS];
pen[TOP_DOT] = FOREGROUND;
if( !Setting && ( DigitsToDraw == DIGITS_WITHOUT_SECONDS ) &&
( ( Tick % 4 ) < 2 ) ) {
pen[TOP_DOT] = BACKGROUND;
}
pen[BOT_DOT] = pen[TOP_DOT];
UpdateColon( dc, i, pen );
}
static void DrawPM( HDC dc, BOOL pm )
/************************************
Draw the AM/PM indicator (This is just a colon in front of the first digit
*/
{
pen_type pen[NUMBER_OF_DOTS];
if( pm ) {
pen[TOP_DOT] = BACKGROUND;
pen[BOT_DOT] = FOREGROUND;
} else {
pen[BOT_DOT] = BACKGROUND;
pen[TOP_DOT] = FOREGROUND;
}
UpdateColon( dc, 0, pen );
}
static void PaintClock( HDC dc )
/*******************************
Paint the clock face on the screen
*/
{
digit_index i;
time_t ltime;
struct tm *t;
BOOL pm;
pm = FALSE;
if( !Setting ) {
time( &ltime );
t = localtime( &ltime );
if( TwelveHour ) {
if( t->tm_hour > 12 ) {
t->tm_hour -= 12;
pm = TRUE;
} else if( t->tm_hour == 0 ) {
t->tm_hour = 12;
}
}
ClockDigits[HOUR_TENS].value = t->tm_hour / 10;
ClockDigits[HOUR_ONES].value = t->tm_hour % 10;
ClockDigits[MIN_TENS].value = t->tm_min / 10;
ClockDigits[MIN_ONES].value = t->tm_min % 10;
ClockDigits[SEC_TENS].value = t->tm_sec / 10;
ClockDigits[SEC_ONES].value = t->tm_sec % 10;
} else {
pm = AlarmPM;
}
if( ClockDigits[HOUR_TENS].value == 0 ) {
ClockDigits[HOUR_TENS].value = BLANK_SPACE_VALUE;
}
for( i = 0; i < DigitsToDraw; ++i ) {
DrawDigit( dc, &ClockDigits[i] );
}
DrawColon( dc, 1 );
if( DigitsToDraw == DIGITS_WITH_SECONDS ) {
DrawColon( dc, 2 );
}
if( TwelveHour ) {
DrawPM( dc, pm );
}
if( ClockDigits[HOUR_TENS].value == BLANK_SPACE_VALUE ) {
ClockDigits[HOUR_TENS].value = 0;
}
}
static void SetColonPos( colon_index i )
/***************************************
Set the screen positions for colon number "i".
*/
{
pixels dx,dy;
pixels add_x,add_y,sub_x,sub_y;
pixels x1,y1,x2,y2;
y1 = ClockDigits[i].segment[SEGMENT_0].position.start.y;
y2 = ClockDigits[i].segment[SEGMENT_6].position.start.y;
switch( i ) {
case 0:
x1 = 0;
x2 = ClockDigits[HOUR_TENS].segment[SEGMENT_0].position.start.x;
break;
case 1:
x1 = ClockDigits[HOUR_ONES].segment[SEGMENT_0].position.end.x;
x2 = ClockDigits[MIN_TENS].segment[SEGMENT_0].position.start.x;
break;
case 2:
x1 = ClockDigits[MIN_ONES].segment[SEGMENT_0].position.end.x;
x2 = ClockDigits[SEC_TENS].segment[SEGMENT_0].position.start.x;
break;
}
dx = ( x2 - x1 ) / 2;
dy = ( y2 - y1 ) / 3;
add_x = dx / PORTION_FOR_COLON;
sub_x = -add_x;
if( add_x == 0 ) add_x = 1;
add_y = dy / PORTION_FOR_COLON;
sub_y = -add_y;
if( add_y == 0 ) add_y = 1;
x1 += dx;
y1 += dy;
Colons[i].dot[TOP_DOT].top_left.x = x1 + sub_x;
Colons[i].dot[TOP_DOT].top_left.y = y1 + sub_y;
Colons[i].dot[TOP_DOT].bot_rite.x = x1 + add_x;
Colons[i].dot[TOP_DOT].bot_rite.y = y1 + add_y;
Colons[i].dot[TOP_DOT].pen = BACKGROUND;
y1 += dy;
Colons[i].dot[BOT_DOT].top_left.x = x1 + sub_x;
Colons[i].dot[BOT_DOT].top_left.y = y1 + sub_y;
Colons[i].dot[BOT_DOT].bot_rite.x = x1 + add_x;
Colons[i].dot[BOT_DOT].bot_rite.y = y1 + add_y;
Colons[i].dot[BOT_DOT].pen = BACKGROUND;
}
static void InitializeTheClock( void )
/*************************************
Initialize each digit of the clock. Calculate the screen position
of each segment of each digit of the clock, as well as the
screen positions of the colons.
*/
{
pixels win_left,win_rite;
pixels top_of_clock;
pixels top,bot;
pixels left,rite;
pixels width,height;
pixels space;
pixels colon_space;
digit_index i;
segment_index j;
long width_scale;
long height_scale;
HeightOfClock = HeightOfWindow;
if( HeightOfClock < MINIMUM_HEIGHT ) {
HeightOfClock = MINIMUM_HEIGHT;
}
WidthOfClock = WidthOfWindow;
height_scale = (long)ScreenHeightInMM * DIGIT_HEIGHT_SCALE;
width_scale = (long)ScreenWidthInMM * DIGIT_WIDTH_SCALE / ( DigitsToDraw + 1 ); /* Allow for 2 colons */
if( WidthOfClock * width_scale > HeightOfClock * height_scale ) {
WidthOfClock = HeightOfClock * height_scale / width_scale;
} else {
HeightOfClock = WidthOfClock * width_scale / height_scale;
}
top_of_clock = ( HeightOfWindow - HeightOfClock ) / 2;
top = HeightOfClock / UNUSED_PORTION_OF_SCREEN_HEIGHT;
bot = HeightOfClock - top;
height = bot - top;
top += top_of_clock;
win_left = WidthOfClock / UNUSED_PORTION_OF_SCREEN_WIDTH;
win_rite = WidthOfClock - win_left;
space = ( win_rite - win_left ) / ( DigitsToDraw + 1 );
InterSegmentGap = space / PORTION_FOR_SEGMENT_GAP;
SegmentWidth = space / PORTION_OF_SPACE_FOR_SEGMENT;
SegmentHeight = (long)SegmentWidth * ScreenHeightInMM / ScreenWidthInMM;
left = space / UNUSED_PORTION_OF_DIGIT_SPACE;
rite = space - left;
width = rite - left;
for( i = 0; i < DigitsToDraw; ++i ) {
for( j = 0; j < NUMBER_OF_SEGMENTS; ++j ) {
ClockDigits[i].segment[j].on = FALSE;
ClockDigits[i].segment[j].position = SegPosition[j];
/* scale the co-ordinates */
ClockDigits[i].segment[j].position.start.x *= width;
ClockDigits[i].segment[j].position.end.x *= width;
ClockDigits[i].segment[j].position.start.y *= height / 2;
ClockDigits[i].segment[j].position.end.y *= height / 2;
/* adjust for left edge of digit's bounding box and window */
colon_space = i / 2 * ( width / 2 ); /* 0,1 -> 0, 2,3 -> 1/2 width, 4,5 -> width */
ClockDigits[i].segment[j].position.start.x += colon_space + i * space + left + win_left;
ClockDigits[i].segment[j].position.end.x += colon_space + i * space + left + win_left;
/* adjust for top edge of digit's bounding box */
ClockDigits[i].segment[j].position.start.y += top;
ClockDigits[i].segment[j].position.end.y += top;
/* adjust all edges for gap */
if( SegPosition[j].start.x != SegPosition[j].end.x ) {
ClockDigits[i].segment[j].position.start.x += InterSegmentGap;
ClockDigits[i].segment[j].position.end.x -= InterSegmentGap;
} else {
ClockDigits[i].segment[j].position.start.y += InterSegmentGap;
ClockDigits[i].segment[j].position.end.y -= InterSegmentGap;
}
}
}
for( i = 0; i < NUMBER_OF_COLONS; ++i ) {
SetColonPos( i );
}
}
static void ReSize( pixels width, pixels height, WORD type )
/***********************************************************
Record the new size of the window and redraw the clock accordingly
*/
{
WidthOfWindow = width;
HeightOfWindow = height;
DigitsToDraw = NumberOfDigits;
if( type == SIZEICONIC ) {
DigitsToDraw = DIGITS_WITHOUT_SECONDS;
} else {
DigitsToDraw = NumberOfDigits;
}
InitializeTheClock();
}
void CreateSupplies( void )
/**************************
Create the art supplies we need
*/
{
Pens[FOREGROUND] = CreatePen( 0, 1, GetSysColor( COLOR_WINDOWTEXT ) );
Pens[BACKGROUND] = CreatePen( 0, 1, GetSysColor( COLOR_WINDOW ) );
}
void DeleteSupplies( void )
/**************************
Delete our art supplies
*/
{
DeleteObject( Pens[FOREGROUND] );
DeleteObject( Pens[BACKGROUND] );
}