File:  [WindowsNT SDKs] / q_a / samples / regions / regions.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs
Thu Aug 9 18:29:57 2018 UTC (7 years, 9 months ago) by root
Branches: msft, MAIN
CVS tags: ntsdk-nov-1993, ntsdk-jul-1993, HEAD
Microsoft Windows NT Build 511 (SDK Final Release) 07-24-1993


/******************************************************************************\
*       This is a part of the Microsoft Source Code Samples. 
*       Copyright (C) 1993 Microsoft Corporation.
*       All rights reserved. 
*       This source code is only intended as a supplement to 
*       Microsoft Development Tools and/or WinHelp documentation.
*       See these sources for detailed information regarding the 
*       Microsoft samples programs.
\******************************************************************************/

/******************************************************************************\
*
*  PROGRAM:     Regions.c
*
*  PURPOSE:     To demonstrate the region APIs in Win32, namely:
*
*                          CombineRgn()
*                          CreateEllipticRgn()
*                          CreateEllipticRgnIndirect()
*                          CreatePolygonRgn()
*                          CreatePolyPolygonRgn()
*                          CreateRectRgn()
*                          FillRgn()
*                          FrameRgn()
*                          GetRgnBox()
*                          InvertRgn()
*                          OffsetRgn()
*                          PaintRgn()
*                          PtInRegion()
*                          RectInRegion()
*                          SetRectRgn()
*
*               The EqualRgn() API is *not* called in this program.
*
*  FUNCTIONS:
*               WinMain()       - initialization, create window, msg loop
*               MainWndProc()   - processes main window msgs
*               AboutDlgProc()  - processes About dialog box msgs
*               RgnBoxDlgProc() - processes RgnBox dialog box msgs
*               MyCreateRgn()   - calls any one of Create*Rgn*() APIs
*               MyCombineRgn()  - calls CombineRgn() API
*               TrackRect()     - creates\draws\deletes a tracking rectangle
*                                 (for use with RectInRegion menu item.)
*               Reset()         - enables\disables menu items, modifies
*                                 global vars (rgnArray[], currRgn).
*
*  COMMENTS:    This program allows a user to create the different kinds
*               of regions available in Win32, and to perform the various
*               operations on them. All operations are immediately
*               reflected on the screen. The order in which the regions
*               are created determines the order in which they are drawn,
*               as well as which operation affects which region(s); for
*               example, the last region created will be drawn on top of
*               the others, and the operations in "Options" menu will
*               affect this region. When two regions are combined the
*               second region will be destroyed.
*
\******************************************************************************/

#include <windows.h>
#include "regions.h"



/******************************************************************************\
*
*  FUNCTION:    WinMain (standard WinMain INPUTS/RETURNS)
*
*  GLOBAL VARS: hInst - Handle of program instance
*
\******************************************************************************/

int WINAPI WinMain (HANDLE hInstance, HANDLE hPrevInstance,
                    LPSTR lpCmdLine, int nCmdShow)
{ HWND hwnd;
  MSG  msg;

  if (!hPrevInstance)
  {
    WNDCLASS wc;

    wc.style         = 0;
    wc.lpfnWndProc   = (WNDPROC)MainWndProc;
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.hInstance     = hInstance;
    wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor       = LoadCursor (NULL, IDC_ARROW);
    wc.hbrBackground = GetStockObject (DKGRAY_BRUSH);
    wc.lpszMenuName  = (LPCTSTR) "Menu";
    wc.lpszClassName = (LPCTSTR) "Main";

    if (!RegisterClass (&wc))
    {
      MessageBox (NULL, (LPCTSTR) "RegisterClass() failed",
                  (LPCTSTR) "Err! - REGIONS", MB_OK | MB_ICONEXCLAMATION);
      return(FALSE);
    }
  }
  hInst = hInstance;
  if (!(hwnd  = CreateWindow ("Main", "Regions API Sample",
                              WS_OVERLAPPED | WS_CAPTION |
                              WS_SYSMENU | WS_MINIMIZEBOX,
                              CW_USEDEFAULT, CW_USEDEFAULT,
                              220, 280, NULL, NULL, hInstance, NULL)))
    return (0);

  ShowWindow   (hwnd, nCmdShow);

  while (GetMessage (&msg, NULL, 0,0))
  {
    TranslateMessage (&msg);
    DispatchMessage  (&msg);
  }

  return (msg.wParam);
}



