PLGBLT.C
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:45k
源码类别:

Windows编程

开发平台:

Visual C++

  1. /******************************************************************************
  2. *       This is a part of the Microsoft Source Code Samples. 
  3. *       Copyright (C) 1992-1997 Microsoft Corporation.
  4. *       All rights reserved. 
  5. *       This source code is only intended as a supplement to 
  6. *       Microsoft Development Tools and/or WinHelp documentation.
  7. *       See these sources for detailed information regarding the 
  8. *       Microsoft samples programs.
  9. ******************************************************************************/
  10. /**************************************************************************
  11. *  plgblt.c -- sample program demonstrating the new PlgBlt() API.
  12. *
  13. *  design:  There is one main window with one dialog box stretched to fill
  14. *   the top of it.  The parameters for the plgblt painted into the main
  15. *   window are stored in the entry fields of this dialog box.  The user
  16. *   may change these values and see the effect on the blt.
  17. **************************************************************************/
  18. #include <windows.h>
  19. #include <commdlg.h>
  20. #include <math.h>
  21. #include <stdio.h>
  22. #include "plgblt.h"
  23. #include "track.h"
  24. #include "bitmap.h"
  25. /* global variables. */
  26. PTrackObject ptoDest, ptoSrc, ptoMask = NULL;
  27. HDC          hdcDest, hdcSrc, hdcMask;
  28. HBITMAP               hbmSrc, hbmMask = NULL;
  29. HANDLE hInst;
  30. HWND   hwndMain, hwndDlg;
  31. int nSpin;
  32. #define  BACKGROUNDBRUSH GetStockObject(LTGRAY_BRUSH)
  33. /**************************************************************************
  34. *
  35. *  function:  WinMain()
  36. *
  37. *  input parameters:  c.f. generic sample
  38. *
  39. **************************************************************************/
  40. int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  41.                      LPSTR lpCmdLine, int nCmdShow)
  42. {
  43.     MSG   msg;
  44.     RECT rect;
  45.     HANDLE haccel;
  46.     UNREFERENCED_PARAMETER( lpCmdLine );
  47.     //
  48.     // Detect platform and exit gracefully if not Windows NT.
  49.     //
  50.     {
  51.       OSVERSIONINFO osvi;
  52.       osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
  53.       GetVersionEx (&osvi);
  54.       if (osvi.dwPlatformId != VER_PLATFORM_WIN32_NT) {
  55.         MessageBox (NULL,
  56.           GetStringRes (IDS_NTONLY),
  57.           "PlgBlt", MB_OK | MB_ICONSTOP);
  58.         return 0;
  59.       }
  60.     }
  61.     /* Check for previous instance.  If none, then register class. */
  62.     if (!hPrevInstance) {
  63.         WNDCLASS  wc;
  64.         wc.style = 0;
  65.         wc.lpfnWndProc = (WNDPROC)MainWndProc;
  66.         wc.cbClsExtra = 0;
  67.         wc.cbWndExtra = 0;
  68.         wc.hInstance = hInstance;
  69.         wc.hIcon = LoadIcon(hInstance, "plgbltIcon");
  70.         wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  71.         wc.hbrBackground = BACKGROUNDBRUSH;
  72.         wc.lpszMenuName =  "plgbltMenu";
  73.         wc.lpszClassName = "plgblt";
  74.         if (!RegisterClass(&wc)) return (FALSE);
  75.     }  /* class registered o.k. */
  76.     /* Create the main window.  Return false if CreateWindow() fails */
  77.     hInst = hInstance;
  78.     hwndMain = CreateWindow(
  79.         "plgblt",
  80.         GetStringRes (IDS_WINDOWTITLE),
  81.         WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
  82.         CW_USEDEFAULT,
  83.         CW_USEDEFAULT,
  84.         CW_USEDEFAULT,
  85.         CW_USEDEFAULT,
  86.         NULL,
  87.         NULL,
  88.         hInstance,
  89.         NULL);
  90.     if (!hwndMain) return (FALSE);
  91.     /* create the top dialog as a child of the main window. */
  92.     hwndDlg = CreateDialog (hInst, "plgbltDlg", hwndMain, (DLGPROC)DlgProc);
  93.     /* Send main window a WM_SIZE message so that it will size the top
  94.      *  dialog correctly.
  95.      */
  96.     GetClientRect (hwndMain, &rect);
  97.     SendMessage (hwndMain, WM_SIZE, 0, (rect.right - rect.left));
  98.     ShowWindow (hwndDlg, SW_SHOW);
  99.     ShowWindow(hwndMain, nCmdShow);
  100.     /* get global handle to the menu */
  101.     /* Load the accelerator table that provides clipboard support. */
  102.     haccel = LoadAccelerators (hInst, "bltAccel");
  103.     /* Loop getting messages and dispatching them. */
  104.     while (GetMessage(&msg,NULL, 0,0)) {
  105.       if (!TranslateAccelerator(hwndMain, haccel, &msg))
  106.       if (!IsDialogMessage (hwndDlg, &msg)){
  107.         DispatchMessage(&msg);
  108.       }
  109.       /* if no messages, and we are spinning, then post spin message. */
  110.       if (!PeekMessage (&msg, hwndMain, 0,0, PM_NOREMOVE) && nSpin)
  111.         PostMessage (hwndMain, WM_SPIN, 0,0);
  112.     }
  113.     /* Return the value from PostQuitMessage */
  114.     return (msg.wParam);
  115. }
  116. /**************************************************************************
  117. *
  118. *  function:  MainWndProc()
  119. *
  120. *  input parameters:  normal window procedure parameters.
  121. *
  122. *  There are 6 different HDCs used for the main window (in addition to the
  123. *   temporary one returned from BeginPaint).  There are two for each of the
  124. *   three thirds of the window.  The first one contains the bitmap.  The
  125. *   second one is for the track object and is stored in the TRACKOBJECT
  126. *   structure.
  127. *
  128. *  global variables:
  129. *   hwndDlg - dialog with entry fields containing parameters.
  130. *   ptoDest, ptoSrc, ptoMask - pointers to the direct manipulation objects
  131. *   hdcDest, hdcSrc, hdcMask - HDCs for the 3 sub regions of the window.
  132. *   hbmSrc, hbmMask          - bitmap handles for source and mask.
  133. **************************************************************************/
  134. LRESULT CALLBACK MainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  135. {
  136. static int miniWidth;
  137. static RECT rect;
  138. static HANDLE hPenGrid, hPenSeparator;
  139.   switch (message) {
  140.     /**********************************************************************
  141.     *  WM_CREATE
  142.     *
  143.     * Get three new HDCs, then create three new track objects.
  144.     *  Each track object has different allowed tracking modes.
  145.     *  Finally create two pens for drawing later on.
  146.     **********************************************************************/
  147.     case WM_CREATE:
  148.         hdcSrc  = GetDC (hwnd);
  149.         hdcDest = GetDC (hwnd);
  150.         hdcMask = GetDC (hwnd);
  151.         ptoDest = doTrackObject (NULL, TROB_NEW, hwnd,0);
  152.         ptoDest->allowedModes = TMALL;
  153.         ptoSrc  = doTrackObject (NULL, TROB_NEW, hwnd,0);
  154.         ptoSrc->allowedModes = TMMOVE | TMSIZEXY;
  155.         ptoMask = doTrackObject (NULL, TROB_NEW, hwnd,0);
  156.         ptoMask->allowedModes = TMMOVE;
  157.         hPenGrid      = CreatePen (PS_SOLID, 1, GRIDCOLOR);
  158.         hPenSeparator = CreatePen (PS_SOLID, 2*SEPARATORWIDTH, (COLORREF) 0x01000000);
  159.         { HMENU hMenu;
  160.         hMenu = GetMenu (hwnd);
  161.         CheckMenuItem(hMenu, IDM_SPINTOPLEFT, MF_CHECKED);
  162.         CheckMenuItem(hMenu, IDM_SPINOFF    , MF_CHECKED);
  163.         nSpin = FALSE;
  164.         }
  165.     break;
  166.     /**********************************************************************
  167.     *  WM_DESTROY
  168.     *
  169.     * Complement of WM_CREATE.  Free up all of the HDCs, send all of the
  170.     *  track objects their delete messages, delete the pens,
  171.     *  then call PostQuitMessage.
  172.     **********************************************************************/
  173.     case WM_DESTROY:
  174.         ReleaseDC (hwnd, hdcSrc );
  175.         ReleaseDC (hwnd, hdcDest);
  176.         ReleaseDC (hwnd, hdcMask);
  177.         doTrackObject (ptoDest, TROB_DELETE, hwnd,0);
  178.         doTrackObject (ptoSrc , TROB_DELETE, hwnd,0);
  179.         doTrackObject (ptoMask, TROB_DELETE, hwnd,0);
  180.         DeleteObject(hPenGrid);
  181.         DeleteObject(hPenSeparator);
  182.         PostQuitMessage(0);
  183.     break;
  184.     /**********************************************************************
  185.     *  WM_SIZE
  186.     *
  187.     * Stretch the top dialog to fill the width of the main window.
  188.     * Adjust the viewport origins of the 6 HDCs.
  189.     * Set the clip regions of the 6 HDCs.
  190.     **********************************************************************/
  191.     case WM_SIZE: {
  192.         HRGN hrgn;
  193.         SetWindowPos (hwndDlg, NULL, 0,0, LOWORD(lParam), DIALOGHEIGHT, 0);
  194.         GetClientRect (hwndMain, &rect);
  195.         miniWidth = rect.right/3;
  196.         SetViewportOrgEx (hdcDest,      0,           DIALOGHEIGHT, NULL);
  197.         SetViewportOrgEx (ptoDest->hdc, 0,           DIALOGHEIGHT, NULL);
  198.         SetViewportOrgEx (hdcSrc,       miniWidth,   DIALOGHEIGHT, NULL);
  199.         SetViewportOrgEx (ptoSrc->hdc,  miniWidth,   DIALOGHEIGHT, NULL);
  200.         SetViewportOrgEx (hdcMask,      2*miniWidth, DIALOGHEIGHT, NULL);
  201.         SetViewportOrgEx (ptoMask->hdc, 2*miniWidth, DIALOGHEIGHT, NULL);
  202.         ptoDest->rectClip.left    = 0;
  203.         ptoDest->rectClip.top     = DIALOGHEIGHT;
  204.         ptoDest->rectClip.right   = miniWidth-2*SEPARATORWIDTH;
  205.         ptoDest->rectClip.bottom  = rect.bottom;
  206.         hrgn = CreateRectRgnIndirect (&ptoDest->rectClip);
  207.         SelectClipRgn (hdcDest,      hrgn);
  208.         SelectClipRgn (ptoDest->hdc, hrgn);
  209.         DeleteObject (hrgn);
  210.         ptoSrc->rectClip.left    = miniWidth;
  211.         ptoSrc->rectClip.top     = DIALOGHEIGHT;
  212.         ptoSrc->rectClip.right   = 2*miniWidth-2*SEPARATORWIDTH;
  213.         ptoSrc->rectClip.bottom  = rect.bottom;
  214.         hrgn = CreateRectRgnIndirect (&ptoSrc->rectClip);
  215.         SelectClipRgn (hdcSrc,       hrgn);
  216.         SelectClipRgn (ptoSrc->hdc,  hrgn);
  217.         DeleteObject (hrgn);
  218.         ptoMask->rectClip.left    = 2*miniWidth;
  219.         ptoMask->rectClip.top     = DIALOGHEIGHT;
  220.         ptoMask->rectClip.right   = 3*miniWidth;
  221.         ptoMask->rectClip.bottom  = rect.bottom;
  222.         hrgn = CreateRectRgnIndirect (&ptoMask->rectClip);
  223.         SelectClipRgn (hdcMask,      hrgn);
  224.         SelectClipRgn (ptoMask->hdc, hrgn);
  225.         DeleteObject (hrgn);
  226.         SendMessage (hwndDlg, WM_PUTUPLPOINTS, (DWORD)hdcDest, (LONG)ptoDest);
  227.         SendMessage (hwndDlg, WM_PUTUPSRCRECT, (DWORD)hdcSrc,  (LONG)ptoSrc);
  228.         SendMessage (hwndDlg, WM_PUTUPMASKPT,  (DWORD)hdcMask, (LONG)ptoMask);
  229.         /* repaint the whole window. */
  230.         InvalidateRect (hwnd, NULL, TRUE);
  231.     } break;
  232.     /**********************************************************************
  233.     *  WM_PAINT
  234.     *
  235.     * miniWidth, rect -- set by WM_SIZE message.
  236.     *
  237.     * First shift the viewport origin down so that 0,0 is the top left
  238.     *  most visible point (out from underneath the top dialog).  Second,
  239.     *  draw the grid with wider lines on the axes.  Finally, read the
  240.     *  values out of the top dialog, do elementary validation, and then
  241.     *  try to call plgblt() with the values.
  242.     **********************************************************************/
  243.      case WM_PAINT: {
  244.         HDC hdc;
  245.         PAINTSTRUCT ps;
  246.         hdc = BeginPaint(hwnd, &ps);
  247.         /* Draw Separator lines for the three miniareas */
  248.         SelectObject(hdc, hPenSeparator);
  249.         MoveToEx (hdc,   miniWidth-SEPARATORWIDTH,0, NULL);
  250.         LineTo   (hdc,   miniWidth-SEPARATORWIDTH, rect.bottom);
  251.         MoveToEx (hdc, 2*miniWidth-SEPARATORWIDTH,0, NULL);
  252.         LineTo   (hdc, 2*miniWidth-SEPARATORWIDTH, rect.bottom);
  253.         /* Grid the HDCs */
  254.         SelectObject(hdcSrc, hPenGrid);
  255.         DrawGrids (hdcSrc, miniWidth, rect.bottom);
  256.         SelectObject(hdcMask, hPenGrid);
  257.         DrawGrids (hdcMask, miniWidth, rect.bottom);
  258.         /* Draw bitmaps if any, then draw track objects over them. */
  259.         if (hbmSrc)  DrawBitmap (hdcSrc, hbmSrc);
  260.         if (hbmMask) DrawBitmap (hdcMask, hbmMask);
  261.         doTrackObject (ptoSrc , TROB_PAINT, hwnd, 0);
  262.         doTrackObject (ptoMask, TROB_PAINT, hwnd, 0);
  263.         /* paint the left third of the window. */
  264.         SendMessage (hwnd, WM_PLGBLT, 0,0);
  265.         EndPaint (hwnd, &ps);
  266.     } return FALSE;
  267.     /**********************************************************************
  268.     *  WM_PLGBLT
  269.     *
  270.     * WM_USER message.  This paints the left third of the window.  It
  271.     *  is called on the WM_PAINT message.  It is separated out here because
  272.     *  it is common for just the plgblt() to need to be called and not the
  273.     *  whole window painted.
  274.     **********************************************************************/
  275.     case WM_PLGBLT: {
  276.         POINT lpPoint[3];
  277.         int XSrc, YSrc, nWidth, nHeight, XMask, YMask;
  278.         BOOL success;
  279.         RECT cliprect;
  280.         doTrackObject (ptoSrc , TROB_PAINT, hwnd, 0);
  281.         doTrackObject (ptoMask, TROB_PAINT, hwnd, 0);
  282.         GetClipBox (hdcDest, &cliprect);
  283.         FillRect (hdcDest, &cliprect,
  284.                   (HBRUSH) GetClassLong (hwnd, GCL_HBRBACKGROUND));
  285.         SelectObject(hdcDest, hPenGrid);
  286.         DrawGrids (hdcDest, miniWidth, rect.bottom);
  287.         if (IsWindow(hwndDlg)) {
  288.           /* Grab points out of the dialog entry fields. */
  289.           lpPoint[0].x = GetDlgItemInt(hwndDlg, DID_P1X, &success, TRUE);
  290.           lpPoint[0].y = GetDlgItemInt(hwndDlg, DID_P1Y, &success, TRUE);
  291.           lpPoint[1].x = GetDlgItemInt(hwndDlg, DID_P2X, &success, TRUE);
  292.           lpPoint[1].y = GetDlgItemInt(hwndDlg, DID_P2Y, &success, TRUE);
  293.           lpPoint[2].x = GetDlgItemInt(hwndDlg, DID_P3X, &success, TRUE);
  294.           lpPoint[2].y = GetDlgItemInt(hwndDlg, DID_P3Y, &success, TRUE);
  295.           XSrc = GetDlgItemInt(hwndDlg, DID_XSRC, &success, TRUE);
  296.           YSrc = GetDlgItemInt(hwndDlg, DID_YSRC, &success, TRUE);
  297.           nWidth = GetDlgItemInt(hwndDlg, DID_WIDTH, &success, TRUE);
  298.           nHeight = GetDlgItemInt(hwndDlg, DID_HEIGHT, &success, TRUE);
  299.           XMask = GetDlgItemInt(hwndDlg, DID_XMASK, &success, TRUE);
  300.           YMask = GetDlgItemInt(hwndDlg, DID_YMASK, &success, TRUE);
  301.           /**********************************************************/
  302.           /**********************************************************/
  303.           PlgBlt (hdcDest, lpPoint,
  304.                   hdcSrc, XSrc, YSrc, nWidth, nHeight,
  305.                   hbmMask, XMask, YMask);
  306.           /**********************************************************/
  307.           /**********************************************************/
  308.         }
  309.         doTrackObject (ptoSrc , TROB_PAINT, hwnd, 0);
  310.         doTrackObject (ptoMask, TROB_PAINT, hwnd, 0);
  311.     } break;
  312.     /**********************************************************************
  313.     *  WM_LBUTTONDOWN & WM_RBUTTONDOWN
  314.     * On button down messages, hittest on the track object, and if
  315.     *  it returns true, then send these messages to the track object.
  316.     **********************************************************************/
  317.     case WM_RBUTTONDOWN:
  318.     case WM_LBUTTONDOWN:
  319.       if (doTrackObject(ptoDest, TROB_HITTEST, hwnd, lParam))
  320.          doTrackObject(ptoDest, message, hwnd, lParam);
  321.       else if (doTrackObject(ptoSrc, TROB_HITTEST, hwnd, lParam))
  322.          doTrackObject(ptoSrc, message, hwnd, lParam);
  323.       else if (doTrackObject(ptoMask, TROB_HITTEST, hwnd, lParam))
  324.          doTrackObject(ptoMask, message, hwnd, lParam);
  325.     break;
  326.     /**********************************************************************
  327.     *  WM_LBUTTONUP & WM_RBUTTONDOWN & MW_MOUSEMOVE
  328.     * If the track object is in a "tracking mode" then send it these messages.
  329.     *  If the transform dialog is not minimized, fill it with numbers.
  330.     *  If the mouse dialog is not minimized, fill it with numbers.
  331.     **********************************************************************/
  332.     case WM_RBUTTONUP:
  333.     case WM_LBUTTONUP:
  334.       /* user action complete.  Force plgblt() update. */
  335.       PostMessage (hwndMain, WM_PLGBLT, 0,0);
  336.     case WM_MOUSEMOVE:
  337.       if (ptoDest->Mode) {
  338.         doTrackObject(ptoDest, message, hwnd, lParam);
  339.         SendMessage (hwndDlg, WM_PUTUPLPOINTS, (DWORD) hdcDest, (LONG) ptoDest);
  340.       }
  341.       if (ptoSrc->Mode) {
  342.         doTrackObject(ptoSrc, message, hwnd, lParam);
  343.         SendMessage (hwndDlg, WM_PUTUPSRCRECT, (DWORD) hdcSrc, (LONG) ptoSrc);
  344.       }
  345.       if (ptoMask->Mode) {
  346.         doTrackObject(ptoMask, message, hwnd, lParam);
  347.         SendMessage (hwndDlg, WM_PUTUPMASKPT, (DWORD) hdcMask, (LONG) ptoMask);
  348.       }
  349.     break;
  350.     /**********************************************************************
  351.     *  WM_SETFOCUS
  352.     *
  353.     * The main window should never have the focus.  Set it back
  354.     *  to the top dialog.
  355.     **********************************************************************/
  356.     case WM_SETFOCUS: SetFocus (hwndDlg);
  357.         return 0;
  358.     /**********************************************************************
  359.     *  Menu item support.
  360.     *
  361.     **********************************************************************/
  362.     case WM_COMMAND:
  363.       switch (LOWORD(wParam)) {
  364.         HBITMAP hbmCompat, hbmOld;
  365.         HDC hdcCompat;
  366.         /******************************************************************
  367.         *  WM_COMMAND, IDM_COPY
  368.         *
  369.         * Create a new bitmap, copy the destination HDC bits into it,
  370.         *  and send the new bitmap to the clipboard.
  371.         ******************************************************************/
  372.         case IDM_COPY: {
  373.           int X[4],Y[4];
  374.           int nWidth, nHeight;
  375.           int Xmin, Ymin, Xmax, Ymax;
  376.           BOOL success;
  377.           int i;
  378.           for (i = 0; i<3 ; i++) {
  379.             X[i] = GetDlgItemInt(hwndDlg, DID_P1X + 2*i, &success, TRUE);
  380.             Y[i] = GetDlgItemInt(hwndDlg, DID_P1Y + 2*i, &success, TRUE);
  381.           }
  382.           X[3] = (X[1] - X[0]) + X[2];
  383.           Y[3] = (Y[2] - Y[0]) + Y[1];
  384.           Xmin = Xmax = X[0];
  385.           Ymin = Ymax = Y[0];
  386.           for (i = 1; i<4 ; i++) {
  387.             Xmin = (X[i] < Xmin) ? X[i] : Xmin;
  388.             Ymin = (Y[i] < Ymin) ? Y[i] : Ymin;
  389.             Xmax = (X[i] > Xmax) ? X[i] : Xmax;
  390.             Ymax = (Y[i] > Ymax) ? Y[i] : Ymax;
  391.           }
  392.           nWidth = Xmax - Xmin;
  393.           nHeight = Ymax - Ymin;
  394.           hdcCompat = CreateCompatibleDC(hdcDest);
  395.           hbmCompat = CreateCompatibleBitmap (hdcDest, nWidth, nHeight);
  396.           hbmOld = SelectObject(hdcCompat,hbmCompat);
  397.           BitBlt (hdcCompat, 0,0,nWidth, nHeight, hdcDest, Xmin,Ymin, SRCCOPY );
  398.           SelectObject(hdcCompat,hbmOld);
  399.           DeleteDC(hdcCompat);
  400.           OpenClipboard (hwnd);
  401.           SetClipboardData (CF_BITMAP,hbmCompat);
  402.           CloseClipboard ();
  403.           DeleteObject (hbmCompat);
  404.         } break;
  405.         /******************************************************************
  406.         *  WM_COMMAND, IDM_PASTE
  407.         *
  408.         * Get bitmap handle from clipboard, create a new bitmap, draw
  409.         *  the clipboard bitmap into the new one, and store the new
  410.         *  handle in the global hbmSrc.
  411.         ******************************************************************/
  412.         case IDM_PASTE: {
  413.           HBITMAP hbm;
  414.           BITMAP bm;
  415.           OpenClipboard (hwnd);
  416.           if ( hbm = GetClipboardData (CF_BITMAP)) {
  417.             DeleteObject (hbmSrc);
  418.             GetObject (hbm, sizeof(BITMAP), &bm);
  419.             hdcCompat = CreateCompatibleDC(hdcDest);
  420.             hbmCompat = CreateCompatibleBitmap (hdcDest, bm.bmWidth, bm.bmHeight);
  421.             hbmOld = SelectObject(hdcCompat,hbmCompat);
  422.             DrawBitmap (hdcCompat, hbm);
  423.             SelectObject(hdcCompat,hbmOld);
  424.             DeleteDC(hdcCompat);
  425.             hbmSrc = hbmCompat;
  426.             InvalidateRect (hwnd, &ptoSrc->rectClip, TRUE);
  427.             InvalidateRect (hwnd, &ptoDest->rectClip, TRUE);
  428.           }
  429.           CloseClipboard ();
  430.         } break;
  431.         /******************************************************************
  432.         *  WM_COMMAND, IDM_BOTH
  433.         *
  434.         * Post a COPY and PASTE command message to this window so that with
  435.         *  one key stroke the user can copy the DEST image into the clipboard,
  436.         *  paste it down into the SRC hdc and cause the blt.
  437.         ******************************************************************/
  438.         case IDM_BOTH:
  439.           PostMessage (hwnd, WM_COMMAND, MAKELONG (IDM_COPY , 1), 0);
  440.           PostMessage (hwnd, WM_COMMAND, MAKELONG (IDM_PASTE, 1), 0);
  441.         break;
  442.         /******************************************************************
  443.         *  WM_COMMAND, IDM_MODE_*
  444.         *
  445.         * manage mutually exclusive menu.
  446.         *  call SetStretchBltMode() for the global destination hdc.
  447.         ******************************************************************/
  448.         case IDM_MODE_BLACKONWHITE:
  449.           { HMENU hMenu;
  450.           hMenu = GetMenu (hwnd);
  451.           CheckMenuItem(hMenu, IDM_MODE_BLACKONWHITE, MF_CHECKED);
  452.           CheckMenuItem(hMenu, IDM_MODE_COLORONCOLOR, MF_UNCHECKED);
  453.           CheckMenuItem(hMenu, IDM_MODE_WHITEONBLACK, MF_UNCHECKED);
  454.           CheckMenuItem(hMenu, IDM_MODE_HALFTONE    , MF_UNCHECKED);
  455.           SetStretchBltMode (hdcDest,BLACKONWHITE);
  456.           SendMessage (hwndMain, WM_PLGBLT, 0,0);
  457.           } return 0;
  458.         case IDM_MODE_COLORONCOLOR:
  459.           { HMENU hMenu;
  460.           hMenu = GetMenu (hwnd);
  461.           CheckMenuItem(hMenu, IDM_MODE_BLACKONWHITE, MF_UNCHECKED);
  462.           CheckMenuItem(hMenu, IDM_MODE_COLORONCOLOR, MF_CHECKED);
  463.           CheckMenuItem(hMenu, IDM_MODE_WHITEONBLACK, MF_UNCHECKED);
  464.           CheckMenuItem(hMenu, IDM_MODE_HALFTONE    , MF_UNCHECKED);
  465.           SetStretchBltMode (hdcDest,COLORONCOLOR);
  466.           SendMessage (hwndMain, WM_PLGBLT, 0,0);
  467.           } return 0;
  468.         case IDM_MODE_WHITEONBLACK:
  469.           { HMENU hMenu;
  470.           hMenu = GetMenu (hwnd);
  471.           CheckMenuItem(hMenu, IDM_MODE_BLACKONWHITE, MF_UNCHECKED);
  472.           CheckMenuItem(hMenu, IDM_MODE_COLORONCOLOR, MF_UNCHECKED);
  473.           CheckMenuItem(hMenu, IDM_MODE_WHITEONBLACK, MF_CHECKED);
  474.           CheckMenuItem(hMenu, IDM_MODE_HALFTONE    , MF_UNCHECKED);
  475.           SetStretchBltMode (hdcDest,WHITEONBLACK);
  476.           SendMessage (hwndMain, WM_PLGBLT, 0,0);
  477.           } return 0;
  478.         case IDM_MODE_HALFTONE    :
  479.           { HMENU hMenu;
  480.           hMenu = GetMenu (hwnd);
  481.           CheckMenuItem(hMenu, IDM_MODE_BLACKONWHITE, MF_UNCHECKED);
  482.           CheckMenuItem(hMenu, IDM_MODE_COLORONCOLOR, MF_UNCHECKED);
  483.           CheckMenuItem(hMenu, IDM_MODE_WHITEONBLACK, MF_UNCHECKED);
  484.           CheckMenuItem(hMenu, IDM_MODE_HALFTONE    , MF_CHECKED);
  485.           SetStretchBltMode (hdcDest,HALFTONE);
  486.           SendMessage (hwndMain, WM_PLGBLT, 0,0);
  487.           } return 0;
  488.         /******************************************************************
  489.         *  WM_COMMAND, IDM_SPIN*
  490.         *
  491.         * manage mutually exclusive menu.
  492.         *
  493.         ******************************************************************/
  494.         case IDM_SPINOFF:
  495.           { HMENU hMenu;
  496.           hMenu = GetMenu (hwnd);
  497.           CheckMenuItem(hMenu, IDM_SPINOFF, MF_CHECKED);
  498.           CheckMenuItem(hMenu, IDM_SPIN5  , MF_UNCHECKED);
  499.           CheckMenuItem(hMenu, IDM_SPIN10 , MF_UNCHECKED);
  500.           CheckMenuItem(hMenu, IDM_SPIN30 , MF_UNCHECKED);
  501.           CheckMenuItem(hMenu, IDM_SPIN60 , MF_UNCHECKED);
  502.           CheckMenuItem(hMenu, IDM_SPIN90 , MF_UNCHECKED);
  503.           nSpin = FALSE;
  504.           SendMessage (hwndMain, WM_PLGBLT, 0,0);
  505.           } return 0;
  506.         case IDM_SPIN5 :
  507.           { HMENU hMenu;
  508.           hMenu = GetMenu (hwnd);
  509.           CheckMenuItem(hMenu, IDM_SPINOFF, MF_UNCHECKED);
  510.           CheckMenuItem(hMenu, IDM_SPIN5  , MF_CHECKED);
  511.           CheckMenuItem(hMenu, IDM_SPIN10 , MF_UNCHECKED);
  512.           CheckMenuItem(hMenu, IDM_SPIN30 , MF_UNCHECKED);
  513.           CheckMenuItem(hMenu, IDM_SPIN60 , MF_UNCHECKED);
  514.           CheckMenuItem(hMenu, IDM_SPIN90 , MF_UNCHECKED);
  515.           nSpin = 5;
  516.           } return 0;
  517.         case IDM_SPIN10:
  518.           { HMENU hMenu;
  519.           hMenu = GetMenu (hwnd);
  520.           CheckMenuItem(hMenu, IDM_SPINOFF, MF_UNCHECKED);
  521.           CheckMenuItem(hMenu, IDM_SPIN5  , MF_UNCHECKED);
  522.           CheckMenuItem(hMenu, IDM_SPIN10 , MF_CHECKED);
  523.           CheckMenuItem(hMenu, IDM_SPIN30 , MF_UNCHECKED);
  524.           CheckMenuItem(hMenu, IDM_SPIN60 , MF_UNCHECKED);
  525.           CheckMenuItem(hMenu, IDM_SPIN90 , MF_UNCHECKED);
  526.           nSpin = 10;
  527.           } return 0;
  528.         case IDM_SPIN30:
  529.           { HMENU hMenu;
  530.           hMenu = GetMenu (hwnd);
  531.           CheckMenuItem(hMenu, IDM_SPINOFF, MF_UNCHECKED);
  532.           CheckMenuItem(hMenu, IDM_SPIN5  , MF_UNCHECKED);
  533.           CheckMenuItem(hMenu, IDM_SPIN10 , MF_UNCHECKED);
  534.           CheckMenuItem(hMenu, IDM_SPIN30 , MF_CHECKED);
  535.           CheckMenuItem(hMenu, IDM_SPIN60 , MF_UNCHECKED);
  536.           CheckMenuItem(hMenu, IDM_SPIN90 , MF_UNCHECKED);
  537.           nSpin = 30;
  538.           } return 0;
  539.         case IDM_SPIN60:
  540.           { HMENU hMenu;
  541.           hMenu = GetMenu (hwnd);
  542.           CheckMenuItem(hMenu, IDM_SPINOFF, MF_UNCHECKED);
  543.           CheckMenuItem(hMenu, IDM_SPIN5  , MF_UNCHECKED);
  544.           CheckMenuItem(hMenu, IDM_SPIN10 , MF_UNCHECKED);
  545.           CheckMenuItem(hMenu, IDM_SPIN30 , MF_UNCHECKED);
  546.           CheckMenuItem(hMenu, IDM_SPIN60 , MF_CHECKED);
  547.           CheckMenuItem(hMenu, IDM_SPIN90 , MF_UNCHECKED);
  548.           nSpin = 60;
  549.           } return 0;
  550.         case IDM_SPIN90:
  551.           { HMENU hMenu;
  552.           hMenu = GetMenu (hwnd);
  553.           CheckMenuItem(hMenu, IDM_SPINOFF, MF_UNCHECKED);
  554.           CheckMenuItem(hMenu, IDM_SPIN5  , MF_UNCHECKED);
  555.           CheckMenuItem(hMenu, IDM_SPIN10 , MF_UNCHECKED);
  556.           CheckMenuItem(hMenu, IDM_SPIN30 , MF_UNCHECKED);
  557.           CheckMenuItem(hMenu, IDM_SPIN60 , MF_UNCHECKED);
  558.           CheckMenuItem(hMenu, IDM_SPIN90 , MF_CHECKED);
  559.           nSpin = 90;
  560.           } return 0;
  561.         case IDM_FLIPONCE:
  562.           nSpin = 90;
  563.           SendMessage (hwndMain, WM_SPIN, 0,0);
  564.           nSpin = FALSE;
  565.           return 0;
  566.         case IDM_SPINTOPLEFT:
  567.           { HMENU hMenu;
  568.           hMenu = GetMenu (hwnd);
  569.           CheckMenuItem(hMenu, IDM_SPINTOPLEFT, MF_CHECKED);
  570.           CheckMenuItem(hMenu, IDM_SPINCENTER , MF_UNCHECKED);
  571.           } return 0;
  572.         case IDM_SPINCENTER:
  573.           { HMENU hMenu;
  574.           hMenu = GetMenu (hwnd);
  575.           CheckMenuItem(hMenu, IDM_SPINTOPLEFT, MF_UNCHECKED);
  576.           CheckMenuItem(hMenu, IDM_SPINCENTER , MF_CHECKED);
  577.           } return 0;
  578.         /******************************************************************
  579.         *  WM_COMMAND, DID_NEW*
  580.         *
  581.         * menu equivalents for buttons on top dialog.  Just pass along
  582.         *  WM_COMMAND messages to the dialog.
  583.         *
  584.         ******************************************************************/
  585.         case DID_NEWSRC:
  586.         case DID_NEWMASK:
  587.           SendMessage (hwndDlg, message, wParam, lParam);
  588.         return 0;
  589.         /******************************************************************
  590.         *  WM_COMMAND, IDM_ABOUT
  591.         *
  592.         ******************************************************************/
  593.         case IDM_ABOUT:
  594.           DialogBox (hInst, "aboutBox", hwnd, (DLGPROC)About);
  595.         return 0;
  596.       }  /* end switch */
  597.     break;  /* end wm_command */
  598.     /******************************************************************
  599.     *  WM_SPIN
  600.     *
  601.     * Set up a transform to modify the destination points.
  602.     *  (Note that the transform in hdcDest remains the identity.)
  603.     *  Loop through, reblitting to the transformed points.
  604.     *  Erase behind the old bitmap by keeping track of the region uncovered.
  605.     *
  606.     ******************************************************************/
  607.     case WM_SPIN: {
  608.       XFORM  x;
  609.       HDC hdc;
  610.       float M11, M12, M21, M22;
  611.       int nSteps, i;
  612.       POINT pivot;
  613.       POINT lpPoint[3];
  614.       POINT lpRgnErase[4], lpRgnBmp[4];
  615.       HRGN hrgnErase, hrgnBmp;
  616.       HMENU hMenu;
  617.       int XSrc, YSrc, nWidth, nHeight, XMask, YMask;
  618.       BOOL success;
  619.       /* validate the dialog on top with the parameters in it. */
  620.       if (!IsWindow(hwndDlg)) return 0;
  621.       /* Grab points out of the dialog entry fields. */
  622.       lpPoint[0].x = GetDlgItemInt(hwndDlg, DID_P1X, &success, TRUE);
  623.       lpPoint[0].y = GetDlgItemInt(hwndDlg, DID_P1Y, &success, TRUE);
  624.       lpPoint[1].x = GetDlgItemInt(hwndDlg, DID_P2X, &success, TRUE);
  625.       lpPoint[1].y = GetDlgItemInt(hwndDlg, DID_P2Y, &success, TRUE);
  626.       lpPoint[2].x = GetDlgItemInt(hwndDlg, DID_P3X, &success, TRUE);
  627.       lpPoint[2].y = GetDlgItemInt(hwndDlg, DID_P3Y, &success, TRUE);
  628.       XSrc = GetDlgItemInt(hwndDlg, DID_XSRC, &success, TRUE);
  629.       YSrc = GetDlgItemInt(hwndDlg, DID_YSRC, &success, TRUE);
  630.       nWidth = GetDlgItemInt(hwndDlg, DID_WIDTH, &success, TRUE);
  631.       nHeight = GetDlgItemInt(hwndDlg, DID_HEIGHT, &success, TRUE);
  632.       XMask = GetDlgItemInt(hwndDlg, DID_XMASK, &success, TRUE);
  633.       YMask = GetDlgItemInt(hwndDlg, DID_YMASK, &success, TRUE);
  634.       /* get an HDC we can use to play with transforms. */
  635.       hdc = GetDC (hwnd);
  636.       SetGraphicsMode (hdc, GM_ADVANCED);
  637.       /* check menu check to pivot on top-left corner, or pivot on center. */
  638.       hMenu = GetMenu (hwnd);
  639.       if (GetMenuState(hMenu, IDM_SPINCENTER, MF_BYCOMMAND) & MF_CHECKED) {
  640.         pivot.x = (lpPoint[1].x +lpPoint[2].x)/2;
  641.         pivot.y = (lpPoint[1].y +lpPoint[2].y)/2;
  642.       } else {
  643.         pivot.x = lpPoint[0].x;
  644.         pivot.y = lpPoint[0].y;
  645.       }
  646.       /* nSpin contains values reflecting the number of degrees per step.
  647.        *  fill in the number of steps required (360 / nSpin), and fill in
  648.        *  the precomputed transformation matrices.
  649.        */
  650.       switch (nSpin) {
  651.         case 5:
  652.           nSteps = 72;
  653.           M11 =                   M22 = (float)0.9961946980917;
  654.           M12 = (float)-0.08715574274766; M21 = (float)0.08715574274766;
  655.           break;
  656.         case 10:
  657.           nSteps = 36;
  658.           M11 =                   M22 = (float)0.984808;
  659.           M12 = (float)-0.173648; M21 = (float)0.173648;
  660.           break;
  661.         case 30:
  662.           nSteps = 12;
  663.           M11 =                   M22 = (float)0.866025;
  664.           M12 = (float)-0.5     ; M21 = (float)0.5;
  665.           break;
  666.         case 60:
  667.           nSteps = 6;
  668.           M11 =                   M22 = (float)0.5     ;
  669.           M12 = (float)-0.866025; M21 = (float)0.866025;
  670.           break;
  671.         case 90:
  672.           nSteps = 4;
  673.           M11 =                   M22 = (float)0.0;
  674.           M12 = (float)-1.0     ; M21 = (float)1.0;
  675.           break;
  676.         default:
  677.           MessageBox (hwnd,
  678.                       GetStringRes (IDS_INVALID),
  679.                       NULL, MB_ICONHAND);
  680.           return 0;
  681.       } /* end switch nSpin */
  682.       /* translate objects from pivot point to origin. */
  683.       x.eM11 = (float)1.0;
  684.       x.eM12 = (float)0.0;
  685.       x.eM21 = (float)0.0;
  686.       x.eM22 = (float)1.0;
  687.       x.eDx = (float)-pivot.x;
  688.       x.eDy = (float)-pivot.y;
  689.       ModifyWorldTransform (hdc, &x, MWT_RIGHTMULTIPLY);
  690.       /* rotate object about origin. */
  691.       x.eM11 = M11;
  692.       x.eM12 = M12;
  693.       x.eM21 = M21;
  694.       x.eM22 = M22;
  695.       x.eDx = (float)0.0;
  696.       x.eDy = (float)0.0;
  697.       ModifyWorldTransform (hdc, &x, MWT_RIGHTMULTIPLY);
  698.       /* translate objects back to pivot point. */
  699.       x.eM11 = (float)1.0;
  700.       x.eM12 = (float)0.0;
  701.       x.eM21 = (float)0.0;
  702.       x.eM22 = (float)1.0;
  703.       x.eDx = (float)pivot.x;
  704.       x.eDy = (float)pivot.y;
  705.       ModifyWorldTransform (hdc, &x, MWT_RIGHTMULTIPLY);
  706.       /* fill in initial region for erasure... the region containing bmp */
  707.       lpRgnErase[0] = lpPoint[0];
  708.       lpRgnErase[1] = lpPoint[1];
  709.       lpRgnErase[3] = lpPoint[2];
  710.       lpRgnErase[2].x =  lpPoint[1].x - lpPoint[0].x;
  711.       lpRgnErase[2].x += lpPoint[2].x - lpPoint[0].x;
  712.       lpRgnErase[2].x += lpPoint[0].x;
  713.       lpRgnErase[2].y =  lpPoint[1].y - lpPoint[0].y;
  714.       lpRgnErase[2].y += lpPoint[2].y - lpPoint[0].y;
  715.       lpRgnErase[2].y += lpPoint[0].y;
  716.       /* loop through transforming the points on each step. */
  717.       for (i= 0; i<nSteps; i++) {
  718.         hrgnErase = CreatePolygonRgn (lpRgnErase, 4, ALTERNATE);
  719.         /* TRANSFORM the lpPoint[] destination extent points */
  720.         LPtoDP (hdc, lpPoint, 3);
  721.         /* create a region containing the new bitmap extents */
  722.         lpRgnBmp[0] = lpPoint[0];
  723.         lpRgnBmp[1] = lpPoint[1];
  724.         lpRgnBmp[3] = lpPoint[2];
  725.         lpRgnBmp[2].x =  lpPoint[1].x - lpPoint[0].x;
  726.         lpRgnBmp[2].x += lpPoint[2].x - lpPoint[0].x;
  727.         lpRgnBmp[2].x += lpPoint[0].x;
  728.         lpRgnBmp[2].y =  lpPoint[1].y - lpPoint[0].y;
  729.         lpRgnBmp[2].y += lpPoint[2].y - lpPoint[0].y;
  730.         lpRgnBmp[2].y += lpPoint[0].y;
  731.         hrgnBmp = CreatePolygonRgn (lpRgnBmp, 4, ALTERNATE);
  732.         /* subtract the new bitmap extents region from the erasure region. */
  733.         CombineRgn (hrgnErase, hrgnErase, hrgnBmp, RGN_DIFF);
  734.         /* while we are here, get points ready for the next loop erasure */
  735.         lpRgnErase[0] = lpPoint[0];
  736.         lpRgnErase[1] = lpPoint[1];
  737.         lpRgnErase[3] = lpPoint[2];
  738.         lpRgnErase[2].x =  lpPoint[1].x - lpPoint[0].x;
  739.         lpRgnErase[2].x += lpPoint[2].x - lpPoint[0].x;
  740.         lpRgnErase[2].x += lpPoint[0].x;
  741.         lpRgnErase[2].y =  lpPoint[1].y - lpPoint[0].y;
  742.         lpRgnErase[2].y += lpPoint[2].y - lpPoint[0].y;
  743.         lpRgnErase[2].y += lpPoint[0].y;
  744.         /**********************************************************/
  745.         PlgBlt (hdcDest, lpPoint,
  746.                 hdcSrc, XSrc, YSrc, nWidth, nHeight,
  747.                 hbmMask, XMask, YMask);
  748.         /**********************************************************/
  749.         /* need to flush graphics buffer, or regions are erased
  750.          *  before the bitmap is drawn.
  751.          */
  752.         GdiFlush();
  753.         /* erase the newly uncovered region. */
  754.         FillRgn (hdcDest, hrgnErase, BACKGROUNDBRUSH );
  755.         DeleteObject (hrgnErase);
  756.         DeleteObject (hrgnBmp);
  757.       } /* end for loop */
  758.       /* because of roundoff error, the 'nSteps'th rotation will not
  759.        *  always bring the parallelogram around to the 0th position.
  760.        *  So we special case the last position, and do one more erase.
  761.        *  Try commenting this out, and see the little glitches left
  762.        *  on the screen if this comment is unclear.
  763.        */
  764.       lpRgnErase[0] = lpPoint[0];
  765.       lpRgnErase[1] = lpPoint[1];
  766.       lpRgnErase[3] = lpPoint[2];
  767.       lpRgnErase[2].x =  lpPoint[1].x - lpPoint[0].x;
  768.       lpRgnErase[2].x += lpPoint[2].x - lpPoint[0].x;
  769.       lpRgnErase[2].x += lpPoint[0].x;
  770.       lpRgnErase[2].y =  lpPoint[1].y - lpPoint[0].y;
  771.       lpRgnErase[2].y += lpPoint[2].y - lpPoint[0].y;
  772.       lpRgnErase[2].y += lpPoint[0].y;
  773.       hrgnErase = CreatePolygonRgn (lpRgnErase, 4, ALTERNATE);
  774.       lpPoint[0].x = GetDlgItemInt(hwndDlg, DID_P1X, &success, TRUE);
  775.       lpPoint[0].y = GetDlgItemInt(hwndDlg, DID_P1Y, &success, TRUE);
  776.       lpPoint[1].x = GetDlgItemInt(hwndDlg, DID_P2X, &success, TRUE);
  777.       lpPoint[1].y = GetDlgItemInt(hwndDlg, DID_P2Y, &success, TRUE);
  778.       lpPoint[2].x = GetDlgItemInt(hwndDlg, DID_P3X, &success, TRUE);
  779.       lpPoint[2].y = GetDlgItemInt(hwndDlg, DID_P3Y, &success, TRUE);
  780.       lpRgnBmp[0] = lpPoint[0];
  781.       lpRgnBmp[1] = lpPoint[1];
  782.       lpRgnBmp[3] = lpPoint[2];
  783.       lpRgnBmp[2].x =  lpPoint[1].x - lpPoint[0].x;
  784.       lpRgnBmp[2].x += lpPoint[2].x - lpPoint[0].x;
  785.       lpRgnBmp[2].x += lpPoint[0].x;
  786.       lpRgnBmp[2].y =  lpPoint[1].y - lpPoint[0].y;
  787.       lpRgnBmp[2].y += lpPoint[2].y - lpPoint[0].y;
  788.       lpRgnBmp[2].y += lpPoint[0].y;
  789.       hrgnBmp = CreatePolygonRgn (lpRgnBmp, 4, ALTERNATE);
  790.       CombineRgn (hrgnErase, hrgnErase, hrgnBmp, RGN_DIFF);
  791.       FillRgn (hdcDest, hrgnErase, BACKGROUNDBRUSH );
  792.       DeleteObject (hrgnErase);
  793.       DeleteObject (hrgnBmp);
  794.       ReleaseDC (hwnd, hdc);
  795.     } return 0; /* end WM_SPIN message */
  796.   } /* end switch */
  797.   return (DefWindowProc(hwnd, message, wParam, lParam));
  798. }
  799. /**************************************************************************
  800. *
  801. *  function:  DlgProc()
  802. *
  803. *  input parameters:  normal window procedure parameters.
  804. *
  805. *  Respond to user button presses by getting new bitmaps or by sending
  806. *   the main window a WM_PLGBLT message.  Also handle special user messages
  807. *   for updating the entry fields with the contents of the direct manipulation
  808. *   objects.
  809. *
  810. *  global variables:
  811. *   hwndMain - the main window.  also the parent of this dialog
  812. *   ptoDest, ptoSrc, ptoMask - pointers to the direct manipulation objects
  813. *   hdcDest, hdcSrc, hdcMask - HDCs for the 3 sub regions of the window.
  814. *   hbmSrc, hbmMask          - bitmap handles for source and mask.
  815. **************************************************************************/
  816. LRESULT CALLBACK DlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  817. {
  818.   switch (message) {
  819.     /**********************************************************************
  820.     *  WM_INITDIALOG
  821.     *
  822.     * Fill the entry fields with sensible original values.
  823.     **********************************************************************/
  824.     case WM_INITDIALOG:
  825.         SetDlgItemText(hwnd, DID_P1X     , "0");
  826.         SetDlgItemText(hwnd, DID_P1Y     , "0");
  827.         SetDlgItemText(hwnd, DID_P2X     , "0");
  828.         SetDlgItemText(hwnd, DID_P2Y     , "0");
  829.         SetDlgItemText(hwnd, DID_P3X     , "0");
  830.         SetDlgItemText(hwnd, DID_P3Y     , "0");
  831.         SetDlgItemText(hwnd, DID_XSRC    , "0");
  832.         SetDlgItemText(hwnd, DID_YSRC    , "0");
  833.         SetDlgItemText(hwnd, DID_WIDTH   , "0");
  834.         SetDlgItemText(hwnd, DID_HEIGHT  , "0");
  835.         SetDlgItemText(hwnd, DID_XMASK   , "0");
  836.         SetDlgItemText(hwnd, DID_YMASK   , "0");
  837.     return TRUE;
  838.     /**********************************************************************
  839.     *  WM_PUTUPLPOINTS
  840.     *
  841.     * wParam -  HDC with the needed world transform.
  842.     * lParam -  Pointer to the track object.
  843.     *
  844.     * Fill the entry fields for the array of 3 dest parallelogram points.
  845.     *  Conditionally change the first point depending on tracking mode.
  846.     **********************************************************************/
  847.     case WM_PUTUPLPOINTS: {
  848.         POINT p, origin;
  849.         PTrackObject pto;
  850.         HDC hdc;
  851.         hdc = (HDC) wParam;
  852.         pto = (PTrackObject) lParam;
  853.         GetViewportOrgEx (hdc, &origin);
  854.         if (pto->Mode & TMMOVE) {
  855.           p.x = pto->rect.left;
  856.           p.y = pto->rect.top;
  857.           LPtoDP (pto->hdc, &p, 1);
  858.           p.x -= origin.x; p.y -= origin.y;
  859.           SetDlgItemInt(hwnd, DID_P1X, p.x, TRUE);
  860.           SetDlgItemInt(hwnd, DID_P1Y, p.y, TRUE);
  861.         }
  862.         p.x = pto->rect.right;
  863.         p.y = pto->rect.top;
  864.         LPtoDP (pto->hdc, &p, 1);
  865.         p.x -= origin.x; p.y -= origin.y;
  866.         SetDlgItemInt(hwnd, DID_P2X, p.x, TRUE);
  867.         SetDlgItemInt(hwnd, DID_P2Y, p.y, TRUE);
  868.         p.x = pto->rect.left;
  869.         p.y = pto->rect.bottom;
  870.         LPtoDP (pto->hdc, &p, 1);
  871.         p.x -= origin.x; p.y -= origin.y;
  872.         SetDlgItemInt(hwnd, DID_P3X, p.x, TRUE);
  873.         SetDlgItemInt(hwnd, DID_P3Y, p.y, TRUE);
  874.     } return FALSE;
  875.     /**********************************************************************
  876.     *  WM_PUTUPSRCRECT
  877.     *
  878.     * wParam -  HDC with the needed world transform.
  879.     * lParam -  Pointer to the track object.
  880.     *
  881.     * Fill the entry fields for the source rectangle points.
  882.     *  Conditionally change <x,y> or <width,height> depending on tracking mode.
  883.     **********************************************************************/
  884.     case WM_PUTUPSRCRECT: {
  885.         POINT p1,p2, origin;
  886.         PTrackObject pto;
  887.         HDC hdc;
  888.         hdc = (HDC) wParam;
  889.         pto = (PTrackObject) lParam;
  890.         GetViewportOrgEx (hdc, &origin);
  891.         p1.x = pto->rect.left;
  892.         p1.y = pto->rect.top;
  893.         LPtoDP (pto->hdc, &p1, 1);
  894.         p2.x = pto->rect.right;
  895.         p2.y = pto->rect.bottom;
  896.         LPtoDP (pto->hdc, &p2, 1);
  897.         p2.x -= p1.x; p2.y -= p1.y;
  898.         p1.x -= origin.x; p1.y -= origin.y;
  899.         if (!(pto->Mode & TMSIZEXY)) {
  900.           SetDlgItemInt(hwnd, DID_XSRC, p1.x, TRUE);
  901.           SetDlgItemInt(hwnd, DID_YSRC, p1.y, TRUE);
  902.         }
  903.         if (!(pto->Mode & TMMOVE)) {
  904.           SetDlgItemInt(hwnd, DID_WIDTH,  p2.x, TRUE);
  905.           SetDlgItemInt(hwnd, DID_HEIGHT, p2.y, TRUE);
  906.         }
  907.     } return FALSE;
  908.     /**********************************************************************
  909.     *  WM_PUTUPMASKPT
  910.     *
  911.     * wParam -  HDC with the needed world transform.
  912.     * lParam -  Pointer to the track object.
  913.     *
  914.     * Fill the entry fields for the mask location point.
  915.     **********************************************************************/
  916.     case WM_PUTUPMASKPT: {
  917.         POINT p1, origin;
  918.         PTrackObject pto;
  919.         HDC hdc;
  920.         hdc = (HDC) wParam;
  921.         pto = (PTrackObject) lParam;
  922.         GetViewportOrgEx (hdc, &origin);
  923.         p1.x = pto->rect.left;
  924.         p1.y = pto->rect.top;
  925.         LPtoDP (pto->hdc, &p1, 1);
  926.         p1.x -= origin.x; p1.y -= origin.y;
  927.         SetDlgItemInt(hwnd, DID_XMASK, p1.x, TRUE);
  928.         SetDlgItemInt(hwnd, DID_YMASK, p1.y, TRUE);
  929.     } return FALSE;
  930.     /**********************************************************************
  931.     *  WM_COMMAND, DID_DRAW
  932.     *
  933.     * Draw button hit - send main window message to call PlgBlt().
  934.     **********************************************************************/
  935.     case WM_COMMAND: {
  936.       HBITMAP hbm;
  937.       if (LOWORD(wParam) == DID_DRAW) {
  938.           SendMessage (hwndMain, WM_PLGBLT, 0,0);
  939.     /**********************************************************************
  940.     *  WM_COMMAND, DID_NEWSRC
  941.     *
  942.     * Try to get a new source bitmap.  Then
  943.     *  invalidate two sub windows so that we force a repaint.
  944.     **********************************************************************/
  945.       } else if (LOWORD(wParam) == DID_NEWSRC) {
  946.         if ( hbm = GetBitmap (hdcSrc, hInst, FALSE)) {
  947.           DeleteObject (hbmSrc);
  948.           hbmSrc = hbm;
  949.           InvalidateRect (hwndMain, &ptoSrc->rectClip, TRUE);
  950.           InvalidateRect (hwndMain, &ptoDest->rectClip, TRUE);
  951.         }
  952.     /**********************************************************************
  953.     *  WM_COMMAND, DID_Mask
  954.     *
  955.     * Try to get a new mask bitmap.  Then
  956.     *  invalidate two sub windows so that we force a repaint.
  957.     **********************************************************************/
  958.       } else if (LOWORD(wParam) == DID_NEWMASK) {
  959.         if ( hbm = GetBitmap (hdcMask,  hInst, TRUE)) {
  960.           DeleteObject (hbmMask);
  961.           hbmMask = hbm;
  962.           InvalidateRect (hwndMain, &ptoMask->rectClip, TRUE);
  963.           InvalidateRect (hwndMain, &ptoDest->rectClip, TRUE);
  964.         }
  965.       }
  966.     } return FALSE; /* end WM_COMMAND */
  967.   } /* end switch */
  968.   return 0;
  969. }
  970. #define TICKSPACE     20
  971. /**************************************************************************
  972. *
  973. *  function:  DrawGrids()
  974. *
  975. *  input parameters:
  976. *   hdc - Device context to draw into.
  977. *   width, height - size of the rectangle to fill with grids.
  978. *
  979. *  global variables:  none.
  980. *
  981. **************************************************************************/
  982. VOID DrawGrids (HDC hdc, int width, int height)
  983. {
  984. int i;
  985.     /* Draw vertical lines. Double at the axis */
  986.     for (i = 0; i<= width; i+=TICKSPACE){
  987.       MoveToEx (hdc, i, 0, NULL);
  988.       LineTo (hdc, i, height);
  989.     }
  990.     MoveToEx (hdc, 1, 0, NULL);
  991.     LineTo (hdc, 1, height);
  992.     /* Draw horizontal lines. Double at the axis */
  993.     for (i = 0; i<= height; i+=TICKSPACE){
  994.       MoveToEx (hdc, 0,i, NULL);
  995.       LineTo (hdc, width,i);
  996.     }
  997.     MoveToEx (hdc, 0, 1, NULL);
  998.     LineTo (hdc, width,1);
  999.   return;
  1000. }
  1001. /****************************************************************************
  1002.     FUNCTION: About
  1003. ****************************************************************************/
  1004. LRESULT CALLBACK About(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  1005. {
  1006.   if ((message == WM_COMMAND) && (LOWORD(wParam) == IDOK)) {
  1007.     EndDialog (hwnd, TRUE);
  1008.     return TRUE;
  1009.   }
  1010.   if ((message == WM_SYSCOMMAND) && (wParam == SC_CLOSE)) {
  1011.     EndDialog (hwnd, TRUE);
  1012.     return TRUE;
  1013.   }
  1014.   return FALSE;
  1015. }
  1016. /******************************************************************************
  1017. *
  1018. *  FUNCTION:    GetStringRes (int id INPUT ONLY)
  1019. *
  1020. *  COMMENTS:    Load the resource string with the ID given, and return a
  1021. *               pointer to it.  Notice that the buffer is common memory so
  1022. *               the string must be used before this call is made a second time.
  1023. *
  1024. ******************************************************************************/
  1025. LPTSTR   GetStringRes (int id)
  1026. {
  1027.   static TCHAR buffer[MAX_PATH];
  1028.   buffer[0]=0;
  1029.   LoadString (GetModuleHandle (NULL), id, buffer, MAX_PATH);
  1030.   return buffer;
  1031. }