Annotation of mstools/samples/wxform/wxform.c, revision 1.1.1.2

1.1       root        1: /**************************************************************************\
                      2: *  wxform.c -- sample program demonstrating the new "World Transform."
                      3: *
1.1.1.2 ! root        4: *         Steve Firebaugh
        !             5: *         Microsoft Developer Support
        !             6: *         Copyright (c) 1992 Microsoft Corporation
        !             7: *
1.1       root        8: *  design:  There are a few global handles or pointers in this application,
                      9: *   and different routines to operate on them.  The obvious case of this
                     10: *   is the three window handles and their associated window procedures.
                     11: *   There is also a unique pointer to a track object and a routine to
                     12: *   operate on it (i.e. doTrackObject).  All communication is accomplished
                     13: *   by sending messages between these procedures.  Each window procedure,
                     14: *   and the track object procedure, operate on some set of messages which
                     15: *   include some of the standard Windows messages, and also miscellaneous
                     16: *   "WM_USER" messages (c.f. wxform.h).
                     17: \**************************************************************************/
                     18: 
                     19: #include <windows.h>
                     20: #include <string.h>
                     21: #include <stdio.h>
                     22: #include <math.h>
                     23: #include <limits.h>
                     24: #include "wxform.h"
                     25: 
                     26: 
                     27: 
                     28: /**************************************************************************\
                     29: *
                     30: *  function:  WinMain()
                     31: *
                     32: *  input parameters:  c.f. generic sample
                     33: *
                     34: \**************************************************************************/
                     35: int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                     36:                      LPSTR lpCmdLine, int nCmdShow)
                     37: {
                     38:     MSG   msg;
                     39:     HICON hicon;
                     40: 
                     41:     UNREFERENCED_PARAMETER( lpCmdLine );
                     42: 
                     43: 
                     44:     /* Check for previous instance.  If none, then register class. */
                     45:     if (!hPrevInstance) {
                     46:         WNDCLASS  wc;
                     47: 
                     48:         wc.style = NULL;
                     49:         wc.lpfnWndProc = (WNDPROC)MainWndProc;
                     50: 
                     51:         wc.cbClsExtra = 0;
                     52:         wc.cbWndExtra = 0;
                     53:         wc.hInstance = hInstance;
                     54:         wc.hIcon = LoadIcon(hInstance, "TransformIcon");
                     55:         wc.hCursor = LoadCursor(NULL, IDC_ARROW);
                     56:         wc.hbrBackground = GetStockObject(LTGRAY_BRUSH);
                     57:         wc.lpszMenuName =  NULL;
                     58:         wc.lpszClassName = "wxform";
                     59: 
                     60:         if (!RegisterClass(&wc)) return (FALSE);
                     61:     }  /* class registered o.k. */
                     62: 
                     63: 
                     64:     /* Create the main window.  Return false if CreateWindow() fails */
                     65:     hInst = hInstance;
                     66: 
                     67:     hwndMain = CreateWindow(
                     68:         "wxform",
                     69:         "World Transform Demonstration",
                     70:         WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
                     71:         CW_USEDEFAULT,
                     72:         CW_USEDEFAULT,
                     73:         CW_USEDEFAULT,
                     74:         CW_USEDEFAULT,
                     75:         NULL,
                     76:         NULL,
                     77:         hInstance,
                     78:         NULL);
                     79: 
                     80:     if (!hwndMain) return (FALSE);
                     81:     ShowWindow(hwndMain, nCmdShow);
                     82:     UpdateWindow(hwndMain);
                     83: 
                     84: 
                     85:     /* create a new track object and paint it for the first time. */
                     86:     ptoRect = doTrackObject(NULL, TROB_NEW, hwndMain, 0);
                     87:     doTrackObject(ptoRect, TROB_PAINT, hwndMain, 0);
                     88: 
                     89: 
                     90:     /* load and display dialog for the world transform matrix.
                     91:      *  then fill its entry fields.  Also, get the HICON from the
                     92:      *  main window and fill it into the dialog's class structure
                     93:      *  for this application.
                     94:      */
                     95:     hwndTransform = CreateDialog(hInst, "TransformDlg",
                     96:                                 hwndMain, (DLGPROC)TransformDlgProc);
                     97:     hicon = (HICON) GetClassLong (hwndMain, GCL_HICON);
                     98:     SetClassLong (hwndTransform, GCL_HICON, (LONG)hicon);
                     99:     showTransform = TRUE;
                    100:     SendMessage (hwndTransform, WM_PUTUPFLOATS, 0, (LONG) &ptoRect->xfmChange);
                    101: 
                    102:     /* load and display the dialog for the mouse position.
                    103:      *  minimize it initially.
                    104:      */
                    105:     hwndMouse = CreateDialog(hInst, "MouseDlg",
                    106:                             hwndMain, (DLGPROC)MouseDlgProc);
                    107:     ShowWindow (hwndMouse, SW_SHOWMINIMIZED);
                    108:     showMouse = FALSE;
                    109: 
                    110: 
                    111:     /* load and display the dialog with the direct manipulation help.
                    112:      *  minimize it initially.   (Don't need a unique window procedure.)
                    113:      */
                    114:     hwndHelp = CreateDialog(hInst, "helpDlg", hwndMain, NULL);
                    115:     ShowWindow (hwndHelp, SW_SHOWMINIMIZED);
                    116: 
                    117: 
                    118: 
                    119:     /* Loop getting messages and dispatching them. */
                    120:     while (GetMessage(&msg,NULL, NULL, NULL)) {
                    121:       if (!IsDialogMessage (hwndTransform, &msg))
                    122:       if (!IsDialogMessage (hwndMouse, &msg))
                    123:       if (!IsDialogMessage (hwndHelp, &msg)){
                    124:        TranslateMessage(&msg);
                    125:        DispatchMessage(&msg);
                    126:       }
                    127:     }
                    128:     return (msg.wParam);
                    129: }
                    130: 
                    131: 
                    132: 
                    133: 
                    134: 
                    135: 
                    136: 
                    137: 
                    138: 
                    139: /**************************************************************************\
                    140: *
                    141: *  function:  MainWndProc()
                    142: *
                    143: *  input parameters:  normal window procedure parameters.
                    144: *
                    145: *  global variables:
                    146: *   hwndTransform,
                    147: *   hwndMouse - information dialog box window handles.
                    148: *   showTransform,
                    149: *   showMouse - Booleans recording the retore/minimize state of the dialogs.
                    150: *   ptoRect   - pointer to track object in middle of screen.
                    151: *
                    152: \**************************************************************************/