/******************************************************************************\
*
*  FUNCTION:    MainWndProc (standard window procedure INPUTS/RETURNS)
*
*  GLOBAL VARS: hInst    - Handle of program instance
*               rgnArray - Array of RGNSTRUCTs describing regions user has
*                          created
*               currRgn  - Index (in rgnArray) of most recently created
*                          region. If -1 then no regions created. Otherwise,
*                          values range from 0 to MAXRGNSTRUCTS - 1.
*               hMenu    - Handle of main window's menu.
*
*  LOCAL VARS:  rect     - Scratch rectangle used in various places.
*               ptr      - Pointer to a TRACKRECTSTRUCT (used for
*                          tracking rectangle).
*               i        - For-loop variable.
*               hdc      - Scratch HDC used in various places.
*               lButtonFlag - Tells what to do when left mouse button goes
*                             down (eg. nothing, check point in region,
*                             check rect in region).
*               bOffsetRgnFlag - A BOOL which tells whether to offset up
*                                and left or down and right.
*
\******************************************************************************/

LRESULT CALLBACK MainWndProc (HWND hWnd, UINT message, WPARAM wParam,
                              LPARAM lParam)
{
  static RECT             rect;
  static PTRACKRECTSTRUCT ptr;
  static BOOL             bOffsetRgnFlag = FALSE;
  static WORD             lButtonFlag = 0;
         int              i;
         HDC              hdc;

  switch (message)
  {
    case WM_CREATE:

      hMenu   = GetMenu (hWnd);
      currRgn = -1;
      Reset (RESET_ALL);
      break;

    case WM_COMMAND:

      switch (LOWORD(wParam))
      {
        case IDM_ERASE:
          Reset (RESET_ALL);
          InvalidateRect (hWnd, NULL, TRUE);
          break;

        case IDM_OFFSETRGN:

          //
          // Offset rgnArray[currRgn].hrgn either down & right, or up &
          //   left (depending on bOffsetRgnFlag). Toggle bOffsetRgnFlag.
          //

          if (bOffsetRgnFlag)

            OffsetRgn (rgnArray[currRgn].hrgn, 15, 10);

          else

            OffsetRgn (rgnArray[currRgn].hrgn, -15, -10);

          bOffsetRgnFlag = ~bOffsetRgnFlag;
          InvalidateRect (hWnd, NULL, TRUE);
          break;

        case IDM_INVERTRGN:

          hdc = GetDC (hWnd);
          InvertRgn (hdc, rgnArray[currRgn].hrgn);
          ReleaseDC (hWnd, hdc);
          break;

        case IDM_FRAMERGN:

          hdc = GetDC (hWnd);

          FrameRgn (hdc, rgnArray[currRgn].hrgn,
                    GetStockObject (LTGRAY_BRUSH), 2, 2);
          ReleaseDC (hWnd, hdc);
          break;

        case IDM_PTINRGN:

          //
          // Uncheck "RectInRgn" menu item, toggle "PtInRgn" menu item,
          //   toggle lButtonFlag
          //

          if (lButtonFlag == IDM_RECTINRGN)
            CheckMenuItem (GetSubMenu (hMenu, 0), IDM_RECTINRGN,
                            MF_UNCHECKED | MF_BYCOMMAND);
          if (lButtonFlag == IDM_PTINRGN)
          {
            CheckMenuItem (GetSubMenu (hMenu, 0), IDM_PTINRGN,
                            MF_UNCHECKED | MF_BYCOMMAND);
            lButtonFlag = 0;
          }
          else
          {
            CheckMenuItem (GetSubMenu (hMenu, 0), IDM_PTINRGN,
                            MF_CHECKED | MF_BYCOMMAND);
            lButtonFlag = IDM_PTINRGN;
          }
          break;

        case IDM_RECTINRGN:

          //
          // Uncheck "PtInRgn" menu item, toggle "RectInRgn" menu item,
          //   toggle lButtonFlag
          //

          if (lButtonFlag == IDM_PTINRGN)

            CheckMenuItem (GetSubMenu (hMenu, 0), IDM_PTINRGN,
                            MF_UNCHECKED | MF_BYCOMMAND);

          if (lButtonFlag == IDM_RECTINRGN)
          {
            CheckMenuItem (GetSubMenu (hMenu, 0), IDM_RECTINRGN,
                            MF_UNCHECKED | MF_BYCOMMAND);
            lButtonFlag = 0;
          }
          else
          {
            CheckMenuItem (GetSubMenu (hMenu, 0), IDM_RECTINRGN,
                            MF_CHECKED | MF_BYCOMMAND);
            lButtonFlag = IDM_RECTINRGN;
          }
          break;

        case IDM_SETRECTRGN:

          //
          // Reset rgnArray[currRgn].hrgn to be the rectangle which
          //   currently bounds it.
          //

          GetRgnBox  (rgnArray[currRgn].hrgn, &rect);
          SetRectRgn (rgnArray[currRgn].hrgn, (int) rect.left,
                      (int) rect.top, (int) rect.right,
                      (int) rect.bottom);
          InvalidateRect (hWnd, NULL, TRUE);
          break;

        case IDM_GETRGNBOX: // put up dlg which call GetRgnBox

          DialogBox (hInst, (LPCTSTR) "RgnBox", hWnd, (DLGPROC)RgnBoxDlgProc);
          break;

        case IDM_ELLIPSE: // create an elliptic region

          MyCreateRgn (ELLIPTIC_RGN);
          InvalidateRect (hWnd, NULL, TRUE);
          break;

        case IDM_POLYPOLYGON: // create a polyPolygon region

          MyCreateRgn (POLYPOLYGON_RGN);
          InvalidateRect (hWnd, NULL, TRUE);
          break;

        case IDM_RECT: // create a rectangular rgn

          MyCreateRgn (RECT_RGN);
          InvalidateRect (hWnd, NULL, TRUE);
          break;

        case IDM_AND:  // combine previous 2 rgns

          MyCombineRgn (RGN_AND);
          InvalidateRect (hWnd, NULL, TRUE);
          break;

        case IDM_COPY: // combine previous 2 rgns

          MyCombineRgn (RGN_COPY);
          InvalidateRect (hWnd, NULL, TRUE);
          break;

        case IDM_DIFF: // combine previous 2 rgns

          MyCombineRgn (RGN_DIFF);
          InvalidateRect (hWnd, NULL, TRUE);
          break;

        case IDM_OR: // combine previous 2 rgns

          MyCombineRgn (RGN_OR);
          InvalidateRect (hWnd, NULL, TRUE);
          break;

        case IDM_XOR: // combine previous 2 rgns

          MyCombineRgn (RGN_XOR);
          InvalidateRect (hWnd, NULL, TRUE);
          break;

        case IDM_ABOUT:  // put up About dialog box

          DialogBox (hInst, (LPCTSTR) "About", hWnd, (DLGPROC)AboutDlgProc);
          break;
      }
      return (0);

    case WM_LBUTTONDOWN:
    {
      //
      // if the "PtInRgn" menu item is checked, then see if the point at
      //   which this event happened is within currRgn, MessageBeep if so.
      //
      // else if the "RectInRgn" menu items are checked, then start
      //   tracking rectangle mode
      //

      if (lButtonFlag == IDM_PTINRGN)
      {
        if (currRgn > -1)

          if (PtInRegion (rgnArray[currRgn].hrgn, (int) LOWORD(lParam),
                          (int) HIWORD(lParam)))
            MessageBeep (0);
      }
      else if (lButtonFlag == IDM_RECTINRGN)

        if ((ptr = TrackRect (NULL, TRECT_NEW, hWnd, lParam)) == NULL)

        //
        // If TrackRect failed to LocalAlloc, then disable the
        //   IDM_RECTINRGN opion.
        //

          EnableMenuItem (GetSubMenu (hMenu, 0), IDM_RECTINRGN,
                          MF_DISABLED | MF_GRAYED | MF_BYCOMMAND);

      return (0);
    }
    case WM_MOUSEMOVE:

      //
      // if in tracking rectangle mode call TrackRect
      //

      if (lButtonFlag == IDM_RECTINRGN && GetCapture () == hWnd)

        TrackRect (ptr, TRECT_PAINT, hWnd, lParam);

      return (0);

    case WM_LBUTTONUP:

      //
      // if in tracking rectangle mode call TrackRect, check out the final
      //   rectangle, and see if it intersects currRgn
      //

      if (lButtonFlag == IDM_RECTINRGN && GetCapture () == hWnd)
      {
        //
        // call TrackRect with TRECT_PAINT so it updates the rectangle
        //   for the last time, then again with TRECT_DELETE so it frees
        //   up the TRACKRECTSTRUCT it allocated
        //

        TrackRect (ptr, TRECT_PAINT, hWnd, lParam);
        rect = ptr->trackRect;
        TrackRect (ptr, TRECT_DELETE, hWnd, lParam);
        if (RectInRegion (rgnArray[currRgn].hrgn, &rect))

          MessageBeep (0);
      }
      return (0);

    case WM_PAINT:
    {
      PAINTSTRUCT ps;
      COLORREF    crColor;
      HBRUSH      hBrush;

      hdc = BeginPaint (hWnd, &ps);

      //
      // For each rgn we created determine appropriate color & draw it
      //

      for (i = 0; i <= currRgn; i++)
      {
        if (rgnArray[i].hrgn != NULL)
        {
          crColor = 0x000000;
          if (rgnArray[i].type & ELLIPTIC_RGN)    // add some red

            crColor |= 0x0000ff;

          if (rgnArray[i].type & POLYPOLYGON_RGN) // add some green

            crColor |= 0x00ff00;

          if (rgnArray[i].type & RECT_RGN)        // add some blue

            crColor |= 0xff0000;

          hBrush = CreateSolidBrush (crColor);

          //
          // Alternately, the following would work:
          //    SelectObject (hdc, hBrush);
          //    FillRgn (hdc, rgnArray[i].hrgn);
          //

          FillRgn (hdc, rgnArray[i].hrgn, hBrush);
          DeleteObject (hBrush);
        }
      }
      EndPaint (hWnd, &ps);
      return (0);
    }
    case WM_DESTROY:

      PostQuitMessage(0);
      return (0);
  }
  return (DefWindowProc(hWnd, message, wParam, lParam));
}



