TRACK.C
资源名称:MSDN_VC98.zip [点击查看]
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:17k
源码类别:
Windows编程
开发平台:
Visual C++
- /******************************************************************************
- * This is a part of the Microsoft Source Code Samples.
- * Copyright (C) 1992-1997 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.
- ******************************************************************************/
- /**************************************************************************
- * track.c -- support for direct manipulation of parallelogram object.
- **************************************************************************/
- #include <windows.h>
- #include <math.h>
- #include "track.h"
- #define EPSILON (float) 0.0001
- #define RECTSIZE 60
- /**************************************************************************
- *
- * function: doTrackObject()
- *
- * input parameters:
- * pto - pointer to a track object.
- * msg - message selecting what action to take. Values may include WM_*'s
- * (see case statements below for more information.)
- * hwnd - Window handle for the window the track object exists within.
- * lParam - Usually fourth param to window proc. varies based on msg.
- *
- * global variables: none.
- *
- * coordinate spaces: There are three coordinate spaces of interest here,
- * and this routine is frequently switching between them...
- *
- * WORLD DEVICE SCREEN
- *
- * object coordinates input mouse pos used w/ SetCursorPos()
- * (pto->rect) (lParam for WM_*)
- *
- * -----> LPtoDP() ----> ----> ClientToScreen() -->
- * <----- DPtoLP() <---- <---- ScreenToClient() <--
- *
- * in addition, the HDC has an offset origin. Device coordinates for the
- * mouse (lParam) never take this into account, but it is necessary to
- * translate them in order to get direct manipulation right.
- *
- **************************************************************************/
- PTrackObject doTrackObject(PTrackObject pto, int msg, HWND hwnd, LONG lParam)
- {
- if ((pto == NULL) && (msg != TROB_NEW)) return NULL;
- switch (msg) {
- /**********************************************************************
- * TROB_NEW
- *
- * Allocate new PTrackObject structure. Fill in default values
- * for the fields of the structure. Set up the HDC correctly.
- * return - pointer to the new object.
- **********************************************************************/
- case TROB_NEW: {
- PTrackObject pto;
- /* with LPTR returned value is a pointer. */
- pto = (PTrackObject) LocalAlloc (LPTR, sizeof (TrackObject));
- /* initialize the HDC and other fields. */
- pto->hdc = GetDC (hwnd);
- SetGraphicsMode (pto->hdc, GM_ADVANCED);
- SetROP2(pto->hdc, R2_NOT);
- SelectObject (pto->hdc, GetStockObject (NULL_BRUSH));
- pto->Mode = TMNONE;
- pto->allowedModes = TMMOVE | TMSIZEXY;
- GetWorldTransform (pto->hdc, &(pto->xfmChange));
- /* initialize the size. */
- pto->rect.top = pto->rect.left = 0;
- pto->rect.bottom = pto->rect.right = RECTSIZE;
- return (pto);
- }
- /**********************************************************************
- * TROB_DELETE
- *
- * Complement of TROB_NEW. Free up the memory allocated for the object.
- **********************************************************************/
- case TROB_DELETE:
- doTrackObject (pto, TROB_PAINT, hwnd, lParam);
- ReleaseDC (hwnd, pto->hdc);
- LocalFree (LocalHandle ((LPSTR)pto));
- return NULL;
- /**********************************************************************
- * TROB_PAINT
- *
- * Paint the object into its hdc. Called half the time to erase
- * the object, and half the time to redraw it.
- **********************************************************************/
- case TROB_PAINT: {
- MoveToEx (pto->hdc, pto->rect.right, pto->rect.top, NULL);
- LineTo (pto->hdc, pto->rect.left, pto->rect.top);
- LineTo (pto->hdc, pto->rect.left, pto->rect.bottom);
- if (pto->allowedModes & TMSIZEXY) {
- LineTo (pto->hdc, pto->rect.right, pto->rect.bottom);
- LineTo (pto->hdc, pto->rect.right, pto->rect.top);
- }
- if (pto->allowedModes & TMROTATE) {
- MoveToEx (pto->hdc, pto->rect.left, pto->rect.bottom/ 4, NULL);
- AngleArc (pto->hdc, pto->rect.left, pto->rect.top,
- (DWORD) pto->rect.bottom/ 4, (float) 270.0, (float) 90.0);
- }
- } return NULL;
- /**********************************************************************
- * TROB_HITTEST
- *
- * Check the point sent in in the lParam to see if it lays within
- * the bounds of the objects defining rectangle.
- * return - pointer to the object iff the point is in rectangle,
- * otherwise return NULL.
- **********************************************************************/
- case TROB_HITTEST:{
- POINT mouWorld;
- mouWorld.x = LOWORD(lParam);
- mouWorld.y = HIWORD(lParam);
- DPtoLP (pto->hdc, &mouWorld, 1);
- if (PtInRect (&pto->rect, mouWorld)) return pto;
- else return NULL;
- }
- /**********************************************************************
- * WM_LBUTTONDOWN & WM_RBUTTONDOWN
- *
- * Capture the mouse, set the tracking mode depending on the mouse
- * location in world coordinates, reset the mouse position.
- *
- **********************************************************************/
- case WM_LBUTTONDOWN:
- case WM_RBUTTONDOWN: {
- POINT newmouScreen;
- POINT mouWorld;
- mouWorld.x = LOWORD(lParam);
- mouWorld.y = HIWORD(lParam);
- DPtoLP (pto->hdc, &mouWorld, 1);
- /* upper left hand corner. right button is no-op. */
- if ((mouWorld.x <= (pto->rect.right / 2)) &&
- (mouWorld.y <= (pto->rect.bottom / 2))) {
- if (msg == WM_RBUTTONDOWN) return NULL;
- pto->Mode = TMMOVE;
- newmouScreen.x = pto->rect.left;
- newmouScreen.y = pto->rect.top;
- /* lower left hand corner */
- } else if ((mouWorld.x <= (pto->rect.right / 2)) &&
- (mouWorld.y > (pto->rect.bottom / 2))) {
- pto->Mode = (msg == WM_RBUTTONDOWN) ? TMSHEARY : TMSIZEY;
- newmouScreen.x = pto->rect.left;
- newmouScreen.y = pto->rect.bottom;
- /* upper right hand corner */
- } else if ((mouWorld.x > (pto->rect.right / 2)) &&
- (mouWorld.y <= (pto->rect.bottom / 2))) {
- pto->Mode = (msg == WM_RBUTTONDOWN) ? TMSHEARX : TMSIZEX;
- newmouScreen.x = pto->rect.right;
- newmouScreen.y = pto->rect.top;
- /* lower right hand corner */
- } else if ((mouWorld.x > (pto->rect.right / 2)) &&
- (mouWorld.y > (pto->rect.bottom / 2))) {
- pto->Mode = (msg == WM_RBUTTONDOWN) ? TMROTATE : TMSIZEXY;
- newmouScreen.x = pto->rect.right;
- newmouScreen.y = pto->rect.bottom;
- }
- if (! (pto->Mode & pto->allowedModes)) {
- pto->Mode = TMNONE;
- return NULL;
- }
- SetCapture(hwnd);
- LPtoDP (pto->hdc, &newmouScreen, 1);
- ClientToScreen (hwnd, &newmouScreen);
- SetCursorPos (newmouScreen.x,newmouScreen.y);
- GetWorldTransform (pto->hdc, &pto->xfmDown);
- } return NULL;
- /**********************************************************************
- * WM_MOUSEMOVE
- *
- * this is where almost all of the interesting calculation is done.
- * First clip the mouse location to be in rectClip, then
- * call MouseMove() to handle the different tracking modes.
- **********************************************************************/
- case WM_MOUSEMOVE: {
- if ((short) LOWORD(lParam) < (short)pto->rectClip.left)
- lParam = MAKELONG ((WORD)pto->rectClip.left, HIWORD(lParam));
- if (LOWORD(lParam) > (WORD)pto->rectClip.right)
- lParam = MAKELONG ((WORD)pto->rectClip.right, HIWORD(lParam));
- if ((short) HIWORD(lParam) < (short)pto->rectClip.top)
- lParam = MAKELONG (LOWORD(lParam), (WORD)pto->rectClip.top);
- if (HIWORD(lParam) > (WORD)pto->rectClip.bottom)
- lParam = MAKELONG (LOWORD(lParam),(WORD)pto->rectClip.bottom);
- MouseMove (pto, msg, hwnd, lParam);
- } return NULL;
- /**********************************************************************
- * WM_RBUTTONUP & WM_LBUTTONUP
- *
- * simply release the mouse capture, and set the mode to TMNONE.
- **********************************************************************/
- case WM_RBUTTONUP:
- case WM_LBUTTONUP: {
- if (pto->Mode) {
- ReleaseCapture();
- pto->Mode = TMNONE;
- }
- } return NULL;
- } /* end switch(msg) */
- }
- /**************************************************************************
- * function: MouseMove()
- *
- * input parameters:
- * pto - pointer to a track object.
- * msg - not used.
- * hwnd - Window handle for the window the track object exists within.
- * lParam - Usually fourth param to window proc. varies based on msg.
- *
- * The tracking behavior which the user observers when moving the mouse
- * is based on the current tracking mode of the object. This is usually
- * determined on the mouse down event (c.f. TM*). First erase the old
- * object, then figure out the change to the transform matrix, finally
- * change the world transform matrix and redraw the object.
- *
- * Tranform:
- * ( eM11 eM12 0 )
- * ( eM21 eM22 0 )
- * ( eDx eDy 1 )
- *
- * xDevice = (xWorld * eM11) + (yWorld * eM21) + eDx
- * yDevice = (xWorld * eM12) + (yWorld * eM22) + eDy
- *
- * In this routine the Device (mouse location) and World (rectangle corner)
- * points are known. Therefore, the two equations above are solved for
- * the desired matrix entry value (e.g. eM11, 1M12, ... eDy). The tracking
- * mode determines which one of these entries may be changed. E.g. scaling
- * in X modifies eM11 while shearing in X modifies eM12. So rather than
- * using the world transform to map from world to device points, we are
- * back-computing the proper contents of the world transform.
- *
- **************************************************************************/
- VOID MouseMove(PTrackObject pto, int msg, HWND hwnd, LONG lParam)
- {
- POINT mouWorld, mouDevice, orgDevice;
- UNREFERENCED_PARAMETER(msg);
- doTrackObject(pto, TROB_PAINT, hwnd, lParam);
- mouDevice.x = mouWorld.x = LOWORD(lParam);
- mouDevice.y = mouWorld.y = HIWORD(lParam);
- SetWorldTransform(pto->hdc, &pto->xfmDown);
- DPtoLP (pto->hdc, &mouWorld, 1);
- /* offset the mouse device point for the viewport's origin. */
- GetViewportOrgEx (pto->hdc, &orgDevice);
- mouDevice.x -= orgDevice.x;
- mouDevice.y -= orgDevice.y;
- GetWorldTransform(pto->hdc, &pto->xfmChange);
- switch (pto->Mode) {
- /*******************************************************
- * ( 1 xShear 0 )
- * ( 0 1 0 )
- * ( 0 0 1 )
- *
- * xWorld = rect.left == 0;
- *******************************************************/
- case TMSHEARX: {
- pto->xfmChange.eM12 = (float) mouDevice.y;
- pto->xfmChange.eM12 -=pto->xfmChange.eDy;
- pto->xfmChange.eM12 /=(float) pto->rect.right ;
- SetWorldTransform (pto->hdc, &pto->xfmChange);
- } break;
- /*******************************************************
- * ( 1 0 0 )
- * ( yShear 1 0 )
- * ( 0 0 1 )
- *
- * yWorld = rect.top == 0;
- *******************************************************/
- case TMSHEARY: {
- pto->xfmChange.eM21 = (float) mouDevice.x;
- pto->xfmChange.eM21 -=pto->xfmChange.eDx;
- pto->xfmChange.eM21 /=(float) pto->rect.bottom ;
- SetWorldTransform (pto->hdc, &pto->xfmChange);
- } break;
- /*******************************************************
- * ( cos(a) -sin(a) 0 )
- * ( sin(a) cos(a) 0 )
- * ( 0 0 1 )
- *
- * a == rotation angle. Since mouse in in lower right,
- * we need to shift this back 45 degrees (assuming that
- * straight down is 0 degrees). Thus we actually compute
- * cos(a) = cos(b - 45) = cos(b)sin(45) + cos(45)sin(45)
- * where b is angle from the origin to the mouse (x,y)
- * cos(45) = sin(45) ~= 0.707107
- * cos(b) = y/r sin(b) = x/r
- *
- *******************************************************/
- case TMROTATE: {
- float r;
- /* translate back to the origin. */
- pto->xfmChange.eDx = pto->xfmChange.eDy = (float)0.0;
- SetWorldTransform (pto->hdc, &pto->xfmChange);
- /* rotate about the origin. */
- r = (float) sqrt( (double)(mouWorld.x * mouWorld.x) +
- (double)(mouWorld.y * mouWorld.y));
- pto->xfmChange.eM11 = (float) mouWorld.y / r;
- pto->xfmChange.eM11 += (float) mouWorld.x / r;
- pto->xfmChange.eM11 *= (float) 0.707107;
- pto->xfmChange.eM22 = pto->xfmChange.eM11;
- pto->xfmChange.eM12 = (float) mouWorld.y / r;
- pto->xfmChange.eM12 -= (float) mouWorld.x / r;
- pto->xfmChange.eM12 *= (float) 0.707107;
- pto->xfmChange.eM21 = -pto->xfmChange.eM12;
- pto->xfmChange.eDx = pto->xfmChange.eDy = (float)0.0;
- ModifyWorldTransform (pto->hdc, &pto->xfmChange, MWT_RIGHTMULTIPLY);
- /* translate back to the original offset. */
- pto->xfmChange.eM11 =
- pto->xfmChange.eM22 = (float) 1.0;
- pto->xfmChange.eM12 =
- pto->xfmChange.eM21 = (float) 0.0;
- pto->xfmChange.eDx = pto->xfmDown.eDx;
- pto->xfmChange.eDy = pto->xfmDown.eDy;
- ModifyWorldTransform (pto->hdc, &pto->xfmChange, MWT_RIGHTMULTIPLY);
- GetWorldTransform (pto->hdc, &pto->xfmChange);
- } break;
- /*******************************************************
- * ( Size X 0 0 )
- * ( 0 Size Y 0 )
- * ( 0 0 1 )
- *
- *******************************************************/
- case TMSIZEXY: {
- pto->xfmChange.eM11 = (float) mouDevice.x;
- pto->xfmChange.eM11 -=pto->xfmChange.eDx;
- pto->xfmChange.eM11 -=((float) pto->rect.bottom*pto->xfmChange.eM21);
- pto->xfmChange.eM11 /=(float) pto->rect.right ;
- if (fabs(pto->xfmChange.eM11) < EPSILON) // HACK. system bug ?
- pto->xfmChange.eM11 = EPSILON;
- pto->xfmChange.eM22 = (float) mouDevice.y;
- pto->xfmChange.eM22 -=pto->xfmChange.eDy;
- pto->xfmChange.eM22 -=((float) pto->rect.right*pto->xfmChange.eM12);
- pto->xfmChange.eM22 /=(float) pto->rect.bottom ;
- if (fabs(pto->xfmChange.eM22) < EPSILON) // HACK. system bug ?
- pto->xfmChange.eM22 = EPSILON;
- SetWorldTransform (pto->hdc, &pto->xfmChange);
- } break;
- /*******************************************************
- * ( Size X 0 0 )
- * ( 0 1 0 )
- * ( 0 0 1 )
- *
- * yWorld = rect.top == 0;
- *******************************************************/
- case TMSIZEX: {
- pto->xfmChange.eM11 = (float) mouDevice.x;
- pto->xfmChange.eM11 -=pto->xfmChange.eDx;
- pto->xfmChange.eM11 /=(float) pto->rect.right ;
- if (fabs(pto->xfmChange.eM11) < EPSILON) // HACK. system bug ?
- pto->xfmChange.eM11 = EPSILON;
- SetWorldTransform (pto->hdc, &pto->xfmChange);
- } break;
- /*******************************************************
- * ( 1 0 0 )
- * ( 0 Size Y 0 )
- * ( 0 0 1 )
- *
- * xWorld = rect.left == 0;
- *******************************************************/
- case TMSIZEY: {
- pto->xfmChange.eM22 = (float) mouDevice.y;
- pto->xfmChange.eM22 -=pto->xfmChange.eDy;
- pto->xfmChange.eM22 /=(float) pto->rect.bottom ;
- if (fabs(pto->xfmChange.eM22) < EPSILON) // HACK. system bug ?
- pto->xfmChange.eM22 = EPSILON;
- SetWorldTransform (pto->hdc, &pto->xfmChange);
- } break;
- /*******************************************************
- * ( 1 0 0 )
- * ( 0 1 0 )
- * ( Move x Move y 1 )
- *
- * xWorld = rect.left == 0;
- * yWorld = rect.top == 0;
- *******************************************************/
- case TMMOVE: {
- pto->xfmChange.eDx = (float) mouDevice.x ;
- pto->xfmChange.eDy = (float) mouDevice.y ;
- SetWorldTransform (pto->hdc, &pto->xfmChange);
- } break;
- } /* end switch */
- doTrackObject(pto, TROB_PAINT, hwnd, lParam);
- return;
- }