home *** CD-ROM | disk | FTP | other *** search
- // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
- // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
- // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
- // PARTICULAR PURPOSE.
- //
- // Copyright (C) 1993-1995 Microsoft Corporation. All Rights Reserved.
- //
- // MODULE: client.c
- //
- // PURPOSE: Contains all input/drawing routines for the GDI Input sample.
- //
- // FUNCTIONS:
- // CreateClientWindow - Creates the client window that handles input.
- // ClientWndProc - Processes messages for the client window.
- // CmdDrawMode - Changes the current drawing mode.
- // CmdFill - Toggles the fill mode.
- // CmdCreatePen - Puts up Pen Style dialog box.
- // CmdCreateBrush - Puts up Brush Style dialog box.
- // MsgClientCreate - Creates initial pens & brushes.
- // MsgClientDestroy - Frees owned objects.
- // MsgClientKeyDown - Looks for Escape key to cancel drawing.
- // MsgClientPaint - Paints the client window.
- // MsgClientSize -
- //
- // MsgClientLButtonDown
- // MsgClientMouseMove => Pass mouse messages to the current handlers.
- // MsgClientLButtonUp
- //
- // PixelLBDown
- // PixelMouseMove ==> Draw individual pixels with SetPixelV.
- // PixelLBUp
- //
- // BezierLBDown
- // BezierMouseMove ==> Select 4 points for drawing a Bezier curve.
- // BezierLBUp
- //
- // RectLBDown
- // RectMouseMove ==> Select 2 points for a line, rect, or ellipse.
- // RectLBUp
- //
- // LineDraw Given 2 points, draw a line, rect, or ellipse.
- // RectDraw ==> These functions all take identical parameters
- // EllipseDraw so they can be used interchangeably.
- //
- // StartRubberBand - Initiates drawing procedure.
- // EndRubberBand - Ends drawing procedure.
- // ClientNewDrawing - Erases current drawing and starts over.
- //
- // COMMENTS:
- //
-
- #include <windows.h> // required for all Windows applications
- #include <windowsx.h>
- #include <commctrl.h> // prototypes and defs for common controls
- #include "globals.h" // prototypes specific to this application
- #include "resource.h"
- #include "toolbar.h" // prototypes for the tool bar
- #include "statbar.h" // prototypes for the status bar
- #include "pendlg.h" // ID's and prototypes for the Pen dialog
- #include "brushdlg.h" // ID's and prototypes for the Brush dialog
-
- // Global variables local to this file
-
- HPEN hpenBlack; // Useful stock objects
- HBRUSH hbrNull;
-
- HPEN hpenDraw; // for drawing lines and frames
- HBRUSH hbrReal; // for filling interiors
- HBRUSH hbrDraw; // equals either hbrReal or hbrNull
-
- LOGPEN logPen;
- LOGBRUSH logBrush;
-
- HDC hdcRB; // DC for Rubber Banding
- HDC hdcDraw; // DC for final drawing
- BOOL bDrawing; // Flag to indicate when we are drawing
- UINT uDrawMode; // IDM_LINE, IDM_RECT, etc.
-
- HDC hdcBitmap; // Used with hbmBitmap
- HBITMAP hbmBitmap; // All drawing is cached here for faster screen updates
- UINT cxBitmap; // Width of bitmap
- UINT cyBitmap; // Height of bitmap
- HBITMAP hbmStock; // Stock 1x1 bitmap that mem DC's are initialized with
-
- #define BEZ_MAXPOINTS 4 // # of points in a Bezier curve
- POINT pPoints[BEZ_MAXPOINTS]; // Stores coordinates for various drawing fns
- UINT cPoints; // Current # of points (for bezier)
-
-
- // The following 3 function pointers are used to point to the current
- // mouse handling functons. Different drawing types can each define a
- // set of mouse functions. When a new drawing mode is selected, these
- // pointers are set to point to the correct functions for that mode.
- // The main mouse message handlers then dereference these pointers to
- // call the correct handlers.
-
- LRESULT (*pfnLBDown) (HWND, POINT); // current mouse handler
- LRESULT (*pfnLBUp) (HWND, POINT); // functions for rubber
- LRESULT (*pfnMouseMove)(HWND, POINT); // banding and such
-
-
- // The Line, Rectangle, and Ellipse modes use a common set of mouse
- // handlers that select 2 points. The following function pointer is
- // used so that the correct drawing function is always used. Like the
- // mouse function pointers, this is set when the drawing mode is
- // selected.
-
- BOOL (*pfnDrawRect)(HDC, POINT, POINT); // current drawing function
-
-
- // Mouse handling functions for different types of drawing.
- LRESULT PixelLBDown(HWND, POINT); // Pixels
- LRESULT PixelLBUp(HWND, POINT);
- LRESULT PixelMouseMove(HWND, POINT);
-
- LRESULT BezierLBDown(HWND, POINT); // Bezier Curves
- LRESULT BezierLBUp(HWND, POINT);
- LRESULT BezierMouseMove(HWND, POINT);
-
- LRESULT RectLBDown(HWND, POINT); // 2-point selection
- LRESULT RectLBUp(HWND, POINT); // Used for Lines, Rects,
- LRESULT RectMouseMove(HWND, POINT); // and Ellipses
-
- // Generic drawing functions for use with the above Rect functions
- BOOL LineDraw(HDC, POINT, POINT);
- BOOL RectDraw(HDC, POINT, POINT);
- BOOL EllipseDraw(HDC, POINT, POINT);
-
-
- // Other helper functions
- void StartRubberBand(HWND hwnd);
- void EndRubberBand(HWND hwnd);
-
-
- // Client window message handling functions
- static LRESULT MsgClientCreate (HWND, UINT, WPARAM, LPARAM);
- static LRESULT MsgClientDestroy (HWND, UINT, WPARAM, LPARAM);
- static LRESULT MsgClientMouseMove (HWND, UINT, WPARAM, LPARAM);
- static LRESULT MsgClientLButtonDown (HWND, UINT, WPARAM, LPARAM);
- static LRESULT MsgClientLButtonUp (HWND, UINT, WPARAM, LPARAM);
- static LRESULT MsgClientKeyDown (HWND, UINT, WPARAM, LPARAM);
- static LRESULT MsgClientPaint (HWND, UINT, WPARAM, LPARAM);
- static LRESULT MsgClientSize (HWND, UINT, WPARAM, LPARAM);
-
-
- // Client window message table definitions.
- MSD rgmsdClient[] =
- {
- {WM_MOUSEMOVE, MsgClientMouseMove },
- {WM_LBUTTONDOWN, MsgClientLButtonDown },
- {WM_LBUTTONUP, MsgClientLButtonUp },
- {WM_KEYDOWN, MsgClientKeyDown },
- {WM_CREATE, MsgClientCreate },
- {WM_DESTROY, MsgClientDestroy },
- {WM_PAINT, MsgClientPaint },
- {WM_SIZE, MsgClientSize },
- };
-
-
- MSDI msdiClient =
- {
- sizeof(rgmsdClient) / sizeof(MSD),
- rgmsdClient,
- edwpWindow
- };
-
-
- //
- // FUNCTION: CreateClientWindow(HWND)
- //
- // PURPOSE: Create the client window.
- //
- // PARAMETERS:
- // hwndParent - The parent (main) window.
- //
- // RETURN VALUE:
- // HWND of client window or null if failure.
- //
- // COMMENTS:
- //
-
- HWND CreateClientWindow(HWND hwndParent)
- {
- return CreateWindowEx(0,
- "ClientWndClass",
- NULL,
- WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS,
- -100, -100, 10, 10, // dummy initial coordinates
- hwndParent,
- (HMENU)-1,
- hInst,
- NULL);
- }
-
-
- //
- // FUNCTION: ClientWndProc(HWND, UINT, WPARAM, LPARAM)
- //
- // PURPOSE: Processes messages for the client window.
- //
- // PARAMETERS:
- // hwnd - window handle
- // uMessage - message number
- // wparam - additional information (dependant on message number)
- // lparam - additional information (dependant on message number)
- //
- // RETURN VALUE:
- // The return value depends on the message number. If the message
- // is implemented in the message dispatch table, the return value is
- // the value returned by the message handling function. Otherwise,
- // the return value is the value returned by the default window procedure.
- //
- // COMMENTS:
- // Call the DispMessage() function with the client window's message
- // dispatch information (msdiClient) and the message specific information.
- //
-
- LRESULT CALLBACK ClientWndProc(HWND hwnd,
- UINT uMessage,
- WPARAM wparam,
- LPARAM lparam)
- {
- return DispMessage(&msdiClient, hwnd, uMessage, wparam, lparam);
- }
-
-
- //
- // FUNCTION: CmdDrawMode(HWND, WORD, WORD, HWND)
- //
- // PURPOSE: Handles WM_COMMAND messages to change drawing mode.
- //
- // PARAMETERS:
- // hwnd - The main window.
- // wCommand - IDM_LINE, IDM_RECT, etc.
- // wNotify - Notification number (unused)
- // hwndCtrl - NULL (unused)
- //
- // RETURN VALUE:
- // Always returns 0 - command handled.
- //
- // COMMENTS:
- //
-
- #pragma argsused
- LRESULT CmdDrawMode(HWND hwnd, WORD wCommand, WORD wNotify, HWND hwndCtrl)
- {
- HMENU hMenu;
-
- if (wCommand == uDrawMode) // First see if the mode has changed
- return 0;
-
- // Update the menu and toolbar states
-
- hMenu = GetMenu(hwnd);
- CheckMenuItem(hMenu, uDrawMode, MF_BYCOMMAND | MF_UNCHECKED);
- uDrawMode = wCommand;
- CheckMenuItem(hMenu, uDrawMode, MF_BYCOMMAND | MF_CHECKED);
-
- SendMessage(hWndToolbar, TB_CHECKBUTTON, uDrawMode, MAKELONG(TRUE, 0));
-
- // Set the pointers for the mouse handler functions to
- // the appropriate functions.
-
- switch(uDrawMode)
- {
- case IDM_PIXEL:
- pfnLBDown = PixelLBDown;
- pfnLBUp = PixelLBUp;
- pfnMouseMove = PixelMouseMove;
- break;
-
- case IDM_BEZIER:
- cPoints = 0;
- pfnLBDown = BezierLBDown;
- pfnLBUp = BezierLBUp;
- pfnMouseMove = BezierMouseMove;
- break;
-
- case IDM_RECT:
- pfnDrawRect = RectDraw;
- pfnLBDown = RectLBDown;
- pfnLBUp = RectLBUp;
- pfnMouseMove = RectMouseMove;
- break;
-
- case IDM_ELLIPSE:
- pfnDrawRect = EllipseDraw;
- pfnLBDown = RectLBDown;
- pfnLBUp = RectLBUp;
- pfnMouseMove = RectMouseMove;
- break;
-
- default:
- case IDM_LINE:
- pfnDrawRect = LineDraw;
- pfnLBDown = RectLBDown;
- pfnLBUp = RectLBUp;
- pfnMouseMove = RectMouseMove;
- break;
- }
-
- return 0;
- }
-
-
- //
- // FUNCTION: CmdFill(HWND, WORD, WORD, HWND)
- //
- // PURPOSE: Handles the IDM_FILL and IDM_NOFILL command messages.
- // Controls whether closed objects (rect's and ellipses) are filled
- // with a brush when drawn.
- //
- // PARAMETERS:
- // hwnd - The main window.
- // wCommand - IDM_FILL or IDM_NOFILL
- // wNotify - Notification number (unused)
- // hwndCtrl - NULL (unused)
- //
- // RETURN VALUE:
- // Always returns 0 - command handled.
- //
- // COMMENTS:
- // The toolbar has 2 buttons (IDM_FILL and IDM_NOFILL) but the
- // menu only has IDM_FILL, so this function will turn filling
- // OFF if wCommand is IDM_NOFILL, and TOGGLE the ON/OFF state
- // if wCommand is IDM_FILL.
- //
-
- #pragma argsused
- LRESULT CmdFill(HWND hwnd, WORD wCommand, WORD wNotify, HWND hwndCtrl)
- {
- static BOOL bFill;
-
- if (IDM_NOFILL == wCommand)
- bFill = FALSE; // turn filling OFF
- else
- bFill = !bFill; // toggle fill state
-
- // Update the menu and toolbar states
-
- CheckMenuItem(GetMenu(hwnd),
- IDM_FILL,
- MF_BYCOMMAND | (bFill ? MF_CHECKED : MF_UNCHECKED));
-
- SendMessage(hWndToolbar,
- TB_CHECKBUTTON,
- (bFill ? IDM_FILL : IDM_NOFILL),
- MAKELONG(TRUE, 0));
-
- // Update hbrDraw and select it into the DC for drawing
- hbrDraw = (bFill ? hbrReal : hbrNull);
- SelectObject(hdcBitmap, hbrDraw);
-
- return 0;
- }
-
-
- //
- // FUNCTION: CmdCreatePen(HWND, WORD, WORD, HWND)
- //
- // PURPOSE: Handles the IDM_CREATEPEN command message. Puts up a dialog
- // to let the user set the pen style to use for drawing.
- //
- // PARAMETERS:
- // hwnd - The main window.
- // wCommand - IDM_CREATEPEN (unused)
- // wNotify - Notification number (unused)
- // hwndCtrl - NULL (unused)
- //
- // RETURN VALUE:
- // Always returns 0 - command handled.
- //
- // COMMENTS:
- //
-
- #pragma argsused
- LRESULT CmdCreatePen(HWND hwnd, WORD wCommand, WORD wNotify, HWND hwndCtrl)
- {
- LOGPEN lp = logPen; // copy for the dialog to munge on
-
- if (DialogBoxParam(hInst, "PenDlg", hwnd, (DLGPROC)PenDlg, (LPARAM)&lp))
- {
- HPEN hpenNew = CreatePenIndirect(&lp); // create new pen
- if (!hpenNew)
- {
- // Should report an error here...
- return 0;
- }
-
- // Select the new pen for drawing (deselect old pen before deleting)
- SelectObject(hdcBitmap, hpenNew);
-
- DeleteObject(hpenDraw); // delete old pen
- hpenDraw = hpenNew; // save changes
- logPen = lp;
- }
-
- return 0;
- }
-
-
- //
- // FUNCTION: CmdCreateBrush(HWND, WORD, WORD, HWND)
- //
- // PURPOSE: Handles the IDM_CREATEBRUSH command message. Puts up a dialog
- // to let the user set the brush style to use for drawing.
- //
- // PARAMETERS:
- // hwnd - The main window.
- // wCommand - IDM_CREATEBRUSH (unused)
- // wNotify - Notification number (unused)
- // hwndCtrl - NULL (unused)
- //
- // RETURN VALUE:
- // Always returns 0 - command handled.
- //
- // COMMENTS:
- //
-
- #pragma argsused
- LRESULT CmdCreateBrush(HWND hwnd, WORD wCommand, WORD wNotify, HWND hwndCtrl)
- {
- LOGBRUSH lb = logBrush; // copy for the dialog to munge on
-
- if (DialogBoxParam(hInst, "BrushDlg", hwnd, (DLGPROC)BrushDlg, (LPARAM)&lb))
- {
- HBRUSH hbrNew = CreateBrushIndirect(&lb); // create new brush
- if (!hbrNew)
- {
- // Should report an error here...
- return 0;
- }
-
- // If "Fill Objects" is turned on, we need to update hbrDraw
- if (GetMenuState(GetMenu(hwnd), IDM_FILL, MF_BYCOMMAND) & MF_CHECKED)
- {
- hbrDraw = hbrNew; // save new handle
- SelectObject(hdcBitmap, hbrDraw); // select new brush
- } // (deselect old brush)
-
- DeleteObject(hbrReal); // delete old brush
- hbrReal = hbrNew; // save changes
- logBrush = lb;
- }
-
- return 0;
- }
-
-
- //
- // FUNCTION: MsgClientCreate(HWND, UINT, WPARAM, LPARAM)
- //
- // PURPOSE: Handles the WM_CREATE message for the client window.
- //
- // PARAMETERS:
- //
- // hwnd - Window handle (Unused)
- // uMessage - Message number (Unused)
- // wparam - Extra data (Unused)
- // lparam - Extra data (Unused)
- //
- // RETURN VALUE:
- //
- // COMMENTS:
- // Initializes pens, brushes, and the off-screen bitmap.
- //
-
- #pragma argsused
- LRESULT MsgClientCreate(HWND hwnd,
- UINT uMessage,
- WPARAM wparam,
- LPARAM lparam)
- {
- HDC hdcTmp;
- RECT rc;
-
- // Initialize pens and brushes
-
- hpenBlack = GetStockObject(BLACK_PEN);
- hbrNull = GetStockObject(NULL_BRUSH);
-
- hpenDraw = hpenBlack;
- hbrReal = GetStockObject(GRAY_BRUSH);
-
- hbrDraw = hbrReal;
-
- GetObject(hpenDraw, sizeof(logPen), &logPen);
- GetObject(hbrReal, sizeof(logBrush), &logBrush);
-
- // Create off-screen bitmap and DC
-
- hdcTmp = GetDC(hwnd); // Screen DC for reference
-
- GetClientRect(hwnd, &rc);
-
- cxBitmap = max(rc.right, 1);
- cyBitmap = max(rc.bottom, 1);
- hbmBitmap = CreateCompatibleBitmap(hdcTmp, cxBitmap, cyBitmap);
-
- if (!hbmBitmap)
- {
- DeleteObject(hpenDraw);
- DeleteObject(hbrReal);
-
- OutputDebugString("MsgClientCreate: Unable to create bitmap\r\n");
- return -1;
- }
-
- // Create memory DC to hold bitmap
- hdcBitmap = CreateCompatibleDC(hdcTmp);
- ReleaseDC(hwnd, hdcTmp); // Done with this
-
- // Initialize memory DC
- SelectObject(hdcBitmap, hpenDraw);
- SelectObject(hdcBitmap, hbrDraw);
- SetBkMode(hdcBitmap, TRANSPARENT);
- hbmStock = SelectObject(hdcBitmap, hbmBitmap);
-
- // Initialize bitmap to white
- PatBlt(hdcBitmap, 0, 0, cxBitmap, cyBitmap, WHITENESS);
-
- return 0;
- }
-
-
- //
- // FUNCTION: MsgClientDestroy(HWND, UINT, WPARAM, LPARAM)
- //
- // PURPOSE: Handles WM_DESTROY message for the client window.
- //
- // PARAMETERS:
- //
- // hwnd - Window handle (Unused)
- // uMessage - Message number (Unused)
- // wparam - Extra data (Unused)
- // lparam - Extra data (Unused)
- //
- // RETURN VALUE:
- //
- // Always returns 0 - Message handled
- //
- // COMMENTS:
- // General clean up happens here.
- //
-
- #pragma argsused
- LRESULT MsgClientDestroy(HWND hwnd,
- UINT uMessage,
- WPARAM wparam,
- LPARAM lparam)
- {
- // Reset bitmap DC before deleting objects
-
- SelectObject(hdcBitmap, hpenBlack);
- SelectObject(hdcBitmap, hbrNull);
- SelectObject(hdcBitmap, hbmStock);
-
- DeleteObject(hpenDraw); // Delete pens/brushes
- DeleteObject(hbrReal);
-
- DeleteObject(hbmBitmap); // Delete bitmap and memory DC
- DeleteDC(hdcBitmap);
-
- return 0;
- }
-
-
- //
- // FUNCTION: MsgClientKeyDown(HWND, UINT, WPARAM, LPARAM)
- //
- // PURPOSE: Handles WM_KEYDOWN message.
- //
- // PARAMETERS:
- //
- // hwnd - Window handle
- // uMessage - Message number (Unused)
- // wparam - Key code (VK_xxx)
- // lparam - Extra data (Unused)
- //
- // RETURN VALUE:
- //
- // COMMENTS:
- // Looks for VK_ESCAPE key only. If user hits the escape key
- // while drawing, cancel the drawing operation.
- //
-
- #pragma argsused
- LRESULT MsgClientKeyDown(HWND hwnd,
- UINT uMessage,
- WPARAM wparam,
- LPARAM lparam)
- {
- if (VK_ESCAPE == wparam && bDrawing)
- {
- // End drawing.
- EndRubberBand(hwnd);
- cPoints = 0;
-
- // Force a repaint of the whole window to remove any junk
- // left by the cancelled drawing operation.
- InvalidateRect(hwnd, NULL, TRUE);
- }
-
- return 0;
- }
-
-
- //
- // FUNCTION: MsgClientPaint(HWND, UINT, WPARAM, LPARAM)
- //
- // PURPOSE: Handles WM_PAINT message.
- //
- // PARAMETERS:
- //
- // hwnd - Window handle
- // uMessage - Message number (Unused)
- // wparam - Extra data (Unused)
- // lparam - Extra data (Unused)
- //
- // RETURN VALUE:
- //
- // COMMENTS:
- // Redraws the screen from the bitmap
- //
-
- #pragma argsused
- LRESULT MsgClientPaint(HWND hwnd,
- UINT uMessage,
- WPARAM wparam,
- LPARAM lparam)
- {
- PAINTSTRUCT ps;
-
- BeginPaint(hwnd, &ps);
-
- BitBlt(ps.hdc, // Destination DC
- ps.rcPaint.left, // Dest origin
- ps.rcPaint.top,
- ps.rcPaint.right - ps.rcPaint.left, // Dest extents
- ps.rcPaint.bottom - ps.rcPaint.top,
- hdcBitmap, // Source DC
- ps.rcPaint.left, // Source origin
- ps.rcPaint.top,
- SRCCOPY); // ROP code
-
- EndPaint(hwnd, &ps);
- return 0;
- }
-
-
- //
- // FUNCTION: MsgClientSize(HWND, UINT, WPARAM, LPARAM)
- //
- // PURPOSE: Handles the WM_SIZE message for the client window.
- // size of the window.
- //
- // PARAMETERS:
- // hwnd - handle of Client window.
- // uMessage - WM_SIZE.
- // wParam - size flag (unused)
- // lParam - width/height of client area (unused)
- //
- // RETURN VALUE:
- // 0
- //
- // COMMENTS:
- // If the window has been enlarged, this will enlarge the bitmap to
- // match the new window size. The bitmap is never made smaller.
- //
-
- #pragma argsused
- LRESULT MsgClientSize(HWND hwnd, UINT uMessage, WPARAM wparam, LPARAM lparam)
- {
- HDC hdcTmp;
- HBITMAP hbmNew;
- UINT cxNew, cyNew;
- UINT cxWindow = LOWORD(lparam);
- UINT cyWindow = HIWORD(lparam);
-
-
- // First see if there's anything to do...
- if (cxBitmap >= cxWindow && cyBitmap >= cyWindow)
- return 0;
-
- // Get new bitmap dimensions
- cxNew = max(cxWindow, cxBitmap);
- cyNew = max(cyWindow, cyBitmap);
-
- // Use a screen DC to create the new bitmap so we get the
- // correct color format.
- hdcTmp = GetDC(hwnd);
- hbmNew = CreateCompatibleBitmap(hdcTmp, cxNew, cyNew);
- ReleaseDC(hwnd, hdcTmp);
-
- // If we couldn't create a new bitmap, just bail out now and leave
- // the old bitmap intact (that's better than having nothing).
- if (hbmNew == NULL)
- return 0;
-
- // Now we need a memory DC to copy old bitmap to new one.
- hdcTmp = CreateCompatibleDC(NULL);
-
- // Select new bitmap into permanent DC (this deselects the old bitmap)
- // and then select the old bitmap into temporary DC.
- SelectObject(hdcBitmap, hbmNew);
- SelectObject(hdcTmp, hbmBitmap);
-
- // Initialize the 'extra' parts of the new bitmap with white
-
- if (cxWindow > cxBitmap)
- PatBlt(hdcBitmap, cxBitmap, 0, cxWindow, cyWindow, WHITENESS);
-
- if (cyWindow > cyBitmap)
- PatBlt(hdcBitmap, 0, cyBitmap, cxWindow, cyWindow, WHITENESS);
-
- // Copy old bitmap to new one
- BitBlt(hdcBitmap,
- 0, 0,
- cxBitmap, cyBitmap,
- hdcTmp,
- 0, 0,
- SRCCOPY);
-
- // Clean up
- SelectObject(hdcTmp, hbmStock);
- DeleteObject(hbmBitmap);
- DeleteDC(hdcTmp);
-
- // Save new info
- hbmBitmap = hbmNew;
- cxBitmap = cxNew;
- cyBitmap = cyNew;
-
- return 0;
- }
-
-
- //
- // FUNCTION: MsgClientLButtonDown(HWND, UINT, WPARAM, LPARAM)
- //
- // PURPOSE: Handles WM_LBUTTONDOWN message.
- //
- // PARAMETERS:
- //
- // hwnd - Window handle
- // uMessage - Message number (Unused)
- // wparam - Extra data (Unused)
- // lparam - Mouse coordinates
- //
- // RETURN VALUE:
- //
- // COMMENTS:
- // Initiates dragging/drawing operation by saving the mouse
- // position and capturing mouse input.
- //
-
- #pragma argsused
- LRESULT MsgClientLButtonDown(HWND hwnd,
- UINT uMessage,
- WPARAM wparam,
- LPARAM lparam)
- {
- POINT pt;
-
- // If we aren't already drawing, set focus to the client window
- // so we can get Escape key messages should the user decide to
- // quit drawing.
-
- if (!bDrawing)
- SetFocus(hwnd);
-
- // Get mouse position
- pt.x = (int)(short)LOWORD(lparam);
- pt.y = (int)(short)HIWORD(lparam);
-
- // Call the current LBDown handler
- return (*pfnLBDown)(hwnd, pt);
- }
-
-
- //
- // FUNCTION: MsgClientMouseMove(HWND, UINT, WPARAM, LPARAM)
- //
- // PURPOSE: Handles WM_MOUSEMOVE message.
- //
- // PARAMETERS:
- //
- // hwnd - Window handle
- // uMessage - Message number (Unused)
- // wparam - Extra data (Unused)
- // lparam - Mouse coordinates
- //
- // RETURN VALUE:
- //
- // COMMENTS:
- // Performs "rubber-banding" by erasing the previous image and
- // redrawing the object using an XOR ROP code.
- //
-
- #pragma argsused
- LRESULT MsgClientMouseMove(HWND hwnd,
- UINT uMessage,
- WPARAM wparam,
- LPARAM lparam)
- {
- POINT pt;
- static char szBuf[20] ; // Array for formatting mouse coordinates
-
- // Get new mouse position
- pt.x = (int)(short)LOWORD(lparam);
- pt.y = (int)(short)HIWORD(lparam);
-
- // Update the status bar with the new position
- wsprintf(szBuf, "%d,%d", pt.x, pt.y);
- UpdateStatusBar(szBuf, 2, 0);
-
- // Call the current MouseMove handler
- return (*pfnMouseMove)(hwnd, pt);
- }
-
-
- //
- // FUNCTION: MsgClientLButtonUp(HWND, UINT, WPARAM, LPARAM)
- //
- // PURPOSE: Handles WM_LBUTTONUP message.
- //
- // PARAMETERS:
- //
- // hwnd - Window handle
- // uMessage - Message number (Unused)
- // wparam - Extra data (Unused)
- // lparam - Mouse coordinates
- //
- // RETURN VALUE:
- //
- // COMMENTS:
- // Erases previous rubber-band image and draws the object in
- // the final position.
- //
-
- #pragma argsused
- LRESULT MsgClientLButtonUp(HWND hwnd,
- UINT uMessage,
- WPARAM wparam,
- LPARAM lparam)
- {
- POINT pt;
-
- // Get new mouse position
- pt.x = (int)(short)LOWORD(lparam);
- pt.y = (int)(short)HIWORD(lparam);
-
- // Call the current LBUp handler
- return (*pfnLBUp)(hwnd, pt);
- }
-
-
- //
- // FUNCTION: xxxLBDown(HWND, UINT, WPARAM, LPARAM)
- // FUNCTION: xxxMouseMove(HWND, UINT, WPARAM, LPARAM)
- // FUNCTION: xxxLBUp(HWND, UINT, WPARAM, LPARAM)
- //
- // PURPOSE: Handles WM_LBUTTONDOWN, WM_MOUSEMOVE, and WM_LBUTTONUP
- //
- // PARAMETERS:
- //
- // hwnd - Window handle
- // pt - Mouse coordinates
- //
- // RETURN VALUE:
- // Always return 0
- //
- // COMMENTS:
- // These functions are called by the actual Msgxxx mouse message
- // handler functions (above) to perform input processing. Three
- // sets of these functions are implemented here. One to input
- // individual pixels; one to select 2 points (used to draw a
- // line, rectangle, or ellipse); and one to select 4 points (for
- // drawing Bezier curves). Additional functions could be "plugged
- // in" to support other types of drawing.
- //
- // In general, xxxLBDown initializes the drawing process, for example
- // by saving the initial coordinates and calling StartRubberBand;
- // xxxMouseMove updates the coordinates; and xxxLBUp performs any
- // final processing and clean up (EndRubberBand).
- //
-
- //
- // FUNCTION: PixelLBDown(HWND, UINT, WPARAM, LPARAM)
- // FUNCTION: PixelMouseMove(HWND, UINT, WPARAM, LPARAM)
- // FUNCTION: PixelLBUp(HWND, UINT, WPARAM, LPARAM)
- //
- // PURPOSE: Perform single point selection (individual pixels).
- //
-
- LRESULT PixelLBDown(HWND hwnd, POINT pt)
- {
- // Get a DC and capture mouse input
- StartRubberBand(hwnd);
- SetROP2(hdcRB, R2_COPYPEN);
-
- // Draw the pixel with the current pen color into both the
- // rubber-banding DC and the bitmap DC.
- SetPixelV(hdcRB, pt.x, pt.y, logPen.lopnColor);
- SetPixelV(hdcBitmap, pt.x, pt.y, logPen.lopnColor);
-
- return 0;
- }
-
-
- #pragma argsused
- LRESULT PixelMouseMove(HWND hwnd, POINT pt)
- {
- // If we are currently drawing, draw the pixel
- if (bDrawing)
- {
- SetPixelV(hdcRB, pt.x, pt.y, logPen.lopnColor);
- SetPixelV(hdcBitmap, pt.x, pt.y, logPen.lopnColor);
- }
-
- return 0;
- }
-
-
- #pragma argsused
- LRESULT PixelLBUp(HWND hwnd, POINT pt)
- {
- // Don't draw the pixel again here (it's already drawn at LBDown
- // and MouseMove time). Just need to clean up.
-
- if (bDrawing)
- EndRubberBand(hwnd);
-
- return 0;
- }
-
-
- //
- // FUNCTION: BezierLBDown(HWND, UINT, WPARAM, LPARAM)
- // FUNCTION: BezierMouseMove(HWND, UINT, WPARAM, LPARAM)
- // FUNCTION: BezierLBUp(HWND, UINT, WPARAM, LPARAM)
- //
- // PURPOSE: Perform 4-point selection for drawing Bezier curves.
- //
-
- #pragma argsused
- LRESULT BezierLBDown(HWND hwnd, POINT pt)
- {
- // If this is the first click, initialize rubber banding.
-
- if (0 == cPoints)
- StartRubberBand(hwnd);
-
- return 0;
- }
-
-
- #pragma argsused
- LRESULT BezierMouseMove(HWND hwnd, POINT pt)
- {
- int i;
-
- if (!bDrawing || 0 == cPoints) // Are we currently drawing?
- return 0;
-
- // Are we rubber banding a Bezier?
- if (cPoints >= 2)
- PolyBezier(hdcRB, pPoints, BEZ_MAXPOINTS); // Erase previous Bezier
-
- // Erase previous line segment
- LineDraw(hdcRB, pPoints[cPoints - 1], pPoints[cPoints]);
-
- // Set the rest of the points to be the same as this one
- for (i = cPoints; i < BEZ_MAXPOINTS; i++)
- pPoints[i] = pt;
-
- // Draw new line segment
- LineDraw(hdcRB, pPoints[cPoints - 1], pPoints[cPoints]);
-
- // Are we rubber banding a Bezier?
- if (cPoints >= 2)
- PolyBezier(hdcRB, pPoints, BEZ_MAXPOINTS);
-
- return 0;
- }
-
-
- LRESULT BezierLBUp(HWND hwnd, POINT pt)
- {
- int i;
-
- if (!bDrawing) // Are we currently drawing?
- return 0;
-
- if (cPoints >= 2) // Are we rubber banding a Bezier?
- {
- // Erase previous Bezier
- PolyBezier(hdcRB, pPoints, BEZ_MAXPOINTS);
-
- if (cPoints == BEZ_MAXPOINTS - 1) // Is this the last point?
- {
- // If so, then erase all line segments.
- for (i = BEZ_MAXPOINTS - 1; i > 0; i--)
- LineDraw(hdcRB, pPoints[i - 1], pPoints[i]);
- }
- }
- // else do *not* erase the previous line segments
-
- // Save new position and increment # of points
- pPoints[cPoints++] = pt;
-
- if (cPoints < BEZ_MAXPOINTS) // Still more points to get.
- {
- // Set the rest of the points to be the same as the current one
- for (i = cPoints; i < BEZ_MAXPOINTS; i++)
- pPoints[i] = pt;
-
- // Draw new line segment
- LineDraw(hdcRB, pPoints[cPoints - 1], pPoints[cPoints]);
-
- // Once we have at least 2 points let's draw the Bezier curve
- if (cPoints >= 2)
- PolyBezier(hdcRB, pPoints, BEZ_MAXPOINTS);
- }
- else // Finish this Bezier and quit drawing.
- {
- // Setup DC for 'real' drawing
- SetROP2(hdcRB, R2_COPYPEN);
- SetBkMode(hdcRB, TRANSPARENT);
- SelectObject(hdcRB, hpenDraw);
-
- // Draw Bezier in permanent position
- PolyBezier(hdcRB, pPoints, cPoints);
-
- // Draw it again into the bitmap DC
- PolyBezier(hdcBitmap, pPoints, cPoints);
-
- // De-select the pen and clean up rubber banding stuff.
- SelectObject(hdcRB, hpenBlack);
- EndRubberBand(hwnd);
- cPoints = 0;
- }
-
- return 0;
- }
-
-
- //
- // FUNCTION: RectLBDown(HWND, UINT, WPARAM, LPARAM)
- // FUNCTION: RectMouseMove(HWND, UINT, WPARAM, LPARAM)
- // FUNCTION: RectLBUp(HWND, UINT, WPARAM, LPARAM)
- //
- // PURPOSE: Perform 2-point selection for drawing lines, rectangles,
- // and ellipses.
- //
-
- LRESULT RectLBDown(HWND hwnd, POINT pt)
- {
- // Current position = starting position = mouse position
- pPoints[0] = pPoints[1] = pt;
-
- // Initialize rubber banding
- StartRubberBand(hwnd);
-
- // Draw initial state
- (*pfnDrawRect)(hdcRB, pPoints[0], pPoints[1]);
-
- return 0;
- }
-
-
- #pragma argsused
- LRESULT RectMouseMove(HWND hwnd, POINT pt)
- {
- if (!bDrawing) // Are we currently drawing?
- return 0;
-
- // Un-draw previous position by redrawing
- (*pfnDrawRect)(hdcRB, pPoints[0], pPoints[1]);
-
- // Save new position
- pPoints[1] = pt;
-
- // Draw in new position
- (*pfnDrawRect)(hdcRB, pPoints[0], pPoints[1]);
-
- return 0;
- }
-
-
- LRESULT RectLBUp(HWND hwnd, POINT pt)
- {
- if (!bDrawing) // Are we currently drawing?
- return 0;
-
- // Un-draw previous position by redrawing
- (*pfnDrawRect)(hdcRB, pPoints[0], pPoints[1]);
-
- // Save new position
- pPoints[1] = pt;
-
- // Setup DC for 'real' drawing
- SetROP2(hdcRB, R2_COPYPEN);
- SetBkMode(hdcRB, TRANSPARENT);
- SelectObject(hdcRB, hpenDraw);
- SelectObject(hdcRB, hbrDraw);
-
- // Draw object in permanent position
- (*pfnDrawRect)(hdcRB, pPoints[0], pPoints[1]);
-
- // Draw it again into the bitmap DC
- (*pfnDrawRect)(hdcBitmap, pPoints[0], pPoints[1]);
-
- // De-select the pen and brush by selecting stock objects
- // and clean up rubber banding stuff.
- SelectObject(hdcRB, hpenBlack);
- SelectObject(hdcRB, hbrNull);
- EndRubberBand(hwnd);
-
- return 0;
- }
-
-
- //
- // FUNCTION: xxxxDraw(HDC hdc, POINT pt1, POINT pt2)
- //
- // PURPOSE: Draws a Line, Rectangle, or Ellipse at the coordinates
- // given by pt1 and pt2.
- //
- // PARAMETERS:
- // hdc - Device context to draw into.
- // pt1 - Beginning point (upper-left corner of rect)
- // pt2 - Ending point (lower-right corner of rect)
- //
- // RETURN VALUE:
- // TRUE for success, FALSE otherwise.
- //
- // COMMENTS:
- // Assumes the DC is already correctly set up.
- //
- //
-
- BOOL LineDraw(HDC hdc, POINT pt1, POINT pt2)
- {
- MoveToEx(hdc, pt1.x, pt1.y, NULL);
- return LineTo(hdc, pt2.x, pt2.y);
- }
-
-
- BOOL RectDraw(HDC hdc, POINT pt1, POINT pt2)
- {
- return Rectangle(hdc, pt1.x, pt1.y, pt2.x, pt2.y);
- }
-
-
- BOOL EllipseDraw(HDC hdc, POINT pt1, POINT pt2)
- {
- return Ellipse(hdc, pt1.x, pt1.y, pt2.x, pt2.y);
- }
-
-
- //
- // FUNCTION: StartRubberBand(HWND)
- //
- // PURPOSE: Sets up DC for rubber banding and captures the mouse.
- //
- // PARAMETERS:
- // hwnd - Window for GetDC
- //
- // RETURN VALUE:
- // None
- //
- // COMMENTS:
- //
-
- void StartRubberBand(HWND hwnd)
- {
- hdcRB = GetDC(hwnd); // Get a DC to draw to
-
- // R2_NOT causes drawing with a pen to invert the screen pixels.
- // This makes it easy to erase something by drawing it a 2nd time.
- SetROP2(hdcRB, R2_NOT);
-
- // For rubber banding with R2_NOT, we use a single pixel pen and
- // a NULL brush.
- SelectObject(hdcRB, hpenBlack);
- SelectObject(hdcRB, hbrNull);
-
- SetCapture(hwnd); // Capture mouse input
- bDrawing = TRUE;
- }
-
-
- //
- // FUNCTION: EndRubberBand(HWND)
- //
- // PURPOSE: Releases rubber banding DC and mouse capture.
- //
- // PARAMETERS:
- // hwnd - Window for ReleaseDC
- //
- // RETURN VALUE:
- // None
- //
- // COMMENTS:
- //
-
- void EndRubberBand(HWND hwnd)
- {
- ReleaseDC(hwnd, hdcRB);
- ReleaseCapture();
- bDrawing = FALSE;
- }
-
-
- //
- // FUNCTION: ClientNewDrawing(VOID)
- //
- // PURPOSE: Erase drawing and start over
- //
- // PARAMETERS:
- // None
- //
- // RETURN VALUE:
- // None
- //
- // COMMENTS:
- //
-
- VOID ClientNewDrawing(VOID)
- {
- if (hWndClient && hdcBitmap)
- {
- HCURSOR hcurSave = SetCursor(LoadCursor(NULL, IDC_WAIT));
-
- PatBlt(hdcBitmap, 0, 0, cxBitmap, cyBitmap, WHITENESS);
- InvalidateRect(hWndClient, NULL, TRUE);
-
- SetCursor(hcurSave);
- }
- }
-