|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.