home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c500 / 4.ddi / ALARM.WEX / ALARM.C next >
Encoding:
C/C++ Source or Header  |  1992-05-28  |  27.3 KB  |  1,064 lines

  1. /*
  2.  *%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  3.  *%                                       %
  4.  *%    Copyright (C) 1991, by WATCOM Systems Inc. All rights reserved.    %
  5.  *%                                       %
  6.  *%     Permission is granted to anyone to use this example program for       %
  7.  *%     any purpose on any computer system, subject to the following       %
  8.  *%    restrictions:                               %
  9.  *%                                       %
  10.  *%     1. This example is provided on an "as is" basis, without warranty. %
  11.  *%       You indemnify, hold harmless and defend WATCOM from and against %
  12.  *%       any claims or lawsuits, including attorney's, that arise or       %
  13.  *%       result from the use or distribution of this example, or any     %
  14.  *%       modification thereof.                       %
  15.  *%                                       %
  16.  *%     2. You may not remove, alter or suppress this notice from this       %
  17.  *%        example program or any modification thereof.               %
  18.  *%                                       %
  19.  *%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  20.  *
  21.  * ALARM.C
  22.  *
  23.  * Windows alarm clock program
  24.  *
  25.  */
  26.  
  27. #include <stdio.h>
  28. #include <windows.h>
  29. #include <time.h>
  30. #include "alarm.h"
  31.  
  32. char        AlarmClass[32]="AlarmClass";
  33.  
  34. digit_index    NumberOfDigits = DIGITS_WITH_SECONDS;
  35. digit_index    DigitsToDraw;
  36.  
  37. unsigned    ScreenWidthInMM;
  38. unsigned    ScreenHeightInMM;
  39.  
  40. /* following variables have units in Pixels */
  41. pixels    ScreenWidth;
  42. pixels    ScreenHeight;
  43. pixels    WidthOfClock;
  44. pixels    HeightOfClock;
  45. pixels    WidthOfWindow;
  46. pixels    HeightOfWindow;
  47. pixels    InterSegmentGap;
  48. pixels    SegmentHeight;
  49. pixels    SegmentWidth;
  50.  
  51. char        Buffer[BUFLEN];
  52. digit        ClockDigits[DIGITS_WITH_SECONDS];
  53. unsigned    AlarmDigits[DIGITS_WITH_SECONDS];
  54. colon        Colons[NUMBER_OF_COLONS];
  55. BOOL        AlarmPM = FALSE;
  56. HPEN        Pens[NUMBER_OF_PENS];
  57. BOOL        FirstAlarmSetting = TRUE;
  58. BOOL        TwelveHour = TRUE;
  59. BOOL        Setting;
  60. unsigned    Tick;
  61.  
  62. static BOOL FirstInstance( HANDLE this_inst );
  63. static BOOL AnyInstance( HANDLE this_inst, int cmdshow );
  64.  
  65. int PASCAL WinMain( HANDLE this_inst, HANDLE prev_inst,
  66.                     LPSTR cmdline, int cmdshow )
  67. /***********************************************
  68.  
  69.     Initialization, message loop.
  70. */
  71. {
  72.     MSG        msg;
  73.  
  74.     cmdline = cmdline;
  75.     prev_inst = prev_inst;
  76. #ifdef __WINDOWS_386__
  77.     sprintf( AlarmClass,"AlarmClass%d", this_inst );
  78. #else
  79.     if( !prev_inst ) 
  80. #endif
  81.     if( !FirstInstance( this_inst ) ) return( FALSE );
  82.  
  83.     if( !AnyInstance( this_inst, cmdshow ) ) return( FALSE );
  84.  
  85.     while( GetMessage( &msg, NULL, NULL, NULL ) ) {
  86.  
  87.     TranslateMessage( &msg );
  88.     DispatchMessage( &msg );
  89.  
  90.     }
  91.  
  92.     return( msg.wParam );
  93.  
  94. }
  95.  
  96. long _EXPORT FAR PASCAL WindowProc( HWND, unsigned, WORD, LONG );
  97.  
  98. static BOOL FirstInstance( HANDLE this_inst )
  99. /********************************************
  100.  
  101.     Register window class for the application,
  102.     and do any other application initialization.
  103. */
  104. {
  105.     WNDCLASS    wc;
  106.     BOOL    rc;
  107.  
  108.     wc.style = CS_HREDRAW | CS_VREDRAW;
  109.     wc.lpfnWndProc = (LPVOID) WindowProc;
  110.     wc.cbClsExtra = 0;
  111.     wc.cbWndExtra = 0;
  112.     wc.hInstance = this_inst;
  113.     wc.hIcon = NULL;
  114.     wc.hCursor = LoadCursor( NULL, IDC_ARROW );
  115.     wc.hbrBackground = GetStockObject( WHITE_BRUSH );
  116.     wc.lpszMenuName = "AlarmMenu";
  117.     wc.lpszClassName = AlarmClass;
  118.     rc = RegisterClass( &wc );
  119.     return( rc );
  120.  
  121. }
  122.  
  123. static BOOL AnyInstance( HANDLE this_inst, int cmdshow )
  124. /*******************************************************
  125.  
  126.     Do work required for every instance of the application:
  127.     create the window, initialize data.
  128. */
  129. {
  130.     HDC        dc;
  131.     HWND     win_handle;
  132.     
  133.     /*
  134.      * create main window
  135.      */
  136.  
  137.     dc = GetDC(NULL);
  138.     ScreenHeight = GetDeviceCaps( dc, VERTRES );
  139.     ScreenWidth = GetDeviceCaps( dc, HORZRES );
  140.     ScreenHeightInMM = GetDeviceCaps( dc, VERTSIZE );
  141.     ScreenWidthInMM = GetDeviceCaps( dc, HORZSIZE );
  142.     ReleaseDC( NULL, dc );
  143.     CreateSupplies();
  144.  
  145.     win_handle = CreateWindow(
  146.     AlarmClass,        /* class */
  147.     "Alarm Clock",        /* caption */
  148.     WS_OVERLAPPEDWINDOW,    /* style */
  149.     CW_USEDEFAULT,        /* init. x pos */
  150.     CW_USEDEFAULT,        /* init. y pos */
  151.     CW_USEDEFAULT,        /* init. x size */
  152.     CW_USEDEFAULT,        /* init. y size */
  153.     NULL,            /* parent window */
  154.     NULL,            /* menu handle */
  155.     this_inst,        /* program handle */
  156.     NULL            /* create parms */
  157.     );
  158.             
  159.     if( !win_handle ) return( FALSE );
  160.  
  161.     /*
  162.      * display window
  163.      */
  164.     ShowWindow( win_handle, cmdshow );
  165.     UpdateWindow( win_handle );
  166.     
  167.     if( !SetTimer( win_handle, TIMER_ID, ONE_SECOND/4, 0L ) ) {
  168.     MessageBox( NULL, "Too many timers in use", Buffer,
  169.            MB_ICONHAND+MB_OK+MB_SYSTEMMODAL );
  170.     return( FALSE );
  171.     }
  172.  
  173.     return( TRUE );
  174.                         
  175. }
  176.  
  177. BOOL _EXPORT FAR PASCAL About( HWND win_handle, unsigned msg,
  178.                 WORD wparam, LONG lparam )
  179. /*****************************
  180.  
  181.     Process messages for the about dialog.
  182. */
  183. {
  184.     lparam = lparam;            /* turn off warning */
  185.     win_handle = win_handle;
  186.  
  187.     switch( msg ) {
  188.     case WM_INITDIALOG:
  189.     return( TRUE );
  190.  
  191.     case WM_COMMAND:
  192.         if( wparam == IDOK ) {
  193.         EndDialog( win_handle, TRUE );
  194.         return( TRUE );
  195.     }
  196.     break;
  197.     }
  198.     return( FALSE );
  199.  
  200. }
  201.  
  202.  
  203. static void TransferClockToAlarm()
  204. /*********************************
  205.  
  206.     Transfer the digits from the Clock array to the Alarm array.
  207. */
  208. {
  209.     digit_index        i;
  210.  
  211.     for( i = 0; i < DIGITS_WITH_SECONDS; ++i ) {
  212.     AlarmDigits[i] = ClockDigits[i].value;
  213.     }
  214. }
  215.  
  216. static void TransferAlarmToClock()
  217. /*********************************
  218.  
  219.     Transfer digits from the Alarm array to the Clock array
  220. */
  221. {
  222.     digit_index        i;
  223.  
  224.     for( i = 0; i < DIGITS_WITH_SECONDS; ++i ) {
  225.     ClockDigits[i].value = AlarmDigits[i];
  226.     }
  227. }
  228.  
  229. static void RePaintTheClock( HWND win_handle )
  230. /*********************************************
  231.  
  232.     Re-paint the entire clock, since it has been invalidated.
  233. */
  234. {
  235.     PAINTSTRUCT ps;
  236.  
  237.     InvalidateRect( win_handle, NULL, TRUE );
  238.     BeginPaint( win_handle, &ps );
  239.     InitializeTheClock();
  240.     PaintClock( ps.hdc );
  241.     EndPaint( win_handle, &ps );
  242. }
  243.  
  244.  
  245. static void CheckAlarm()
  246. /***********************
  247.  
  248.     See if the alarm has gone off, and pop up a message box if it has.
  249. */
  250. {
  251.     digit_index        i;
  252.  
  253.     for( i = 0; i < DIGITS_WITH_SECONDS; ++i ) {
  254.     if( AlarmDigits[i] != ClockDigits[i].value ) return;
  255.     }
  256.     MessageBox( NULL, "The alarm clock is ringing!", Buffer,
  257.            MB_ICONHAND+MB_OK+MB_SYSTEMMODAL );
  258. }
  259.  
  260.  
  261. static void UpdateTheClock( HWND win_handle )
  262. /********************************************
  263.  
  264.     Incrementally update the clock display.
  265. */
  266. {
  267.     HDC        dc;
  268.  
  269.     dc = GetDC( win_handle );
  270.     PaintClock( dc );
  271.     ReleaseDC( win_handle, dc );
  272. }
  273.  
  274.  
  275. static void SetNumberOfDigits( digit_index num )
  276. /***********************************************
  277.  
  278.     Set the number of digits to be displayed (4 or 6)
  279. */
  280. {
  281.     NumberOfDigits = num;
  282.     DigitsToDraw = num;
  283. }
  284.  
  285.  
  286. static void SetAlarm()
  287. /*********************
  288.  
  289.     Put the clock into alarm setting mode.
  290. */
  291. {
  292.     if( Setting ) return;
  293.     Setting = TRUE;
  294.     if( FirstAlarmSetting ) {
  295.     TransferClockToAlarm();
  296.     if( NumberOfDigits == DIGITS_WITHOUT_SECONDS ) {
  297.         AlarmDigits[SEC_TENS] = 0;
  298.         AlarmDigits[SEC_ONES] = 0;
  299.     }
  300.     FirstAlarmSetting = FALSE;
  301.     }
  302.     TransferAlarmToClock();
  303. }
  304.  
  305. static void RunTheClock()
  306. /************************
  307.  
  308.     Put the clock into running mode.
  309. */
  310. {
  311.     if( !Setting ) return;
  312.     Setting = FALSE;
  313.     TransferClockToAlarm();
  314. }
  315.  
  316.  
  317. static void Set12HourClock( HWND win_handle )
  318. /********************************************
  319.  
  320.     Put the clock into 12 hour mode.
  321. */
  322. {
  323.     int        i;
  324.  
  325.     if( TwelveHour ) return;
  326.     TwelveHour = TRUE;
  327.     i = AlarmDigits[HOUR_TENS]*10 + AlarmDigits[HOUR_ONES];
  328.     if( i > 12 ) {
  329.     i -= 12;
  330.         AlarmPM = TRUE;
  331.     }
  332.     AlarmDigits[HOUR_TENS] = i / 10;
  333.     AlarmDigits[HOUR_ONES] = i % 10;
  334.     if( Setting ) TransferAlarmToClock();
  335.     UpdateTheClock( win_handle );
  336. }
  337.  
  338.  
  339. static void Set24HourClock( HWND win_handle )
  340. /********************************************
  341.  
  342.     Put the clock into 24 hour mode
  343. */
  344. {
  345.     int        i;
  346.  
  347.     if( !TwelveHour ) return;
  348.     TwelveHour = FALSE;
  349.     i = AlarmDigits[HOUR_TENS]*10 + AlarmDigits[HOUR_ONES];
  350.     if( i <= 12 && AlarmPM ) {
  351.         i += 12;
  352.     AlarmPM = FALSE;
  353.     }
  354.     AlarmDigits[HOUR_TENS] = i / 10;
  355.     AlarmDigits[HOUR_ONES] = i % 10;
  356.     if( Setting ) TransferAlarmToClock();
  357.     UpdateTheClock( win_handle );
  358. }
  359.  
  360.  
  361. static void DisplayAboutBox( win_handle )
  362. /****************************************
  363.  
  364.     Display the "About ..." box
  365. */
  366. {
  367.     FARPROC     proc;
  368.     HANDLE    inst_handle;
  369.  
  370.     inst_handle = GetWindowWord( win_handle, GWW_HINSTANCE );
  371.     proc = MakeProcInstance( About, inst_handle );
  372.     DialogBox( inst_handle, "AboutBox", win_handle, proc );
  373.     FreeProcInstance( proc );
  374. }
  375.  
  376.  
  377. static void MenuItem( HWND win_handle, WORD wparam )
  378. /***************************************************
  379.  
  380.     Handle a menu item which has been selected by the user.
  381. */
  382. {
  383.  
  384.     switch( wparam ) {
  385.     case MENU_ABOUT:
  386.     DisplayAboutBox( win_handle );
  387.     break;
  388.     case MENU_DISPLAY_SECONDS:
  389.     SetNumberOfDigits( DIGITS_WITH_SECONDS );
  390.     break;
  391.     case MENU_SUPRESS_SECONDS:
  392.     SetNumberOfDigits( DIGITS_WITHOUT_SECONDS );
  393.     break;
  394.     case MENU_SET_ALARM:
  395.     SetAlarm();
  396.     break;
  397.     case MENU_RUN_CLOCK:
  398.     RunTheClock();
  399.     break;
  400.     case MENU_12_HOUR_CLOCK:
  401.     Set12HourClock( win_handle );
  402.     break;
  403.     case MENU_24_HOUR_CLOCK:
  404.     Set24HourClock( win_handle );
  405.     break;
  406.     }
  407.     InvalidateRect( win_handle, NULL, TRUE );
  408. }
  409.  
  410.  
  411. static    int Check[] = { MF_UNCHECKED, MF_CHECKED };
  412.  
  413. static void InitMenu( WORD wparam )
  414. /**********************************
  415.  
  416.     Initialize the menu display. Disable any items which are not applicable.
  417. */
  418. {
  419.     BOOL    on;
  420.  
  421.     CheckMenuItem( wparam, MENU_SET_ALARM, Check[ Setting ] );
  422.     CheckMenuItem( wparam, MENU_RUN_CLOCK, Check[ !Setting ] );
  423.     on = ( NumberOfDigits == DIGITS_WITHOUT_SECONDS );
  424.     CheckMenuItem( wparam, MENU_SUPRESS_SECONDS, Check[ on ] );
  425.     CheckMenuItem( wparam, MENU_DISPLAY_SECONDS, Check[ !on ] );
  426.     CheckMenuItem( wparam, MENU_24_HOUR_CLOCK, Check[ !TwelveHour ] );
  427.     CheckMenuItem( wparam, MENU_12_HOUR_CLOCK, Check[ TwelveHour ] );
  428. }
  429.  
  430. static unsigned  MaximumNumber[] = { 0, 0, 5, 9, 5, 9 };
  431.  
  432. static void MouseClick( pixels x, pixels y, unsigned msg )
  433. /*********************************************************
  434.  
  435.     Handle a mouse click at position x,y.
  436. */
  437. {
  438.     digit_index        i;
  439.  
  440.     TransferAlarmToClock();
  441.     if( TwelveHour ) {
  442.     MaximumNumber[HOUR_TENS] = 1;
  443.     if( ClockDigits[HOUR_TENS].value == 1 ) {
  444.         MaximumNumber[HOUR_ONES] = 2;
  445.     } else {
  446.         MaximumNumber[HOUR_ONES] = 9;
  447.     }
  448.     } else {
  449.     MaximumNumber[HOUR_TENS] = 2;
  450.     if( ClockDigits[HOUR_TENS].value == 2 ) {
  451.         MaximumNumber[HOUR_ONES] = 4;
  452.     } else {
  453.         MaximumNumber[HOUR_ONES] = 9;
  454.     }
  455.     }
  456.     for( i = 0; i < NumberOfDigits; ++i ) {
  457.         if( x < ClockDigits[i].segment[SEGMENT_0].position.start.x ) continue;
  458.         if( x > ClockDigits[i].segment[SEGMENT_6].position.end.x ) continue;
  459.         if( y < ClockDigits[i].segment[SEGMENT_0].position.start.y ) continue;
  460.         if( y > ClockDigits[i].segment[SEGMENT_6].position.end.y ) continue;
  461.     if( msg == WM_LBUTTONDOWN ) {
  462.         ClockDigits[i].value++;
  463.     } else if( msg == WM_RBUTTONDOWN ) {
  464.         ClockDigits[i].value--;
  465.     }
  466.     if( ClockDigits[i].value > MaximumNumber[ i ] ) {
  467.         ClockDigits[i].value = 0;
  468.     } else if( ClockDigits[i].value < 0 ) {
  469.         ClockDigits[i].value = MaximumNumber[i];
  470.     }
  471.     }
  472.     if( TwelveHour ) {
  473.     if( x < ClockDigits[HOUR_TENS].segment[SEGMENT_0].position.start.x &&
  474.             y > ClockDigits[HOUR_TENS].segment[SEGMENT_0].position.start.y &&
  475.             y < ClockDigits[HOUR_TENS].segment[SEGMENT_6].position.end.y ) {
  476.         AlarmPM = !AlarmPM;
  477.     }
  478.     if( ClockDigits[HOUR_TENS].value == 1 && ClockDigits[HOUR_ONES].value > 2 ) {
  479.         ClockDigits[HOUR_ONES].value = 2;
  480.     }
  481.     if( ClockDigits[HOUR_TENS].value == 0 &&
  482.         ClockDigits[HOUR_ONES].value == 0 ) {
  483.         ClockDigits[HOUR_ONES].value = 1;
  484.     }
  485.     } else {
  486.     if( ClockDigits[HOUR_TENS].value == 2 &&
  487.         ClockDigits[HOUR_ONES].value > 4 ) {
  488.         ClockDigits[HOUR_ONES].value = 4;
  489.     }
  490.     }
  491.     TransferClockToAlarm();
  492. }
  493.  
  494.  
  495. LONG _EXPORT FAR PASCAL WindowProc( HWND win_handle, unsigned msg,
  496.                      WORD wparam, LONG lparam )
  497. /**************************************************************
  498.  
  499.     Handle messages for the main application window.
  500. */
  501. {
  502.  
  503.     switch( msg ) {
  504.     case WM_INITMENU:
  505.         InitMenu( wparam );
  506.     break;
  507.  
  508.     case WM_COMMAND:
  509.         MenuItem( win_handle, wparam );
  510.     break;
  511.  
  512.     case WM_SYSCOLORCHANGE:
  513.         DeleteSupplies();
  514.     CreateSupplies();
  515.         break;
  516.  
  517.     case WM_PAINT:
  518.         RePaintTheClock( win_handle );
  519.     break;
  520.  
  521.     case WM_TIMER:
  522.     case WM_TIMECHANGE:
  523.     if( Setting ) break;
  524.     Tick++;
  525.     CheckAlarm();
  526.     UpdateTheClock( win_handle );
  527.     break;
  528.  
  529.     case WM_SIZE:
  530.     ReSize( LOWORD( lparam ), HIWORD( lparam ), wparam );
  531.     break;
  532.  
  533.     case WM_DESTROY:
  534.         DeleteSupplies();
  535.     KillTimer( win_handle, TIMER_ID );
  536.     PostQuitMessage( 0 );
  537.     break;
  538.  
  539.     case WM_LBUTTONDOWN:
  540.     case WM_RBUTTONDOWN:
  541.         if( !Setting ) break;
  542.         MouseClick( LOWORD( lparam ), HIWORD( lparam ), msg );
  543.     UpdateTheClock( win_handle );
  544.     break;
  545.  
  546.     default:
  547.     return( DefWindowProc( win_handle, msg, wparam, lparam ) );
  548.     }
  549.     return( 0L );
  550.  
  551. }
  552.  
  553.  
  554.  
  555. static seg_position  SegPosition[ NUMBER_OF_SEGMENTS ] =
  556. /*******************************************************
  557.  
  558.     These are the positions of the start and end points
  559.     of each digit segment segments based on the
  560.     following co-ordinate system.
  561.  
  562.  
  563.    (0,0) ---0--- (1,0)
  564.         |       |
  565.         1       2   
  566.         |       |
  567.    (0,1) ---3--- (1,1)
  568.         |       |
  569.         4       5   
  570.         |       |
  571.    (0,2) ---6--- (1,2)
  572.  
  573. */
  574.     /* start.x    start.y    end.x    end.y */
  575. {
  576.     {  0,    0,    1,    0 },    /* 0 */
  577.     {  0,    0,    0,    1 },    /* 1 */
  578.     {  1,    0,    1,    1 },    /* 2 */
  579.     {  0,    1,    1,    1 },    /* 3 */
  580.     {  0,    1,    0,    2 },    /* 4 */
  581.     {  1,    1,    1,    2 },    /* 5 */
  582.     {  0,    2,    1,    2 },    /* 6 */
  583. };
  584.  
  585. /*************************************************************************
  586.  
  587.     The following arrays define the polygon for each digit segment
  588.     based on the two end points defined in SegPosition. Each entry
  589.     is an (x,y) point based on the start or end point of the line
  590.     segment plus some delta in the x and y direction. For example,
  591.     START+UP_QUARTER+RITE_HALF means the starting point of the line
  592.     segment, moved up 1/4 of a segment width, and rite 1/2 of a
  593.     segment width
  594. */
  595.  
  596. typedef enum {
  597.     START        = 0x0001,
  598.     END        = 0x0002,
  599.     DOWN_ONE    = 0x0004,
  600.     UP_ONE        = 0x0008,
  601.     DOWN_HALF    = 0x0010,
  602.     UP_HALF        = 0x0020,
  603.     DOWN_QUARTER    = 0x0040,
  604.     UP_QUARTER    = 0x0080,
  605.     LEFT_ONE    = 0x0100,
  606.     RITE_ONE    = 0x0200,
  607.     LEFT_HALF    = 0x0400,
  608.     RITE_HALF    = 0x0800,
  609.     LEFT_QUARTER    = 0x1000,
  610.     RITE_QUARTER    = 0x2000
  611. } point_delta;
  612.  
  613. static point_delta Poly0[] = {
  614.     START+UP_QUARTER+RITE_QUARTER,
  615.     END+UP_QUARTER+LEFT_QUARTER,
  616.     END,
  617.     END+DOWN_ONE+LEFT_ONE,
  618.     START+DOWN_ONE+RITE_ONE,
  619.     START,
  620.     0
  621. };
  622.  
  623. static point_delta Poly1[] = {
  624.     START+DOWN_QUARTER+LEFT_QUARTER,
  625.     END+UP_QUARTER+LEFT_QUARTER,
  626.     END,
  627.     END+UP_HALF+RITE_ONE,
  628.     START+DOWN_ONE+RITE_ONE,
  629.     START,
  630.     0
  631. };
  632.  
  633. static point_delta Poly2[] = {
  634.     START+RITE_QUARTER+DOWN_QUARTER,
  635.     END+UP_QUARTER+RITE_QUARTER,
  636.     END,
  637.     END+UP_HALF+LEFT_ONE,
  638.     START+DOWN_ONE+LEFT_ONE,
  639.     START,
  640.     0
  641. };
  642.  
  643. static point_delta Poly3[] = {
  644.     START+UP_HALF+RITE_ONE,
  645.     END+UP_HALF+LEFT_ONE,
  646.     END,
  647.     END+DOWN_HALF+LEFT_ONE,
  648.     START+DOWN_HALF+RITE_ONE,
  649.     START,
  650.     0
  651. };
  652.  
  653. static point_delta Poly4[] = {
  654.     START+DOWN_QUARTER+LEFT_QUARTER,
  655.     END+UP_QUARTER+LEFT_QUARTER,
  656.     END,
  657.     END+UP_ONE+RITE_ONE,
  658.     START+DOWN_HALF+RITE_ONE,
  659.     START,
  660.     0
  661. };
  662.  
  663. static point_delta Poly5[] = {
  664.     START+RITE_QUARTER+DOWN_QUARTER,
  665.     END+UP_QUARTER+RITE_QUARTER,
  666.     END,
  667.     END+UP_ONE+LEFT_ONE,
  668.     START+DOWN_HALF+LEFT_ONE,
  669.     START,
  670.     0
  671. };
  672.  
  673. static point_delta Poly6[] = {
  674.     START+DOWN_QUARTER+RITE_QUARTER,
  675.     END+DOWN_QUARTER+LEFT_QUARTER,
  676.     END,
  677.     END+UP_ONE+LEFT_ONE,
  678.     START+UP_ONE+RITE_ONE,
  679.     START,
  680.     0
  681. };
  682.  
  683. static point_delta *SegPoly[] =
  684. {
  685.     &Poly0,  &Poly1,  &Poly2,  &Poly3,  &Poly4,  &Poly5,  &Poly6
  686. };
  687.  
  688.  
  689. static void DrawSegment( HDC dc, pen_type pen,
  690.                          seg_position *pos, point_delta *delta )
  691. /***************************************************************
  692.  
  693.     Draw the polygon for a segment of a digit.
  694. */
  695. {
  696.     pixels    x,y;
  697.     pixels    one_x,one_y;
  698.     pixels    half_x,half_y;
  699.     pixels    quarter_x,quarter_y;
  700.  
  701.     one_y = SegmentHeight;
  702.     half_y = SegmentHeight / 2;
  703.     quarter_y = SegmentHeight / 4;
  704.     if( one_y <= 2 ) one_y = 1;
  705.     one_x = SegmentWidth;
  706.     half_x = SegmentWidth / 2;
  707.     quarter_x = SegmentWidth / 4;
  708.     if( one_x <= 2 ) one_x = 1;
  709.     SelectObject( dc, Pens[pen] );
  710.     MoveTo( dc, pos->start.x, pos->start.y );
  711.     while( *delta != 0 ) {
  712.     if( *delta & START ) {
  713.         x = pos->start.x;
  714.         y = pos->start.y;
  715.     } else if( *delta & END ) {
  716.         x = pos->end.x;
  717.         y = pos->end.y;
  718.     }
  719.     if( *delta & UP_QUARTER )    y -= quarter_y;
  720.     if( *delta & UP_HALF )        y -= half_y;
  721.     if( *delta & UP_ONE )        y -= one_y;
  722.     if( *delta & DOWN_QUARTER )    y += quarter_y;
  723.     if( *delta & DOWN_HALF )    y += half_y;
  724.     if( *delta & DOWN_ONE )        y += one_y;
  725.     if( *delta & LEFT_QUARTER )    x -= quarter_x;
  726.     if( *delta & LEFT_HALF )    x -= half_x;
  727.     if( *delta & LEFT_ONE )        x -= one_x;
  728.     if( *delta & RITE_QUARTER )    x += quarter_x;
  729.     if( *delta & RITE_HALF )    x += half_x;
  730.     if( *delta & RITE_ONE )        x += one_x;
  731.     LineTo( dc, x, y );
  732.     ++delta;
  733.     }
  734.     LineTo( dc, pos->start.x, pos->start.y );
  735. }
  736.  
  737.  
  738. static BOOL SegmentOnInDigit[ 11 ][ NUMBER_OF_SEGMENTS ] =
  739. /*********************************************************
  740.  
  741.     SegmentIsOn[ i ][ j ] indicates whether or not segment number i should
  742.     be turned on in the digit j.
  743. */
  744. {
  745. /*    0      1      2      3      4      5      6        */
  746.     {  TRUE,  TRUE,  TRUE, FALSE,  TRUE,  TRUE,  TRUE }, /* 0 */
  747.     { FALSE, FALSE,  TRUE, FALSE, FALSE,  TRUE, FALSE }, /* 1 */
  748.     {  TRUE, FALSE,  TRUE,  TRUE,  TRUE, FALSE,  TRUE }, /* 2 */
  749.     {  TRUE, FALSE,  TRUE,  TRUE, FALSE,  TRUE,  TRUE }, /* 3 */
  750.     { FALSE,  TRUE,  TRUE,  TRUE, FALSE,  TRUE, FALSE }, /* 4 */
  751.     {  TRUE,  TRUE, FALSE,  TRUE, FALSE,  TRUE,  TRUE }, /* 5 */
  752.     {  TRUE,  TRUE, FALSE,  TRUE,  TRUE,  TRUE,  TRUE }, /* 6 */
  753.     {  TRUE,  TRUE,  TRUE, FALSE, FALSE,  TRUE, FALSE }, /* 7 */
  754.     {  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE }, /* 8 */
  755.     {  TRUE,  TRUE,  TRUE,  TRUE, FALSE,  TRUE,  TRUE }, /* 9 */
  756.     { FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, /* 10 */
  757. };
  758.  
  759. static void DrawDigit( HDC dc, digit *p )
  760. /****************************************
  761.  
  762.     Draw one digit of the the clock.
  763. */
  764. {
  765.     segment_index        i;
  766.  
  767.     for( i = 0; i < NUMBER_OF_SEGMENTS; ++i ) {
  768.     if( SegmentOnInDigit[ p->value ][ i ] ) {
  769.         if( !p->segment[i].on ) {
  770.         DrawSegment( dc, FOREGROUND,
  771.                      &p->segment[i].position, SegPoly[i] );
  772.         p->segment[i].on = TRUE;
  773.         }
  774.     } else {
  775.         if( p->segment[i].on ) {
  776.         DrawSegment( dc, BACKGROUND,
  777.                      &p->segment[i].position, SegPoly[i] );
  778.         p->segment[i].on = FALSE;
  779.         }
  780.     }
  781.     }
  782. }
  783.  
  784.  
  785. static void UpdateColon( HDC dc, colon_index i, pen_type *pen )
  786. /**************************************************************
  787.  
  788.     Draw the colon separating the clock digits (and the AM/PM indicator)
  789. */
  790. {
  791.     dot_index        j;
  792.  
  793.     for( j = 0; j < NUMBER_OF_DOTS; ++j ) {
  794.     if( Colons[i].dot[j].pen != pen[j] ) {
  795.         SelectObject( dc, Pens[ pen[j] ] );
  796.         Rectangle( dc, Colons[i].dot[j].top_left.x,
  797.                        Colons[i].dot[j].top_left.y,
  798.                Colons[i].dot[j].bot_rite.x,
  799.                Colons[i].dot[j].bot_rite.y );
  800.         Colons[i].dot[j].pen = pen[j];
  801.     }
  802.     }
  803. }
  804.  
  805.  
  806. static void DrawColon( HDC dc, colon_index i )
  807. /*********************************************
  808.  
  809.     Draw the colon separating the digits. It flashes if seconds are supressed
  810. */
  811. {
  812.     pen_type    pen[NUMBER_OF_DOTS];
  813.  
  814.     pen[TOP_DOT] = FOREGROUND;
  815.     if( !Setting && ( DigitsToDraw == DIGITS_WITHOUT_SECONDS ) &&
  816.         ( ( Tick % 4 ) < 2 ) ) {
  817.         pen[TOP_DOT] = BACKGROUND;
  818.     }
  819.     pen[BOT_DOT] = pen[TOP_DOT];
  820.     UpdateColon( dc, i, pen );
  821. }
  822.  
  823.  
  824. static void DrawPM( HDC dc, BOOL pm )
  825. /************************************
  826.  
  827.     Draw the AM/PM indicator (This is just a colon in front of the first digit
  828. */
  829. {
  830.     pen_type    pen[NUMBER_OF_DOTS];
  831.  
  832.     if( pm ) {
  833.     pen[TOP_DOT] = BACKGROUND;
  834.     pen[BOT_DOT] = FOREGROUND;
  835.     } else {
  836.     pen[BOT_DOT] = BACKGROUND;
  837.     pen[TOP_DOT] = FOREGROUND;
  838.     }
  839.     UpdateColon( dc, 0, pen );
  840. }
  841.  
  842.  
  843. static void PaintClock( HDC dc )
  844. /*******************************
  845.  
  846.     Paint the clock face on the screen
  847. */
  848. {
  849.     digit_index    i;
  850.     time_t    ltime;
  851.     struct tm    *t;
  852.     BOOL    pm;
  853.  
  854.     pm = FALSE;
  855.     if( !Setting ) {
  856.     time( <ime );
  857.     t = localtime( <ime );
  858.     if( TwelveHour ) {
  859.         if( t->tm_hour > 12 ) {
  860.         t->tm_hour -= 12;
  861.         pm = TRUE;
  862.         } else if( t->tm_hour == 0 ) {
  863.         t->tm_hour = 12;
  864.         }
  865.     }
  866.     ClockDigits[HOUR_TENS].value = t->tm_hour / 10;
  867.     ClockDigits[HOUR_ONES].value = t->tm_hour % 10;
  868.     ClockDigits[MIN_TENS].value = t->tm_min / 10;
  869.     ClockDigits[MIN_ONES].value = t->tm_min % 10;
  870.     ClockDigits[SEC_TENS].value = t->tm_sec / 10;
  871.     ClockDigits[SEC_ONES].value = t->tm_sec % 10;
  872.     } else {
  873.     pm = AlarmPM;
  874.     }
  875.     if( ClockDigits[HOUR_TENS].value == 0 ) {
  876.     ClockDigits[HOUR_TENS].value = BLANK_SPACE_VALUE;
  877.     }
  878.     for( i = 0; i < DigitsToDraw; ++i ) {
  879.     DrawDigit( dc, &ClockDigits[i] );
  880.     }
  881.     DrawColon( dc, 1 );
  882.     if( DigitsToDraw == DIGITS_WITH_SECONDS ) {
  883.     DrawColon( dc, 2 );
  884.     }
  885.     if( TwelveHour ) {
  886.         DrawPM( dc, pm );
  887.     }
  888.     if( ClockDigits[HOUR_TENS].value == BLANK_SPACE_VALUE ) {
  889.     ClockDigits[HOUR_TENS].value = 0;
  890.     }
  891. }
  892.  
  893.  
  894. static void SetColonPos( colon_index i )
  895. /***************************************
  896.  
  897.     Set the screen positions for colon number "i".
  898. */
  899. {
  900.     pixels    dx,dy;
  901.     pixels    add_x,add_y,sub_x,sub_y;
  902.     pixels    x1,y1,x2,y2;
  903.  
  904.     y1 = ClockDigits[i].segment[SEGMENT_0].position.start.y;
  905.     y2 = ClockDigits[i].segment[SEGMENT_6].position.start.y;
  906.     switch( i ) {
  907.     case 0:
  908.     x1 = 0;
  909.     x2 = ClockDigits[HOUR_TENS].segment[SEGMENT_0].position.start.x;
  910.     break;
  911.     case 1:
  912.     x1 = ClockDigits[HOUR_ONES].segment[SEGMENT_0].position.end.x;
  913.     x2 = ClockDigits[MIN_TENS].segment[SEGMENT_0].position.start.x;
  914.     break;
  915.     case 2:
  916.     x1 = ClockDigits[MIN_ONES].segment[SEGMENT_0].position.end.x;
  917.     x2 = ClockDigits[SEC_TENS].segment[SEGMENT_0].position.start.x;
  918.     break;
  919.     }
  920.     dx = ( x2 - x1 ) / 2;
  921.     dy = ( y2 - y1 ) / 3;
  922.     add_x = dx / PORTION_FOR_COLON;
  923.     sub_x = -add_x;
  924.     if( add_x == 0 ) add_x = 1;
  925.     add_y = dy / PORTION_FOR_COLON;
  926.     sub_y = -add_y;
  927.     if( add_y == 0 ) add_y = 1;
  928.     x1 += dx;
  929.     y1 += dy;
  930.     Colons[i].dot[TOP_DOT].top_left.x = x1 + sub_x;
  931.     Colons[i].dot[TOP_DOT].top_left.y = y1 + sub_y;
  932.     Colons[i].dot[TOP_DOT].bot_rite.x = x1 + add_x;
  933.     Colons[i].dot[TOP_DOT].bot_rite.y = y1 + add_y;
  934.     Colons[i].dot[TOP_DOT].pen = BACKGROUND;
  935.     y1 += dy;
  936.     Colons[i].dot[BOT_DOT].top_left.x = x1 + sub_x;
  937.     Colons[i].dot[BOT_DOT].top_left.y = y1 + sub_y;
  938.     Colons[i].dot[BOT_DOT].bot_rite.x = x1 + add_x;
  939.     Colons[i].dot[BOT_DOT].bot_rite.y = y1 + add_y;
  940.     Colons[i].dot[BOT_DOT].pen = BACKGROUND;
  941. }
  942.  
  943.  
  944. static void InitializeTheClock()
  945. /*******************************
  946.  
  947.     Initialize each digit of the clock. Calculate the screen position
  948.     of each segment of each digit of the clock, as well as the
  949.     screen positions of the colons.
  950. */
  951. {
  952.     pixels        win_left,win_rite;
  953.     pixels        top_of_clock;
  954.     pixels        top,bot;
  955.     pixels        left,rite;
  956.     pixels        width,height;
  957.     pixels        space;
  958.     pixels        colon_space;
  959.     digit_index        i;
  960.     segment_index    j;
  961.     long        width_scale;
  962.     long        height_scale;
  963.  
  964.     HeightOfClock = HeightOfWindow;
  965.     if( HeightOfClock < MINIMUM_HEIGHT ) {
  966.     HeightOfClock = MINIMUM_HEIGHT;
  967.     }
  968.     WidthOfClock = WidthOfWindow;
  969.     height_scale = (long)ScreenHeightInMM * DIGIT_HEIGHT_SCALE;
  970.     width_scale = (long)ScreenWidthInMM * DIGIT_WIDTH_SCALE / ( DigitsToDraw + 1 ); /* Allow for 2 colons */
  971.     if( WidthOfClock * width_scale > HeightOfClock * height_scale ) {
  972.     WidthOfClock = HeightOfClock * height_scale / width_scale;
  973.     } else {
  974.     HeightOfClock = WidthOfClock * width_scale / height_scale;
  975.     }
  976.     top_of_clock = ( HeightOfWindow - HeightOfClock ) / 2;
  977.  
  978.     top = HeightOfClock / UNUSED_PORTION_OF_SCREEN_HEIGHT;
  979.     bot = HeightOfClock - top;
  980.     height = bot - top;
  981.     top += top_of_clock;
  982.  
  983.     win_left = WidthOfClock / UNUSED_PORTION_OF_SCREEN_WIDTH;
  984.     win_rite = WidthOfClock - win_left;
  985.  
  986.     space = ( win_rite - win_left ) / ( DigitsToDraw + 1 );
  987.     InterSegmentGap = space / PORTION_FOR_SEGMENT_GAP;
  988.     SegmentWidth = space / PORTION_OF_SPACE_FOR_SEGMENT;
  989.     SegmentHeight = (long)SegmentWidth * ScreenHeightInMM / ScreenWidthInMM;
  990.  
  991.     left = space / UNUSED_PORTION_OF_DIGIT_SPACE;
  992.     rite = space - left;
  993.     width = rite - left;
  994.  
  995.     for( i = 0; i < DigitsToDraw; ++i ) {
  996.     for( j = 0; j < NUMBER_OF_SEGMENTS; ++j ) {
  997.         ClockDigits[i].segment[j].on = FALSE;
  998.         ClockDigits[i].segment[j].position = SegPosition[j];
  999.         /* scale the co-ordinates */
  1000.         ClockDigits[i].segment[j].position.start.x *= width;
  1001.         ClockDigits[i].segment[j].position.end.x   *= width;
  1002.         ClockDigits[i].segment[j].position.start.y *= height / 2;
  1003.         ClockDigits[i].segment[j].position.end.y   *= height / 2;
  1004.         /* adjust for left edge of digit's bounding box and window */
  1005.         colon_space = i / 2 * ( width / 2 ); /* 0,1 -> 0, 2,3 -> 1/2 width, 4,5 -> width */
  1006.         ClockDigits[i].segment[j].position.start.x += colon_space + i * space + left + win_left;
  1007.         ClockDigits[i].segment[j].position.end.x   += colon_space + i * space + left + win_left;
  1008.         /* adjust for top edge of digit's bounding box */
  1009.         ClockDigits[i].segment[j].position.start.y += top;
  1010.         ClockDigits[i].segment[j].position.end.y   += top;
  1011.         /* adjust all edges for gap */
  1012.         if( SegPosition[j].start.x != SegPosition[j].end.x ) {
  1013.         ClockDigits[i].segment[j].position.start.x += InterSegmentGap;
  1014.         ClockDigits[i].segment[j].position.end.x -= InterSegmentGap;
  1015.         } else {
  1016.         ClockDigits[i].segment[j].position.start.y += InterSegmentGap;
  1017.         ClockDigits[i].segment[j].position.end.y -= InterSegmentGap;
  1018.         }
  1019.     }
  1020.     }
  1021.     for( i = 0; i < NUMBER_OF_COLONS; ++i ) {
  1022.     SetColonPos( i );
  1023.     }
  1024. }
  1025.  
  1026.  
  1027. static void ReSize( pixels width, pixels height, WORD type )
  1028. /***********************************************************
  1029.  
  1030.     Record the new size of the window and redraw the clock accordingly
  1031. */
  1032. {
  1033.     WidthOfWindow = width;
  1034.     HeightOfWindow = height;
  1035.     DigitsToDraw = NumberOfDigits;
  1036.     if( type == SIZEICONIC ) {
  1037.     DigitsToDraw = DIGITS_WITHOUT_SECONDS;
  1038.     } else {
  1039.     DigitsToDraw = NumberOfDigits;
  1040.     }
  1041.     InitializeTheClock();
  1042. }
  1043.  
  1044. void CreateSupplies()
  1045. /********************
  1046.  
  1047.     Create the art supplies we need
  1048. */
  1049. {
  1050.     Pens[FOREGROUND] = CreatePen( 0, 1, GetSysColor( COLOR_WINDOWTEXT ) );
  1051.     Pens[BACKGROUND] = CreatePen( 0, 1, GetSysColor( COLOR_WINDOW ) );
  1052. }
  1053.  
  1054.  
  1055. void DeleteSupplies()
  1056. /********************
  1057.  
  1058.     Delete our art supplies
  1059. */
  1060. {
  1061.     DeleteObject( Pens[FOREGROUND] );
  1062.     DeleteObject( Pens[BACKGROUND] );
  1063. }
  1064.