1.1.1.2 ! root      153: LRESULT CALLBACK MainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1.1       root      154: {
                    155: static HANDLE hPenGrid;
                    156: 
                    157:   switch (message) {
                    158: 
                    159:     /**********************************************************************\
                    160:     *  WM_CREATE
                    161:     *
                    162:     * create a pen for later use.
                    163:     \**********************************************************************/
                    164:     case WM_CREATE:
                    165:       hPenGrid  = CreatePen (PS_SOLID, 1, GRIDCOLOR);
                    166:     break;
                    167: 
                    168: 
                    169: 
                    170:     /**********************************************************************\
                    171:     *  WM_DESTROY
                    172:     *
                    173:     * Complement of WM_CREATE.  send the track object the delete messages,
                    174:     *  then call PostQuitMessage.
                    175:     \**********************************************************************/
                    176:     case WM_DESTROY:
                    177:       DeleteObject(hPenGrid);
                    178:       doTrackObject(ptoRect, TROB_DELETE, hwnd, lParam);
                    179:       PostQuitMessage(0);
                    180:     break;
                    181: 
                    182: 
                    183: 
                    184:     /**********************************************************************\
                    185:     *  WM_SIZE
                    186:     *
                    187:     * Invalidate the whole window because we reset the origin on paint
                    188:     *  messages according to the size.  Also, send the track object a
                    189:     *  message so that it will also change its HDC's viewport origin.
                    190:     \**********************************************************************/
                    191:     case WM_SIZE:
                    192:         InvalidateRect (hwnd, NULL, TRUE);
                    193:         doTrackObject (ptoRect, TROB_CENTER, hwnd, lParam);
                    194:     break;
                    195: 
                    196: 
                    197: 
                    198:     /**********************************************************************\
                    199:     *  WM_PAINT
                    200:     *
                    201:     * First invalidate the whole window (forces the object to be painted
                    202:     *  fresh, and thus it won't XOR its old self out).  Then draw the
                    203:     *  grid and finally draw the object.
                    204:     \**********************************************************************/
                    205:     case WM_PAINT : {
                    206:       PAINTSTRUCT ps;
                    207:       HDC hdc;
                    208:       RECT  rect;
                    209:       POINT point;
                    210:       int i;
                    211: 
                    212:       InvalidateRect (hwnd, NULL, TRUE);
                    213: 
                    214:       hdc = BeginPaint(hwnd, &ps);
                    215: 
                    216:       CenterOrigin (hwnd, hdc);
                    217:       GetClientRect (hwnd, &rect);
                    218:       GetViewportOrgEx(hdc, &point);
                    219:       OffsetRect(&rect, -point.x, -point.y );
                    220: 
                    221: 
                    222:       /* Draw vertical lines.  Draw three at the origin. */
                    223:       SelectObject(hdc, hPenGrid);
                    224:       for (i = 0; i<= rect.right; i+=TICKSPACE){
                    225:         MoveToEx (hdc, i, rect.top, NULL);
                    226:         LineTo (hdc, i, rect.bottom);
                    227:         MoveToEx (hdc, -i, rect.top, NULL);
                    228:         LineTo (hdc, -i, rect.bottom);
                    229:       }
                    230:       MoveToEx (hdc, -1, rect.top, NULL);
                    231:       LineTo (hdc, -1, rect.bottom);
                    232:       MoveToEx (hdc, 1, rect.top, NULL);
                    233:       LineTo (hdc, 1, rect.bottom);
                    234: 
                    235: 
                    236:       /* Draw horizontal lines.  Draw three at the origin. */
                    237:       for (i = 0; i<= rect.bottom; i+=TICKSPACE){
                    238:         MoveToEx (hdc, rect.left, i, NULL);
                    239:         LineTo (hdc, rect.right, i);
                    240:         MoveToEx (hdc, rect.left, -i, NULL);
                    241:         LineTo (hdc, rect.right, -i);
                    242:       }
                    243:       MoveToEx (hdc, rect.left, -1, NULL);
                    244:       LineTo (hdc, rect.right, -1);
                    245:       MoveToEx (hdc, rect.left, 1, NULL);
                    246:       LineTo (hdc, rect.right, 1);
                    247: 
                    248:       doTrackObject(ptoRect, TROB_PAINT, hwnd, lParam);
                    249: 
                    250:       EndPaint (hwnd, &ps);
                    251:     } break;
                    252: 
                    253: 
                    254: 
                    255:     /**********************************************************************\
                    256:     *  WM_LBUTTONDOWN & WM_RBUTTONDOWN
                    257:     * On button down messages, hittest on the track object, and if
                    258:     *  it returns true, then send these messages to the track object.
                    259:     \**********************************************************************/
                    260:     case WM_RBUTTONDOWN:
                    261:     case WM_LBUTTONDOWN:
                    262:       if (doTrackObject(ptoRect, TROB_HITTEST, hwnd, lParam))
                    263:          doTrackObject(ptoRect, message, hwnd, lParam);
                    264:     break;
                    265: 
                    266: 
                    267: 
                    268:     /**********************************************************************\
                    269:     *  WM_LBUTTONUP & WM_RBUTTONDOWN & MW_MOUSEMOVE
                    270:     * If the track object is in a "tracking mode" then send it these messages.
                    271:     *  If the transform dialog is not minimized, fill it with numbers.
                    272:     *  If the mouse dialog is not minimized, fill it with numbers.
                    273:     \**********************************************************************/
                    274:     case WM_RBUTTONUP:
                    275:     case WM_LBUTTONUP:
                    276:     case WM_MOUSEMOVE:
                    277:       if (ptoRect->Mode) {
                    278:         doTrackObject(ptoRect, message, hwnd, lParam);
                    279:         if (showTransform)
                    280:           SendMessage (hwndTransform, WM_PUTUPFLOATS, 0,
                    281:                        (LONG) &ptoRect->xfmChange);
                    282:       }
                    283: 
                    284:       if (showMouse)
                    285:         SendMessage (hwndMouse, WM_PUTUPFLOATS, (DWORD) hwnd, lParam);
                    286: 
                    287:     break;
                    288: 
                    289: 
                    290:     default:
                    291:       return (DefWindowProc(hwnd, message, wParam, lParam));
                    292:   }
                    293:   return (NULL);
                    294: }
                    295: 
                    296: 
                    297: 
                    298: 
                    299: 
                    300: 
                    301: /**************************************************************************\
                    302: *
                    303: *  function:  TransformDlgProc()
                    304: *
                    305: *  input parameters:  normal window procedure parameters.
                    306: *
                    307: *  global variables:
                    308: *   showTransform  - TRUE if window is restored, FALSE if minimized.
                    309: *       maintain the value in this routine for other windows' use.
                    310: *   ptoRect - pointer to the track object.
                    311: *   showMouse, hwndMain.
                    312: *
                    313: *  nonstandard messages:
                    314: *   WM_PUTUPFLOATS - fill the entry fields with the contents of an XFORM.
                    315: \**************************************************************************/
