Annotation of q_a/samples/maskblt/track.c, revision 1.1

1.1     ! root        1: 
        !             2: /******************************************************************************\
        !             3: *       This is a part of the Microsoft Source Code Samples. 
        !             4: *       Copyright (C) 1993 Microsoft Corporation.
        !             5: *       All rights reserved. 
        !             6: *       This source code is only intended as a supplement to 
        !             7: *       Microsoft Development Tools and/or WinHelp documentation.
        !             8: *       See these sources for detailed information regarding the 
        !             9: *       Microsoft samples programs.
        !            10: \******************************************************************************/
        !            11: 
        !            12: /**************************************************************************\
        !            13: *  track.c -- support for direct manipulation of parallelogram object.
        !            14: \**************************************************************************/
        !            15: 
        !            16: #include <windows.h>
        !            17: #include <math.h>
        !            18: #include "track.h"
        !            19: 
        !            20: #define EPSILON  (float) 0.0001
        !            21: #define RECTSIZE  60
        !            22: 
        !            23: 
        !            24: 
        !            25: /**************************************************************************\
        !            26: *
        !            27: *  function:  doTrackObject()
        !            28: *
        !            29: *  input parameters:
        !            30: *   pto -  pointer to a track object.
        !            31: *   msg -  message selecting what action to take.  Values may include WM_*'s
        !            32: *           (see case statements below for more information.)
        !            33: *   hwnd - Window handle for the window the track object exists within.
        !            34: *   lParam - Usually fourth param to window proc. varies based on msg.
        !            35: *
        !            36: *  global variables:  none.
        !            37: *
        !            38: *  coordinate spaces:  There are three coordinate spaces of interest here,
        !            39: *   and this routine is frequently switching between them...
        !            40: *
        !            41: *           WORLD                   DEVICE                  SCREEN
        !            42: *
        !            43: *      object coordinates       input mouse pos       used w/ SetCursorPos()
        !            44: *         (pto->rect)          (lParam for WM_*)
        !            45: *
        !            46: *             ----->  LPtoDP() ---->    ----> ClientToScreen() -->
        !            47: *             <-----  DPtoLP() <----    <---- ScreenToClient() <--
        !            48: *
        !            49: *   in addition, the HDC has an offset origin.  Device coordinates for the
        !            50: *   mouse (lParam) never take this into account, but it is necessary to
        !            51: *   translate them in order to get direct manipulation right.
        !            52: *
        !            53: \**************************************************************************/
        !            54: PTrackObject doTrackObject(PTrackObject pto, int msg, HWND hwnd, LONG lParam)
        !            55: {
        !            56:   if ((pto == NULL) && (msg != TROB_NEW))  return NULL;
        !            57: 
        !            58:   switch (msg) {
        !            59: 
        !            60: 
        !            61:     /**********************************************************************\
        !            62:     *  TROB_NEW
        !            63:     *
        !            64:     * Allocate new PTrackObject structure.  Fill in default values
        !            65:     *  for the fields of the structure.  Set up the HDC correctly.
        !            66:     * return - pointer to the new object.
        !            67:     \**********************************************************************/
        !            68:     case  TROB_NEW: {
        !            69:         PTrackObject  pto;
        !            70: 
        !            71:         /* with LPTR returned value is a pointer. */
        !            72:         pto = (PTrackObject) LocalAlloc (LPTR, sizeof (TrackObject));
        !            73: 
        !            74:         /* initialize the HDC and other fields. */
        !            75:         pto->hdc = GetDC (hwnd);
        !            76:         SetGraphicsMode (pto->hdc, GM_ADVANCED);
        !            77:         SetROP2(pto->hdc, R2_NOT);
        !            78:         SelectObject (pto->hdc, GetStockObject (NULL_BRUSH));
        !            79:         pto->Mode = TMNONE;
        !            80:         pto->allowedModes = TMMOVE | TMSIZEXY;
        !            81: 
        !            82:         GetWorldTransform (pto->hdc, &(pto->xfmChange));
        !            83: 
        !            84:         /* initialize the size. */
        !            85:         pto->rect.top = pto->rect.left = 0;
        !            86:         pto->rect.bottom = pto->rect.right = RECTSIZE;
        !            87: 
        !            88:         return (pto);
        !            89:     }
        !            90: 
        !            91: 
        !            92: 
        !            93:     /**********************************************************************\
        !            94:     *  TROB_DELETE
        !            95:     *
        !            96:     * Complement of TROB_NEW.  Free up the memory allocated for the object.
        !            97:     \**********************************************************************/
        !            98:     case  TROB_DELETE:
        !            99:         doTrackObject (pto, TROB_PAINT, hwnd, lParam);
        !           100:         ReleaseDC (hwnd, pto->hdc);
        !           101:         LocalFree (LocalHandle ((LPSTR)pto));
        !           102:     return NULL;
        !           103: 
        !           104: 
        !           105: 
        !           106:     /**********************************************************************\
        !           107:     *  TROB_PAINT
        !           108:     *
        !           109:     * Paint the object into its hdc.  Called half the time to erase
        !           110:     *  the object, and half the time to redraw it.
        !           111:     \**********************************************************************/
        !           112:     case TROB_PAINT: {
        !           113:         MoveToEx (pto->hdc, pto->rect.right, pto->rect.top, NULL);
        !           114:         LineTo (pto->hdc,  pto->rect.left, pto->rect.top);
        !           115:         LineTo (pto->hdc,  pto->rect.left, pto->rect.bottom);
        !           116: 
        !           117:         if (pto->allowedModes & TMSIZEXY) {
        !           118:           LineTo (pto->hdc,  pto->rect.right, pto->rect.bottom);
        !           119:           LineTo (pto->hdc,  pto->rect.right, pto->rect.top);
        !           120:         }
        !           121: 
        !           122:         if (pto->allowedModes & TMROTATE) {
        !           123:           MoveToEx (pto->hdc, pto->rect.left, pto->rect.bottom/ 4, NULL);
        !           124:           AngleArc (pto->hdc, pto->rect.left, pto->rect.top,
        !           125:                  (DWORD) pto->rect.bottom/ 4, (float) 270.0, (float) 90.0);
        !           126:         }
        !           127: 
        !           128:     } return NULL;
        !           129: 
        !           130: 
        !           131: 
        !           132:     /**********************************************************************\
        !           133:     *  TROB_HITTEST
        !           134:     *
        !           135:     * Check the point sent in in the lParam to see if it lays within
        !           136:     *  the bounds of the objects defining rectangle.
        !           137:     * return - pointer to the object iff the point is in rectangle,
        !           138:     *  otherwise return NULL.
        !           139:     \**********************************************************************/
        !           140:     case TROB_HITTEST:{
        !           141:         POINT  mouWorld;
        !           142:         mouWorld.x = LOWORD(lParam);
        !           143:         mouWorld.y = HIWORD(lParam);
        !           144: 
        !           145:         DPtoLP (pto->hdc, &mouWorld, 1);
        !           146: 
        !           147:         if (PtInRect (&pto->rect, mouWorld))  return pto;
        !           148:         else  return NULL;
        !           149:     }
        !           150: 
        !           151: 
        !           152: 
        !           153:     /**********************************************************************\
        !           154:     *  WM_LBUTTONDOWN &  WM_RBUTTONDOWN
        !           155:     *
        !           156:     * Capture the mouse, set the tracking mode depending on the mouse
        !           157:     *  location in world coordinates, reset the mouse position.
        !           158:     *
        !           159:     \**********************************************************************/
        !           160:     case WM_LBUTTONDOWN:
        !           161:     case WM_RBUTTONDOWN: {
        !           162:       POINT  newmouScreen;
        !           163:       POINT  mouWorld;
        !           164: 
        !           165:       mouWorld.x = LOWORD(lParam);
        !           166:       mouWorld.y = HIWORD(lParam);
        !           167:       DPtoLP (pto->hdc, &mouWorld, 1);
        !           168: 
        !           169:       /* upper left hand corner. right button is no-op. */
        !           170:       if ((mouWorld.x <= (pto->rect.right  / 2)) &&
        !           171:           (mouWorld.y <= (pto->rect.bottom / 2))) {
        !           172:           if (msg == WM_RBUTTONDOWN) return NULL;
        !           173:           pto->Mode = TMMOVE;
        !           174:           newmouScreen.x = pto->rect.left;
        !           175:           newmouScreen.y = pto->rect.top;
        !           176: 
        !           177:       /* lower left hand corner */
        !           178:       } else if ((mouWorld.x <= (pto->rect.right  / 2)) &&
        !           179:           (mouWorld.y > (pto->rect.bottom / 2))) {
        !           180: 
        !           181:           pto->Mode = (msg == WM_RBUTTONDOWN) ? TMSHEARY : TMSIZEY;
        !           182:           newmouScreen.x = pto->rect.left;
        !           183:           newmouScreen.y = pto->rect.bottom;
        !           184: 
        !           185:       /* upper right hand corner */
        !           186:       } else if ((mouWorld.x > (pto->rect.right  / 2)) &&
        !           187:           (mouWorld.y <= (pto->rect.bottom / 2))) {
        !           188: 
        !           189:           pto->Mode = (msg == WM_RBUTTONDOWN) ? TMSHEARX : TMSIZEX;
        !           190:           newmouScreen.x = pto->rect.right;
        !           191:           newmouScreen.y = pto->rect.top;
        !           192: 
        !           193:       /* lower right hand corner */
        !           194:       } else if ((mouWorld.x > (pto->rect.right  / 2)) &&
        !           195:           (mouWorld.y > (pto->rect.bottom / 2))) {
        !           196: 
        !           197:           pto->Mode = (msg == WM_RBUTTONDOWN) ? TMROTATE : TMSIZEXY;
        !           198:           newmouScreen.x = pto->rect.right;
        !           199:           newmouScreen.y = pto->rect.bottom;
        !           200:       }
        !           201: 
        !           202:       if (! (pto->Mode & pto->allowedModes)) {
        !           203:         pto->Mode = TMNONE;
        !           204:         return NULL;
        !           205:       }
        !           206: 
        !           207:       SetCapture(hwnd);
        !           208:       LPtoDP (pto->hdc, &newmouScreen, 1);
        !           209:       ClientToScreen (hwnd, &newmouScreen);
        !           210:       SetCursorPos (newmouScreen.x,newmouScreen.y);
        !           211: 
        !           212:       GetWorldTransform (pto->hdc, &pto->xfmDown);
        !           213:     } return NULL;
        !           214: 
        !           215: 
        !           216: 
        !           217:     /**********************************************************************\
        !           218:     *  WM_MOUSEMOVE
        !           219:     *
        !           220:     * this is where almost all of the interesting calculation is done.
        !           221:     *  First clip the mouse location to be in rectClip, then
        !           222:     *  call MouseMove() to handle the different tracking modes.
        !           223:     \**********************************************************************/
        !           224:     case WM_MOUSEMOVE: {
        !           225:       if ((short) LOWORD(lParam) < (short)pto->rectClip.left)
        !           226:         lParam = MAKELONG ((WORD)pto->rectClip.left, HIWORD(lParam));
        !           227: 
        !           228:       if (LOWORD(lParam) > (WORD)pto->rectClip.right)
        !           229:         lParam = MAKELONG ((WORD)pto->rectClip.right, HIWORD(lParam));
        !           230: 
        !           231:       if ((short) HIWORD(lParam) < (short)pto->rectClip.top)
        !           232:         lParam = MAKELONG (LOWORD(lParam), (WORD)pto->rectClip.top);
        !           233: 
        !           234:       if (HIWORD(lParam) > (WORD)pto->rectClip.bottom)
        !           235:         lParam = MAKELONG (LOWORD(lParam),(WORD)pto->rectClip.bottom);
        !           236: 
        !           237:       MouseMove (pto, msg, hwnd, lParam);
        !           238: 
        !           239:     } return NULL;
        !           240: 
        !           241: 
        !           242: 
        !           243:     /**********************************************************************\
        !           244:     *  WM_RBUTTONUP & WM_LBUTTONUP
        !           245:     *
        !           246:     * simply release the mouse capture, and set the mode to TMNONE.
        !           247:     \**********************************************************************/
        !           248:     case WM_RBUTTONUP:
        !           249:     case WM_LBUTTONUP: {
        !           250:       if (pto->Mode) {
        !           251:          ReleaseCapture();
        !           252:          pto->Mode = TMNONE;
        !           253:       }
        !           254:     } return NULL;
        !           255: 
        !           256:   }  /* end switch(msg) */
        !           257: }
        !           258: 
        !           259: 
        !           260: 
        !           261: 
        !           262: 
        !           263: 
        !           264: /**************************************************************************\
        !           265: *  function:  MouseMove()
        !           266: *
        !           267: *  input parameters:
        !           268: *   pto -  pointer to a track object.
        !           269: *   msg -  not used.
        !           270: *   hwnd - Window handle for the window the track object exists within.
        !           271: *   lParam - Usually fourth param to window proc. varies based on msg.
        !           272: *
        !           273: *  The tracking behavior which the user observers when moving the mouse
        !           274: *   is based on the current tracking mode of the object.  This is usually
        !           275: *   determined on the mouse down event (c.f. TM*).  First erase the old
        !           276: *   object, then figure out the change to the transform matrix, finally
        !           277: *   change the world transform matrix and redraw the object.
        !           278: *
        !           279: *  Tranform:
        !           280: *    (    eM11        eM12        0   )
        !           281: *    (    eM21        eM22        0   )
        !           282: *    (    eDx         eDy         1   )
        !           283: *
        !           284: *   xDevice = (xWorld * eM11) + (yWorld * eM21) + eDx
        !           285: *   yDevice = (xWorld * eM12) + (yWorld * eM22) + eDy
        !           286: *
        !           287: *   In this routine the Device (mouse location) and World (rectangle corner)
        !           288: *   points are known.  Therefore, the two equations above are solved for
        !           289: *   the desired matrix entry value (e.g. eM11, 1M12, ... eDy).  The tracking
        !           290: *   mode determines which one of these entries may be changed.  E.g. scaling
        !           291: *   in X modifies eM11 while shearing in X modifies eM12.  So rather than
        !           292: *   using the world transform to map from world to device points, we are
        !           293: *   back-computing the proper contents of the world transform.
        !           294: *
        !           295: \**************************************************************************/
        !           296: VOID MouseMove(PTrackObject pto, int msg, HWND hwnd, LONG lParam)
        !           297: {
        !           298: POINT  mouWorld, mouDevice, orgDevice;
        !           299: 
        !           300:     UNREFERENCED_PARAMETER(msg);
        !           301: 
        !           302:     doTrackObject(pto, TROB_PAINT, hwnd, lParam);
        !           303:     mouDevice.x = mouWorld.x = LOWORD(lParam);
        !           304:     mouDevice.y = mouWorld.y = HIWORD(lParam);
        !           305: 
        !           306:     SetWorldTransform(pto->hdc, &pto->xfmDown);
        !           307:     DPtoLP (pto->hdc, &mouWorld, 1);
        !           308: 
        !           309:     /* offset the mouse device point for the viewport's origin. */
        !           310:     GetViewportOrgEx (pto->hdc, &orgDevice);
        !           311:     mouDevice.x -= orgDevice.x;
        !           312:     mouDevice.y -= orgDevice.y;
        !           313: 
        !           314:     GetWorldTransform(pto->hdc, &pto->xfmChange);
        !           315: 
        !           316:     switch (pto->Mode) {
        !           317:       /*******************************************************\
        !           318:       *    (     1         xShear       0   )
        !           319:       *    (     0           1          0   )
        !           320:       *    (     0           0          1   )
        !           321:       *
        !           322:       * xWorld = rect.left == 0;
        !           323:       \*******************************************************/
        !           324:       case TMSHEARX: {
        !           325:         pto->xfmChange.eM12 = (float) mouDevice.y;
        !           326:         pto->xfmChange.eM12 -=pto->xfmChange.eDy;
        !           327:         pto->xfmChange.eM12 /=(float) pto->rect.right ;
        !           328:         SetWorldTransform (pto->hdc, &pto->xfmChange);
        !           329:       } break;
        !           330: 
        !           331: 
        !           332:       /*******************************************************\
        !           333:       *    (     1           0          0   )
        !           334:       *    (   yShear        1          0   )
        !           335:       *    (     0           0          1   )
        !           336:       *
        !           337:       * yWorld = rect.top == 0;
        !           338:       \*******************************************************/
        !           339:       case TMSHEARY: {
        !           340:         pto->xfmChange.eM21 = (float) mouDevice.x;
        !           341:         pto->xfmChange.eM21 -=pto->xfmChange.eDx;
        !           342:         pto->xfmChange.eM21 /=(float) pto->rect.bottom ;
        !           343:         SetWorldTransform (pto->hdc, &pto->xfmChange);
        !           344: 
        !           345:       } break;
        !           346: 
        !           347: 
        !           348:       /*******************************************************\
        !           349:       *    (   cos(a)      -sin(a)      0   )
        !           350:       *    (   sin(a)       cos(a)      0   )
        !           351:       *    (     0           0          1   )
        !           352:       *
        !           353:       * a == rotation angle.  Since mouse in in lower right,
        !           354:       *  we need to shift this back 45 degrees (assuming that
        !           355:       *  straight down is 0 degrees).  Thus we actually compute
        !           356:       *  cos(a) = cos(b - 45) = cos(b)sin(45) + cos(45)sin(45)
        !           357:       *  where b is angle from the origin to the mouse (x,y)
        !           358:       *  cos(45) = sin(45) ~= 0.707107
        !           359:       *  cos(b) = y/r    sin(b) = x/r
        !           360:       *
        !           361:       \*******************************************************/
        !           362:       case TMROTATE: {
        !           363:         float r;
        !           364: 
        !           365:         /* translate back to the origin. */
        !           366:         pto->xfmChange.eDx = pto->xfmChange.eDy = (float)0.0;
        !           367:         SetWorldTransform (pto->hdc, &pto->xfmChange);
        !           368: 
        !           369:         /* rotate about the origin. */
        !           370:         r = (float) sqrt( (double)(mouWorld.x * mouWorld.x) +
        !           371:                           (double)(mouWorld.y * mouWorld.y));
        !           372: 
        !           373:         pto->xfmChange.eM11 = (float) mouWorld.y / r;
        !           374:         pto->xfmChange.eM11 += (float) mouWorld.x / r;
        !           375:         pto->xfmChange.eM11 *= (float) 0.707107;
        !           376:         pto->xfmChange.eM22 = pto->xfmChange.eM11;
        !           377: 
        !           378:         pto->xfmChange.eM12 = (float) mouWorld.y / r;
        !           379:         pto->xfmChange.eM12 -= (float) mouWorld.x / r;
        !           380:         pto->xfmChange.eM12 *= (float) 0.707107;
        !           381:         pto->xfmChange.eM21 = -pto->xfmChange.eM12;
        !           382: 
        !           383:         pto->xfmChange.eDx = pto->xfmChange.eDy = (float)0.0;
        !           384: 
        !           385:         ModifyWorldTransform (pto->hdc, &pto->xfmChange, MWT_RIGHTMULTIPLY);
        !           386: 
        !           387:         /* translate back to the original offset. */
        !           388:         pto->xfmChange.eM11 =
        !           389:         pto->xfmChange.eM22 = (float) 1.0;
        !           390:         pto->xfmChange.eM12 =
        !           391:         pto->xfmChange.eM21 = (float) 0.0;
        !           392: 
        !           393:         pto->xfmChange.eDx = pto->xfmDown.eDx;
        !           394:         pto->xfmChange.eDy = pto->xfmDown.eDy;
        !           395:         ModifyWorldTransform (pto->hdc, &pto->xfmChange, MWT_RIGHTMULTIPLY);
        !           396:         GetWorldTransform (pto->hdc, &pto->xfmChange);
        !           397:       } break;
        !           398: 
        !           399: 
        !           400:       /*******************************************************\
        !           401:       *    (  Size X         0          0   )
        !           402:       *    (     0        Size Y        0   )
        !           403:       *    (     0           0          1   )
        !           404:       *
        !           405:       \*******************************************************/
        !           406:       case TMSIZEXY: {
        !           407:         pto->xfmChange.eM11 = (float) mouDevice.x;
        !           408:         pto->xfmChange.eM11 -=pto->xfmChange.eDx;
        !           409:         pto->xfmChange.eM11 -=((float) pto->rect.bottom*pto->xfmChange.eM21);
        !           410:         pto->xfmChange.eM11 /=(float) pto->rect.right ;
        !           411:         if (fabs(pto->xfmChange.eM11) < EPSILON)  // HACK.  system bug ?
        !           412:            pto->xfmChange.eM11 = EPSILON;
        !           413: 
        !           414:         pto->xfmChange.eM22 = (float) mouDevice.y;
        !           415:         pto->xfmChange.eM22 -=pto->xfmChange.eDy;
        !           416:         pto->xfmChange.eM22 -=((float) pto->rect.right*pto->xfmChange.eM12);
        !           417:         pto->xfmChange.eM22 /=(float) pto->rect.bottom ;
        !           418:         if (fabs(pto->xfmChange.eM22) < EPSILON)  // HACK.  system bug ?
        !           419:            pto->xfmChange.eM22 = EPSILON;
        !           420:         SetWorldTransform (pto->hdc, &pto->xfmChange);
        !           421:       } break;
        !           422: 
        !           423: 
        !           424:       /*******************************************************\
        !           425:       *    (  Size X         0          0   )
        !           426:       *    (     0           1          0   )
        !           427:       *    (     0           0          1   )
        !           428:       *
        !           429:       * yWorld = rect.top == 0;
        !           430:       \*******************************************************/
        !           431:       case TMSIZEX: {
        !           432:         pto->xfmChange.eM11 = (float) mouDevice.x;
        !           433:         pto->xfmChange.eM11 -=pto->xfmChange.eDx;
        !           434:         pto->xfmChange.eM11 /=(float) pto->rect.right ;
        !           435:         if (fabs(pto->xfmChange.eM11) < EPSILON)  // HACK.  system bug ?
        !           436:            pto->xfmChange.eM11 = EPSILON;
        !           437: 
        !           438:         SetWorldTransform (pto->hdc, &pto->xfmChange);
        !           439:       } break;
        !           440: 
        !           441: 
        !           442:       /*******************************************************\
        !           443:       *    (     1           0          0   )
        !           444:       *    (     0        Size Y        0   )
        !           445:       *    (     0           0          1   )
        !           446:       *
        !           447:       * xWorld = rect.left == 0;
        !           448:       \*******************************************************/
        !           449:       case TMSIZEY: {
        !           450:         pto->xfmChange.eM22 = (float) mouDevice.y;
        !           451:         pto->xfmChange.eM22 -=pto->xfmChange.eDy;
        !           452:         pto->xfmChange.eM22 /=(float) pto->rect.bottom ;
        !           453:         if (fabs(pto->xfmChange.eM22) < EPSILON)  // HACK.  system bug ?
        !           454:            pto->xfmChange.eM22 = EPSILON;
        !           455:         SetWorldTransform (pto->hdc, &pto->xfmChange);
        !           456:       } break;
        !           457: 
        !           458: 
        !           459:       /*******************************************************\
        !           460:       *    (     1           0          0   )
        !           461:       *    (     0           1          0   )
        !           462:       *    (   Move x      Move y       1   )
        !           463:       *
        !           464:       * xWorld = rect.left == 0;
        !           465:       * yWorld = rect.top == 0;
        !           466:       \*******************************************************/
        !           467:       case TMMOVE: {
        !           468:         pto->xfmChange.eDx = (float) mouDevice.x ;
        !           469:         pto->xfmChange.eDy = (float) mouDevice.y ;
        !           470:         SetWorldTransform (pto->hdc, &pto->xfmChange);
        !           471:       } break;
        !           472:     } /* end switch */
        !           473: 
        !           474:     doTrackObject(pto, TROB_PAINT, hwnd, lParam);
        !           475: 
        !           476:     return;
        !           477:  }
        !           478: 

unix.superglobalmegacorp.com

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