|
|
1.1 root 1: /*
2: biopaint.c - WM_PAINT processing and calendar conversion routines
3:
4: Created by Microsoft, IBM Corporation, 1990
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 SHORT 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 APPPaint( hWnd )
65: HWND hWnd;
66: {
67: HPS hPS;
68: POINTL ptl;
69: SHORT y, i;
70: SHORT start, last;
71: char szDay[16];
72: SHORT Amplitude, offset;
73: SHORT year, month;
74: double day;
75: RECTL rc, rcClip;
76: SHORT 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 julian (year, month, day)
215: SHORT 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 calendar (juldate, year, month, day)
258: double juldate;
259: SHORT *year;
260: SHORT *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 trunc4( dflValue )
284: double dflValue;
285: {
286: double intValue;
287: modf(dflValue, &intValue);
288: return (long)intValue;
289: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.