1.1.1.2 ! root      316: LRESULT CALLBACK TransformDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1.1       root      317: {
                    318: XFORM  xform;
                    319: char buffer[MAXCHARS];
                    320: 
                    321: 
                    322:   switch (message) {
                    323: 
                    324: 
                    325:     /**********************************************************************\
                    326:     *  WM_INITDIALOG
                    327:     *
                    328:     * Fill the entry fields with sensible original values.
                    329:     \**********************************************************************/
                    330:     case WM_INITDIALOG:
                    331:       SetDlgItemText(hwnd, IDD_13, "0");
                    332:       SetDlgItemText(hwnd, IDD_23, "0");
                    333:       SetDlgItemText(hwnd, IDD_33, "1");
                    334:     return TRUE;
                    335: 
                    336: 
                    337:     /******************************************************************\
                    338:     *  WM_PUTUPFLOATS
                    339:     *
                    340:     *  lParam - pointer to an XFORM structure.
                    341:     *   fill the entry fields with the XFORM values.
                    342:     \******************************************************************/
                    343:     case WM_PUTUPFLOATS: {
                    344:       PXFORM pxform;
                    345:       pxform = (PXFORM) lParam;
                    346: 
                    347:       sprintf (buffer, FORMATFLOAT,pxform->eM11);
                    348:       SetDlgItemText(hwnd, IDD_EM11, buffer);
                    349:       sprintf (buffer, FORMATFLOAT,pxform->eM12);
                    350:       SetDlgItemText(hwnd, IDD_EM12, buffer);
                    351:       sprintf (buffer, FORMATFLOAT,pxform->eDx);
                    352:       SetDlgItemText(hwnd, IDD_EDX, buffer);
                    353: 
                    354:       sprintf (buffer, FORMATFLOAT,pxform->eM21);
                    355:       SetDlgItemText(hwnd, IDD_EM21, buffer);
                    356:       sprintf (buffer, FORMATFLOAT,pxform->eM22);
                    357:       SetDlgItemText(hwnd, IDD_EM22, buffer);
                    358:       sprintf (buffer, FORMATFLOAT,pxform->eDy);
                    359:       SetDlgItemText(hwnd, IDD_EDY, buffer);
                    360: 
                    361:     } return FALSE;
                    362: 
                    363: 
                    364: 
                    365:     /******************************************************************\
                    366:     *  WM_SIZE
                    367:     *
                    368:     *  toggle the global variable keeping track of the iconized state
                    369:     *   of this window.
                    370:     \******************************************************************/
                    371:     case WM_SIZE :
                    372:       if (wParam == SIZEICONIC)
                    373:         showTransform = FALSE;
                    374:       else {
                    375:         showTransform = TRUE;
                    376:         SendMessage (hwnd, WM_PUTUPFLOATS, 0, (LONG) &ptoRect->xfmChange);
                    377:       }
                    378:     return FALSE;
                    379: 
                    380: 
                    381:     case WM_COMMAND:
                    382:       /******************************************************************\
                    383:       *  WM_COMMAND,  IDD_SETXFORM
                    384:       *
                    385:       *  take the values from the entry field, fill them into an XFORM
                    386:       *   structure and then send the track object the message to use
                    387:       *   these values.  Finally, reformat and repaint the entry fields.
                    388:       \******************************************************************/
                    389:       if (LOWORD(wParam) == IDD_SETXFORM) {
                    390:         GetDlgItemText(hwnd, IDD_EM11, buffer, MAXCHARS);
                    391:         xform.eM11 = (float) atof (buffer);
                    392:         GetDlgItemText(hwnd, IDD_EM12, buffer, MAXCHARS);
                    393:         xform.eM12 = (float) atof (buffer);
                    394:         GetDlgItemText(hwnd, IDD_EDX, buffer, MAXCHARS);
                    395:         xform.eDx = (float) atof (buffer);
                    396: 
                    397:         GetDlgItemText(hwnd, IDD_EM21, buffer, MAXCHARS);
                    398:         xform.eM21 = (float) atof (buffer);
                    399:         GetDlgItemText(hwnd, IDD_EM22, buffer, MAXCHARS);
                    400:         xform.eM22 = (float) atof (buffer);
                    401:         GetDlgItemText(hwnd, IDD_EDY, buffer, MAXCHARS);
                    402:         xform.eDy = (float) atof (buffer);
                    403: 
                    404:         // HACK.  The WM_SIZE here is used to flush the GDI buffer in order
                    405:         //  to eliminate a very strange bug whereby DPtoLP() doesn't work.
                    406:         if (showMouse) SendMessage (hwndMain, WM_SIZE, NULL, NULL);
                    407: 
                    408: 
                    409:         doTrackObject (ptoRect, TROB_SETXFORM, hwnd, (LONG) &xform);
                    410:         SendMessage (hwnd, WM_PUTUPFLOATS, 0, (LONG) &xform);
                    411: 
                    412: 
                    413:       /******************************************************************\
                    414:       *  WM_COMMAND,  IDD_IDENTITY
                    415:       *
                    416:       *  fill a local XFORM structure with the identity matrix.  Now
                    417:       *   send the track object the message to use these values.
                    418:       *   Finally, reformat and repaint the entry fields.
                    419:       \******************************************************************/
                    420:       } else if (LOWORD(wParam) == IDD_IDENTITY) {
                    421:         xform.eM11 =
                    422:         xform.eM22 =  (float) 1.0;
                    423:         xform.eDx  =
                    424:         xform.eDy  =
                    425:         xform.eM12 =
                    426:         xform.eM21 =  (float) 0.0;
                    427: 
                    428:         // HACK.  The WM_SIZE here is used to flush the GDI buffer in order
                    429:         //  to eliminate a very strange bug whereby DPtoLP() doesn't work.
                    430:         if (showMouse) SendMessage (hwndMain, WM_SIZE, NULL, NULL);
                    431: 
                    432:         doTrackObject (ptoRect, TROB_SETXFORM, hwnd, (LONG) &xform);
                    433:         SendMessage (hwnd, WM_PUTUPFLOATS, 0, (LONG) &xform);
                    434:       } /* end WM_COMMAND */
                    435:     return FALSE;
                    436: 
                    437: 
                    438:   } /* end switch */
                    439:   return FALSE;
                    440: }
                    441: 
                    442: 
                    443: 
                    444: 
                    445: 
                    446: /**************************************************************************\
                    447: *
                    448: *  function:  MouseDlgProc()
                    449: *
                    450: *  input parameters:  normal window procedure parameters.
                    451: *
                    452: *  global variables:
                    453: *   showMouse  -- TRUE if window is restored, FALSE if minimized.
                    454: *       maintain the value in this routine for other windows' use.
                    455: *   ptoRect - pointer to the track object.  Needed for DPtoLP()
                    456: *
                    457: *  nonstandard messages:
                    458: *   WM_PUTUPFLOATS - fill the entry fields with the mouse position.
                    459: *
                    460: \**************************************************************************/