/******************************************************************************\
*
*  FUNCTION:    AboutDlgProc (standard dialog procedure INPUTS/RETURNS)
*
*  COMMENTS:    Displays "about" message
*
\******************************************************************************/

LRESULT CALLBACK AboutDlgProc (HWND hwnd, UINT message, WPARAM wParam,
                               LPARAM lParam)
{ switch (message)
  {
    case WM_COMMAND:

      if (LOWORD(wParam) == IDOK)
      {
        EndDialog(hwnd, TRUE);
        return (TRUE);
      }
      return (TRUE);
  }
  return (FALSE);
}



/******************************************************************************\
*
*  FUNCTION:    RgnBoxDlgProc (standard dialog procedure INPUTS/RETURNS)
*
*  GLOBAL VARS: rgnArray - Array of RGNSTRUCTs describing regions user has
*                          created
*               currRgn  - Index (in rgnArray) of most recently created
*                          region. If -1 then no regions created. Other-
*                          wise, values range from 0 to MAXRGNSTRUCTS - 1.
*
*  COMMENTS:    Displays bounding rectangle of most recently created
*               region.
*
\******************************************************************************/

LRESULT CALLBACK RgnBoxDlgProc (HWND hwnd, UINT message, WPARAM wParam,
                                LPARAM lParam)
{
  switch (message)
  {
    case WM_INITDIALOG:
    {
      RECT rect;
      char buf[15];

      //
      // get the bounding rect of currRgn, fill in the dlg controls
      //   with text string describing the bounding rect.
      //

      if (GetRgnBox (rgnArray[currRgn].hrgn, &rect) == SIMPLEREGION)

        SetDlgItemText (hwnd, 102, "SIMPLEREGION");

      else

        SetDlgItemText (hwnd, 102, "COMPLEXREGION");

      wsprintf (buf, "%ld", rect.left);
      SetDlgItemText (hwnd, 107, buf);
      wsprintf (buf, "%ld", rect.top);
      SetDlgItemText (hwnd, 108, buf);
      wsprintf (buf, "%ld", rect.right);
      SetDlgItemText (hwnd, 109, buf);
      wsprintf (buf, "%ld", rect.bottom);
      SetDlgItemText (hwnd, 110, buf);

      return (TRUE);
    }

    case WM_COMMAND:

      if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
      {
        EndDialog(hwnd, TRUE);
        return (TRUE);
      }
      return (TRUE);
  }
  return (FALSE);
}



