home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / VSCPPv8.zip / VACPP / IBMCPP / samples / TOOLKIT / PM / BMPSAMP / JIGSAW.C < prev    next >
C/C++ Source or Header  |  1994-11-17  |  90KB  |  2,411 lines

  1. /******************************************************************************
  2. *
  3. *  File Name   : JIGSAW.C
  4. *
  5. *  Description : main function and code for the Jigsaw application
  6. *
  7. *     This program provides a jigsaw puzzle, based on a decomposition of an
  8. *     arbitrary bitmap loaded from a file.  The user can jumble the pieces,
  9. *     then drag them individually by means of the mouse.  The image can be
  10. *     zoomed in and out and scrolled up/down and left/right.
  11. *
  12. *     JIGSAW uses GpiBitBlt with clip paths to create a collection of picture
  13. *     fragments which are the puzzle pieces.  In earlier versions of the
  14. *     program, each of these pieces was associated with a single retain-mode
  15. *     graphics segment.  The retain-mode technique, however, proved to be
  16. *     too slow, so subsequent versions of the program used retain-mode APIs
  17. *     for fewer and fewer operations.  The current version eliminates
  18. *     retain-mode graphics altogether.  Instead, the drawing data for each
  19. *     piece is stored in _SEGLIST data structure defined in JIGSAW.H.
  20. *     This structure contains all the data needed to draw a piece, including
  21. *     pointers to the previous and next pieces.  The _SEGLIST nodes are
  22. *     arranged in drawing priority order, so the picture can be reconstructed
  23. *     by traversing the list in sequence, drawing each piece as its
  24. *     corresponding structure is encountered.  Where the comments in the
  25. *     rest of the program refer to a "segment," they are simply referring to
  26. *     a piece of the puzzle as defined by a record in this data structure.
  27. *
  28. *     To retain responsiveness to user requests, the real work is done in a
  29. *     second thread, with work requests transmitted from the main thread in
  30. *     the form of messages.  This arrangement makes it possible for the user
  31. *     to override lengthy drawing operations with a higher-priority request
  32. *     (eg. program termination, magnification change, etc.).
  33. *
  34. *     Individual pieces are made to "move" by changing their model transforms.
  35. *     Scrolling and zooming of the whole picture is done by changing the
  36. *     default viewing transform.  The points in model space associated with
  37. *     each piece (control points for the bounding curve, corners of the
  38. *     bounding box, etc.) are converted via GpiConvert into points in device
  39. *     space prior to use with GpiBitBlt, etc.
  40. *
  41. *  Concepts    : Illustrates the use of GPI
  42. *                Illustrates the use of off-screen bitmaps
  43. *
  44. *  Entry Points:
  45. *                CalcSize()
  46. *                CheckMenu()
  47. *                CheckPsl()
  48. *                CreatePicture()
  49. *                DispErrorMsg()
  50. *                DoHorzScroll()
  51. *                DosGetThreadInfo()
  52. *                DoVertScroll()
  53. *                DumpPicture()
  54. *                EnableMenu()
  55. *                NewThread()
  56. *                Finalize()
  57. *                Initialize()
  58. *                Jumble()
  59. *                LeftDown()
  60. *                LeftUp()
  61. *                Load()
  62. *                main()
  63. *                MouseMove()
  64. *                PrepareBitmap()
  65. *                ReadBitmap()
  66. *                ReportError()
  67. *                ResetScrollBars()
  68. *                SegListCheck()
  69. *                ToBottom()
  70. *                Zoom()
  71. *
  72. *  API's       : GpiBeginPath
  73. *                GpiEndPath
  74. *                GpiFillPath
  75. *                GpiSetClipPath
  76. *                GpiSetClipRegion
  77. *
  78. *                GpiCreateBitmap
  79. *                GpiDeleteBitmap
  80. *                GpiSetBitmap
  81. *                GpiSetBitmapBits
  82. *                GpiBitBlt
  83. *
  84. *                GpiConvert
  85. *
  86. *                GpiCreateRegion
  87. *                GpiCombineRegion
  88. *                GpiSetRegion
  89. *                GpiDestroyRegion
  90. *                GpiQueryRegionBox
  91. *
  92. *                GpiSetAttrMode
  93. *                GpiSetColor
  94. *
  95. *                GpiQueryDefaultViewMatrix
  96. *                GpiSetDefaultViewMatrix
  97. *
  98. *  Copyright (C) 1992 IBM Corporation
  99. *
  100. *      DISCLAIMER OF WARRANTIES.  The following [enclosed] code is
  101. *      sample code created by IBM Corporation. This sample code is not
  102. *      part of any standard or IBM product and is provided to you solely
  103. *      for  the purpose of assisting you in the development of your
  104. *      applications.  The code is provided "AS IS", without
  105. *      warranty of any kind.  IBM shall not be liable for any damages
  106. *      arising out of your use of the sample code, even if they have been
  107. *      advised of the possibility of such damages.                                                    *
  108. *
  109. ******************************************************************************/
  110.  
  111. #include "jigsaw.h"
  112. #include "globals.h"
  113. #include <stdlib.h>
  114. #include <stdio.h>
  115. #include <string.h>
  116.  
  117. /******************************************************************************
  118. *
  119. *  Name        : main
  120. *
  121. *  Description : Main thread will initialize the process for PM services and
  122. *                process the application message queue until a WM_QUIT message
  123. *                is received.  It will then destroy all PM resources and
  124. *                terminate.  Any error during initialization will be reported
  125. *                and the process terminated.
  126. *
  127. *  Concepts    :
  128. *
  129. *  API's       :
  130. *
  131. *  Parameters  : VOID
  132. *
  133. *  Return      :
  134. *
  135. ******************************************************************************/
  136.  
  137. VOID main(VOID)
  138. {
  139.   QMSG  qmsg;
  140.  
  141.   if( Initialize())
  142.       while( WinGetMsg( habMain, &qmsg, NULLHANDLE, 0, 0))
  143.           WinDispatchMsg( habMain, &qmsg);
  144.   else
  145.       ReportError( habMain);
  146.   Finalize();
  147.  
  148. }   /* end main() */
  149.  
  150. /******************************************************************************
  151. *
  152. *  Name        : Initialize
  153. *
  154. *  Description :
  155. *
  156. *  The Initialize function will initialize the PM interface,
  157. *  create an application message queue, a standard frame window and a new
  158. *  thread to control drawing operations.  It will also initialize static
  159. *  strings.
  160. *
  161. *  Concepts    :
  162. *
  163. *  API's       :
  164. *
  165. *  Parameters  : VOID
  166. *
  167. *  Return      : BOOL
  168. *
  169. ******************************************************************************/
  170.  
  171. BOOL Initialize(VOID)
  172. {
  173.   ULONG    flCreate;
  174.   PID      pid;
  175.   TID      tid;
  176.  
  177.    /*
  178.     * create all semaphores for mutual exclusion and event timing
  179.     */
  180.                    /* (anonomous,            ,    private,  reset) */
  181.  
  182.    if (DosCreateEventSem( NULL,  &hevDrawOn,          0,    FALSE) ||
  183.        DosCreateEventSem( NULL,  &hevMouse,           0,    FALSE) ||
  184.        DosCreateEventSem( NULL,  &hevLoadingBitmap,   0,    FALSE) ||
  185.        DosCreateEventSem( NULL,  &hevTerminate,       0,    FALSE) ||
  186.        DosCreateEventSem( NULL,  &hevKillDraw,        0,    FALSE))
  187.    {
  188.        return (FALSE);                       /* failed to create a semaphore */
  189.    }
  190.  
  191.    WinShowPointer( HWND_DESKTOP, TRUE);
  192.    habMain = WinInitialize( 0);
  193.    if( !habMain)
  194.        return( FALSE);
  195.  
  196.    hmqMain = WinCreateMsgQueue( habMain,0);
  197.    if( !hmqMain)
  198.        return( FALSE);
  199.  
  200.    WinLoadString( habMain, 0, IDS_TITLEBAR, sizeof(szTitle), szTitle);
  201.    WinLoadString( habMain, 0, IDS_ERROR_TITLE, sizeof(szErrorTitle), szErrorTitle);
  202.    if( !WinRegisterClass( habMain
  203.                         , (PCH)szTitle
  204.                         , ClientWndProc
  205.                         , CS_SIZEREDRAW
  206.                         , 0 ))
  207.        return( FALSE);
  208.  
  209.    flCreate =   (FCF_STANDARD | FCF_VERTSCROLL | FCF_HORZSCROLL)
  210.               & ~(ULONG)FCF_TASKLIST;
  211.    hwndFrame =
  212.    WinCreateStdWindow(
  213.       HWND_DESKTOP,                       /* handle of the parent window     */
  214.       WS_VISIBLE,                         /* frame-window style              */
  215.       &flCreate,                          /* creation flags                  */
  216.       szTitle,                            /* client-window class name        */
  217.       szTitle,                            /* address of title-bar text       */
  218.       WS_VISIBLE,                         /* client-window style             */
  219.       0,                                  /* handle of the resource module   */
  220.       IDR_MAIN,                           /* frame-window identifier         */
  221.       &hwndClient);                       /* address of client-window handle */
  222.  
  223.    if( !hwndFrame)
  224.        return( FALSE);
  225.  
  226.    sizlMaxClient.cx = WinQuerySysValue( HWND_DESKTOP, SV_CXFULLSCREEN);
  227.    sizlMaxClient.cy = WinQuerySysValue( HWND_DESKTOP, SV_CYFULLSCREEN);
  228.  
  229.    lByteAlignX = WinQuerySysValue( HWND_DESKTOP, SV_CXBYTEALIGN);
  230.    lByteAlignY = WinQuerySysValue( HWND_DESKTOP, SV_CYBYTEALIGN);
  231.  
  232.    hdcClient = WinOpenWindowDC( hwndClient);
  233.    hpsClient = GpiCreatePS( habMain
  234.                           , hdcClient
  235.                           , &sizlMaxClient
  236.                           , GPIA_ASSOC | PU_PELS );
  237.    if( !hpsClient)
  238.    {
  239.     DispError(habMain,hwndClient);
  240.     return( TRUE);
  241.    }
  242.    if (GpiSetAttrMode( hpsClient, AM_PRESERVE) == GPI_ERROR)
  243.        DispError(habMain,hwndClient);
  244.  
  245.    hwndHorzScroll = WinWindowFromID( hwndFrame, FID_HORZSCROLL);
  246.  
  247.    hwndVertScroll = WinWindowFromID( hwndFrame, FID_VERTSCROLL);
  248.  
  249.    if ((hpsPaint = GpiCreatePS( habMain, NULLHANDLE, &sizlMaxClient, PU_PELS)) == GPI_ERROR)
  250.                   DispError(habMain,hwndClient);
  251.  
  252.    hrgnInvalid = GpiCreateRegion( hpsClient, 0L, NULL);
  253.  
  254.    WinQueryWindowProcess( hwndFrame, &pid, &tid);
  255.    swctl.hwnd      = hwndFrame;
  256.    swctl.idProcess = pid;
  257.    strcpy( swctl.szSwtitle, szTitle);
  258.    hsw = WinAddSwitchEntry( &swctl);
  259.  
  260.    hwndMenu = WinWindowFromID( hwndFrame, FID_MENU);
  261.  
  262.    if(DosCreateThread(&tidAsync,
  263.                       (PFNTHREAD) NewThread,
  264.                       0,
  265.                       0,
  266.                       STACKSIZE )) {
  267.        return( FALSE);
  268.        }                               /* create async thread                 */
  269.    if( !CreateBitmapHdcHps( &hdcBitmapFile, &hpsBitmapFile))
  270.        return( FALSE);
  271.    if( !CreateBitmapHdcHps( &hdcBitmapSize, &hpsBitmapSize))
  272.        return( FALSE);
  273.    if( !CreateBitmapHdcHps( &hdcBitmapBuff, &hpsBitmapBuff))
  274.        return( FALSE);
  275.    if( !CreateBitmapHdcHps( &hdcBitmapSave, &hpsBitmapSave))
  276.        return( FALSE);
  277.  
  278.    ResetScrollBars();
  279.    /*
  280.     * initialise help mechanism
  281.     */
  282.  
  283.    HelpInit();
  284.    return( TRUE);
  285.  
  286. }   /* end Initialize() */
  287.  
  288. /******************************************************************************
  289. *
  290. *  Name        : Finalize
  291. *
  292. *  Description :
  293. *
  294. * Finalize will destroy the asynchronous drawing thread, all Presentation
  295. * Manager resources, and terminate the process.
  296. *
  297. *  Concepts    :
  298. *
  299. *  API's       :
  300. *
  301. *  Parameters  : VOID
  302. *
  303. *  Return      : VOID
  304. *
  305. ******************************************************************************/
  306.  
  307. VOID Finalize(VOID)
  308. {
  309.   ULONG ulPostCt;
  310.  
  311.   if( tidAsync)
  312.   {
  313.       DosResetEventSem( hevDrawOn, &ulPostCt);
  314.       DosPostEventSem( hevKillDraw);
  315.       DosPostEventSem( hevTerminate);
  316.       SendCommand( UM_DIE, (MPARAM)NULL, (MPARAM)NULL);
  317.   }
  318.  
  319.   while( pslHead != NULL )
  320.   {
  321.     if (GpiSetBitmap( pslHead->hpsFill, NULLHANDLE) == (HBITMAP)BMB_ERROR)
  322.       DispError(habMain,hwndClient);
  323.     if (GpiDeleteBitmap( pslHead->hbmFill) == GPI_ERROR)
  324.       DispError(habMain,hwndClient);
  325.     if (GpiDestroyPS( pslHead->hpsFill) == GPI_ERROR)
  326.       DispError(habMain,hwndClient);
  327.     DevCloseDC( pslHead->hdcFill);
  328.  
  329.     if (GpiSetBitmap( pslHead->hpsHole, NULLHANDLE)== (HBITMAP)BMB_ERROR)
  330.       DispError(habMain,hwndClient);
  331.     if (GpiDeleteBitmap( pslHead->hbmHole) == GPI_ERROR)
  332.       DispError(habMain,hwndClient);
  333.     if (GpiDestroyPS( pslHead->hpsHole) == GPI_ERROR)
  334.       DispError(habMain,hwndClient);
  335.     DevCloseDC( pslHead->hdcHole);
  336.  
  337.     SegListUpdate( DEL_SEG, pslHead);
  338.   }
  339.  
  340.   if( hrgnInvalid)
  341.       GpiDestroyRegion( hpsClient, hrgnInvalid);
  342.   if( hpsClient)
  343.   {
  344.       GpiAssociate( hpsClient, NULLHANDLE);
  345.       GpiDestroyPS( hpsClient);
  346.   }
  347.   if( hpsPaint)
  348.       GpiDestroyPS( hpsPaint);
  349.  
  350.   if( hpsBitmapFile)
  351.   {
  352.       GpiSetBitmap( hpsBitmapFile, NULLHANDLE);
  353.       GpiDeleteBitmap( hbmBitmapFile);
  354.       GpiDestroyPS( hpsBitmapFile);
  355.       DevCloseDC( hdcBitmapFile);
  356.   }
  357.   if( hpsBitmapSize)
  358.   {
  359.       GpiSetBitmap( hpsBitmapSize, NULLHANDLE);
  360.       GpiDeleteBitmap( hbmBitmapSize);
  361.       GpiDestroyPS( hpsBitmapSize);
  362.       DevCloseDC( hdcBitmapSize);
  363.   }
  364.   if( hpsBitmapBuff)
  365.   {
  366.       GpiSetBitmap( hpsBitmapBuff, NULLHANDLE);
  367.       GpiDeleteBitmap( hbmBitmapBuff);
  368.       GpiDestroyPS( hpsBitmapBuff);
  369.       DevCloseDC( hdcBitmapBuff);
  370.   }
  371.   if( hpsBitmapSave)
  372.   {
  373.       GpiSetBitmap( hpsBitmapSave, NULLHANDLE);
  374.       GpiDeleteBitmap( hbmBitmapSave);
  375.       GpiDestroyPS( hpsBitmapSave);
  376.       DevCloseDC( hdcBitmapSave);
  377.   }
  378.  
  379.   DestroyHelpInstance();
  380.  
  381.   if( hwndFrame)
  382.       WinDestroyWindow( hwndFrame);
  383.   if( hmqMain)
  384.       WinDestroyMsgQueue( hmqMain);
  385.   if( habMain)
  386.       WinTerminate( habMain);
  387.  
  388.   DosExit( EXIT_PROCESS, 0);
  389.  
  390. }   /* end Finalize() */
  391.  
  392. /******************************************************************************
  393. *
  394. *  Name        : ReportError
  395. *
  396. *  Description :
  397. *
  398. * ReportError  will display the latest error information for the required
  399. * thread. No resources to be loaded if out of memory error.
  400. *
  401. *  Concepts    :
  402. *
  403. *  API's       :
  404. *
  405. *  Parameters  : HAB hab
  406. *
  407. *  Return      : VOID
  408. *
  409. ******************************************************************************/
  410.  
  411. VOID ReportError(HAB hab)
  412. {
  413. PERRINFO  perriBlk;
  414. PSZ       pszErrMsg;
  415. PSZ       pszOffSet;
  416.  
  417.   if (!fErrMem){
  418.       if ((perriBlk = WinGetErrorInfo(hab)) != (PERRINFO)NULL){
  419.           pszOffSet = ((PSZ)perriBlk) + perriBlk->offaoffszMsg;
  420.           pszErrMsg = ((PSZ)perriBlk) + *((PULONG)pszOffSet);
  421.           WinMessageBox(HWND_DESKTOP,
  422.                         hwndFrame,
  423.                        (PSZ)(pszErrMsg),
  424.                        (PSZ)szTitle,
  425.                         0,
  426.                         MB_MOVEABLE | MB_CUACRITICAL | MB_CANCEL );
  427.           WinFreeErrorInfo(perriBlk);
  428.           return;
  429.       }
  430.   } /* endif */
  431.  
  432.   MessageBox(                                                       /* ERROR */
  433.      hwndFrame,
  434.      IDS_ERROR_OUTOFMEMORY,
  435.      MB_MOVEABLE | MB_CUACRITICAL | MB_CANCEL,
  436.      TRUE);
  437.  
  438. }   /* end ReportError() */
  439.  
  440. /******************************************************************************
  441. *
  442. *  Name        : ResetScrollBars
  443. *
  444. *  Description :
  445. *
  446. * Reset the scroll bars to be in the middle of their range
  447. *
  448. *  Concepts    :
  449. *
  450. *  API's       :
  451. *
  452. *  Parameters  : VOID
  453. *
  454. *  Return      : VOID
  455. *
  456. ******************************************************************************/
  457.  
  458. VOID ResetScrollBars(VOID)
  459. {
  460.     RECTL     rclClient;
  461.  
  462.     WinQueryWindowRect( hwndClient, &rclClient);
  463.     ptsScrollMax.x = (SHORT)(rclClient.xRight - rclClient.xLeft);
  464.     ptsHalfScrollMax.x = ptsScrollMax.x >> 1;
  465.     ptsScrollPage.x = ptsScrollMax.x >> 3;
  466.     ROUND_DOWN_MOD( ptsScrollPage.x, (SHORT)lByteAlignX);
  467.     ptsScrollLine.x = ptsScrollMax.x >> 5;
  468.     ROUND_DOWN_MOD( ptsScrollLine.x, (SHORT)lByteAlignX);
  469.     ptsScrollPos.x = ptsHalfScrollMax.x;
  470.     ptsOldScrollPos.x = ptsHalfScrollMax.x;
  471.     WinSendMsg( hwndHorzScroll
  472.               , SBM_SETSCROLLBAR
  473.               , MPFROMSHORT( ptsScrollPos.x)
  474.               , MPFROM2SHORT( 1, ptsScrollMax.x) );
  475.  
  476.     ptsScrollMax.y = (SHORT)(rclClient.yTop - rclClient.yBottom);
  477.     ptsHalfScrollMax.y = ptsScrollMax.y >> 1;
  478.     ptsScrollPage.y = ptsScrollMax.y >> 3;
  479.     ROUND_DOWN_MOD( ptsScrollPage.y, (SHORT)lByteAlignY);
  480.     ptsScrollLine.y = ptsScrollMax.y >> 5;
  481.     ROUND_DOWN_MOD( ptsScrollLine.y, (SHORT)lByteAlignY);
  482.     ptsScrollPos.y = ptsHalfScrollMax.y;
  483.     ptsOldScrollPos.y = ptsHalfScrollMax.y;
  484.     WinSendMsg( hwndVertScroll
  485.               , SBM_SETSCROLLBAR
  486.               , MPFROMSHORT( ptsScrollPos.y)
  487.               , MPFROM2SHORT( 1, ptsScrollMax.y) );
  488.  
  489.     WinSendMsg( hwndHorzScroll
  490.               , SBM_SETTHUMBSIZE
  491.               , MPFROM2SHORT(ptsScrollPage.x, ptsScrollMax.x)
  492.               , 0                                );
  493.  
  494.     WinSendMsg( hwndVertScroll
  495.               , SBM_SETTHUMBSIZE
  496.               , MPFROM2SHORT(ptsScrollPage.y, ptsScrollMax.y)
  497.               , NULL                             );
  498.  
  499. }   /* end ResetScrollBars() */
  500.  
  501. /******************************************************************************
  502. *
  503. *  Name        : Load
  504. *
  505. *  Description : Load a bitmap
  506. *
  507. *  Parameters  : PLOADINFO pli - pointer to file information (name, handle...)
  508. *
  509. *  Return      : VOID
  510. *
  511. ******************************************************************************/
  512.  
  513. VOID Load(PLOADINFO pli)
  514. {
  515.  ULONG     ulPostCt;
  516.  PUCHAR    pFilename;
  517.  UCHAR     szWindowText[CCHMAXPATH];
  518.  
  519.    DosResetEventSem( hevLoadingBitmap, &ulPostCt);  /* begin loading bitmap */
  520.  
  521.    /*
  522.     *   Disable bitmap manipulation submenus
  523.     */
  524.  
  525.    EnableMenu(IDM_SIZE_MENU,   FALSE);
  526.    EnableMenu(IDM_SIZE_SMALL,  FALSE);
  527.    EnableMenu(IDM_SIZE_MEDIUM, FALSE);
  528.    EnableMenu(IDM_SIZE_LARGE,  FALSE);
  529.    EnableMenu(IDM_SIZE_FULL,   FALSE);
  530.    EnableMenu(IDM_JUMBLE,      FALSE);
  531.  
  532.    CheckMenu(Currentchecked, FALSE);                    /* uncheck old menu */
  533.  
  534.    if( hbmBitmapFile)
  535.    {
  536.       if (GpiSetBitmap( hpsBitmapFile, NULLHANDLE) == (HBITMAP)BMB_ERROR)
  537.           DispError(habMain,hwndClient);
  538.       if (GpiDeleteBitmap( hbmBitmapFile) == GPI_ERROR)
  539.           DispError(habMain,hwndClient);
  540.    }
  541.  
  542.    if (!ReadBitmap( pli->hf))
  543.    {
  544.       MessageBox(hwndClient, IDS_ERROR_READ, MB_OK | MB_ERROR, TRUE);
  545.       DosPostEventSem( hevLoadingBitmap);             /* end loading bitmap */
  546.       if (!fFirstLoad)
  547.       {
  548.          /*
  549.           *   Re-Enable bitmap manipulation submenus
  550.           */
  551.  
  552.          EnableMenu(IDM_SIZE_MENU,   TRUE);
  553.          EnableMenu(IDM_SIZE_SMALL,  TRUE);
  554.          EnableMenu(IDM_SIZE_MEDIUM, TRUE);
  555.          EnableMenu(IDM_SIZE_LARGE,  TRUE);
  556.          EnableMenu(IDM_SIZE_FULL,   TRUE);
  557.          EnableMenu(IDM_JUMBLE,      TRUE);
  558.  
  559.          CheckMenu(Currentchecked, TRUE);                /* recheck old menu */
  560.  
  561.       }   /* end if (!fFirstLoad) */
  562.  
  563.       return;
  564.    }
  565.  
  566.    /*
  567.     *   Change Title Bar text and Window List text to include filename.
  568.     */
  569.  
  570.    strcpy(swctl.szSwtitle, szTitle);
  571.    strcat(swctl.szSwtitle, " - ");
  572.    strcpy(szWindowText, swctl.szSwtitle);            /* save duplicate part */
  573.    pFilename = strrchr(pli->szFileName, '\\');         /* contain pathname? */
  574.  
  575.    if (pFilename == NULL)
  576.       pFilename = pli->szFileName;         /* filename doesn't contain path */
  577.    else
  578.       ++pFilename;                            /* point past last back-slash */
  579.    strcat( swctl.szSwtitle, pFilename);
  580.    WinChangeSwitchEntry( hsw, &swctl);
  581.  
  582.    strcat(szWindowText, pli->szFileName);    /* use full filename in window */
  583.    WinSetWindowText( hwndFrame, szWindowText);
  584.    ResetScrollBars();
  585.  
  586.    if (fFirstLoad ||
  587.        (PBMP1(pbmp2BitmapFile)->cx        >  PBMP1(pbmp2BitmapFileRef)->cx ||
  588.         PBMP1(pbmp2BitmapFile)->cy        >  PBMP1(pbmp2BitmapFileRef)->cy ||
  589.         PBMP1(pbmp2BitmapFile)->cPlanes   != PBMP1(pbmp2BitmapFileRef)->cPlanes ||
  590.         PBMP1(pbmp2BitmapFile)->cBitCount != PBMP1(pbmp2BitmapFileRef)->cBitCount))
  591.    {
  592.      if( !fFirstLoad)
  593.               DumpPicture();
  594.      if( !PrepareBitmap() )
  595.      {
  596.         MessageBox(hwndClient, IDS_ERROR_READ, MB_OK | MB_ERROR, TRUE);
  597.         DosPostEventSem( hevLoadingBitmap);      /* end loading bitmap */
  598.         if (!fFirstLoad)
  599.         {
  600.            /*
  601.             *   Re-Enable bitmap manipulation submenus
  602.             */
  603.  
  604.            EnableMenu(IDM_SIZE_MENU,   TRUE);
  605.            EnableMenu(IDM_SIZE_SMALL,  TRUE);
  606.            EnableMenu(IDM_SIZE_MEDIUM, TRUE);
  607.            EnableMenu(IDM_SIZE_LARGE,  TRUE);
  608.            EnableMenu(IDM_SIZE_FULL,   TRUE);
  609.            EnableMenu(IDM_JUMBLE,      TRUE);
  610.  
  611.            CheckMenu(Currentchecked, TRUE);             /* recheck old menu */
  612.  
  613.         }   /* end if (!fFirstLoad) */
  614.  
  615.         return;
  616.      }
  617.      CreatePicture( PICTURE_CREATE);
  618.      bmp2BitmapFileRef = bmp2BitmapFile;
  619.    } else
  620.    {
  621.      CreatePicture( PICTURE_UPDATE);
  622.    }
  623.  
  624.    lScale = 0;
  625.  
  626.    CalcBounds();
  627.    ptlScaleRef.x = ptlScaleRef.y = 0L;
  628.    CalcTransform( hwndClient);
  629.  
  630.    DosPostEventSem( hevLoadingBitmap);                /* end loading bitmap */
  631.  
  632.    fFirstLoad = FALSE;
  633.    fPictureAssembled = TRUE;
  634.    BmpLoaded = TRUE;
  635.  
  636.    /*
  637.     *   Enable bitmap manipulation submenus
  638.     */
  639.    EnableMenu(IDM_SIZE_MENU,   TRUE);
  640.    EnableMenu(IDM_SIZE_SMALL,  TRUE);
  641.    EnableMenu(IDM_SIZE_MEDIUM, TRUE);
  642.    EnableMenu(IDM_SIZE_LARGE,  TRUE);
  643.    EnableMenu(IDM_SIZE_FULL,   TRUE);
  644.    EnableMenu(IDM_JUMBLE,      TRUE);
  645.  
  646.    CheckMenu(IDM_SIZE_FULL, TRUE);                        /* check full size */
  647.    Currentchecked = IDM_SIZE_FULL;
  648.  
  649. }   /* end Load() */
  650.  
  651. /******************************************************************************/
  652. /* Throw the pieces around the screen.                                        */
  653. /******************************************************************************/
  654. VOID Jumble(VOID)
  655. {
  656.   LONG      lWidth, lHeight;
  657.   DATETIME  date;
  658.   POINTL    ptl;
  659.   RECTL     rclClient;
  660.   PSEGLIST  psl;
  661.  
  662.   if( WinQueryWindowRect( hwndClient, &rclClient) )
  663.   {
  664.     lWidth  = rclClient.xRight - rclClient.xLeft;
  665.     lHeight = rclClient.yTop   - rclClient.yBottom;
  666.     if( (lWidth > 0) && (lHeight > 0) )
  667.     {
  668.        DosGetDateTime( &date);
  669.        srand( (USHORT)date.hundredths);
  670.        for( psl = pslHead; psl != NULL; psl = psl->pslNext)
  671.        {
  672.                psl->pslNextIsland = psl;    /* reset island pointer                   */
  673.                psl->fIslandMark = FALSE;    /* clear island mark                      */
  674.                ptl.x = rclClient.xLeft   + (rand() % lWidth);
  675.                ptl.y = rclClient.yBottom + (rand() % lHeight);
  676.                if (GpiConvert( hpsClient, CVTC_DEVICE, CVTC_MODEL, 1L, &ptl) == GPI_ERROR)
  677.                  DispError(habMain,hwndClient);
  678.                ptl.x = 50 * (ptl.x / 50) - 250;
  679.                ptl.y = 50 * (ptl.y / 50) - 250;
  680.                psl->ptlModelXlate.x = ptl.x - psl->ptlLocation.x;
  681.                psl->ptlModelXlate.y = ptl.y - psl->ptlLocation.y;
  682.                SetRect( psl);
  683.       }
  684.     }
  685.     fPictureAssembled = FALSE;
  686.   }
  687. }
  688.  
  689. /******************************************************************************/
  690. /*                                                                                                                                                  */
  691. /*                                                                                                                                                  */
  692. /*                                                                                                                                                  */
  693. /******************************************************************************/
  694. VOID ToBottom( pslDown)
  695. PSEGLIST pslDown;
  696. {
  697.   BOOL      fFirst;
  698.   PSEGLIST  psl;
  699.  
  700.   for( psl = pslDown, fFirst = TRUE
  701.      ; (psl != pslDown) || fFirst
  702.      ; psl = psl->pslNextIsland, fFirst = FALSE )
  703.     SegListUpdate( MAKE_HEAD_SEG, psl);       /* at head => lowest priority   */
  704. }
  705.  
  706.  
  707. /******************************************************************************/
  708. /*                                                                                                                                                  */
  709. /* NewThread is the asynchronous drawing thread. It is responsible for all    */
  710. /* drawing.  It will initialize its PM interface and create an application    */
  711. /* message queue.  It will then monitor its message queue and process any     */
  712. /* commands received.                                                                                                           */
  713. /*                                                                                                                                                  */
  714. /******************************************************************************/
  715. VOID NewThread(VOID)
  716. {
  717.   QMSG      qmsgAsync, qmsgPeek;
  718.   BOOL      fDone;
  719.   POINTL    aptlDraw[3];
  720.   USHORT    usChar, fsKeyFlags;
  721.   PSEGLIST  psl;
  722.   ULONG     ulPostCt;
  723.  
  724.   /****************************************************************************/
  725.   /* Initialize the PM interface.  If it fails, terminate both threads.       */
  726.   /****************************************************************************/
  727.   habAsync = WinInitialize( 0);
  728.   if( !habAsync)
  729.   {
  730.       WinPostMsg( hwndClient, WM_QUIT, NULL, NULL);
  731.       DosExit( EXIT_THREAD, 0);
  732.   }
  733.  
  734.   /****************************************************************************/
  735.   /* Create a message queue.  If it fails, terminate both threads.               */
  736.   /****************************************************************************/
  737.   hmqAsync = WinCreateMsgQueue( habAsync, 150);
  738.   if( !hmqAsync)
  739.   {
  740.       WinPostMsg( hwndClient, WM_QUIT, NULL, NULL);
  741.       WinTerminate( habAsync);
  742.       DosExit( EXIT_THREAD, 0);
  743.   }
  744.   else
  745.   {
  746.      WinCancelShutdown( hmqAsync, TRUE);   /* don't wait around for shutdown */
  747.   }
  748.  
  749.   DosSetPriority( PRTYS_THREAD, PRTYC_NOCHANGE, sPrty, (TID)NULL);
  750.  
  751.  
  752.   while( TRUE)
  753.   {
  754.     WinGetMsg( habAsync, &qmsgAsync, NULLHANDLE, 0, 0);
  755.  
  756.     /*
  757.      *   If we're exiting, give that message highest priority.
  758.      */
  759.  
  760.     if( WinPeekMsg(habAsync, &qmsgPeek, NULLHANDLE, UM_DIE, UM_DIE, PM_NOREMOVE))
  761.             qmsgAsync = qmsgPeek;
  762.     /*
  763.      *   Disallow drawing and mouse tracking as needed
  764.      */
  765.  
  766.     if( (qmsgAsync.msg < UM_SIZING) || (qmsgAsync.msg > UM_LOAD))
  767.             DosPostEventSem( hevMouse);             /* enable mouse tracking */
  768.     else
  769.             DosResetEventSem( hevMouse, &ulPostCt); /* disable mouse tracking */
  770.  
  771.     if( WinPeekMsg( habAsync, &qmsgPeek, NULLHANDLE, UM_SIZING, UM_LOAD, PM_NOREMOVE))
  772.     {
  773.        DosResetEventSem( hevDrawOn, &ulPostCt);           /* disable drawing */
  774.        DosResetEventSem( hevMouse, &ulPostCt);     /* disable mouse tracking */
  775.     }
  776.     else
  777.     {
  778.        DosPostEventSem( hevDrawOn);                        /* enable drawing */
  779.        DosPostEventSem( hevMouse);                  /* enable mouse tracking */
  780.     }
  781.  
  782.     /**************************************************************************/
  783.     /* process the commands                                                   */
  784.     /**************************************************************************/
  785.  
  786.     switch( qmsgAsync.msg)
  787.     {
  788.       /************************************************************************/
  789.       case UM_CHAR:
  790.             fsKeyFlags = (USHORT)SHORT1FROMMP(qmsgAsync.mp1);
  791.             usChar         = (USHORT)SHORT1FROMMP(qmsgAsync.mp2);
  792.             if(   (fsKeyFlags & KC_CHAR)
  793.                && ((usChar == 'b') || (usChar == 'B')))
  794.             {
  795.               if( psl = Correlate( &ptlMouse))
  796.               {
  797.                 ToBottom( psl);
  798.                 Redraw();
  799.               }
  800.             }
  801.             break;
  802.  
  803.       /************************************************************************/
  804.       case UM_LOAD:
  805.               Load( (PLOADINFO)qmsgAsync.mp1);
  806.               Redraw();
  807.         break;
  808.  
  809.       /************************************************************************/
  810.       case UM_JUMBLE:
  811.         Jumble();
  812.         Redraw();
  813.         break;
  814.  
  815.       /************************************************************************/
  816.       case UM_REDRAW:
  817.         Redraw();
  818.         break;
  819.  
  820.       /************************************************************************/
  821.       /* DRAW will use the passed region containing the invalidated area of   */
  822.       /* the screen, repaint it and then destroy the region.                  */
  823.       /************************************************************************/
  824.       case UM_DRAW:
  825.  
  826.         if (!BmpLoaded)
  827.              break;
  828.         if( qmsgAsync.mp1)
  829.         {
  830.           DoDraw( hpsBitmapBuff, (HRGN)qmsgAsync.mp1, TRUE);
  831.           if (GpiQueryRegionBox( hpsClient, (HRGN)qmsgAsync.mp1, (PRECTL)aptlDraw) == RGN_ERROR)
  832.                  DispError(habMain,hwndClient);
  833.           if (GpiDestroyRegion( hpsClient, (HRGN)qmsgAsync.mp1) == GPI_ERROR)
  834.                  DispError(habMain,hwndClient);
  835.           WinMapWindowPoints( hwndClient, HWND_DESKTOP, aptlDraw, 3);
  836.           ROUND_DOWN_MOD( aptlDraw[0].x, lByteAlignX);    /* round down       */
  837.           ROUND_DOWN_MOD( aptlDraw[0].y, lByteAlignY);    /* round down       */
  838.           ROUND_UP_MOD(   aptlDraw[1].x, lByteAlignX);    /* round up         */
  839.           ROUND_UP_MOD(   aptlDraw[1].y, lByteAlignY);    /* round up         */
  840.           WinMapWindowPoints( HWND_DESKTOP, hwndClient, aptlDraw, 3);
  841.           aptlDraw[2] = aptlDraw[0];
  842.           if (GpiBitBlt( hpsClient
  843.                        , hpsBitmapBuff
  844.                        , 3L
  845.                        , aptlDraw
  846.                        , ROP_SRCCOPY
  847.                        , BBO_IGNORE ) == GPI_ERROR)
  848.               DispError(habMain,hwndClient);
  849.         }
  850.         break;
  851.  
  852.  
  853.       /************************************************************************/
  854.       /* Get new scroll posn from command ( i.e. +/-1 +/-page) or new         */
  855.       /* absolute position from parameter, update scroll posn, change the     */
  856.       /* transform and update the thumb posn.  Finally update the window.     */
  857.       /************************************************************************/
  858.       case UM_HSCROLL:
  859.         switch( SHORT2FROMMP( qmsgAsync.mp1) )
  860.         {
  861.             case SB_LINEUP:
  862.                 ptsScrollPos.x -= ptsScrollLine.x;
  863.                 break;
  864.             case SB_LINEDOWN:
  865.                 ptsScrollPos.x += ptsScrollLine.x;
  866.                 break;
  867.             case SB_SLIDERTRACK:
  868.             case SB_SLIDERPOSITION:
  869.                 for( fDone = FALSE; !fDone ;)
  870.                 {
  871.                   if( WinPeekMsg( habAsync
  872.                                 , &qmsgPeek
  873.                                 , NULLHANDLE
  874.                                 , UM_HSCROLL
  875.                                 , UM_HSCROLL
  876.                                 , PM_NOREMOVE))
  877.                       if(   (SHORT2FROMMP( qmsgPeek.mp1) == SB_SLIDERTRACK)
  878.                           ||(SHORT2FROMMP( qmsgPeek.mp1) == SB_SLIDERPOSITION))
  879.                           WinPeekMsg( habAsync
  880.                                     , &qmsgAsync
  881.                                     , NULLHANDLE
  882.                                     , UM_HSCROLL
  883.                                     , UM_HSCROLL
  884.                                     , PM_REMOVE);
  885.                       else
  886.                           fDone = TRUE;
  887.                   else
  888.                       fDone = TRUE;
  889.                 }
  890.                 ptsScrollPos.x = SHORT1FROMMP( qmsgAsync.mp1);
  891.                 ROUND_DOWN_MOD( ptsScrollPos.x, (SHORT)lByteAlignX);
  892.                 break;
  893.             case SB_PAGEUP:
  894.                 ptsScrollPos.x -= ptsScrollPage.x;
  895.                 break;
  896.             case SB_PAGEDOWN:
  897.                 ptsScrollPos.x += ptsScrollPage.x;
  898.                 break;
  899.             case SB_ENDSCROLL:
  900.                 break;
  901.             default:
  902.                 break;
  903.         }
  904.         DoHorzScroll();
  905.         break;
  906.  
  907.       case UM_VSCROLL:
  908.         switch( SHORT2FROMMP( qmsgAsync.mp1) )
  909.         {
  910.             case SB_LINEUP:
  911.                 ptsScrollPos.y -= ptsScrollLine.y;
  912.                 break;
  913.             case SB_LINEDOWN:
  914.                 ptsScrollPos.y += ptsScrollLine.y;
  915.                 break;
  916.             case SB_SLIDERTRACK:
  917.             case SB_SLIDERPOSITION:
  918.                 for( fDone = FALSE; !fDone ;)
  919.                 {
  920.                   if( WinPeekMsg( habAsync
  921.                                 , &qmsgPeek
  922.                                 , NULLHANDLE
  923.                                 , UM_VSCROLL
  924.                                 , UM_VSCROLL
  925.                                 , PM_NOREMOVE))
  926.                       if(   (SHORT2FROMMP( qmsgPeek.mp1) == SB_SLIDERTRACK)
  927.                           ||(SHORT2FROMMP( qmsgPeek.mp1) == SB_SLIDERPOSITION))
  928.                           WinPeekMsg( habAsync
  929.                                     , &qmsgAsync
  930.                                     , NULLHANDLE
  931.                                     , UM_VSCROLL
  932.                                     , UM_VSCROLL
  933.                                     , PM_REMOVE);
  934.                       else
  935.                           fDone = TRUE;
  936.                   else
  937.                       fDone = TRUE;
  938.                 }
  939.                 ptsScrollPos.y = SHORT1FROMMP( qmsgAsync.mp1);
  940.                 ROUND_DOWN_MOD( ptsScrollPos.y, (SHORT)lByteAlignY);
  941.                 break;
  942.             case SB_PAGEUP:
  943.                 ptsScrollPos.y -= ptsScrollPage.y;
  944.                 break;
  945.             case SB_PAGEDOWN:
  946.                 ptsScrollPos.y += ptsScrollPage.y;
  947.                 break;
  948.             case SB_ENDSCROLL:
  949.                 break;
  950.             default:
  951.                 break;
  952.         }
  953.         DoVertScroll();
  954.         break;
  955.  
  956.       /************************************************************************/
  957.       /* the window is being resized                                          */
  958.       /************************************************************************/
  959.       case UM_SIZING:
  960.         CalcBounds();
  961.         CalcTransform( hwndClient);
  962.         break;
  963.  
  964.       /************************************************************************/
  965.       /* adjust zoom factor                                                   */
  966.       /************************************************************************/
  967.       case UM_ZOOM:
  968.         if( WinPeekMsg( habAsync
  969.                       , &qmsgPeek
  970.                       , NULLHANDLE
  971.                       , UM_SIZING
  972.                       , UM_LOAD
  973.                       , PM_NOREMOVE))
  974.             DosResetEventSem( hevDrawOn, &ulPostCt);
  975.         else {
  976.             DosPostEventSem( hevDrawOn);
  977.             }
  978.  
  979.         Zoom();
  980.         break;
  981.  
  982.       /************************************************************************/
  983.       /* Button down will cause a correlate on the picture to test for a hit. */
  984.       /* Any selected segment will be highlighted and redrawn as dynamic.     */
  985.       /************************************************************************/
  986.       case UM_LEFTDOWN:
  987.         if( !fButtonDownAsync)
  988.         {
  989.             fButtonDownAsync = TRUE;
  990.        if(!fPictureAssembled)
  991.                LeftDown( qmsgAsync.mp1);
  992.         }
  993.         break;
  994.  
  995.       /************************************************************************/
  996.       /* if a segment is being dragged it will be redrawn in a new posn       */
  997.       /************************************************************************/
  998.       case UM_MOUSEMOVE:
  999. #ifdef fred
  1000.         if( !fButtonDownAsync)
  1001.             break;
  1002. #endif
  1003.         for( fDone = FALSE; !fDone ;)
  1004.         {
  1005.           if( WinPeekMsg( habAsync            /* look through first button-up */
  1006.                         , &qmsgPeek
  1007.                         , NULLHANDLE
  1008.                         , UM_MOUSEMOVE
  1009.                         , UM_LEFTUP
  1010.                         , PM_NOREMOVE))
  1011.               if( qmsgPeek.msg == UM_MOUSEMOVE) /* only collapse move msgs    */
  1012.                   WinPeekMsg( habAsync
  1013.                             , &qmsgAsync
  1014.                             , NULLHANDLE
  1015.                             , UM_MOUSEMOVE
  1016.                             , UM_MOUSEMOVE
  1017.                             , PM_REMOVE);
  1018.               else
  1019.                   fDone = TRUE;
  1020.           else
  1021.               fDone = TRUE;
  1022.         }
  1023.         MouseMove( qmsgAsync.mp1);      /* process last move before button-up */
  1024.         break;
  1025.  
  1026.       /************************************************************************/
  1027.       /* if a segment is being dragged it will be redrawn as normal           */
  1028.       /************************************************************************/
  1029.       case UM_LEFTUP:
  1030.         if( fButtonDownAsync)
  1031.         {
  1032.             LeftUp();
  1033.             fButtonDownAsync = FALSE;
  1034.         }
  1035.         break;
  1036.  
  1037.       /************************************************************************/
  1038.       /* destroy resources and terminate                                                           */
  1039.       /************************************************************************/
  1040.       case UM_DIE:
  1041.               WinDestroyMsgQueue( hmqAsync);
  1042.               WinTerminate( habAsync);
  1043.               DosExit( EXIT_THREAD, 0);
  1044.               break;
  1045.  
  1046.       /************************************************************************/
  1047.       default:
  1048.         break;
  1049.     }
  1050.   }
  1051. }
  1052.  
  1053. /******************************************************************************/
  1054. /*                                                                            */
  1055. /******************************************************************************/
  1056. VOID CalcSize( mp1, mp2)
  1057. MPARAM mp1;
  1058. MPARAM mp2;
  1059. {
  1060.   ptsScrollMax.y = SHORT2FROMMP( mp2);
  1061.   ptsHalfScrollMax.y = ptsScrollMax.y >> 1;
  1062.   ptsScrollPage.x = ptsScrollMax.x >> 3;
  1063.   ROUND_DOWN_MOD( ptsScrollPage.x, (SHORT)lByteAlignX);
  1064.   ptsScrollLine.x = ptsScrollMax.x >> 5;
  1065.   ROUND_DOWN_MOD( ptsScrollLine.x, (SHORT)lByteAlignX);
  1066.   ptsScrollPos.y = (SHORT)(
  1067.                            (  (LONG)ptsScrollPos.y
  1068.                             * (LONG)SHORT2FROMMP(mp2)
  1069.                            )/ (LONG)SHORT2FROMMP(mp1)
  1070.                           );
  1071.   ptsOldScrollPos.y = (SHORT)(
  1072.                               (  (LONG)ptsOldScrollPos.y
  1073.                                * (LONG)SHORT2FROMMP(mp2)
  1074.                               )/ (LONG)SHORT2FROMMP(mp1)
  1075.                              );
  1076.   WinSendMsg( hwndVertScroll
  1077.             , SBM_SETSCROLLBAR
  1078.             , MPFROMSHORT( ptsScrollPos.y)
  1079.             , MPFROM2SHORT( 1, ptsScrollMax.y) );
  1080.  
  1081.   ptsScrollMax.x = SHORT1FROMMP( mp2);
  1082.   ptsHalfScrollMax.x = ptsScrollMax.x >> 1;
  1083.   ptsScrollPage.y = ptsScrollMax.y >> 3;
  1084.   ROUND_DOWN_MOD( ptsScrollPage.y, (SHORT)lByteAlignY);
  1085.   ptsScrollLine.y = ptsScrollMax.y >> 5;
  1086.   ROUND_DOWN_MOD( ptsScrollLine.y, (SHORT)lByteAlignY);
  1087.   ptsScrollPos.x = (SHORT)(
  1088.                            (  (LONG)ptsScrollPos.x
  1089.                             * (LONG)SHORT1FROMMP(mp2)
  1090.                            )/(LONG)SHORT1FROMMP(mp1)
  1091.                           );
  1092.   ptsOldScrollPos.x = (SHORT)(
  1093.                               (  (LONG)ptsOldScrollPos.x
  1094.                                * (LONG)SHORT1FROMMP(mp2)
  1095.                               )/ (LONG)SHORT1FROMMP(mp1)
  1096.                              );
  1097.   WinSendMsg( hwndHorzScroll
  1098.             , SBM_SETSCROLLBAR
  1099.             , MPFROMSHORT( ptsScrollPos.x)
  1100.             , MPFROM2SHORT( 1, ptsScrollMax.x) );
  1101.     WinSendMsg( hwndHorzScroll
  1102.               , SBM_SETTHUMBSIZE
  1103.               , MPFROM2SHORT(ptsScrollPage.x, ptsScrollMax.x)
  1104.               , NULL                             );
  1105.  
  1106.     WinSendMsg( hwndVertScroll
  1107.               , SBM_SETTHUMBSIZE
  1108.               , MPFROM2SHORT(ptsScrollPage.y, ptsScrollMax.y)
  1109.               , NULL                             );
  1110.  
  1111. }
  1112.  
  1113. /******************************************************************************/
  1114. /* button down will cause one segment to be indicated and made dynamic        */
  1115. /******************************************************************************/
  1116. VOID LeftDown(MPARAM mp)
  1117. {
  1118.   POINTL    ptl;
  1119.   HRGN      hrgn, hrgnUpdt, hrgnUpdtDrag;
  1120.   RECTL     rcl;
  1121.   BOOL      fFirst;
  1122.   PSEGLIST  psl;
  1123.  
  1124.   ptl.x = (LONG)(SHORT)SHORT1FROMMP( mp);
  1125.   ptl.y = (LONG)(SHORT)SHORT2FROMMP( mp);
  1126.  
  1127.   /****************************************************************************/
  1128.   pslPicked = Correlate( &ptl);
  1129.   if( pslPicked)
  1130.     lPickedSeg   = pslPicked->lSegId;
  1131.   else
  1132.   {
  1133.     fButtonDownAsync = FALSE;
  1134.     return;
  1135.   }
  1136.   if( (lPickedSeg < 1) || (lPickedSeg > lLastSegId) )
  1137.   {
  1138.      #if defined(DEBUG)
  1139.      {
  1140.        CHAR      szMsg[40];
  1141.  
  1142.         sprintf( szMsg, "Segment id out of range: %x", lPickedSeg);
  1143.         WinMessageBox(HWND_DESKTOP, hwndFrame, szMsg, szErrorTitle, 0,
  1144.                        MB_OK | MB_ICONEXCLAMATION | MB_APPLMODAL);
  1145.      }
  1146.      #endif
  1147.  
  1148.      fButtonDownAsync = FALSE;
  1149.      return;
  1150.   }
  1151.  
  1152.   /****************************************************************************/
  1153.   ptlOffStart = pslPicked->ptlModelXlate;
  1154.   ptlMoveStart = ptl;
  1155.   if (GpiConvert( hpsClient, CVTC_DEVICE, CVTC_MODEL, 1L, &ptlMoveStart) == GPI_ERROR)
  1156.       DispError(habMain,hwndClient);
  1157.   ptlMoveStart.x = (ptlMoveStart.x / 50) * 50;
  1158.   ptlMoveStart.y = (ptlMoveStart.y / 50) * 50;
  1159.   ptlUpdtRef = ptlMoveStart;
  1160.   if (GpiConvert( hpsClient, CVTC_MODEL, CVTC_DEVICE, 1L, &ptlUpdtRef) == GPI_ERROR)
  1161.       DispError(habMain,hwndClient);
  1162.  
  1163.   /****************************************************************************/
  1164.   hrgnUpdt = GpiCreateRegion( hpsClient, 0L, NULL);
  1165.   for( psl = pslPicked, fFirst = TRUE
  1166.      ; (psl != pslPicked) || fFirst
  1167.      ; psl = psl->pslNextIsland, fFirst = FALSE )
  1168.   {
  1169.     rcl = psl->rclCurrent;   /* get model space bounding box of piece         */
  1170.     if (GpiConvert( hpsClient, CVTC_MODEL, CVTC_DEVICE, 2L, (PPOINTL)&rcl) == GPI_ERROR)
  1171.         DispError(habMain,hwndClient);
  1172.     rcl.xRight++;            /* adjust rectangle for conversion to dev space  */
  1173.     rcl.yTop++;
  1174.     rcl.xRight  += 2;                            /* should not need           */
  1175.     rcl.yTop    += 2;                            /* should not need           */
  1176.     rcl.xLeft   -= 4;                            /* should not need           */
  1177.     rcl.yBottom -= 4;                            /* should not need           */
  1178.     hrgn = GpiCreateRegion( hpsClient, 1L, &rcl);
  1179.     if (GpiCombineRegion( hpsClient, hrgnUpdt, hrgnUpdt, hrgn, CRGN_OR) == RGN_ERROR)
  1180.         DispError(habMain,hwndClient);
  1181.     if (GpiDestroyRegion( hpsClient, hrgn) == GPI_ERROR)
  1182.         DispError(habMain,hwndClient);
  1183.     psl->fVisible = FALSE;
  1184.   }
  1185.  
  1186.   if (GpiQueryRegionBox( hpsClient, hrgnUpdt, (PRECTL)aptlUpdt) == GPI_ERROR)
  1187.       DispError(habMain,hwndClient);
  1188.   WinMapWindowPoints( hwndClient, HWND_DESKTOP, aptlUpdt, 3);
  1189.   ROUND_DOWN_MOD( aptlUpdt[0].x, lByteAlignX);            /* round down       */
  1190.   ROUND_DOWN_MOD( aptlUpdt[0].y, lByteAlignY);            /* round down       */
  1191.   ROUND_UP_MOD(   aptlUpdt[1].x, lByteAlignX);            /* round up         */
  1192.   ROUND_UP_MOD(   aptlUpdt[1].y, lByteAlignY);            /* round up         */
  1193.   WinMapWindowPoints( HWND_DESKTOP, hwndClient, aptlUpdt, 3);
  1194.   hrgnUpdtDrag = GpiCreateRegion( hpsBitmapBuff, 1L, (PRECTL)aptlUpdt);
  1195.  
  1196.   aptlUpdt[2] = aptlUpdt[0];
  1197.   DoDraw( hpsBitmapBuff, hrgnUpdtDrag, TRUE);
  1198.   if (GpiDestroyRegion( hpsClient, hrgnUpdt) == GPI_ERROR)
  1199.       DispError(habMain,hwndClient);
  1200.   if (GpiDestroyRegion( hpsBitmapBuff, hrgnUpdtDrag) == GPI_ERROR)
  1201.       DispError(habMain,hwndClient);
  1202.   if (GpiBitBlt( hpsBitmapSave
  1203.                , hpsBitmapBuff
  1204.                , 3L
  1205.                , aptlUpdt
  1206.                , ROP_SRCCOPY
  1207.                , BBO_IGNORE ) == GPI_ERROR)
  1208.       DispError(habMain,hwndClient);
  1209.  
  1210.   /****************************************************************************/
  1211.   for( psl = pslPicked, fFirst = TRUE
  1212.      ; (psl != pslPicked) || fFirst
  1213.      ; psl = psl->pslNextIsland, fFirst = FALSE )
  1214.   {
  1215.     psl->fVisible = TRUE;
  1216.     DrawPiece( hpsBitmapBuff, psl, TRUE);
  1217.   }
  1218.   if (GpiBitBlt( hpsClient
  1219.            , hpsBitmapBuff
  1220.            , 3L
  1221.            , aptlUpdt
  1222.            , ROP_SRCCOPY
  1223.            , BBO_IGNORE ) ==  GPI_ERROR)
  1224.       DispError(habMain,hwndClient);
  1225.   WinSetCapture( HWND_DESKTOP, hwndClient);
  1226. }
  1227.  
  1228.  
  1229.  
  1230.  
  1231. /******************************************************************************/
  1232. /*                                                                            */
  1233. /* move the segment                                                           */
  1234. /*                                                                            */
  1235. /******************************************************************************/
  1236. VOID MouseMove( mp)
  1237. MPARAM mp;
  1238. {
  1239.   RECTL     rcl;
  1240.   POINTL    ptl, ptlModel, ptlDevice;
  1241.   POINTL    aptlUpdtRef[3], aptlUpdtNew[3];
  1242.   PSEGLIST  psl;
  1243.   BOOL      fFirst;
  1244.  
  1245.   ptl.x = (LONG)(SHORT)SHORT1FROMMP( mp);
  1246.   ptl.y = (LONG)(SHORT)SHORT2FROMMP( mp);
  1247.  
  1248.   /****************************************************************************/
  1249.   /* clip mouse coords to client window                                       */
  1250.   /****************************************************************************/
  1251.   WinQueryWindowRect( hwndClient, &rcl);
  1252.   if (rcl.xLeft > ptl.x)
  1253.     ptl.x = rcl.xLeft;
  1254.   if (rcl.xRight <= ptl.x)
  1255.     ptl.x = rcl.xRight;
  1256.   if (rcl.yBottom > ptl.y)
  1257.     ptl.y = rcl.yBottom;
  1258.   if (rcl.yTop <= ptl.y)
  1259.     ptl.y = rcl.yTop;
  1260.   ptlMouse = ptl;
  1261.  
  1262.   if( !lPickedSeg || !pslPicked || !fButtonDownAsync)
  1263.     return;
  1264.  
  1265.   ptlModel = ptl;
  1266.   if (GpiConvert( hpsClient, CVTC_DEVICE, CVTC_MODEL, 1L, &ptlModel) == GPI_ERROR)
  1267.       DispError(habMain,hwndClient);
  1268.   ptlModel.x = 50 * (ptlModel.x / 50);
  1269.   ptlModel.y = 50 * (ptlModel.y / 50);
  1270.   if( (ptlModel.x == ptlOldMouse.x) && (ptlModel.y == ptlOldMouse.y))
  1271.     return;
  1272.   ptlOldMouse.x = ptlModel.x;
  1273.   ptlOldMouse.y = ptlModel.y;
  1274.   ptlDevice = ptlModel;
  1275.   if (GpiConvert( hpsClient, CVTC_MODEL, CVTC_DEVICE, 1L, &ptlDevice) == GPI_ERROR)
  1276.       DispError(habMain,hwndClient);
  1277.  
  1278.   if (GpiBitBlt( hpsBitmapBuff
  1279.            , hpsBitmapSave
  1280.            , 3L
  1281.            , aptlUpdt
  1282.            , ROP_SRCCOPY
  1283.            , BBO_IGNORE ) == GPI_ERROR)
  1284.       DispError(habMain,hwndClient);
  1285.   aptlUpdtRef[0] = aptlUpdt[0];
  1286.   aptlUpdtRef[1] = aptlUpdt[1];
  1287.  
  1288.   aptlUpdt[0].x += ptlDevice.x - ptlUpdtRef.x;
  1289.   aptlUpdt[0].y += ptlDevice.y - ptlUpdtRef.y;
  1290.   aptlUpdt[1].x += ptlDevice.x - ptlUpdtRef.x;
  1291.   aptlUpdt[1].y += ptlDevice.y - ptlUpdtRef.y;
  1292.   WinMapWindowPoints( hwndClient, HWND_DESKTOP, aptlUpdt, 3);
  1293.   ROUND_DOWN_MOD( aptlUpdt[0].x, lByteAlignX);            /* round down       */
  1294.   ROUND_DOWN_MOD( aptlUpdt[0].y, lByteAlignY);            /* round down       */
  1295.   ROUND_UP_MOD(   aptlUpdt[1].x, lByteAlignX);            /* round up         */
  1296.   ROUND_UP_MOD(   aptlUpdt[1].y, lByteAlignY);            /* round up         */
  1297.   WinMapWindowPoints( HWND_DESKTOP, hwndClient, aptlUpdt, 3);
  1298.   aptlUpdt[2] = aptlUpdt[0];
  1299.   ptlUpdtRef = ptlDevice;
  1300.   if (GpiBitBlt( hpsBitmapSave
  1301.                , hpsBitmapBuff
  1302.                , 3L
  1303.                , aptlUpdt
  1304.                , ROP_SRCCOPY
  1305.                , BBO_IGNORE ) == GPI_ERROR)
  1306.       DispError(habMain,hwndClient);
  1307.  
  1308.  
  1309.   pslPicked->ptlModelXlate.x = ptlOffStart.x + ptlModel.x - ptlMoveStart.x;
  1310.   pslPicked->ptlModelXlate.y = ptlOffStart.y + ptlModel.y - ptlMoveStart.y;
  1311.  
  1312.   for( psl = pslPicked, fFirst = TRUE
  1313.      ; (psl != pslPicked) || fFirst
  1314.      ; psl = psl->pslNextIsland, fFirst = FALSE )
  1315.   {
  1316.     psl->ptlModelXlate = pslPicked->ptlModelXlate;
  1317.     DrawPiece( hpsBitmapBuff, psl, TRUE);
  1318.   }
  1319.  
  1320.   WinUnionRect( habMain
  1321.               , (PRECTL)aptlUpdtNew
  1322.               , (PRECTL)aptlUpdt
  1323.               , (PRECTL)aptlUpdtRef);
  1324.   WinMapWindowPoints( hwndClient, HWND_DESKTOP, aptlUpdtNew, 2);
  1325.   ROUND_DOWN_MOD( aptlUpdtNew[0].x, lByteAlignX);         /* round down       */
  1326.   ROUND_DOWN_MOD( aptlUpdtNew[0].y, lByteAlignY);         /* round down       */
  1327.   ROUND_UP_MOD(   aptlUpdtNew[1].x, lByteAlignX);         /* round up         */
  1328.   ROUND_UP_MOD(   aptlUpdtNew[1].y, lByteAlignY);         /* round up         */
  1329.   WinMapWindowPoints( HWND_DESKTOP, hwndClient, aptlUpdtNew, 2);
  1330.   aptlUpdtNew[2] = aptlUpdtNew[0];
  1331.   if (GpiBitBlt( hpsClient
  1332.                , hpsBitmapBuff
  1333.                , 3L
  1334.                , aptlUpdtNew
  1335.                , ROP_SRCCOPY
  1336.                , BBO_IGNORE ) == GPI_ERROR)
  1337.       DispError(habMain,hwndClient);
  1338. }
  1339.  
  1340.  
  1341. /******************************************************************************/
  1342. /*                                                                                                                         */
  1343. /* The dragged segment is being unselected.  Return it to its normal state.   */
  1344. /*                                                                                                                         */
  1345. /******************************************************************************/
  1346. VOID LeftUp(VOID)
  1347. {
  1348.   PSEGLIST   psl, pslTemp;
  1349.   POINTL     ptlShift;
  1350.   BOOL       fFirst;
  1351.   LONG       l;
  1352.  
  1353.   if (!BmpLoaded)
  1354.     {
  1355.            MessageBox(hwndFrame, IDS_LOADBITMAP, MB_OK | MB_INFORMATION, TRUE);
  1356.       return;
  1357.     }
  1358.   else if(fPictureAssembled)
  1359.     {
  1360.            MessageBox(hwndFrame, IDS_OPTIONJUMBLE, MB_OK | MB_INFORMATION, TRUE);
  1361.       return;
  1362.     }
  1363.  
  1364.   if( !lPickedSeg || !pslPicked)
  1365.     return;
  1366.  
  1367.   for( psl = pslPicked, fFirst = TRUE
  1368.      ; (psl != pslPicked) || fFirst
  1369.      ; psl = psl->pslNextIsland, fFirst = FALSE )
  1370.   {
  1371.  
  1372.     SetRect( psl);
  1373.     SegListUpdate( MAKE_TAIL_SEG, psl);       /* at tail => highest priority  */
  1374.     psl->fIslandMark = TRUE;                  /* mark as island member        */
  1375.   }
  1376.   ptlShift = pslPicked->ptlModelXlate;
  1377.  
  1378.   for( psl = pslHead; psl != NULL; psl = psl->pslNext)
  1379.     if( !psl->fIslandMark)
  1380.       for( l = 0; l < 8; l++)
  1381.         if( pslPicked->lAdjacent[l] == psl->lSegId)
  1382.           if(   (ptlShift.x == psl->ptlModelXlate.x)
  1383.              && (ptlShift.y == psl->ptlModelXlate.y))
  1384.           {
  1385.             DosBeep( 600, 100);
  1386.             DosBeep( 1200, 50);
  1387.             MarkIsland( psl, TRUE);           /* mark the whole new island    */
  1388.             pslTemp = psl->pslNextIsland;     /* swap island ptrs             */
  1389.             psl->pslNextIsland = pslPicked->pslNextIsland;
  1390.             pslPicked->pslNextIsland = pslTemp;
  1391.           }
  1392.   MarkIsland( pslPicked, FALSE);              /* unmark the island            */
  1393.  
  1394.   pslPicked = NULL;
  1395.   lPickedSeg = 0;
  1396.  
  1397.   WinSetCapture( HWND_DESKTOP, (HWND)NULL);
  1398. }
  1399.  
  1400.  
  1401. /******************************************************************************/
  1402. /*                                                                                                                    */
  1403. /* DoHorzScroll will horizontally scroll the current contents of                    */
  1404. /* the client area and redraw the invalidated area                                           */
  1405. /*                                                                                                                         */
  1406. /******************************************************************************/
  1407. VOID DoHorzScroll(VOID)
  1408. {
  1409.   POINTL    aptlClient[3];
  1410.   HRGN      hrgn;
  1411.   MATRIXLF  matlf;
  1412.  
  1413.   if( ptsScrollPos.x > ptsScrollMax.x)     /* clip to range of scroll param   */
  1414.       ptsScrollPos.x = ptsScrollMax.x;
  1415.   if( ptsScrollPos.x < 0)
  1416.       ptsScrollPos.x = 0;
  1417.  
  1418.   if( ptsOldScrollPos.x != ptsScrollPos.x) /* only process change in position */
  1419.       WinSendMsg( hwndHorzScroll
  1420.                 , SBM_SETPOS
  1421.                 , MPFROM2SHORT( ptsScrollPos.x, 0)
  1422.                 , MPFROMLONG( NULL));
  1423.  
  1424.   /****************************************************************************/
  1425.   /* Scroll the window the reqd amount, using bitblt'ing (ScrollWindow)       */
  1426.   /* if any of the screen still in view, and paint into uncovered region;     */
  1427.   /* else repaint the whole client area.                                      */
  1428.   /****************************************************************************/
  1429.   hrgn = GpiCreateRegion( hpsClient, 0L, NULL);
  1430.   WinQueryWindowRect( hwndClient, (PRECTL)aptlClient);
  1431.   if( abs( ptsScrollPos.x - ptsOldScrollPos.x) <= ptsScrollMax.x)
  1432.   {
  1433.       WinScrollWindow( hwndClient
  1434.                      , (SHORT) (ptsOldScrollPos.x - ptsScrollPos.x)
  1435.                      , (SHORT) 0
  1436.                      , (PRECTL) NULL
  1437.                      , (PRECTL) NULL
  1438.                      , (HRGN) hrgn
  1439.                      , (PRECTL) NULL
  1440.                      , 0);
  1441.   } else
  1442.   {
  1443.       if (GpiSetRegion( hpsClient, hrgn, 1L, (PRECTL)aptlClient) == GPI_ERROR)
  1444.           DispError(habMain,hwndClient);
  1445.   }
  1446.   /****************************************************************************/
  1447.   /* adjust the default view matrix                                           */
  1448.   /****************************************************************************/
  1449.   if (GpiQueryDefaultViewMatrix( hpsClient, 9L, &matlf ) == GPI_ERROR)
  1450.       DispError(habMain,hwndClient);
  1451.   matlf.lM31 -= ptsScrollPos.x - ptsOldScrollPos.x;
  1452.   if (GpiSetDefaultViewMatrix( hpsClient, 9L, &matlf, TRANSFORM_REPLACE) == GPI_ERROR)
  1453.       DispError(habMain,hwndClient);
  1454.  
  1455.   DoDraw( hpsClient, hrgn, TRUE);     /* paint into the client area           */
  1456.   ptsOldScrollPos.x = ptsScrollPos.x;
  1457.   if (GpiDestroyRegion( hpsClient, hrgn) == GPI_ERROR)
  1458.       DispError(habMain,hwndClient);
  1459.  
  1460.   aptlClient[2] = aptlClient[0];
  1461.   if (!fFirstLoad)                  /* don't bother if no bitmap was read in */
  1462.   {
  1463.      if (GpiBitBlt( hpsBitmapBuff      /* update the off-screen client image */
  1464.                   , hpsClient
  1465.                   , 3L
  1466.                   , aptlClient
  1467.                   , ROP_SRCCOPY
  1468.                   , BBO_IGNORE ) == GPI_ERROR)
  1469.          DispError(habMain,hwndClient);
  1470.   }   /* end if () */
  1471. }
  1472.  
  1473. /******************************************************************************/
  1474. /*                                                                            */
  1475. /* DoVertScroll will vertically scroll the current contents of                */
  1476. /* the client area and redraw the invalidated area                            */
  1477. /*                                                                            */
  1478. /******************************************************************************/
  1479. VOID DoVertScroll(VOID)
  1480. {
  1481.   POINTL    aptlClient[3];
  1482.   HRGN      hrgn;
  1483.   MATRIXLF  matlf;
  1484.  
  1485.   if( ptsScrollPos.y > ptsScrollMax.y)
  1486.       ptsScrollPos.y = ptsScrollMax.y;
  1487.   if( ptsScrollPos.y < 0)
  1488.       ptsScrollPos.y = 0;
  1489.  
  1490.   if( ptsOldScrollPos.y != ptsScrollPos.y)
  1491.       WinSendMsg( hwndVertScroll
  1492.                 , SBM_SETPOS
  1493.                 , MPFROM2SHORT( ptsScrollPos.y, 0)
  1494.                 , MPFROMLONG( NULL));
  1495.  
  1496.   /****************************************************************************/
  1497.   /* Scroll the window the reqd amount, using bitblt'ing (ScrollWindow)       */
  1498.   /* if any of the screen still in view, and paint into uncovered region;     */
  1499.   /* else repaint the whole client area.                                      */
  1500.   /****************************************************************************/
  1501.   hrgn = GpiCreateRegion( hpsClient, 0L, NULL);
  1502.   WinQueryWindowRect( hwndClient, (PRECTL)aptlClient);
  1503.   if( abs( ptsScrollPos.y - ptsOldScrollPos.y) <= ptsScrollMax.y)
  1504.   {
  1505.       WinScrollWindow( hwndClient
  1506.                      , 0
  1507.                      , (SHORT) (ptsScrollPos.y - ptsOldScrollPos.y)
  1508.                      , (PRECTL) NULL
  1509.                      , (PRECTL) NULL
  1510.                      , (HRGN) hrgn
  1511.                      , (PRECTL) NULL
  1512.                      , 0);
  1513.   } else
  1514.   {
  1515.       if (GpiSetRegion( hpsClient, hrgn, 1L, (PRECTL)aptlClient) == GPI_ERROR)
  1516.           DispError(habMain,hwndClient);
  1517.   }
  1518.   if (GpiQueryDefaultViewMatrix( hpsClient, 9L, &matlf ) == GPI_ERROR)
  1519.       DispError(habMain,hwndClient);
  1520.   matlf.lM32 += ptsScrollPos.y - ptsOldScrollPos.y;
  1521.   if (GpiSetDefaultViewMatrix( hpsClient, 9L, &matlf, TRANSFORM_REPLACE) == GPI_ERROR)
  1522.       DispError(habMain,hwndClient);
  1523.  
  1524.   DoDraw( hpsClient, hrgn, TRUE);
  1525.   ptsOldScrollPos.y = ptsScrollPos.y;
  1526.   if (GpiDestroyRegion( hpsClient, hrgn) == GPI_ERROR)
  1527.       DispError(habMain,hwndClient);
  1528.  
  1529.   aptlClient[2] = aptlClient[0];
  1530.   if (!fFirstLoad)                  /* don't bother if no bitmap was read in */
  1531.   {
  1532.      if (GpiBitBlt( hpsBitmapBuff
  1533.                   , hpsClient
  1534.                   , 3L
  1535.                   , aptlClient
  1536.                   , ROP_SRCCOPY
  1537.                   , BBO_IGNORE ) == GPI_ERROR)
  1538.          DispError(habMain,hwndClient);
  1539.   }
  1540. }
  1541.  
  1542. /******************************************************************************
  1543. *
  1544. *  Name        : EnableMenu
  1545. *
  1546. *  Description : Enable/Disable bitmap size submenus
  1547. *
  1548. *  Parameters  : ULONG id        - menu id (ASSUME: id = submenu of FID_MAIN
  1549. *                BOOL  fEnable   - enable/disable?
  1550. *
  1551. *  Return      : VOID
  1552. *
  1553. ******************************************************************************/
  1554.  
  1555. VOID EnableMenu(ULONG id, BOOL fEnable)
  1556. {
  1557.     WinSendMsg(hwndMenu,                          /* global main menu handle */
  1558.        MM_SETITEMATTR,                                 /* set menu attribute */
  1559.        MPFROM2SHORT(id, TRUE),                                    /* menu id */
  1560.        MPFROM2SHORT(MIA_DISABLED,                      /* mask = disable bit */
  1561.                     fEnable ? ~MIA_DISABLED : MIA_DISABLED)); /* turn off/on */
  1562.  
  1563. }   /* end EnableMenu() */
  1564.  
  1565. /******************************************************************************
  1566. *
  1567. *  Name        : CheckMenu
  1568. *
  1569. *  Description : Check/Uncheck bitmap size submenus
  1570. *
  1571. *  Parameters  : ULONG id       - menu id  (ASSUME: id = submenu of FID_MAIN
  1572. *                BOOL  fCheck   - check/unckeck?
  1573. *
  1574. *  Return      : VOID
  1575. *
  1576. ******************************************************************************/
  1577.  
  1578. VOID CheckMenu(ULONG id, BOOL fCheck)
  1579. {
  1580.     WinSendMsg(hwndMenu,                          /* global main menu handle */
  1581.        MM_SETITEMATTR,                                 /* set menu attribute */
  1582.        MPFROM2SHORT(id, TRUE),                                    /* menu id */
  1583.        MPFROM2SHORT(MIA_CHECKED,                         /* mask = check bit */
  1584.                     fCheck ? MIA_CHECKED : ~MIA_CHECKED));    /* turn on/off */
  1585.  
  1586. }   /* end CheckMenu() */
  1587.  
  1588.  
  1589. /******************************************************************************/
  1590. /*                                                                                                                         */
  1591. /* adjust zoom factor and recalc the picture transform, then do a redraw of   */
  1592. /* whole screen                                                                                                   */
  1593. /*                                                                                                               */
  1594. /******************************************************************************/
  1595. VOID Zoom( VOID )
  1596. {
  1597.   ULONG  ulPostKillDraw, ulPostCt;
  1598.  
  1599.   DosQueryEventSem(hevKillDraw, &ulPostKillDraw);
  1600.  
  1601.   CalcBounds();
  1602.   DosQueryEventSem(hevKillDraw, &ulPostCt);
  1603.   if (ulPostKillDraw != ulPostCt)
  1604.   {
  1605.      DosResetEventSem(hevKillDraw, &ulPostCt);
  1606.      return;
  1607.   }
  1608.   CalcTransform( hwndClient);
  1609.   DosQueryEventSem(hevKillDraw, &ulPostCt);
  1610.   if (ulPostKillDraw != ulPostCt)
  1611.   {
  1612.      DosResetEventSem(hevKillDraw, &ulPostCt);
  1613.      return;
  1614.   }
  1615.   Redraw();
  1616. }
  1617.  
  1618. /******************************************************************************/
  1619. /*                                                                            */
  1620. /* Check the segment list for obvious errors.                                 */
  1621. /*                                                                            */
  1622. /******************************************************************************/
  1623. BOOL SegListCheck(INT iLoc)
  1624. {
  1625.   PSEGLIST   psl;
  1626.   CHAR       szMsg[50];
  1627.  
  1628.   szMsg[0] = '\0';
  1629.   for( psl = pslHead; psl != NULL; psl = psl->pslNext)
  1630.     if( (psl->lSegId < 1) || (psl->lSegId > lLastSegId) )
  1631.     {
  1632.       #if defined(DEBUG)
  1633.  
  1634.          sprintf( szMsg, "Bad head segment list, location %d", iLoc);
  1635.          WinMessageBox(HWND_DESKTOP, hwndFrame, szMsg, szErrorTitle, 0,
  1636.                         MB_OK | MB_ICONEXCLAMATION | MB_APPLMODAL);
  1637.       #endif
  1638.  
  1639.       return( FALSE);
  1640.     }
  1641.   for( psl = pslTail; psl != NULL; psl = psl->pslPrev)
  1642.     if( (psl->lSegId < 1) || (psl->lSegId > lLastSegId) )
  1643.     {
  1644.       #if defined(DEBUG)
  1645.  
  1646.          sprintf( szMsg, "Bad head segment list, location %d", iLoc);
  1647.          WinMessageBox(HWND_DESKTOP, hwndFrame, szMsg, szErrorTitle, 0,
  1648.                         MB_OK | MB_ICONEXCLAMATION | MB_APPLMODAL);
  1649.       #endif
  1650.  
  1651.       return( FALSE);
  1652.     }
  1653.   return( TRUE);
  1654. }
  1655.  
  1656. /******************************************************************************/
  1657. /*                                                                            */
  1658. /* DumpPicture will free the list and segment store for the picture           */
  1659. /*                                                                            */
  1660. /******************************************************************************/
  1661. BOOL DumpPicture(VOID)
  1662. {
  1663.   while( pslHead != NULL )
  1664.   {
  1665.     if (GpiSetBitmap( pslHead->hpsFill, NULLHANDLE) == (HBITMAP)BMB_ERROR)
  1666.         DispError(habMain,hwndClient);
  1667.     if (GpiDeleteBitmap( pslHead->hbmFill) == GPI_ERROR)
  1668.         DispError(habMain,hwndClient);
  1669.     if (GpiDestroyPS( pslHead->hpsFill) == GPI_ERROR)
  1670.         DispError(habMain,hwndClient);
  1671.     DevCloseDC( pslHead->hdcFill);
  1672.  
  1673.     if (GpiSetBitmap( pslHead->hpsHole, NULLHANDLE) == (HBITMAP)BMB_ERROR)
  1674.         DispError(habMain,hwndClient);
  1675.     if (GpiDeleteBitmap( pslHead->hbmHole) == GPI_ERROR)
  1676.         DispError(habMain,hwndClient);
  1677.     if (GpiDestroyPS( pslHead->hpsHole) == GPI_ERROR)
  1678.         DispError(habMain,hwndClient);
  1679.     DevCloseDC( pslHead->hdcHole);
  1680.  
  1681.     SegListUpdate( DEL_SEG, pslHead);
  1682.   }
  1683.  
  1684.   if( hbmBitmapSize)
  1685.   {
  1686.       if (GpiSetBitmap( hpsBitmapSize, NULLHANDLE) == (HBITMAP)BMB_ERROR)
  1687.           DispError(habMain,hwndClient);
  1688.       if (GpiDeleteBitmap( hbmBitmapSize) == GPI_ERROR)
  1689.           DispError(habMain,hwndClient);
  1690.   }
  1691.   if( hbmBitmapBuff)
  1692.   {
  1693.       if (GpiSetBitmap( hpsBitmapBuff, NULLHANDLE) == (HBITMAP)BMB_ERROR)
  1694.           DispError(habMain,hwndClient);
  1695.       if (GpiDeleteBitmap( hbmBitmapBuff) == GPI_ERROR)
  1696.           DispError(habMain,hwndClient);
  1697.   }
  1698.   if( hbmBitmapSave)
  1699.   {
  1700.       if (GpiSetBitmap( hpsBitmapSave, NULLHANDLE) == (HBITMAP)BMB_ERROR)
  1701.           DispError(habMain,hwndClient);
  1702.       if (GpiDeleteBitmap( hbmBitmapSave) == GPI_ERROR)
  1703.           DispError(habMain,hwndClient);
  1704.   }
  1705.  
  1706.   return( TRUE);
  1707. }
  1708.  
  1709. /******************************************************************************/
  1710. /*                                                                            */
  1711. /* Draw the picture into segment store.                                       */
  1712. /*                                                                            */
  1713. /******************************************************************************/
  1714. BOOL CreatePicture(SHORT sUpdate)
  1715. {
  1716.   POINTL             ptl, aptlSides[12], aptlControl[12];
  1717.   SEGLIST            sl;
  1718.   PSEGLIST           psl;
  1719.   LONG               l, lMinor, lNeighbor, alFuzz[36][4];
  1720.   SIZEL              sizl;
  1721.   BITMAPINFOHEADER2  bmp2;
  1722.   PBITMAPINFOHEADER2 pbmp2 = &bmp2;
  1723.   DATETIME           date;
  1724.   ULONG              ulPostCt;
  1725.  
  1726.   /****************************************************************************/
  1727.   /* compute some fuzz for the control points                                 */
  1728.   /****************************************************************************/
  1729.   DosGetDateTime( &date);
  1730.   srand( (USHORT)date.hundredths);
  1731.   for( l = 0; l < 36; l++)
  1732.     for( lMinor = 0; lMinor < 4; lMinor++)
  1733.       alFuzz[l][lMinor] = 50 * (rand() % 10);
  1734.  
  1735.   /****************************************************************************/
  1736.   /* reset the default viewing transform to identity                          */
  1737.   /****************************************************************************/
  1738.   SetDVTransform( (FIXED)UNITY
  1739.                 , (FIXED)0
  1740.                 , (FIXED)0
  1741.                 , (FIXED)UNITY
  1742.                 , 0L
  1743.                 , 0L
  1744.                 , TRANSFORM_REPLACE);
  1745.  
  1746.   /****************************************************************************/
  1747.   /* draw the pieces                                                          */
  1748.   /****************************************************************************/
  1749.   lLastSegId = 0;
  1750.   for( ptl.x = ptlBotLeft.x; ptl.x < ptlTopRight.x; ptl.x += 500)
  1751.   {
  1752.     DosQueryEventSem( hevTerminate, &ulPostCt);
  1753.     if( ulPostCt)
  1754.       break;
  1755.     for( ptl.y = ptlBotLeft.y; ptl.y < ptlTopRight.y; ptl.y += 500)
  1756.     {
  1757.       DosQueryEventSem( hevTerminate, &ulPostCt);
  1758.       if( ulPostCt)
  1759.               break;
  1760.       lLastSegId++;
  1761.  
  1762.       /************************************************************************/
  1763.       /* compute the piece outline control points                             */
  1764.       /************************************************************************/
  1765.       aptlControl[0].x = 250L;
  1766.       aptlControl[0].y = 500L;
  1767.       aptlControl[1].x = 250;
  1768.       aptlControl[1].y = -500L;
  1769.       aptlControl[2].x = 500L;
  1770.       aptlControl[2].y = 0L;
  1771.  
  1772.       aptlControl[3].x = 0L;
  1773.       aptlControl[3].y = 250L;
  1774.       aptlControl[4].x = 1000L;
  1775.       aptlControl[4].y = 250L;
  1776.       aptlControl[5].x = 500L;
  1777.       aptlControl[5].y = 500L;
  1778.  
  1779.       aptlControl[6].x = 250L;
  1780.       aptlControl[6].y = 0L;
  1781.       aptlControl[7].x = 250L;
  1782.       aptlControl[7].y = 1000L;
  1783.       aptlControl[8].x = 0L;
  1784.       aptlControl[8].y = 500L;
  1785.  
  1786.       aptlControl[9].x  = 500L;
  1787.       aptlControl[9].y  = 250L;
  1788.       aptlControl[10].x = -500L;
  1789.       aptlControl[10].y = 250L;
  1790.       aptlControl[11].x = 0L;
  1791.       aptlControl[11].y = 0L;
  1792.  
  1793.       if( ptl.y == ptlBotLeft.y)
  1794.       {
  1795.               aptlControl[0].y = 0L;
  1796.               aptlControl[1].y = 0L;
  1797.       }
  1798.  
  1799.       if( (ptl.x + 500) == ptlTopRight.x)
  1800.       {
  1801.         aptlControl[3].x = 500L;
  1802.               aptlControl[4].x = 500L;
  1803.       }
  1804.  
  1805.       if( (ptl.y + 500) == ptlTopRight.y)
  1806.       {
  1807.               aptlControl[6].y = 500L;
  1808.         aptlControl[7].y = 500L;
  1809.       }
  1810.  
  1811.       if( ptl.x == ptlBotLeft.x)
  1812.       {
  1813.               aptlControl[ 9].x = 0L;
  1814.               aptlControl[10].x = 0L;
  1815.       }
  1816.  
  1817.       /************************************************************************/
  1818.       /* compute the adjacent segments                                        */
  1819.       /************************************************************************/
  1820.       sl.lAdjacent[0] = lLastSegId - 7;
  1821.       sl.lAdjacent[1] = lLastSegId - 6;
  1822.       sl.lAdjacent[2] = lLastSegId - 5;
  1823.       sl.lAdjacent[3] = lLastSegId - 1;
  1824.       sl.lAdjacent[4] = lLastSegId + 1;
  1825.       sl.lAdjacent[5] = lLastSegId + 5;
  1826.       sl.lAdjacent[6] = lLastSegId + 6;
  1827.       sl.lAdjacent[7] = lLastSegId + 7;
  1828.       if( ptl.x == ptlBotLeft.x)
  1829.       {
  1830.               sl.lAdjacent[0] = 0;
  1831.               sl.lAdjacent[1] = 0;
  1832.               sl.lAdjacent[2] = 0;
  1833.       }
  1834.       if( ptl.y == ptlBotLeft.y)
  1835.       {
  1836.               sl.lAdjacent[0] = 0;
  1837.               sl.lAdjacent[3] = 0;
  1838.               sl.lAdjacent[5] = 0;
  1839.       }
  1840.       if( (ptl.x + 500) == ptlTopRight.x)
  1841.       {
  1842.               sl.lAdjacent[5] = 0;
  1843.               sl.lAdjacent[6] = 0;
  1844.               sl.lAdjacent[7] = 0;
  1845.       }
  1846.       if( (ptl.y + 500) == ptlTopRight.y)
  1847.       {
  1848.               sl.lAdjacent[2] = 0;
  1849.               sl.lAdjacent[4] = 0;
  1850.               sl.lAdjacent[7] = 0;
  1851.       }
  1852.  
  1853.       /************************************************************************/
  1854.       /* throw in some fuzz                                                   */
  1855.       /************************************************************************/
  1856.       if( sl.lAdjacent[3])
  1857.       {
  1858.               aptlControl[0].y  -= alFuzz[lLastSegId - 1][0];
  1859.               aptlControl[1].y  += alFuzz[lLastSegId - 1][1];
  1860.       }
  1861.  
  1862.       if( sl.lAdjacent[1])
  1863.       {
  1864.         aptlControl[9].x  -= alFuzz[lLastSegId - 1][2];
  1865.               aptlControl[10].x += alFuzz[lLastSegId - 1][3];
  1866.       }
  1867.  
  1868.       if( lNeighbor = sl.lAdjacent[4])
  1869.       {
  1870.         aptlControl[7].y  -= alFuzz[lNeighbor - 1][0];
  1871.               aptlControl[6].y  += alFuzz[lNeighbor - 1][1];
  1872.       }
  1873.  
  1874.       if( lNeighbor = sl.lAdjacent[6])
  1875.       {
  1876.               aptlControl[4].x  -= alFuzz[lNeighbor - 1][2];
  1877.               aptlControl[3].x  += alFuzz[lNeighbor - 1][3];
  1878.       }
  1879.  
  1880.       /************************************************************************/
  1881.       /* compute the piece control points in world coordinates                */
  1882.       /************************************************************************/
  1883.       for( l=0; l<12; l++)
  1884.       {
  1885.               aptlSides[l].x = ptl.x + aptlControl[l].x;
  1886.               aptlSides[l].y = ptl.y + aptlControl[l].y;
  1887.               sl.aptlSides[l] = aptlSides[l];
  1888.       }
  1889.  
  1890.       /************************************************************************/
  1891.       /* compute the dimensions of the matching rects for BitBlt              */
  1892.       /************************************************************************/
  1893.       sl.rclBitBlt.xLeft   = ptl.x - 250;
  1894.       sl.rclBitBlt.yBottom = ptl.y - 250;
  1895.       sl.rclBitBlt.xRight  = ptl.x + 750;
  1896.       sl.rclBitBlt.yTop    = ptl.y + 750;
  1897.       if( ptl.x == ptlBotLeft.x)
  1898.               sl.rclBitBlt.xLeft += 250;
  1899.       if( ptl.y == ptlBotLeft.y)
  1900.               sl.rclBitBlt.yBottom += 250;
  1901.       if( (ptl.x + 500) == ptlTopRight.x)
  1902.         sl.rclBitBlt.xRight -= 250;
  1903.       if( (ptl.y + 500) == ptlTopRight.y)
  1904.               sl.rclBitBlt.yTop -= 250;
  1905.  
  1906.       /************************************************************************/
  1907.       /* store the piece location                                             */
  1908.       /************************************************************************/
  1909.       sl.ptlLocation = ptl;
  1910.  
  1911.       /************************************************************************/
  1912.       /* create the masks                                                     */
  1913.       /************************************************************************/
  1914.       if( sUpdate == PICTURE_CREATE)
  1915.       {
  1916.               bmp2      = bmp2BitmapFile;
  1917.       if (bmp2.cbFix  == sizeof(BITMAPINFOHEADER))
  1918.          {
  1919.               sizl.cx = 2 +  ((PBITMAPINFOHEADER)pbmp2BitmapFile)->cx
  1920.                        * (sl.rclBitBlt.xRight - sl.rclBitBlt.xLeft)
  1921.                        / (ptlTopRight.x - ptlBotLeft.x);
  1922.               sizl.cy = 2 +  ((PBITMAPINFOHEADER)pbmp2BitmapFile)->cy
  1923.                        * (sl.rclBitBlt.yTop - sl.rclBitBlt.yBottom)
  1924.                        / (ptlTopRight.y - ptlBotLeft.y);
  1925.             ((PBITMAPINFOHEADER)pbmp2)->cx = LOUSHORT( sizl.cx);
  1926.             ((PBITMAPINFOHEADER)pbmp2)->cy = LOUSHORT( sizl.cy);
  1927.          }
  1928.       else
  1929.          {
  1930.               sizl.cx = 2 + ((pbmp2BitmapFile->cx
  1931.                        * (sl.rclBitBlt.xRight - sl.rclBitBlt.xLeft))
  1932.                        / (ptlTopRight.x - ptlBotLeft.x));
  1933.               sizl.cy = 2 + ((pbmp2BitmapFile->cy
  1934.                        * (sl.rclBitBlt.yTop - sl.rclBitBlt.yBottom))
  1935.                        / (ptlTopRight.y - ptlBotLeft.y));
  1936.              (pbmp2)->cx = LOUSHORT( sizl.cx);
  1937.              (pbmp2)->cy = LOUSHORT( sizl.cy);
  1938.         }
  1939.  
  1940.               if ((sl.hdcHole = DevOpenDC( habMain
  1941.                               , OD_MEMORY
  1942.                               , "*"
  1943.                               , 3L
  1944.                               , (PDEVOPENDATA)&dop
  1945.                               , NULLHANDLE)) == DEV_ERROR)
  1946.                  DispError(habMain,hwndClient);
  1947.               if ((sl.hpsHole = GpiCreatePS( habMain
  1948.                                 , sl.hdcHole
  1949.                                 , &sizl
  1950.                                 , PU_PELS | GPIA_ASSOC | GPIT_MICRO )) == GPI_ERROR)
  1951.                  DispError(habMain,hwndClient);
  1952.  
  1953.               if ((sl.hbmHole = GpiCreateBitmap( sl.hpsHole
  1954.                                     , pbmp2
  1955.                                     , 0L
  1956.                                     , NULL
  1957.                                     , NULL)) == (HBITMAP)GPI_ERROR)
  1958.                  DispError(habMain,hwndClient);
  1959.  
  1960.  
  1961.               if ((GpiSetBitmap( sl.hpsHole, sl.hbmHole)) == (HBITMAP)BMB_ERROR)
  1962.                  DispError(habMain,hwndClient);
  1963.  
  1964.  
  1965.               if ((sl.hdcFill = DevOpenDC( habMain
  1966.                               , OD_MEMORY
  1967.                               , "*"
  1968.                               , 3L
  1969.                               , (PDEVOPENDATA)&dop
  1970.                               , NULLHANDLE)) == DEV_ERROR)
  1971.                  DispError(habMain,hwndClient);
  1972.               if ((sl.hpsFill = GpiCreatePS( habMain
  1973.                                 , sl.hdcFill
  1974.                                 , &sizl
  1975.                                 , PU_PELS | GPIA_ASSOC | GPIT_MICRO )) == GPI_ERROR)
  1976.                  DispError(habMain,hwndClient);
  1977.               if ((sl.hbmFill = GpiCreateBitmap( sl.hpsFill
  1978.                                     , pbmp2
  1979.                                     , 0L
  1980.                                     , NULL
  1981.                                     , NULL)) == (HBITMAP)GPI_ERROR)
  1982.                  DispError(habMain,hwndClient);
  1983.  
  1984.               if ((GpiSetBitmap( sl.hpsFill, sl.hbmFill)) == (HBITMAP)BMB_ERROR)
  1985.                  DispError(habMain,hwndClient);
  1986.       }
  1987.  
  1988.  
  1989.       sl.fVisible        = TRUE;
  1990.       sl.lSegId          = lLastSegId;
  1991.       sl.fIslandMark     = FALSE;
  1992.       sl.ptlModelXlate.x = sl.ptlModelXlate.y = 0L;
  1993.       if( sUpdate == PICTURE_CREATE)
  1994.       {
  1995.               sl.pslNext           = NULL;
  1996.               sl.pslPrev           = NULL;
  1997.               SetRect( &sl);
  1998.               psl = SegListUpdate( ADD_TAIL_SEG, &sl);
  1999.        } else
  2000.        {
  2001.               psl = SegListGet( lLastSegId);
  2002.               psl->fIslandMark = FALSE;
  2003.               for( l=0; l<12; l++)
  2004.                 psl->aptlSides[l] = aptlSides[l];
  2005.               psl->ptlModelXlate = sl.ptlModelXlate;
  2006.               SetRect( psl);
  2007.        }
  2008.        psl->pslNextIsland = psl;        /* point to self ==> island of one    */
  2009.     }
  2010.   }
  2011.   if( ulPostCt)
  2012.       SendCommand( UM_DIE, (MPARAM)NULL, (MPARAM)NULL);
  2013.  
  2014.   return( TRUE);
  2015. }
  2016.  
  2017. /******************************************************************************/
  2018. /******************************************************************************/
  2019. /******************************************************************************/
  2020. VOID CheckPsl( psl)
  2021. PSEGLIST  psl;
  2022. {
  2023.   SHORT   s;
  2024.  
  2025.   for( s=2; s<12; s+=3)
  2026.     if( !WinPtInRect( habAsync, &psl->rclBitBlt, &psl->aptlSides[s]))
  2027.       break;
  2028. }
  2029.  
  2030. /******************************************************************************/
  2031. /*                                                                            */
  2032. /* Create the Size, Save and Buff bitmaps.                                    */
  2033. /*                                                                            */
  2034. /******************************************************************************/
  2035. BOOL PrepareBitmap(VOID)
  2036. {
  2037.   hbmBitmapSize    = GpiCreateBitmap( hpsBitmapSize
  2038.                                     , pbmp2BitmapFile
  2039.                                     , 0L
  2040.                                     , NULL
  2041.                                     , NULL);
  2042.   if( !hbmBitmapSize)
  2043.     {
  2044.     DispError(habMain,hwndClient);
  2045.     return( FALSE);
  2046.     }
  2047.   if (GpiSetBitmap( hpsBitmapSize, hbmBitmapSize) == (HBITMAP)BMB_ERROR)
  2048.      DispError(habMain,hwndClient);
  2049.  
  2050.   bmp2BitmapSave    = bmp2BitmapFile;
  2051.   if (pbmp2BitmapSave->cbFix  == sizeof(BITMAPINFOHEADER))
  2052.       {
  2053.       ((PBITMAPINFOHEADER)pbmp2BitmapSave)->cx = LOUSHORT( sizlMaxClient.cx);
  2054.       ((PBITMAPINFOHEADER)pbmp2BitmapSave)->cy = LOUSHORT( sizlMaxClient.cy);
  2055.       }
  2056.   else
  2057.       {
  2058.       (pbmp2BitmapSave)->cx = LOUSHORT(sizlMaxClient.cx);
  2059.       (pbmp2BitmapSave)->cy = LOUSHORT(sizlMaxClient.cy);
  2060.       }
  2061.   hbmBitmapSave     = GpiCreateBitmap( hpsBitmapSave
  2062.                                     , pbmp2BitmapSave
  2063.                                     , 0L
  2064.                                     , NULL
  2065.                                     , NULL);
  2066.   if( !hbmBitmapSave)
  2067.     {
  2068.      DispError(habMain,hwndClient);
  2069.      return( FALSE);
  2070.     }
  2071.   if (GpiSetBitmap( hpsBitmapSave, hbmBitmapSave) == (HBITMAP)BMB_ERROR)
  2072.      DispError(habMain,hwndClient);
  2073.  
  2074.  
  2075.   hbmBitmapBuff     = GpiCreateBitmap( hpsBitmapBuff
  2076.                                     , pbmp2BitmapSave
  2077.                                     , 0L
  2078.                                     , NULL
  2079.                                     , NULL);
  2080.   if( !hbmBitmapBuff)
  2081.     {
  2082.     DispError(habMain,hwndClient);
  2083.     return( FALSE);
  2084.     }
  2085.   if (GpiSetBitmap( hpsBitmapBuff, hbmBitmapBuff) == (HBITMAP)BMB_ERROR)
  2086.     DispError(habMain,hwndClient);
  2087.  
  2088.   return( TRUE);
  2089. }
  2090.  
  2091. /******************************************************************************
  2092. *
  2093. *  Name        : ReadBitmap
  2094. *
  2095. *  Description :
  2096. *
  2097. * Get the bitmap from disk.
  2098. * Note that there are 2 formats for bitmap files, one of which is archaic.
  2099. * Both formats are supported here.  All new bitmaps should follow the format
  2100. * in BITMAPFILEHEADER.
  2101. *
  2102. *  Concepts    :
  2103. *
  2104. *  API's       :
  2105. *
  2106. *  Parameters  : HFILE hfile
  2107. *
  2108. *  Return      : BOOL
  2109. *
  2110. *  Notes:
  2111. *
  2112. *   File Layout - size and layout of following map are dependent on the
  2113. *   type of bitmap.  The cbFix field of the structures is used to determine
  2114. *   the size of the structures which in turn identifies them.
  2115. *
  2116. *
  2117. *           SINGLE BITMAP FILE FORMAT
  2118. *
  2119. *   ┌─────────────────────────────────────────┐ offset 0
  2120. *   │  Bitmap File Header             (bfh2)  │ pbfh2->offBits contains data ─┐
  2121. *   │                                         │ offset (from begin of file)   │
  2122. *   ├─────────────────────────────────────────┤                               │
  2123. *   │  Bitmap Information Header      (bmp2)  │                               │
  2124. *   ├─────────────────────────────────────────┤                               │
  2125. *   │  Color Table of RGB Structures  (argb2) │                               │
  2126. *   ├─────────────────────────────────────────┤ <─────────────────────────────┘
  2127. *   │  Bitmap Data (scan lines)               │
  2128. *   │             .                           │
  2129. *   │             .                           │
  2130. *   │             .                           │
  2131. *   └─────────────────────────────────────────┘
  2132. *
  2133. *
  2134. *         BITMAP-ARRAY FILE FORMAT
  2135. *
  2136. *   ┌─────────────────────────────────────────┐ offset 0
  2137. *   │  Bitmap Array File Header       (baf2)  │
  2138. *   │  (only for bitmap arrays)               │
  2139. *   ├─────────────────────────────────────────┤
  2140. *   │  Bitmap File Header             (bfh2)  │ pbfh2->offBits contains data ─┐
  2141. *   │                                         │ offset (from begin of file)   │
  2142. *   ├─────────────────────────────────────────┤                               │
  2143. *   │  Bitmap Information Header      (bmp2)  │                               │
  2144. *   ├─────────────────────────────────────────┤                               │
  2145. *   │  Color Table of RGB Structures  (argb2) │                               │
  2146. *   ├─────────────────────────────────────────┤                               │
  2147. *   │     next Bitmap Array File Header       │                               │
  2148. *   │             .                           │                               │
  2149. *   │             .                           │                               │
  2150. *   │             .                           │                               │
  2151. *   ├─────────────────────────────────────────┤ <─────────────────────────────┘
  2152. *   │  1st Bitmap Data (scan lines)           │
  2153. *   │                                         │
  2154. *   │                                         │
  2155. *   ├─────────────────────────────────────────┤
  2156. *   │     next Bitmap Data (scan lines)       │
  2157. *   │             .                           │
  2158. *   │             .                           │
  2159. *   │             .                           │
  2160. *   └─────────────────────────────────────────┘
  2161. *
  2162. ******************************************************************************/
  2163.  
  2164. BOOL ReadBitmap(HFILE hfile)
  2165. {
  2166.    APIRET     rc;                                         /* API return code */
  2167.    BOOL       fRet = FALSE;                         /* Function return code. */
  2168.    FILESTATUS fsts;
  2169.    PBITMAPFILEHEADER2 pbfh2;                   /* can address any file types */
  2170.    PBITMAPINFOHEADER2 pbmp2;                     /* address any info headers */
  2171.    PBYTE  pFileBegin = NULL;                /* beginning of bitmap file data */
  2172.    ULONG  cbRead;                        /* Number of bytes read by DosRead. */
  2173.    ULONG  cScans, cScansRet;          /* number of scan lines in bitmap (cy) */
  2174.  
  2175.    /*
  2176.     *   Use Loop to avoid duplicate cleanup code.  If any errors, a break
  2177.     *   statement will jump directly to error cleanup code.
  2178.     */
  2179.  
  2180.    do
  2181.    {
  2182.       /*
  2183.        *   Find out how big the file is, allocate that much memory, and read
  2184.        *   in the entire bitmap.
  2185.        */
  2186.  
  2187.       rc =
  2188.       DosQueryFileInfo(hfile, 1, &fsts, sizeof(fsts));
  2189.       if (rc)
  2190.          break;                        /* jump to error code outside of loop */
  2191.  
  2192.       rc =
  2193.       DosAllocMem(
  2194.          (PPVOID) &pFileBegin,
  2195.          (ULONG)  fsts.cbFile,
  2196.          (ULONG)  PAG_READ | PAG_WRITE | PAG_COMMIT);
  2197.  
  2198.       if (rc)
  2199.          break;                        /* jump to error code outside of loop */
  2200.  
  2201.       if (DosRead( hfile, (PVOID)pFileBegin, fsts.cbFile, &cbRead))
  2202.          break;                        /* jump to error code outside of loop */
  2203.  
  2204.       /*
  2205.        *   If it's a bitmap-array, point to common file header.  Otherwise,
  2206.        *   point to beginning of file.
  2207.        */
  2208.  
  2209.       pbfh2 = (PBITMAPFILEHEADER2) pFileBegin;
  2210.       pbmp2 = NULL;                   /* only set this when we validate type */
  2211.  
  2212.       switch (pbfh2->usType)
  2213.       {
  2214.          case BFT_BITMAPARRAY:
  2215.  
  2216.             /*
  2217.              *   If this is a Bitmap-Array, adjust pointer to the normal
  2218.              *   file header.  We'll just use the first bitmap in the
  2219.              *   array and ignore other device forms.
  2220.              */
  2221.  
  2222.             pbfh2 = &(((PBITMAPARRAYFILEHEADER2) pFileBegin)->bfh2);
  2223.             pbmp2 = &pbfh2->bmp2;    /* pointer to info header (readability) */
  2224.             break;
  2225.  
  2226.          case BFT_BMAP:
  2227.  
  2228.             pbmp2 = &pbfh2->bmp2;    /* pointer to info header (readability) */
  2229.             break;
  2230.  
  2231.          default:      /* these formats aren't supported; don't set any ptrs */
  2232.          case BFT_ICON:
  2233.          case BFT_POINTER:
  2234.          case BFT_COLORICON:
  2235.          case BFT_COLORPOINTER:
  2236.  
  2237.             break;
  2238.  
  2239.       }   /* end switch (pbfh2->usType) */
  2240.  
  2241.       if (pbmp2 == NULL)
  2242.          break;        /* File format NOT SUPPORTED: break out to error code */
  2243.  
  2244.       /*
  2245.        *   Check to see if BMP file has an old structure, a new structure, or
  2246.        *   Windows structure.  Capture the common data and treat all bitmaps
  2247.        *   generically with pointer to new format.  API's will determine format
  2248.        *   using cbFixed field.
  2249.        *
  2250.        *   Windows bitmaps have the new format, but with less data fields
  2251.        *   than PM.  The old strucuture has some different size fields,
  2252.        *   though the field names are the same.
  2253.        *
  2254.        *
  2255.        *   NOTE: bitmap data is located by offsetting the beginning of the file
  2256.        *         by the offset contained in pbfh2->offBits.  This value is in
  2257.        *         the same relatie location for different format bitmap files.
  2258.        */
  2259.  
  2260.       if (pbmp2->cbFix == sizeof(BITMAPINFOHEADER))           /* old format? */
  2261.       {
  2262.          cScans = (ULONG) ((PBITMAPINFOHEADER)pbmp2)->cy;
  2263.       }
  2264.       else                               /* new PM format, Windows, or other */
  2265.       {
  2266.          cScans = pbmp2->cy;
  2267.       }
  2268.  
  2269.       memcpy(                      /* copy bitmap info into global structure */
  2270.          (PVOID) pbmp2BitmapFile,
  2271.          (PVOID) pbmp2,
  2272.          pbmp2->cbFix);      /* only copy specified size (varies per format) */
  2273.  
  2274.       hbmBitmapFile =
  2275.       GpiCreateBitmap(
  2276.          hpsBitmapFile,                         /* presentation-space handle */
  2277.          pbmp2BitmapFile,            /* address of structure for format data */
  2278.          0L,                                                      /* options */
  2279.          NULL,                            /* address of buffer of image data */
  2280.          NULL);                 /* address of structure for color and format */
  2281.  
  2282.       if (!hbmBitmapFile)
  2283.       {
  2284.          DispError(habMain,hwndClient);
  2285.          break;                        /* jump to error code outside of loop */
  2286.       }
  2287.  
  2288.       if (GpiSetBitmap( hpsBitmapFile, hbmBitmapFile) == (HBITMAP)BMB_ERROR)
  2289.       {
  2290.          DispError(habMain,hwndClient);
  2291.          break;                        /* jump to error code outside of loop */
  2292.       }
  2293.  
  2294.       /*
  2295.        *   Tell GPI to put the bits into the thread's PS. The function returns
  2296.        *   the number of scan lines of the bitmap that were copied.  We want
  2297.        *   all of them at once.
  2298.        */
  2299.  
  2300.       cScansRet =
  2301.       GpiSetBitmapBits(
  2302.          hpsBitmapFile,                         /* presentation-space handle */
  2303.          0L,                                     /* index of first scan line */
  2304.          cScans,                                     /* number of scan lines */
  2305.          pFileBegin + pbfh2->offBits,              /* address of bitmap data */
  2306.          (PBITMAPINFO2) pbmp2);            /* address of bitmap header table */
  2307.  
  2308.       if (cScansRet != cScans)                       /* original # of scans? */
  2309.       {
  2310.          DispError(habMain,hwndClient);
  2311.          break;                        /* jump to error code outside of loop */
  2312.       }
  2313.  
  2314.       DosFreeMem( pFileBegin);
  2315.       DosClose( hfile);
  2316.       return TRUE;                                    /* function successful */
  2317.  
  2318.    } while (FALSE); /* fall through loop first time */
  2319.  
  2320.     /*
  2321.      *   Close the file, free the buffer space and leave.  This is an error exit
  2322.      *   point from the function.  Cleanup code is here to avoid duplicate code
  2323.      *   after each operation.
  2324.      */
  2325.  
  2326.     if (pFileBegin != NULL)
  2327.        DosFreeMem( pFileBegin);
  2328.     DosClose( hfile);
  2329.  
  2330.     return FALSE;                                         /* function failed */
  2331.  
  2332. }   /* end ReadBitmap() */
  2333.  
  2334.  
  2335. /**************************************************************************/
  2336. /* DispError -- report an error returned from an API service.             */
  2337. /*                                                                        */
  2338. /* The error message is displayed using a message box                     */
  2339. /*                                                                        */
  2340. /**************************************************************************/
  2341. VOID DispErrorMsg(HAB hab, HWND hwndFrame, PCH FileName, LONG LineNum)
  2342. {
  2343.  PERRINFO  pErrInfoBlk;
  2344.  PSZ       pszOffSet, pszErrMsg;
  2345.  ERRORID   ErrorId;
  2346.  PCH       ErrorStr;
  2347.  CHAR      szbuff[125];
  2348.  
  2349.    DosBeep(800,10);
  2350.    #if defined(DEBUG)
  2351.       DosBeep(800,10);
  2352.       DosBeep(800,10);
  2353.       DosBeep(800,10);
  2354.       DosBeep(800,10);
  2355.       DosBeep(800,10);
  2356.    #endif   /* defined(DEBUG) */
  2357.  
  2358.    if (!hab)
  2359.    {                                     /* Non-PM Error */
  2360.       WinLoadString( habMain,0, IDS_UNKNOWNMSG, sizeof(szbuff), (PSZ)szbuff);
  2361.       ErrorStr = malloc(strlen(szbuff)+strlen(FileName)+10);
  2362.       sprintf(ErrorStr, szbuff, FileName, LineNum);
  2363.       WinMessageBox(HWND_DESKTOP,         /* Parent window is desk top */
  2364.                     hwndFrame,            /* Owner window is our frame */
  2365.                     (PSZ)ErrorStr,        /* PMWIN Error message       */
  2366.                     szErrorTitle,         /* Title bar message         */
  2367.                     MSGBOXID,             /* Message identifier        */
  2368.                     MB_MOVEABLE | MB_CUACRITICAL | MB_CANCEL ); /* Flags */
  2369.       free(ErrorStr);
  2370.       return;
  2371.    }
  2372.  
  2373.    ErrorId = WinGetLastError(hab);
  2374.  
  2375.    if ((pErrInfoBlk = WinGetErrorInfo(hab)) != (PERRINFO)NULL)
  2376.    {
  2377.       pszOffSet = ((PSZ)pErrInfoBlk) + pErrInfoBlk->offaoffszMsg;
  2378.       pszErrMsg = ((PSZ)pErrInfoBlk) + *((PULONG)pszOffSet);
  2379.  
  2380.       WinLoadString( habMain,0, IDS_ERRORMSG, sizeof(szbuff), (PSZ)szbuff);
  2381.       ErrorStr = malloc(strlen(szbuff)+strlen(pszErrMsg)+strlen(FileName)+10);
  2382.       sprintf(ErrorStr, szbuff, pszErrMsg, FileName, LineNum);
  2383.  
  2384.       WinMessageBox(HWND_DESKTOP,         /* Parent window is desk top */
  2385.                     hwndFrame,            /* Owner window is our frame */
  2386.                     (PSZ)ErrorStr,        /* PMWIN Error message       */
  2387.                     szErrorTitle,         /* Title bar message         */
  2388.                     MSGBOXID,             /* Message identifier        */
  2389.                     MB_MOVEABLE | MB_CUACRITICAL | MB_CANCEL ); /* Flags */
  2390.  
  2391.       free(ErrorStr);
  2392.  
  2393.       WinFreeErrorInfo(pErrInfoBlk);
  2394.    }
  2395. }
  2396.  
  2397.  
  2398. /********************************************************************/
  2399.  
  2400. /* DosGetThreadInfo Call Only Temp Call for the LX Toronto Compiler */
  2401.  
  2402. /********************************************************************/
  2403.  
  2404. APIRET DosGetThreadInfo(PTIB *pptib,PPIB *pppib)
  2405. {
  2406.  
  2407.       return( DosGetInfoBlocks(pptib,pppib) );
  2408. }
  2409.  
  2410. /*******************************  END JIGSAW.C  ******************************/
  2411.