1.1.1.2 ! root      461: LRESULT CALLBACK MouseDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1.1       root      462: {
                    463: char buffer[MAXCHARS];
                    464: 
                    465:   switch (message) {
                    466: 
                    467:     /******************************************************************\
                    468:     *  WM_PUTUPFLOATS
                    469:     *
                    470:     *  wParam - contains the hwnd for the main window.
                    471:     *  lParam - contains the mouse position in device coordinates.
                    472:     *           (c.f. WM_MOUSEMOVE)
                    473:     \******************************************************************/
                    474:     case WM_PUTUPFLOATS: {
                    475:       POINT pScreen, pWorld;
                    476:       HWND hwndMain;
                    477: 
                    478:       hwndMain = (HWND) wParam;
                    479:       pScreen.x = pWorld.x = LOWORD(lParam);
                    480:       pScreen.y = pWorld.y  = HIWORD(lParam);
                    481: 
                    482:       sprintf (buffer, "%d", pScreen.x);
                    483:       SetDlgItemText(hwnd, IDD_DEVICEX, buffer);
                    484:       sprintf (buffer, "%d", pScreen.y);
                    485:       SetDlgItemText(hwnd, IDD_DEVICEY, buffer);
                    486: 
                    487:       ClientToScreen (hwndMain, &pScreen);
                    488:       sprintf (buffer, "%d", pScreen.x);
                    489:       SetDlgItemText(hwnd, IDD_SCREENX, buffer);
                    490:       sprintf (buffer, "%d", pScreen.y);
                    491:       SetDlgItemText(hwnd, IDD_SCREENY, buffer);
                    492: 
                    493:       DPtoLP (ptoRect->hdc, &pWorld, 1);
                    494:       sprintf (buffer, FORMATFLOAT, (float) pWorld.x);
                    495:       SetDlgItemText(hwnd, IDD_WORLDX , buffer);
                    496:       sprintf (buffer, FORMATFLOAT, (float) pWorld.y);
                    497:       SetDlgItemText(hwnd, IDD_WORLDY , buffer);
                    498: 
                    499:     } return FALSE;
                    500: 
                    501: 
                    502: 
                    503:     /******************************************************************\
                    504:     *  WM_SIZE
                    505:     *
                    506:     *  toggle the global variable keeping track of the iconized state
                    507:     *   of this window.
                    508:     \******************************************************************/
                    509:     case WM_SIZE :
                    510:       if (wParam == SIZEICONIC)
                    511:         showMouse = FALSE;
                    512:       else
                    513:         showMouse = TRUE;
                    514:     return FALSE;
                    515: 
                    516:   }
                    517:   return FALSE;
                    518: }
                    519: 
                    520: 
                    521: 
                    522: 
                    523: 
                    524: 
                    525: /**************************************************************************\
                    526: *  function:  CenterOrigin()
                    527: *
                    528: *  input parameters:
                    529: *   hwnd - window with client we want the center of.
                    530: *   hdc - device context which we set the Viewport origin of.
                    531: *
                    532: \**************************************************************************/
                    533: VOID CenterOrigin (HWND hwnd, HDC hdc)
                    534: {
                    535: RECT  rect;
                    536: POINT center;
                    537: 
                    538:     GetClientRect (hwnd, &rect);
                    539:     center.x = rect.right / 2;
                    540:     center.y = rect.bottom /2;
                    541: 
                    542:     SetViewportOrgEx (hdc, center.x, center.y, NULL);
                    543:     return;
                    544: }
                    545: 
                    546: 
                    547: 
                    548: 
                    549: 
                    550: 
                    551: /**************************************************************************\
                    552: *
                    553: *  function:  doTrackObject()
                    554: *
                    555: *  input parameters:
                    556: *   pto -  pointer to a track object.
                    557: *   msg -  message selecting what action to take.  Values may include WM_*'s
                    558: *           (see case statements below for more information.)
                    559: *   hwnd - Window handle for the window the track object exists within.
                    560: *   lParam - Usually fourth param to window proc. varies based on msg.
                    561: *
                    562: *  global variables:  none.
                    563: *
                    564: *  coordinate spaces:  There are three coordinate spaces of interest here,
                    565: *   and this routine is frequently switching between them...
                    566: *
                    567: *           WORLD                   DEVICE                  SCREEN
                    568: *
                    569: *      object coordinates       input mouse pos       used w/ SetCursorPos()
                    570: *         (pto->rect)          (lParam for WM_*)
                    571: *
                    572: *             ----->  LPtoDP() ---->    ----> ClientToScreen() -->
                    573: *             <-----  DPtoLP() <----    <---- ScreenToClient() <--
                    574: *
                    575: *   in addition, the HDC has an offset origin.  Device coordinates for the
                    576: *   mouse (lParam) never take this into account, but it is necessary to
                    577: *   translate them in order to get direct manipulation right.
                    578: *
                    579: \**************************************************************************/
                    580: PTrackObject doTrackObject(PTrackObject pto, int msg, HWND hwnd, LONG lParam)
                    581: {
                    582:   if ((pto == NULL) && (msg != TROB_NEW))  return NULL;
                    583: 
                    584:   switch (msg) {
                    585: 
                    586: 
                    587:     /**********************************************************************\
                    588:     *  TROB_NEW
                    589:     *
                    590:     * Allocate new PTrackObject structure.  Fill in default values
                    591:     *  for the fields of the structure.  Set up the HDC correctly.
                    592:     * return - pointer to the new object.
                    593:     \**********************************************************************/
                    594:     case  TROB_NEW: {
                    595:         PTrackObject  pto;
                    596: 
                    597:         /* with LPTR returned value is a pointer. */
                    598:         pto = (PTrackObject) LocalAlloc (LPTR, sizeof (TrackObject));
                    599: 
                    600:         /* initialize the HDC and other fields. */
                    601:         pto->hdc = GetDC(hwnd);
                    602:         SetROP2(pto->hdc, R2_NOT);
                    603:         SelectObject (pto->hdc, GetStockObject (NULL_BRUSH));
                    604:         SelectObject(pto->hdc, CreatePen (PS_SOLID, 2, (COLORREF) 0x01000009));
                    605:         pto->Mode = TMNONE;
                    606:         doTrackObject (pto, TROB_CENTER, hwnd, lParam);
                    607:         GetWorldTransform (pto->hdc, &(pto->xfmChange));
                    608: 
                    609:         /* initialize the size. */
                    610:         pto->rect.top = pto->rect.left = 0;
                    611:         pto->rect.bottom = pto->rect.right = TICKSPACE*5;
                    612: 
                    613:         return (pto);
                    614:     }
                    615: 
                    616: 
                    617:     /**********************************************************************\
                    618:     *  TROB_DELETE
                    619:     *
                    620:     * Delete the pen that we created, release the DC,
                    621:     *  free up the memory allocated for the object.
                    622:     \**********************************************************************/
                    623:     case  TROB_DELETE:
                    624:         DeleteObject (SelectObject (pto->hdc, GetStockObject (BLACK_PEN)));
                    625:         doTrackObject (pto, TROB_PAINT, hwnd, lParam);
                    626:         ReleaseDC (hwnd, pto->hdc);
                    627:         LocalFree (LocalHandle ((LPSTR)pto));
                    628:     return NULL;
                    629: 
                    630: 
                    631: 
                    632:     /**********************************************************************\
                    633:     *  TROB_CENTER
                    634:     *
                    635:     * Called in order to reset the view port origin in the track objects
                    636:     *  hdc whenever the client window changes size.  This hdc is thus kept
                    637:     *  synchronized with the hdc that the axes are painted into.
                    638:     \**********************************************************************/
                    639:     case TROB_CENTER: {
                    640:         CenterOrigin (hwnd, pto->hdc);
                    641:         return (pto);
                    642:     }
                    643: 
                    644: 
                    645: 
                    646:     /**********************************************************************\
                    647:     *  TROB_PAINT
                    648:     *
                    649:     * Paint the object into its hdc.  Called half the time to erase
                    650:     *  the object, and half the time to redraw it.
                    651:     \**********************************************************************/
                    652:     case TROB_PAINT: {
                    653:         Rectangle (pto->hdc, pto->rect.left+1, pto->rect.top+1,
                    654:                              pto->rect.left+INC, pto->rect.top+INC);
                    655: 
                    656:         Rectangle (pto->hdc, pto->rect.left, pto->rect.top,
                    657:                              pto->rect.right, pto->rect.bottom);
                    658:     } return NULL;
                    659: 
                    660: 
                    661: 
                    662:     /**********************************************************************\
                    663:     *  TROB_SETXFORM
                    664:     *
                    665:     * lParam - pointer to the new transform.
                    666:     *  set the new transform into the HDC, then update xfmChange.
                    667:     \**********************************************************************/
                    668:     case TROB_SETXFORM: {
                    669:         doTrackObject (pto, TROB_PAINT, hwnd, lParam);
                    670:         SetWorldTransform(pto->hdc, (PXFORM) lParam);
                    671:         GetWorldTransform(pto->hdc, &pto->xfmChange);
                    672:         doTrackObject (pto, TROB_PAINT, hwnd, lParam);
                    673:     } return NULL;
                    674: 
                    675: 
                    676: 
                    677:     /**********************************************************************\
                    678:     *  TROB_HITTEST
                    679:     *
                    680:     * Check the point sent in in the lParam to see if it lays within
                    681:     *  the bounds of the objects defining rectangle.
                    682:     * return - pointer to the object iff the point is in rectangle,
                    683:     *  otherwise return NULL.
                    684:     \**********************************************************************/
                    685:     case TROB_HITTEST:{
                    686:         POINT  mouWorld;
                    687:         mouWorld.x = LOWORD(lParam);
                    688:         mouWorld.y = HIWORD(lParam);
                    689: 
                    690:         DPtoLP (pto->hdc, &mouWorld, 1);
                    691: 
                    692:         if (PtInRect (&pto->rect, mouWorld))  return pto;
                    693:         else  return NULL;
                    694:     }
                    695: 
                    696: 
                    697: 
                    698:     /**********************************************************************\
                    699:     *  WM_LBUTTONDOWN &  WM_RBUTTONDOWN
                    700:     *
                    701:     * Capture the mouse, set the tracking mode depending on the mouse
                    702:     *  location in world coordinates, reset the mouse position.
                    703:     *
                    704:     \**********************************************************************/
                    705:     case WM_LBUTTONDOWN:
                    706:     case WM_RBUTTONDOWN: {
                    707:       POINT  newmouScreen;
                    708:       POINT  mouWorld;
                    709: 
                    710:       mouWorld.x = LOWORD(lParam);
                    711:       mouWorld.y = HIWORD(lParam);
                    712:       DPtoLP (pto->hdc, &mouWorld, 1);
                    713: 
                    714:       /* upper left hand corner. right button is no-op. */
                    715:       if ((mouWorld.x <= (pto->rect.right  / 2)) &&
                    716:           (mouWorld.y <= (pto->rect.bottom / 2))) {
                    717:           if (msg == WM_RBUTTONDOWN) return NULL;
                    718:           pto->Mode = TMMOVE;
                    719:           newmouScreen.x = pto->rect.left;
                    720:           newmouScreen.y = pto->rect.top;
                    721: 
                    722:       /* lower left hand corner */
                    723:       } else if ((mouWorld.x <= (pto->rect.right  / 2)) &&
                    724:           (mouWorld.y > (pto->rect.bottom / 2))) {
                    725: 
                    726:           pto->Mode = (msg == WM_RBUTTONDOWN) ? TMSHEARY : TMSIZEY;
                    727:           newmouScreen.x = pto->rect.left;
                    728:           newmouScreen.y = pto->rect.bottom;
                    729: 
                    730:       /* upper right hand corner */
                    731:       } else if ((mouWorld.x > (pto->rect.right  / 2)) &&
                    732:           (mouWorld.y <= (pto->rect.bottom / 2))) {
                    733: 
                    734:           pto->Mode = (msg == WM_RBUTTONDOWN) ? TMSHEARX : TMSIZEX;
                    735:           newmouScreen.x = pto->rect.right;
                    736:           newmouScreen.y = pto->rect.top;
                    737: 
                    738:       /* lower right hand corner */
                    739:       } else if ((mouWorld.x > (pto->rect.right  / 2)) &&
                    740:           (mouWorld.y > (pto->rect.bottom / 2))) {
                    741: 
                    742:           pto->Mode = (msg == WM_RBUTTONDOWN) ? TMROTATE : TMSIZEXY;
                    743:           newmouScreen.x = pto->rect.right;
                    744:           newmouScreen.y = pto->rect.bottom;
                    745:       }
                    746: 
                    747:       SetCapture(hwnd);
                    748:       LPtoDP (pto->hdc, &newmouScreen, 1);
                    749:       ClientToScreen (hwnd, &newmouScreen);
                    750:       SetCursorPos (newmouScreen.x,newmouScreen.y);
                    751: 
                    752:       GetWorldTransform (pto->hdc, &pto->xfmDown);
                    753:     } return NULL;
                    754: 
                    755: 
                    756: 
                    757:     /**********************************************************************\
                    758:     *  WM_MOUSEMOVE
                    759:     *
                    760:     * this is where almost all of the interesting calculation is done.
                    761:     *  First clip the mouse location to be in client rectangle, then
                    762:     *  call MouseMove() to handle the different tracking modes.
                    763:     \**********************************************************************/
                    764:     case WM_MOUSEMOVE: {
                    765:       RECT  rect;
                    766:       GetClientRect (hwnd, &rect);
                    767: 
                    768:       if ((short) LOWORD(lParam) < (short)rect.left)
                    769:         lParam = MAKELONG ((WORD)rect.left, HIWORD(lParam));
                    770: 
                    771:       if (LOWORD(lParam) > (WORD)rect.right)
                    772:         lParam = MAKELONG ((WORD)rect.right, HIWORD(lParam));
                    773: 
                    774:       if ((short) HIWORD(lParam) < (short)rect.top)
                    775:         lParam = MAKELONG (LOWORD(lParam), (WORD)rect.top);
                    776: 
                    777:       if (HIWORD(lParam) > (WORD)rect.bottom)
                    778:         lParam = MAKELONG (LOWORD(lParam),(WORD)rect.bottom);
                    779: 
                    780:       MouseMove (pto, msg, hwnd, lParam);
                    781: 
                    782:     } return NULL;
                    783: 
                    784: 
                    785: 
                    786:     /**********************************************************************\
                    787:     *  WM_RBUTTONUP & WM_LBUTTONUP
                    788:     *
                    789:     * simply release the mouse capture, and set the mode to TMNONE.
                    790:     \**********************************************************************/
                    791:     case WM_RBUTTONUP:
                    792:     case WM_LBUTTONUP: {
                    793:       if (pto->Mode) {
                    794:          ReleaseCapture();
                    795:          pto->Mode = TMNONE;
                    796:       }
                    797:     } return NULL;
                    798: 
                    799:   }  /* end switch(msg) */
                    800: }
                    801: 
                    802: 
                    803: 
                    804: 
                    805: 
                    806: 
                    807: /**************************************************************************\
                    808: *  function:  MouseMove()
                    809: *
                    810: *  input parameters:
                    811: *   pto -  pointer to a track object.
                    812: *   msg -  not used.
                    813: *   hwnd - Window handle for the window the track object exists within.
                    814: *   lParam - Usually fourth param to window proc. varies based on msg.
                    815: *
                    816: *  The tracking behavior which the user observers when moving the mouse
                    817: *   is based on the current tracking mode of the object.  This is usually
                    818: *   determined on the mouse down event (c.f. TM*).  First erase the old
                    819: *   object, then figure out the change to the transform matrix, finally
                    820: *   change the world transform matrix and redraw the object.
                    821: *
                    822: *  Tranform:
                    823: *    (    eM11        eM12        0   )
                    824: *    (    eM21        eM22        0   )
                    825: *    (    eDx         eDy         1   )
                    826: *
                    827: *   xDevice = (xWorld * eM11) + (yWorld * eM21) + eDx
                    828: *   yDevice = (xWorld * eM12) + (yWorld * eM22) + eDy
                    829: *
                    830: *   In this routine the Device (mouse location) and World (rectangle corner)
                    831: *   points are known.  Therefore, the two equations above are solved for
                    832: *   the desired matrix entry value (e.g. eM11, 1M12, ... eDy).  The tracking
                    833: *   mode determines which one of these entries may be changed.  E.g. scaling
                    834: *   in X modifies eM11 while shearing in X modifies eM12.  So rather than
                    835: *   using the world transform to map from world to device points, we are
                    836: *   back-computing the proper contents of the world transform.
                    837: *
                    838: \**************************************************************************/
                    839: VOID MouseMove(PTrackObject pto, int msg, HWND hwnd, LONG lParam)
                    840: {
                    841: POINT  mouWorld, mouDevice, orgDevice;
                    842: 
                    843:     UNREFERENCED_PARAMETER(msg);
                    844: 
                    845:     doTrackObject(pto, TROB_PAINT, hwnd, lParam);
                    846:     mouDevice.x = mouWorld.x = LOWORD(lParam);
                    847:     mouDevice.y = mouWorld.y = HIWORD(lParam);
                    848: 
                    849:     SetWorldTransform(pto->hdc, &pto->xfmDown);
                    850:     DPtoLP (pto->hdc, &mouWorld, 1);
                    851: 
                    852:     /* offset the mouse device point for the viewport's origin. */
                    853:     GetViewportOrgEx (pto->hdc, &orgDevice);
                    854:     mouDevice.x -= orgDevice.x;
                    855:     mouDevice.y -= orgDevice.y;
                    856: 
                    857:     GetWorldTransform(pto->hdc, &pto->xfmChange);
                    858: 
                    859:     switch (pto->Mode) {
                    860:       /*******************************************************\
                    861:       *    (     1         xShear       0   )
                    862:       *    (     0           1          0   )
                    863:       *    (     0           0          1   )
                    864:       *
                    865:       * xWorld = rect.left == 0;
                    866:       \*******************************************************/
                    867:       case TMSHEARX: {
                    868:         pto->xfmChange.eM12 = (float) mouDevice.y;
                    869:         pto->xfmChange.eM12 -=pto->xfmChange.eDy;
                    870:         pto->xfmChange.eM12 /=(float) pto->rect.right ;
                    871:         SetWorldTransform (pto->hdc, &pto->xfmChange);
                    872:       } break;
                    873: 
                    874: 
                    875:       /*******************************************************\
                    876:       *    (     1           0          0   )
                    877:       *    (   yShear        1          0   )
                    878:       *    (     0           0          1   )
                    879:       *
                    880:       * yWorld = rect.top == 0;
                    881:       \*******************************************************/
                    882:       case TMSHEARY: {
                    883:         pto->xfmChange.eM21 = (float) mouDevice.x;
                    884:         pto->xfmChange.eM21 -=pto->xfmChange.eDx;
                    885:         pto->xfmChange.eM21 /=(float) pto->rect.bottom ;
                    886:         SetWorldTransform (pto->hdc, &pto->xfmChange);
                    887: 
                    888:       } break;
                    889: 
                    890: 
                    891:       /*******************************************************\
                    892:       *    (   cos(a)      -sin(a)      0   )
                    893:       *    (   sin(a)       cos(a)      0   )
                    894:       *    (     0           0          1   )
                    895:       *
                    896:       * a == rotation angle.  Since mouse in in lower right,
                    897:       *  we need to shift this back 45 degrees (assuming that
                    898:       *  straight down is 0 degrees).  Thus we actually compute
                    899:       *  cos(a) = cos(b - 45) = cos(b)sin(45) + cos(45)sin(45)
                    900:       *  where b is angle from the origin to the mouse (x,y)
                    901:       *  cos(45) = sin(45) ~= 0.707107
                    902:       *  cos(b) = y/r    sin(b) = x/r
                    903:       *
                    904:       \*******************************************************/
                    905:       case TMROTATE: {
                    906:         float r;
                    907: 
                    908:         /* translate back to the origin. */
                    909:         pto->xfmChange.eDx = pto->xfmChange.eDy = (float)0.0;
                    910:         SetWorldTransform (pto->hdc, &pto->xfmChange);
                    911: 
                    912:         /* rotate about the origin. */
                    913:         r = (float) sqrt( (double)(mouWorld.x * mouWorld.x) +
                    914:                           (double)(mouWorld.y * mouWorld.y));
                    915: 
                    916:         pto->xfmChange.eM11 = (float) mouWorld.y / r;
                    917:         pto->xfmChange.eM11 += (float) mouWorld.x / r;
                    918:         pto->xfmChange.eM11 *= (float) 0.707107;
                    919:         pto->xfmChange.eM22 = pto->xfmChange.eM11;
                    920: 
                    921:         pto->xfmChange.eM12 = (float) mouWorld.y / r;
                    922:         pto->xfmChange.eM12 -= (float) mouWorld.x / r;
                    923:         pto->xfmChange.eM12 *= (float) 0.707107;
                    924:         pto->xfmChange.eM21 = -pto->xfmChange.eM12;
                    925: 
                    926:         pto->xfmChange.eDx = pto->xfmChange.eDy = (float)0.0;
                    927: 
                    928:         ModifyWorldTransform (pto->hdc, &pto->xfmChange, MWT_RIGHTMULTIPLY);
                    929: 
                    930:         /* translate back to the original offset. */
                    931:         pto->xfmChange.eM11 =
                    932:         pto->xfmChange.eM22 = (float) 1.0;
                    933:         pto->xfmChange.eM12 =
                    934:         pto->xfmChange.eM21 = (float) 0.0;
                    935: 
                    936:         pto->xfmChange.eDx = pto->xfmDown.eDx;
                    937:         pto->xfmChange.eDy = pto->xfmDown.eDy;
                    938:         ModifyWorldTransform (pto->hdc, &pto->xfmChange, MWT_RIGHTMULTIPLY);
                    939:         GetWorldTransform (pto->hdc, &pto->xfmChange);
                    940:       } break;
                    941: 
                    942: 
                    943:       /*******************************************************\
                    944:       *    (  Size X         0          0   )
                    945:       *    (     0        Size Y        0   )
                    946:       *    (     0           0          1   )
                    947:       *
                    948:       \*******************************************************/
                    949:       case TMSIZEXY: {
                    950:         pto->xfmChange.eM11 = (float) mouDevice.x;
                    951:         pto->xfmChange.eM11 -=pto->xfmChange.eDx;
                    952:         pto->xfmChange.eM11 -=((float) pto->rect.bottom * pto->xfmChange.eM21);
                    953:         pto->xfmChange.eM11 /=(float) pto->rect.right ;
                    954: 
                    955:         pto->xfmChange.eM22 = (float) mouDevice.y;
                    956:         pto->xfmChange.eM22 -=pto->xfmChange.eDy;
                    957:         pto->xfmChange.eM22 -=((float) pto->rect.right  * pto->xfmChange.eM12);
                    958:         pto->xfmChange.eM22 /=(float) pto->rect.bottom ;
                    959:         SetWorldTransform (pto->hdc, &pto->xfmChange);
                    960:       } break;
                    961: 
                    962: 
                    963:       /*******************************************************\
                    964:       *    (  Size X         0          0   )
                    965:       *    (     0           1          0   )
                    966:       *    (     0           0          1   )
                    967:       *
                    968:       * yWorld = rect.top == 0;
                    969:       \*******************************************************/
                    970:       case TMSIZEX: {
                    971:         pto->xfmChange.eM11 = (float) mouDevice.x;
                    972:         pto->xfmChange.eM11 -=pto->xfmChange.eDx;
                    973:         pto->xfmChange.eM11 /=(float) pto->rect.right ;
                    974:         SetWorldTransform (pto->hdc, &pto->xfmChange);
                    975:       } break;
                    976: 
                    977: 
                    978:       /*******************************************************\
                    979:       *    (     1           0          0   )
                    980:       *    (     0        Size Y        0   )
                    981:       *    (     0           0          1   )
                    982:       *
                    983:       * xWorld = rect.left == 0;
                    984:       \*******************************************************/
                    985:       case TMSIZEY: {
                    986:         pto->xfmChange.eM22 = (float) mouDevice.y;
                    987:         pto->xfmChange.eM22 -=pto->xfmChange.eDy;
                    988:         pto->xfmChange.eM22 /=(float) pto->rect.bottom ;
                    989:         SetWorldTransform (pto->hdc, &pto->xfmChange);
                    990:       } break;
                    991: 
                    992: 
                    993:       /*******************************************************\
                    994:       *    (     1           0          0   )
                    995:       *    (     0           1          0   )
                    996:       *    (   Move x      Move y       1   )
                    997:       *
                    998:       * xWorld = rect.left == 0;
                    999:       * yWorld = rect.top == 0;
                   1000:       \*******************************************************/
                   1001:       case TMMOVE: {
                   1002:         pto->xfmChange.eDx = (float) mouDevice.x ;
                   1003:         pto->xfmChange.eDy = (float) mouDevice.y ;
                   1004:         SetWorldTransform (pto->hdc, &pto->xfmChange);
                   1005:       } break;
                   1006:     } /* end switch */
                   1007: 
                   1008:     doTrackObject(pto, TROB_PAINT, hwnd, lParam);
                   1009: 
                   1010:     return;
                   1011:  }

unix.superglobalmegacorp.com

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