/******************************************************************************\
*
*  FUNCTION:    MyCreateRgn
*
*  INPUTS:      rgnStyle - The type of region to create (ELLIPTIC_RGN,
*                          POLYPOLYGON_RGN, RECT_RGN)
*
*  GLOBAL VARS: rgnArray          - Array of RGNSTRUCTs describing regions
*                                   user has created.
*               currRgn           - Index (in rgnArray) of most recently
*                                   created region. If -1 then no regions
*                                   created. Otherwise, values range from
*                                   0 to MAXRGNSTRUCTS-1.
*               hMenu             - Handle of main window's menu.
*               ellipseRect       - Rectangle bounding elliptical region.
*               polyPolygonPoints - The points for the polyPolygon region.
*               polyPolygonCounts - The count of points for each polygon
*                                   in the polyPolygon region.
*               rectRect          - The points for the rectangular region.
*
*  COMMENTS:    Creates a region (based on rgnStyle), increments currRgn,
*               and fills in rgnArray[currRgn].
*
\******************************************************************************/

void MyCreateRgn (WORD rgnStyle)
{
  if (++currRgn == 0)         // if this is 1st region enable options menu

    Reset (ENABLE_OPTIONS);

  else if (currRgn == 1)      // if this is 2nd region enable combine menu

    Reset (ENABLE_COMBINERGN);

  rgnArray[currRgn].type = rgnStyle;

  switch (rgnStyle)
  {
    case ELLIPTIC_RGN:

      //
      //  The following will also work here:
      //     CreateEllipticRgn ((int) ellipseRect.left,
      //                        (int) ellipseRect.top,
      //                        (int) ellipseRect.right,
      //                        (int) ellipseRect.bottom);
      //

      rgnArray[currRgn].hrgn = CreateEllipticRgnIndirect (&ellipseRect);

      EnableMenuItem (GetSubMenu (hMenu, 1), IDM_ELLIPSE,
                      MF_GRAYED | MF_DISABLED | MF_BYCOMMAND);
      break;

    case POLYPOLYGON_RGN:

      //
      // Alternately, several calls to CreatePolygonRgn could be made.
      //

      rgnArray[currRgn].hrgn = CreatePolyPolygonRgn (polyPolygonPoints,
                                                     polyPolygonCounts,
                                                     POLYPOLYGONCOUNT,
                                                     WINDING);
      EnableMenuItem (GetSubMenu (hMenu, 1), IDM_POLYPOLYGON,
                      MF_GRAYED | MF_DISABLED | MF_BYCOMMAND);
      break;

    case RECT_RGN:

      //
      // Alternately, a call to CreatePolygonRgn could be made.
      //

      rgnArray[currRgn].hrgn = CreateRectRgn (rectRect.left,
                                              rectRect.top,
                                              rectRect.right,
                                              rectRect.bottom);

      EnableMenuItem (GetSubMenu (hMenu, 1), IDM_RECT,
                      MF_GRAYED | MF_DISABLED | MF_BYCOMMAND);
      break;
  }
}



