Annotation of mstools/samples/wxform/wxform.c, revision 1.1.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.