home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library 1.3 / Microsoft-Programers-Library-v1.3.iso / sampcode / os2sdk / os2sdk12 / bio / biopaint.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-11-20  |  9.2 KB  |  290 lines

  1. /*
  2.     biopaint.c    -   WM_PAINT processing and calendar conversion routines
  3.  
  4.     Created by Microsoft Corporation, 1989
  5. */
  6. #define INCL_WIN
  7. #define INCL_GPI
  8. #include <os2.h>
  9.  
  10. #include "bio.h"
  11. #include <math.h>
  12. #include <stdio.h>
  13.  
  14. /* Read-only global variables */
  15. extern double   Born;
  16. extern long     Day, SelectDay;
  17. extern BOOL     bBorn;
  18. extern FONTMETRICS tmFontInfo;
  19. extern int      LinesPerPage;
  20. extern RECTL    rclClient;
  21. extern SHORT    cxDateField;
  22.  
  23. /* Read-only static variables */
  24. static double   Cycle[] = { 23.0, 28.0, 33.0 };
  25. static char     cDayOfWeek[] = "MTWTFSS";
  26. extern LONG     Color[];
  27.  
  28.  
  29.  
  30. /*  APPPaint() - Parent window WM_PAINT processing routine.
  31. *
  32. *   Purpose:
  33. *       Routine to graph biorhythm cycles and tabulate dates.
  34. *
  35. *   Arguments:
  36. *       hWnd          - Handle of Window owning message
  37. *       message       - Message itself
  38. *       mp1           - Extra message-dependent info
  39. *       mp2           - Extra message-dependent info
  40. *
  41. *   Globals (static):
  42. *       Cycle[]       - Array holding period for phy/emot/int: 23,28,33
  43. *       cDayOfWeek[]  - Array of chars holding first letter of days of week.
  44. *       Color[]       - Set of colored pens used to identify cycles.
  45. *
  46. *   Globals (referenced):
  47. *       Born          - Birthdate in julian days.  Read from WIN.INI.
  48. *    SelectDay     - Current day being tracked, day is highlighted.
  49. *            This is stored as the number of days from birthdate.
  50. *            Initialized to present day in WM_CREATE processing.
  51. *       Day           - Day number from date born which is top line being
  52. *                       displayed.  Initially three days before SelectDay.
  53. *       bBorn         - Boolean indicating whether valid birtdate entered or
  54. *    rclClient     - Size of client area defined by WM_SIZE message
  55. *       LinesPerPage  - Number of system font lines on client area, defined
  56. *                       by WM_SIZE message handling
  57. *       tmFontInfo    - Text Metric structure defined during WM_CREATE 
  58. *
  59. *   Description:
  60. *       Tabulates dates and graphs cycles.  On color displays, weekends
  61. *       are written in red.  The update rectangle is used to minimize
  62. *       repaint time of affected client area.
  63. */
  64. VOID APIENTRY APPPaint( hWnd )
  65. HWND   hWnd;
  66. {
  67.     HPS         hPS;
  68.     POINTL      ptl;
  69.     int         y, i;
  70.     int         start, last;
  71.     char        szDay[16];
  72.     int         Amplitude, offset;
  73.     int         year, month;
  74.     double      day;
  75.     RECTL       rc, rcClip;
  76.     int         DayOfWeek;
  77.     HRGN    hrgnClip;
  78.     POINTL    ptlTextBox[5];
  79.  
  80.     hPS = WinBeginPaint( hWnd, NULL, &rcClip );
  81.  
  82.     /* Erase client area */
  83.     WinQueryWindowRect( hWnd, &rc );
  84.     WinFillRect( hPS, &rc, CLR_WHITE );
  85.  
  86.     /* Label parts of table and graph. */
  87.     ptl.y = rclClient.yTop - tmFontInfo.lMaxBaselineExt + /* Top line */
  88.             tmFontInfo.lMaxDescender;
  89.     ptl.x = 0;
  90.     GpiCharStringAt( hPS, &ptl, 7L, (PCH)"   DATE" );
  91.     ptl.x = cxDateField + tmFontInfo.lAveCharWidth;
  92.     GpiCharStringAt( hPS, &ptl, 3L, (PCH)"LOW" );
  93.     GpiQueryTextBox( hPS, 4L, "HIGH", TXTBOX_COUNT, ptlTextBox );
  94.     ptl.x = rclClient.xRight - ptlTextBox[TXTBOX_CONCAT].x - tmFontInfo.lAveCharWidth;
  95.     GpiCharStringAt( hPS, &ptl, 4L, (PCH)"HIGH" );
  96.  
  97.     /* Underline labels from left to right across client area */
  98.     ptl.y = rclClient.yTop - tmFontInfo.lMaxBaselineExt;
  99.     ptl.x = 0;
  100.     GpiMove( hPS, &ptl );
  101.     ptl.x = rclClient.xRight;
  102.     GpiLine( hPS, &ptl );
  103.  
  104.     /* Draw a vertical line separator between dates and cycles */
  105.     ptl.y = rclClient.yTop;
  106.     ptl.x = cxDateField;
  107.     GpiMove( hPS, &ptl );
  108.     ptl.y = rclClient.yBottom;
  109.     GpiLine( hPS, &ptl );
  110.  
  111.     /* Draw a dotted vertical center line to reference cycles */
  112.     GpiSetLineType( hPS, LINETYPE_DOT );
  113.     ptl.x = (cxDateField + rclClient.xRight) / 2;
  114.     GpiMove( hPS, &ptl );
  115.     ptl.y = rclClient.yTop;
  116.     GpiLine( hPS, &ptl );
  117.     /* (Should not have to restore line type after EndPaint) */
  118.     GpiSetLineType( hPS, LINETYPE_DEFAULT );
  119.  
  120.     /* Update only the range of lines which fall into update rectangle */
  121.     start = (int)((rclClient.yTop - rcClip.yTop) / tmFontInfo.lMaxBaselineExt);
  122.     if (start<1)
  123.        start = 1;
  124.     last = (int)((rclClient.yTop - rcClip.yBottom) / tmFontInfo.lMaxBaselineExt);
  125.     if (last>(LinesPerPage-1))
  126.        last = LinesPerPage-1;
  127.     
  128.     /* Set clip rectangle to completely draw entire rectangle representing
  129.        each date affected.  Start drawing one day before and after
  130.        (outside clip rectangle) so that cycle lines will connect correctly
  131.        with unaffected lines. */
  132.     rcClip.yTop = rclClient.yTop - start*tmFontInfo.lMaxBaselineExt;
  133.     start--;
  134.     last++;
  135.     rcClip.yBottom = rclClient.yTop - last*tmFontInfo.lMaxBaselineExt + 1;
  136.     hrgnClip = GpiCreateRegion( hPS, 1L, &rcClip );
  137.     GpiSetClipRegion( hPS, hrgnClip, &hrgnClip );
  138.  
  139.     /* List days and date */
  140.     for (y=start; y<=last; y++) {
  141.         /* Get the calendar date from julian day */
  142.         calendar( Born+Day+y-1, &year, &month, &day );
  143.         /* Get offset into days of the week initials array */
  144.         DayOfWeek = (int)((LONG)(Born+Day+y) % 7);
  145.         /* Assemble each of the parts in a buffer */
  146.     sprintf(szDay, " %02d-%02d-%02d",
  147.                 month, (int)day, year - (trunc4((double)year / 100)*100) );
  148.         /* If color available, draw weekends in red */
  149.         if (DayOfWeek > 4)
  150.            GpiSetColor( hPS, CLR_RED );
  151.         ptl.x = 0;
  152.         ptl.y = rclClient.yTop - ((y+1)*tmFontInfo.lMaxBaselineExt -
  153.         tmFontInfo.lMaxDescender);
  154.     GpiCharStringAt( hPS, &ptl, 1L, (PCH)&cDayOfWeek[DayOfWeek] );
  155.     GpiQueryWidthTable( hPS, (LONG)'W', 1L, &ptl.x );
  156.     GpiCharStringAt( hPS, &ptl, 9L, (PCH)szDay );
  157.         GpiSetColor( hPS, CLR_BLACK );
  158.     }
  159.  
  160.     /* Amplitude of sin wave is half client area minus space for dates */
  161.     Amplitude = (int)((rclClient.xRight - cxDateField - tmFontInfo.lAveCharWidth) >> 1);
  162.     /* Move to right, make room for column of dates */
  163.     offset = (int)(Amplitude + cxDateField + tmFontInfo.lAveCharWidth - (tmFontInfo.lAveCharWidth>>1));
  164.     for (i=0; i<3 && bBorn; i++ ) {
  165.         GpiSetColor( hPS, Color[i] );
  166.         for (y=start; y<=last; y++) {
  167.             ptl.x = (int)(sin( (y+Day-1)/Cycle[i]*2*3.14159 ) * Amplitude + offset);
  168.             ptl.y = rclClient.yTop - (y*tmFontInfo.lMaxBaselineExt +
  169.                         tmFontInfo.lMaxBaselineExt/2);
  170.             if ((y+Day-1 > 0) && (y>start))
  171.                GpiLine( hPS, &ptl );
  172.             else
  173.                GpiMove( hPS, &ptl );
  174.         }
  175.     }
  176.  
  177.     /* Draw highlight on selected day if visible. */
  178.     if ((SelectDay >= Day) && (SelectDay - Day < LinesPerPage - 1)) {
  179.         rc.xRight = rclClient.xRight;
  180.         rc.xLeft = rclClient.xLeft;
  181.         rc.yTop = rclClient.yTop - (int)(SelectDay - Day + 1) * tmFontInfo.lMaxBaselineExt;
  182.         rc.yBottom = rc.yTop - tmFontInfo.lMaxBaselineExt + 1;
  183.         WinInvertRect( hPS, &rc );
  184.     }
  185.  
  186.     WinEndPaint( hPS );
  187.  
  188.     return;
  189. }
  190.  
  191.  
  192. /*  julian() - Compute julian date from Gregorian calendar date.
  193. *
  194. *   Purpose:
  195. *       Provide a standard time base.
  196. *
  197. *   Arguments:
  198. *       year          - Calendar year
  199. *       month         - Calendar month
  200. *       day           - Calendar day and fraction
  201. *
  202. *   Return Value:
  203. *       double        - Julian date converted
  204. *
  205. *   Description:
  206. *       Convert Gregorian dates to Julian Days.  Refer to Alamanac for
  207. *       Computers (1978), p. B2, Naval Observatory Pub.
  208. *
  209. *   Limits:
  210. *       Valid between ~1900 and 2099.
  211. *
  212. */
  213.  
  214. double PASCAL julian (year, month, day)
  215. int    year, month;
  216. double day;
  217. {
  218.   double dj;
  219.   double fracDay, intDay;
  220.  
  221.   fracDay = modf(day, &intDay);
  222.   dj = (long)367*year - 7*(year + (month+9) / 12) / 4 + 275*month / 9 +
  223.        intDay + 1721013.5 + fracDay;
  224.   return dj;
  225. }
  226.  
  227.  
  228. /*  calendar() - Compute Gregorian calendar date from julian date.
  229. *
  230. *   Purpose:
  231. *       Provide a standard time base.
  232. *
  233. *   Arguments:
  234. *       juldate       - Julian date to convert
  235. *       year          - Calendar year result
  236. *       month         - Calendar month result
  237. *       day           - Calendar day and fraction result
  238. *
  239. *   Return Value:
  240. *       void
  241. *
  242. *   Globals (modified):
  243. *       none
  244. *
  245. *   Globals (referenced):
  246. *       none
  247. *
  248. *   Description:
  249. *       Convert Julian Days to Gregorian date.  Refer to Astronomical
  250. *       Formulae for Calculators (1979), p. 23, by Jean Meeus.
  251. *
  252. *   Limits:
  253. *       Valid for positive Julian Day values.
  254. *
  255. */
  256.  
  257. void PASCAL calendar (juldate, year, month, day)
  258. double juldate;
  259. int *year;
  260. int *month;
  261. double *day;
  262. {
  263.   long b, c, d, e, z, alf;
  264.  
  265.   juldate = juldate + 0.5;
  266.   z = trunc4(juldate);
  267.   alf = trunc4((z - 1867216.25)/36524.25);
  268.   b = z + 1 + alf - alf / 4 + 1524;
  269.   c = trunc4((b - 122.1)/365.25);
  270.   d = 365*c + c / 4;
  271.   e = trunc4((b - d)/30.6001);
  272.   *day = b - d - trunc4(30.6001*e) + juldate - z;
  273.   if (e > 13)
  274.       *month = (int)e - 13;
  275.   else
  276.       *month = (int)e - 1;
  277.   if (*month > 2)
  278.       *year = (int)c - 4716;
  279.   else
  280.       *year = (int)c - 4715;
  281. }
  282.  
  283. long PASCAL trunc4( dflValue )
  284. double dflValue;
  285. {
  286.    double intValue;
  287.    modf(dflValue, &intValue);
  288.    return (long)intValue;
  289. }
  290.