/******************************************************************************\
*
*  FUNCTION:    MyCombineRgn
*
*  INPUTS:      fnCombineMode- Operation to perform on the two regions
*                              (RGN_AND, RGN_COPY, RGN_DIFF, RGN_OR,
*                              RGN_XOR)
*
*  GLOBAL VARS: rgnArray- Array of RGNSTRUCTs describing regions user has
*                         created
*               currRgn - Index (in rgnArray) of most recently created
*                         region. If -1 then no regions created. Otherwise,
*                         values range from 0 to MAXRGNSTRUCTS - 1.
*
*  COMMENTS:    Combines the two regions rgnArray[currRgn-1] and
*               rgnArray[currRgn] using fnCombineMode, placing the
*               results in rgnArray[currRgn-1]. Destroys rgnArray[currRgn]
*               and decrements currRgn.
*
\******************************************************************************/

void MyCombineRgn (int fnCombineMode)
{
  if (currRgn >= 1) // only if two or more regions have been created
  {
    CombineRgn (rgnArray[currRgn-1].hrgn, rgnArray[currRgn-1].hrgn,
                rgnArray[currRgn].hrgn, fnCombineMode);

    rgnArray[currRgn-1].type |= rgnArray[currRgn].type;

    //
    // Delete the second of the two regions after combining
    //

    DeleteObject (rgnArray[currRgn--].hrgn);

    if (currRgn == 0)

      Reset (DISABLE_COMBINERGN);
  }
}



