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

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

unix.superglobalmegacorp.com

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