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

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:  }

unix.superglobalmegacorp.com

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