Annotation of q_a/samples/streblt/track.c, revision 1.1.1.2

1.1.1.2 ! 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: 
1.1       root       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);
1.1.1.2 ! root       76:         SetGraphicsMode (pto->hdc, GM_ADVANCED);
1.1       root       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.