/******************************************************************************\
*
*  FUNCTION:    Reset
*
*  INPUTS:      action - Describes which reset action to take, eg. which
*                        menus to enable/disable etc...
*
*  GLOBAL VARS: rgnArray - Array of RGNSTRUCTs describing regions user has
*                          created
*               currRgn  - Index (in rgnArray) of most recently created
*                          region. If -1 then no regions created. Other-
*                          wise, values range from 0 to MAXRGNSTRUCTS - 1.
*               hMenu    - Handle of main window's menu.
*
*  COMMENTS:    Sets appropriate menu states and deletes old regions
*               according to "action" parameter.
*
\******************************************************************************/

void Reset (WORD action)
{
  UINT i;

  switch (action)
  {
    case RESET_ALL:
      if (currRgn > 0)

        for (i = 0; i <= (UINT) currRgn; i++)

          DeleteObject (rgnArray[i].hrgn);

      currRgn = -1;
      for (i = IDM_ERASE; i <= IDM_GETRGNBOX; i++)

        EnableMenuItem (GetSubMenu (hMenu, 0), i, MF_DISABLED | MF_GRAYED
                                                  | MF_BYCOMMAND);
      for (i = IDM_ELLIPSE; i <= IDM_RECT; i++)

        EnableMenuItem (GetSubMenu (hMenu, 1), i, MF_ENABLED |
                                                  MF_BYCOMMAND);
      for (i = IDM_AND; i <= IDM_XOR; i++)

        EnableMenuItem (GetSubMenu (hMenu, 2), i, MF_DISABLED | MF_GRAYED
                                                  | MF_BYCOMMAND);
      break;

   case ENABLE_OPTIONS:

      for (i = IDM_ERASE; i <= IDM_GETRGNBOX; i++)

        EnableMenuItem (GetSubMenu (hMenu, 0), i, MF_ENABLED |
                                                  MF_BYCOMMAND);
      break;

   case ENABLE_COMBINERGN:

      for (i = IDM_AND; i <= IDM_XOR; i++)

        EnableMenuItem (GetSubMenu (hMenu, 2), i, MF_ENABLED |
                                                  MF_BYCOMMAND);
      break;

   case DISABLE_COMBINERGN:

      for (i = IDM_AND; i <= IDM_XOR; i++)

        EnableMenuItem (GetSubMenu (hMenu, 2), i, MF_DISABLED | MF_GRAYED
                                                  | MF_BYCOMMAND);
      break;
  }
}


/******************************************************************************\
*
*  FUNCTION:    TrackRect()
*
*  INPUTS:      ptr    - Pointer to a PTRACKRECTSTRUCT.
*               action - Message selecting what action to take.
*               hWnd   - Window handle for the window the track rect
*                        exists within.
*               lParam - Fourth param to window proc (as with WM_MOUSEMOVE,
*                        WM_LBUTTONDOWN, WM_LBUTTONUP...) desribing
*                        event location.
*
*  RETURNS:     A pointer to a new TRACKRECTSTRUCT if msg == TRECT_NEW,
*               NULL if msg != NEW
*
*  COMMENTS:    This function provides tracking rectangle functionality.
*
\******************************************************************************/

