|
|
1.1 root 1: /********************************** Jigsaw ***********************************/
2: /* */
3: /* Created 1988, Microsoft Corporation. */
4: /* */
5: /* Purpose: To illustrate the use of Gpi retained segments. */
6: /* */
7: /* Summary: This program provides a jigsaw puzzle, based on a decomposition */
8: /* of an arbitrary bitmap loaded from a file. The user can jumble the */
9: /* pieces, then drag them individually by means of the mouse. The image */
10: /* can be zoomed in and out and scrolled up/down and left/right. */
11: /* */
12: /* Each piece of the puzzle is a retained segment. When a piece is */
13: /* selected for dragging, it is made dynamic. A menu option allows the */
14: /* selected piece to be dragged as an outline or as a normal-looking piece. */
15: /* */
16: /* Individual pieces are made to "move" by changing their model transforms. */
17: /* Scrolling and zooming of the whole picture is done by changing the */
18: /* default viewing transform. */
19: /* */
20: /* Optimizations: While it is possible to implement this puzzle using a very */
21: /* naive approach, this is liable to lead to a rather slowly-operating */
22: /* program. The following optimizations dramatically improve program */
23: /* performance: */
24: /* */
25: /* 1> BitBlt only as much of the bitmap through a clip path as necessary. */
26: /* Each piece of the puzzle is drawn by defining a clip path, blitting */
27: /* through the path, and drawing an outline on the same path. The naive */
28: /* approach is to blit the whole bitmap through the clip path. A more */
29: /* clever approach is to compute the piece's bounding box and only use */
30: /* the source and destination rectangles which correspond to this box. */
31: /* This leads to an order-of-magnitude speedup in the time to draw one */
32: /* piece. */
33: /* */
34: /* 2> Make the source and target rectangles for BitBlt the same size */
35: /* in device coordinates. A BitBlt in a retained segment must be done */
36: /* with GpiWCBitBlt and the target rectangle must be specified in world */
37: /* coordinates, so you must use GpiConvert (taking into account that in */
38: /* world space rectangles are inclusive-inclusive while in device space */
39: /* rectangles are inclusive-exclusive) to compute what target world space */
40: /* rectangle will be converted to the desired device space rectangle. */
41: /* Making the sizes of the source and converted target rectangles differ */
42: /* by even one pel will cause strectching or compression to occur, with */
43: /* a dramatic loss in speed. Unfortunately, due to rounding effects, it is */
44: /* not always possible to guarantee that adding an offset to the */
45: /* transformation applied to a segment will leave the size of the */
46: /* rectangle defined by the orders in the segment unchanged. */
47: /* */
48: /* 3> Use auxiliary information to reduce the number of segments which */
49: /* must be checked for correlation. The naive approach to hit-testing is */
50: /* to test the whole chain, even though generally only a small fraction of */
51: /* the segments in the chain could possibly get a hit. A more clever */
52: /* approach is to take the bounding box for each segment and only include */
53: /* the segment in the correlation check if the box contains the correlation */
54: /* point. eg. */
55: /* a> Edit the chain by adjusting the ATTR_CHAINED attribute of each */
56: /* segment to reflect candidacy for being hit. Afterwards, fix up by */
57: /* adding back removed segments to the chain. */
58: /* b> Even faster is to keep an auxiliary data structure which records */
59: /* the priority of the segments (placed in the SEGLIST chain). Run */
60: /* through the priority list from high-priority to low-priority and do a */
61: /* correlation test on each segment which passes the bounding-box test. */
62: /* */
63: /* 4> When repainting through a clip region, only draw those segments which */
64: /* overlap the clip region. The naive approach is to set up the clip */
65: /* region and do a GpiDrawChain on the whole chain. The drawback to this */
66: /* is that much time will be spent running through the orders in segments */
67: /* which are not visible through the clip region. Very often, most of the */
68: /* segments in the picture can be eliminated from needing to be drawn by */
69: /* recognizing that there is no overlap between the bounding boxes of the */
70: /* segment and the clip region. */
71: /* */
72: /* 5> Do WinScrollWindow horizontally in multiples of 8 pels when possible. */
73: /* For example, horizontal scrolls by 7 or 9 pels are much slower than a */
74: /* a horizontal scroll by 8 pels. */
75: /* */
76: /******************************************************************************/
77:
78: #define INCL_BITMAPFILEFORMAT
79:
80: #define INCL_DOSPROCESS
81: #define INCL_DOSSEMAPHORES
82: #define INCL_DOSMEMMGR
83:
84: #define INCL_DEV
85:
86: #define INCL_WINWINDOWMGR
87: #define INCL_WINMESSAGEMGR
88: #define INCL_WININPUT
89: #define INCL_WINRECTANGLES
90: #define INCL_WINPOINTERS
91: #define INCL_WINMENUS
92: #define INCL_WINSCROLLBARS
93: #define INCL_WINFRAMEMGR
94: #define INCL_WINSWITCHLIST
95: #define INCL_WINSYS
96:
97: #define INCL_GPIBITMAPS
98: #define INCL_GPICONTROL
99: #define INCL_GPITRANSFORMS
100: #define INCL_GPIPRIMITIVES
101: #define INCL_GPIMETAFILES
102: #define INCL_GPIPATHS
103: #define INCL_GPIREGIONS
104: #define INCL_GPISEGMENTS
105: #define INCL_GPISEGEDITING
106: #define INCL_GPICORRELATION
107: #define INCL_GPILCIDS
108:
109: #define INCL_ERRORS
110:
111: #include <os2.h>
112: #include <stdlib.h>
113: #include <stdio.h>
114: #include <string.h>
115: #include <opendlg.h>
116: #include "jigsaw.h"
117:
118:
119:
120: /*----------------------- inter-thread messages ------------------------------*/
121:
122: #define UM_DIE WM_USER+1 /* instruct async thread to terminate */
123: #define UM_DRAW WM_USER+2 /* draw the current picture */
124: #define UM_VSCROLL WM_USER+3 /* perform scroll by recalculating the */
125: /* default viewing transform */
126: #define UM_HSCROLL WM_USER+4 /* perform scroll by recalculating the */
127: /* default viewing transform */
128: #define UM_SIZING WM_USER+5 /* perform sizing by recalculating the */
129: /* default viewing transform */
130: #define UM_ZOOM_IN WM_USER+6 /* zoom the picture by recalculating */
131: /* the default viewing transform */
132: #define UM_ZOOM_OUT WM_USER+7 /* zoom the picture by recalculating */
133: /* the default viewing transform */
134: #define UM_REDRAW WM_USER+8
135: #define UM_JUMBLE WM_USER+9
136: #define UM_LOAD WM_USER+10
137: #define UM_DUMMY WM_USER+11 /* all commands not forcing redraw */
138: /* must come after this one */
139:
140: #define UM_LEFTDOWN WM_USER+12 /* mouse button down in the client area*/
141: /* perform a correlation on the current*/
142: /* picture, setting any picked segment */
143: /* to dynamic */
144: #define UM_MOUSEMOVE WM_USER+13 /* mousemove command, remove, repositon*/
145: /* and redraw any dynamic sements */
146: #define UM_LEFTUP WM_USER+14 /* mouse button up in the client area */
147: /* set any dynamic segment to normal */
148: #define UM_FASTDRAG WM_USER+15 /* toggle fast-drag (outline) mode */
149: #define UM_DRAWDONE WM_USER+16 /* Async DrawChain has completed */
150: #define UM_FLUSH WM_USER+17
151:
152:
153: /*------------------------ element label values -----------------------------*/
154:
155: #define FILLPATH 222L
156: #define BITBLT_TOP 232L
157: #define BITBLT_BOTTOM 233L
158:
159:
160: /*------------------------- correlation parameters ---------------------------*/
161:
162: #define HITS 1L /* maximum number of hits to return */
163: #define DEPTH 2L /* max depth of seg calls to return */
164:
165:
166: /*-------------------------- general definitions -----------------------------*/
167:
168:
169: HAB habMain=NULL; /* main thread anchor block handle */
170: HMQ hmqMain=NULL; /* main thread queue handle */
171: HWND hwndFrame=NULL; /* frame control handle */
172: HWND hwndClient=NULL; /* client area handle */
173: HDC hdcClient=NULL; /* window dc handle */
174: HPS hpsClient=NULL; /* client area Gpi ps handle */
175: SIZEL sizlMaxClient; /* max client area size */
176: HPS hpsPaint=NULL; /* ps for use in Main Thread */
177: HRGN hrgnInvalid = NULL; /* handle to the invalid region */
178:
179: HAB habAsync=NULL; /* async thread anchor block handle */
180: HMQ hmqAsync=NULL; /* async thread queue handle */
181: TID tidAsync; /* async thread id */
182: SEL selStack; /* async thread stack selector */
183: #define STACKSIZE 4096 /* async thread stack size */
184: SHORT sPrty = -1; /* async thread priority */
185:
186: HWND hwndHorzScroll=NULL; /* horizontal scroll bar window */
187: HWND hwndVertScroll=NULL; /* vertical scroll bar window */
188: POINTS ptsScrollPos, ptsOldScrollPos;
189: POINTS ptsScrollMax, ptsHalfScrollMax;
190: POINTS ptsScrollLine = { 8, 8};
191: POINTS ptsScrollPage = { 64, 64};
192:
193: #define UNITY 65536L
194: MATRIXLF matlfIdentity = { UNITY, 0, 0, 0, UNITY, 0, 0, 0, 1 };
195: LONG lScale = 0; /* current zoom level */
196: #define ZOOM_MAX 8
197: #define ZOOM_IN_ARG 1
198: #define ZOOM_OUT_ARG -1
199:
200: #define CALLSEG_BASE 1000
201: POINTL ptlOffset;
202: POINTL ptlBotLeft = { 0, 0};
203: POINTL ptlTopRight = { 300, 300};
204: LONG lLastSegId; /* last segment id assigned to a piece */
205: LONG lPickedSeg; /* seg id of piece selected for drag */
206: RECTL rclBounds; /* pict bounding box in model coords. */
207: POINTL ptlOldMouse = {0L, 0L}; /* current mouse posn */
208: BOOL fButtonDown = FALSE; /* only drag if mouse down */
209: BOOL fFastDrag = FALSE; /* show only outline of dragging piece */
210:
211:
212: /*-------------------------- segment list ------------------------------------*/
213:
214: typedef struct _SEGLIST { /* sl */
215: LONG lSegId;
216: struct _SEGLIST FAR * pslPrev;
217: struct _SEGLIST FAR * pslNext;
218: POINTL ptlLocation; /* piece location, world coordinates */
219: RECTL rclCurrent; /* segment bounding box, model coords */
220: RECTL rclBitBlt; /* segment bounding box, world coords */
221: } SEGLIST ;
222: typedef SEGLIST FAR *PSEGLIST; /* psl */
223: typedef PSEGLIST FAR *PPSEGLIST; /* ppsl */
224: PSEGLIST pslHead = NULL; /* head of the list */
225: PSEGLIST pslTail = NULL; /* tail of the list */
226: PSEGLIST pslPicked = NULL; /* picked segment's list member */
227: #define ADD_HEAD_SEG 1
228: #define ADD_TAIL_SEG 2
229: #define DEL_SEG 3
230:
231: /*-------------------------- bitmap-related data -----------------------------*/
232:
233: typedef struct _LOADINFO { /* li */
234: HFILE hf;
235: CHAR szFileName[MAX_FNAME_LEN];
236: } LOADINFO ;
237: typedef LOADINFO FAR *PLOADINFO; /* pli */
238:
239: HPS hpsBitmapFile=NULL, hpsBitmapTemp=NULL, hpsBitmapDrag=NULL;
240: HDC hdcBitmapFile=NULL, hdcBitmapTemp=NULL, hdcBitmapDrag=NULL;
241: HBITMAP hbmBitmapFile=NULL, hbmBitmapTemp=NULL, hbmBitmapDrag=NULL;
242: BITMAPINFOHEADER bmpBitmapFile = {12L, 0, 0, 0, 0};
243: BITMAPINFOHEADER bmpBitmapTemp = {12L, 0, 0, 0, 0};
244: BITMAPINFOHEADER bmpBitmapDrag = {12L, 0, 0, 0, 0};
245: BITMAPINFO bmiBitmap = {12L, 0, 0, 0, 0, {{0, 0, 0}}};
246: static DEVOPENSTRUC dop = { NULL
247: , "DISPLAY"
248: , NULL
249: , NULL
250: , NULL
251: , NULL
252: , NULL
253: , NULL
254: , NULL };
255:
256:
257: /*-------------------------- old-style bitmap header -------------------------*/
258:
259: typedef struct {
260: USHORT wType;
261: ULONG dwSize;
262: int xHotspot;
263: int yHotspot;
264: ULONG dwBitsOffset;
265: USHORT bmWidth;
266: USHORT bmHeight;
267: USHORT bmPlanes;
268: USHORT bmBitcount;
269: } RCBITMAP;
270: typedef RCBITMAP FAR *PRCBITMAP;
271:
272:
273: /*--------------------------- Miscellaneous ----------------------------------*/
274:
275: ULONG ulTerminateSem = 0; /* main thread blocks while async dies */
276: HSEM hsemTerminate = &ulTerminateSem;
277:
278: ULONG ulSzFmt = 0; /* serializes access to sprintf() */
279: HSEM hsemSzFmt = &ulSzFmt;
280: CHAR szFmt[50]; /* buffer used by sprintf() */
281:
282: SWCNTRL swctl = { 0, 0, 0, 0, 0, SWL_VISIBLE, SWL_JUMPABLE, NULL, 0 };
283: HSWITCH hsw; /* handle to a switch list entry */
284: char szTitle[80]; /* Title bar text */
285:
286: BOOL fErrMem = FALSE; /* set if alloc async stack fails */
287:
288:
289: /*------------------------- Function Prototypes ------------------------------*/
290:
291: VOID CalcBounds( VOID);
292: VOID CalcTransform( HWND);
293: MRESULT CALLBACK ClientWndProc( HWND, USHORT, MPARAM, MPARAM);
294: BOOL CreateBitmapHdcHps( HDC, HPS);
295: BOOL CreateThread( VOID);
296: BOOL CreatePicture( VOID);
297: VOID DestroyThread( VOID);
298: BOOL DoDraw( HRGN);
299: VOID DoHorzScroll( VOID);
300: VOID DoVertScroll( VOID);
301: BOOL DumpPicture( VOID);
302: VOID Finalize( VOID);
303: BOOL Initialize( VOID);
304: VOID Jumble( VOID);
305: VOID LeftDown( MPARAM);
306: VOID LeftUp( VOID);
307: VOID Load( PLOADINFO);
308: VOID cdecl main( VOID);
309: VOID MessageInt( HWND, INT, PCH);
310: VOID MouseMove( MPARAM);
311: VOID MyMessageBox( HWND, PSZ);
312: VOID FAR NewThread( VOID);
313: BOOL PrepareBitmap( VOID);
314: BOOL ReadBitmap( HFILE);
315: VOID Redraw( VOID);
316: VOID ReportError( HAB);
317: BOOL SegListCheck( INT);
318: PSEGLIST SegListGet( LONG);
319: BOOL SegListUpdate( USHORT, PSEGLIST);
320: BOOL SendCommand( USHORT, ULONG);
321: VOID SetDVTransform( FIXED, FIXED, FIXED, FIXED, LONG, LONG, LONG);
322: VOID SetRect( PSEGLIST);
323: VOID ToggleFastDrag( VOID);
324: VOID Translate( PSEGLIST, PPOINTL);
325: MRESULT WndProcCommand( HWND, USHORT, MPARAM, MPARAM);
326: MRESULT WndProcCreate( HWND);
327: MRESULT WndProcPaint( VOID);
328: MRESULT WndProcSize( MPARAM, MPARAM);
329: VOID Zoom( SHORT);
330: VOID ZoomMenuItems( VOID);
331:
332:
333: /******************************************************************************/
334: /* */
335: /* MyMessageBox */
336: /* */
337: /* Displays a message box with the given string. To simplify matters, */
338: /* the box will always have the same title ("Jigsaw"), will always */
339: /* have a single button ("Ok"), will always have an exclamation point */
340: /* icon, and will always be application modal. */
341: /* */
342: /******************************************************************************/
343: VOID
344: MyMessageBox( hWnd, psz)
345:
346: HWND hWnd;
347: PSZ psz;
348: {
349: WinMessageBox( HWND_DESKTOP
350: , hWnd
351: , psz
352: , szTitle
353: , NULL
354: , MB_OK | MB_ICONEXCLAMATION | MB_APPLMODAL );
355: }
356:
357: /******************************************************************************/
358: /* */
359: /* Main thread will initialize the process for PM services and process */
360: /* the application message queue until a WM_QUIT message is received. It will */
361: /* then destroy all PM resources and terminate. Any error during */
362: /* initialization will be reported and the process terminated. */
363: /* */
364: /******************************************************************************/
365: VOID cdecl
366: main()
367: {
368: QMSG qmsg;
369:
370: if( Initialize())
371: while( WinGetMsg( habMain, &qmsg, NULL, NULL, NULL))
372: WinDispatchMsg( habMain, &qmsg);
373: else
374: ReportError( habMain);
375: Finalize();
376: }
377:
378:
379: /******************************************************************************/
380: /* */
381: /* The Initialize function will initialize the PM interface, */
382: /* create an application message queue, a standard frame window and a new */
383: /* thread to control drawing operations. It will also initialize static */
384: /* strings. */
385: /* */
386: /******************************************************************************/
387: BOOL
388: Initialize()
389: {
390: ULONG flCreate;
391: PID pid;
392: TID tid;
393:
394: WinShowPointer( HWND_DESKTOP, TRUE);
395: habMain = WinInitialize( NULL);
396: if( !habMain)
397: return( FALSE);
398:
399: hmqMain = WinCreateMsgQueue( habMain,0);
400: if( !hmqMain)
401: return( FALSE);
402:
403: WinLoadString( habMain, NULL, TITLEBAR, sizeof(szTitle), szTitle);
404: if( !WinRegisterClass( habMain
405: , (PCH)szTitle
406: , (PFNWP)ClientWndProc
407: , CS_SIZEREDRAW
408: , 0 ))
409: return( FALSE);
410:
411: flCreate = (FCF_STANDARD | FCF_VERTSCROLL | FCF_HORZSCROLL)
412: & ~(ULONG)FCF_TASKLIST;
413: hwndFrame = WinCreateStdWindow( HWND_DESKTOP
414: , WS_VISIBLE
415: , &flCreate
416: , szTitle
417: , szTitle
418: , WS_VISIBLE
419: , NULL
420: , APPMENU
421: , &hwndClient);
422: if( !hwndFrame)
423: return( FALSE);
424:
425: WinQueryWindowProcess( hwndFrame, &pid, &tid);
426: swctl.hwnd = hwndFrame;
427: swctl.idProcess = pid;
428: lstrcpy( swctl.szSwtitle, szTitle);
429: hsw = WinAddSwitchEntry( &swctl);
430:
431: if( !CreateThread()) /* create async thread */
432: return ( FALSE);
433: if( !CreateBitmapHdcHps( &hdcBitmapFile, &hpsBitmapFile))
434: return( FALSE);
435: if( !CreateBitmapHdcHps( &hdcBitmapTemp, &hpsBitmapTemp))
436: return( FALSE);
437: if( !CreateBitmapHdcHps( &hdcBitmapDrag, &hpsBitmapDrag))
438: return( FALSE);
439:
440: return( TRUE);
441: }
442:
443: /******************************************************************************/
444: /* */
445: /* Finalize will destroy the asynchronous drawing thread, all Presentation */
446: /* Manager resources, and terminate the process. */
447: /* */
448: /******************************************************************************/
449: VOID
450: Finalize()
451: {
452: DestroyThread();
453:
454: while( pslHead != NULL )
455: SegListUpdate( DEL_SEG, pslHead);
456: if( hrgnInvalid)
457: GpiDestroyRegion( hpsClient, hrgnInvalid);
458: if( hpsClient)
459: GpiAssociate( hpsClient, NULL);
460: if( hpsPaint)
461: GpiAssociate( hpsPaint, NULL);
462: if( hpsBitmapFile)
463: GpiAssociate( hpsBitmapFile, NULL);
464: if( hpsBitmapTemp)
465: GpiAssociate( hpsBitmapTemp, NULL);
466: if( hpsBitmapDrag)
467: GpiAssociate( hpsBitmapDrag, NULL);
468: if( hwndFrame)
469: WinDestroyWindow( hwndFrame);
470: if( hmqMain)
471: WinDestroyMsgQueue( hmqMain);
472: if( habMain)
473: WinTerminate( habMain);
474:
475: DosExit( EXIT_PROCESS, 0);
476: }
477:
478:
479: /******************************************************************************/
480: /* */
481: /* ReportError will display the latest error information for the required */
482: /* thread. No resources to be loaded if out of memory error. */
483: /* */
484: /******************************************************************************/
485: VOID
486: ReportError( hab)
487:
488: HAB hab;
489: {
490: PERRINFO perriBlk;
491: PSZ pszErrMsg;
492: USHORT * TempPtr;
493:
494: if( !hwndFrame)
495: return;
496: if( !fErrMem)
497: {
498: perriBlk = WinGetErrorInfo(hab);
499: if( !perriBlk)
500: return;
501: SELECTOROF( pszErrMsg) = SELECTOROF(perriBlk);
502: SELECTOROF( TempPtr) = SELECTOROF(perriBlk);
503: OFFSETOF( TempPtr) = perriBlk->offaoffszMsg;
504: OFFSETOF( pszErrMsg) = *TempPtr;
505: WinMessageBox( HWND_DESKTOP
506: , hwndFrame
507: , pszErrMsg
508: , szTitle
509: , 0
510: , MB_CUACRITICAL | MB_ENTER);
511: WinFreeErrorInfo( perriBlk);
512: } else
513: WinMessageBox( HWND_DESKTOP
514: , hwndFrame
515: , "ERROR - Out Of Memory"
516: , szTitle
517: , 0
518: , MB_CUACRITICAL | MB_ENTER);
519: }
520:
521:
522: /******************************************************************************/
523: /* */
524: /* CreateThread creates the asynchronous drawing thread. It will allocate */
525: /* stack space and create the thread. */
526: /* */
527: /******************************************************************************/
528: BOOL
529: CreateThread()
530: {
531: PBYTE pbAsyncStack; /* long pointer to stack for new thread */
532:
533:
534: if( DosAllocSeg( STACKSIZE, (PSEL)&selStack, 0 ))
535: {
536: fErrMem = TRUE;
537: return( FALSE);
538: }
539: OFFSETOF(pbAsyncStack) = STACKSIZE-2;
540: SELECTOROF(pbAsyncStack) = selStack;
541: if( DosCreateThread( (PFNTHREAD)NewThread, &tidAsync, pbAsyncStack ))
542: return( FALSE);
543: return( TRUE);
544: }
545:
546:
547: /******************************************************************************/
548: /* */
549: /* DestroyThread will send a message to the asynchronous drawing thread */
550: /* commanding it to terminate itself. If the send is successful it will wait */
551: /* until the async thread has terminated. It will then release any stack space*/
552: /* used by that thread. */
553: /* */
554: /******************************************************************************/
555: VOID
556: DestroyThread()
557: {
558: if( tidAsync)
559: {
560: DosSemSet( hsemTerminate);
561: if( SendCommand( (USHORT)UM_DIE, (ULONG)NULL))
562: DosSemWait( hsemTerminate, SEM_INDEFINITE_WAIT);
563: }
564: if( selStack)
565: DosFreeSeg( selStack);
566: }
567:
568:
569: /******************************************************************************/
570: /* */
571: /* SendCommand will attempt to post the required command and parameters to */
572: /* the asynchronous drawing thread's message queue. The command will only */
573: /* be posted if the queue exists. */
574: /* */
575: /******************************************************************************/
576: BOOL
577: SendCommand( usCommand, ulInfo)
578:
579: USHORT usCommand;
580: ULONG ulInfo;
581: {
582: if( !hmqAsync)
583: return( FALSE);
584:
585: switch( usCommand)
586: {
587: case UM_DIE:
588: case UM_LEFTDOWN:
589: case UM_LEFTUP:
590: case UM_MOUSEMOVE:
591: case UM_DRAW:
592: case UM_HSCROLL:
593: case UM_VSCROLL:
594: case UM_ZOOM_IN:
595: case UM_ZOOM_OUT:
596: case UM_REDRAW:
597: case UM_SIZING:
598: case UM_FASTDRAG:
599: case UM_JUMBLE:
600: case UM_LOAD:
601:
602: return( WinPostQueueMsg( hmqAsync
603: , usCommand
604: , MPFROMLONG( ulInfo)
605: , MPFROMLONG( NULL ) ) );
606: break;
607:
608: default:
609: return( TRUE);
610: }
611: }
612:
613:
614: /******************************************************************************/
615: /* */
616: /* ClientWndProd is the window procedure associated with the client window. */
617: /* */
618: /******************************************************************************/
619: MRESULT CALLBACK
620: ClientWndProc( hwnd, msg, mp1, mp2)
621:
622: HWND hwnd;
623: USHORT msg;
624: MPARAM mp1;
625: MPARAM mp2;
626: {
627: CHAR szTemp[128];
628:
629: switch( msg)
630: {
631: case WM_CREATE:
632: return( WndProcCreate( hwnd));
633: break;
634:
635: case WM_CLOSE:
636: WinLoadString( habMain, NULL, TERMINATE, sizeof(szTemp), (PSZ)szTemp );
637: if( WinMessageBox( HWND_DESKTOP
638: , hwndFrame
639: , szTemp
640: , szTitle
641: , 0
642: , MB_CUAWARNING | MB_YESNO | MB_DEFBUTTON2)
643: == MBID_YES)
644: WinPostMsg( hwnd, WM_QUIT, NULL, NULL);
645: break;
646:
647: case WM_PAINT:
648: return( WndProcPaint());
649: break;
650:
651: /**************************************************************************/
652: /* */
653: /**************************************************************************/
654: case WM_ERASEBACKGROUND:
655: WinFillRect( (HPS)mp1, (PRECTL)mp2, CLR_BACKGROUND);
656: return( FALSE);
657: break;
658:
659: /**************************************************************************/
660: /* */
661: /**************************************************************************/
662: case WM_MINMAXFRAME:
663: if( (((PSWP)mp1)->fs & SWP_RESTORE) ||
664: (((PSWP)mp1)->fs & SWP_MAXIMIZE) )
665: SendCommand( (USHORT)UM_SIZING, 0L);
666: break;
667:
668: /**************************************************************************/
669: /* Process menu item commands, and commands generated from the keyboard */
670: /* via the accelerator table. Most are handled by the async thread */
671: /**************************************************************************/
672: case WM_COMMAND:
673: return( WndProcCommand( hwnd, msg, mp1, mp2));
674: break;
675:
676: /**************************************************************************/
677: /* Scrolling is handled by the async drawing thread. Simply pass on the */
678: /* command and parameters */
679: /**************************************************************************/
680: case WM_HSCROLL:
681: SendCommand( (USHORT)UM_HSCROLL, LONGFROMMP(mp2));
682: break;
683:
684: case WM_VSCROLL:
685: SendCommand( (USHORT)UM_VSCROLL, LONGFROMMP(mp2));
686: break;
687:
688: /************************************************************************/
689: /* The client area is being resized. */
690: /************************************************************************/
691: case WM_SIZE:
692: return( WndProcSize( mp1, mp2));
693: break;
694:
695: /**************************************************************************/
696: /* Mouse commands are handled by the async thread. Simply send on the */
697: /* command and parameters. */
698: /**************************************************************************/
699: case WM_BUTTON1DBLCLK:
700: case WM_BUTTON1DOWN:
701: if( hwnd != WinQueryFocus( HWND_DESKTOP, FALSE))
702: WinSetFocus( HWND_DESKTOP, hwnd);
703: if( !fButtonDown)
704: {
705: fButtonDown = TRUE;
706: SendCommand( (USHORT)UM_LEFTDOWN, LONGFROMMP(mp1));
707: }
708: return( TRUE);
709: break;
710:
711: case WM_BUTTON1UP:
712: if( !fButtonDown)
713: return( TRUE);
714: if( SendCommand( (USHORT)UM_LEFTUP, LONGFROMMP(mp1)))
715: fButtonDown = FALSE;
716: else
717: WinAlarm( HWND_DESKTOP, WA_WARNING);
718: return( TRUE);
719: break;
720:
721: case WM_MOUSEMOVE:
722: if( fButtonDown && (pslPicked != NULL))
723: SendCommand( (USHORT)UM_MOUSEMOVE, LONGFROMMP(mp1));
724: return( WinDefWindowProc( hwnd, msg, mp1, mp2));
725: break;
726:
727: /**************************************************************************/
728: /* Default for the rest */
729: /**************************************************************************/
730: default:
731: return( WinDefWindowProc( hwnd, msg, mp1, mp2));
732: }
733:
734: return( FALSE);
735: }
736:
737: /******************************************************************************/
738: /* */
739: /* Get the maximum client area size. Create a window DC for the client */
740: /* area and a normal GPI Presentation Space and associate the two. The GPI */
741: /* PS will be the maximum client area size and be in pels. */
742: /* */
743: /******************************************************************************/
744: MRESULT
745: WndProcCreate( hwnd)
746:
747: HWND hwnd;
748: {
749: SIZEL sizlPickApp; /* pick aperture size */
750:
751: sizlMaxClient.cx = WinQuerySysValue( HWND_DESKTOP, SV_CXFULLSCREEN);
752: sizlMaxClient.cy = WinQuerySysValue( HWND_DESKTOP, SV_CYFULLSCREEN);
753:
754: hdcClient = WinOpenWindowDC( hwnd);
755: hpsClient = GpiCreatePS( habMain
756: , hdcClient
757: , &sizlMaxClient
758: , GPIA_ASSOC | PU_PELS );
759: if( !hpsClient)
760: return( TRUE);
761: GpiSetAttrMode( hpsClient, AM_PRESERVE);
762:
763: hwndHorzScroll = WinWindowFromID( WinQueryWindow( hwnd, QW_PARENT, FALSE)
764: , FID_HORZSCROLL);
765:
766: hwndVertScroll = WinWindowFromID( WinQueryWindow( hwnd, QW_PARENT, FALSE)
767: , FID_VERTSCROLL);
768:
769: hpsPaint = GpiCreatePS( habMain, NULL, &sizlMaxClient, PU_PELS);
770:
771: hrgnInvalid = GpiCreateRegion( hpsClient, 0L, NULL);
772:
773: sizlPickApp.cx = sizlPickApp.cy = 1;
774: GpiSetPickApertureSize( hpsClient, PICKAP_REC, &sizlPickApp);
775: return( FALSE);
776: }
777:
778:
779: /*******************************************************************************/
780: /* */
781: /* WM_PAINT message */
782: /* */
783: /*******************************************************************************/
784: MRESULT
785: WndProcPaint()
786:
787: {
788: HRGN hrgnUpdt;
789: SHORT sRgnType;
790:
791: hrgnUpdt = GpiCreateRegion( hpsPaint, 0L, NULL);
792: sRgnType = WinQueryUpdateRegion( hwndClient, hrgnUpdt);
793: WinValidateRegion( hwndClient, hrgnUpdt, FALSE);
794: SendCommand( UM_DRAW, (ULONG)hrgnUpdt);
795: return( FALSE);
796: }
797:
798: /******************************************************************************/
799: /* Process menu item commands, and commands generated from the keyboard via */
800: /* the accelerator table. Most are handled by the async thread */
801: /******************************************************************************/
802: MRESULT
803: WndProcCommand( hwnd, msg, mp1, mp2)
804:
805: HWND hwnd;
806: USHORT msg;
807: MPARAM mp1, mp2;
808: {
809: CHAR szTemp[128];
810: DLF dlf;
811: SEL sel;
812: PLOADINFO pli;
813: PSZ pszError, psz1, psz2;
814:
815: switch( SHORT1FROMMP(mp1))
816: {
817: case MENU_JUMBLE:
818: SendCommand( UM_JUMBLE, 0L);
819: break;
820:
821: case MENU_LOAD:
822: DosAllocSeg( sizeof( LOADINFO), &sel, 0);
823: pli = MAKEP( sel, 0);
824:
825: dlf.rgbAction = DLG_OPENDLG;
826: dlf.rgbFlags = ATTRDIRLIST;
827: dlf.phFile = &(pli->hf);
828: dlf.pszExt = (PSZ)"\\*.bmp";
829: dlf.pszAppName = szTitle;
830: dlf.pszTitle = "Load Bitmap";
831: dlf.pszInstructions = NULL;
832: dlf.szFileName[0] = '\0';
833: dlf.szOpenFile[0] = '\0';
834: pszError = "Error reading file.";
835:
836: switch( DlgFile( hwnd, &dlf))
837: {
838: case TDF_ERRMEM:
839: case TDF_INVALID:
840: MyMessageBox( hwnd, pszError);
841: break;
842:
843: case TDF_NOOPEN:
844: break;
845:
846: default:
847: for( psz1 = dlf.szFileName, psz2 = pli->szFileName
848: ; *psz2++ = *psz1++
849: ; )
850: ;
851: SendCommand( UM_LOAD, (LONG)pli);
852: break;
853: }
854: break;
855: /**********************************************************************/
856: /* EXIT command, menu item or F3 key pressed. Give the operator a */
857: /* second chance, if confirmed post a WM_QUIT msg to the application */
858: /* msg queue. This will force the MAIN thread to terminate. */
859: /**********************************************************************/
860: case MENU_EXIT:
861: WinLoadString( habMain, NULL, TERMINATE, sizeof(szTemp), szTemp);
862: if( WinMessageBox( HWND_DESKTOP
863: , hwndFrame
864: , szTemp
865: , szTitle
866: , 0
867: , MB_CUAWARNING | MB_YESNO | MB_DEFBUTTON2)
868: == MBID_YES)
869: WinPostMsg( hwnd, WM_QUIT, NULL, NULL);
870: break;
871:
872: /**********************************************************************/
873: /* Pass on the rest to the async thread. */
874: /**********************************************************************/
875: case MENU_ZOOMIN:
876: SendCommand( UM_ZOOM_IN, 0L);
877: break;
878:
879: case MENU_ZOOMOUT:
880: SendCommand( UM_ZOOM_OUT, 0L);
881: break;
882:
883: case MENU_FASTDRAG:
884: SendCommand( UM_FASTDRAG, 0L);
885: break;
886:
887: /**********************************************************************/
888: /* Unrecognised => default */
889: /**********************************************************************/
890: default:
891: return( WinDefWindowProc(hwnd, msg, mp1, mp2));
892: }
893: return( FALSE);
894: }
895:
896: /******************************************************************************/
897: /* Load a bitmap */
898: /******************************************************************************/
899: VOID
900: Load( pli)
901:
902: PLOADINFO pli;
903: {
904: PSZ pszError;
905: RECTL rclClient;
906:
907: pszError = (PSZ)"Error reading file.";
908:
909: DumpPicture();
910: if( !ReadBitmap( pli->hf) )
911: {
912: MyMessageBox( hwndClient, pszError);
913: return;
914: }
915: if( !PrepareBitmap() )
916: {
917: MyMessageBox( hwndClient, pszError);
918: return;
919: }
920:
921: lstrcpy( swctl.szSwtitle, szTitle);
922: lstrcat( swctl.szSwtitle, ": ");
923: lstrcat( swctl.szSwtitle, pli->szFileName);
924: WinChangeSwitchEntry( hsw, &swctl);
925: WinSetWindowText( hwndFrame, swctl.szSwtitle);
926:
927: CreatePicture();
928: lScale = 0;
929:
930: WinQueryWindowRect( hwndClient, &rclClient);
931: ptsScrollMax.x = (SHORT)(rclClient.xRight - rclClient.xLeft);
932: ptsHalfScrollMax.x = ptsScrollMax.x >> 1;
933: ptsScrollPos.x = ptsHalfScrollMax.x;
934: ptsOldScrollPos.x = ptsHalfScrollMax.x;
935: WinSendMsg( hwndHorzScroll
936: , SBM_SETSCROLLBAR
937: , MPFROMSHORT( ptsScrollPos.x)
938: , MPFROM2SHORT( 1, ptsScrollMax.x) );
939: ptsScrollMax.y = (SHORT)(rclClient.yTop - rclClient.yBottom);
940: ptsHalfScrollMax.y = ptsScrollMax.y >> 1;
941: ptsScrollPos.y = ptsHalfScrollMax.y;
942: ptsOldScrollPos.y = ptsHalfScrollMax.y;
943: WinSendMsg( hwndVertScroll
944: , SBM_SETSCROLLBAR
945: , MPFROMSHORT( ptsScrollPos.y)
946: , MPFROM2SHORT( 1, ptsScrollMax.y) );
947:
948: CalcBounds();
949: CalcTransform( hwndClient);
950: DosFreeSeg( SELECTOROF( pli));
951: }
952: /******************************************************************************/
953: /* Throw the pieces around the screen. */
954: /******************************************************************************/
955: VOID
956: Jumble()
957: {
958: LONG lWidth, lHeight;
959: DATETIME date;
960: POINTL ptl;
961: RECTL rclClient;
962: PSEGLIST psl;
963:
964: if( WinQueryWindowRect( hwndClient, &rclClient) )
965: {
966: lWidth = rclClient.xRight - rclClient.xLeft;
967: lHeight = rclClient.yTop - rclClient.yBottom;
968: if( (lWidth > 0) && (lHeight > 0) )
969: {
970: DosGetDateTime( &date);
971: srand( (USHORT)date.hundredths);
972: for( psl = pslHead; psl != NULL; psl = psl->pslNext)
973: {
974: ptl.x = rclClient.xLeft + (rand() % lWidth);
975: ptl.y = rclClient.yBottom + (rand() % lHeight);
976: Translate( psl, &ptl);
977: SetRect( psl);
978: }
979: }
980: }
981: }
982:
983: /******************************************************************************/
984: /* The client area is being resized. The current scroll bar thumb position */
985: /* and scroll bar range must be recalculated prior to recalculating the */
986: /* default viewing transform for the picture. Wait for subsequent WM_PAINT */
987: /* to do any drawing. */
988: /******************************************************************************/
989: MRESULT
990: WndProcSize( mp1, mp2)
991:
992: MPARAM mp1, mp2;
993: {
994: HWND hwndFrameTemp;
995:
996: if( hwndFrame)
997: hwndFrameTemp = hwndFrame;
998: else
999: hwndFrameTemp = WinQueryWindow( hwndClient, QW_PARENT, FALSE);
1000:
1001: ptsScrollMax.y = SHORT2FROMMP( mp2);
1002: ptsHalfScrollMax.y = ptsScrollMax.y >> 1;
1003: if( mp1)
1004: {
1005: ptsScrollPos.y = (SHORT)(((LONG)ptsScrollPos.y * (LONG)SHORT2FROMMP(mp2))/(LONG)SHORT2FROMMP(mp1));
1006: ptsOldScrollPos.y = (SHORT)(((LONG)ptsOldScrollPos.y * (LONG)SHORT2FROMMP(mp2))/(LONG)SHORT2FROMMP(mp1));
1007: } else
1008: {
1009: ptsScrollPos.y = ptsHalfScrollMax.y; /* first sizing after window creation */
1010: ptsOldScrollPos.y = ptsHalfScrollMax.y;
1011: }
1012: WinSendMsg( hwndVertScroll
1013: , SBM_SETSCROLLBAR
1014: , MPFROMSHORT( ptsScrollPos.y)
1015: , MPFROM2SHORT( 1, ptsScrollMax.y) );
1016:
1017:
1018: ptsScrollMax.x = SHORT1FROMMP( mp2);
1019: ptsHalfScrollMax.x = ptsScrollMax.x >> 1;
1020: if( mp1)
1021: {
1022: ptsScrollPos.x = (SHORT)(((LONG)ptsScrollPos.x * (LONG)SHORT1FROMMP(mp2))/(LONG)SHORT1FROMMP(mp1));
1023: ptsOldScrollPos.x = (SHORT)(((LONG)ptsOldScrollPos.x * (LONG)SHORT1FROMMP(mp2))/(LONG)SHORT1FROMMP(mp1));
1024: } else
1025: {
1026: ptsScrollPos.x = ptsHalfScrollMax.x; /* first sizing after window creation */
1027: ptsOldScrollPos.x = ptsHalfScrollMax.x;
1028: }
1029: WinSendMsg( hwndHorzScroll
1030: , SBM_SETSCROLLBAR
1031: , MPFROMSHORT( ptsScrollPos.x)
1032: , MPFROM2SHORT( 1, ptsScrollMax.x) );
1033:
1034:
1035: SendCommand( UM_SIZING, 0L);
1036: return( FALSE);
1037: }
1038:
1039: /******************************************************************************/
1040: /* */
1041: /* NewThread is the asynchronous drawing thread. It is responsible for all */
1042: /* drawing. It will initialize its PM interface and create an application */
1043: /* message queue. It will then monitor its message queue and process any */
1044: /* commands received. */
1045: /* */
1046: /******************************************************************************/
1047: VOID FAR
1048: NewThread()
1049: {
1050: QMSG qmsgAsync, qmsgPeek;
1051: BOOL fDone;
1052:
1053: /****************************************************************************/
1054: /* Initialize the PM interface. If it fails, terminate both threads. */
1055: /****************************************************************************/
1056: habAsync = WinInitialize( NULL);
1057: if( !habAsync)
1058: {
1059: WinPostMsg( hwndClient, WM_QUIT, NULL, NULL);
1060: DosExit( EXIT_THREAD, 0);
1061: }
1062:
1063: /****************************************************************************/
1064: /* Create a message queue. If it fails, terminate both threads. */
1065: /****************************************************************************/
1066: hmqAsync = WinCreateMsgQueue( habAsync, 80);
1067: if( !hmqAsync)
1068: {
1069: WinPostMsg( hwndClient, WM_QUIT, NULL, NULL);
1070: WinTerminate( habAsync);
1071: DosExit( EXIT_THREAD, 0);
1072: }
1073:
1074: DosSetPrty( PRTYS_THREAD, PRTYC_NOCHANGE, sPrty, (TID)NULL);
1075:
1076:
1077: while( TRUE)
1078: {
1079: WinGetMsg( habAsync, &qmsgAsync, NULL, 0, 0);
1080:
1081: /**************************************************************************/
1082: /* process the commands */
1083: /**************************************************************************/
1084: switch( qmsgAsync.msg)
1085: {
1086:
1087: /************************************************************************/
1088: /************************************************************************/
1089: case UM_LOAD:
1090: Load( (PLOADINFO)qmsgAsync.mp1);
1091: Redraw();
1092: break;
1093:
1094: /************************************************************************/
1095: case UM_JUMBLE:
1096: Jumble();
1097: Redraw();
1098: break;
1099:
1100: /************************************************************************/
1101: case UM_REDRAW:
1102: Redraw();
1103: break;
1104:
1105: /************************************************************************/
1106: /* DRAW will use the passed region containing the invalidated area of */
1107: /* the screen, repaint it and then destroy the region. */
1108: /************************************************************************/
1109: case UM_DRAW:
1110: DoDraw( (HRGN)qmsgAsync.mp1);
1111: if( qmsgAsync.mp1)
1112: GpiDestroyRegion( hpsClient, (HRGN)qmsgAsync.mp1);
1113: break;
1114:
1115:
1116: /************************************************************************/
1117: /* Get new scroll posn from command ( i.e. +/-1 +/-page) or new */
1118: /* absolute position from parameter, update scroll posn, change the */
1119: /* transform and update the thumb posn. Finally update the window. */
1120: /************************************************************************/
1121: case UM_HSCROLL:
1122: switch( SHORT2FROMMP( qmsgAsync.mp1) )
1123: {
1124: case SB_LINEUP:
1125: ptsScrollPos.x -= ptsScrollLine.x;
1126: break;
1127: case SB_LINEDOWN:
1128: ptsScrollPos.x += ptsScrollLine.x;
1129: break;
1130: case SB_SLIDERTRACK:
1131: case SB_SLIDERPOSITION:
1132: for( fDone = FALSE; !fDone ;)
1133: {
1134: if( WinPeekMsg( habAsync
1135: , &qmsgPeek
1136: , NULL
1137: , UM_HSCROLL
1138: , UM_HSCROLL
1139: , PM_NOREMOVE))
1140: if( (SHORT2FROMMP( qmsgPeek.mp1) == SB_SLIDERTRACK)
1141: ||(SHORT2FROMMP( qmsgPeek.mp1) == SB_SLIDERPOSITION) )
1142: WinPeekMsg( habAsync
1143: , &qmsgAsync
1144: , NULL
1145: , UM_HSCROLL
1146: , UM_HSCROLL
1147: , PM_REMOVE);
1148: else
1149: fDone = TRUE;
1150: else
1151: fDone = TRUE;
1152: }
1153: ptsScrollPos.x = SHORT1FROMMP( qmsgAsync.mp1);
1154: break;
1155: case SB_PAGEUP:
1156: ptsScrollPos.x -= ptsScrollPage.x;
1157: break;
1158: case SB_PAGEDOWN:
1159: ptsScrollPos.x += ptsScrollPage.x;
1160: break;
1161: case SB_ENDSCROLL:
1162: break;
1163: default:
1164: break;
1165: }
1166: DoHorzScroll();
1167: break;
1168:
1169: case UM_VSCROLL:
1170: switch( SHORT2FROMMP( qmsgAsync.mp1) )
1171: {
1172: case SB_LINEUP:
1173: ptsScrollPos.y -= ptsScrollLine.y;
1174: break;
1175: case SB_LINEDOWN:
1176: ptsScrollPos.y += ptsScrollLine.y;
1177: break;
1178: case SB_SLIDERTRACK:
1179: case SB_SLIDERPOSITION:
1180: for( fDone = FALSE; !fDone ;)
1181: {
1182: if( WinPeekMsg( habAsync
1183: , &qmsgPeek
1184: , NULL
1185: , UM_VSCROLL
1186: , UM_VSCROLL
1187: , PM_NOREMOVE))
1188: if( (SHORT2FROMMP( qmsgPeek.mp1) == SB_SLIDERTRACK)
1189: ||(SHORT2FROMMP( qmsgPeek.mp1) == SB_SLIDERPOSITION) )
1190: WinPeekMsg( habAsync
1191: , &qmsgAsync
1192: , NULL
1193: , UM_VSCROLL
1194: , UM_VSCROLL
1195: , PM_REMOVE);
1196: else
1197: fDone = TRUE;
1198: else
1199: fDone = TRUE;
1200: }
1201: ptsScrollPos.y = SHORT1FROMMP( qmsgAsync.mp1);
1202: break;
1203: case SB_PAGEUP:
1204: ptsScrollPos.y -= ptsScrollPage.y;
1205: break;
1206: case SB_PAGEDOWN:
1207: ptsScrollPos.y += ptsScrollPage.y;
1208: break;
1209: case SB_ENDSCROLL:
1210: break;
1211: default:
1212: break;
1213: }
1214: DoVertScroll();
1215: break;
1216:
1217: /************************************************************************/
1218: /* recalc the picture transform */
1219: /************************************************************************/
1220: case UM_SIZING:
1221: CalcBounds();
1222: CalcTransform( hwndClient);
1223: break;
1224:
1225: /************************************************************************/
1226: /* adjust zoom factor */
1227: /************************************************************************/
1228: case UM_ZOOM_IN:
1229: Zoom( ZOOM_IN_ARG);
1230: break;
1231:
1232: case UM_ZOOM_OUT:
1233: Zoom( ZOOM_OUT_ARG);
1234: break;
1235:
1236: /************************************************************************/
1237: /* toggle fast-drag */
1238: /************************************************************************/
1239: case UM_FASTDRAG:
1240: ToggleFastDrag();
1241: break;
1242:
1243: /************************************************************************/
1244: /* Button down will cause a correlate on the picture to test for a hit. */
1245: /* Any selected segment will be highlighted and redrawn as dynamic. */
1246: /************************************************************************/
1247: case UM_LEFTDOWN:
1248: LeftDown( qmsgAsync.mp1);
1249: break;
1250:
1251: /************************************************************************/
1252: /* if a segment is being dragged it will be redrawn in a new posn */
1253: /************************************************************************/
1254: case UM_MOUSEMOVE:
1255: for( fDone = FALSE; !fDone ;)
1256: {
1257: if( WinPeekMsg( habAsync
1258: , &qmsgPeek
1259: , NULL
1260: , UM_MOUSEMOVE
1261: , UM_LEFTUP
1262: , PM_NOREMOVE))
1263: if( qmsgPeek.msg == UM_MOUSEMOVE)
1264: WinPeekMsg( habAsync
1265: , &qmsgAsync
1266: , NULL
1267: , UM_MOUSEMOVE
1268: , UM_MOUSEMOVE
1269: , PM_REMOVE);
1270: else
1271: fDone = TRUE;
1272: else
1273: fDone = TRUE;
1274: }
1275: MouseMove( qmsgAsync.mp1);
1276: break;
1277:
1278: /************************************************************************/
1279: /* if a segment is being dragged it will be redrawn as normal */
1280: /************************************************************************/
1281: case UM_LEFTUP:
1282: LeftUp();
1283: break;
1284:
1285: /************************************************************************/
1286: /* destroy resources and terminate */
1287: /************************************************************************/
1288: case UM_DIE:
1289: WinDestroyMsgQueue( hmqAsync);
1290: WinTerminate( habAsync);
1291: DosEnterCritSec();
1292: DosSemClear( hsemTerminate);
1293: DosExit( EXIT_THREAD, 0);
1294: break;
1295:
1296: /************************************************************************/
1297: /* finish flush of commands from queue */
1298: /************************************************************************/
1299: case UM_FLUSH:
1300: break;
1301:
1302: default:
1303: break;
1304: }
1305: }
1306: }
1307:
1308: /******************************************************************************/
1309: /* button down will cause one segment to be indicated and made dynamic */
1310: /******************************************************************************/
1311: VOID
1312: LeftDown( mp)
1313:
1314: MPARAM mp;
1315: {
1316: HRGN hrgnUpdt;
1317: LONG alSegTag[HITS][DEPTH][2];
1318: POINTL ptl, aptl[4];
1319: RECTL rcl;
1320: MATRIXLF matlf;
1321: LONG lOffset;
1322: BYTE bBuff[128];
1323: CHAR pszMsg[40];
1324: PSZ psz1, psz2;
1325:
1326: ptl.x = (LONG)(SHORT)SHORT1FROMMP( mp);
1327: ptl.y = (LONG)(SHORT)SHORT2FROMMP( mp);
1328:
1329: /****************************************************************************/
1330: /****************************************************************************/
1331: for( pslPicked = pslTail; pslPicked != NULL; pslPicked = pslPicked->pslPrev)
1332: {
1333: rcl = pslPicked->rclCurrent;
1334: GpiConvert( hpsClient, CVTC_MODEL, CVTC_DEVICE, 2L, (PPOINTL)&rcl);
1335: rcl.xRight++;
1336: rcl.yTop++;
1337: if( WinPtInRect( habAsync, &rcl, &ptl))
1338: {
1339: LONG lRet;
1340:
1341: GpiSetEditMode( hpsClient, SEGEM_INSERT);
1342: GpiOpenSegment( hpsClient, pslPicked->lSegId);
1343: GpiSetElementPointerAtLabel( hpsClient, FILLPATH);
1344: GpiFillPath( hpsClient, 1L, 0L);
1345: GpiCloseSegment( hpsClient);
1346: lRet = GpiCorrelateSegment( hpsClient
1347: , pslPicked->lSegId
1348: , PICKSEL_VISIBLE
1349: , &ptl
1350: , HITS
1351: , DEPTH
1352: , (PLONG)alSegTag );
1353: GpiOpenSegment( hpsClient, pslPicked->lSegId);
1354: GpiSetElementPointerAtLabel( hpsClient, FILLPATH);
1355: GpiOffsetElementPointer( hpsClient, 1L);
1356: GpiDeleteElement( hpsClient);
1357: GpiCloseSegment( hpsClient);
1358:
1359: if( lRet > 0)
1360: break;
1361: }
1362: }
1363: if( pslPicked)
1364: lPickedSeg = pslPicked->lSegId;
1365: else
1366: {
1367: fButtonDown = FALSE;
1368: return;
1369: }
1370: if( (lPickedSeg < 1) || (lPickedSeg > lLastSegId) )
1371: {
1372: DosSemRequest( hsemSzFmt, SEM_INDEFINITE_WAIT);
1373: sprintf( szFmt, "Segment id out of range: %x", lPickedSeg);
1374: for( psz1 = szFmt, psz2 = pszMsg; *psz2++ = *psz1++; )
1375: ;
1376: DosSemClear( hsemSzFmt);
1377: MyMessageBox( hwndClient, pszMsg);
1378: fButtonDown = FALSE;
1379: return;
1380: }
1381:
1382: /****************************************************************************/
1383: hrgnUpdt = GpiCreateRegion( hpsClient, 1L, &rcl);
1384: GpiSetSegmentAttrs( hpsClient, lPickedSeg, ATTR_VISIBLE, ATTR_OFF);
1385:
1386: GpiQuerySegmentTransformMatrix( hpsClient
1387: , lPickedSeg
1388: , 9L
1389: , &matlf );
1390: GpiBeginPath( hpsClient, 1L);
1391: GpiCallSegmentMatrix( hpsClient
1392: , lPickedSeg + CALLSEG_BASE
1393: , 9L
1394: , &matlf
1395: , TRANSFORM_REPLACE );
1396: GpiEndPath( hpsClient);
1397: GpiSetClipPath( hpsClient, 1L, SCP_AND);
1398: DoDraw( hrgnUpdt);
1399: GpiSetClipPath( hpsClient, 0L, SCP_RESET);
1400: GpiDestroyRegion( hpsClient, hrgnUpdt);
1401:
1402: /****************************************************************************/
1403: ptlOffset = ptlBotLeft;
1404: GpiConvert( hpsClient, CVTC_WORLD, CVTC_DEVICE, 1L, &ptlOffset);
1405:
1406: aptl[0].x = pslPicked->rclBitBlt.xLeft;
1407: aptl[0].y = pslPicked->rclBitBlt.yBottom;
1408: aptl[1].x = pslPicked->rclBitBlt.xRight;
1409: aptl[1].y = pslPicked->rclBitBlt.yTop;
1410: aptl[2] = aptl[0];
1411: aptl[3] = aptl[1];
1412: GpiConvert( hpsClient, CVTC_WORLD, CVTC_DEVICE, 2L, &aptl[2]);
1413: aptl[2].x -= ptlOffset.x;
1414: aptl[2].y -= ptlOffset.y;
1415: aptl[3].x -= ptlOffset.x - 1;
1416: aptl[3].y -= ptlOffset.y - 1;
1417: GpiSetEditMode( hpsClient, SEGEM_INSERT);
1418:
1419: for( lOffset = 0L; GpiGetData( hpsClient
1420: , lPickedSeg
1421: , &lOffset
1422: , DFORM_NOCONV
1423: , (LONG)sizeof( bBuff)
1424: , bBuff) > 0; )
1425: ;
1426:
1427: GpiOpenSegment( hpsClient, lPickedSeg);
1428: GpiDeleteElementsBetweenLabels( hpsClient, BITBLT_TOP, BITBLT_BOTTOM);
1429: if( !fFastDrag)
1430: GpiWCBitBlt( hpsClient
1431: , hbmBitmapDrag
1432: , 4L
1433: , aptl
1434: , ROP_SRCCOPY
1435: , BBO_IGNORE );
1436: GpiCloseSegment( hpsClient);
1437:
1438: for( lOffset = 0L; GpiGetData( hpsClient
1439: , lPickedSeg
1440: , &lOffset
1441: , DFORM_NOCONV
1442: , (LONG)sizeof( bBuff)
1443: , bBuff) > 0; )
1444: ;
1445:
1446: /****************************************************************************/
1447: GpiSetSegmentAttrs( hpsClient, lPickedSeg, ATTR_VISIBLE, ATTR_ON);
1448: GpiSetSegmentAttrs( hpsClient, lPickedSeg, ATTR_DYNAMIC, ATTR_ON);
1449: GpiSetDrawControl( hpsClient, DCTL_DYNAMIC, DCTL_ON);
1450: GpiDrawSegment( hpsClient, lPickedSeg);
1451:
1452: WinSetCapture( HWND_DESKTOP, hwndClient);
1453: }
1454:
1455:
1456:
1457:
1458: /******************************************************************************/
1459: /* */
1460: /* move the segment */
1461: /* */
1462: /******************************************************************************/
1463: VOID
1464: MouseMove( mp)
1465:
1466: MPARAM mp;
1467: {
1468: RECTL rcl;
1469: POINTL ptl, ptlModel;
1470:
1471: ptl.x = (LONG)(SHORT)SHORT1FROMMP( mp);
1472: ptl.y = (LONG)(SHORT)SHORT2FROMMP( mp);
1473:
1474: ptlModel = ptl;
1475: GpiConvert( hpsClient, CVTC_DEVICE, CVTC_MODEL, 1L, &ptlModel);
1476: ptlModel.x = 5 * (ptlModel.x / 5);
1477: ptlModel.y = 5 * (ptlModel.y / 5);
1478: if( (ptlModel.x == ptlOldMouse.x) && (ptlModel.y == ptlOldMouse.y))
1479: return;
1480: ptlOldMouse.x = ptlModel.x;
1481: ptlOldMouse.y = ptlModel.y;
1482:
1483: /****************************************************************************/
1484: /* clip mouse coords to client window */
1485: /****************************************************************************/
1486: WinQueryWindowRect(hwndClient, &rcl);
1487: if (rcl.xLeft > ptl.x)
1488: ptl.x = rcl.xLeft;
1489: if (rcl.xRight <= ptl.x)
1490: ptl.x = rcl.xRight;
1491: if (rcl.yBottom > ptl.y)
1492: ptl.y = rcl.yBottom;
1493: if (rcl.yTop <= ptl.y)
1494: ptl.y = rcl.yTop;
1495:
1496: GpiRemoveDynamics( hpsClient, lPickedSeg, lPickedSeg);
1497: Translate( pslPicked, &ptl);
1498: GpiDrawDynamics( hpsClient);
1499: }
1500:
1501:
1502: /******************************************************************************/
1503: /* */
1504: /* The dragged segment is being unselected. Return it to its normal state. */
1505: /* */
1506: /******************************************************************************/
1507: VOID
1508: LeftUp()
1509: {
1510: SEGLIST sl;
1511: POINTL aptl[4];
1512:
1513: if( !lPickedSeg)
1514: return;
1515: GpiRemoveDynamics( hpsClient, lPickedSeg, lPickedSeg);
1516: GpiSetSegmentAttrs( hpsClient, lPickedSeg, ATTR_DYNAMIC, ATTR_OFF);
1517:
1518: /****************************************************************************/
1519: ptlOffset = ptlBotLeft;
1520: GpiConvert( hpsClient, CVTC_WORLD, CVTC_DEVICE, 1L, &ptlOffset);
1521:
1522: aptl[0].x = pslPicked->rclBitBlt.xLeft;
1523: aptl[0].y = pslPicked->rclBitBlt.yBottom;
1524: aptl[1].x = pslPicked->rclBitBlt.xRight;
1525: aptl[1].y = pslPicked->rclBitBlt.yTop;
1526: aptl[2] = aptl[0];
1527: aptl[3] = aptl[1];
1528: GpiConvert( hpsClient, CVTC_WORLD, CVTC_DEVICE, 2L, &aptl[2]);
1529: aptl[2].x -= ptlOffset.x;
1530: aptl[2].y -= ptlOffset.y;
1531: aptl[3].x -= ptlOffset.x - 1;
1532: aptl[3].y -= ptlOffset.y - 1;
1533: GpiSetEditMode( hpsClient, SEGEM_INSERT);
1534: GpiOpenSegment( hpsClient, lPickedSeg);
1535: GpiDeleteElementsBetweenLabels( hpsClient, BITBLT_TOP, BITBLT_BOTTOM);
1536: GpiWCBitBlt( hpsClient
1537: , hbmBitmapTemp
1538: , 4L
1539: , aptl
1540: , ROP_SRCCOPY
1541: , BBO_IGNORE );
1542: GpiCloseSegment( hpsClient);
1543:
1544: /****************************************************************************/
1545: GpiDrawSegment( hpsClient, lPickedSeg);
1546: GpiSetSegmentPriority( hpsClient, lPickedSeg, 0L, LOWER_PRI); /* highest */
1547: SetRect( pslPicked);
1548:
1549: sl = *pslPicked;
1550: SegListUpdate( DEL_SEG, pslPicked);
1551: SegListUpdate( ADD_TAIL_SEG, &sl); /* at tail => highest priority */
1552: pslPicked = NULL;
1553:
1554: WinSetCapture( HWND_DESKTOP, (HWND)NULL);
1555: }
1556:
1557:
1558: /******************************************************************************/
1559: /* */
1560: /* DoHorzScroll will horizontally scroll the current contents of */
1561: /* the client area and redraw the invalidated area */
1562: /* */
1563: /******************************************************************************/
1564: VOID
1565: DoHorzScroll()
1566: {
1567: RECTL rcl;
1568: HRGN hrgn;
1569: MATRIXLF matlf;
1570:
1571: if( ptsScrollPos.x > ptsScrollMax.x)
1572: ptsScrollPos.x = ptsScrollMax.x;
1573: if( ptsScrollPos.x < 0)
1574: ptsScrollPos.x = 0;
1575:
1576: if( ptsOldScrollPos.x != ptsScrollPos.x)
1577: WinSendMsg( hwndHorzScroll
1578: , SBM_SETPOS
1579: , MPFROM2SHORT( ptsScrollPos.x, 0)
1580: , MPFROMLONG( NULL));
1581:
1582: /****************************************************************************/
1583: /* Scroll the window the reqd amount, using bitblt'ing (ScrollWindow) */
1584: /* if any of the screen still in view, and paint into uncovered region; */
1585: /* else repaint the whole client area. */
1586: /****************************************************************************/
1587: hrgn = GpiCreateRegion( hpsClient, 0L, NULL);
1588: if( abs( ptsScrollPos.x - ptsOldScrollPos.x) <= ptsScrollMax.x)
1589: {
1590: WinScrollWindow( hwndClient
1591: , ptsOldScrollPos.x - ptsScrollPos.x
1592: , 0
1593: , NULL
1594: , NULL
1595: , hrgn
1596: , &rcl
1597: , 0);
1598: } else
1599: {
1600: WinQueryWindowRect( hwndClient, &rcl);
1601: GpiSetRegion( hpsClient, hrgn, 1L, &rcl);
1602: }
1603: GpiQueryDefaultViewMatrix( hpsClient, 9L, &matlf );
1604: matlf.lM31 -= ptsScrollPos.x - ptsOldScrollPos.x;
1605: GpiSetDefaultViewMatrix( hpsClient, 9L, &matlf, TRANSFORM_REPLACE);
1606:
1607: DoDraw( hrgn);
1608: ptsOldScrollPos.x = ptsScrollPos.x;
1609: GpiDestroyRegion( hpsClient, hrgn);
1610: }
1611:
1612: /******************************************************************************/
1613: /* */
1614: /* DoVertScroll will vertically scroll the current contents of */
1615: /* the client area and redraw the invalidated area */
1616: /* */
1617: /******************************************************************************/
1618: VOID
1619: DoVertScroll()
1620: {
1621: RECTL rcl;
1622: HRGN hrgn;
1623: MATRIXLF matlf;
1624:
1625: if( ptsScrollPos.y > ptsScrollMax.y)
1626: ptsScrollPos.y = ptsScrollMax.y;
1627: if( ptsScrollPos.y < 0)
1628: ptsScrollPos.y = 0;
1629:
1630: if( ptsOldScrollPos.y != ptsScrollPos.y)
1631: WinSendMsg( hwndVertScroll
1632: , SBM_SETPOS
1633: , MPFROM2SHORT( ptsScrollPos.y, 0)
1634: , MPFROMLONG( NULL));
1635:
1636: /****************************************************************************/
1637: /* Scroll the window the reqd amount, using bitblt'ing (ScrollWindow) */
1638: /* if any of the screen still in view, and paint into uncovered region; */
1639: /* else repaint the whole client area. */
1640: /****************************************************************************/
1641: hrgn = GpiCreateRegion( hpsClient, 0L, NULL);
1642: if( abs( ptsScrollPos.y - ptsOldScrollPos.y) <= ptsScrollMax.y)
1643: {
1644: WinScrollWindow( hwndClient
1645: , 0
1646: , ptsScrollPos.y - ptsOldScrollPos.y
1647: , NULL
1648: , NULL
1649: , hrgn
1650: , &rcl
1651: , 0);
1652: } else
1653: {
1654: WinQueryWindowRect( hwndClient, &rcl);
1655: GpiSetRegion( hpsClient, hrgn, 1L, &rcl);
1656: }
1657: GpiQueryDefaultViewMatrix( hpsClient, 9L, &matlf );
1658: matlf.lM32 += ptsScrollPos.y - ptsOldScrollPos.y;
1659: GpiSetDefaultViewMatrix( hpsClient, 9L, &matlf, TRANSFORM_REPLACE);
1660:
1661: DoDraw( hrgn);
1662: ptsOldScrollPos.y = ptsScrollPos.y;
1663: GpiDestroyRegion( hpsClient, hrgn);
1664: }
1665:
1666: /******************************************************************************/
1667: /* */
1668: /* Redraw the entire client window. */
1669: /* */
1670: /******************************************************************************/
1671: VOID
1672: Redraw()
1673: {
1674: RECTL rclInvalid;
1675: HRGN hrgnUpdt;
1676:
1677: WinQueryWindowRect( hwndClient, &rclInvalid);
1678: hrgnUpdt = GpiCreateRegion( hpsClient, 1L, &rclInvalid);
1679: DoDraw( hrgnUpdt);
1680: GpiDestroyRegion( hpsClient, hrgnUpdt);
1681: }
1682:
1683:
1684: /******************************************************************************/
1685: /* */
1686: /* toggle the fast-drag flag and update the menu check-box */
1687: /* */
1688: /******************************************************************************/
1689: VOID
1690: ToggleFastDrag()
1691: {
1692: MENUITEM mi;
1693: HWND hwndMenu, hwndOptions;
1694:
1695: hwndMenu = WinWindowFromID( hwndFrame, FID_MENU);
1696: WinSendMsg( hwndMenu
1697: , MM_QUERYITEM
1698: , MPFROM2SHORT( SM_OPTIONS, FALSE)
1699: , MPFROMP( (PMENUITEM)&mi));
1700: hwndOptions = mi.hwndSubMenu;
1701:
1702: if( fFastDrag)
1703: {
1704: fFastDrag = FALSE;
1705: WinSendMsg( hwndOptions
1706: , MM_SETITEMATTR
1707: , MPFROM2SHORT( MENU_FASTDRAG, TRUE)
1708: , MPFROM2SHORT( MIA_CHECKED, ~MIA_CHECKED) );
1709: }
1710: else
1711: {
1712: fFastDrag = TRUE;
1713: WinSendMsg( hwndOptions
1714: , MM_SETITEMATTR
1715: , MPFROM2SHORT( MENU_FASTDRAG, TRUE)
1716: , MPFROM2SHORT( MIA_CHECKED, MIA_CHECKED) );
1717: }
1718: }
1719:
1720: /******************************************************************************/
1721: /* */
1722: /* adjust zoom factor and recalc the picture transform, then do a redraw of */
1723: /* whole screen */
1724: /* */
1725: /******************************************************************************/
1726: VOID
1727: Zoom( sInOrOut)
1728:
1729: SHORT sInOrOut;
1730: {
1731: LONG lScaleOld;
1732:
1733: lScaleOld = lScale;
1734: lScale += sInOrOut;
1735: if( lScale > ZOOM_MAX)
1736: lScale = ZOOM_MAX;
1737: else
1738: if( lScale < -ZOOM_MAX)
1739: lScale = -ZOOM_MAX;
1740: if( lScale != lScaleOld)
1741: {
1742: ZoomMenuItems();
1743: CalcBounds();
1744: CalcTransform( hwndClient);
1745: Redraw();
1746: }
1747: }
1748:
1749: /******************************************************************************/
1750: /* */
1751: /* enable/disable zoom menu items depending on scaling */
1752: /* */
1753: /******************************************************************************/
1754: VOID
1755: ZoomMenuItems()
1756: {
1757: MENUITEM mi;
1758: HWND hwndMenu, hwndOptions;
1759:
1760: hwndMenu = WinWindowFromID( hwndFrame, FID_MENU);
1761: WinSendMsg( hwndMenu
1762: , MM_QUERYITEM
1763: , MPFROM2SHORT( SM_OPTIONS, FALSE)
1764: , MPFROMP( (PMENUITEM)&mi));
1765: hwndOptions = mi.hwndSubMenu;
1766:
1767: if( lScale >= ZOOM_MAX)
1768: {
1769: WinSendMsg( hwndOptions
1770: , MM_SETITEMATTR
1771: , MPFROM2SHORT( MENU_ZOOMIN, TRUE)
1772: , MPFROM2SHORT( MIA_DISABLED, MIA_DISABLED));
1773: WinSendMsg( hwndOptions
1774: , MM_SETITEMATTR
1775: , MPFROM2SHORT( MENU_ZOOMOUT, TRUE)
1776: , MPFROM2SHORT( MIA_DISABLED, ~MIA_DISABLED));
1777: } else
1778: {
1779: if( lScale <= - ZOOM_MAX)
1780: {
1781: WinSendMsg( hwndOptions
1782: , MM_SETITEMATTR
1783: , MPFROM2SHORT( MENU_ZOOMOUT, TRUE)
1784: , MPFROM2SHORT( MIA_DISABLED, MIA_DISABLED));
1785: WinSendMsg( hwndOptions
1786: , MM_SETITEMATTR
1787: , MPFROM2SHORT( MENU_ZOOMIN, TRUE)
1788: , MPFROM2SHORT( MIA_DISABLED, ~MIA_DISABLED));
1789: } else
1790: {
1791: WinSendMsg( hwndOptions
1792: , MM_SETITEMATTR
1793: , MPFROM2SHORT( MENU_ZOOMOUT, TRUE)
1794: , MPFROM2SHORT( MIA_DISABLED, ~MIA_DISABLED));
1795: WinSendMsg( hwndOptions
1796: , MM_SETITEMATTR
1797: , MPFROM2SHORT( MENU_ZOOMIN, TRUE)
1798: , MPFROM2SHORT( MIA_DISABLED, ~MIA_DISABLED));
1799: }
1800: }
1801: }
1802:
1803: /******************************************************************************/
1804: /* */
1805: /* Determine the bounding rect of a segment. */
1806: /* */
1807: /******************************************************************************/
1808: VOID
1809: SetRect( psl)
1810:
1811: PSEGLIST psl;
1812: {
1813: GpiResetBoundaryData( hpsClient);
1814: GpiSetDrawControl( hpsClient, DCTL_DISPLAY, DCTL_OFF);
1815: GpiSetDrawControl( hpsClient, DCTL_BOUNDARY, DCTL_ON);
1816: GpiDrawSegment( hpsClient, psl->lSegId);
1817: GpiSetDrawControl( hpsClient, DCTL_DISPLAY, DCTL_ON);
1818: GpiSetDrawControl( hpsClient, DCTL_BOUNDARY, DCTL_OFF);
1819: GpiQueryBoundaryData( hpsClient, &(psl->rclCurrent));
1820: }
1821:
1822: /******************************************************************************/
1823: /* */
1824: /* Translate a segment */
1825: /* */
1826: /******************************************************************************/
1827: VOID
1828: Translate( psl, pptlNew)
1829:
1830: PSEGLIST psl;
1831: PPOINTL pptlNew;
1832: {
1833: POINTL ptl;
1834: MATRIXLF matlf;
1835:
1836: ptl = *pptlNew;
1837: GpiConvert( hpsClient, CVTC_DEVICE, CVTC_MODEL, 1L, &ptl);
1838: ptl.x = (ptl.x / 5) * 5;
1839: ptl.y = (ptl.y / 5) * 5;
1840: ptl.x -= 25;
1841: ptl.y -= 25;
1842:
1843: GpiQuerySegmentTransformMatrix( hpsClient
1844: , psl->lSegId
1845: , 9L
1846: , &matlf);
1847: matlf.lM31 = ptl.x - (psl->ptlLocation).x;
1848: matlf.lM32 = ptl.y - (psl->ptlLocation).y;
1849: GpiSetSegmentTransformMatrix( hpsClient
1850: , psl->lSegId
1851: , 9L
1852: , &matlf
1853: , TRANSFORM_REPLACE);
1854: }
1855:
1856:
1857: /******************************************************************************/
1858: /* */
1859: /* set the default viewing transform */
1860: /* */
1861: /******************************************************************************/
1862: VOID
1863: SetDVTransform( fx11, fx12, fx21, fx22, l31, l32, lType)
1864:
1865: FIXED fx11, fx12, fx21, fx22;
1866: LONG l31, l32, lType;
1867: {
1868: MATRIXLF matlf;
1869:
1870: matlf.fxM11 = fx11;
1871: matlf.fxM12 = fx12;
1872: matlf.lM13 = 0L;
1873: matlf.fxM21 = fx21;
1874: matlf.fxM22 = fx22;
1875: matlf.lM23 = 0L;
1876: matlf.lM31 = l31;
1877: matlf.lM32 = l32;
1878: matlf.lM33 = 1L;
1879: GpiSetDefaultViewMatrix( hpsClient, 9L, &matlf, lType);
1880: }
1881:
1882: /******************************************************************************/
1883: /* */
1884: /* get bounding rect of whole picture in model coordinates */
1885: /* */
1886: /******************************************************************************/
1887: VOID
1888: CalcBounds()
1889: {
1890: PSEGLIST psl;
1891: RECTL rcl;
1892:
1893: if( !pslHead)
1894: return;
1895: rclBounds = pslHead->rclCurrent;
1896: for( psl = pslHead->pslNext; psl != NULL; psl = psl->pslNext)
1897: {
1898: rcl = psl->rclCurrent;
1899: if( rcl.xLeft < rclBounds.xLeft)
1900: rclBounds.xLeft = rcl.xLeft;
1901: if( rcl.xRight > rclBounds.xRight)
1902: rclBounds.xRight = rcl.xRight;
1903: if( rcl.yTop > rclBounds.yTop)
1904: rclBounds.yTop = rcl.yTop;
1905: if( rcl.yBottom < rclBounds.yBottom)
1906: rclBounds.yBottom = rcl.yBottom;
1907: }
1908: }
1909:
1910: /******************************************************************************/
1911: /* */
1912: /* Calculate and set the default viewing transform based on zoom and scroll */
1913: /* */
1914: /******************************************************************************/
1915: VOID
1916: CalcTransform( hwnd)
1917:
1918: HWND hwnd;
1919: {
1920: RECTL rclClient;
1921: POINTL ptlCenter, ptlTrans, ptlScale, aptl[4];
1922: HRGN hrgn;
1923: PSEGLIST psl;
1924:
1925: /****************************************************************************/
1926: /* from bounding rect of picture get center of picture */
1927: /****************************************************************************/
1928: ptlCenter.x = (rclBounds.xLeft + rclBounds.xRight) / 2;
1929: ptlCenter.y = (rclBounds.yBottom + rclBounds.yTop ) / 2;
1930:
1931: /****************************************************************************/
1932: /* translate center of picture to origin */
1933: /****************************************************************************/
1934: SetDVTransform( (FIXED)UNITY
1935: , (FIXED)0
1936: , (FIXED)0
1937: , (FIXED)UNITY
1938: , -ptlCenter.x
1939: , -ptlCenter.y
1940: , TRANSFORM_REPLACE);
1941:
1942: /****************************************************************************/
1943: /* scale down to 60% of max client area */
1944: /****************************************************************************/
1945: ptlScale.x = (6 * UNITY * sizlMaxClient.cx) /
1946: (10 * (ptlTopRight.x - ptlBotLeft.x));
1947: ptlScale.y = (6 * UNITY * sizlMaxClient.cy) /
1948: (10 * (ptlTopRight.y - ptlBotLeft.y));
1949:
1950: /****************************************************************************/
1951: /* add in zoom scale */
1952: /****************************************************************************/
1953: ptlScale.x += ptlScale.x * lScale / (ZOOM_MAX + 1);
1954: ptlScale.y += ptlScale.y * lScale / (ZOOM_MAX + 1);
1955:
1956: SetDVTransform( (FIXED)ptlScale.x
1957: , (FIXED)0
1958: , (FIXED)0
1959: , (FIXED)ptlScale.y
1960: , 0L
1961: , 0L
1962: , TRANSFORM_ADD);
1963:
1964: /****************************************************************************/
1965: /* translate center of picture to center of client window */
1966: /****************************************************************************/
1967: WinQueryWindowRect( hwnd, &rclClient);
1968: ptlTrans.x = (rclClient.xRight - rclClient.xLeft) / 2;
1969: ptlTrans.y = (rclClient.yTop - rclClient.yBottom) / 2;
1970:
1971: /****************************************************************************/
1972: /* add in horizontal and vertical scrolling factors */
1973: /****************************************************************************/
1974: ptlTrans.x += ptsScrollPos.x - ptsHalfScrollMax.x;
1975: ptlTrans.y += ptsScrollPos.y - ptsHalfScrollMax.y;
1976: SetDVTransform( (FIXED)UNITY
1977: , (FIXED)0
1978: , (FIXED)0
1979: , (FIXED)UNITY
1980: , ptlTrans.x
1981: , ptlTrans.y
1982: , TRANSFORM_ADD);
1983:
1984: /****************************************************************************/
1985: /* create a shadow bitmap of the original, sized to the current output size */
1986: /****************************************************************************/
1987: aptl[0] = ptlBotLeft;
1988: aptl[1] = ptlTopRight;
1989: GpiConvert( hpsClient, CVTC_WORLD, CVTC_DEVICE, 2L, aptl);
1990: ptlOffset = aptl[0];
1991:
1992: aptl[0].x -= ptlOffset.x;
1993: aptl[0].y -= ptlOffset.y;
1994: aptl[1].x -= ptlOffset.x - 1;
1995: aptl[1].y -= ptlOffset.y - 1;
1996: aptl[2].x = 0L;
1997: aptl[2].y = 0L;
1998: aptl[3].x = bmpBitmapFile.cx;
1999: aptl[3].y = bmpBitmapFile.cy;
2000: GpiSetBitmap( hpsBitmapTemp, hbmBitmapTemp);
2001: GpiBitBlt( hpsBitmapTemp
2002: , hpsBitmapFile
2003: , 4L
2004: , aptl
2005: , ROP_SRCCOPY
2006: , BBO_IGNORE);
2007: GpiSetBitmap( hpsBitmapTemp, NULL);
2008:
2009: /****************************************************************************/
2010: /* create a copy of the shadow bitmap, adjusted to appear normal when */
2011: /* bitblt'd in XOR mode onto a CLR_BACKGROUND background (dynamic segment) */
2012: /****************************************************************************/
2013: GpiSetBitmap( hpsBitmapDrag, hbmBitmapDrag);
2014: GpiSetColor( hpsBitmapDrag, CLR_BACKGROUND);
2015: hrgn = GpiCreateRegion( hpsBitmapDrag, 1L, (PRECTL)aptl);
2016: GpiPaintRegion( hpsBitmapDrag, hrgn);
2017: GpiDestroyRegion( hpsBitmapDrag, hrgn);
2018: GpiBitBlt( hpsBitmapDrag
2019: , hpsBitmapFile
2020: , 4L
2021: , aptl
2022: , ROP_SRCINVERT
2023: , BBO_IGNORE);
2024: GpiSetBitmap( hpsBitmapDrag, NULL);
2025:
2026: for( psl = pslHead; psl != NULL; psl = psl->pslNext)
2027: {
2028: aptl[0].x = psl->rclBitBlt.xLeft;
2029: aptl[0].y = psl->rclBitBlt.yBottom;
2030: aptl[1].x = psl->rclBitBlt.xRight;
2031: aptl[1].y = psl->rclBitBlt.yTop;
2032: aptl[2] = aptl[0];
2033: aptl[3] = aptl[1];
2034: GpiConvert( hpsClient, CVTC_WORLD, CVTC_DEVICE, 2L, &aptl[2]);
2035: aptl[2].x -= ptlOffset.x;
2036: aptl[2].y -= ptlOffset.y;
2037: aptl[3].x -= ptlOffset.x - 1;
2038: aptl[3].y -= ptlOffset.y - 1;
2039: GpiSetEditMode( hpsClient, SEGEM_INSERT);
2040: GpiOpenSegment( hpsClient, psl->lSegId);
2041: GpiDeleteElementsBetweenLabels( hpsClient, BITBLT_TOP, BITBLT_BOTTOM);
2042: GpiWCBitBlt( hpsClient
2043: , hbmBitmapTemp
2044: , 4L
2045: , aptl
2046: , ROP_SRCCOPY
2047: , BBO_IGNORE );
2048: GpiCloseSegment( hpsClient);
2049: }
2050: }
2051:
2052:
2053: /******************************************************************************/
2054: /* */
2055: /* Draw the picture, using the passed region for clipping. */
2056: /* Test each segment to see if its bounding box intersects the bounding box */
2057: /* of the clipping region. Draw only if there is an intersection. */
2058: /* */
2059: /******************************************************************************/
2060: BOOL
2061: DoDraw( hrgn)
2062:
2063: HRGN hrgn;
2064: {
2065: HRGN hrgnOld;
2066: RECTL rcl, rclRegion, rclDst;
2067: PSEGLIST psl;
2068:
2069: GpiSetColor( hpsClient, CLR_BACKGROUND);
2070: GpiPaintRegion( hpsClient, hrgn);
2071:
2072: GpiQueryRegionBox( hpsClient, hrgn, &rclRegion);
2073: GpiSetClipRegion( hpsClient, hrgn, &hrgnOld);
2074: for( psl = pslHead; psl != NULL; psl = psl->pslNext)
2075: {
2076: rcl = psl->rclCurrent;
2077: GpiConvert( hpsClient, CVTC_MODEL, CVTC_DEVICE, 2L, (PPOINTL)&rcl);
2078: rcl.xRight++;
2079: rcl.yTop++;
2080: if( WinIntersectRect( habAsync, &rclDst, &rcl, &rclRegion))
2081: GpiDrawSegment( hpsClient, psl->lSegId);
2082: }
2083: GpiSetClipRegion( hpsClient, NULL, &hrgnOld);
2084:
2085: return( TRUE);
2086: }
2087:
2088: /******************************************************************************/
2089: /* */
2090: /* Return a pointer to a segment list member, based on segment id. */
2091: /* */
2092: /******************************************************************************/
2093: PSEGLIST
2094: SegListGet( lSeg)
2095:
2096: LONG lSeg;
2097: {
2098: PSEGLIST psl;
2099:
2100: for( psl = pslHead; psl != NULL; psl = psl->pslNext)
2101: if( psl->lSegId == lSeg)
2102: return( psl);
2103: return( NULL);
2104: }
2105:
2106: /******************************************************************************/
2107: /* */
2108: /* Check the segment list for obvious errors. */
2109: /* */
2110: /******************************************************************************/
2111: BOOL
2112: SegListCheck( iLoc)
2113:
2114: INT iLoc;
2115: {
2116: PSEGLIST psl;
2117: CHAR pszMsg[50];
2118: PSZ psz1, psz2;
2119:
2120: pszMsg[0] = '\0';
2121: for( psl = pslHead; psl != NULL; psl = psl->pslNext)
2122: if( (psl->lSegId < 1) || (psl->lSegId > lLastSegId) )
2123: {
2124: DosSemRequest( hsemSzFmt, SEM_INDEFINITE_WAIT);
2125: sprintf( szFmt, "Bad head segment list, location %d", iLoc);
2126: for( psz1 = szFmt, psz2 = pszMsg; *psz2++ = *psz1++; )
2127: ;
2128: DosSemClear( hsemSzFmt);
2129: MyMessageBox( hwndClient, pszMsg);
2130: return( FALSE);
2131: }
2132: for( psl = pslTail; psl != NULL; psl = psl->pslPrev)
2133: if( (psl->lSegId < 1) || (psl->lSegId > lLastSegId) )
2134: {
2135: DosSemRequest( hsemSzFmt, SEM_INDEFINITE_WAIT);
2136: sprintf( szFmt, "Bad head segment list, location %d", iLoc);
2137: for( psz1 = szFmt, psz2 = pszMsg; *psz2++ = *psz1++; )
2138: ;
2139: DosSemClear( hsemSzFmt);
2140: MyMessageBox( hwndClient, pszMsg);
2141: return( FALSE);
2142: }
2143: return( TRUE);
2144: }
2145: /******************************************************************************/
2146: /* */
2147: /* Add (at head or tail) or delete a specified segment list member. */
2148: /* */
2149: /******************************************************************************/
2150: BOOL
2151: SegListUpdate( usOperation, pslUpdate)
2152:
2153: USHORT usOperation;
2154: PSEGLIST pslUpdate;
2155: {
2156: PSEGLIST psl;
2157: SEL sel;
2158:
2159: switch( usOperation)
2160: {
2161: case ADD_HEAD_SEG:
2162: DosAllocSeg( sizeof( SEGLIST), &sel, 0);
2163: if( pslHead == NULL)
2164: {
2165: pslHead = MAKEP( sel, 0);
2166: if( pslHead == NULL)
2167: return( FALSE);
2168: *pslHead = *pslUpdate;
2169: pslHead->pslPrev = NULL;
2170: pslHead->pslNext = NULL;
2171: pslTail = pslHead;
2172: } else
2173: {
2174: psl = MAKEP( sel, 0);
2175: if( psl == NULL)
2176: return( FALSE);
2177: *psl = *pslUpdate;
2178: pslHead->pslPrev = psl;
2179: psl->pslNext = pslHead;
2180: psl->pslPrev = NULL;
2181: pslHead = psl;
2182: }
2183: return( TRUE);
2184: break;
2185:
2186: case ADD_TAIL_SEG:
2187: DosAllocSeg( sizeof( SEGLIST), &sel, 0);
2188: if( pslTail == NULL)
2189: {
2190: pslHead = MAKEP( sel, 0);
2191: if( pslHead == NULL)
2192: return( FALSE);
2193: *pslHead = *pslUpdate;
2194: pslHead->pslPrev = NULL;
2195: pslHead->pslNext = NULL;
2196: pslTail = pslHead;
2197: } else
2198: {
2199: psl = MAKEP( sel, 0);
2200: if( psl == NULL)
2201: return( FALSE);
2202: *psl = *pslUpdate;
2203: pslTail->pslNext = psl;
2204: psl->pslPrev = pslTail;
2205: psl->pslNext = NULL;
2206: pslTail = psl;
2207: }
2208: return( TRUE);
2209: break;
2210:
2211: case DEL_SEG:
2212: for( psl = pslHead; psl != NULL; psl = psl->pslNext)
2213: {
2214: if( psl->lSegId == pslUpdate->lSegId)
2215: {
2216: if( psl == pslHead)
2217: {
2218: pslHead = psl->pslNext;
2219: if( pslHead == NULL)
2220: pslTail = NULL;
2221: else
2222: pslHead->pslPrev = NULL;
2223: }else if( psl == pslTail)
2224: {
2225: pslTail = psl->pslPrev;
2226: pslTail->pslNext = NULL;
2227: } else
2228: {
2229: (psl->pslPrev)->pslNext = psl->pslNext;
2230: (psl->pslNext)->pslPrev = psl->pslPrev;
2231: }
2232: DosFreeSeg( SELECTOROF(psl));
2233: return( TRUE);
2234: break;
2235: }
2236: }
2237: return( FALSE);
2238: break;
2239:
2240: default:
2241: return( FALSE);
2242: }
2243: }
2244:
2245:
2246:
2247: /******************************************************************************/
2248: /* */
2249: /* DumpPicture will free the list and segment store for the picture */
2250: /* */
2251: /******************************************************************************/
2252: BOOL
2253: DumpPicture()
2254: {
2255: while( pslHead != NULL )
2256: SegListUpdate( DEL_SEG, pslHead);
2257: GpiDeleteSegments( hpsClient, 1L, CALLSEG_BASE + lLastSegId);
2258: GpiSetBitmap( hpsBitmapFile, NULL);
2259: if( hbmBitmapFile)
2260: GpiDeleteBitmap( hbmBitmapFile);
2261: GpiSetBitmap( hpsBitmapTemp, NULL);
2262: if( hbmBitmapTemp)
2263: GpiDeleteBitmap( hbmBitmapTemp);
2264: GpiSetBitmap( hpsBitmapDrag, NULL);
2265: if( hbmBitmapDrag)
2266: GpiDeleteBitmap( hbmBitmapDrag);
2267:
2268: return( TRUE);
2269: }
2270:
2271: /******************************************************************************/
2272: /* */
2273: /* Draw the picture into segment store. */
2274: /* */
2275: /******************************************************************************/
2276: BOOL
2277: CreatePicture()
2278: {
2279:
2280: POINTL ptl, aptlSides[12], aptlControl[12];
2281: SEGLIST sl;
2282: LONG lCallSegId, l;
2283:
2284: /****************************************************************************/
2285: /* reset the default viewing transform to identity */
2286: /****************************************************************************/
2287: SetDVTransform( (FIXED)UNITY
2288: , (FIXED)0
2289: , (FIXED)0
2290: , (FIXED)UNITY
2291: , 0L
2292: , 0L
2293: , TRANSFORM_REPLACE);
2294:
2295: /****************************************************************************/
2296: /* set to store mode */
2297: /****************************************************************************/
2298: GpiSetDrawingMode( hpsClient, DM_RETAIN);
2299:
2300: /****************************************************************************/
2301: /* chaining and detectability off, fastchaining off */
2302: /****************************************************************************/
2303: GpiSetInitialSegmentAttrs( hpsClient, ATTR_CHAINED, ATTR_OFF);
2304: GpiSetInitialSegmentAttrs( hpsClient, ATTR_DETECTABLE, ATTR_OFF);
2305: GpiSetInitialSegmentAttrs( hpsClient, ATTR_FASTCHAIN, ATTR_OFF);
2306:
2307: /****************************************************************************/
2308: /* draw the pieces */
2309: /****************************************************************************/
2310: lLastSegId = 0;
2311: lCallSegId = CALLSEG_BASE;
2312: for( ptl.x = ptlBotLeft.x; ptl.x < ptlTopRight.x; ptl.x += 50)
2313: {
2314: for( ptl.y = ptlBotLeft.y; ptl.y < ptlTopRight.y; ptl.y += 50)
2315: {
2316: /************************************************************************/
2317: /* compute the piece outline control points */
2318: /************************************************************************/
2319: aptlControl[0].x = 10L;
2320: aptlControl[0].y = 10L;
2321: aptlControl[1].x = 40L;
2322: aptlControl[1].y = -10L;
2323: aptlControl[2].x = 50L;
2324: aptlControl[2].y = 0L;
2325:
2326: aptlControl[3].x = 40L;
2327: aptlControl[3].y = 10L;
2328: aptlControl[4].x = 60L;
2329: aptlControl[4].y = 40L;
2330: aptlControl[5].x = 50L;
2331: aptlControl[5].y = 50L;
2332:
2333: aptlControl[6].x = 40L;
2334: aptlControl[6].y = 40L;
2335: aptlControl[7].x = 10L;
2336: aptlControl[7].y = 60L;
2337: aptlControl[8].x = 0L;
2338: aptlControl[8].y = 50L;
2339:
2340: aptlControl[9].x = 10L;
2341: aptlControl[9].y = 40L;
2342: aptlControl[10].x = -10L;
2343: aptlControl[10].y = 10L;
2344: aptlControl[11].x = 0L;
2345: aptlControl[11].y = 0L;
2346:
2347: if( ptl.y == ptlBotLeft.y)
2348: {
2349: aptlControl[0].y = 0L;
2350: aptlControl[1].y = 0L;
2351: }
2352:
2353: if( (ptl.x + 50) == ptlTopRight.x)
2354: {
2355: aptlControl[3].x = 50L;
2356: aptlControl[4].x = 50L;
2357: }
2358:
2359: if( (ptl.y + 50) == ptlTopRight.y)
2360: {
2361: aptlControl[6].y = 50L;
2362: aptlControl[7].y = 50L;
2363: }
2364:
2365: if( ptl.x == ptlBotLeft.x)
2366: {
2367: aptlControl[ 9].x = 0L;
2368: aptlControl[10].x = 0L;
2369: }
2370:
2371: for( l=0; l<12; l++)
2372: {
2373: aptlSides[l].x = ptl.x + aptlControl[l].x;
2374: aptlSides[l].y = ptl.y + aptlControl[l].y;
2375: }
2376:
2377: GpiOpenSegment( hpsClient, ++lCallSegId);
2378: GpiMove( hpsClient, &ptl);
2379: GpiPolyLine( hpsClient, 12L, aptlSides);
2380: GpiCloseSegment( hpsClient);
2381:
2382: /************************************************************************/
2383: /* draw the root segment */
2384: /************************************************************************/
2385: GpiOpenSegment( hpsClient, ++lLastSegId);
2386: GpiSetTag( hpsClient, lLastSegId);
2387:
2388: /************************************************************************/
2389: /* store the piece location */
2390: /************************************************************************/
2391: sl.ptlLocation = ptl;
2392:
2393: /************************************************************************/
2394: /* compute the dimensions of the matching rects for BitBlt */
2395: /************************************************************************/
2396: sl.rclBitBlt.xLeft = ptl.x - 10;
2397: sl.rclBitBlt.yBottom = ptl.y - 10;
2398: sl.rclBitBlt.xRight = ptl.x + 60;
2399: sl.rclBitBlt.yTop = ptl.y + 60;
2400: if( ptl.x == ptlBotLeft.x)
2401: sl.rclBitBlt.xLeft += 10;
2402: if( ptl.y == ptlBotLeft.y)
2403: sl.rclBitBlt.yBottom += 10;
2404: if( (ptl.x + 50) == ptlTopRight.x)
2405: sl.rclBitBlt.xRight -= 10;
2406: if( (ptl.y + 50) == ptlTopRight.y)
2407: sl.rclBitBlt.yTop -= 10;
2408:
2409: /************************************************************************/
2410: /* draw one piece */
2411: /************************************************************************/
2412: GpiBeginPath( hpsClient, 1L);
2413: GpiMove( hpsClient, &ptl);
2414: GpiPolyLine( hpsClient, 12L, aptlSides);
2415: GpiEndPath( hpsClient);
2416: GpiSetColor( hpsClient, CLR_BLACK);
2417: GpiLabel( hpsClient, FILLPATH);
2418:
2419: GpiSetClipPath( hpsClient, 0L, SCP_RESET);
2420: GpiBeginPath( hpsClient, 1L);
2421: GpiMove( hpsClient, &ptl);
2422: GpiPolyLine( hpsClient, 12L, aptlSides);
2423: GpiEndPath( hpsClient);
2424: GpiSetClipPath( hpsClient, 1L, SCP_AND);
2425: GpiLabel( hpsClient, BITBLT_TOP);
2426: GpiLabel( hpsClient, BITBLT_BOTTOM);
2427:
2428: GpiSetClipPath( hpsClient, 0L, SCP_RESET);
2429: GpiSetColor( hpsClient, CLR_RED);
2430: GpiMove( hpsClient, &ptl);
2431: GpiPolyLine( hpsClient, 12L, aptlSides);
2432:
2433: GpiCloseSegment( hpsClient);
2434: GpiSetSegmentAttrs( hpsClient, lLastSegId, ATTR_CHAINED, ATTR_ON);
2435: GpiSetSegmentAttrs( hpsClient, lLastSegId, ATTR_DETECTABLE, ATTR_ON);
2436:
2437: sl.lSegId = lLastSegId;
2438: sl.pslNext = NULL;
2439: sl.pslPrev = NULL;
2440: SetRect( &sl);
2441: SegListUpdate( ADD_TAIL_SEG, &sl);
2442: }
2443: }
2444: return( TRUE);
2445: }
2446:
2447: /******************************************************************************/
2448: /* */
2449: /* Create the Temp and Drag bitmaps. */
2450: /* */
2451: /******************************************************************************/
2452: BOOL
2453: PrepareBitmap()
2454: {
2455: bmpBitmapTemp = bmpBitmapFile;
2456: bmpBitmapTemp.cx = LOUSHORT( (sizlMaxClient.cx * 6L) / 5L);
2457: bmpBitmapTemp.cy = LOUSHORT( (sizlMaxClient.cy * 6L) / 5L);
2458: hbmBitmapTemp = GpiCreateBitmap( hpsBitmapTemp
2459: , &bmpBitmapTemp
2460: , 0L
2461: , NULL
2462: , NULL);
2463: if( !hbmBitmapTemp)
2464: return( FALSE);
2465:
2466: bmpBitmapDrag = bmpBitmapFile;
2467: bmpBitmapDrag.cx = LOUSHORT( (sizlMaxClient.cx * 6L) / 5L);
2468: bmpBitmapDrag.cy = LOUSHORT( (sizlMaxClient.cy * 6L) / 5L);
2469: hbmBitmapDrag = GpiCreateBitmap( hpsBitmapDrag
2470: , &bmpBitmapDrag
2471: , 0L
2472: , NULL
2473: , NULL);
2474: if( !hbmBitmapDrag)
2475: return( FALSE);
2476: return( TRUE);
2477: }
2478:
2479: /******************************************************************************/
2480: /* */
2481: /* Create a memory DC and an associated PS. */
2482: /* */
2483: /******************************************************************************/
2484: BOOL
2485: CreateBitmapHdcHps( phdc, phps)
2486:
2487: PHDC phdc;
2488: PHPS phps;
2489: {
2490: SIZEL sizl;
2491: HDC hdc;
2492: HPS hps;
2493:
2494: hdc = DevOpenDC( habMain, OD_MEMORY, "*", 3L, (PDEVOPENDATA)&dop, NULL);
2495: if( !hdc)
2496: return( FALSE);
2497:
2498: sizl.cx = sizl.cy = 0L;
2499: hps = GpiCreatePS( habMain
2500: , hdc
2501: , &sizl
2502: , PU_PELS | GPIA_ASSOC );
2503: if( !hps)
2504: return( FALSE);
2505:
2506: *phdc = hdc;
2507: *phps = hps;
2508: return( TRUE);
2509: }
2510:
2511: /******************************************************************************/
2512: /* */
2513: /* Get the bitmap from disk. */
2514: /* Note that there are 2 formats for bitmap files, one of which is archaic. */
2515: /* Both formats are supported here. All new bitmaps should follow the format */
2516: /* in BITMAPFILEHEADER. */
2517: /* */
2518: /******************************************************************************/
2519: BOOL
2520: ReadBitmap( hfile)
2521:
2522: HFILE hfile;
2523: {
2524: ULONG cScans;
2525: ULONG ulSize; /* Number of bytes occupied by bitmap bits. */
2526: USHORT cSegs; /* Number of 64K segments in ulSize. */
2527: USHORT cbExtra; /* Bytes in last segment of ulSize. */
2528: SEL sel; /* Base selector to file data. */
2529: USHORT hugeshift; /* Segment index shift value. */
2530: USHORT cbRead1; /* Number of bytes to read first call to DosRead */
2531: USHORT cbRead2; /* Number of bytes to read second call to DosRead */
2532: USHORT cbRead; /* Number of bytes read by DosRead. */
2533: BOOL fRet = FALSE; /* Function return code. */
2534: INT i; /* Generic loop index. */
2535: FILESTATUS fsts;
2536: PBITMAPFILEHEADER pbfh;
2537: PRCBITMAP rb;
2538: PBYTE pImage;
2539:
2540:
2541: /**************************************************************************/
2542: /* Find out how big the file is so we can read the whole thing in. */
2543: /**************************************************************************/
2544:
2545: if( DosQFileInfo( hfile, 1, &fsts, sizeof(FILESTATUS)) != 0)
2546: goto ReadBitmap_close_file;
2547:
2548: ulSize = fsts.cbFile;
2549: cSegs = (USHORT)(ulSize/0x10000L);
2550: cbExtra = (USHORT)(ulSize%0x10000L);
2551: if (DosAllocHuge(cSegs, cbExtra, (PSEL)&sel, 0, 0))
2552: goto ReadBitmap_close_file;
2553: if (DosGetHugeShift( &hugeshift))
2554: goto ReadBitmap_free_bits;
2555:
2556: pImage = (PBYTE)MAKEP(sel, 0);
2557: rb = (PRCBITMAP)pImage;
2558: pbfh = (PBITMAPFILEHEADER)pImage;
2559:
2560:
2561: /**************************************************************************/
2562: /* Read the bits in from the file. The DosRead function allows a */
2563: /* maximum of 64K-1 bytes read at a time. We get around this */
2564: /* by reading two 32K chunks for each 64K segment, and reading the */
2565: /* last segment in one piece. */
2566: /**************************************************************************/
2567:
2568: for (i = 0; i <= cSegs; ++i)
2569: {
2570: if (i < cSegs)
2571: {
2572: /* This segment is 64K bytes long, so split it up. */
2573: cbRead1 = 0x8000;
2574: cbRead2 = 0x8000;
2575: }
2576: else
2577: {
2578: /* This segment is less than 64K bytes long, so read it all. */
2579: cbRead1 = cbExtra;
2580: cbRead2 = 0;
2581: }
2582:
2583: /* There's a possibility that cbExtra will be 0, so check
2584: * to avoid an unnecessary system call.
2585: */
2586: if (cbRead1 > 0)
2587: {
2588: if (DosRead( hfile
2589: , (PVOID)MAKEP(sel+(i<<hugeshift), 0)
2590: , cbRead1
2591: , &cbRead))
2592: goto ReadBitmap_free_bits;
2593: if (cbRead1 != cbRead)
2594: goto ReadBitmap_free_bits;
2595: }
2596:
2597: /* This will always be skipped on the last partial segment. */
2598: if (cbRead2 > 0)
2599: {
2600: if (DosRead( hfile
2601: , (PVOID)MAKEP(sel+(i<<hugeshift), cbRead1)
2602: , cbRead2
2603: , &cbRead))
2604: goto ReadBitmap_free_bits;
2605: if (cbRead2 != cbRead)
2606: goto ReadBitmap_free_bits;
2607: }
2608: }
2609:
2610:
2611: /**************************************************************************/
2612: /* Tell GPI to put the bits into the thread's PS. The function returns */
2613: /* the number of scan lines of the bitmap that were copied. We want */
2614: /* all of them at once. */
2615: /**************************************************************************/
2616:
2617: if (pbfh->bmp.cbFix != sizeof(BITMAPINFOHEADER))
2618: {
2619: bmpBitmapFile.cx = rb->bmWidth;
2620: bmpBitmapFile.cy = rb->bmHeight;
2621: bmpBitmapFile.cPlanes = rb->bmPlanes;
2622: bmpBitmapFile.cBitCount = rb->bmBitcount;
2623: hbmBitmapFile = GpiCreateBitmap( hpsBitmapFile
2624: , &bmpBitmapFile
2625: , 0L
2626: , NULL
2627: , NULL);
2628: if( !hbmBitmapFile)
2629: goto ReadBitmap_free_bits;
2630: GpiSetBitmap( hpsBitmapFile, hbmBitmapFile);
2631:
2632: pImage += rb->dwBitsOffset;
2633: rb->dwBitsOffset = sizeof(BITMAPINFOHEADER);
2634: cScans = GpiSetBitmapBits( hpsBitmapFile
2635: , 0L
2636: , (LONG)rb->bmHeight
2637: , pImage
2638: , (PBITMAPINFO)&(rb->dwBitsOffset));
2639: if (cScans != (LONG)rb->bmHeight) /* original number of scans ? */
2640: goto ReadBitmap_free_bits;
2641: }
2642: else
2643: {
2644: bmpBitmapFile.cx = pbfh->bmp.cx;
2645: bmpBitmapFile.cy = pbfh->bmp.cy;
2646: bmpBitmapFile.cPlanes = pbfh->bmp.cPlanes;
2647: bmpBitmapFile.cBitCount = pbfh->bmp.cBitCount;
2648: hbmBitmapFile = GpiCreateBitmap( hpsBitmapFile
2649: , &bmpBitmapFile
2650: , 0L
2651: , NULL
2652: , NULL);
2653: if( !hbmBitmapFile)
2654: goto ReadBitmap_free_bits;
2655: GpiSetBitmap( hpsBitmapFile, hbmBitmapFile);
2656:
2657: cScans = GpiSetBitmapBits( hpsBitmapFile
2658: , 0L
2659: , (LONG)pbfh->bmp.cy
2660: , pImage + pbfh->offBits
2661: , (PBITMAPINFO)&(pbfh->bmp));
2662: if (cScans != (LONG)pbfh->bmp.cy) /* original number of scans ? */
2663: goto ReadBitmap_free_bits;
2664: }
2665:
2666: fRet = TRUE; /* okey-dokey */
2667:
2668:
2669: /**************************************************************************/
2670: /* Close the file, free the buffer space and leave. This is a */
2671: /* common exit point from the function. Since the same cleanup */
2672: /* operations need to be performed for such a large number of */
2673: /* possible error conditions, this is concise way to do the right */
2674: /* thing. */
2675: /**************************************************************************/
2676:
2677: ReadBitmap_free_bits:
2678: DosFreeSeg( sel);
2679: ReadBitmap_close_file:
2680: DosClose( hfile);
2681: return fRet;
2682: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.