home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / rexx / library2 / gbmrexx / gbmv2 / gbmv2.c next >
C/C++ Source or Header  |  1993-11-10  |  100KB  |  3,789 lines

  1. /*
  2.  
  3. GBMV2.C  Display a bitmap
  4.  
  5. */
  6.  
  7. /*...sincludes:0:*/
  8. #define    INCL_DOS
  9. #define    INCL_WIN
  10. #define    INCL_GPI
  11. #define    INCL_DEV
  12. #define    INCL_SPL
  13. #define    INCL_SPLDOSPRINT
  14. #define    INCL_BITMAPFILEFORMAT
  15. #include <os2.h>
  16. #include <stdio.h>
  17. #include <ctype.h>
  18. #include <stdlib.h>
  19. #include <stdarg.h>
  20. #include <string.h>
  21. #include <malloc.h>
  22. #include <memory.h>
  23. #include <process.h>
  24. #include <math.h>
  25. #include <sys/types.h>
  26. #include <sys/stat.h>
  27. #include <io.h>
  28. #include <fcntl.h>
  29. #include "standard.h"
  30. #include "scroll.h"
  31. #include "gbm.h"
  32. #include "gbmtrunc.h"
  33. #include "gbmerr.h"
  34. #include "gbmht.h"
  35. #include "gbmhist.h"
  36. #include "gbmmir.h"
  37. #include "gbmrect.h"
  38. #include "gbmdlg.h"
  39. #include "gbmdlgrc.h"
  40. #include "gbmv2.h"
  41. #include "gbmv2hlp.h"
  42.  
  43. /*...vscroll\46\h:0:*/
  44. /*...vgbm\46\h:0:*/
  45. /*...vgbmtrunc\46\h:0:*/
  46. /*...vgbmerr\46\h:0:*/
  47. /*...vgbmht\46\h:0:*/
  48. /*...vgbmhist\46\h:0:*/
  49. /*...vgbmmir\46\h:0:*/
  50. /*...vgbmrect\46\h:0:*/
  51. /*...vgbmdlg\46\h:0:*/
  52. /*...vgbmdlgrc\46\h:0:*/
  53. /*...vgbmv2\46\h:0:*/
  54. /*...vgbmv2hlp\46\h:0:*/
  55. /*...e*/
  56. /*...suseful:0:*/
  57. /* Windows has these 2 */
  58.  
  59. /*...sEnableMenuItem:0:*/
  60. static VOID EnableMenuItem(HWND hWndMenu, SHORT idMenuItem, BOOL fEnabled)
  61.     {
  62.     WinSendMsg(hWndMenu, MM_SETITEMATTR,
  63.            MPFROM2SHORT(idMenuItem, TRUE),
  64.            MPFROM2SHORT(MIA_DISABLED, ( fEnabled ) ? 0 : MIA_DISABLED));
  65.     }
  66. /*...e*/
  67. /*...sCheckMenuItem:0:*/
  68. static VOID CheckMenuItem(HWND hWndMenu, SHORT idMenuItem, BOOL fChecked)
  69.     {
  70.     WinSendMsg(hWndMenu, MM_SETITEMATTR,
  71.            MPFROM2SHORT(idMenuItem, TRUE),
  72.            MPFROM2SHORT(MIA_CHECKED, ( fChecked ) ? MIA_CHECKED : 0));
  73.     }
  74. /*...e*/
  75.  
  76. /* These are generally useful */
  77.  
  78. /*...sWarning:0:*/
  79. static VOID Warning(HWND hwnd, const CHAR *szFmt, ...)
  80.     {
  81.     va_list vars;
  82.     CHAR sz [256+1];
  83.  
  84.     va_start(vars, szFmt);
  85.     vsprintf(sz, szFmt, vars);
  86.     va_end(vars);
  87.     WinMessageBox(HWND_DESKTOP, hwnd, sz, NULL, 0, MB_OK | MB_WARNING | MB_MOVEABLE);
  88.     }
  89. /*...e*/
  90.  
  91. /*...sTidySysMenu:0:*/
  92. static VOID TidySysMenu(HWND hwndFrame)
  93.     {
  94.     HWND hwndSysMenu = WinWindowFromID(hwndFrame, FID_SYSMENU);
  95.     USHORT id        = SHORT1FROMMR(WinSendMsg(hwndSysMenu, MM_ITEMIDFROMPOSITION, MPFROMSHORT(0), NULL));
  96.     MENUITEM mi;
  97.     HWND hwndSysSubMenu;
  98.     SHORT sInx, cItems;
  99.     
  100.     WinSendMsg(hwndSysMenu, MM_QUERYITEM, MPFROM2SHORT(id, FALSE), MPFROMP(&mi));
  101.     hwndSysSubMenu = mi.hwndSubMenu;
  102.     
  103.     cItems = SHORT1FROMMR(WinSendMsg(hwndSysSubMenu, MM_QUERYITEMCOUNT, NULL, NULL));
  104.     
  105.     for ( sInx = cItems - 1; sInx >= 0; sInx-- )
  106.         {
  107.         id = SHORT1FROMMR(WinSendMsg(hwndSysSubMenu, MM_ITEMIDFROMPOSITION, MPFROMSHORT(sInx), NULL));
  108.  
  109.         WinSendMsg(hwndSysSubMenu, MM_QUERYITEM,
  110.                MPFROM2SHORT(id, FALSE), MPFROMP(&mi));
  111.         if ( (mi.afStyle     & MIS_SEPARATOR) != 0 ||
  112.              (mi.afAttribute & MIA_DISABLED ) != 0 ||
  113.              id == (USHORT) SC_TASKMANAGER         )
  114.             WinSendMsg(hwndSysSubMenu, MM_DELETEITEM,
  115.                    MPFROM2SHORT(id, FALSE), NULL);
  116.         }
  117.     }    
  118. /*...e*/
  119. /*...sRestrictEntryfield:0:*/
  120. /*
  121. This is a function you call on an WC_ENTRYFIELD window that causes the window
  122. to only allow strings in one set to be used and also not allow strings in
  123. another set.
  124. */
  125.  
  126. typedef struct /* restr */
  127.         {
  128.         CHAR *szIfIn;
  129.         CHAR *szMapTo;
  130.         CHAR *szAllowed;
  131.         CHAR *szNotAllowed;
  132.         PFNWP pfnwpOld;
  133.         } RESTR;
  134.  
  135. /*...sRestrictSubProc:0:*/
  136. #define L_ENTRYMAX      500
  137.  
  138. /*...sMapChar:0:*/
  139. static CHAR MapChar(RESTR *prestr, CHAR ch)
  140.         {
  141.         CHAR *sz;
  142.  
  143.         if ( prestr -> szIfIn == NULL || prestr -> szMapTo == NULL )
  144.                 return ( ch );
  145.  
  146.         if ( (sz = strchr(prestr -> szIfIn, ch)) == NULL )
  147.                 return ( ch );
  148.  
  149.         return ( prestr -> szMapTo [sz - prestr -> szIfIn] );
  150.         }
  151. /*...e*/
  152. /*...sProblemAllowed:0:*/
  153. static BOOL ProblemAllowed(RESTR *prestr, CHAR ch)
  154.         {
  155.         return ( prestr -> szAllowed != NULL && strchr(prestr -> szAllowed, ch) == NULL );
  156.         }                                                        /* More >>> */
  157. /*...e*/
  158. /*...sProblemNotAllowed:0:*/
  159. static BOOL ProblemNotAllowed(RESTR *prestr, CHAR ch)
  160.         {
  161.         return ( prestr -> szNotAllowed != NULL && strchr(prestr -> szNotAllowed, ch) != NULL );
  162.         }                                                        /* More >>> */
  163. /*...e*/
  164.  
  165. MRESULT _System RestrictSubProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  166.         {
  167.         RESTR *prestr = (RESTR *) WinQueryWindowULong(hwnd, QWL_USER);
  168.         PFNWP pfnwpOld = prestr -> pfnwpOld;
  169.  
  170.         switch ( (int) msg )
  171.                 {
  172. /*...sWM_DESTROY \45\ clean up:16:*/
  173. case WM_DESTROY:
  174.         free(prestr);
  175.         break;
  176. /*...e*/
  177. /*...sWM_CHAR    \45\ map incoming chars:16:*/
  178. case WM_CHAR:
  179.         {
  180.         USHORT fs     = SHORT1FROMMP(mp1);
  181.         CHAR   ch     = (CHAR) SHORT1FROMMP(mp2);
  182.         USHORT vkey   = SHORT2FROMMP(mp2);
  183.  
  184.     if ( (fs & KC_VIRTUALKEY) != 0 && (fs & KC_ALT) != 0 &&
  185.          (vkey == VK_LEFT || vkey == VK_RIGHT || vkey == VK_UP || vkey == VK_DOWN) )
  186.         /* If we let the entryfield get these, it won't process them */
  187.         /* It will pass them to its owner, the dialog. */
  188.         /* The dialog will use them to change the focus! */
  189.         /* This is not desired, as Alt+NNN is being used */
  190.         return ( (MRESULT) 0 );
  191.  
  192.         if ( (fs & KC_CHAR) != 0 && ch != '\b' && ch != '\t' )
  193.                 {
  194.                 ch = MapChar(prestr, ch);
  195.  
  196.                 if ( ProblemAllowed(prestr, ch) ||
  197.                      ProblemNotAllowed(prestr, ch) )
  198.                         {
  199.                         WinAlarm(HWND_DESKTOP, WA_WARNING);
  200.                         return ( (MRESULT) 0 );
  201.                         }
  202.  
  203.                 mp2 = MPFROM2SHORT(ch, vkey);
  204.                 }
  205.         }
  206.         break;
  207. /*...e*/
  208. /*...sEM_PASTE   \45\ paste then alter chars:16:*/
  209. case EM_PASTE:
  210.         {
  211.         MRESULT mr = (*pfnwpOld)(hwnd, msg, mp1, mp2);
  212.         MRESULT mrSel = WinSendMsg(hwnd, EM_QUERYSEL, NULL, NULL);
  213.         CHAR sz [L_ENTRYMAX+1], *szTmp;
  214.  
  215.         WinQueryWindowText(hwnd, L_ENTRYMAX, sz);
  216.         for ( szTmp = sz; *szTmp; szTmp++ )
  217.                 {
  218.                 *szTmp = MapChar(prestr, *szTmp);
  219.                 if ( ProblemAllowed(prestr, *szTmp) ||
  220.                      ProblemNotAllowed(prestr, *szTmp) )
  221.                         {
  222.                         strcpy(szTmp, szTmp + 1);
  223.                         szTmp--;
  224.                         }
  225.                 }
  226.         WinSetWindowText(hwnd, sz);
  227.         WinSendMsg(hwnd, EM_SETSEL, mrSel, NULL);
  228.  
  229.         return ( mr );
  230.         }
  231. /*...e*/
  232.                 }
  233.         return ( (*pfnwpOld)(hwnd, msg, mp1, mp2) );
  234.         }
  235. /*...e*/
  236.  
  237. static BOOL RestrictEntryfield(
  238.         HWND hwnd,
  239.         CHAR *szIfIn,
  240.         CHAR *szMapTo,
  241.         CHAR *szAllowed,
  242.         CHAR *szNotAllowed
  243.         )
  244.         {
  245.         RESTR *prestr;
  246.  
  247.         if ( (prestr = malloc(sizeof(RESTR))) == NULL )
  248.                 return ( FALSE );
  249.  
  250.         prestr -> szIfIn       = szIfIn      ;
  251.         prestr -> szMapTo      = szMapTo     ;
  252.         prestr -> szAllowed    = szAllowed   ;
  253.         prestr -> szNotAllowed = szNotAllowed;
  254.         prestr -> pfnwpOld     = WinSubclassWindow(hwnd, RestrictSubProc);
  255.  
  256.         WinSetWindowULong(hwnd, QWL_USER, (LONG) prestr);
  257.  
  258.         return ( TRUE );
  259.         }
  260. /*...e*/
  261. /*...e*/
  262. /*...spriority:0:*/
  263. static VOID LowPri(VOID)
  264.     {
  265. #ifdef NEVER
  266.     DosSetPrty(PRTYS_THREAD, PRTYC_IDLETIME, 0, 0);
  267. #endif
  268.     DosSetPrty(PRTYS_THREAD, PRTYC_REGULAR, PRTYD_MINIMUM, 0);
  269.     }
  270.  
  271. static VOID RegPri(VOID)
  272.     {
  273.     DosSetPrty(PRTYS_THREAD, PRTYC_REGULAR, 0, 0);
  274.     }
  275. /*...e*/
  276. /*...sbmputils:0:*/
  277. /*
  278.  
  279. All bitmaps referred to below should not be selected into a hps at time of
  280. call. They will be selected into screen or printer compatible hps's during the
  281. call and be unselected afterwards. Because of this, you will find that the
  282. colours change in the bitmap when using the BmpPrint call. The solution is
  283. to copy the desired bitmap, call BmpPrint on it, then to discard it.
  284.  
  285. */
  286.  
  287. typedef USHORT BMP_ERR;
  288. #define    BMP_ERR_OK    0        /* All went ok                       */
  289. #define    BMP_ERR_MEM    1        /* Out of memory                     */
  290. #define    BMP_ERR_RES    2        /* Out of PM resources (DC, PS etc.) */
  291. #define    BMP_ERR_QUERY    3        /* Can't query queue info            */
  292. #define    BMP_ERR_PRINTER    4        /* Can't find the printer            */
  293. #define    BMP_ERR_PRINT    5        /* Error in the printing itself      */
  294.  
  295. /*...sBmpBlitter          \45\ blit one part of one bitmap to part of another:0:*/
  296. BMP_ERR BmpBlitter(
  297.     HAB hab,
  298.     HBITMAP hbmSrc, RECTL rclSrc,
  299.     HBITMAP hbmDst, RECTL rclDst
  300.     )
  301.     {
  302.     HDC hdcSrc, hdcDst;
  303.     HPS hpsSrc, hpsDst;
  304.     BITMAPINFOHEADER2 bmp;
  305.     SIZEL sizl;
  306.     POINTL aptl [4];
  307.  
  308.     if ( (hdcSrc = DevOpenDC(hab, OD_MEMORY, "*", 0L, (PDEVOPENDATA) NULL, (HDC) NULL)) == (HDC) NULL )
  309.         return ( BMP_ERR_RES );
  310.  
  311.     bmp.cbFix = sizeof(BITMAPINFOHEADER2);
  312.     GpiQueryBitmapInfoHeader(hbmSrc, &bmp);
  313.     sizl.cx = bmp.cx; sizl.cy = bmp.cy;
  314.     if ( (hpsSrc = GpiCreatePS(hab, hdcSrc, &sizl, PU_PELS | GPIF_DEFAULT | GPIT_MICRO | GPIA_ASSOC)) == (HPS) NULL )
  315.         {
  316.         DevCloseDC(hdcSrc);
  317.         return ( BMP_ERR_RES );
  318.         }
  319.  
  320.     if ( (hdcDst = DevOpenDC(hab, OD_MEMORY, "*", 0L, (PDEVOPENDATA) NULL, (HDC) NULL)) == (HDC) NULL )
  321.         {
  322.         GpiDestroyPS(hpsSrc); DevCloseDC(hdcSrc);
  323.         return ( BMP_ERR_RES );
  324.         }
  325.  
  326.     bmp.cbFix = sizeof(BITMAPINFOHEADER2);
  327.     GpiQueryBitmapInfoHeader(hbmDst, &bmp);
  328.     sizl.cx = bmp.cx; sizl.cy = bmp.cy;
  329.     if ( (hpsDst = GpiCreatePS(hab, hdcDst, &sizl, PU_PELS | GPIF_DEFAULT | GPIT_MICRO | GPIA_ASSOC)) == (HPS) NULL )
  330.         {
  331.         DevCloseDC(hdcDst);
  332.         GpiDestroyPS(hpsSrc); DevCloseDC(hdcSrc);
  333.         return ( BMP_ERR_RES );
  334.         }
  335.  
  336.     GpiSetBitmap(hpsSrc, hbmSrc);
  337.     GpiSetBitmap(hpsDst, hbmDst);
  338.  
  339.     aptl [0].x = rclDst.xLeft;
  340.     aptl [0].y = rclDst.yBottom;
  341.     aptl [1].x = rclDst.xRight;
  342.     aptl [1].y = rclDst.yTop;
  343.     aptl [2].x = rclSrc.xLeft;
  344.     aptl [2].y = rclSrc.yBottom;
  345.     aptl [3].x = rclSrc.xRight;
  346.     aptl [3].y = rclSrc.yTop;
  347.  
  348.     if ( aptl [1].x - aptl [0].x == aptl [3].x - aptl [2].x &&
  349.          aptl [1].y - aptl [0].y == aptl [3].y - aptl [2].y )
  350.         GpiBitBlt(hpsDst, hpsSrc, 3L, aptl, ROP_SRCCOPY, BBO_IGNORE);
  351.     else
  352.         GpiBitBlt(hpsDst, hpsSrc, 4L, aptl, ROP_SRCCOPY, BBO_IGNORE);
  353.  
  354.     GpiSetBitmap(hpsDst, (HBITMAP) NULL); GpiDestroyPS(hpsDst); DevCloseDC(hdcDst);
  355.     GpiSetBitmap(hpsSrc, (HBITMAP) NULL); GpiDestroyPS(hpsSrc); DevCloseDC(hdcSrc);
  356.  
  357.     return ( BMP_ERR_OK );
  358.     }
  359. /*...e*/
  360. /*...sBmpCopySubrectangle \45\ make a new bitmap from a bit of the first:0:*/
  361. BMP_ERR BmpCopySubrectangle(HAB hab, HBITMAP hbmSrc, RECTL rclSrc, HBITMAP *phbmDst)
  362.     {
  363.     BITMAPINFOHEADER2 bmp;
  364.     HBITMAP hbmDst;
  365.     RECTL rclDst;
  366.     SIZEL sizl;
  367.     USHORT rc;
  368.     HDC hdc;
  369.     HPS hps;
  370.  
  371.     bmp.cbFix = sizeof(BITMAPINFOHEADER2);
  372.     GpiQueryBitmapInfoHeader(hbmSrc, &bmp);
  373.  
  374.     bmp.cx = (USHORT) (rclSrc.xRight - rclSrc.xLeft);
  375.     bmp.cy = (USHORT) (rclSrc.yTop - rclSrc.yBottom);
  376.  
  377.     if ( (hdc = DevOpenDC(hab, OD_MEMORY, "*", 0L, (PDEVOPENDATA) NULL, (HDC) NULL)) == (HDC) NULL )
  378.         return ( BMP_ERR_RES );
  379.  
  380.     sizl.cx = bmp.cx; sizl.cy = bmp.cy;
  381.     if ( (hps = GpiCreatePS(hab, hdc, &sizl, PU_PELS | GPIF_DEFAULT | GPIT_MICRO | GPIA_ASSOC)) == (HPS) NULL )
  382.         {
  383.         DevCloseDC(hdc);
  384.         return ( BMP_ERR_RES );
  385.         }
  386.  
  387.     if ( (hbmDst = GpiCreateBitmap(hps, &bmp, 0L, NULL, NULL)) == (HBITMAP) NULL )
  388.         {
  389.         GpiDestroyPS(hps);
  390.         DevCloseDC(hdc);
  391.         return ( BMP_ERR_MEM );
  392.         }
  393.  
  394.     GpiDestroyPS(hps);
  395.     DevCloseDC(hdc);
  396.  
  397.     rclDst.xLeft = 0; rclDst.xRight = bmp.cx;
  398.     rclDst.yBottom = 0; rclDst.yTop = bmp.cy;
  399.  
  400.     if ( (rc = BmpBlitter(hab, hbmSrc, rclSrc, hbmDst, rclDst)) != BMP_ERR_OK )
  401.         {
  402.         GpiDeleteBitmap(hbmDst);
  403.         return ( rc );
  404.         }
  405.  
  406.     *phbmDst = hbmDst;
  407.  
  408.     return ( BMP_ERR_OK );
  409.     }
  410. /*...e*/
  411. /*...sBmpCopy             \45\ make a new bitmap from all of the first:0:*/
  412. BMP_ERR BmpCopy(HAB hab, HBITMAP hbmSrc, HBITMAP *phbmDst)
  413.     {
  414.     BITMAPINFOHEADER2 bmp;
  415.     RECTL rclSrc;
  416.  
  417.     bmp.cbFix = sizeof(BITMAPINFOHEADER2);
  418.     GpiQueryBitmapInfoHeader(hbmSrc, &bmp);
  419.  
  420.     rclSrc.xLeft = 0; rclSrc.xRight = bmp.cx;
  421.     rclSrc.yBottom = 0; rclSrc.yTop = bmp.cy;
  422.  
  423.     return ( BmpCopySubrectangle(hab, hbmSrc, rclSrc, phbmDst) );
  424.     }
  425. /*...e*/
  426. /*...sBmpPrint            \45\ print a bitmap:0:*/
  427. /*...sEnquireQueueDetails:0:*/
  428. static BOOL EnquireQueueDetails(
  429.     CHAR *szQueue,
  430.     CHAR *szLogAddress,
  431.     CHAR *szDriverName,
  432.     CHAR *szNameWPS,
  433.     DRIVDATA **ppdriv
  434.     )
  435.     {
  436.     ULONG cb; PRQINFO3 *ppq3;
  437.  
  438.     SplQueryQueue(NULL, szQueue, 3, NULL, 0, &cb);
  439.     if ( cb < sizeof(PRQINFO3) )
  440.         return ( FALSE );
  441.     if ( (ppq3 = (PRQINFO3 *) malloc(cb)) == (PRQINFO3 *) NULL )
  442.         return ( FALSE );
  443.     SplQueryQueue(NULL, szQueue, 3, ppq3, cb, &cb);
  444.     strcpy(szNameWPS, ppq3 -> pszComment);
  445.     strcpy(szLogAddress, szQueue);
  446.     sscanf(ppq3 -> pszDriverName, "%[^.,;]", szDriverName);
  447.     *ppdriv = ppq3 -> pDriverData;
  448.     free(ppq3);
  449.     return ( TRUE );
  450.     }
  451. /*...e*/
  452. /*...sPrinterInfo:0:*/
  453. static BOOL PrinterInfo(HPS hpsPrinter, CHAR *szNameWPS)
  454.     {
  455.     HDC hdcPrinter = GpiQueryDevice(hpsPrinter);
  456.     LONG lBitCount, lPlanes, lColors, lPhysColors;
  457.     SIZEL sizlPrinter;
  458.     CHAR sz [100+1];
  459.  
  460.     GpiQueryPS(hpsPrinter, &sizlPrinter);
  461.  
  462.     DevQueryCaps(hdcPrinter, CAPS_COLOR_BITCOUNT, 1L, &lBitCount  );
  463.     DevQueryCaps(hdcPrinter, CAPS_COLOR_PLANES  , 1L, &lPlanes    );
  464.     DevQueryCaps(hdcPrinter, CAPS_COLORS        , 1L, &lColors    );
  465.     DevQueryCaps(hdcPrinter, CAPS_PHYS_COLORS   , 1L, &lPhysColors);
  466.  
  467.     sprintf(sz, "%s: %ldx%ld, %ld bits, %ld planes, %ld colors, %ld physical colors?",
  468.         szNameWPS, sizlPrinter.cx, sizlPrinter.cy, lBitCount, lPlanes, lColors, lPhysColors);
  469.  
  470.     return ( WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, sz, "GbmV2 - Confirm Printer", 0, MB_OKCANCEL | MB_QUERY | MB_MOVEABLE) == MBID_OK );
  471.     }
  472. /*...e*/
  473. /*...sTransferBitmapData:0:*/
  474. /*
  475. Put the largest possible copy of the bitmap onto the printer presentation
  476. space. Preserve aspect ratio and correct for printer aspect ratio.
  477. */
  478.  
  479. /*...sMonoPrint:0:*/
  480. static BOOL MonoPrint(HPS hpsPrinter)
  481.     {
  482.     HDC hdcPrinter = GpiQueryDevice(hpsPrinter);
  483.     LONG lBitCount, lPlanes;
  484.  
  485.     DevQueryCaps(hdcPrinter, CAPS_COLOR_BITCOUNT, 1L, &lBitCount);
  486.     DevQueryCaps(hdcPrinter, CAPS_COLOR_PLANES  , 1L, &lPlanes  );
  487.  
  488.     return ( lBitCount == 1 && lPlanes == 1 );
  489.     }
  490. /*...e*/
  491.  
  492. static BMP_ERR TransferBitmapData(HAB hab, HBITMAP hbm, HDC hdcPrinter, HPS hpsPrinter)
  493.     {
  494.     SIZEL sizlMemory, sizlPrinter, sizlImage;
  495.     SIZEL sizlMmPrinter, sizlMmImage; /* Sizes in mm */
  496.     HDC hdcMemory;
  497.     HPS hpsMemory;
  498.     POINTL aptl [4];
  499.     BITMAPINFOHEADER2 bmp;
  500.     LONG xRes, yRes, xCentre, yCentre;
  501.  
  502.     /* Query printer size */
  503.  
  504.     GpiQueryPS(hpsPrinter, &sizlPrinter);
  505.  
  506.     /* Query bitmap size */
  507.  
  508.     bmp.cbFix = sizeof(BITMAPINFOHEADER2);
  509.     GpiQueryBitmapInfoHeader(hbm, &bmp);
  510.     sizlMemory.cx = (LONG) bmp.cx;
  511.     sizlMemory.cy = (LONG) bmp.cy;
  512.  
  513.     /* Make a memory device context for the bitmap */
  514.  
  515.     if ( (hdcMemory = DevOpenDC(hab, OD_MEMORY, "*", 0L, NULL, hdcPrinter)) == (HPS) NULL )
  516.         return ( BMP_ERR_RES );
  517.  
  518.     if ( (hpsMemory = GpiCreatePS(hab, hdcMemory, &sizlMemory, PU_PELS | GPIF_DEFAULT | GPIT_MICRO | GPIA_ASSOC)) == (HPS) NULL )
  519.         {
  520.         DevCloseDC(hdcMemory);
  521.         return ( BMP_ERR_RES );
  522.         }
  523.  
  524.     GpiSetBitmap(hpsMemory, hbm);
  525.  
  526.     /* Set colours ready for blitting into printer ps */
  527.  
  528.     GpiSetColor(hpsMemory, CLR_WHITE);
  529.     GpiSetBackColor(hpsMemory, CLR_BLACK);
  530.     GpiSetColor(hpsPrinter, CLR_WHITE);
  531.     GpiSetBackColor(hpsPrinter, CLR_BLACK);
  532.  
  533. /*...sscale to fit page:8:*/
  534. /* Query printer aspect ratio */
  535.  
  536. DevQueryCaps(hdcPrinter, CAPS_HORIZONTAL_RESOLUTION, 1L, &xRes);
  537. DevQueryCaps(hdcPrinter, CAPS_VERTICAL_RESOLUTION  , 1L, &yRes);
  538.  
  539. /* Get size of page in mm */
  540.  
  541. sizlMmPrinter.cx = (1000L * sizlPrinter.cx) / xRes;
  542. sizlMmPrinter.cy = (1000L * sizlPrinter.cy) / yRes;
  543.  
  544. /* Get largest image size in mm */
  545.  
  546. if ( sizlMemory.cx * sizlMmPrinter.cy > sizlMemory.cy * sizlMmPrinter.cx )
  547.     /* Stretch to fill width */
  548.     {
  549.     sizlMmImage.cx = sizlMmPrinter.cx;
  550.     sizlMmImage.cy = (sizlMmImage.cx * sizlMemory.cy) / sizlMemory.cx;
  551.     }
  552. else
  553.     /* Stretch to fill height */
  554.     {
  555.     sizlMmImage.cy = sizlMmPrinter.cy;
  556.     sizlMmImage.cx = (sizlMmImage.cy * sizlMemory.cx) / sizlMemory.cy;
  557.     }
  558.  
  559. sizlImage.cx = (xRes * sizlMmImage.cx) / 1000L;
  560. sizlImage.cy = (yRes * sizlMmImage.cy) / 1000L;
  561.  
  562. xCentre = ((sizlPrinter.cx - sizlImage.cx) >> 1);
  563. yCentre = ((sizlPrinter.cy - sizlImage.cy) >> 1);
  564.  
  565. aptl [0].x = xCentre;
  566. aptl [0].y = yCentre;
  567. aptl [1].x = xCentre + sizlImage.cx;
  568. aptl [1].y = yCentre + sizlImage.cy;
  569. aptl [2].x = 0;
  570. aptl [2].y = 0;
  571. aptl [3].x = sizlMemory.cx;
  572. aptl [3].y = sizlMemory.cy;
  573.  
  574. GpiBitBlt(hpsPrinter, hpsMemory, 4L, aptl, ROP_SRCCOPY, 
  575.     MonoPrint(hpsPrinter) ? BBO_AND : BBO_IGNORE);
  576. /*...e*/
  577. #ifdef NEVER
  578. /*...sposition in the middle if room:8:*/
  579. if ( sizlMemory.cx < sizlPrinter.cx &&
  580.      sizlMemory.cy < sizlPrinter.cy )
  581.     { 
  582.     xCentre = ((sizlPrinter.cx - sizlMemory.cx) >> 1);
  583.     yCentre = ((sizlPrinter.cy - sizlMemory.cy) >> 1);
  584.  
  585.     aptl [0].x = xCentre;
  586.     aptl [0].y = yCentre;
  587.     aptl [1].x = xCentre + sizlMemory.cx;
  588.     aptl [1].y = yCentre + sizlMemory.cy;
  589.     aptl [2].x = 0;
  590.     aptl [2].y = 0;
  591.  
  592.     GpiBitBlt(hpsPrinter, hpsMemory, 3L, aptl, ROP_SRCCOPY, BBO_IGNORE);
  593.     }
  594. /*...e*/
  595. #endif
  596.  
  597.     GpiSetBitmap(hpsMemory, (HBITMAP) NULL);
  598.     GpiDestroyPS(hpsMemory);
  599.     DevCloseDC(hdcMemory);
  600.  
  601.     return ( BMP_ERR_OK );
  602.     }
  603. /*...e*/
  604.  
  605. BMP_ERR BmpPrint(
  606.     HAB hab,
  607.     HBITMAP hbm,
  608.     CHAR *szDocName,
  609.     CHAR *szComment,
  610.     CHAR *szQueueToUse
  611.     )
  612.     {
  613.     static SIZEL sizl = { 0, 0 };
  614.     HDC hdcPrinter;
  615.     HPS hpsPrinter;
  616.     CHAR szLogAddress [256];
  617.     CHAR szDriverName [256];
  618.     CHAR szNameWPS [256];
  619.     DEVOPENSTRUC dop;
  620.     USHORT cb, usJobId;
  621.     CHAR szQueue [256];
  622.     BMP_ERR rc;
  623.     LONG lOutCount;
  624.     BOOL fQueried = FALSE;
  625.  
  626.     /* Set defaults, in case can't query information about printer */
  627.  
  628.     dop.pszLogAddress      = szLogAddress;
  629.     dop.pszDriverName      = szDriverName;
  630.     dop.pdriv              = NULL;
  631.     dop.pszDataType        = "PM_Q_STD";
  632.     dop.pszComment         = szComment;
  633.     dop.pszQueueProcName   = NULL;
  634.     dop.pszQueueProcParams = NULL;
  635.     dop.pszSpoolerParams   = NULL;
  636.     dop.pszNetworkParams   = NULL;
  637.  
  638.     if ( szQueueToUse != NULL )
  639.         /* Use the queue we have been told to use */
  640.         fQueried = EnquireQueueDetails(szQueueToUse, szLogAddress, szDriverName, szNameWPS, &dop.pdriv);
  641.     else if ( (cb = (USHORT) PrfQueryProfileString(HINI_PROFILE, "PM_SPOOLER",
  642.          "QUEUE", NULL, szQueue, (LONG) sizeof(szQueue))) > 0 )
  643.         /* Use application default queue */
  644.         {
  645.         szQueue [cb - 2] = '\0'; /* Remove semicolon at end */
  646.         fQueried = EnquireQueueDetails(szQueue, szLogAddress, szDriverName, szNameWPS, &dop.pdriv);
  647.         }
  648.  
  649.     if ( !fQueried )
  650.         return ( BMP_ERR_QUERY );
  651.  
  652.     /* Try to create printer device context */
  653.  
  654.     if ( (hdcPrinter = DevOpenDC(hab, OD_QUEUED, "*", 5L, (PDEVOPENDATA) &dop, (HDC) NULL)) == (HDC) NULL )
  655.         /* Failed to open printer device context */
  656.         return ( BMP_ERR_PRINTER );
  657.  
  658.     /* Create a presentation space of default size (size of page) */
  659.  
  660.     if ( (hpsPrinter = GpiCreatePS(hab, hdcPrinter, &sizl, PU_PELS | GPIF_DEFAULT | GPIA_ASSOC)) == (HPS) NULL )
  661.         /* Could not make presentation space */
  662.         {
  663.         DevCloseDC(hdcPrinter);
  664.         return ( BMP_ERR_PRINTER );
  665.         }
  666.  
  667.     /* Tell user about printer, and give chance to abort job */
  668.  
  669.     if ( !PrinterInfo(hpsPrinter, szNameWPS) )
  670.         {
  671.         GpiAssociate(hpsPrinter, (HDC) NULL);
  672.         GpiDestroyPS(hpsPrinter);
  673.         DevCloseDC(hdcPrinter);
  674.         return ( BMP_ERR_OK );
  675.         }
  676.  
  677.     /* Indicate a new print job is starting */
  678.  
  679.     if ( !DevEscape(hdcPrinter, DEVESC_STARTDOC, (LONG) strlen(szDocName),
  680.           (BYTE *) szDocName, &lOutCount, (BYTE *) NULL) )
  681.         {
  682.         GpiAssociate(hpsPrinter, (HDC) NULL);
  683.         GpiDestroyPS(hpsPrinter);
  684.         DevCloseDC(hdcPrinter);
  685.         return ( BMP_ERR_PRINT );
  686.         }
  687.  
  688.     GpiErase(hpsPrinter); /* Blank the page to CLR_BACKGROUND */
  689.  
  690.     if ( (rc = TransferBitmapData(hab, hbm, hdcPrinter, hpsPrinter)) != BMP_ERR_OK )
  691.         {
  692.         DevEscape(hdcPrinter, DEVESC_ABORTDOC, 0L, NULL, 0L, NULL);
  693.         GpiAssociate(hpsPrinter, (HDC) NULL);
  694.         GpiDestroyPS(hpsPrinter);
  695.         DevCloseDC(hdcPrinter);
  696.         return ( rc );
  697.         }
  698.  
  699.     /* Indicate the job is done */
  700.  
  701.     if ( !DevEscape(hdcPrinter, DEVESC_ENDDOC, 0L, (BYTE *) NULL, &lOutCount, (BYTE *) &usJobId) )
  702.         {
  703.         GpiAssociate(hpsPrinter, (HDC) NULL);
  704.         GpiDestroyPS(hpsPrinter);
  705.         DevCloseDC(hdcPrinter);
  706.         return ( BMP_ERR_PRINT );
  707.         }
  708.  
  709.     GpiAssociate(hpsPrinter, (HDC) NULL);
  710.     GpiDestroyPS(hpsPrinter);
  711.     DevCloseDC(hdcPrinter);
  712.  
  713.     return ( BMP_ERR_OK );
  714.     }
  715. /*...e*/
  716. /*...sBmpErrorMessage     \45\ get error message from error return code:0:*/
  717. CHAR *BmpErrorMessage(BMP_ERR rc, CHAR *sz)
  718.     {
  719.     static CHAR *aszBitmapErrors [] =
  720.         {
  721.         "",
  722.         "out of memory",
  723.         "out of resources",
  724.         "can't query printer/queue details",
  725.         "can't locate printer/queue",
  726.         "error sending data to printer/queue",
  727.         };
  728.  
  729.     return ( strcpy(sz, aszBitmapErrors [rc]) );
  730.     }
  731. /*...e*/
  732. /*...e*/
  733. /*...shelp:0:*/
  734. static HELPINIT hinit;
  735.  
  736. /*...sHlpWarning:0:*/
  737. static VOID HlpWarning(HWND hwnd, CHAR *szFmt, ...)
  738.     {
  739.     va_list vars;
  740.     CHAR sz [256+1];
  741.  
  742.     va_start(vars, szFmt);
  743.     vsprintf(sz, szFmt, vars);
  744.     va_end(vars);
  745.     WinMessageBox(HWND_DESKTOP, hwnd, sz, "Help system", 0, MB_OK | MB_WARNING | MB_MOVEABLE);
  746.     }
  747. /*...e*/
  748. /*...sHlpInit:0:*/
  749. static HWND HlpInit(
  750.     HWND hwnd,
  751.     HMODULE hmod, USHORT idHelpTable,
  752.     CHAR *szHelpFile,
  753.     CHAR *szTitle
  754.     )
  755.     {
  756.     HAB hab = WinQueryAnchorBlock(hwnd);
  757.     HWND hwndHelp;
  758.     CHAR sz [256+1];
  759.  
  760.     hinit.cb                       = sizeof(HELPINIT);
  761.     hinit.ulReturnCode             = 0L;
  762.  
  763.     /* HELPTABLE resource handle */
  764.     hinit.hmodHelpTableModule      = hmod;
  765.     hinit.phtHelpTable             = (HELPTABLE *) (0xffff0000L | idHelpTable);
  766.  
  767.     /* Help window title bar */
  768.     strcpy(sz, szTitle);
  769.     strcat(sz, " Help");
  770.     hinit.pszHelpWindowTitle       = sz;
  771.  
  772.     /* Not showing panel IDs */
  773.     hinit.fShowPanelId             = CMIC_HIDE_PANEL_ID;
  774.  
  775.     /* No tutorial program */
  776.     hinit.pszTutorialName          = NULL;
  777.  
  778.     /* Action bar is not tailored */
  779.     hinit.hmodAccelActionBarModule = (HMODULE) NULL;
  780.     hinit.idAccelTable             = (USHORT) NULL;
  781.     hinit.idActionBar              = (USHORT) NULL;
  782.  
  783.     /* No default librarys */
  784.     hinit.pszHelpLibraryName       = "";
  785.  
  786.     if ( (hwndHelp = WinCreateHelpInstance(hab, &hinit)) == (HWND) NULL )
  787.         {
  788.         HlpWarning(hwnd, "Unable to create help instance");
  789.         return ( (HWND) NULL );
  790.         }
  791.  
  792.     if ( WinSendMsg(hwndHelp, HM_SET_HELP_LIBRARY_NAME, MPFROMP(szHelpFile), NULL) )
  793.         {
  794.         WinDestroyHelpInstance(hwndHelp);
  795.         HlpWarning(hwnd, "Unable to find help libraries");
  796.         return ( (HWND) NULL );
  797.         }
  798.  
  799.     return ( hwndHelp );
  800.     }
  801. /*...e*/
  802. /*...sHlpDeinit:0:*/
  803. static VOID HlpDeinit(HWND hwndHelp)
  804.     {
  805.     WinDestroyHelpInstance(hwndHelp);
  806.     }
  807. /*...e*/
  808. /*...sHlpActivate:0:*/
  809. static VOID HlpActivate(HWND hwndHelp, HWND hwndFrame)
  810.     {
  811.     if ( !WinAssociateHelpInstance(hwndHelp, hwndFrame))
  812.         HlpWarning(hwndFrame, "Unable to associate help instance");
  813.     }
  814. /*...e*/
  815. /*...sHlpWndProc:0:*/
  816. MRESULT _System HlpWndProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  817.     {
  818.     CHAR sz [256+1];
  819.  
  820.     switch ( (int) msg )
  821.         {
  822. /*...sHM_ERROR:16:*/
  823. case HM_ERROR:
  824.     switch( SHORT1FROMMP(mp1) )
  825.         {
  826.         case HMERR_HELPITEM_NOT_FOUND:
  827.             sprintf(sz, "Item 0x%08lx not found", LONGFROMMP(mp2));
  828.             HlpWarning(hwnd, sz);
  829.             break;
  830.         case HMERR_HELPSUBITEM_NOT_FOUND:
  831.             sprintf(sz, "Sub-Item 0x%08lx not found", LONGFROMMP(mp2));
  832.             HlpWarning(hwnd, sz);
  833.             break;
  834.         case HMERR_INDEX_NOT_FOUND:
  835.             HlpWarning(hwnd, "No index in library file" );
  836.             break;
  837.         case HMERR_CONTENT_NOT_FOUND:
  838.             HlpWarning(hwnd, "Library file does not have any contents");
  839.             break;
  840.         case HMERR_OPEN_LIB_FILE:
  841.             HlpWarning(hwnd, "Cannot open library file");
  842.             break;
  843.         case HMERR_READ_LIB_FILE:
  844.             HlpWarning(hwnd, "Cannot read library file");
  845.             break;
  846.         case HMERR_CLOSE_LIB_FILE:
  847.             HlpWarning(hwnd, "Cannot close library file");
  848.             break;
  849.         case HMERR_INVALID_LIB_FILE:
  850.             HlpWarning(hwnd, "Improper library file provided");
  851.             break;
  852.         case HMERR_NO_MEMORY:
  853.             HlpWarning(hwnd, "Unable to allocate the requested amount of memory");
  854.             break;
  855.         case HMERR_ALLOCATE_SEGMENT:
  856.             HlpWarning(hwnd, "Unable to allocate memory for IPF");
  857.             break;
  858.         case HMERR_FREE_MEMORY:
  859.             HlpWarning(hwnd, "Unable to free allocated memory");
  860.             break;
  861.         case HMERR_PANEL_NOT_FOUND:
  862.             HlpWarning(hwnd, "Unable to find help panel requested");
  863.             break;
  864.         case HMERR_DATABASE_NOT_OPEN:
  865.             HlpWarning(hwnd, "Unable to read the unopened database");
  866.             break;
  867.         default:
  868.             sprintf(sz, "Error mp1=0x%08lx mp2=0x%08lx",LONGFROMMP(mp1), LONGFROMMP(mp2));
  869.             HlpWarning(hwnd, sz);
  870.             break;
  871.         }
  872.     break;
  873. /*...e*/
  874. /*...sHM_INFORM:16:*/
  875. case HM_INFORM:
  876.     sprintf(sz, "Inform 0x%08lx 0x%08lx",
  877.         LONGFROMMP(mp1), LONGFROMMP(mp2));
  878.     HlpWarning(hwnd, sz);
  879.     break;
  880. /*...e*/
  881. /*...sHM_QUERY_KEYS_HELP:16:*/
  882. case HM_QUERY_KEYS_HELP:
  883.     return ( (MRESULT) HID_HELPKEYS );    
  884. /*...e*/
  885. /*...sHM_EXT_HELP_UNDEFINED:16:*/
  886. case HM_EXT_HELP_UNDEFINED:
  887.     sprintf(sz, "Extended help undefined mp1=0x%08lx mp2=0x%l08x",
  888.         LONGFROMMP(mp1), LONGFROMMP(mp2));
  889.     HlpWarning(hwnd, sz);
  890.     break;
  891. /*...e*/
  892. /*...sHM_HELPSUBITEM_NOT_FOUND:16:*/
  893. case HM_HELPSUBITEM_NOT_FOUND:
  894.     sprintf(sz, "Sub-Item 0x%08lx 0x%08lx not found",
  895.         LONGFROMMP(mp1), LONGFROMMP(mp2));
  896.     HlpWarning(hwnd, sz);
  897.     break;
  898. /*...e*/
  899.         }
  900.     return ( WinDefWindowProc(hwnd, msg, mp1, mp2) );
  901.     }
  902. /*...e*/
  903. /*...sHlpHelpForHelp:0:*/
  904. static VOID HlpHelpForHelp(HWND hwndHelp)
  905.     {
  906.     WinPostMsg(hwndHelp, HM_DISPLAY_HELP, NULL, NULL);
  907.     }
  908. /*...e*/
  909.  
  910. static HWND hwndHelp;
  911. /*...e*/
  912. /*...svars:0:*/
  913. #define    MAX_FILE_NAME    256
  914.  
  915. static CHAR szAppName [] = "GbmV2";
  916. static CHAR szFileName [MAX_FILE_NAME+1] = "";
  917.  
  918. static BOOL fGotBitmap = FALSE;
  919. static BOOL fUnsavedChanges = FALSE;
  920. static GBM gbm;
  921. static GBMRGB gbmrgb [0x100];
  922. static BYTE *pbData;
  923.  
  924. #define    VIEW_NULL    0
  925. #define    VIEW_HALFTONE    1
  926. #define    VIEW_ERRDIFF    2
  927. static BYTE bView = VIEW_NULL;
  928. static LONG lBitCountScreen;
  929.  
  930. static BOOL fBusy = FALSE;
  931. static HWND hwndObject;
  932. static HWND hwndBitmap;
  933. static HWND hwndScroller;
  934. static BOOL fSelectionDefined = FALSE;
  935. static RECTL rclSelection;
  936. /*...e*/
  937. /*...sundo:0:*/
  938. static BOOLEAN fCanUndo = FALSE;
  939. static GBM gbmUndo;
  940. static GBMRGB gbmrgbUndo [0x100];
  941. static BYTE *pbDataUndo;
  942. static CHAR *szWhatUndo;
  943.  
  944. /*...sDiscardUndo:0:*/
  945. static VOID DiscardUndo(VOID)
  946.     {
  947.     if ( fCanUndo )
  948.         {
  949.         if ( pbDataUndo != NULL )
  950.             free(pbDataUndo);
  951.         fCanUndo = FALSE;
  952.         }
  953.     }
  954. /*...e*/
  955. /*...sKeepForUndo:0:*/
  956. static VOID KeepForUndo(GBM *gbm, GBMRGB *gbmrgb, BYTE *pbData, CHAR *szWhat)
  957.     {
  958.     int stride = ((gbm -> w * gbm -> bpp + 31) / 32) * 4;
  959.     DiscardUndo();
  960.     szWhatUndo = szWhat;
  961.     gbmUndo = *gbm;
  962.     memcpy(gbmrgbUndo, gbmrgb, 0x100 * sizeof(GBMRGB));
  963.     if ( pbData != NULL )
  964.         {
  965.         if ( (pbDataUndo = malloc(stride * gbm -> h)) == NULL )
  966.             return; /* Can't keep data for undo purposes */
  967.         memcpy(pbDataUndo, pbData, stride * gbm -> h);
  968.         }
  969.     else
  970.         pbDataUndo = NULL;
  971.     fCanUndo = TRUE;
  972.     }
  973. /*...e*/
  974. /*...sUseUndoBuffer:0:*/
  975. static VOID UseUndoBuffer(GBM *gbm, GBMRGB *gbmrgb, BYTE **ppbData, CHAR **pszWhat)
  976.     {
  977.     *gbm = gbmUndo;
  978.     memcpy(gbmrgb, gbmrgbUndo, 0x100 * sizeof(GBMRGB));
  979.     *ppbData = pbDataUndo;
  980.     *pszWhat = szWhatUndo;
  981.     fCanUndo = FALSE;
  982.     }
  983. /*...e*/
  984. /*...e*/
  985. /*...sLoadBitmap:0:*/
  986. static BOOL LoadBitmap(
  987.     HWND hwnd,
  988.     CHAR *szFn, CHAR *szOpt,
  989.     GBM *gbm, GBMRGB *gbmrgb, BYTE **ppbData
  990.     )
  991.     {
  992.     GBM_ERR rc;
  993.     int fd, ft;
  994.     ULONG cb, cbLine;
  995.  
  996.     if ( gbm_guess_filetype(szFn, &ft) != GBM_ERR_OK )
  997.         {
  998.         Warning(hwnd, "Can't deduce bitmap format from file extension: %s", szFn);
  999.         return ( FALSE );
  1000.         }
  1001.  
  1002.     if ( (fd = open(szFn, O_RDONLY|O_BINARY)) == -1 )
  1003.         {
  1004.         Warning(hwnd, "Can't open file: %s", szFn);
  1005.         return ( FALSE );
  1006.         }
  1007.  
  1008.     if ( (rc = gbm_read_header(szFn, fd, ft, gbm, szOpt)) != GBM_ERR_OK )
  1009.         {
  1010.         close(fd);
  1011.         Warning(hwnd, "Can't read file header of %s: %s", szFn, gbm_err(rc));
  1012.         return ( FALSE );
  1013.         }
  1014.  
  1015.     if ( (rc = gbm_read_palette(fd, ft, gbm, gbmrgb)) != GBM_ERR_OK )
  1016.         {
  1017.         close(fd);
  1018.         Warning(hwnd, "Can't read file palette of %s: %s", szFn, gbm_err(rc));
  1019.         return ( FALSE );
  1020.         }
  1021.  
  1022.     cbLine = ((gbm -> w * gbm -> bpp + 31)/32) * 4;
  1023.     cb = gbm -> h * cbLine;
  1024.     if ( (*ppbData = malloc((int) cb)) == NULL )
  1025.         {
  1026.         close(fd);
  1027.         Warning(hwnd, "Out of memory requesting %ld bytes", cb);
  1028.         return ( FALSE );
  1029.         }
  1030.  
  1031.     if ( (rc = gbm_read_data(fd, ft, gbm, *ppbData)) != GBM_ERR_OK )
  1032.         {
  1033.         free(*ppbData);
  1034.         close(fd);
  1035.         Warning(hwnd, "Can't read file data of %s: %s", szFn, gbm_err(rc));
  1036.         return ( FALSE );
  1037.         }
  1038.  
  1039.     close(fd);
  1040.  
  1041.     return ( TRUE );
  1042.     }
  1043. /*...e*/
  1044. /*...sCopyTo24:0:*/
  1045. static VOID CopyTo24(GBM *gbm, GBMRGB *gbmrgb, BYTE *pbDataSrc, BYTE *pbDataDest)
  1046.     {
  1047.     int cbLineSrc  = ((gbm -> w * gbm -> bpp + 31)/32) * 4;
  1048.     int cbLineDest = ((gbm -> w * 3 + 3) & ~3);
  1049.     int y;
  1050.  
  1051.     for ( y = 0; y < gbm -> h; y++ )
  1052.         {
  1053.         BYTE *pbSrc  = pbDataSrc  + y * cbLineSrc ;
  1054.         BYTE *pbDest = pbDataDest + y * cbLineDest;
  1055.         int x;
  1056.  
  1057.         switch ( gbm -> bpp )
  1058.             {
  1059. /*...s1:24:*/
  1060. case 1:
  1061.     {
  1062.     BYTE c;
  1063.  
  1064.     for ( x = 0; x < gbm -> w; x++ )
  1065.         {
  1066.         if ( (x & 7) == 0 )
  1067.             c = *pbSrc++;
  1068.         else
  1069.             c <<= 1;
  1070.  
  1071.         *pbDest++ = gbmrgb [c >> 7].b;
  1072.         *pbDest++ = gbmrgb [c >> 7].g;
  1073.         *pbDest++ = gbmrgb [c >> 7].r;
  1074.         }
  1075.     }
  1076.     break;
  1077. /*...e*/
  1078. /*...s4:24:*/
  1079. case 4:
  1080.     for ( x = 0; x + 1 < gbm -> w; x += 2 )
  1081.         {
  1082.         BYTE c = *pbSrc++;
  1083.  
  1084.         *pbDest++ = gbmrgb [c >> 4].b;
  1085.         *pbDest++ = gbmrgb [c >> 4].g;
  1086.         *pbDest++ = gbmrgb [c >> 4].r;
  1087.         *pbDest++ = gbmrgb [c & 15].b;
  1088.         *pbDest++ = gbmrgb [c & 15].g;
  1089.         *pbDest++ = gbmrgb [c & 15].r;
  1090.         }
  1091.  
  1092.     if ( x < gbm -> w )
  1093.         {
  1094.         BYTE c = *pbSrc;
  1095.  
  1096.         *pbDest++ = gbmrgb [c >> 4].b;
  1097.         *pbDest++ = gbmrgb [c >> 4].g;
  1098.         *pbDest++ = gbmrgb [c >> 4].r;
  1099.         }
  1100.     break;
  1101. /*...e*/
  1102. /*...s8:24:*/
  1103. case 8:
  1104.     for ( x = 0; x < gbm -> w; x++ )
  1105.         {
  1106.         BYTE c = *pbSrc++;
  1107.  
  1108.         *pbDest++ = gbmrgb [c].b;
  1109.         *pbDest++ = gbmrgb [c].g;
  1110.         *pbDest++ = gbmrgb [c].r;
  1111.         }
  1112.     break;
  1113. /*...e*/
  1114. /*...s24:24:*/
  1115. case 24:
  1116.     memcpy(pbDataDest, pbDataSrc, cbLineSrc * gbm -> h);
  1117.     break;
  1118. /*...e*/
  1119.             }
  1120.         }
  1121.     }
  1122. /*...e*/
  1123. /*...sTo24Bit:0:*/
  1124. static BOOL To24Bit(GBM *gbm, GBMRGB *gbmrgb, BYTE *pbData, BYTE **ppbDataNew)
  1125.     {
  1126.     int cbLineDest = ((gbm -> w * 3 + 3) & ~3);
  1127.     if ( (*ppbDataNew = malloc(cbLineDest * gbm -> h)) == NULL )
  1128.         return ( FALSE );
  1129.  
  1130.     CopyTo24(gbm, gbmrgb, pbData, *ppbDataNew);
  1131.  
  1132.     return ( TRUE );
  1133.     }
  1134. /*...e*/
  1135. /*...sMakeBitmap:0:*/
  1136. static BOOL MakeBitmap(
  1137.     HWND hwnd,
  1138.     GBM *gbm, GBMRGB *gbmrgb, BYTE *pbData,
  1139.     HBITMAP *phbm
  1140.     )
  1141.     {
  1142.     HAB hab = WinQueryAnchorBlock(hwnd);
  1143.     USHORT cRGB, usCol;
  1144.     SIZEL sizl;
  1145.     HDC hdc;
  1146.     HPS hps;
  1147.     struct
  1148.         {
  1149.         BITMAPINFOHEADER2 bmp2;
  1150.         RGB2 argb2Color [0x100];
  1151.         } bm;
  1152.  
  1153.     /* Got the data in memory, now make bitmap */
  1154.  
  1155.     memset(&bm, 0, sizeof(bm));
  1156.  
  1157.     bm.bmp2.cbFix     = sizeof(BITMAPINFOHEADER2);
  1158.     bm.bmp2.cx        = gbm -> w;
  1159.     bm.bmp2.cy        = gbm -> h;
  1160.     bm.bmp2.cBitCount = gbm -> bpp;
  1161.     bm.bmp2.cPlanes   = 1;
  1162.  
  1163.     cRGB = ( (1 << gbm -> bpp) & 0x1ff );
  1164.         /* 1 -> 2, 4 -> 16, 8 -> 256, 24 -> 0 */
  1165.  
  1166.     for ( usCol = 0; usCol < cRGB; usCol++ )
  1167.         {
  1168.         bm.argb2Color [usCol].bRed   = gbmrgb [usCol].r;
  1169.         bm.argb2Color [usCol].bGreen = gbmrgb [usCol].g;
  1170.         bm.argb2Color [usCol].bBlue  = gbmrgb [usCol].b;
  1171.         }
  1172.  
  1173.     if ( (hdc = DevOpenDC(hab, OD_MEMORY, "*", 0L, (PDEVOPENDATA) NULL, (HDC) NULL)) == (HDC) NULL )
  1174.         {
  1175.         Warning(hwnd, "DevOpenDC failure");
  1176.         return ( FALSE );
  1177.         }
  1178.  
  1179.     sizl.cx = bm.bmp2.cx;
  1180.     sizl.cy = bm.bmp2.cy;
  1181.     if ( (hps = GpiCreatePS(hab, hdc, &sizl, PU_PELS | GPIF_DEFAULT | GPIT_MICRO | GPIA_ASSOC)) == (HPS) NULL )
  1182.         {
  1183.         Warning(hwnd, "GpiCreatePS failure");
  1184.         DevCloseDC(hdc);
  1185.         return ( FALSE );
  1186.         }
  1187.  
  1188.  
  1189.     if ( cRGB == 2 )
  1190. /*...shandle 1bpp case:16:*/
  1191. /*
  1192. 1bpp presentation spaces have a reset or background colour.
  1193. They also have a contrast or foreground colour.
  1194. When data is mapped into a 1bpp presentation space :-
  1195. Data which is the reset colour, remains reset, and is stored as 0's.
  1196. All other data becomes contrast, and is stored as 1's.
  1197. The reset colour for 1bpp screen HPSs is white.
  1198. I want 1's in the source data to become 1's in the HPS.
  1199. We seem to have to reverse the ordering here to get the desired effect.
  1200. */
  1201.  
  1202. {
  1203. static RGB2 argb2Black = { 0x00, 0x00, 0x00 };
  1204. static RGB2 argb2White = { 0xff, 0xff, 0xff };
  1205. bm.argb2Color [0] = argb2Black; /* Contrast */
  1206. bm.argb2Color [1] = argb2White; /* Reset */
  1207. }
  1208. /*...e*/
  1209.  
  1210.     if ( (*phbm = GpiCreateBitmap(hps, &(bm.bmp2), CBM_INIT, pbData, (BITMAPINFO2 *) &(bm.bmp2))) == (HBITMAP) NULL )
  1211.         {
  1212.         Warning(hwnd, "GpiCreateBitmap failure");
  1213.         GpiDestroyPS(hps);
  1214.         DevCloseDC(hdc);
  1215.         return ( FALSE );
  1216.         }
  1217.  
  1218.     GpiSetBitmap(hps, (HBITMAP) NULL);
  1219.     GpiDestroyPS(hps);
  1220.     DevCloseDC(hdc);
  1221.  
  1222.     return ( TRUE );
  1223.     }
  1224. /*...e*/
  1225. /*...sMakeVisual:0:*/
  1226. static BOOL MakeVisual(
  1227.     HWND hwnd,
  1228.     GBM *gbm, GBMRGB *gbmrgb, BYTE *pbData,
  1229.     BYTE bView,
  1230.     HBITMAP *phbm, LONG *plColorBg, LONG *plColorFg
  1231.     )
  1232.     {
  1233.     HPS hps = WinGetPS(HWND_DESKTOP);
  1234.     HDC hdc = GpiQueryDevice(hps);
  1235.     LONG lPlanes, lBitCount;
  1236.     GBM gbmVisual;
  1237.     GBMRGB gbmrgbVisual [0x100];
  1238.     BYTE *pbDataVisual;
  1239.  
  1240.     DevQueryCaps(hdc, CAPS_COLOR_PLANES  , 1L, &lPlanes  );
  1241.     DevQueryCaps(hdc, CAPS_COLOR_BITCOUNT, 1L, &lBitCount);
  1242.     WinReleasePS(hps);
  1243.  
  1244.     gbmVisual = *gbm;
  1245.     memcpy(gbmrgbVisual, gbmrgb, 0x100 * sizeof(GBMRGB));
  1246.     pbDataVisual = pbData;
  1247.  
  1248.     switch ( bView )
  1249.         {
  1250. /*...sVIEW_HALFTONE:16:*/
  1251. case VIEW_HALFTONE:
  1252.     if ( !To24Bit(gbm, gbmrgb, pbData, &pbDataVisual) )
  1253.         {
  1254.         Warning(hwnd, "Out of memory making halftoned view");
  1255.         break;
  1256.         }
  1257.     gbmVisual.bpp = 24;
  1258.     switch ( (int) lBitCount )
  1259.         {
  1260.         case 4:
  1261.             gbm_ht_pal_VGA(gbmrgbVisual);
  1262.             gbm_ht_VGA_3x3(&gbmVisual, pbDataVisual, pbDataVisual);
  1263.             gbmVisual.bpp = 4;
  1264.             break;
  1265.         case 8:
  1266.             gbm_ht_pal_7R8G4B(gbmrgbVisual);
  1267.             gbm_ht_7R8G4B_2x2(&gbmVisual, pbDataVisual, pbDataVisual);
  1268.             gbmVisual.bpp = 8;
  1269.             break;
  1270.         case 16:
  1271.             gbm_ht_24_2x2(&gbmVisual, pbDataVisual, pbDataVisual, 0xf8, 0xfc, 0xf8);
  1272.             gbmVisual.bpp = 24;
  1273.             break;
  1274.         }
  1275.     break;
  1276. /*...e*/
  1277. /*...sVIEW_ERRDIFF:16:*/
  1278. case VIEW_ERRDIFF:
  1279.     if ( !To24Bit(gbm, gbmrgb, pbData, &pbDataVisual) )
  1280.         {
  1281.         Warning(hwnd, "Out of memory making error-diffused view");
  1282.         break;
  1283.         }
  1284.     gbmVisual.bpp = 24;
  1285.     switch ( (int) lBitCount )
  1286.         {
  1287.         case 4:
  1288.             /* VGA */
  1289.             gbm_errdiff_pal_VGA(gbmrgbVisual);
  1290.             gbm_errdiff_VGA(&gbmVisual, pbDataVisual, pbDataVisual);
  1291.             gbmVisual.bpp = 4;
  1292.             break;
  1293.         case 8:
  1294.             /* 8514/A, XGA, IA/A */
  1295.             gbm_errdiff_pal_7R8G4B(gbmrgbVisual);
  1296.             gbm_errdiff_7R8G4B(&gbmVisual, pbDataVisual, pbDataVisual);
  1297.             gbmVisual.bpp = 8;
  1298.             break;
  1299.         case 16:
  1300.             /* XGA-2 5:6:5 mode */
  1301.             if ( !gbm_errdiff_24(&gbmVisual, pbDataVisual, pbDataVisual, 0xf8, 0xfc, 0xf8) )
  1302.                 break;
  1303.             gbmVisual.bpp = 24;
  1304.             break;
  1305.         }
  1306.     break;
  1307. /*...e*/
  1308.         }
  1309.  
  1310.     if ( !MakeBitmap(hwnd, &gbmVisual, gbmrgbVisual, pbDataVisual, phbm) )
  1311.         {
  1312.         if ( pbDataVisual != pbData )
  1313.             free(pbDataVisual);
  1314.         /* Note MakeBitmap displays its own message */
  1315.         return ( FALSE );
  1316.         }
  1317.  
  1318.     if ( gbmVisual.bpp == 1 )
  1319. /*...sremember Bg and Fg colours:16:*/
  1320. {
  1321. *plColorBg = (gbmrgbVisual [0].r << 16) + (gbmrgbVisual [0].g << 8) + gbmrgbVisual [0].b;
  1322. *plColorFg = (gbmrgbVisual [1].r << 16) + (gbmrgbVisual [1].g << 8) + gbmrgbVisual [1].b;
  1323. }
  1324. /*...e*/
  1325.  
  1326.     if ( pbDataVisual != pbData )
  1327.         free(pbDataVisual);
  1328.  
  1329.     return ( TRUE );
  1330.     }
  1331. /*...e*/
  1332. /*...sSaveBitmap:0:*/
  1333. static BOOL SaveBitmap(
  1334.     HWND hwnd,
  1335.     CHAR *szFn, CHAR *szOpt,
  1336.     GBM *gbm, GBMRGB *gbmrgb, BYTE *pbData
  1337.     )
  1338.     {
  1339.     GBM_ERR rc;
  1340.     int fd, ft, flag;
  1341.     GBMFT gbmft;
  1342.  
  1343.     if ( gbm_guess_filetype(szFn, &ft) != GBM_ERR_OK )
  1344.         {
  1345.         Warning(hwnd, "Can't deduce bitmap format from file extension: %s", szFn);
  1346.         return ( FALSE );
  1347.         }
  1348.  
  1349.     gbm_query_filetype(ft, &gbmft);
  1350.     switch ( gbm -> bpp )
  1351.         {
  1352.         case 1:        flag = GBM_FT_W1;    break;
  1353.         case 4:        flag = GBM_FT_W4;    break;
  1354.         case 8:        flag = GBM_FT_W8;    break;
  1355.         case 24:    flag = GBM_FT_W24;    break;
  1356.         }
  1357.  
  1358.     if ( (gbmft.flags & flag) == 0 )
  1359.         {
  1360.         Warning(hwnd, "Bitmap file format %s does not support writing %d bpp files",
  1361.             gbmft.short_name, gbm -> bpp);
  1362.         return ( FALSE );
  1363.         }
  1364.  
  1365.     if ( (fd = open(szFn, O_CREAT|O_TRUNC|O_WRONLY|O_BINARY, S_IREAD|S_IWRITE)) == -1 )
  1366.         {
  1367.         Warning(hwnd, "Can't create file: %s", szFn);
  1368.         return ( FALSE );
  1369.         }
  1370.  
  1371.     if ( (rc = gbm_write(szFn, fd, ft, gbm, gbmrgb, pbData, szOpt)) != GBM_ERR_OK )
  1372.         {
  1373.         close(fd);
  1374.         unlink(szFn);
  1375.         Warning(hwnd, "Can't write bitmap to file %s: %s", szFn, gbm_err(rc));
  1376.         return ( FALSE );
  1377.         }
  1378.  
  1379.     close(fd);
  1380.  
  1381.     return ( TRUE );
  1382.     }
  1383. /*...e*/
  1384. /*...sSaveChanges:0:*/
  1385. /*
  1386. Returns TRUE if changes saved ok.
  1387. Returns FALSE if cancel selected.
  1388. */
  1389.  
  1390. static BOOL SaveChanges(HWND hwnd)
  1391.     {
  1392.     CHAR sz [255];
  1393.  
  1394.     if ( !fGotBitmap )
  1395.         return ( TRUE );
  1396.  
  1397.     if ( !fUnsavedChanges )
  1398.         return ( TRUE );
  1399.  
  1400.     sprintf(sz, "Save current changes: %s", szFileName);
  1401.     switch ( WinMessageBox(HWND_DESKTOP, hwnd, sz, szAppName, 0, MB_YESNOCANCEL | MB_WARNING | MB_MOVEABLE) )
  1402.         {
  1403.         case MBID_YES:
  1404.             {
  1405.             GBMFILEDLG gbmfild;
  1406.  
  1407.             memset(&gbmfild.fild, 0, sizeof(FILEDLG));
  1408.             gbmfild.fild.cbSize = sizeof(FILEDLG);
  1409.             gbmfild.fild.fl = (FDS_CENTER|FDS_SAVEAS_DIALOG|FDS_HELPBUTTON);
  1410.             strcpy(gbmfild.fild.szFullFile, szFileName);
  1411.             strcpy(gbmfild.szOptions, "");    
  1412.             while ( gbmfild.fild.szFullFile [0] == '\0' )
  1413.                 /* Try to correct filename */
  1414.                 {
  1415.                 GbmFileDlg(HWND_DESKTOP, hwnd, &gbmfild);
  1416.                 if ( gbmfild.fild.lReturn != DID_OK )
  1417.                     return ( FALSE );
  1418.                 }
  1419.             if ( !SaveBitmap(hwnd, gbmfild.fild.szFullFile, gbmfild.szOptions, &gbm, gbmrgb, pbData) )
  1420.                 return ( FALSE );
  1421.  
  1422.             strcpy(szFileName, gbmfild.fild.szFullFile);
  1423.             fUnsavedChanges = FALSE;
  1424.             return ( TRUE );
  1425.             }
  1426.         case MBID_NO:
  1427.             return ( TRUE );
  1428.         case MBID_CANCEL:
  1429.             return ( FALSE );
  1430.         }
  1431.     /* NOT REACHED */
  1432.     return ( FALSE ); /* Keep fussy compiler happy */
  1433.     }
  1434. /*...e*/
  1435. /*...sBitmapWndProc:0:*/
  1436. #define    WC_BITMAP    "GbmV2BitmapViewerClass"
  1437.  
  1438. static BOOL fTracking = FALSE;
  1439.  
  1440. /*
  1441. This is a pretty simple window class. Its aim in life is to display the bitmap
  1442. held by the global variable 'hbm'.
  1443. */
  1444.  
  1445. static HBITMAP hbm = NULLHANDLE;
  1446. static LONG lColorBg, lColorFg;
  1447. static HMTX hmtxHbm;
  1448.  
  1449. static VOID RequestHbm(VOID)
  1450.     {
  1451.     DosRequestMutexSem(hmtxHbm, SEM_INDEFINITE_WAIT);
  1452.     }
  1453.  
  1454. static VOID ReleaseHbm(VOID)
  1455.     {
  1456.     DosReleaseMutexSem(hmtxHbm);
  1457.     }
  1458.  
  1459. MRESULT _System BitmapWndProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  1460.     {
  1461.     switch ( (int) msg )
  1462.         {
  1463. /*...sWM_PAINT       \45\ repaint client area:16:*/
  1464. case WM_PAINT:
  1465.     {
  1466.     RECTL rclUpdate;
  1467.     HPS hps = WinBeginPaint(hwnd, (HPS) NULL, &rclUpdate);
  1468.  
  1469.     RequestHbm();
  1470.  
  1471.     if ( hbm != (HBITMAP) NULL )
  1472.         {
  1473.         static SIZEL sizl = { 0, 0 };
  1474.         HAB hab = WinQueryAnchorBlock(hwnd);
  1475.         HDC hdcBmp = DevOpenDC(hab, OD_MEMORY, "*", 0L, (PDEVOPENDATA) NULL, (HDC) NULL);
  1476.         HPS hpsBmp = GpiCreatePS(hab, hdcBmp, &sizl, PU_PELS | GPIF_DEFAULT | GPIT_MICRO | GPIA_ASSOC);
  1477.         POINTL aptl [3];
  1478.         BITMAPINFOHEADER bmp;
  1479.  
  1480.         GpiQueryBitmapParameters(hbm, &bmp);
  1481.  
  1482.         GpiSetBitmap(hpsBmp, hbm);
  1483.  
  1484.         GpiSetBackColor(hps, GpiQueryColorIndex(hps, 0, lColorBg));
  1485.         GpiSetColor    (hps, GpiQueryColorIndex(hps, 0, lColorFg));
  1486.  
  1487.         aptl [0].x = 0;
  1488.         aptl [0].y = 0;
  1489.         aptl [1].x = bmp.cx;
  1490.         aptl [1].y = bmp.cy;
  1491.         aptl [2].x = 0;
  1492.         aptl [2].y = 0;
  1493.         GpiBitBlt(hps, hpsBmp, 3L, aptl, ROP_SRCCOPY, BBO_IGNORE);
  1494.  
  1495.         GpiSetBitmap(hpsBmp, (HBITMAP) NULL);
  1496.         GpiDestroyPS(hpsBmp);
  1497.         DevCloseDC(hdcBmp);
  1498.  
  1499.         if ( fSelectionDefined )
  1500.             {
  1501.             POINTL ptl;
  1502.  
  1503.             GpiSetMix(hps, FM_INVERT);
  1504.             ptl.x = rclSelection.xLeft;
  1505.             ptl.y = rclSelection.yBottom;
  1506.             GpiMove(hps, &ptl);
  1507.             ptl.x = rclSelection.xRight - 1L;
  1508.             ptl.y = rclSelection.yTop   - 1L;
  1509.             GpiBox(hps, DRO_OUTLINE, &ptl, 0L, 0L);
  1510.             }
  1511.         }
  1512.  
  1513.     ReleaseHbm();
  1514.  
  1515.     WinEndPaint(hps);
  1516.     }
  1517.     return ( (MRESULT) 0 );
  1518. /*...e*/
  1519. /*...sWM_CHAR        \45\ got a character from the user:16:*/
  1520. #define    KS(vkey,kc) ((vkey)+((kc&(KC_ALT|KC_SHIFT|KC_CTRL))<<16))
  1521.  
  1522. case WM_CHAR:
  1523.     {
  1524.     USHORT fs        = SHORT1FROMMP(mp1);
  1525.     CHAR   ch        = (CHAR) SHORT1FROMMP(mp2);
  1526.     USHORT vkey      = SHORT2FROMMP(mp2);
  1527.     HWND hwndHscroll = WinWindowFromID(hwndScroller, SCID_HSCROLL);
  1528.     HWND hwndVscroll = WinWindowFromID(hwndScroller, SCID_VSCROLL);
  1529.  
  1530.     if ( fTracking )
  1531.         /* Swallow the key */
  1532.         return ( (MRESULT) 0 );
  1533.  
  1534.     if ( fs & KC_VIRTUALKEY )
  1535.         {
  1536.         switch ( KS(vkey,fs) )
  1537.             {
  1538.             case KS(VK_LEFT,0):
  1539.             case KS(VK_RIGHT,0):
  1540.                 return ( WinSendMsg(hwndHscroll, msg, mp1, mp2) );
  1541.             case KS(VK_LEFT,KC_SHIFT):
  1542.                 fs &= ~KC_SHIFT;
  1543.                 vkey = VK_PAGEUP;
  1544.                 mp1 = MPFROMSHORT(fs);
  1545.                 mp2 = MPFROM2SHORT(ch, vkey);
  1546.                 return ( WinSendMsg(hwndHscroll, msg, mp1, mp2) );
  1547.             case KS(VK_RIGHT,KC_SHIFT):
  1548.                 fs &= ~KC_SHIFT;
  1549.                 vkey = VK_PAGEDOWN;
  1550.                 mp1 = MPFROMSHORT(fs);
  1551.                 mp2 = MPFROM2SHORT(ch, vkey);
  1552.                 return ( WinSendMsg(hwndHscroll, msg, mp1, mp2) );
  1553.             case KS(VK_UP,0):
  1554.             case KS(VK_DOWN,0):
  1555.             case KS(VK_PAGEUP,0):
  1556.             case KS(VK_PAGEDOWN,0):
  1557.                 return ( WinSendMsg(hwndVscroll, msg, mp1, mp2) );
  1558.             case KS(VK_UP,KC_SHIFT):
  1559.                 fs &= ~KC_SHIFT;
  1560.                 vkey = VK_PAGEUP;
  1561.                 mp1 = MPFROMSHORT(fs);
  1562.                 mp2 = MPFROM2SHORT(ch, vkey);
  1563.                 return ( WinSendMsg(hwndVscroll, msg, mp1, mp2) );
  1564.             case KS(VK_DOWN,KC_SHIFT):
  1565.                 fs &= ~KC_SHIFT;
  1566.                 vkey = VK_PAGEDOWN;
  1567.                 mp1 = MPFROMSHORT(fs);
  1568.                 mp2 = MPFROM2SHORT(ch, vkey);
  1569.                 return ( WinSendMsg(hwndVscroll, msg, mp1, mp2) );
  1570.             }
  1571.         }
  1572.     }
  1573.     break;
  1574. /*...e*/
  1575. /*...sWM_BUTTON2DOWN \45\ cancel current selection:16:*/
  1576. case WM_BUTTON2DOWN:
  1577.     fSelectionDefined = FALSE;
  1578.     WinInvalidateRect(hwnd, NULL, TRUE);
  1579.     WinUpdateWindow(hwnd);
  1580.     break;
  1581. /*...e*/
  1582. /*...sWM_MOUSEMOVE   \45\ hourglass:16:*/
  1583. case WM_MOUSEMOVE:
  1584.     if ( fTracking )
  1585.         return ( (MRESULT) 0 );
  1586.  
  1587.     if ( fBusy )
  1588.         {
  1589.         WinSetPointer(HWND_DESKTOP,
  1590.             WinQuerySysPointer(HWND_DESKTOP, SPTR_WAIT, FALSE));
  1591.         return ( (MRESULT) 0 );
  1592.         }
  1593.     break;
  1594. /*...e*/
  1595.         }
  1596.     return ( WinDefWindowProc(hwnd, msg, mp1, mp2) );
  1597.     }
  1598. /*...e*/
  1599. /*...sSetBitmap:0:*/
  1600. static VOID SetBitmap(HBITMAP hbmNew)
  1601.     {
  1602.     HBITMAP hbmOld = hbm;
  1603.     BOOL fOld = ( hbmOld != (HBITMAP) NULL );
  1604.     BOOL fNew = ( hbmNew != (HBITMAP) NULL );
  1605.  
  1606.     RequestHbm();
  1607.  
  1608.     if ( hbmNew == hbmOld )
  1609.         {
  1610.         ReleaseHbm();
  1611.         return;
  1612.         }
  1613.  
  1614.     hbm = hbmNew;
  1615.  
  1616.     if ( fOld )
  1617.         GpiDeleteBitmap(hbmOld);
  1618.  
  1619.     if ( fNew )
  1620.         {
  1621.         BITMAPINFOHEADER2 bmp;
  1622.  
  1623.         bmp.cbFix = sizeof(BITMAPINFOHEADER2);
  1624.         GpiQueryBitmapInfoHeader(hbm, &bmp);
  1625.         ReleaseHbm();
  1626.         WinShowWindow(hwndBitmap, FALSE);        
  1627.         WinSetWindowPos(hwndBitmap, (HWND) NULL, 0,0,bmp.cx,bmp.cy, SWP_SIZE);
  1628.         }
  1629.     else
  1630.         {
  1631.         ReleaseHbm();
  1632.         WinSetWindowPos(hwndBitmap, (HWND) NULL, 0,0,0,0, SWP_SIZE);
  1633.         }
  1634.  
  1635.     if ( !fOld && fNew )
  1636.         {
  1637.         WinSendMsg(hwndScroller, SCM_CHILD, MPFROMHWND(hwndBitmap), NULL);
  1638.         WinShowWindow(hwndBitmap, TRUE);
  1639.         }
  1640.  
  1641.     if ( fOld && fNew )
  1642.         {
  1643.         WinSendMsg(hwndScroller, SCM_SIZE, MPFROMHWND(hwndBitmap), NULL);
  1644.         WinShowWindow(hwndBitmap, TRUE);
  1645.         }
  1646.  
  1647.     if ( fOld && !fNew )
  1648.         WinSendMsg(hwndScroller, SCM_CHILD, MPFROMHWND((HWND) NULL), NULL);
  1649.     }
  1650. /*...e*/
  1651. /*...sSelect:0:*/
  1652. /*...sTracking:0:*/
  1653. /*
  1654. Credit for this to Petzold.
  1655. */
  1656.  
  1657. static BOOL Tracking(
  1658.     HWND hwnd,
  1659.     RECTL *prclTrack,
  1660.     int x, int y, int cx, int cy,
  1661.     HPOINTER hptr1, HPOINTER hptr2
  1662.     )
  1663.     {
  1664.     TRACKINFO ti;
  1665.  
  1666.     ti.cxBorder   = 1;
  1667.     ti.cyBorder   = 1;
  1668.     ti.cxGrid     = 0;
  1669.     ti.cyGrid     = 0;
  1670.     ti.cxKeyboard = 4;
  1671.     ti.cyKeyboard = 4;
  1672.  
  1673.     ti.rclBoundary.xLeft   = x;
  1674.     ti.rclBoundary.xRight  = x + cx;
  1675.     ti.rclBoundary.yBottom = y;
  1676.     ti.rclBoundary.yTop    = y + cy;
  1677.  
  1678.     ti.ptlMinTrackSize.x = 1;
  1679.     ti.ptlMinTrackSize.y = 1;
  1680.  
  1681.     ti.ptlMaxTrackSize.x = cx;
  1682.     ti.ptlMaxTrackSize.y = cy;
  1683.  
  1684.     ti.rclTrack.xLeft   = x + cx/4;
  1685.     ti.rclTrack.xRight  = x + cx/4;
  1686.     ti.rclTrack.yBottom = y + cy/4;
  1687.     ti.rclTrack.yTop    = y + cy/4;
  1688.  
  1689. /*...smove pointer:8:*/
  1690. {
  1691. POINTL ptl;
  1692.  
  1693. ptl.x = ti.rclTrack.xLeft;
  1694. ptl.y = ti.rclTrack.yBottom;
  1695. WinMapWindowPoints(hwnd, HWND_DESKTOP, &ptl, 1);
  1696. WinSetPointerPos(HWND_DESKTOP, ptl.x, ptl.y);
  1697. }
  1698. /*...e*/
  1699.  
  1700.     ti.fs = TF_MOVE | TF_STANDARD | TF_SETPOINTERPOS | TF_ALLINBOUNDARY;
  1701.  
  1702.     WinSetPointer(HWND_DESKTOP, hptr1);
  1703.  
  1704.     if ( !WinTrackRect(hwnd, (HPS) NULL, &ti) )
  1705.         return ( FALSE );
  1706.  
  1707.     ti.fs = TF_RIGHT | TF_TOP | TF_STANDARD | TF_SETPOINTERPOS | TF_ALLINBOUNDARY;
  1708.  
  1709.     WinSetPointer(HWND_DESKTOP, hptr2);
  1710.  
  1711.     if ( !WinTrackRect(hwnd, (HPS) NULL, &ti) )
  1712.         return ( FALSE );
  1713.  
  1714.     *prclTrack = ti.rclTrack;
  1715.  
  1716.     return ( TRUE );
  1717.     }
  1718. /*...e*/
  1719.  
  1720. static BOOL Select(
  1721.     HWND hwnd,
  1722.     RECTL *prclTrack,
  1723.     int x, int y, int cx, int cy
  1724.     )
  1725.     {
  1726.     HPOINTER hptr1 = WinLoadPointer(HWND_DESKTOP, (HMODULE) NULL, RID_SELECT1);
  1727.     HPOINTER hptr2 = WinLoadPointer(HWND_DESKTOP, (HMODULE) NULL, RID_SELECT2);
  1728.     BOOL f;
  1729.  
  1730.     fTracking = TRUE;
  1731.     f = Tracking(hwnd, prclTrack, x, y, cx, cy, hptr1, hptr2);
  1732.     fTracking = FALSE;
  1733.  
  1734.     WinDestroyPointer(hptr1);
  1735.     WinDestroyPointer(hptr2);
  1736.  
  1737.     return ( f );
  1738.     }
  1739. /*...e*/
  1740. /*...sDeleteBitmap:0:*/
  1741. static VOID DeleteBitmap(VOID)
  1742.     {
  1743.     if ( fGotBitmap )
  1744.         {
  1745.         free(pbData);
  1746.         fGotBitmap = FALSE;
  1747.         }
  1748.     }
  1749. /*...e*/
  1750. /*...sCaption:0:*/
  1751. static VOID Caption(HWND hwndClient, CHAR *szFmt, CHAR *szFileName)
  1752.     {
  1753.     HWND hwndFrame = WinQueryWindow(hwndClient, QW_PARENT);
  1754.     CHAR sz [20+MAX_FILE_NAME+50+1], *szAppend;
  1755.  
  1756.     strcpy(sz, szAppName);
  1757.  
  1758.     szAppend = sz + strlen(sz);
  1759.  
  1760.     sprintf(szAppend, szFmt, 
  1761.         ( szFileName [0] != '\0' ) ? szFileName : "(untitled)" );
  1762.  
  1763.     WinSetWindowText(hwndFrame, sz);
  1764.     }
  1765. /*...e*/
  1766. /*...sObjectWndProc:0:*/
  1767. #define    WC_GBMV2_OBJECT    "GbmV2ObjectWindowClass"
  1768.  
  1769. /*...sUM_ user window messages:0:*/
  1770. #define    UM_NEW             WM_USER
  1771. #define    UM_OPEN            (WM_USER+ 1)
  1772. #define    UM_SAVE            (WM_USER+ 2)
  1773. #define    UM_SAVE_AS        (WM_USER+ 3)
  1774. #define    UM_PRINT        (WM_USER+ 4)
  1775. #define    UM_UNDO            (WM_USER+ 5)
  1776. #define    UM_SELECT        (WM_USER+ 6)
  1777. #define    UM_SELECT_ALL        (WM_USER+ 7)
  1778. #define    UM_DESELECT        (WM_USER+ 8)
  1779. #define    UM_COPY            (WM_USER+ 9)
  1780. #define    UM_REF_HORZ        (WM_USER+10)
  1781. #define    UM_REF_VERT        (WM_USER+11)
  1782. #define    UM_ROT_90        (WM_USER+12)
  1783. #define    UM_ROT_180        (WM_USER+13)
  1784. #define    UM_ROT_270        (WM_USER+14)
  1785. #define    UM_TRANSPOSE        (WM_USER+15)
  1786. #define    UM_CROP            (WM_USER+16)
  1787. #define    UM_COLOUR        (WM_USER+17)
  1788. #define    UM_MAP            (WM_USER+18)
  1789. #define    UM_VIEW_NULL        (WM_USER+19)
  1790. #define    UM_VIEW_HALFTONE    (WM_USER+20)
  1791. #define    UM_VIEW_ERRDIFF        (WM_USER+21)
  1792.  
  1793. #define    UM_DONE            (WM_USER+22)
  1794. /*...e*/
  1795.  
  1796. /*...sReflect:0:*/
  1797. static VOID Reflect(HWND hwndClient, BOOL fHorz, BOOL fVert, BOOL fTranspose, CHAR *szWhat)
  1798.     {
  1799.     HBITMAP hbmNew;
  1800.     int stride, stride_t;
  1801.     GBM gbmNew;
  1802.     BYTE *pbDataNew;
  1803.     RECTL rclNew;
  1804.     LONG lColorBgNew, lColorFgNew;
  1805.  
  1806.     Caption(hwndClient, " - reflecting %s", szFileName);
  1807.  
  1808.     stride = (((gbm.w * gbm.bpp + 31) / 32) * 4);
  1809.     if ( (pbDataNew = malloc(stride * gbm.h)) == NULL )
  1810.         {
  1811.         Warning(hwndClient, "Out of memory");
  1812.         return;
  1813.         }
  1814.         
  1815.     gbmNew = gbm;
  1816.     memcpy(pbDataNew, pbData, stride * gbm.h);
  1817.     if ( fSelectionDefined )
  1818.         rclNew = rclSelection;
  1819.     LowPri();
  1820.     if ( fHorz )
  1821.         {
  1822.         if ( !gbm_ref_horz(&gbm, pbDataNew) )
  1823.             {
  1824.             free(pbDataNew);
  1825.             RegPri();
  1826.             Warning(hwndClient, "Out of memory");
  1827.             return;
  1828.             }
  1829.         if ( fSelectionDefined )
  1830.             {
  1831.             LONG xLeft  = rclNew.xLeft;
  1832.             LONG xRight = rclNew.xRight;
  1833.             rclNew.xLeft  = gbm.w - xRight;
  1834.             rclNew.xRight = gbm.w - xLeft;
  1835.             }
  1836.         }
  1837.  
  1838.     if ( fVert )
  1839.         {
  1840.         if ( !gbm_ref_vert(&gbm, pbDataNew) )
  1841.             {
  1842.             free(pbDataNew);
  1843.             RegPri();
  1844.             Warning(hwndClient, "Out of memory");
  1845.             return;
  1846.             }
  1847.         if ( fSelectionDefined )
  1848.             {
  1849.             LONG yBottom = rclNew.yBottom;
  1850.             LONG yTop    = rclNew.yTop;
  1851.             rclNew.yTop    = gbm.h - yBottom;
  1852.             rclNew.yBottom = gbm.h - yTop;
  1853.             }
  1854.         }
  1855.  
  1856.     if ( fTranspose )
  1857.         {
  1858.         BYTE *pbDataTrans;
  1859.         int t;
  1860.  
  1861.         stride_t = (((gbm.h * gbm.bpp + 31) / 32) * 4);
  1862.  
  1863.         if ( (pbDataTrans = malloc(stride_t * gbm.w)) == NULL )
  1864.             {
  1865.             free(pbDataNew);
  1866.             RegPri();
  1867.             Warning(hwndClient, "Out of memory");
  1868.             return;
  1869.             }
  1870.  
  1871.         gbm_transpose(&gbm, pbDataNew, pbDataTrans);
  1872.         free(pbDataNew);
  1873.         pbDataNew = pbDataTrans;
  1874.         t = gbmNew.w; gbmNew.w = gbmNew.h; gbmNew.h = t;
  1875.  
  1876.         if ( fSelectionDefined )
  1877.             {
  1878.             LONG tt;
  1879.  
  1880.             tt = rclNew.xLeft; rclNew.xLeft = rclNew.yBottom; rclNew.yBottom = tt;
  1881.             tt = rclNew.xRight; rclNew.xRight = rclNew.yTop; rclNew.yTop = tt;
  1882.             }
  1883.         }
  1884.  
  1885.     Caption(hwndClient, " - rendering %s", szFileName);
  1886.     if ( !MakeVisual(hwndClient, &gbmNew, gbmrgb, pbDataNew, bView, &hbmNew, &lColorBgNew, &lColorFgNew) )
  1887.         {
  1888.         free(pbDataNew);
  1889.         RegPri();
  1890.         return;
  1891.         }
  1892.  
  1893.     KeepForUndo(&gbm, gbmrgb, pbData, szWhat);
  1894.  
  1895.     gbm = gbmNew;
  1896.     free(pbData);
  1897.     pbData = pbDataNew;
  1898.     if ( fSelectionDefined )
  1899.         rclSelection = rclNew;
  1900.     lColorBg = lColorBgNew;
  1901.     lColorFg = lColorFgNew;
  1902.     SetBitmap(hbmNew);
  1903.     WinInvalidateRect(hwndBitmap, NULL, TRUE);
  1904.     WinUpdateWindow(hwndBitmap);
  1905.     fUnsavedChanges = TRUE;
  1906.     RegPri();
  1907.     }
  1908. /*...e*/
  1909. /*...sColourAdjust:0:*/
  1910. /*...smapinfos:0:*/
  1911. #define    CVT_I_TO_L    0
  1912. #define    CVT_I_TO_P    1
  1913. #define    CVT_L_TO_I    2
  1914. #define    CVT_L_TO_P    3
  1915. #define    CVT_P_TO_I    4
  1916. #define    CVT_P_TO_L    5
  1917. /*...e*/
  1918.  
  1919. static int map = CVT_I_TO_L;
  1920. static double gama = 2.1, shelf = 0.0;
  1921.  
  1922. MRESULT _System ColourDlgProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  1923.     {
  1924.     switch ( msg )
  1925.         {
  1926. /*...sWM_INITDLG:16:*/
  1927. case WM_INITDLG:
  1928.     {
  1929.     CHAR sz [50+1];
  1930.     SHORT id;
  1931.  
  1932.     switch ( map )
  1933.         {
  1934.         case CVT_I_TO_L:    id = DID_I_TO_L;    break;
  1935.         case CVT_I_TO_P:    id = DID_I_TO_P;    break;
  1936.         case CVT_L_TO_I:    id = DID_L_TO_I;    break;
  1937.         case CVT_L_TO_P:    id = DID_L_TO_P;    break;
  1938.         case CVT_P_TO_I:    id = DID_P_TO_I;    break;
  1939.         case CVT_P_TO_L:    id = DID_P_TO_L;    break;
  1940.         }
  1941.  
  1942.     WinSendDlgItemMsg(hwnd, id, BM_CLICK, MPFROMSHORT(TRUE), NULL);
  1943.     WinSetFocus(HWND_DESKTOP, WinWindowFromID(hwnd, id));
  1944.  
  1945.     sprintf(sz, "%1.1lf", gama);
  1946.     WinSetDlgItemText(hwnd, DID_GAMMA, sz);
  1947.     RestrictEntryfield(WinWindowFromID(hwnd, DID_GAMMA), NULL, NULL, "0123456789.", NULL);
  1948.  
  1949.     sprintf(sz, "%1.1lf", shelf);
  1950.     WinSetDlgItemText(hwnd, DID_SHELF, sz);
  1951.     RestrictEntryfield(WinWindowFromID(hwnd, DID_SHELF), NULL, NULL, "0123456789.", NULL);
  1952.  
  1953.     TidySysMenu(hwnd);
  1954.     return ( (MRESULT) TRUE ); /* We have set the focus */
  1955.     }
  1956. /*...e*/
  1957. /*...sWM_COMMAND:16:*/
  1958. case WM_COMMAND:
  1959.     switch ( COMMANDMSG(&msg) -> cmd )
  1960.         {
  1961. /*...sDID_OK:32:*/
  1962. case DID_OK:
  1963.     {
  1964.     SHORT sInx = SHORT1FROMMR(WinSendDlgItemMsg(hwnd, DID_I_TO_L, BM_QUERYCHECKINDEX, NULL, NULL)) - 1;
  1965.     CHAR sz [50+1];
  1966.     int mapNew;
  1967.     double gamaNew, shelfNew;
  1968.  
  1969.     switch ( sInx )
  1970.         {
  1971.         case DID_I_TO_L - DID_I_TO_L:    mapNew = CVT_I_TO_L;    break;
  1972.         case DID_I_TO_P - DID_I_TO_L:    mapNew = CVT_I_TO_P;    break;
  1973.         case DID_L_TO_I - DID_I_TO_L:    mapNew = CVT_L_TO_I;    break;
  1974.         case DID_L_TO_P - DID_I_TO_L:    mapNew = CVT_L_TO_P;    break;
  1975.         case DID_P_TO_I - DID_I_TO_L:    mapNew = CVT_P_TO_I;    break;
  1976.         case DID_P_TO_L - DID_I_TO_L:    mapNew = CVT_P_TO_L;    break;
  1977.         }
  1978.     WinQueryDlgItemText(hwnd, DID_GAMMA, sizeof(sz), sz);
  1979.     sscanf(sz, "%lf", &gamaNew);
  1980.     WinQueryDlgItemText(hwnd, DID_SHELF, sizeof(sz), sz);
  1981.     sscanf(sz, "%lf", &shelfNew);
  1982.  
  1983.     if ( gamaNew < 0.1 || gamaNew > 10.0 )
  1984.         Warning(hwnd, "Gamma must be between 0.1 and 10.0");
  1985.     else if ( shelfNew < 0.0 || shelfNew > 1.0 )
  1986.         Warning(hwnd, "Shelf must be between 0.0 and 1.0");
  1987.     else
  1988.         {
  1989.         map   = mapNew;
  1990.         gama  = gamaNew;
  1991.         shelf = shelfNew;
  1992.         WinDismissDlg(hwnd, TRUE);
  1993.         return ( (MRESULT) 0 );
  1994.         }
  1995.     }
  1996.     break;
  1997. /*...e*/
  1998. /*...sDID_CANCEL:32:*/
  1999. case DID_CANCEL:
  2000.     WinDismissDlg(hwnd, FALSE);
  2001.     return ( (MRESULT) 0 );
  2002. /*...e*/
  2003.         }
  2004.     break;
  2005. /*...e*/
  2006. /*...sWM_CONTROL:16:*/
  2007. case WM_CONTROL:
  2008.     {
  2009.     SHORT id = SHORT1FROMMP(mp1);
  2010.     SHORT note = SHORT2FROMMP(mp1);
  2011.     HWND hwndG = WinWindowFromID(hwnd, DID_GAMMA_TEXT);
  2012.     HWND hwndS = WinWindowFromID(hwnd, DID_SHELF_TEXT);
  2013.  
  2014.     switch ( id )
  2015.         {
  2016.         case DID_I_TO_L:
  2017.         case DID_L_TO_I:
  2018.             if ( note == BN_CLICKED )
  2019.                 {
  2020.                 WinEnableWindow(hwndG, FALSE);
  2021.                 WinEnableWindow(hwndS, FALSE);
  2022.                 }
  2023.             break;
  2024.         case DID_I_TO_P:
  2025.         case DID_P_TO_I:
  2026.         case DID_P_TO_L:
  2027.         case DID_L_TO_P:
  2028.             if ( note == BN_CLICKED )
  2029.                 {
  2030.                 WinEnableWindow(hwndG, TRUE);
  2031.                 WinEnableWindow(hwndS, TRUE);
  2032.                 }
  2033.             break;
  2034.         }
  2035.     }
  2036.     break;
  2037. /*...e*/
  2038. /*...sWM_CLOSE:16:*/
  2039. case WM_CLOSE:
  2040.     WinDismissDlg(hwnd, FALSE);
  2041.     return ( (MRESULT) 0 );
  2042. /*...e*/
  2043. /*...sWM_HELP:16:*/
  2044. case WM_HELP:
  2045.     /* Parent is HWND_DESKTOP */
  2046.     /* WinDefDlgProc() will pass this up to the parent */
  2047.     /* So redirect to the owner */
  2048.     return ( WinSendMsg(WinQueryWindow(hwnd, QW_OWNER), msg, mp1, mp2) );
  2049. /*...e*/
  2050.         }
  2051.     return ( WinDefDlgProc(hwnd, msg, mp1, mp2) );
  2052.     }
  2053.  
  2054. /*...smap_compute:0:*/
  2055. /*...slstar_from_i:0:*/
  2056. static double lstar_from_i(double y)
  2057.     {
  2058.     y = pow(1.16 * y, 1.0/3.0) - 0.16;
  2059.  
  2060.     if ( y < 0.0 ) y = 0.0; else if ( y > 1.0 ) y = 1.0;
  2061.  
  2062.     return ( y );
  2063.     }
  2064. /*...e*/
  2065. /*...si_from_lstar:0:*/
  2066. static double i_from_lstar(double y)
  2067.     {
  2068.     y = pow(y + 0.16, 3.0) / 1.16;
  2069.  
  2070.     if ( y < 0.0 ) y = 0.0; else if ( y > 1.0 ) y = 1.0;
  2071.  
  2072.     return ( y );
  2073.     }
  2074. /*...e*/
  2075. /*...spal_from_i:0:*/
  2076. static double pal_from_i(double y, double gam, double shelf)
  2077.     {
  2078.     y = pow(y,1.0 / gam) * (1.0 - shelf) + shelf;
  2079.  
  2080.     if ( y < 0.0 ) y = 0.0; else if ( y > 1.0 ) y = 1.0;
  2081.  
  2082.     return ( y );
  2083.     }
  2084. /*...e*/
  2085. /*...si_from_pal:0:*/
  2086. static double i_from_pal(double y, double gam, double shelf)
  2087.     {
  2088.     if ( y >= shelf )
  2089.         y = pow((y - shelf) / (1.0 - shelf), gam);
  2090.     else
  2091.         y = 0.0;
  2092.  
  2093.     if ( y < 0.0 ) y = 0.0; else if ( y > 1.0 ) y = 1.0;
  2094.  
  2095.     return ( y );
  2096.     }
  2097. /*...e*/
  2098.  
  2099. static void map_compute(int m, byte remap [], double gam, double shelf)
  2100.     {
  2101.     int    i;
  2102.  
  2103.     for ( i = 0; i < 0x100; i++ )
  2104.         {
  2105.         double y = (double) i / 255.0;
  2106.  
  2107.         switch ( m )
  2108.             {
  2109.             case CVT_I_TO_P: y = pal_from_i(y, gam, shelf); break;
  2110.             case CVT_P_TO_I: y = i_from_pal(y, gam, shelf); break;
  2111.             case CVT_I_TO_L: y = lstar_from_i(y); break;
  2112.             case CVT_L_TO_I: y = i_from_lstar(y); break;
  2113.             case CVT_P_TO_L: y = lstar_from_i(i_from_pal(y, gam, shelf)); break;
  2114.             case CVT_L_TO_P: y = pal_from_i(i_from_lstar(y), gam, shelf); break;
  2115.             }
  2116.  
  2117.         remap [i] = (byte) (y * 255.0);
  2118.         }
  2119.     }
  2120. /*...e*/
  2121. /*...smap_data:0:*/
  2122. static void map_data(byte *data, int w, int h, byte remap [])
  2123.     {
  2124.     int stride = ((w * 3 + 3) & ~3);
  2125.     int x, y;
  2126.  
  2127.     for ( y = 0; y < h; y++, data += stride )
  2128.         for ( x = 0; x < w * 3; x++ )
  2129.             data [x] = remap [data [x]];
  2130.     }
  2131. /*...e*/
  2132. /*...smap_palette:0:*/
  2133. static void map_palette(GBMRGB *gbmrgb, int npals, byte remap [])
  2134.     {
  2135.     for ( ; npals--; gbmrgb++ )
  2136.         {
  2137.         gbmrgb -> b = remap [gbmrgb -> b];
  2138.         gbmrgb -> g = remap [gbmrgb -> g];
  2139.         gbmrgb -> r = remap [gbmrgb -> r];
  2140.         }
  2141.     }
  2142. /*...e*/
  2143.  
  2144. static VOID ColourAdjust(HWND hwndClient)
  2145.     {
  2146.     HBITMAP hbmNew;
  2147.     LONG lColorBgNew, lColorFgNew;
  2148.     BYTE abRemap [0x100];
  2149.  
  2150.     Caption(hwndClient, " - colour adjusting %s", szFileName);
  2151.  
  2152.     map_compute(map, abRemap, gama, shelf);
  2153.  
  2154.     LowPri();
  2155.     if ( gbm.bpp == 24 )
  2156. /*...smap the data:16:*/
  2157. {
  2158. int stride;
  2159. BYTE *pbDataNew;    
  2160.  
  2161. stride = (((gbm.w * gbm.bpp + 31) / 32) * 4);
  2162. if ( (pbDataNew = malloc(stride * gbm.h)) == NULL )
  2163.     {
  2164.     Warning(hwndClient, "Out of memory");
  2165.     return;
  2166.     }
  2167.  
  2168. memcpy(pbDataNew, pbData, stride * gbm.h);
  2169. map_data(pbDataNew, gbm.w, gbm.h, abRemap);
  2170.  
  2171. Caption(hwndClient, " - rendering %s", szFileName);
  2172. if ( !MakeVisual(hwndClient, &gbm, gbmrgb, pbDataNew, bView, &hbmNew, &lColorBgNew, &lColorFgNew) )
  2173.     {
  2174.     free(pbDataNew);
  2175.     RegPri();
  2176.     return;
  2177.     }
  2178.  
  2179. KeepForUndo(&gbm, gbmrgb, pbData, "colour space mapping");
  2180.  
  2181. free(pbData);
  2182. pbData = pbDataNew;
  2183. }
  2184. /*...e*/
  2185.     else
  2186. /*...smap the palette:16:*/
  2187. {
  2188. GBMRGB gbmrgbNew [0x100];
  2189.  
  2190. memcpy(gbmrgbNew, gbmrgb, (sizeof(GBMRGB) << gbm.bpp) );
  2191. map_palette(gbmrgbNew, 1 << gbm.bpp, abRemap);
  2192.  
  2193. Caption(hwndClient, " - rendering %s", szFileName);
  2194. if ( !MakeVisual(hwndClient, &gbm, gbmrgbNew, pbData, bView, &hbmNew, &lColorBgNew, &lColorFgNew) )
  2195.     {
  2196.     RegPri();
  2197.     return;
  2198.     }
  2199.  
  2200. KeepForUndo(&gbm, gbmrgb, NULL, "colour space mapping");
  2201.  
  2202. memcpy(gbmrgb, gbmrgbNew, (sizeof(GBMRGB) << gbm.bpp) );
  2203. }
  2204. /*...e*/
  2205.  
  2206.     lColorBg = lColorBgNew;
  2207.     lColorFg = lColorFgNew;
  2208.     SetBitmap(hbmNew);
  2209.     WinInvalidateRect(hwndBitmap, NULL, TRUE);
  2210.     WinUpdateWindow(hwndBitmap);
  2211.     fUnsavedChanges = TRUE;
  2212.     RegPri();
  2213.     }
  2214. /*...e*/
  2215. /*...sMap:0:*/
  2216. /*...smapinfos:0:*/
  2217. #define    CVT_BW        0
  2218. #define    CVT_VGA        1
  2219. #define    CVT_8        2
  2220. #define    CVT_4G        3
  2221. #define    CVT_784        4
  2222. #define    CVT_666        5
  2223. #define    CVT_8G        6
  2224. #define    CVT_TRIPEL    7
  2225. #define    CVT_RGB        8
  2226. #define    CVT_FREQ    9
  2227.  
  2228. #define    CVT_NEAREST    0
  2229. #define    CVT_ERRDIFF    1
  2230. #define    CVT_HALFTONE    2
  2231. /*...e*/
  2232.  
  2233. static int iKeepRed = 8, iKeepGreen = 8, iKeepBlue = 8, nCols = 256;
  2234. static int iPal = CVT_784, iAlg = CVT_ERRDIFF;
  2235.  
  2236. MRESULT _System MapDlgProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  2237.     {
  2238.     switch ( msg )
  2239.         {
  2240. /*...sWM_INITDLG:16:*/
  2241. case WM_INITDLG:
  2242.     {
  2243.     CHAR sz [50+1];
  2244.     SHORT id;
  2245.  
  2246.     switch ( iPal )
  2247.         {
  2248.         case CVT_BW:        id = DID_MAP_BW;    break;
  2249.         case CVT_VGA:        id = DID_MAP_VGA;    break;
  2250.         case CVT_8:        id = DID_MAP_8;        break;
  2251.         case CVT_4G:        id = DID_MAP_4G;    break;
  2252.         case CVT_784:        id = DID_MAP_784;    break;
  2253.         case CVT_666:        id = DID_MAP_666;    break;
  2254.         case CVT_8G:        id = DID_MAP_8G;    break;
  2255.         case CVT_TRIPEL:    id = DID_MAP_TRIPEL;    break;
  2256.         case CVT_RGB:        id = DID_MAP_RGB;    break;
  2257.         case CVT_FREQ:        id = DID_MAP_FREQ;    break;
  2258.         }
  2259.  
  2260.     WinSendDlgItemMsg(hwnd, id, BM_CLICK, MPFROMSHORT(TRUE), NULL);
  2261.     WinSetFocus(HWND_DESKTOP, WinWindowFromID(hwnd, id));
  2262.  
  2263.     switch ( iAlg )
  2264.         {
  2265.         case CVT_NEAREST:    id = DID_NEAREST;    break;
  2266.         case CVT_HALFTONE:    id = DID_HALFTONE;    break;
  2267.         case CVT_ERRDIFF:    id = DID_ERRDIFF;    break;
  2268.         }
  2269.  
  2270.     WinSendDlgItemMsg(hwnd, id, BM_CLICK, MPFROMSHORT(TRUE), NULL);
  2271.  
  2272.     sprintf(sz, "%d", iKeepRed);
  2273.     WinSetDlgItemText(hwnd, DID_R, sz);
  2274.     RestrictEntryfield(WinWindowFromID(hwnd, DID_R), NULL, NULL, "0123456789", NULL);
  2275.  
  2276.     sprintf(sz, "%d", iKeepGreen);
  2277.     WinSetDlgItemText(hwnd, DID_G, sz);
  2278.     RestrictEntryfield(WinWindowFromID(hwnd, DID_G), NULL, NULL, "0123456789", NULL);
  2279.  
  2280.     sprintf(sz, "%d", iKeepBlue);
  2281.     WinSetDlgItemText(hwnd, DID_B, sz);
  2282.     RestrictEntryfield(WinWindowFromID(hwnd, DID_B), NULL, NULL, "0123456789", NULL);
  2283.  
  2284.     sprintf(sz, "%d", nCols);
  2285.     WinSetDlgItemText(hwnd, DID_N, sz);
  2286.     RestrictEntryfield(WinWindowFromID(hwnd, DID_N), NULL, NULL, "0123456789", NULL);
  2287.  
  2288.     TidySysMenu(hwnd);
  2289.     return ( (MRESULT) TRUE ); /* We have set the focus */
  2290.     }
  2291. /*...e*/
  2292. /*...sWM_CONTROL:16:*/
  2293. case WM_CONTROL:
  2294.     {
  2295.     SHORT id = SHORT1FROMMP(mp1);
  2296.     SHORT note = SHORT2FROMMP(mp1);
  2297.     HWND hwndR = WinWindowFromID(hwnd, DID_R_TEXT);
  2298.     HWND hwndG = WinWindowFromID(hwnd, DID_G_TEXT);
  2299.     HWND hwndB = WinWindowFromID(hwnd, DID_B_TEXT);
  2300.     HWND hwndN = WinWindowFromID(hwnd, DID_N_TEXT);
  2301.     HWND hwndH = WinWindowFromID(hwnd, DID_HALFTONE);
  2302.     HWND hwndE = WinWindowFromID(hwnd, DID_ERRDIFF);
  2303.  
  2304.     switch ( id )
  2305.         {
  2306.         case DID_MAP_BW:
  2307.         case DID_MAP_8:
  2308.         case DID_MAP_VGA:
  2309.         case DID_MAP_4G:
  2310.         case DID_MAP_784:
  2311.         case DID_MAP_666:
  2312.         case DID_MAP_8G:
  2313.         case DID_MAP_TRIPEL:
  2314.             if ( note == BN_CLICKED )
  2315.                 {
  2316.                 WinEnableWindow(hwndR, FALSE);
  2317.                 WinEnableWindow(hwndG, FALSE);
  2318.                 WinEnableWindow(hwndB, FALSE);
  2319.                 WinEnableWindow(hwndN, FALSE);
  2320.                 }
  2321.             break;
  2322.         case DID_MAP_RGB:
  2323.             if ( note == BN_CLICKED )
  2324.                 {
  2325.                 WinEnableWindow(hwndR, TRUE);
  2326.                 WinEnableWindow(hwndG, TRUE);
  2327.                 WinEnableWindow(hwndB, TRUE);
  2328.                 WinEnableWindow(hwndN, FALSE);
  2329.                 }
  2330.             break;
  2331.         case DID_MAP_FREQ:
  2332.             if ( note == BN_CLICKED )
  2333.                 {
  2334.                 WinEnableWindow(hwndR, TRUE);
  2335.                 WinEnableWindow(hwndG, TRUE);
  2336.                 WinEnableWindow(hwndB, TRUE);
  2337.                 WinEnableWindow(hwndN, TRUE);
  2338.                 }
  2339.             break;
  2340.         }
  2341.  
  2342.     switch ( id )
  2343.         {
  2344.         case DID_MAP_8G:
  2345.         case DID_MAP_TRIPEL:
  2346.         case DID_MAP_FREQ:
  2347.             if ( note == BN_CLICKED )
  2348.                 {
  2349.                 WinSendDlgItemMsg(hwnd, DID_NEAREST, BM_CLICK, MPFROMSHORT(TRUE), NULL);
  2350.                 WinEnableWindow(hwndH, FALSE);
  2351.                 WinEnableWindow(hwndE, FALSE);
  2352.                 }
  2353.             break;
  2354.         case DID_MAP_BW:
  2355.         case DID_MAP_4G:
  2356.             if ( note == BN_CLICKED )
  2357.                 {
  2358.                 WinSendDlgItemMsg(hwnd, DID_NEAREST, BM_CLICK, MPFROMSHORT(TRUE), NULL);
  2359.                 WinEnableWindow(hwndH, FALSE);
  2360.                 WinEnableWindow(hwndE, TRUE);
  2361.                 }
  2362.             break;
  2363.         case DID_MAP_8:
  2364.         case DID_MAP_VGA:
  2365.         case DID_MAP_784:
  2366.         case DID_MAP_666:
  2367.         case DID_MAP_RGB:
  2368.             if ( note == BN_CLICKED )
  2369.                 {
  2370.                 WinEnableWindow(hwndH, TRUE);
  2371.                 WinEnableWindow(hwndE, TRUE);
  2372.                 }
  2373.             break;
  2374.         }
  2375.     }
  2376.     break;
  2377. /*...e*/
  2378. /*...sWM_COMMAND:16:*/
  2379. case WM_COMMAND:
  2380.     switch ( COMMANDMSG(&msg) -> cmd )
  2381.         {
  2382. /*...sDID_OK:32:*/
  2383. case DID_OK:
  2384.     {
  2385.     SHORT sInx;
  2386.     CHAR sz [50+1];
  2387.     int iPalNew, iAlgNew;
  2388.     int iKeepRedNew, iKeepGreenNew, iKeepBlueNew, nColsNew;
  2389.  
  2390.     sInx = SHORT1FROMMR(WinSendDlgItemMsg(hwnd, DID_MAP_BW, BM_QUERYCHECKINDEX, NULL, NULL)) - 1;
  2391.     switch ( sInx )
  2392.         {
  2393.         case DID_MAP_BW     - DID_MAP_BW:    iPalNew = CVT_BW;    break;
  2394.         case DID_MAP_VGA    - DID_MAP_BW:    iPalNew = CVT_VGA;    break;
  2395.         case DID_MAP_8      - DID_MAP_BW:    iPalNew = CVT_8;    break;
  2396.         case DID_MAP_4G     - DID_MAP_BW:    iPalNew = CVT_4G;    break;
  2397.         case DID_MAP_784    - DID_MAP_BW:    iPalNew = CVT_784;    break;
  2398.         case DID_MAP_666    - DID_MAP_BW:    iPalNew = CVT_666;    break;
  2399.         case DID_MAP_8G     - DID_MAP_BW:    iPalNew = CVT_8G;    break;
  2400.         case DID_MAP_TRIPEL - DID_MAP_BW:    iPalNew = CVT_TRIPEL;    break;
  2401.         case DID_MAP_RGB    - DID_MAP_BW:    iPalNew = CVT_RGB;    break;
  2402.         case DID_MAP_FREQ   - DID_MAP_BW:    iPalNew = CVT_FREQ;    break;
  2403.         }
  2404.  
  2405.     WinEnableWindow(WinWindowFromID(hwnd, DID_NEAREST ), TRUE);
  2406.     WinEnableWindow(WinWindowFromID(hwnd, DID_HALFTONE), TRUE);
  2407.     WinEnableWindow(WinWindowFromID(hwnd, DID_ERRDIFF ), TRUE);
  2408.  
  2409.     sInx = SHORT1FROMMR(WinSendDlgItemMsg(hwnd, DID_NEAREST, BM_QUERYCHECKINDEX, NULL, NULL)) - 1;
  2410.     switch ( sInx )
  2411.         {
  2412.         case DID_NEAREST  - DID_NEAREST:    iAlgNew = CVT_NEAREST;    break;
  2413.         case DID_HALFTONE - DID_NEAREST:    iAlgNew = CVT_HALFTONE;    break;
  2414.         case DID_ERRDIFF  - DID_NEAREST:    iAlgNew = CVT_ERRDIFF;    break;
  2415.         }
  2416.  
  2417.     WinQueryDlgItemText(hwnd, DID_R, sizeof(sz), sz);
  2418.     sscanf(sz, "%d", &iKeepRedNew);
  2419.     WinQueryDlgItemText(hwnd, DID_G, sizeof(sz), sz);
  2420.     sscanf(sz, "%d", &iKeepGreenNew);
  2421.     WinQueryDlgItemText(hwnd, DID_B, sizeof(sz), sz);
  2422.     sscanf(sz, "%d", &iKeepBlueNew);
  2423.     WinQueryDlgItemText(hwnd, DID_N, sizeof(sz), sz);
  2424.     sscanf(sz, "%d", &nColsNew);
  2425.  
  2426.     if ( iKeepRedNew   < 0 || iKeepRedNew   > 8 )
  2427.         Warning(hwnd, "No. bits R must be between 0 and 8");
  2428.     else if ( iKeepGreenNew < 0 || iKeepGreenNew > 8 )
  2429.         Warning(hwnd, "No. bits G must be between 0 and 8");
  2430.     else if ( iKeepBlueNew  < 0 || iKeepBlueNew  > 8 )
  2431.         Warning(hwnd, "No. bits B must be between 0 and 8");
  2432.     else if ( nColsNew      < 1 || nColsNew      > 256 )
  2433.         Warning(hwnd, "No. bits B must be between 1 and 256");
  2434.     else
  2435.         {
  2436.         iPal       = iPalNew;
  2437.         iAlg       = iAlgNew;
  2438.         iKeepRed   = iKeepRedNew;
  2439.         iKeepGreen = iKeepGreenNew;
  2440.         iKeepBlue  = iKeepBlueNew;
  2441.         nCols      = nColsNew;
  2442.         WinDismissDlg(hwnd, TRUE);
  2443.         return ( (MRESULT) 0 );
  2444.         }
  2445.     }
  2446.     return ( (MRESULT) 0 );
  2447. /*...e*/
  2448. /*...sDID_CANCEL:32:*/
  2449. case DID_CANCEL:
  2450.     WinDismissDlg(hwnd, FALSE);
  2451.     return ( (MRESULT) 0 );
  2452. /*...e*/
  2453.         }
  2454.     break;
  2455. /*...e*/
  2456. /*...sWM_CLOSE:16:*/
  2457. case WM_CLOSE:
  2458.     WinDismissDlg(hwnd, FALSE);
  2459.     return ( (MRESULT) 0 );
  2460. /*...e*/
  2461. /*...sWM_HELP:16:*/
  2462. case WM_HELP:
  2463.     /* Parent is HWND_DESKTOP */
  2464.     /* WinDefDlgProc() will pass this up to the parent */
  2465.     /* So redirect to the owner */
  2466.     return ( WinSendMsg(WinQueryWindow(hwnd, QW_OWNER), msg, mp1, mp2) );
  2467. /*...e*/
  2468.         }
  2469.     return ( WinDefDlgProc(hwnd, msg, mp1, mp2) );
  2470.     }
  2471.  
  2472. /*...sToGreyPal:0:*/
  2473. static VOID ToGreyPal(GBMRGB *gbmrgb)
  2474.     {
  2475.     int    i;
  2476.  
  2477.     for ( i = 0; i < 0x100; i++ )
  2478.         gbmrgb [i].r =
  2479.         gbmrgb [i].g =
  2480.         gbmrgb [i].b = (byte) i;
  2481.     }
  2482. /*...e*/
  2483. /*...sToGrey:0:*/
  2484. static VOID ToGrey(GBM *gbm, byte *src_data, byte *dest_data)
  2485.     {
  2486.     int    src_stride  = ((gbm -> w * 3 + 3) & ~3);
  2487.     int    dest_stride = ((gbm -> w     + 3) & ~3);
  2488.     int    y;
  2489.  
  2490.     for ( y = 0; y < gbm -> h; y++ )
  2491.         {
  2492.         byte    *src  = src_data;
  2493.         byte    *dest = dest_data;
  2494.         int    x;
  2495.  
  2496.         for ( x = 0; x < gbm -> w; x++ )
  2497.             {
  2498.             byte    b = *src++;
  2499.             byte    g = *src++;
  2500.             byte    r = *src++;
  2501.  
  2502.             *dest++ = (byte) (((word) r * 77 + (word) g * 151 + (word) b * 28) >> 8);
  2503.             }
  2504.  
  2505.         src_data  += src_stride;
  2506.         dest_data += dest_stride;
  2507.         }
  2508.     gbm -> bpp = 8;
  2509.     }
  2510. /*...e*/
  2511. /*...sTripelPal:0:*/
  2512. static VOID TripelPal(GBMRGB *gbmrgb)
  2513.     {
  2514.     int    i;
  2515.  
  2516.     memset(gbmrgb, 0, 0x100 * sizeof(GBMRGB));
  2517.  
  2518.     for ( i = 0; i < 0x40; i++ )
  2519.         {
  2520.         gbmrgb [i       ].r = (byte) (i << 2);
  2521.         gbmrgb [i + 0x40].g = (byte) (i << 2);
  2522.         gbmrgb [i + 0x80].b = (byte) (i << 2);
  2523.         }
  2524.     }
  2525. /*...e*/
  2526. /*...sTripel:0:*/
  2527. static VOID Tripel(GBM *gbm, byte *src_data, byte *dest_data)
  2528.     {
  2529.     int    src_stride  = ((gbm -> w * 3 + 3) & ~3);
  2530.     int    dest_stride = ((gbm -> w     + 3) & ~3);
  2531.     int    y;
  2532.  
  2533.     for ( y = 0; y < gbm -> h; y++ )
  2534.         {
  2535.         byte    *src  = src_data;
  2536.         byte    *dest = dest_data;
  2537.         int    x;
  2538.  
  2539.         for ( x = 0; x < gbm -> w; x++ )
  2540.             {
  2541.             byte    b = *src++;
  2542.             byte    g = *src++;
  2543.             byte    r = *src++;
  2544.  
  2545.             switch ( (x+y)%3 )
  2546.                 {
  2547.                 case 0:    *dest++ = (byte)         (r >> 2) ;    break;
  2548.                 case 1:    *dest++ = (byte) (0x40 + (g >> 2));    break;
  2549.                 case 2:    *dest++ = (byte) (0x80 + (b >> 2));    break;
  2550.                 }
  2551.             }
  2552.  
  2553.         src_data  += src_stride;
  2554.         dest_data += dest_stride;
  2555.         }
  2556.     gbm -> bpp = 8;
  2557.     }
  2558. /*...e*/
  2559.  
  2560. static VOID Map(HWND hwndClient)
  2561.     {
  2562.     HBITMAP hbmNew;
  2563.     GBM gbmNew;
  2564.     LONG lColorBgNew, lColorFgNew;
  2565.     GBMRGB gbmrgbNew [0x100];
  2566.     BYTE *pbDataNew;
  2567.     BOOL ok = TRUE;
  2568.     int stride;
  2569.     BYTE bViewFast;
  2570.  
  2571.     Caption(hwndClient, " - mapping %s", szFileName);
  2572.  
  2573. /*...sspeedup rendering later:8:*/
  2574. {
  2575. CHAR *szFast =    "You have just selected a mapping to a palette which has all "
  2576.         "of its colours in the screen palette. Therefore halftoning "
  2577.         "or error diffusion will cause no improvement - change View "
  2578.         "setting to Raw PM mapping?";
  2579. bViewFast = bView;
  2580.  
  2581. switch ( iPal )
  2582.     {
  2583.     case CVT_BW:
  2584.         bViewFast = VIEW_NULL;
  2585.         break;
  2586.     case CVT_8:
  2587.     case CVT_VGA:
  2588.         if ( lBitCountScreen == 4 )
  2589.             bViewFast = VIEW_NULL;
  2590.         break;
  2591.     case CVT_784:
  2592.         if ( lBitCountScreen == 8 )
  2593.             bViewFast = VIEW_NULL;
  2594.         break;
  2595.     case CVT_FREQ:
  2596.     case CVT_RGB:
  2597.         if ( lBitCountScreen == 16 &&
  2598.              iKeepRed   <= 5 &&
  2599.              iKeepGreen <= 6 &&
  2600.              iKeepBlue  <= 5 )
  2601.             bViewFast = VIEW_NULL;
  2602.         break;
  2603.     }
  2604.  
  2605. if ( bViewFast != bView )
  2606.     switch ( WinMessageBox(HWND_DESKTOP, hwndClient, szFast, szAppName, 0, MB_YESNOCANCEL | MB_WARNING | MB_MOVEABLE) )
  2607.         {
  2608.         case MBID_YES:
  2609.             bView = bViewFast;
  2610.             break;
  2611.         case MBID_NO:
  2612.             break;
  2613.         case MBID_CANCEL:
  2614.             return;
  2615.         }
  2616. }
  2617. /*...e*/
  2618.  
  2619.     gbmNew = gbm;
  2620.     gbmNew.bpp = 24;
  2621.  
  2622.     stride = ((gbm.w * 3 + 3) & ~3);
  2623.     if ( (pbDataNew = malloc(stride * gbm.h)) == NULL )
  2624.         {
  2625.         Warning(hwndClient, "Out of memory");
  2626.         return;
  2627.         }
  2628.  
  2629.     CopyTo24(&gbm, gbmrgb, pbData, pbDataNew);
  2630.  
  2631.     LowPri();
  2632. /*...sdo mapping:8:*/
  2633. {
  2634. BYTE rm = (BYTE) (0xff00 >> iKeepRed  );
  2635. BYTE gm = (BYTE) (0xff00 >> iKeepGreen);
  2636. BYTE bm = (BYTE) (0xff00 >> iKeepBlue );
  2637.  
  2638. #define    SW2(a,b)    (((a)<<8)|(b))
  2639.  
  2640. switch ( SW2(iPal,iAlg) )
  2641.     {
  2642.     case SW2(CVT_BW,CVT_NEAREST):
  2643.         gbm_trunc_pal_BW(gbmrgbNew);
  2644.         gbm_trunc_BW(&gbmNew, pbDataNew, pbDataNew);
  2645.         break;
  2646.     case SW2(CVT_4G,CVT_NEAREST):
  2647.         gbm_trunc_pal_4G(gbmrgbNew);
  2648.         gbm_trunc_4G(&gbmNew, pbDataNew, pbDataNew);
  2649.         break;
  2650.     case SW2(CVT_8,CVT_NEAREST):
  2651.         gbm_trunc_pal_8(gbmrgbNew);
  2652.         gbm_trunc_8(&gbmNew, pbDataNew, pbDataNew);
  2653.         break;
  2654.     case SW2(CVT_VGA,CVT_NEAREST):
  2655.         gbm_trunc_pal_VGA(gbmrgbNew);
  2656.         gbm_trunc_VGA(&gbmNew, pbDataNew, pbDataNew);
  2657.         break;
  2658.     case SW2(CVT_784,CVT_NEAREST):
  2659.         gbm_trunc_pal_7R8G4B(gbmrgbNew);
  2660.         gbm_trunc_7R8G4B(&gbmNew, pbDataNew, pbDataNew);
  2661.         break;
  2662.     case SW2(CVT_666,CVT_NEAREST):
  2663.         gbm_trunc_pal_6R6G6B(gbmrgbNew);
  2664.         gbm_trunc_6R6G6B(&gbmNew, pbDataNew, pbDataNew);
  2665.         break;
  2666.     case SW2(CVT_8G,CVT_NEAREST):
  2667.         ToGreyPal(gbmrgbNew);
  2668.         ToGrey(&gbmNew, pbDataNew, pbDataNew);
  2669.         break;
  2670.     case SW2(CVT_TRIPEL,CVT_NEAREST):
  2671.         TripelPal(gbmrgbNew);
  2672.         Tripel(&gbmNew, pbDataNew, pbDataNew);
  2673.         break;
  2674.     case SW2(CVT_FREQ,CVT_NEAREST):
  2675.         memset(gbmrgbNew, 0, sizeof(gbmrgbNew));
  2676.         gbm_hist(&gbmNew, pbDataNew, gbmrgbNew, pbDataNew, nCols, rm, gm, bm);
  2677.         break;
  2678.     case SW2(CVT_RGB,CVT_NEAREST):
  2679.         gbm_trunc_24(&gbmNew, pbDataNew, pbDataNew, rm, gm, bm);
  2680.         break;
  2681.     case SW2(CVT_BW,CVT_ERRDIFF):
  2682.         gbm_errdiff_pal_BW(gbmrgbNew);
  2683.         ok = gbm_errdiff_BW(&gbmNew, pbDataNew, pbDataNew);
  2684.         break;
  2685.     case SW2(CVT_4G,CVT_ERRDIFF):
  2686.         gbm_errdiff_pal_4G(gbmrgbNew);
  2687.         ok = gbm_errdiff_4G(&gbmNew, pbDataNew, pbDataNew);
  2688.         break;
  2689.     case SW2(CVT_8,CVT_ERRDIFF):
  2690.         gbm_errdiff_pal_8(gbmrgbNew);
  2691.         ok = gbm_errdiff_8(&gbmNew, pbDataNew, pbDataNew);
  2692.         break;
  2693.     case SW2(CVT_VGA,CVT_ERRDIFF):
  2694.         gbm_errdiff_pal_VGA(gbmrgbNew);
  2695.         ok = gbm_errdiff_VGA(&gbmNew, pbDataNew, pbDataNew);
  2696.         break;
  2697.     case SW2(CVT_784,CVT_ERRDIFF):
  2698.         gbm_errdiff_pal_7R8G4B(gbmrgbNew);
  2699.         ok = gbm_errdiff_7R8G4B(&gbmNew, pbDataNew, pbDataNew);
  2700.         break;
  2701.     case SW2(CVT_666,CVT_ERRDIFF):
  2702.         gbm_errdiff_pal_6R6G6B(gbmrgbNew);
  2703.         ok = gbm_errdiff_6R6G6B(&gbmNew, pbDataNew, pbDataNew);
  2704.         break;
  2705.     case SW2(CVT_RGB,CVT_ERRDIFF):
  2706.         ok = gbm_errdiff_24(&gbmNew, pbDataNew, pbDataNew, rm, gm, bm);
  2707.         break;
  2708.     case SW2(CVT_784,CVT_HALFTONE):
  2709.         gbm_ht_pal_7R8G4B(gbmrgbNew);
  2710.         gbm_ht_7R8G4B_2x2(&gbmNew, pbDataNew, pbDataNew);
  2711.         break;
  2712.     case SW2(CVT_666,CVT_HALFTONE):
  2713.         gbm_ht_pal_6R6G6B(gbmrgbNew);
  2714.         gbm_ht_6R6G6B_2x2(&gbmNew, pbDataNew, pbDataNew);
  2715.         break;
  2716.     case SW2(CVT_8,CVT_HALFTONE):
  2717.         gbm_ht_pal_8(gbmrgbNew);
  2718.         gbm_ht_8_3x3(&gbmNew, pbDataNew, pbDataNew);
  2719.         break;
  2720.     case SW2(CVT_VGA,CVT_HALFTONE):
  2721.         gbm_ht_pal_VGA(gbmrgbNew);
  2722.         gbm_ht_VGA_3x3(&gbmNew, pbDataNew, pbDataNew);
  2723.         break;
  2724.     case SW2(CVT_RGB,CVT_HALFTONE):
  2725.         gbm_ht_24_2x2(&gbmNew, pbDataNew, pbDataNew, rm, gm, bm);
  2726.         break;
  2727.     }
  2728.  
  2729. switch ( iPal )
  2730.     {
  2731.     case CVT_BW:
  2732.         gbmNew.bpp = 1;
  2733.         break;
  2734.     case CVT_4G:
  2735.     case CVT_8:
  2736.     case CVT_VGA:
  2737.         gbmNew.bpp = 4;
  2738.         break;
  2739.     case CVT_784:
  2740.     case CVT_666:
  2741.     case CVT_8G:
  2742.     case CVT_TRIPEL:
  2743.     case CVT_FREQ:
  2744.         gbmNew.bpp = 8;
  2745.         break;
  2746.     case CVT_RGB:
  2747.         gbmNew.bpp = 24;
  2748.         break;
  2749.     }
  2750. }
  2751. /*...e*/
  2752.  
  2753.     if ( !ok )
  2754.         {
  2755.         free(pbDataNew);
  2756.         RegPri();
  2757.         Warning(hwndClient, "Unable to perform mapping");
  2758.         return;
  2759.         }    
  2760.  
  2761.     Caption(hwndClient, " - rendering %s", szFileName);
  2762.     if ( !MakeVisual(hwndClient, &gbmNew, gbmrgbNew, pbDataNew, bViewFast, &hbmNew, &lColorBgNew, &lColorFgNew) )
  2763.         {
  2764.         free(pbDataNew);
  2765.         RegPri();
  2766.         return;
  2767.         }
  2768.  
  2769.     KeepForUndo(&gbm, gbmrgb, pbData, "mapping");
  2770.  
  2771.     gbm = gbmNew;
  2772.     if ( gbm.bpp != 24 )
  2773.         memcpy(gbmrgb, gbmrgbNew, (sizeof(GBMRGB) << gbm.bpp) );
  2774.     free(pbData);
  2775.     pbData = pbDataNew;
  2776.  
  2777.     stride = (((gbm.w * gbm.bpp + 31) / 32) * 4);
  2778.     if ( (pbDataNew = realloc(pbData, stride * gbm.h)) != NULL )
  2779.         pbData = pbDataNew;
  2780.  
  2781.     lColorBg = lColorBgNew;
  2782.     lColorFg = lColorFgNew;
  2783.     SetBitmap(hbmNew);
  2784.     WinInvalidateRect(hwndBitmap, NULL, TRUE);
  2785.     WinUpdateWindow(hwndBitmap);
  2786.     fUnsavedChanges = TRUE;
  2787.     RegPri();
  2788.     }
  2789. /*...e*/
  2790.  
  2791. MRESULT _System ObjectWndProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  2792.     {
  2793.     switch ( (int) msg )
  2794.         {
  2795. /*...sUM_NEW           \45\ clear out bitmap:16:*/
  2796. case UM_NEW:
  2797.     {
  2798.     HWND hwndClient = HWNDFROMMP(mp1);
  2799.  
  2800.     DiscardUndo();
  2801.  
  2802.     if ( fGotBitmap )
  2803.         if ( SaveChanges(hwndClient) )
  2804.             {
  2805.             SetBitmap((HBITMAP) NULL);
  2806.             WinInvalidateRect(hwndScroller, NULL, TRUE);
  2807.             WinUpdateWindow(hwndScroller);
  2808.             DeleteBitmap();
  2809.             strcpy(szFileName, "");
  2810.             fSelectionDefined = FALSE;
  2811.             fUnsavedChanges = FALSE;
  2812.             Caption(hwndClient, "", "");
  2813.             }
  2814.  
  2815.     WinSendMsg(hwnd, UM_DONE, NULL, NULL);
  2816.     return ( (MRESULT) 0 );
  2817.     }
  2818. /*...e*/
  2819. /*...sUM_OPEN          \45\ read in a new bitmap:16:*/
  2820. case UM_OPEN:
  2821.     {
  2822.     HWND hwndClient = HWNDFROMMP(mp1);
  2823.  
  2824.     if ( SaveChanges(hwndClient) )
  2825.         {
  2826.         GBMFILEDLG gbmfild;
  2827.  
  2828.         memset(&gbmfild.fild, 0, sizeof(FILEDLG));
  2829.         gbmfild.fild.cbSize = sizeof(FILEDLG);
  2830.         gbmfild.fild.fl = (FDS_CENTER|FDS_OPEN_DIALOG|FDS_HELPBUTTON);
  2831.         strcpy(gbmfild.fild.szFullFile, szFileName);
  2832.         strcpy(gbmfild.szOptions, "");    
  2833.         GbmFileDlg(HWND_DESKTOP, hwndClient, &gbmfild);
  2834.         if ( gbmfild.fild.lReturn == DID_OK )
  2835.             {
  2836.             HBITMAP hbmNew;
  2837.             LONG lColorBgNew, lColorFgNew;
  2838.  
  2839.             SetBitmap((HBITMAP) NULL);
  2840.             WinInvalidateRect(hwndScroller, NULL, TRUE);
  2841.             WinUpdateWindow(hwndScroller);
  2842.             DeleteBitmap();
  2843.             DiscardUndo();
  2844.             Caption(hwndClient, " - reading %s", gbmfild.fild.szFullFile);
  2845.             LowPri();
  2846.             if ( LoadBitmap(hwndClient, gbmfild.fild.szFullFile, gbmfild.szOptions, &gbm, gbmrgb, &pbData) )
  2847.                 {
  2848.                 Caption(hwndClient, " - rendering %s", gbmfild.fild.szFullFile);
  2849.                 LowPri();
  2850.                 if ( MakeVisual(hwndClient, &gbm, gbmrgb, pbData, bView, &hbmNew, &lColorBgNew, &lColorFgNew) )
  2851.                     {
  2852.                     strcpy(szFileName, gbmfild.fild.szFullFile);
  2853.                     fGotBitmap = TRUE;
  2854.                     fSelectionDefined = FALSE;
  2855.                     fUnsavedChanges = FALSE;
  2856.                     lColorBg = lColorBgNew;
  2857.                     lColorFg = lColorFgNew;
  2858.                     SetBitmap(hbmNew);
  2859.                     WinInvalidateRect(hwndBitmap, NULL, TRUE);
  2860.                     WinUpdateWindow(hwndBitmap);
  2861.                     Caption(hwndClient, " - %s", szFileName);
  2862.                     }
  2863.                 else
  2864.                     {
  2865.                     free(pbData);
  2866.                     Caption(hwndClient, "", "");
  2867.                     }
  2868.                 }
  2869.             else
  2870.                 Caption(hwndClient, "", "");
  2871.             RegPri();
  2872.             }
  2873.         }
  2874.  
  2875.     WinSendMsg(hwnd, UM_DONE, NULL, NULL);
  2876.     return ( (MRESULT) 0 );
  2877.     }
  2878. /*...e*/
  2879. /*...sUM_SAVE          \45\ save with old name:16:*/
  2880. case UM_SAVE:
  2881.     {
  2882.     HWND hwndClient = HWNDFROMMP(mp1);
  2883.  
  2884.     Caption(hwndClient, " - saving %s", szFileName);
  2885.     LowPri();
  2886.     if ( SaveBitmap(hwndClient, szFileName, "", &gbm, gbmrgb, pbData) )
  2887.         fUnsavedChanges = FALSE;
  2888.     RegPri();
  2889.     Caption(hwndClient, "- %s", szFileName);
  2890.  
  2891.     WinSendMsg(hwnd, UM_DONE, NULL, NULL);
  2892.     return ( (MRESULT) 0 );
  2893.     }
  2894. /*...e*/
  2895. /*...sUM_SAVE_AS       \45\ save with new name:16:*/
  2896. case UM_SAVE_AS:
  2897.     {
  2898.     HWND hwndClient = HWNDFROMMP(mp1);
  2899.     GBMFILEDLG gbmfild;
  2900.  
  2901.     memset(&gbmfild.fild, 0, sizeof(FILEDLG));
  2902.     gbmfild.fild.cbSize = sizeof(FILEDLG);
  2903.     gbmfild.fild.fl = (FDS_CENTER|FDS_SAVEAS_DIALOG|FDS_HELPBUTTON);
  2904.     strcpy(gbmfild.fild.szFullFile, szFileName);
  2905.     strcpy(gbmfild.szOptions, "");    
  2906.     GbmFileDlg(HWND_DESKTOP, hwndClient, &gbmfild);
  2907.     if ( gbmfild.fild.lReturn == DID_OK )
  2908.         {
  2909.         Caption(hwndClient, " - saving as %s", gbmfild.fild.szFullFile);
  2910.         LowPri();
  2911.         if ( SaveBitmap(hwndClient, gbmfild.fild.szFullFile, "", &gbm, gbmrgb, pbData) )
  2912.             {
  2913.             strcpy(szFileName, gbmfild.fild.szFullFile);
  2914.             fUnsavedChanges = FALSE;
  2915.             }
  2916.         RegPri();
  2917.         Caption(hwndClient, " - %s", szFileName);
  2918.         }
  2919.  
  2920.     WinSendMsg(hwnd, UM_DONE, NULL, NULL);
  2921.     return ( (MRESULT) 0 );
  2922.     }
  2923. /*...e*/
  2924. /*...sUM_PRINT         \45\ print image:16:*/
  2925. case UM_PRINT:
  2926.     {
  2927.     HWND hwndClient = HWNDFROMMP(mp1);
  2928.     HAB hab = WinQueryAnchorBlock(hwndClient);
  2929.     HBITMAP hbmCopy;
  2930.     BMP_ERR rc;
  2931.     CHAR sz [255+1];
  2932.  
  2933.     Caption(hwndClient, " - printing %s", szFileName);
  2934.     LowPri();
  2935.     if ( (rc = BmpCopy(hab, hbm, &hbmCopy)) != BMP_ERR_OK )
  2936.         {
  2937.         RegPri();
  2938.         Caption(hwndClient, " - %s", szFileName);
  2939.         Warning(hwndClient, "Can't make a copy of bitmap to send to printer: %s", BmpErrorMessage(rc, sz));
  2940.         }
  2941.     else if ( (rc = BmpPrint(hab, hbmCopy, szFileName, szAppName, NULL)) != BMP_ERR_OK )
  2942.         {
  2943.         RegPri();
  2944.         Caption(hwndClient, " - %s", szFileName);
  2945.         GpiDeleteBitmap(hbmCopy);
  2946.         Warning(hwndClient, "Unable to print bitmap: %s", BmpErrorMessage(rc, sz));
  2947.         }
  2948.     else
  2949.         {
  2950.         RegPri();
  2951.         Caption(hwndClient, " - %s", szFileName);
  2952.         GpiDeleteBitmap(hbmCopy);
  2953.         }
  2954.  
  2955.     WinSendMsg(hwnd, UM_DONE, NULL, NULL);
  2956.     return ( (MRESULT) 0 );
  2957.     }
  2958.  
  2959. /*...e*/
  2960. /*...sUM_UNDO          \45\ undo previous operation:16:*/
  2961. case UM_UNDO:
  2962.     {
  2963.     HWND hwndClient = HWNDFROMMP(mp1);
  2964.     GBM gbmNew;
  2965.     GBMRGB gbmrgbNew [0x100];
  2966.     BYTE *pbDataNew;
  2967.     CHAR *szWhat;
  2968.     HBITMAP hbmNew;
  2969.     LONG lColorBgNew, lColorFgNew;
  2970.  
  2971.     UseUndoBuffer(&gbmNew, gbmrgbNew, &pbDataNew, &szWhat);
  2972.     if ( pbDataNew == NULL )
  2973.         pbDataNew = pbData;
  2974.  
  2975.     Caption(hwndClient, " - rendering %s", szFileName);
  2976.     if ( !MakeVisual(hwndClient, &gbmNew, gbmrgbNew, pbDataNew, bView, &hbmNew, &lColorBgNew, &lColorFgNew) )
  2977.         {
  2978.         if ( pbDataNew != pbData )
  2979.             free(pbDataNew);
  2980.         RegPri();
  2981.         Caption(hwndClient, " - %s", szFileName);
  2982.         WinSendMsg(hwnd, UM_DONE, NULL, NULL);
  2983.         return ( (MRESULT) 0 );
  2984.         }
  2985.  
  2986.     gbm = gbmNew;
  2987.     memcpy(gbmrgb, gbmrgbNew, 0x100 * sizeof(GBMRGB));
  2988.     if ( pbDataNew != pbData )
  2989.         {
  2990.         free(pbData);
  2991.         pbData = pbDataNew;
  2992.         }
  2993.     fSelectionDefined = FALSE;
  2994.     lColorBg = lColorBgNew;
  2995.     lColorFg = lColorFgNew;
  2996.     SetBitmap(hbmNew);
  2997.     WinInvalidateRect(hwndBitmap, NULL, TRUE);
  2998.     WinUpdateWindow(hwndBitmap);
  2999.     fUnsavedChanges = TRUE;
  3000.     RegPri();
  3001.     Caption(hwndClient, " - %s", szFileName);
  3002.  
  3003.     WinSendMsg(hwnd, UM_DONE, NULL, NULL);
  3004.     return ( (MRESULT) 0 );
  3005.     }
  3006. /*...e*/
  3007. /*...sUM_SELECT        \45\ select region of bitmap:16:*/
  3008. case UM_SELECT:
  3009.     {
  3010.     BITMAPINFOHEADER2 bmp;
  3011.     SWP swpBitmap, swpScroller;
  3012.     int cxScrollbar, cyScrollbar, x, y, cx, cy;
  3013.  
  3014.     bmp.cbFix = sizeof(BITMAPINFOHEADER2);
  3015.     GpiQueryBitmapInfoHeader(hbm, &bmp);
  3016.     fSelectionDefined = FALSE;
  3017.     WinInvalidateRect(hwndBitmap, NULL, TRUE);
  3018.     WinUpdateWindow(hwndBitmap);
  3019.     WinQueryWindowPos(hwndBitmap  , &swpBitmap  );
  3020.     WinQueryWindowPos(hwndScroller, &swpScroller);
  3021.     cxScrollbar = (int) WinQuerySysValue(HWND_DESKTOP, SV_CXVSCROLL);
  3022.     cyScrollbar = (int) WinQuerySysValue(HWND_DESKTOP, SV_CYHSCROLL);
  3023.     x = - (int) swpBitmap.x              ; if ( x < 0 ) x = 0;
  3024.     y = - (int) swpBitmap.y + cyScrollbar; if ( y < 0 ) y = 0;
  3025.     cx = (int) swpScroller.cx - cxScrollbar; if ( cx > (int) bmp.cx ) cx = (int) bmp.cx;
  3026.     cy = (int) swpScroller.cy - cyScrollbar; if ( cy > (int) bmp.cy ) cy = (int) bmp.cy;
  3027.     fSelectionDefined = Select(hwndBitmap, &rclSelection, x, y, cx, cy);
  3028.     if ( fSelectionDefined )
  3029.         {
  3030.         if ( rclSelection.xLeft   != rclSelection.xRight &&
  3031.              rclSelection.yBottom != rclSelection.yTop   )
  3032.             {
  3033.             WinInvalidateRect(hwndBitmap, NULL, TRUE);
  3034.             WinUpdateWindow(hwndBitmap);
  3035.             }
  3036.         }
  3037.  
  3038.     WinSendMsg(hwnd, UM_DONE, NULL, NULL);
  3039.     return ( (MRESULT) 0 );
  3040.     }
  3041. /*...e*/
  3042. /*...sUM_SELECT_ALL    \45\ select region of bitmap:16:*/
  3043. case UM_SELECT_ALL:
  3044.     {
  3045.     BITMAPINFOHEADER2 bmp;
  3046.  
  3047.     fSelectionDefined = FALSE;
  3048.     WinInvalidateRect(hwndBitmap, NULL, TRUE);
  3049.  
  3050.     bmp.cbFix = sizeof(BITMAPINFOHEADER2);
  3051.     GpiQueryBitmapInfoHeader(hbm, &bmp);
  3052.     fSelectionDefined    = TRUE;
  3053.     rclSelection.xLeft   = 0;
  3054.     rclSelection.xRight  = bmp.cx;
  3055.     rclSelection.yTop    = bmp.cy;
  3056.     rclSelection.yBottom = 0;
  3057.     WinInvalidateRect(hwndBitmap, NULL, TRUE);
  3058.     WinUpdateWindow(hwndBitmap);
  3059.  
  3060.     WinSendMsg(hwnd, UM_DONE, NULL, NULL);
  3061.     return ( (MRESULT) 0 );
  3062.     }
  3063. /*...e*/
  3064. /*...sUM_DESELECT      \45\ de\45\select any selcted area:16:*/
  3065. case UM_DESELECT:
  3066.     if ( fSelectionDefined )
  3067.         {
  3068.         fSelectionDefined = FALSE;
  3069.         WinInvalidateRect(hwndBitmap, NULL, TRUE);
  3070.         WinUpdateWindow(hwndBitmap);
  3071.         }
  3072.  
  3073.     WinSendMsg(hwnd, UM_DONE, NULL, NULL);
  3074.     return ( (MRESULT) 0 );
  3075. /*...e*/
  3076. /*...sUM_COPY          \45\ copy bitmap to clipboard:16:*/
  3077. case UM_COPY:
  3078.     {
  3079.     HWND hwndClient = HWNDFROMMP(mp1);
  3080.     HAB hab = WinQueryAnchorBlock(hwndClient);
  3081.     HBITMAP hbmClipbrd;
  3082.     BITMAPINFOHEADER2 bmpClipbrd;
  3083.     RECTL rclClipbrd;
  3084.     HPS hps;
  3085.  
  3086.     hps = WinGetPS(hwndClient);
  3087.     bmpClipbrd.cbFix = sizeof(BITMAPINFOHEADER2);
  3088.     GpiQueryBitmapInfoHeader(hbm, &bmpClipbrd);
  3089.     bmpClipbrd.cx = (USHORT) (rclSelection.xRight - rclSelection.xLeft);
  3090.     bmpClipbrd.cy = (USHORT) (rclSelection.yTop - rclSelection.yBottom);
  3091.     if ( (hbmClipbrd = GpiCreateBitmap(hps, &bmpClipbrd, 0L, NULL, NULL)) == (HBITMAP) NULL )
  3092.         Warning(hwndClient, "Can't create bitmap to place on the clipboard");
  3093.     else
  3094.         {
  3095.         rclClipbrd.xLeft   = 0; rclClipbrd.xRight = bmpClipbrd.cx;
  3096.         rclClipbrd.yBottom = 0; rclClipbrd.yTop   = bmpClipbrd.cy;
  3097.         BmpBlitter(hab, hbm, rclSelection, hbmClipbrd, rclClipbrd);
  3098.         WinOpenClipbrd(hab);
  3099.         WinEmptyClipbrd(hab);
  3100.         WinSetClipbrdData(hab, (ULONG) hbmClipbrd, CF_BITMAP, CFI_HANDLE);
  3101.         WinCloseClipbrd(hab);
  3102.         }
  3103.     WinReleasePS(hps);
  3104.  
  3105.     WinSendMsg(hwnd, UM_DONE, NULL, NULL);
  3106.     return ( (MRESULT) 0 );
  3107.     }
  3108. /*...e*/
  3109. /*...sUM_REF_HORZ      \45\ reflect horizontally:16:*/
  3110. case UM_REF_HORZ:
  3111.     {
  3112.     HWND hwndClient = HWNDFROMMP(mp1);
  3113.  
  3114.     Caption(hwndClient, " - reflecting horizontally %s", szFileName);
  3115.     Reflect(hwndClient, TRUE, FALSE, FALSE, "horizontal reflection");
  3116.     Caption(hwndClient, " - %s", szFileName);
  3117.     WinSendMsg(hwnd, UM_DONE, NULL, NULL);
  3118.     return ( (MRESULT) 0 );
  3119.     }
  3120. /*...e*/
  3121. /*...sUM_REF_VERT      \45\ reflect vertically:16:*/
  3122. case UM_REF_VERT:
  3123.     {
  3124.     HWND hwndClient = HWNDFROMMP(mp1);
  3125.  
  3126.     Caption(hwndClient, " - reflecting vertically %s", szFileName);
  3127.     Reflect(hwndClient, FALSE, TRUE, FALSE, "vertical reflection");
  3128.     Caption(hwndClient, " - %s", szFileName);
  3129.     WinSendMsg(hwnd, UM_DONE, NULL, NULL);
  3130.     return ( (MRESULT) 0 );
  3131.     }
  3132. /*...e*/
  3133. /*...sUM_ROT_90        \45\ rotate 90 degrees:16:*/
  3134. case UM_ROT_90:
  3135.     {
  3136.     HWND hwndClient = HWNDFROMMP(mp1);
  3137.  
  3138.     Caption(hwndClient, " - rotating 90 %s", szFileName);
  3139.     Reflect(hwndClient, FALSE, TRUE, TRUE, "90 degree rotation");
  3140.     Caption(hwndClient, " - %s", szFileName);
  3141.     WinSendMsg(hwnd, UM_DONE, NULL, NULL);
  3142.     return ( (MRESULT) 0 );
  3143.     }
  3144. /*...e*/
  3145. /*...sUM_ROT_180       \45\ rotate 180 degrees:16:*/
  3146. case UM_ROT_180:
  3147.     {
  3148.     HWND hwndClient = HWNDFROMMP(mp1);
  3149.  
  3150.     Caption(hwndClient, " - rotating 180 %s", szFileName);
  3151.     Reflect(hwndClient, TRUE, TRUE, FALSE, "180 degree rotation");
  3152.     Caption(hwndClient, " - %s", szFileName);
  3153.     WinSendMsg(hwnd, UM_DONE, NULL, NULL);
  3154.     return ( (MRESULT) 0 );
  3155.     }
  3156. /*...e*/
  3157. /*...sUM_ROT_270       \45\ rotate 270 degrees:16:*/
  3158. case UM_ROT_270:
  3159.     {
  3160.     HWND hwndClient = HWNDFROMMP(mp1);
  3161.  
  3162.     Caption(hwndClient, " - rotating 270 %s", szFileName);
  3163.     Reflect(hwndClient, TRUE, FALSE, TRUE, "270 degree rotation");
  3164.     Caption(hwndClient, " - %s", szFileName);
  3165.     WinSendMsg(hwnd, UM_DONE, NULL, NULL);
  3166.     return ( (MRESULT) 0 );
  3167.     }
  3168. /*...e*/
  3169. /*...sUM_TRANSPOSE     \45\ transpose x for y:16:*/
  3170. case UM_TRANSPOSE:
  3171.     {
  3172.     HWND hwndClient = HWNDFROMMP(mp1);
  3173.  
  3174.     Caption(hwndClient, " - transposing %s", szFileName);
  3175.     Reflect(hwndClient, FALSE, FALSE, TRUE, "transpose");
  3176.     Caption(hwndClient, " - %s", szFileName);
  3177.     WinSendMsg(hwnd, UM_DONE, NULL, NULL);
  3178.     return ( (MRESULT) 0 );
  3179.     }
  3180. /*...e*/
  3181. /*...sUM_CROP          \45\ crop to selection:16:*/
  3182. case UM_CROP:
  3183.     {
  3184.     HWND hwndClient = HWNDFROMMP(mp1);
  3185.     GBM gbmNew;
  3186.     LONG lColorBgNew, lColorFgNew;
  3187.     BYTE *pbDataNew;
  3188.     HBITMAP hbmNew;
  3189.     int stride;
  3190.  
  3191.     Caption(hwndClient, " - cropping %s", szFileName);
  3192.     LowPri();
  3193.  
  3194.     gbmNew.w   = rclSelection.xRight - rclSelection.xLeft;
  3195.     gbmNew.h   = rclSelection.yTop - rclSelection.yBottom;
  3196.     gbmNew.bpp = gbm.bpp;
  3197.  
  3198.     stride = (((gbm.w * gbm.bpp + 31) / 32) * 4);
  3199.  
  3200.     if ( (pbDataNew = malloc(stride * gbmNew.h)) == NULL )
  3201.         {
  3202.         RegPri();
  3203.         Warning(hwndClient, "Out of memory");
  3204.         Caption(hwndClient, " - %s", szFileName);
  3205.         WinSendMsg(hwnd, UM_DONE, NULL, NULL);
  3206.         return ( (MRESULT) 0 );
  3207.         }
  3208.  
  3209.     gbm_subrectangle(&gbm, rclSelection.xLeft, rclSelection.yBottom,
  3210.         gbmNew.w, gbmNew.h, pbData, pbDataNew);
  3211.  
  3212.     if ( !MakeVisual(hwndClient, &gbmNew, gbmrgb, pbDataNew, bView, &hbmNew, &lColorBgNew, &lColorFgNew) )
  3213.         {
  3214.         free(pbDataNew);
  3215.         RegPri();
  3216.         Caption(hwndClient, " - %s", szFileName);
  3217.         WinSendMsg(hwnd, UM_DONE, NULL, NULL);
  3218.         return ( (MRESULT) 0 );
  3219.         }
  3220.  
  3221.     KeepForUndo(&gbm, gbmrgb, pbData, "cropping");
  3222.  
  3223.     gbm = gbmNew;
  3224.     free(pbData);
  3225.     pbData = pbDataNew;
  3226.     fSelectionDefined = FALSE;
  3227.     lColorBg = lColorBgNew;
  3228.     lColorFg = lColorFgNew;
  3229.     SetBitmap(hbmNew);
  3230.     WinInvalidateRect(hwndBitmap, NULL, TRUE);
  3231.     WinUpdateWindow(hwndBitmap);
  3232.     fUnsavedChanges = TRUE;
  3233.     RegPri();
  3234.     Caption(hwndClient, " - %s", szFileName);
  3235.  
  3236.     WinSendMsg(hwnd, UM_DONE, NULL, NULL);
  3237.     return ( (MRESULT) 0 );
  3238.     }
  3239. /*...e*/
  3240. /*...sUM_COLOUR        \45\ colour space:16:*/
  3241. case UM_COLOUR:
  3242.     {
  3243.     HWND hwndClient = HWNDFROMMP(mp1);
  3244.     if ( WinDlgBox(HWND_DESKTOP, hwndClient, ColourDlgProc, (HMODULE) NULL, RID_DLG_COLOUR, NULL) )
  3245.         {
  3246.         ColourAdjust(hwndClient);
  3247.         Caption(hwndClient, " - %s", szFileName);
  3248.         }
  3249.     WinSendMsg(hwnd, UM_DONE, NULL, NULL);
  3250.     return ( (MRESULT) 0 );
  3251.     }
  3252. /*...e*/
  3253. /*...sUM_MAP           \45\ map:16:*/
  3254. case UM_MAP:
  3255.     {
  3256.     HWND hwndClient = HWNDFROMMP(mp1);
  3257.     if ( WinDlgBox(HWND_DESKTOP, hwndClient, MapDlgProc, (HMODULE) NULL, RID_DLG_MAP, NULL) )
  3258.         {
  3259.         Map(hwndClient);
  3260.         Caption(hwndClient, " - %s", szFileName);
  3261.         }
  3262.     WinSendMsg(hwnd, UM_DONE, NULL, NULL);
  3263.     return ( (MRESULT) 0 );
  3264.     }
  3265. /*...e*/
  3266. /*...sUM_VIEW_NULL     \45\ view with no transform:16:*/
  3267. case UM_VIEW_NULL:
  3268.     {
  3269.     HWND hwndClient = HWNDFROMMP(mp1);
  3270.     HBITMAP hbmNew;
  3271.     LONG lColorBgNew, lColorFgNew;
  3272.  
  3273.     Caption(hwndClient, " - rendering %s", szFileName);
  3274.     LowPri();
  3275.     if ( MakeVisual(hwndClient, &gbm, gbmrgb, pbData, VIEW_NULL, &hbmNew, &lColorBgNew, &lColorFgNew) )
  3276.         {
  3277.         lColorBg = lColorBgNew;
  3278.         lColorFg = lColorFgNew;
  3279.         SetBitmap(hbmNew);
  3280.         WinInvalidateRect(hwndBitmap, NULL, TRUE);
  3281.         WinUpdateWindow(hwndBitmap);
  3282.         bView = VIEW_NULL;
  3283.         }
  3284.     RegPri();
  3285.     Caption(hwndClient, " - %s", szFileName);
  3286.  
  3287.     WinSendMsg(hwnd, UM_DONE, NULL, NULL);
  3288.     return ( (MRESULT) 0 );
  3289.     }
  3290. /*...e*/
  3291. /*...sUM_VIEW_HALFTONE \45\ view with error diffusion:16:*/
  3292. case UM_VIEW_HALFTONE:
  3293.     {
  3294.     HWND hwndClient = HWNDFROMMP(mp1);
  3295.     HBITMAP hbmNew;
  3296.     LONG lColorBgNew, lColorFgNew;
  3297.  
  3298.     Caption(hwndClient, " - rendering %s", szFileName);
  3299.     LowPri();
  3300.     if ( MakeVisual(hwndClient, &gbm, gbmrgb, pbData, VIEW_HALFTONE, &hbmNew, &lColorBgNew, &lColorFgNew) )
  3301.         {
  3302.         lColorBg = lColorBgNew;
  3303.         lColorFg = lColorFgNew;
  3304.         SetBitmap(hbmNew);
  3305.         WinInvalidateRect(hwndBitmap, NULL, TRUE);
  3306.         WinUpdateWindow(hwndBitmap);
  3307.         bView = VIEW_HALFTONE;
  3308.         }
  3309.     RegPri();
  3310.     Caption(hwndClient, " - %s", szFileName);
  3311.  
  3312.     WinSendMsg(hwnd, UM_DONE, NULL, NULL);
  3313.     return ( (MRESULT) 0 );
  3314.     }
  3315. /*...e*/
  3316. /*...sUM_VIEW_ERRDIFF  \45\ view with halftoning:16:*/
  3317. case UM_VIEW_ERRDIFF:
  3318.     {
  3319.     HWND hwndClient = HWNDFROMMP(mp1);
  3320.     HBITMAP hbmNew;
  3321.     LONG lColorBgNew, lColorFgNew;
  3322.  
  3323.     Caption(hwndClient, " - rendering %s", szFileName);
  3324.     LowPri();
  3325.     if ( MakeVisual(hwndClient, &gbm, gbmrgb, pbData, VIEW_ERRDIFF, &hbmNew, &lColorBgNew, &lColorFgNew) )
  3326.         {
  3327.         lColorBg = lColorBgNew;
  3328.         lColorFg = lColorFgNew;
  3329.         SetBitmap(hbmNew);
  3330.         WinInvalidateRect(hwndBitmap, NULL, TRUE);
  3331.         WinUpdateWindow(hwndBitmap);
  3332.         bView = VIEW_ERRDIFF;
  3333.         }
  3334.     RegPri();
  3335.     Caption(hwndClient, " - %s", szFileName);
  3336.  
  3337.     WinSendMsg(hwnd, UM_DONE, NULL, NULL);
  3338.     return ( (MRESULT) 0 );
  3339.     }
  3340. /*...e*/
  3341. /*...sUM_DONE          \45\ done\44\ and set pointer back:16:*/
  3342. case UM_DONE:
  3343.     {
  3344.     POINTL ptl;
  3345.     fBusy = FALSE;
  3346.     WinQueryPointerPos(HWND_DESKTOP, &ptl);
  3347.     WinSetPointerPos(HWND_DESKTOP, ptl.x, ptl.y);
  3348.     return ( (MRESULT) 0 );
  3349.     }
  3350. /*...e*/
  3351.         }
  3352.     return ( WinDefWindowProc(hwnd, msg, mp1, mp2) );
  3353.     }
  3354. /*...e*/
  3355. /*...sObjectThread:0:*/
  3356. #define    CB_STACK_OBJECT    0x8000
  3357.  
  3358. static VOID _Optlink ObjectThread(VOID *pvParams)
  3359.     {
  3360.     HAB hab = WinInitialize(0);
  3361.     HMQ hmq = WinCreateMsgQueue(hab, 0);
  3362.     QMSG qmsg;
  3363.  
  3364.     pvParams=pvParams; /* Suppress 'unref' compiler warning */
  3365.  
  3366.     WinRegisterClass(hab, WC_GBMV2_OBJECT, ObjectWndProc, 0L, 0);
  3367.  
  3368.     hwndObject = WinCreateWindow(HWND_OBJECT, WC_GBMV2_OBJECT, NULL, 0L, 0,0,0,0,
  3369.             HWND_DESKTOP, HWND_BOTTOM, 0, NULL, NULL);
  3370.  
  3371.     while ( WinGetMsg(hab, &qmsg, (HWND) NULL, 0, 0) )
  3372.         WinDispatchMsg(hab, &qmsg);
  3373.  
  3374.     WinDestroyWindow(hwndObject);
  3375.  
  3376.     WinDestroyMsgQueue(hmq);
  3377.     WinTerminate(hab);
  3378.     }
  3379. /*...e*/
  3380. /*...sGbmV2WndProc:0:*/
  3381. #define    WC_GBMV2    "GbmV2Class"
  3382.  
  3383. MRESULT _System GbmV2WndProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  3384.     {
  3385.     switch ( (int) msg )
  3386.         {
  3387. /*...sWM_PAINT     \45\ repaint client area:16:*/
  3388. /*
  3389. Dead simple, as this window is usually completely covered by the scroller
  3390. window.
  3391. */
  3392.  
  3393. case WM_PAINT:
  3394.     {
  3395.     HPS hps = WinBeginPaint(hwnd, (HPS) NULL, (RECTL *) NULL);
  3396.  
  3397.     GpiSetBackColor(hps, CLR_RED);
  3398.  
  3399.     GpiErase(hps);
  3400.  
  3401.     WinEndPaint(hps);
  3402.     }
  3403.     return ( (MRESULT) 0 );
  3404. /*...e*/
  3405. /*...sWM_SIZE      \45\ user has resized window:16:*/
  3406. case WM_SIZE:
  3407.     {
  3408.     SWP swp;
  3409.  
  3410.     WinQueryWindowPos(hwnd, &swp);
  3411.     WinSetWindowPos(hwndScroller, (HWND) NULL, 0, 0, swp.cx, swp.cy, SWP_SIZE);
  3412.     }
  3413.     break;
  3414. /*...e*/
  3415. /*...sWM_INITMENU  \45\ enable right menuitems:16:*/
  3416. case WM_INITMENU:
  3417.     {
  3418.     HWND hwndFrame = WinQueryWindow(hwnd, QW_PARENT);
  3419.     HWND hwndMenu = WinWindowFromID(hwndFrame, FID_MENU);
  3420.  
  3421.     switch ( SHORT1FROMMP(mp1) )
  3422.         {
  3423. /*...sMID_FILE:32:*/
  3424. case MID_FILE:
  3425.     EnableMenuItem(hwndMenu, MID_NEW    , !fBusy && fGotBitmap);
  3426.     EnableMenuItem(hwndMenu, MID_OPEN   , !fBusy              );
  3427.     EnableMenuItem(hwndMenu, MID_SAVE   , !fBusy && fGotBitmap && (szFileName [0] != '\0') );
  3428.     EnableMenuItem(hwndMenu, MID_SAVE_AS, !fBusy && fGotBitmap);
  3429.     EnableMenuItem(hwndMenu, MID_PRINT  , !fBusy && fGotBitmap);
  3430.     return ( (MRESULT) 0 );
  3431. /*...e*/
  3432. /*...sMID_EDIT:32:*/
  3433. case MID_EDIT:
  3434.     {
  3435.     CHAR szUndo [100+1];
  3436.     EnableMenuItem(hwndMenu, MID_UNDO      , !fBusy && fCanUndo);
  3437.     if ( fCanUndo )
  3438.         sprintf(szUndo, "~Undo %s", szWhatUndo);
  3439.     else
  3440.         sprintf(szUndo, "~Undo");
  3441.     WinSendMsg(hwndMenu, MM_SETITEMTEXT, MPFROMSHORT(MID_UNDO), MPFROMP(szUndo));
  3442.     EnableMenuItem(hwndMenu, MID_SELECT    , !fBusy && fGotBitmap);
  3443.     EnableMenuItem(hwndMenu, MID_SELECT_ALL, !fBusy && fGotBitmap);
  3444.     EnableMenuItem(hwndMenu, MID_DESELECT  , !fBusy && fSelectionDefined);
  3445.     EnableMenuItem(hwndMenu, MID_COPY      , !fBusy && fGotBitmap && fSelectionDefined);
  3446.     return ( (MRESULT) 0 );
  3447.     }
  3448. /*...e*/
  3449. /*...sMID_BITMAP:32:*/
  3450. case MID_BITMAP:
  3451.     EnableMenuItem(hwndMenu, MID_REF_HORZ , !fBusy && fGotBitmap);
  3452.     EnableMenuItem(hwndMenu, MID_REF_VERT , !fBusy && fGotBitmap);
  3453.     EnableMenuItem(hwndMenu, MID_ROT_90   , !fBusy && fGotBitmap); 
  3454.     EnableMenuItem(hwndMenu, MID_ROT_180  , !fBusy && fGotBitmap);
  3455.     EnableMenuItem(hwndMenu, MID_ROT_270  , !fBusy && fGotBitmap);
  3456.     EnableMenuItem(hwndMenu, MID_TRANSPOSE, !fBusy && fGotBitmap);
  3457.     EnableMenuItem(hwndMenu, MID_CROP     , !fBusy && fGotBitmap && fSelectionDefined);
  3458.     EnableMenuItem(hwndMenu, MID_COLOUR   , !fBusy && fGotBitmap);
  3459.     EnableMenuItem(hwndMenu, MID_MAP      , !fBusy && fGotBitmap);
  3460.     return ( (MRESULT) 0 );
  3461. /*...e*/
  3462. /*...sMID_VIEW:32:*/
  3463. case MID_VIEW:
  3464.     {
  3465.     BOOL fHalftone = ( lBitCountScreen == 4 || lBitCountScreen == 8 || lBitCountScreen == 16 );
  3466.     BOOL fErrDiff  = ( lBitCountScreen == 4 || lBitCountScreen == 8 || lBitCountScreen == 16 );
  3467.  
  3468.     EnableMenuItem(hwndMenu, MID_VIEW_NULL    , !fBusy && fGotBitmap && bView != VIEW_NULL                 );
  3469.     EnableMenuItem(hwndMenu, MID_VIEW_HALFTONE, !fBusy && fGotBitmap && bView != VIEW_HALFTONE && fHalftone);
  3470.     EnableMenuItem(hwndMenu, MID_VIEW_ERRDIFF , !fBusy && fGotBitmap && bView != VIEW_ERRDIFF  && fErrDiff );
  3471.     CheckMenuItem(hwndMenu, MID_VIEW_NULL    , bView == VIEW_NULL    );
  3472.     CheckMenuItem(hwndMenu, MID_VIEW_HALFTONE, bView == VIEW_HALFTONE);
  3473.     CheckMenuItem(hwndMenu, MID_VIEW_ERRDIFF , bView == VIEW_ERRDIFF );
  3474.     return ( (MRESULT) 0 );
  3475.     }
  3476. /*...e*/
  3477.         }
  3478.     }
  3479.     break;
  3480. /*...e*/
  3481. /*...sWM_COMMAND   \45\ menu command:16:*/
  3482. case WM_COMMAND:
  3483.     switch ( COMMANDMSG(&msg) -> cmd )
  3484.         {
  3485. /*...sMID_NEW           \45\ clear out bitmap:32:*/
  3486. case MID_NEW:
  3487.     fBusy = TRUE;
  3488.     WinPostMsg(hwndObject, UM_NEW, MPFROMHWND(hwnd), NULL);
  3489.     break;
  3490. /*...e*/
  3491. /*...sMID_OPEN          \45\ read in a new bitmap:32:*/
  3492. case MID_OPEN:
  3493.     fBusy = TRUE;
  3494.     WinPostMsg(hwndObject, UM_OPEN, MPFROMHWND(hwnd), NULL);
  3495.     break;
  3496. /*...e*/
  3497. /*...sMID_SAVE          \45\ save with old name:32:*/
  3498. case MID_SAVE:
  3499.     fBusy = TRUE;
  3500.     WinPostMsg(hwndObject, UM_SAVE, MPFROMHWND(hwnd), NULL);
  3501.     break;
  3502. /*...e*/
  3503. /*...sMID_SAVE_AS       \45\ save with new name:32:*/
  3504. case MID_SAVE_AS:
  3505.     fBusy = TRUE;
  3506.     WinPostMsg(hwndObject, UM_SAVE_AS, MPFROMHWND(hwnd), NULL);
  3507.     break;
  3508. /*...e*/
  3509. /*...sMID_PRINT         \45\ print image:32:*/
  3510. case MID_PRINT:
  3511.     fBusy = TRUE;
  3512.     WinPostMsg(hwndObject, UM_PRINT, MPFROMHWND(hwnd), NULL);
  3513.     break;
  3514. /*...e*/
  3515. /*...sMID_UNDO          \45\ undo previous operation:32:*/
  3516. case MID_UNDO:
  3517.     fBusy = TRUE;
  3518.     WinPostMsg(hwndObject, UM_UNDO, MPFROMHWND(hwnd), NULL);
  3519.     break;
  3520. /*...e*/
  3521. /*...sMID_SELECT        \45\ select region of bitmap:32:*/
  3522. case MID_SELECT:
  3523.     fBusy = TRUE;
  3524.     WinPostMsg(hwndObject, UM_SELECT, MPFROMHWND(hwnd), NULL);
  3525.     break;
  3526. /*...e*/
  3527. /*...sMID_SELECT_ALL    \45\ select region of bitmap:32:*/
  3528. case MID_SELECT_ALL:
  3529.     fBusy = TRUE;
  3530.     WinPostMsg(hwndObject, UM_SELECT_ALL, MPFROMHWND(hwnd), NULL);
  3531.     break;
  3532. /*...e*/
  3533. /*...sMID_DESELECT      \45\ de\45\select any selcted area:32:*/
  3534. case MID_DESELECT:
  3535.     fBusy = TRUE;
  3536.     WinPostMsg(hwndObject, UM_DESELECT, MPFROMHWND(hwnd), NULL);
  3537.     break;
  3538. /*...e*/
  3539. /*...sMID_COPY          \45\ copy bitmap to clipboard:32:*/
  3540. case MID_COPY:
  3541.     fBusy = TRUE;
  3542.     WinPostMsg(hwndObject, UM_COPY, MPFROMHWND(hwnd), NULL);
  3543.     break;
  3544. /*...e*/
  3545. /*...sMID_REF_HORZ      \45\ reflect horizontally:32:*/
  3546. case MID_REF_HORZ:
  3547.     fBusy = TRUE;
  3548.     WinPostMsg(hwndObject, UM_REF_HORZ, MPFROMHWND(hwnd), NULL);
  3549.     break;
  3550. /*...e*/
  3551. /*...sMID_REF_VERT      \45\ reflect vertically:32:*/
  3552. case MID_REF_VERT:
  3553.     fBusy = TRUE;
  3554.     WinPostMsg(hwndObject, UM_REF_VERT, MPFROMHWND(hwnd), NULL);
  3555.     break;
  3556. /*...e*/
  3557. /*...sMID_ROT_90        \45\ rotate by 90 degrees:32:*/
  3558. case MID_ROT_90:
  3559.     fBusy = TRUE;
  3560.     WinPostMsg(hwndObject, UM_ROT_90, MPFROMHWND(hwnd), NULL);
  3561.     break;
  3562. /*...e*/
  3563. /*...sMID_ROT_180       \45\ rotate by 180 degrees:32:*/
  3564. case MID_ROT_180:
  3565.     fBusy = TRUE;
  3566.     WinPostMsg(hwndObject, UM_ROT_180, MPFROMHWND(hwnd), NULL);
  3567.     break;
  3568. /*...e*/
  3569. /*...sMID_ROT_270       \45\ rotate by 270 degrees:32:*/
  3570. case MID_ROT_270:
  3571.     fBusy = TRUE;
  3572.     WinPostMsg(hwndObject, UM_ROT_270, MPFROMHWND(hwnd), NULL);
  3573.     break;
  3574. /*...e*/
  3575. /*...sMID_TRANSPOSE     \45\ transpose x for y:32:*/
  3576. case MID_TRANSPOSE:
  3577.     fBusy = TRUE;
  3578.     WinPostMsg(hwndObject, UM_TRANSPOSE, MPFROMHWND(hwnd), NULL);
  3579.     break;
  3580. /*...e*/
  3581. /*...sMID_CROP          \45\ crop to selection:32:*/
  3582. case MID_CROP:
  3583.     fBusy = TRUE;
  3584.     WinPostMsg(hwndObject, UM_CROP, MPFROMHWND(hwnd), NULL);
  3585.     break;
  3586. /*...e*/
  3587. /*...sMID_COLOUR        \45\ change colour space:32:*/
  3588. case MID_COLOUR:
  3589.     fBusy = TRUE;
  3590.     WinPostMsg(hwndObject, UM_COLOUR, MPFROMHWND(hwnd), NULL);
  3591.     break;
  3592. /*...e*/
  3593. /*...sMID_MAP           \45\ map:32:*/
  3594. case MID_MAP:
  3595.     fBusy = TRUE;
  3596.     WinPostMsg(hwndObject, UM_MAP, MPFROMHWND(hwnd), NULL);
  3597.     break;
  3598. /*...e*/
  3599. /*...sMID_VIEW_NULL     \45\ view with no transform:32:*/
  3600. case MID_VIEW_NULL:
  3601.     fBusy = TRUE;
  3602.     WinPostMsg(hwndObject, UM_VIEW_NULL, MPFROMHWND(hwnd), NULL);
  3603.     break;
  3604. /*...e*/
  3605. /*...sMID_VIEW_HALFTONE \45\ view with errordiffusion:32:*/
  3606. case MID_VIEW_HALFTONE:
  3607.     fBusy = TRUE;
  3608.     WinPostMsg(hwndObject, UM_VIEW_HALFTONE, MPFROMHWND(hwnd), NULL);
  3609.     break;
  3610. /*...e*/
  3611. /*...sMID_VIEW_ERRDIFF  \45\ view with halftoning:32:*/
  3612. case MID_VIEW_ERRDIFF:
  3613.     fBusy = TRUE;
  3614.     WinPostMsg(hwndObject, UM_VIEW_ERRDIFF, MPFROMHWND(hwnd), NULL);
  3615.     break;
  3616. /*...e*/
  3617. /*...sMID_HELP_FOR_HELP \45\ bring up help for help:32:*/
  3618. case MID_HELP_FOR_HELP:
  3619.     HlpHelpForHelp(hwndHelp);
  3620.     break;
  3621. /*...e*/
  3622. /*...sMID_EXIT          \45\ initiate shutdown of this app:32:*/
  3623. case MID_EXIT:
  3624.     WinPostMsg(hwnd, WM_QUIT, 0L, 0L);
  3625.     break;
  3626. /*...e*/
  3627.         }
  3628.     return ( (MRESULT) 0 );
  3629. /*...e*/
  3630. /*...sWM_CLOSE     \45\ close window:16:*/
  3631. case WM_CLOSE:
  3632.     WinPostMsg(hwnd, WM_QUIT, 0L, 0L);
  3633.     return ( (MRESULT) 0 );
  3634. /*...e*/
  3635. /*...sWM_CONTROL   \45\ override scrolling amount:16:*/
  3636. case WM_CONTROL:
  3637.     if ( SHORT1FROMMP(mp1) == WID_SCROLL )
  3638.         switch ( SHORT2FROMMP(mp1) )
  3639.             {
  3640.             case SCN_HPAGE:
  3641.             case SCN_VPAGE:
  3642.                 return ( (MRESULT) SHORT2FROMMP(mp2) );
  3643.             }
  3644.     break;
  3645. /*...e*/
  3646. /*...sWM_ACTIVATE  \45\ ensure help instance is ours:16:*/
  3647. case WM_ACTIVATE:
  3648.     {
  3649.     HWND hwndFrame = WinQueryWindow(hwnd, QW_PARENT);
  3650.  
  3651.     if ( mp1 && hwndHelp != (HWND) NULL )
  3652.         HlpActivate(hwndHelp, hwndFrame);
  3653.     }
  3654.     break;
  3655. /*...e*/
  3656. /*...sHM_\42\         \45\ redirect help support:16:*/
  3657. case HM_ERROR:
  3658. case HM_INFORM:
  3659. case HM_QUERY_KEYS_HELP:
  3660. case HM_EXT_HELP_UNDEFINED:
  3661. case HM_HELPSUBITEM_NOT_FOUND:
  3662.     return ( HlpWndProc(hwnd, msg, mp1, mp2) );
  3663. /*...e*/
  3664.         }
  3665.     return ( WinDefWindowProc(hwnd, msg, mp1, mp2) );
  3666.     }
  3667. /*...e*/
  3668. /*...smain:0:*/
  3669. int main(int argc, CHAR *argv [])
  3670.     {
  3671.     HAB hab = WinInitialize(0);
  3672.     HMQ hmq = WinCreateMsgQueue(hab, 0);
  3673.     QMSG qmsg;
  3674.     HWND hwndFrame, hwndClient;
  3675.     HPS hps;
  3676.     HDC hdc;
  3677.     SWP swp;
  3678.     static ULONG flFrameFlags = FCF_TITLEBAR      | FCF_SYSMENU    |
  3679.                     FCF_SIZEBORDER    | FCF_MINMAX     |
  3680.                     FCF_MENU          | FCF_ICON       |
  3681.                     FCF_SHELLPOSITION | FCF_TASKLIST   |
  3682.                     FCF_ACCELTABLE    ;
  3683.  
  3684.     gbm_init();
  3685.  
  3686.     hps = WinGetPS(HWND_DESKTOP);
  3687.     hdc = GpiQueryDevice(hps);
  3688.     DevQueryCaps(hdc, CAPS_COLOR_BITCOUNT, 1L, &lBitCountScreen);
  3689.     WinReleasePS(hps);
  3690.  
  3691.     DosCreateMutexSem(NULL, &hmtxHbm, 0 /*=Private*/, FALSE /*=unowned*/ );
  3692.  
  3693.     RegisterScrollClass(hab);
  3694.     WinRegisterClass(hab, WC_GBMV2, GbmV2WndProc, CS_CLIPCHILDREN|CS_SIZEREDRAW, 0);
  3695.     WinRegisterClass(hab, WC_BITMAP, BitmapWndProc, 0L, 0);
  3696.  
  3697.     hwndFrame = WinCreateStdWindow(
  3698.         HWND_DESKTOP,        /* Parent window handle              */
  3699.         WS_VISIBLE,        /* Style of frame window             */
  3700.         &flFrameFlags,        /* Pointer to control data           */
  3701.         WC_GBMV2,        /* Client window class name          */
  3702.         NULL,            /* Title bar text                    */
  3703.         0L,            /* Style of client window            */
  3704.         (HMODULE) NULL,        /* Module handle for resources       */
  3705.         RID_GBMV2,        /* ID of resources                   */
  3706.         &hwndClient);        /* Pointer to client window handle   */
  3707.  
  3708.     WinSetWindowText(hwndFrame, szAppName);
  3709.  
  3710.     WinQueryWindowPos(hwndClient, &swp);
  3711.  
  3712.     hwndScroller = WinCreateWindow(hwndClient, WC_SCROLL, "", WS_VISIBLE|SCS_HSCROLL|SCS_VSCROLL|SCS_HCENTRE|SCS_VCENTRE|SCS_HPAGE|SCS_VPAGE,
  3713.          0,0,swp.cx,swp.cy, hwndClient, HWND_BOTTOM, WID_SCROLL, NULL, NULL);
  3714.     hwndBitmap = WinCreateWindow(hwndScroller, WC_BITMAP, "", WS_VISIBLE|WS_CLIPSIBLINGS,
  3715.          0,0,0,0, hwndScroller, HWND_BOTTOM, WID_BITMAP, NULL, NULL);
  3716.     WinSetFocus(HWND_DESKTOP, hwndBitmap);
  3717.  
  3718.     _beginthread(ObjectThread, NULL, CB_STACK_OBJECT, NULL);
  3719.  
  3720.     if ( argc >= 2 )
  3721.         {
  3722.         CHAR *szOpt;
  3723.  
  3724.         if ( (szOpt = strchr(argv [1], ',')) != NULL )
  3725.             *szOpt++ = '\0';
  3726.         else
  3727.             szOpt = "";
  3728.  
  3729.         if ( LoadBitmap(HWND_DESKTOP, argv [1], szOpt, &gbm, gbmrgb, &pbData) )
  3730.             {
  3731.             HBITMAP hbmNew;
  3732.             LONG lColorBgNew, lColorFgNew;
  3733.  
  3734.             if ( MakeVisual(HWND_DESKTOP, &gbm, gbmrgb, pbData, bView, &hbmNew, &lColorBgNew, &lColorFgNew) )
  3735.                 {
  3736.                 strcpy(szFileName, argv [1]);
  3737.                 Caption(hwndClient, " - %s", szFileName);
  3738.                 lColorBg = lColorBgNew;
  3739.                 lColorFg = lColorFgNew;
  3740.                 SetBitmap(hbmNew);
  3741.                 WinInvalidateRect(hwndScroller, NULL, TRUE);
  3742.                 WinUpdateWindow(hwndScroller);
  3743.                 fGotBitmap = TRUE;
  3744.                 }
  3745.             else
  3746.                 free(pbData);
  3747.             }
  3748.         }
  3749.  
  3750.     if ( (hwndHelp = HlpInit(hwndClient,
  3751.                (HMODULE) NULL, RID_HELP_TABLE,
  3752.                "GBMV2.HLP GBMDLG.HLP", szAppName)) != (HWND) NULL )
  3753.         HlpActivate(hwndHelp, hwndFrame);
  3754.  
  3755.     for ( ;; )
  3756.         {
  3757.         while ( WinGetMsg(hab, &qmsg, (HWND) NULL, 0, 0) )
  3758.             WinDispatchMsg(hab, &qmsg);
  3759.  
  3760.         if ( SaveChanges(hwndFrame) )
  3761.             /* User has not cancelled Close */
  3762.             {        
  3763.             if ( !fBusy )
  3764.                 break;
  3765.  
  3766.             Warning(hwndFrame, "Cannot Close yet, %s is busy, please wait and retry", szAppName);
  3767.             }
  3768.         }
  3769.  
  3770.     if ( hwndHelp != (HWND) NULL )
  3771.         HlpDeinit(hwndHelp);
  3772.  
  3773.     WinPostMsg(hwndObject, WM_QUIT, NULL, NULL);
  3774.  
  3775.     WinDestroyWindow(hwndBitmap);
  3776.     WinDestroyWindow(hwndScroller);
  3777.     WinDestroyWindow(hwndFrame);
  3778.  
  3779.     DosCloseMutexSem(hmtxHbm);
  3780.  
  3781.     gbm_deinit();
  3782.  
  3783.     WinDestroyMsgQueue(hmq);
  3784.     WinTerminate(hab);
  3785.  
  3786.     return ( 0 );
  3787.     }
  3788. /*...e*/
  3789.