PTRACKRECTSTRUCT TrackRect (PTRACKRECTSTRUCT ptr, int action, HWND hWnd,
                            LPARAM lParam)
{
  if ((ptr == NULL) && (action != TRECT_NEW))  return NULL;

  switch (action)
  {
    //
    // TRECT_NEW: Allocate new PTRACKRECTSTRUCT. Fill in initial values
    //            for the fields of the structure. Set up the HDC
    //            correctly.
    //
    // return - pointer to the new object.
    //

    case TRECT_NEW:
    {
      PTRACKRECTSTRUCT ptr;

      if ((ptr = LocalAlloc (LPTR, sizeof (TRACKRECTSTRUCT))) == NULL)
      {
        MessageBox (hWnd, (LPCTSTR) "REGIONS: LocalAlloc() failed", "Err!",
                    MB_OK | MB_ICONEXCLAMATION);
        return NULL;
      }

      //
      // initialize the HDC and other fields.
      //

      ptr->hdc = GetDC(hWnd);
      SetROP2(ptr->hdc, R2_NOT);
      SelectObject (ptr->hdc, GetStockObject (NULL_BRUSH));
      SelectObject (ptr->hdc, CreatePen (PS_SOLID, 2,
                   (COLORREF) 0x01000009));

      //
      // initialize the size
      //

      ptr->trackRect.left = ptr->trackRect.right =
                            (LONG) (ptr->xOrigin = LOWORD (lParam));
      ptr->trackRect.top = ptr->trackRect.bottom =
                            (LONG) (ptr->yOrigin = HIWORD (lParam));

      SetCapture (hWnd);
      GetClientRect (hWnd, &(ptr->clientRect));
      return (ptr);
    }

    //
    // TRECT_DELETE: Free up the memory allocated for the tracking rect.
    //               Also, erase the last rectangle we drew.
    //

    case  TRECT_DELETE:

      Rectangle (ptr->hdc, (int) ptr->trackRect.left,
                           (int) ptr->trackRect.top,
                           (int) ptr->trackRect.right,
                           (int) ptr->trackRect.bottom);
      ReleaseDC (hWnd, ptr->hdc);
      LocalFree (LocalHandle ((LPSTR)ptr));
      ReleaseCapture ();
      return NULL;

    //
    // TRECT_PAINT: Draw the tracking rectangle (involves erasing last
    //              rectangle at old coordinates, and drawing new rect
    //              at new coordinates).
    //

    case TRECT_PAINT:

      //
      // Remove the last rectangle we painted by painting over it again
      //

      Rectangle (ptr->hdc, (int) ptr->trackRect.left,
                           (int) ptr->trackRect.top,
                           (int) ptr->trackRect.right,
                           (int) ptr->trackRect.bottom);

      //
      // We want to restrict our Rectangle() calls to paint within the
      //   client area, so do a bounds check on lParam and reset any
      //   values which fall outside the client area (eg. <1,
      //   >clientRect.left, >clientRect.top).
      //

      if ((SHORT)LOWORD(lParam) < 1)

        lParam &= 0xffff0000;

      else if (LOWORD(lParam) > (WORD) (ptr->clientRect.right- 1))

        lParam = MAKELONG ((WORD) ptr->clientRect.right - 1,
                           HIWORD(lParam));

      if ((SHORT)HIWORD(lParam) < 1)

        lParam &= 0x0000ffff;

      else if (HIWORD(lParam) > (WORD) (ptr->clientRect.bottom - 1))

        lParam = MAKELONG (LOWORD(lParam),
                           (WORD) ptr->clientRect.bottom - 1);

      ptr->trackRect.left   = (LONG) (ptr->xOrigin > LOWORD(lParam)
                               ? LOWORD(lParam) : ptr->xOrigin);
      ptr->trackRect.right  = (LONG) (ptr->xOrigin > LOWORD(lParam)
                               ? ptr->xOrigin : LOWORD(lParam));
      ptr->trackRect.top    = (LONG) (ptr->yOrigin > HIWORD(lParam)
                               ? HIWORD(lParam) : ptr->yOrigin);
      ptr->trackRect.bottom = (LONG) (ptr->yOrigin > HIWORD(lParam)
                               ? ptr->yOrigin : HIWORD(lParam));

      //
      // Redraw the tracking rectangle
      //

      Rectangle (ptr->hdc, (int) ptr->trackRect.left,
                           (int) ptr->trackRect.top,
                           (int) ptr->trackRect.right,
                           (int) ptr->trackRect.bottom);
      return NULL;
  }
}

unix.superglobalmegacorp.com

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