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