|
|
1.1 root 1: /*==============================================================*\
2: * sem_pnt.c - routines for the painting of the main window *
3: * Created 1990, Microsoft, IBM Corp. *
4: *--------------------------------------------------------------*
5: * *
6: * This module contains the code for the main client window *
7: * painting *
8: * *
9: *--------------------------------------------------------------*
10: * *
11: * This source file contains the following functions: *
12: * *
13: * DrawResource(PRECTL, COLOR) - Draws colored square *
14: * DrawStats(USHORT) update the statistics for a thread *
15: * ChangeResource(COLOR) - Changes resource color *
16: * InitSemaphExample(VOID) - Sets initial colors *
17: * SetRectPositions(HWND) - Calculate rectangle locations *
18: * MyOffsetRect(PRECTL,SHORT,SHORT) - Offsets consumer *
19: * rectangles from *
20: * resource *
21: * MainPaint(hwnd) - main WM_PAINT processing routine *
22: * *
23: \*==============================================================*/
24:
25: /*--------------------------------------------------------------*\
26: * Include files, macros, defined constants, and externs *
27: \*--------------------------------------------------------------*/
28:
29: #define LINT_ARGS
30: #define INCL_PM
31: #define INCL_BASE
32:
33: #include <os2.h>
34: #include <stdio.h>
35: #include <stdlib.h>
36: #include <string.h>
37: #include "sem_pnt.h"
38: #include "sem_main.h"
39: #include "sem_xtrn.h"
40: #include "semaph.h"
41:
42: /*--------------------------------------------------------------*\
43: * Global variables *
44: \*--------------------------------------------------------------*/
45: CHAR szWindowText[MAXTEXTLEN]="Sample";
46: USHORT cNumUsers = NUMUSERS;
47: SQ aSquares[MAXRESOURCES];
48: LONG colors[MAXUSERS]= {
49: CLR_WHITE, CLR_BLACK, CLR_BLUE, CLR_RED, CLR_PINK, CLR_GREEN,
50: CLR_CYAN, CLR_YELLOW, CLR_DARKGRAY, CLR_DARKBLUE, CLR_DARKRED,
51: CLR_DARKPINK, CLR_DARKGREEN, CLR_DARKCYAN, CLR_BROWN, CLR_PALEGRAY};
52:
53: LONG clrText[MAXUSERS]= {
54: CLR_BLACK, CLR_WHITE, CLR_YELLOW, CLR_GREEN, CLR_BLACK, CLR_YELLOW,
55: CLR_WHITE, CLR_RED, CLR_WHITE, CLR_BLUE, CLR_RED,
56: CLR_PINK, CLR_GREEN, CLR_CYAN, CLR_WHITE, CLR_DARKGRAY};
57:
58: /* static variables - only visible within this file */
59: static LONG yStatsTop, yStatsBtm, xStatsRight, yBoardTop, yDescGlobal;
60: static POINTL ptlInfoOne, ptlInfoTwo;
61: SHORT xWidth;
62: extern USHORT fSemaphoreStarted, fSemaphoreWasStarted;
63:
64: /****************************************************************\
65: * Routine to print informational message
66: *--------------------------------------------------------------
67: *
68: * Name: InfoLine (HPS)
69: *
70: * Purpose: print informational message as space allows
71: *
72: * Usage: called from DrawRects on screen repaint
73: *
74: * Method: use information stored in global variables to
75: * calculate the position for 2 lines of informational
76: * text and lines to bracket them.
77: *
78: * Returns: none
79: *
80: \****************************************************************/
81: VOID
82: InfoLine (HPS hps)
83: {
84: POINTL ptl;
85: LONG yBot;
86: CHAR acLineOne[MESSAGELEN];
87: CHAR acLineTwo[MESSAGELEN];
88:
89: /* print dividing line at bottom of stat display */
90: ptl.x = 0;
91: yBot = ptl.y = yStatsBtm - 2;
92: GpiMove (hps, &ptl);
93: ptl.x = xWidth;
94: GpiLine (hps, &ptl);
95:
96: /* ptlInfoOne and ptlInfoTwo are intialized in SetRectPositions
97: * when the window is created or resized.
98: * The y coordinate will be zero if the window is too small
99: * for the informational text.
100: */
101: if (ptlInfoOne.y) {
102: /* load informational text from resource file */
103: memset (acLineOne, 0, MESSAGELEN);
104: if(WinLoadString(hab, NULL, IDS_INFOONE, MESSAGELEN, (PSZ)acLineOne)) {
105: GpiCharStringAt (hps, &ptlInfoOne, MESSAGELEN, acLineOne);
106: yBot = ptlInfoOne.y - yDescGlobal - 1;
107: }
108: }
109:
110: if (ptlInfoTwo.y) {
111: /* load informational text from resource file */
112: memset (acLineTwo, 0, MESSAGELEN);
113: if(WinLoadString(hab, NULL, IDS_INFOTWO, MESSAGELEN, (PSZ)acLineTwo)) {
114: GpiCharStringAt (hps, &ptlInfoTwo, MESSAGELEN, acLineTwo);
115: yBot = ptlInfoTwo.y - yDescGlobal - 1;
116: }
117: }
118:
119: /* if there is informational text, then print another line at the top
120: * of the "game board".
121: */
122: if (yBoardTop != yStatsBtm) {
123: ptl.x = 0;
124: ptl.y = min (yBoardTop + 1, yBot);
125: GpiMove (hps, &ptl);
126: ptl.x = xWidth;
127: GpiLine (hps, &ptl);
128: }
129: }
130:
131: /****************************************************************\
132: * Routine to draw the resource rectangle. *
133: *--------------------------------------------------------------*
134: * *
135: * Name: DrawResource(PRECTL, COLOR) *
136: * *
137: * Purpose: Color 1 of the 64 rectangles on the playing board.*
138: * *
139: * Usage: Called from ThreadConsumer in semaph.c when *
140: * resource becomes owned by a thread. *
141: * *
142: * Method: Get the PS from global hwndMain and WinFillRect. *
143: * This rountine is included so that no access *
144: * to the resouce is made outside of paint.c. *
145: * This is to produce code which is more *
146: * object orientated. *
147: * *
148: * Returns: none *
149: * *
150: \****************************************************************/
151:
152: VOID DrawResource(PRECTL prcl, COLOR color)
153: {
154: HPS hps;
155:
156: hps = WinGetPS(hwndMain);
157: /* this code is related to the WinFillRect in DrawRects.
158: * they should stay in synch with each other.
159: */
160: WinFillRect(hps,prcl,color);
161: WinReleasePS(hps);
162: }
163:
164: /****************************************************************\
165: * update the statistics (number of hits) for a thread *
166: *--------------------------------------------------------------*
167: * *
168: * Name: DrawStats(USHORT) *
169: * *
170: * Purpose: update statistics display for for a thread *
171: * *
172: * Usage: Called from ThreadConsumer in semaph.c when *
173: * resource becomes owned by a thread. *
174: * *
175: * *
176: * Method: Get the PS, set colors, print number of hits for *
177: * the thread identified by usMyID. *
178: * This rountine is included so that no access *
179: * to the resouce is made outside of paint.c. *
180: * *
181: * Returns: *
182: * *
183: \****************************************************************/
184:
185: VOID DrawStats(USHORT usMyID)
186: {
187: HPS hps;
188: POINTL ptl;
189: THRDATA *pThr = &thrConsumers[usMyID];
190: CHAR szBuf [CNT_SZHITS];
191:
192: ptl.x = pThr->rcl.xLeft;
193: ptl.y = pThr->rcl.yBottom;
194: /* sprintf is non-reentrant, so it is used only when
195: * have the mutex.
196: */
197: sprintf (szBuf, "%4.4lu", pThr->lHits);
198: hps = WinGetPS(hwndMain);
199: GpiSetBackColor (hps, colors [usMyID]);
200: GpiSetColor (hps, clrText [usMyID]);
201: GpiCharStringPosAt (hps, &ptl, &pThr->rcl, CHS_CLIP | CHS_OPAQUE,
202: strlen (szBuf), szBuf, NULL);
203: WinReleasePS(hps);
204: }
205:
206:
207: /****************************************************************\
208: * Routine to paint rectangles in main window. *
209: *--------------------------------------------------------------*
210: * *
211: * Name: DrawRects(HPS) *
212: * *
213: * Purpose: Does painting of rectangles. *
214: * *
215: * Usage: Called from MainPaint when a paint message *
216: * is received after the semaphore sample has *
217: * been started. *
218: * *
219: * Method: Uses WinFillRect API to color all owned squares on*
220: * the square "playing board". Updates stats for *
221: * every active consumer thread. Prints the static *
222: * informational text. *
223: * *
224: * Returns: none. *
225: * *
226: \****************************************************************/
227:
228: VOID DrawRects(HPS hps)
229: {
230: INT i;
231:
232: /*
233: * Fill all rectangles in consumer array.... as well as rectangle
234: * for resource.
235: */
236: if (fSemaphoreWasStarted) {
237: for ( i = 0; i < MAXRESOURCES; i++ )
238: {
239: if (aSquares[i].usOwner < (USHORT) MAXUSERS &&
240: aSquares[i].usOwner != (USHORT) UNOWNED) {
241: /* this line is identical to that in DrawResource.
242: * they should stay in synch with each other.
243: */
244: WinFillRect (hps, &aSquares[i].rcl, colors[aSquares[i].usOwner]);
245: }
246: }
247: }
248: InfoLine (hps);
249: /* print statistics for each user */
250: for (i = 0; i < cNumUsers; i++) {
251: DrawStats (i);
252: }
253: }
254:
255:
256:
257: /********************************************************************\
258: * Routine to size and set the positions of rectangle.
259: *------------------------------------------------------------------
260: *
261: * Name: SetRectPositions (xClient, yClient, yChar, yDesc)
262: * SHORT xClient; width of client window
263: * SHORT yClient; height of client window
264: * SHORT yChar; maximum baseline extender
265: * SHORT yDesc; maximum char descender
266: *
267: * Purpose: Given above information about the window, calculate
268: * the area need for the square game board, the statistics
269: * display, and informative text.
270: *
271: * Usage: Called from MainWndProc whenever a size message
272: * is received.
273: *
274: * Method: Determines space needed for statistics display from the
275: * font information given as parameters to this procedure.
276: * Then calculates the 18 values which describe a chess
277: * by distances from a corner along 2 adjacent sides.
278: * These are stored in arrays aX and aY. Given these values,
279: * rectangles are calculated for each square on the grid,
280: * and stored as part of the information about those squares.
281: * Then the size of the rectangles used for the stat display
282: * at the top of the window are calculated, and stored in
283: * the struct describing the thread. Finally, the position
284: * of the line of informative text which divides the two regions
285: * of colored squares is derived.
286: *
287: * Returns: none
288: *
289: \********************************************************************/
290:
291: VOID SetRectPositions(SHORT xClient, SHORT yClient, SHORT yChar, SHORT yDesc)
292: {
293: INT i;
294: INT dx;
295: LONG aX [CNT_POINTS_EDGE];
296: LONG aY [CNT_POINTS_EDGE];
297: SHORT xScale, yScale;
298:
299: if (!fSemaphoreStarted)
300: {
301: /* insert code here for informative display */
302: }
303:
304: /* top of stat display */
305: yStatsTop = yClient;
306:
307: /* bottom of stat display */
308: yStatsBtm = yClient - yChar - yDesc;
309:
310: /* width of stat display */
311: xStatsRight = xClient;
312:
313: /* dx is the "scaling factor" for the statistics display */
314: dx = xStatsRight / cNumUsers;
315:
316: /* rectangles for the stat display */
317: for (i = 0; i < cNumUsers; i++) {
318: thrConsumers[i].rcl.yBottom = yStatsBtm;
319: thrConsumers[i].rcl.yTop = yStatsTop;
320: thrConsumers[i].rcl.xLeft = i * dx;
321: thrConsumers[i].rcl.xRight = (i+1) * dx;
322: }
323: /* consume any unused edge */
324: thrConsumers [cNumUsers - 1].rcl.xRight = xClient;
325:
326: /* if there is room for it, print an informational message */
327: if (yStatsBtm > yChar + yDesc) {
328: /* there is room for the first line */
329: ptlInfoOne.x = 0;
330: ptlInfoOne.y = yStatsBtm - yChar;
331: }
332: else
333: ptlInfoOne.y = 0L;
334:
335: if (ptlInfoOne.y && ptlInfoOne.y > (2 * yDesc + yChar)) {
336: /* room for second line */
337: ptlInfoTwo.x = 0;
338: ptlInfoTwo.y = ptlInfoOne.y - yChar - yDesc;
339: }
340: else
341: ptlInfoTwo.y = 0L;
342:
343: /* calculate top of playing board, hence stored in yClient */
344: if (ptlInfoTwo.y) {
345: yClient = ptlInfoTwo.y - yDesc;
346: }
347: else if (ptlInfoOne.y) {
348: yClient = ptlInfoOne.y - yDesc;
349: }
350: else
351: yClient = yStatsBtm - 1;
352:
353: /* discard unusable portion */
354: yClient = yClient - (yClient % CNT_SQUARES_EDGE);
355: /* the scaling factors determine how large each square will be */
356: xScale = xClient / CNT_SQUARES_EDGE;
357: yScale = yClient / CNT_SQUARES_EDGE;
358:
359: /* the entire game board is described by the points that are
360: * calculated here.
361: */
362: for (i = 0; i < CNT_POINTS_EDGE; i++) {
363: aX[i] = i * xScale;
364: aY[i] = i * yScale;
365: }
366: /* consume any unused portion */
367: aX[CNT_SQUARES_EDGE] = aX[CNT_SQUARES_EDGE] + xClient % CNT_SQUARES_EDGE;
368: aY[CNT_SQUARES_EDGE] = aY[CNT_SQUARES_EDGE] + yClient % CNT_SQUARES_EDGE - 1;
369:
370: /* now plug the points just calculated into the
371: * rectangles that make up the board
372: */
373: for (i = 0; i < MAXRESOURCES; i++) {
374: aSquares[i].rcl.xLeft = aX [i % CNT_SQUARES_EDGE];
375: aSquares[i].rcl.xRight = aX [(i % CNT_SQUARES_EDGE) + 1];
376: aSquares[i].rcl.yBottom = aY [i / CNT_SQUARES_EDGE];
377: aSquares[i].rcl.yTop = aY [(i / CNT_SQUARES_EDGE) + 1];
378: }
379: /* store the descender for later */
380: yDescGlobal = yDesc;
381: /* store top of board for later reference */
382: yBoardTop = aY[CNT_SQUARES_EDGE];
383: /* finally, store the width of the client window for later reference */
384: xWidth = xClient;
385: }
386:
387:
388:
389: /****************************************************************\
390: * client painting routine *
391: *--------------------------------------------------------------*
392: * *
393: * Name: MainPaint(hwnd) *
394: * *
395: * Purpose: Paints the main client window. *
396: * *
397: * Usage: Routine is called whenver the client window *
398: * procedure receives a WM_PAINT message *
399: * *
400: * Method: *
401: * - begins painting by calling WinBeginPaint *
402: * and retriving the HPS for the window *
403: * - performs any painting desired. Currently the *
404: * only painting it does is to draw rectangles on *
405: * the screen if semaphore is started. *
406: * - ends painting by calling WinEndPaint *
407: * *
408: * Returns: *
409: * *
410: \****************************************************************/
411:
412: VOID MainPaint(hwnd)
413: HWND hwnd; /* handle of the window to be painted */
414: {
415: HPS hps;
416:
417: hps = WinBeginPaint(hwnd, NULL, NULL);
418: GpiErase (hps);
419: DrawRects (hps);
420: WinEndPaint(hps);
421:
422: } /* MainPaint() */
423:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.