Annotation of pmsdk/samples/jigsaw/jigsaw.c, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.