home *** CD-ROM | disk | FTP | other *** search
/ QBasic & Borland Pascal & C / Delphi5.iso / C / Samples / CSAPE32.ARJ / EXAMPLES / DEMOCLOK.C < prev    next >
C/C++ Source or Header  |  1991-03-09  |  28KB  |  1,066 lines

  1. /*
  2.     democlok.c
  3.  
  4.     12/90 pmcm
  5.  
  6.     %    userwin clock demo for C-scape 3.2
  7.  
  8.     This program relies on the compiler supplied graphics library
  9.     to draw a clock in a userwin.  The clock appears in color under
  10.     a graphics display mode that has at least 16 available colors; else,
  11.     it appears in monochrome.
  12.  
  13.     Comments in the code explain the calculations used to draw the
  14.     clock.
  15.  
  16.     Functions used herein that are not documented in the C-scape Function
  17.     Reference are documented in the grafix.txt document contained on your
  18.     distribution media (DOS and Apollo versions only).
  19.  
  20.     The graphics libraries of these 2 compilers are supported:
  21.  
  22.     MICROSOFT C
  23.     BORLAND TURBO C
  24.  
  25.     Note:    If you are running on a CGA then you must run
  26.             the DOS utility GRAPTABL.COM before running
  27.             this program.  GRAPTABL.COM loads the extended
  28.             ASCII character    set for use in graphics mode.
  29.  
  30.     Note:    The Microsoft graphics library does not support the
  31.             Hercules card.
  32.  
  33.     Copyright (c) 1990 by Oakland Group, Inc.
  34.     ALL RIGHTS RESERVED.
  35.  
  36.     Revision History:
  37.     -----------------
  38.     12/05/90 pmcm    composed from jdc's ogl and gam's clock scraps
  39.  
  40. */
  41.  
  42. #include <stdio.h>
  43. #include <time.h>        /*     for time structure */
  44. #include <math.h>        /*     for sin() and cos() */
  45.  
  46. #include "cscape.h"
  47. #include "ostdlib.h"    /*    for exit() and rand() */
  48. #include "kbidle.h"        /*     for idle function */
  49. #include "cstime.h"        /*     for C-scape time routines */
  50. #include "pcmode.h"        /*     for pc_GetMode() */
  51. #include "oakalloc.h"    /*    for omalloc() */
  52. #include "popdecl.h"    /*     for pop_Prompt() */
  53. #include "scancode.h"    /*    for KEY_NONE in idle function */
  54.  
  55. /*----------------------------- COMPILER SPECIFIC INCLUDES ----------------- */
  56.  
  57. /*-----------------------------    Microsoft C specific ------------------------*/
  58.  
  59. #ifdef M6                  /* Microsoft C 5.1 or 6.0 */
  60. #include <graph.h>
  61. #endif
  62.  
  63. /*----------------------------- Borland Turbo C specific --------------------*/
  64.  
  65. #ifdef __TURBOC__        /* Borland Turbo C */
  66. #include <graphics.h>
  67.  
  68. /*     Borland Users!
  69.     BGI_PATH is directory in which initgraph looks for the Borland .BGI
  70.     files.  You may have to change this path depending on how you have
  71.     installed your compiler.  Consult the compiler manual under initgraph
  72.     for more information.  Note that the backslashes in the path name
  73.     must be quoted with a preceding backslash.
  74.  
  75.     You can also define the environment variable BGIPATH which overrides
  76.     the #define below:
  77.  
  78.         set BGIPATH=\tc\bgi
  79. */
  80.  
  81. #define BGI_PATH     "\\TC\\"
  82.  
  83. #endif
  84.  
  85. /*----------------------------- end of compiler specific includes ------------*/
  86.  
  87. /*----------------------------- CONSTANTS ------------------------------------*/
  88.  
  89. #define PI                        3.141592
  90.  
  91. /*    default display window attribute--used to
  92.     set the display background color
  93. */
  94. #define DISP_ATTR        0x10
  95.  
  96. /*    paints for the color clock */
  97.  
  98. #define CLOCK_CBACK        11
  99. #define CLOCK_CHAND        1
  100. #define CLOCK_CSEC        4
  101. #define CLOCK_CTICK        0
  102. #define CLOCK_CBORD        0xb3
  103.  
  104. /*    shadow paints for the color clock */
  105.  
  106. #define CLOCK_SHADBACK        3
  107. #define CLOCK_SHADHAND        8
  108. #define CLOCK_SHADSEC        4
  109. #define CLOCK_SHADTICK        7
  110. #define CLOCK_SHADBORD        0x3b
  111.  
  112. /*    paints for monochrome clock.
  113.     (shadows are rendered inverse
  114.     see clock_Draw.)
  115. */
  116. #define CLOCK_MBACK            1
  117. #define CLOCK_MHAND            0
  118. #define CLOCK_MSEC            0
  119. #define CLOCK_MTICK            0
  120. #define CLOCK_MBORD            0x10
  121.  
  122. /*    default pix dimensions of clock window */
  123. #define CLOCK_WIDTH        10
  124. #define CLOCK_HEIGHT    30
  125.  
  126. /*    clock color data
  127.     the clock is rendered in color only on displays supporting 16
  128.     or more colors.  if the display supports less colors, the clock
  129.     is rendered in monochrome.
  130. */
  131.  
  132. struct clockcolor_struct {
  133.     int        back;        /*  color of the background */
  134.     int     tick;        /*  color of the tickmarks around the clock face */
  135.     int        hand;        /*    color of the minute and hour hands */
  136.     int        sec;        /*     color of the second hand */
  137.     byte    bord;        /*    attribute of the clock window border */
  138. };
  139.  
  140. /*    clock plot data (see clock_InitData(), below */
  141.  
  142. struct tick_struct {
  143.     double    x1;
  144.     double    y1;
  145.     double    x2;
  146.     double    y2;
  147. };
  148.  
  149. /*    clock data structure */
  150.  
  151. typedef struct _clockdata_struct {
  152.     boolean                        mono;            /*    color or mono clock? */
  153.     int                            msg;            /*    regular paint or shadow? */
  154.     struct clockcolor_struct     color_clock;    /*    color paints */
  155.     struct clockcolor_struct     shadow_clock;    /*    color shadow paints */
  156.     struct clockcolor_struct     mono_clock;     /*     monochrome paints */
  157.     struct tm                     time;            /*    current time */
  158.     struct tick_struct            tick[12];        /*     tickmark positions */
  159. } clockdata_struct;
  160.  
  161. typedef clockdata_struct *clockdata_type;
  162.  
  163. /*----------------------------- PROTOTYPES -----------------------------------*/
  164.  
  165. aux_func(aux_Clock);
  166. idle_func(clock_Idle);
  167.  
  168. void        democlock_Prompt(void);
  169.  
  170. win_type     clock_Open(void);
  171. void         clock_InitData(win_type clock);
  172. void         clock_Draw(ptd_struct *ptd);
  173. void         clock_DrawHand(ptd_struct *ptd, double theta, double radius, boolean sec, int color);
  174. void         clock_DrawTicks(ptd_struct *ptd, int color);
  175. void         clock_PrintOWLNoInitMsg(void);
  176. void         clock_PrintGrafNoInitMsg(int err);
  177.  
  178. void        cdp_GetColors(clockdata_type cdp, int *bck, int *tck, int *hnd, int *sec);
  179.  
  180. int         dgraf_Init(void);
  181. void         dgraf_Line(ptd_struct *ptd, opbox *lineboxp, int color);
  182. void        dgraf_SetClip(opbox *opboxp);
  183.  
  184. /*----------------------------- MAIN -----------------------------------------*/
  185. int main(void)
  186. {
  187.     int    x;    /* error return value of graphics initialization (Turbo only) */
  188.  
  189.     if (!disp_Init(def_ModeGraphics, FNULL)) {
  190.         clock_PrintOWLNoInitMsg();
  191.         exit(1);
  192.         return(1);
  193.     }
  194.  
  195.     /*     set global flag */
  196.     if (disp_GetColors() <= 2L) {
  197.         disp_MapMono(TRUE);
  198.     }
  199.  
  200.     /* initialize graphics library */
  201.     if ((x = dgraf_Init()) != 0) {
  202.         disp_Close();
  203.         clock_PrintGrafNoInitMsg(x);
  204.         exit(1);
  205.         return(0);
  206.     }
  207.  
  208.     /*    set display window attribute--must come after dgraf_Init
  209.         or you won't see it
  210.     */
  211.     disp_SetAttr(DISP_ATTR);
  212.     disp_Repaint();
  213.  
  214.     /*     turn on the mouse--must come after dgraf_Init
  215.         or you won't see it
  216.     */
  217.     hard_InitMouse();
  218.     sedwin_ClassInit();
  219.  
  220.     /*    install idle function */
  221.     kb_Idle(clock_Idle);
  222.  
  223.     /*    create, run and clock the democlock prompt window */
  224.     democlock_Prompt();
  225.  
  226.     disp_Close();
  227.  
  228.     exit(0);
  229.     return(0);
  230. }
  231.  
  232. /* -------------------------------------------------------------------------- */
  233. void democlock_Prompt(void)
  234. /*
  235.       display and run a prompt window which tells about the demo.
  236. */
  237. {
  238.     menu_type    menu;
  239.     sed_type    sed;
  240.  
  241.     menu = menu_Open();
  242.  
  243.     menu_Printf(menu, "\n The clock is an example of a window\n");
  244.     menu_Printf(menu, " where you control the painting.\n");
  245.     menu_Printf(menu, " You may move either window & resize\n");
  246.     menu_Printf(menu, " the clock.");
  247.     menu_Printf(menu, "@p[6,17]@f[ OK ]",
  248.       NULL, &gmenu_funcs);
  249.  
  250.     menu_Flush(menu);
  251.  
  252.     sed = sed_Open(menu);
  253.     sed_SetColors(sed, 0x4b, 0x4b, 0x3f);
  254.     sed_SetMouse(sed, sedmou_Track);
  255.     sed_SetPosition(sed, 1, 1);
  256.     sed_SetShadow(sed, 1);
  257.     sed_SetShadowAttr(sed, 0x4f);
  258.     sed_SetBorder(sed, bd_prompt);
  259.     sed_SetBorderTitle(sed, " democlok ");
  260.     sed_SetBorderFeature(sed, BD_MOVE | BD_TOP);
  261.  
  262.     sed_Repaint(sed);
  263.     sed_Go(sed);
  264.     sed_Close(sed);
  265.  
  266.      return;
  267. }
  268.  
  269. /*----------------------------- CLOCK ROUTINES -------------------------------*/
  270. int clock_Idle(int msg, unsigned wait)
  271. /*
  272.     open the clock when this idle function is connected.
  273.     run the clock when we have time.
  274.     close the clock when this idle function is disconnected.
  275. */
  276. {
  277.     static win_type            clock;
  278.     static short                oldsec;
  279.     static clockdata_type    cdp;
  280.  
  281.     switch (msg) {
  282.  
  283.     case IDLE_START:
  284.         /*    build clock (inits its own data) */
  285.         if ((clock = clock_Open()) != NULL) {
  286.  
  287.             cdp = (clockdata_type) win_GetData(clock);
  288.  
  289.             /*    paint the clock to the display */
  290.             win_Employ(clock);
  291.         }
  292.         else {
  293.              clock = NULL;
  294.         }
  295.         break;
  296.  
  297.     case IDLE_CHECK:
  298.     case IDLE_READ:
  299.         if (clock != NULL) {
  300.  
  301.             /*     get current time */
  302.             tm_Now(&(cdp->time));
  303.  
  304.             /*     paint the clock every new second */
  305.             if (oldsec != cdp->time.tm_sec) {
  306.                 oldsec = (short)cdp->time.tm_sec;
  307.                 win_Paint(clock);
  308.             }
  309.         }
  310.         break;
  311.  
  312.     case IDLE_STOP:
  313.         /*    close the clock and free its data storage */
  314.         if (clock != NULL) {
  315.             if (cdp != NULL) {
  316.                  ofree(OA_NOTAG, cdp);
  317.                 cdp = NULL;
  318.                 win_SetData(clock, NULL);
  319.             }
  320.             win_Close(clock);
  321.             clock = NULL;
  322.         }
  323.         break;
  324.  
  325.     default:
  326.         break;
  327.     }
  328.  
  329.     return(KEY_NONE);
  330. }
  331.  
  332. /* -------------------------------------------------------------------------- */
  333. win_type clock_Open()
  334. /*
  335.     opens the clock window of the userwin_Class.
  336.     sets the clock window size, position, etc.
  337.     initializes the clock data.
  338.     returns the clock window to caller to paint and run.
  339. */
  340. {
  341.     win_type         clock;
  342.     ocbox             cbox;
  343.     clockdata_type    cdp;
  344.  
  345.  
  346.     /*    set up an Oakland character box for win_Open() */
  347.     cbox.toprow   = 0;
  348.     cbox.leftcol  = 0;
  349.     cbox.botrow   = 1;
  350.     cbox.rightcol = 1;
  351.  
  352.     /*    open the clock window */
  353.     if ((clock = win_Open(userwin_Class, &cbox)) == NULL) {
  354.          return(NULL);
  355.     }
  356.  
  357.     win_SetSize(clock, CLOCK_WIDTH, CLOCK_HEIGHT);
  358.  
  359.     /*    open a border for the window and allocate the clock data storage */
  360.     if (!win_SetBorder(clock, bd_1)  ||
  361.         (cdp = (clockdata_type) omalloc(OA_NOTAG,
  362.         sizeof(clockdata_struct))) == NULL) {
  363.  
  364.         win_Close(clock);
  365.         return(NULL);
  366.     }
  367.  
  368.     /*    attach the clock data to the clock window's generic data pointer */
  369.     win_SetData(clock, (VOID *)cdp);
  370.  
  371.     /*    initialize the clock data */
  372.     clock_InitData(clock);
  373.  
  374.     /*    set some miscellaneous stuff */
  375.  
  376.     bord_SetFeature(clock, BD_MOVE | BD_RESIZE | BD_TOP);
  377.     win_SetShadow(clock, 1);
  378.     win_SetShadowAttr(clock, CLOCK_SHADBORD);
  379.     bord_SetAttr(clock, cdp->mono ? cdp->mono_clock.bord : cdp->color_clock.bord);
  380.  
  381.     /*    position at display center */
  382.      win_SetPosition(clock, (disp_GetHeight() - bord_GetHeight(clock)) / 2,
  383.          (disp_GetWidth() - bord_GetWidth(clock))  / 2);
  384.  
  385.     win_SetMouse(clock, winmou_Track);
  386.  
  387.     obj_SetName(clock, "clock");
  388.     obj_SetAux(clock, aux_Clock);
  389.  
  390.      return(clock);
  391. }
  392.  
  393. /* -------------------------------------------------------------------------- */
  394. void clock_InitData(win_type clock)
  395. /*
  396.       initialize the clock data.
  397. */
  398. {
  399.     clockdata_type    cdp;
  400.     int             tickno;
  401.     double          theta;
  402.     double            ourcos, oursin;
  403.  
  404.     if (clock != NULL &&
  405.         (cdp = (clockdata_type) win_GetData(clock)) != NULL) {
  406.  
  407.         cdp->msg  = 0;
  408.         cdp->mono = (disp_GetColors() < 16L) ? TRUE : FALSE;
  409.  
  410.         cdp->mono_clock.back                 = CLOCK_MBACK;
  411.         cdp->mono_clock.hand                = CLOCK_MHAND;
  412.         cdp->mono_clock.sec                    = CLOCK_MSEC;
  413.         cdp->mono_clock.tick                = CLOCK_MTICK;
  414.         cdp->mono_clock.bord                = CLOCK_MBORD;
  415.  
  416.         cdp->color_clock.back                = CLOCK_CBACK;
  417.         cdp->color_clock.hand                = CLOCK_CHAND;
  418.         cdp->color_clock.sec                = CLOCK_CSEC;
  419.         cdp->color_clock.tick                = CLOCK_CTICK;
  420.         cdp->color_clock.bord                = CLOCK_CBORD;
  421.  
  422.         cdp->shadow_clock.back                = CLOCK_SHADBACK;
  423.         cdp->shadow_clock.hand                = CLOCK_SHADHAND;
  424.         cdp->shadow_clock.sec                = CLOCK_SHADSEC;
  425.         cdp->shadow_clock.tick                = CLOCK_SHADTICK;
  426.         cdp->shadow_clock.bord                = CLOCK_SHADBORD;
  427.  
  428.         /*    initialize the tickmark coordinate array.
  429.  
  430.             a tickmark is a mark around the face of the clock denoting
  431.             a clock interval.  coordinates are stored in a tick_struct.
  432.             the coordinates are the endpoints of a tickmark line.
  433.  
  434.             the face of the clock is circular.  we want to calculate the
  435.             tickmark positions in a manner that allows us to specify
  436.             their length and position, relative to the size of the clock
  437.             circle.
  438.  
  439.             consider a circle, of radius r, whose center is at the origin
  440.             (0,0) and a point p, on the circle.  as the end point of a
  441.             vector from the origin, p is rotated through an angle theta
  442.             to point p' like this
  443.  
  444.                 x'    = r * cos(theta)
  445.                 y'    = r * sin(theta)
  446.  
  447.             we calculate the endpoints tickmarks as points on 2 concentric
  448.              circles, with the same origin as the clock circle, rotated through
  449.             the same angle.  the distance between the points is the length
  450.             of the tickmark.
  451.  
  452.             so that the tickmarks can be scaled with the clock, we conceive
  453.             of r as a percentage of the diameter of the clock circle.  r
  454.             may range from 0.0 to 100.0 (0% to 100%), inclusive.
  455.  
  456.             below, 12 tickmarks are calculated at regular intervals about the
  457.             full circumference of the clock.  the length of a tickmark is
  458.             12% the diameter of the clock (40 - 28).  its distance from the
  459.             center is 28% of the diameter of the clock; from the edge of the
  460.             clock, 10% (100/2 - 40).
  461.  
  462.             (PI/2.0 is a quarter around the circle.)
  463.         */
  464.  
  465.         for (tickno = 0; tickno < 12; tickno++) {
  466.             theta = (PI/2.0 - ((double)tickno * PI/6.0));
  467.             cdp->tick[tickno].x1 = ((double)40.0) * (ourcos = cos(theta));
  468.             cdp->tick[tickno].y1 = ((double)40.0) * (oursin = sin(theta));
  469.             cdp->tick[tickno].x2 = ((double)28.0) * ourcos;
  470.             cdp->tick[tickno].y2 = ((double)28.0) * oursin;
  471.         }
  472.     }
  473.  
  474.     return;
  475. }
  476.  
  477. /* -------------------------------------------------------------------------- */
  478. int aux_Clock(win_type win, int msg, VOID *indata, VOID *outdata)
  479. /*
  480.     paints the clock, in shadow and in light.
  481. */
  482. {
  483.     ptd_struct         *ptd;
  484.     boolean             active;
  485.  
  486.     switch(msg) {
  487.  
  488.     case WINA_SHADOW:
  489.         /*    fall through ... */
  490.  
  491.     case WINA_PAINT:
  492.         ptd = (ptd_struct *) indata;
  493.  
  494.         /*    let the draw routine know whether or not we are in shadow */
  495.         ((clockdata_type) win_GetData(ptd->win))->msg = msg;
  496.  
  497.         /* draw the clock */
  498.         clock_Draw(ptd);
  499.  
  500.         break;
  501.  
  502.     case WINA_GO:
  503.  
  504.         active = TRUE;
  505.         while(active) {
  506.             switch(kb_Read()) {
  507.             case MOU_THERE:
  508.             case ESC:
  509.                 active = FALSE;
  510.                 break;
  511.  
  512.             case MOU_CLICK:
  513.                 win_Top(win);
  514.                 break;
  515.             case MOU_DCLICK:
  516.                 tone();
  517.                 break;
  518.             }
  519.         }
  520.         break;
  521.  
  522.     default:
  523.         break;
  524.     }
  525.  
  526.     return(1);
  527. }
  528.  
  529. /* -------------------------------------------------------------------------- */
  530. void clock_Draw(ptd_struct *ptd)
  531. /*
  532.     refresh the clock display
  533. */
  534. {
  535.     ptd_struct        inptd;
  536.     opbox            inbox, relbox;
  537.     clockdata_type    cdp;
  538.     double          theta;
  539.     int                back_color, tick_color, hand_color, sec_color;
  540.  
  541.     /*
  542.         the ptd we are given may include our border. call ptd_SetInner to
  543.         make inptd a copy of ptd but with its relboxp pointing to inbox.
  544.         ptd_SetInner clips inbox within the ptd window's inner box (the
  545.         area exclusive of its border).
  546.     */
  547.     if (!ptd_SetInner(ptd, &inptd, &inbox)) {
  548.         /*     nothing to do */
  549.         return;
  550.     }
  551.  
  552.     /*    copy the inptd's relbox to our local relbox */
  553.     opbox_copy(&relbox, inptd.relboxp);
  554.  
  555.     /*    translate relbox so it is display, not window relative.
  556.         we need it like this to set the clip region.
  557.     */
  558.     opbox_trans(&relbox, win_GetXmin(ptd->win), win_GetYmin(ptd->win));
  559.     dgraf_SetClip(&relbox);
  560.  
  561.     cdp = (clockdata_type) win_GetData(ptd->win);
  562.     cdp_GetColors(cdp, &back_color, &tick_color, &hand_color, &sec_color);
  563.  
  564.     /* clear the background */
  565.     ptd_Clear(&inptd, back_color);
  566.  
  567.     /*    12 tickmarks */
  568.     clock_DrawTicks(&inptd, tick_color);
  569.  
  570.     /*     second hand, its length is 40% of clock diameter */
  571.     theta = (PI/2.0) - (cdp->time.tm_sec * (PI/30.0));
  572.     clock_DrawHand(&inptd, theta, (double)40.0, TRUE, sec_color);
  573.  
  574.     /*    minute hand, its length is 30% of clock diameter */
  575.     theta = (PI/2.0) - (cdp->time.tm_min * (PI/30.0)) ;
  576.     clock_DrawHand(&inptd, theta, (double)30.0, FALSE, hand_color);
  577.  
  578.     /*     hour hand,   its length is 20% of clock diameter */
  579.     theta = (PI/2.0) - (cdp->time.tm_hour * (PI/6.0));
  580.     clock_DrawHand(&inptd, theta, (double)20.0, FALSE, hand_color);
  581.  
  582.      return;
  583. }
  584.  
  585. /* -------------------------------------------------------------------------- */
  586. void clock_DrawTicks(ptd_struct *ptd, int color)
  587. /*
  588.     theta is the radian measure of the angle of the tickmark.
  589. */
  590. {
  591.     opbox            drawbox, dimbox;
  592.     opcoord            wid, hgt;
  593.     clockdata_type     cdp;
  594.     int                tickno;
  595.  
  596.     cdp = (clockdata_type) win_GetData(ptd->win);
  597.  
  598.     /*    for TURBO C--the line drawing routines are clip region relative */
  599.  
  600.     win_GetPixBox(ptd->win, &dimbox);
  601.     wid = opbox_GetWidth(&dimbox);
  602.     hgt = opbox_GetHeight(&dimbox);
  603.  
  604.     /*     draw the 12 tick marks on the clock face from the
  605.         pre-calculated array of relative positions
  606.     */
  607.     for (tickno = 0; tickno < 12; tickno++) {
  608.  
  609.         /* scale and translate draw coords to window size */
  610.         drawbox.xmax = dimbox.xmin +
  611.             ((int) (((long) ((double)50.0 + cdp->tick[tickno].x2) * (long) wid) / 100L));
  612.         drawbox.ymax = dimbox.ymin +
  613.             ((int) (((long) ((double)50.0 - cdp->tick[tickno].y2) * (long) hgt) / 100L));
  614.         drawbox.xmin = dimbox.xmin +
  615.             ((int) (((long) ((double)50.0 + cdp->tick[tickno].x1) * (long) wid) / 100L));
  616.         drawbox.ymin = dimbox.ymin +
  617.             ((int) (((long) ((double)50.0 - cdp->tick[tickno].y1) * (long) hgt) / 100L));
  618.  
  619.         dgraf_Line(ptd, &drawbox, color);
  620.     }
  621.     return;
  622. }
  623.  
  624. /* -------------------------------------------------------------------------- */
  625. void clock_DrawHand(ptd_struct *ptd, double theta, double radius, boolean sec, int color)
  626. /*
  627.     theta is the radian measure of the angle of the hand's axis.
  628.  
  629.     radius is the radius of the circle used to calculate the endpoints of the
  630.     hand.  it represents a percentage of the extent of the window.
  631.  
  632.     sec is a flag denoting whether to the hand is the second hand.  if so,
  633.     a single line is drawn; else a triangular outline of the hour or
  634.     minute hand is drawn.
  635. */
  636. {
  637.     double    tipx, tipy;
  638.     opbox    drawbox, dimbox;
  639.     opcoord    wid, hgt;
  640.     int        xcenter, ycenter;
  641.  
  642.     win_GetPixBox(ptd->win, &dimbox);
  643.     wid = opbox_GetWidth(&dimbox);
  644.     hgt = opbox_GetHeight(&dimbox);
  645.  
  646.     /*    the outermost tip of the hand */
  647.     tipx = radius * cos(theta);
  648.     tipy = radius * sin(theta);
  649.  
  650.     /*    translate (relative to clock center, 50% of clock dimension)
  651.         and scale
  652.     */
  653.     drawbox.xmax = dimbox.xmin +
  654.         (int) (((((double) 50.0) + tipx) * (double)wid) * (double)0.01);
  655.     drawbox.ymax = dimbox.ymin +
  656.         (int) (((((double)50.0) - tipy) * (double)hgt) * (double)0.01);
  657.     drawbox.xmin = dimbox.xmin +
  658.         (int) ((((double)50.0) * (double)wid) * (double)0.01);
  659.     drawbox.ymin = dimbox.ymin +
  660.         (int) ((((double)50.0) * (double)hgt) * (double)0.01);
  661.  
  662.     xcenter = drawbox.xmin;
  663.     ycenter = drawbox.ymin;
  664.  
  665.     if (sec) {
  666.  
  667.         /*    draw the second hand from the tip we set up on the periphery of
  668.             the clock to the clock center
  669.         */
  670.         dgraf_Line(ptd, &drawbox, color);
  671.     }
  672.     else {
  673.         /*    hour or minute hand rendering */
  674.  
  675.         double     basex1, basey1, basex2, basey2;
  676.         int     tempx, tempy;
  677.  
  678.         /*    figure an angle (almost, PI/1.6) perpendicular to the hand axis.
  679.             form a short vector which, together with the tip point calculated
  680.             above,  denotes a line that will render one side of the hand.
  681.             the endpoint calculated here is at the broad end
  682.             of the hand near the center of the clock.
  683.         */
  684.         basex1 = ((double)2.0) * cos(theta - PI/2.0);
  685.         basey1 = ((double)2.0) * sin(theta - PI/2.0);
  686.         basex2 = ((double)2.0) * cos(theta + PI/2.0);
  687.         basey2 = ((double)2.0) * sin(theta + PI/2.0);
  688.  
  689.         /*    (drawbox max has the tip) put base pt in drawbox min to
  690.             draw one side of the hand
  691.         */
  692.         drawbox.xmin = dimbox.xmin +
  693.             (int) (((((double)50.0) + basex1) * (double)wid) * (double)0.01);
  694.         drawbox.ymin = dimbox.ymin +
  695.             (int) (((((double)50.0) - basey1) * (double)hgt) * (double)0.01);
  696.         dgraf_Line(ptd, &drawbox, color);
  697.  
  698.         /*    save this base endpoint */
  699.         tempx = drawbox.xmin;
  700.         tempy = drawbox.ymin;
  701.  
  702.         /*    put in the other base endpoint--plot to tip */
  703.         drawbox.xmin = dimbox.xmin +
  704.             (int) (((((double)50.0) + basex2) * (double)wid) * (double)0.01);
  705.         drawbox.ymin = dimbox.ymin +
  706.             (int) (((((double)50.0) - basey2) * (double)hgt) * (double)0.01);
  707.         dgraf_Line(ptd, &drawbox, color);
  708.  
  709.         /*     plot from endpoints to center */
  710.         drawbox.xmax = xcenter;
  711.         drawbox.ymax = ycenter;
  712.         dgraf_Line(ptd, &drawbox, color);
  713.         drawbox.xmin = tempx;
  714.         drawbox.ymin = tempy;
  715.         dgraf_Line(ptd, &drawbox, color);
  716.     }
  717.  
  718.      return;
  719. }
  720.  
  721. /* -------------------------------------------------------------------------- */
  722. void cdp_GetColors(clockdata_type cdp, int *back_color, int *tick_color, int *hand_color, int *sec_color)
  723. {
  724.     if (!cdp->mono) {
  725.         if (cdp->msg == WINA_SHADOW) {
  726.             *back_color = cdp->shadow_clock.back;
  727.             *tick_color = cdp->shadow_clock.tick;
  728.             *hand_color = cdp->shadow_clock.hand;
  729.             *sec_color  = cdp->shadow_clock.sec;
  730.         }
  731.         else {
  732.             *back_color = cdp->color_clock.back;
  733.             *tick_color = cdp->color_clock.tick;
  734.             *hand_color = cdp->color_clock.hand;
  735.             *sec_color  = cdp->color_clock.sec;
  736.         }
  737.     }
  738.     else {
  739.         *back_color = cdp->mono_clock.back;
  740.         *tick_color = cdp->mono_clock.tick;
  741.         *hand_color = cdp->mono_clock.hand;
  742.         *sec_color  = cdp->mono_clock.sec;
  743.  
  744.         if (cdp->msg == WINA_SHADOW) {
  745.             *back_color = *back_color ? 0 : 1;
  746.             *tick_color = *tick_color ? 0 : 1;
  747.             *hand_color = *hand_color ? 0 : 1;
  748.             *sec_color  = *sec_color  ? 0 : 1;
  749.         }
  750.     }
  751.     return;
  752. }
  753.  
  754. /* -------------------------------------------------------------------------- */
  755. void clock_PrintOWLNoInitMsg(void)
  756. /*
  757.       error message for when disp_Init fails.
  758. */
  759. {
  760.     printf("\nCLOCK: No graphics hardware found; or, ");
  761.     printf("\n         there is insufficient memory to initialize the OWL ...\n");
  762.     return;
  763. }
  764.  
  765. /* -------------------------------------------------------------------------- */
  766. void clock_PrintGrafNoInitMsg(int err)
  767. /*
  768.       error message for when initializing graphics library fails.
  769. */
  770. {
  771.  
  772. #ifdef __TURBOC__            /* Turbo C/C++ */
  773.     switch(err) {
  774.     case -2:
  775.         printf("\nCLOCK: Turbo C initgraph cannot detect graphics card.\n");
  776.         break;
  777.     case -3:
  778.         printf("\nCLOCK: Turbo C initgraph cannot find BGI driver file.\n");
  779.         break;
  780.     case -4:
  781.         printf("\nCLOCK: Turbo C initgraph does not support this video hardware.\n");
  782.         break;
  783.     case -5:
  784.         printf("\nCLOCK: Turbo C initgraph insufficient memory to load driver.\n");
  785.         break;
  786.     default:
  787.         printf("\nCLOCK: Turbo C initgraph error %d.\n", err);
  788.         break;
  789.     }
  790. #else
  791.         printf("\nCLOCK: Microsoft C _setvideomode does not support this video hardware.\n");
  792. #endif
  793.  
  794.     return;
  795. }
  796.  
  797. /* !!!!!!!!!!!!!!!!!!!!!!!!!!!! COMPILER SPECIFIC ROUTINES !!!!!!!!!!!!!!!!!!!*/
  798.  
  799. /*
  800.     Portable graphics routines:
  801.     The following routines are defined for the various graphics libraries
  802.     supported.
  803. */
  804.  
  805. /*-----------------------------    Microsoft C specific -------------------------*/
  806.  
  807. #ifdef M6            /* Microsoft C 5.1 or 6.0 */
  808.  
  809. int dgraf_Init(void)
  810. /*
  811.     Initialize the graphics library.
  812.     Initialize demo data.
  813.  
  814.     Returns      0     if successful
  815.                 -1    if the video hardware is unsupported by MS.
  816.  
  817.     Microsoft C version.
  818. */
  819. {
  820.     struct videoconfig     config;        /* Microsoft defined structure */
  821.     int                 mode;
  822.  
  823.     switch(pc_GetMode()) {
  824.        case 0x13:
  825.         mode = _MRES256COLOR;
  826.         break;
  827.        case 0x12:
  828.         mode = _VRES16COLOR;
  829.         break;
  830.        case 0x11:
  831.         mode = _VRES2COLOR;
  832.         break;
  833.        case 0x10:
  834.         mode = _ERESCOLOR;
  835.         break;
  836.        case 0x0f:
  837.         mode = _ERESNOCOLOR;
  838.         break;
  839.        case 0x0e:
  840.         mode = _HRES16COLOR;
  841.         break;
  842.        case 0x0d:
  843.         mode = _MRES16COLOR;
  844.         break;
  845.        case 0x06:
  846.         mode = _HRESBW;
  847.         break;
  848.        case 0x05:
  849.     case 0x04:
  850.         mode = _MRESNOCOLOR;
  851.         break;
  852.     case 0x10A:
  853.     case 0x10B:
  854.         /*
  855.         The    Hercules graphics card is not supported by Microsoft.  _HERCMONO
  856.         is in their graphic.h but does not work with _setvideomode, below.
  857.         */
  858.         mode = _HERCMONO;
  859.         break;
  860.     case 0x140:
  861.         /* Compaq Plasma 40 not supported by Microsoft, fall through ... */
  862.     default:
  863.         return(-1);
  864.     }
  865.  
  866.     /* initialize Microsoft video mode */
  867.     if ((_setvideomode(mode)) == 0) {
  868.         return(-1);    /* unsupported hardware configuration */
  869.     }
  870.  
  871.     /* initialize config structure */
  872.     _getvideoconfig(&config);
  873.  
  874.     return(0);
  875. }
  876.  
  877. void dgraf_SetClip(opbox *opboxp)
  878. /*
  879.     Set clipping region.
  880.     Miscrosoft C version.
  881. */
  882. {
  883.     _setcliprgn((short)opboxp->xmin, (short)opboxp->ymin,
  884.                 (short)opboxp->xmax, (short)opboxp->ymax);
  885.     return;
  886. }
  887.  
  888. void dgraf_Line(ptd_struct *ptd, opbox *lineboxp, int color)
  889. /*
  890.     Plot a line.
  891.  
  892.     ptd         contains a pointer to a window relative box
  893.                 denoting the area in which to draw.
  894.     lineboxp
  895.     color        is an index into the hardware palette
  896.  
  897.     Microsoft C version.
  898. */
  899. {
  900.     opbox         clipbox;    /* local work copy of ptd relbox */
  901.     opbox         drawbox;    /* local work copy of linebox */
  902.  
  903.     /*     translate ptd win to disp coords for to set the clip region */
  904.     opbox_copy(&clipbox, ptd->relboxp);
  905.     opbox_trans(&clipbox, win_GetXmin(ptd->win), win_GetYmin(ptd->win));
  906.  
  907.     /*    set the clip region */
  908.     dgraf_SetClip(&clipbox);
  909.  
  910.     /*     the given box for line drawing is window relative.
  911.         translate linebox to display.
  912.     */
  913.     opbox_copy(&drawbox, lineboxp);
  914.     opbox_trans(&drawbox, win_GetXmin(ptd->win), win_GetYmin(ptd->win));
  915.  
  916.     _setcolor(color);
  917.  
  918.     /* draw a line */
  919.     _moveto(drawbox.xmin, drawbox.ymin);
  920.     _lineto(drawbox.xmax, drawbox.ymax);
  921. }
  922.  
  923. #endif
  924.  
  925. /*----------------------------- Borland Turbo C specific ---------------------*/
  926.  
  927. #ifdef __TURBOC__            /* Turbo C */
  928.  
  929. int dgraf_Init(void)
  930. /*
  931.     Turbo C version.
  932.  
  933.     Initialize the graphics library.
  934.     Initialize demo data.
  935.  
  936.     Returns
  937.             0 if successful.
  938.  
  939.             turbo initgraph error code if not successful:
  940.                 -2 cannot detect graphics card
  941.                 -3 cannot find driver file
  942.                 -4 invalid driver (unsupported video mode)
  943.                 -5 insufficient memory to load driver
  944. */
  945.  
  946. {
  947.     int        mode, driver;
  948.     char   *bgipath;
  949.  
  950.     switch(pc_GetMode()) {
  951.        case 0x12:
  952.         driver = VGA;
  953.         mode = VGAHI;
  954.         break;
  955.        case 0x11:
  956.         driver = MCGA;
  957.         mode = MCGAHI;
  958.         break;
  959.        case 0x10:
  960.         driver = EGA;
  961.         mode = EGAHI;
  962.         break;
  963.        case 0x0f:
  964.         driver = EGAMONO;
  965.         mode = EGAMONOHI;
  966.         break;
  967.        case 0x0e:
  968.         driver = EGA;
  969.         mode = EGALO;
  970.         break;
  971.        case 0x06:
  972.         driver = CGA;
  973.         mode = CGAHI;
  974.         break;
  975.        case 0x05:
  976.     case 0x04:
  977.         driver = CGA;
  978.         mode = CGAC1;
  979.         break;
  980.     case 0x10A:
  981.     case 0x10B:
  982.         driver = HERCMONO;
  983.         mode = HERCMONOHI;
  984.         break;
  985.     case 0x140:    /* Compaq plasma mode 40 */
  986.         driver = ATT400;
  987.         mode = ATT400HI;
  988.         break;
  989.        case 0x13:    /* 320x200  (pc_Mode13) 256 color VGA/MCGA, fall through... */
  990.        case 0x0d:    /* 320x200  (pc_ModeD)  16 color EGA, fall through...       */
  991.     default:
  992.                 /* Not supported by TC -- return code for invalid driver */
  993.         return(-4);
  994.     }
  995.  
  996.     /* test for environment variable */
  997.     if ((bgipath = getenv("BGIPATH")) == NULL) {
  998.         bgipath = BGI_PATH;
  999.     }
  1000.  
  1001.     initgraph(&driver, &mode, bgipath);
  1002.  
  1003.     if (driver < 0) {
  1004.         /* initgraph failed */
  1005.         return(driver);
  1006.     }
  1007.  
  1008.     return(0);
  1009. }
  1010.  
  1011. void dgraf_SetClip(opbox *opboxp)
  1012. /*
  1013.     Set clipping region.
  1014.     Turbo C version.
  1015. */
  1016. {
  1017.     setviewport((int)opboxp->xmin, (int)opboxp->ymin,
  1018.                 (int)opboxp->xmax - 1, (int)opboxp->ymax - 1, TRUE);
  1019.     return;
  1020. }
  1021.  
  1022. void dgraf_Line(ptd_struct *ptd, opbox *lineboxp, int color)
  1023. /*
  1024.     Plot a line.
  1025.  
  1026.     ptd         contains a pointer to a window relative box
  1027.                 denoting the area in which to draw.
  1028.     lineboxp
  1029.     color        is an index into the hardware palette
  1030.  
  1031.     Turbo C version.
  1032. */
  1033. {
  1034.     opbox         clipbox;    /* local work copy of ptd relbox */
  1035.     opbox         drawbox;    /* local work copy of linebox */
  1036.  
  1037.     /*     NOTE: Turbo plot coordinates are relative to the Turbo clip region */
  1038.  
  1039.     /*     translate ptd win to disp coords for to set the clip region */
  1040.     opbox_copy(&clipbox, ptd->relboxp);
  1041.     opbox_trans(&clipbox, win_GetXmin(ptd->win), win_GetYmin(ptd->win));
  1042.  
  1043.     /*    set the clip region */
  1044.     dgraf_SetClip(&clipbox);
  1045.  
  1046.     /*     the given box for line drawing is window relative.
  1047.         translate linebox to clip region coords.
  1048.     */
  1049.     opbox_copy(&drawbox, lineboxp);
  1050.     opbox_trans(&drawbox, - (ptd->relboxp->xmin), - (ptd->relboxp->ymin));
  1051.  
  1052.     setcolor((int) color);
  1053.  
  1054.     /* draw a line */
  1055.     line((int) (drawbox.xmin), (int) (drawbox.ymin), (int) (drawbox.xmax), (int) (drawbox.ymax));
  1056.  
  1057.     return;
  1058. }
  1059.  
  1060. #endif
  1061.  
  1062. /*---------------------------------------------------------------------------*/
  1063.  
  1064.  
  1065.  
  1066.