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