|
|
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.