Annotation of mstools/samples/sdktools/dlgedit/drag.c, revision 1.1.1.1

1.1       root        1: 
                      2: /******************************************************************************\
                      3: *       This is a part of the Microsoft Source Code Samples. 
                      4: *       Copyright (C) 1993 Microsoft Corporation.
                      5: *       All rights reserved. 
                      6: *       This source code is only intended as a supplement to 
                      7: *       Microsoft Development Tools and/or WinHelp documentation.
                      8: *       See these sources for detailed information regarding the 
                      9: *       Microsoft samples programs.
                     10: \******************************************************************************/
                     11: 
                     12: /****************************** Module Header *******************************
                     13: * Module Name: drag.c
                     14: *
                     15: * Contains routines for dragging and sizing controls.
                     16: *
                     17: * Functions:
                     18: *    ShowTrackRect()
                     19: *    HideTrackRect()
                     20: *    FitRectToBounds()
                     21: *    GetOverHang()
                     22: *    GridizeRect()
                     23: *    SizeDragToControl()
                     24: *    DragWndProc()
                     25: *    DrawHandles()
                     26: *    HandleHitTest()
                     27: *    CtrlButtonDown()
                     28: *    DragNewBegin()
                     29: *    CtrlMouseMove()
                     30: *    PreDragTimeout()
                     31: *    DragCancel()
                     32: *    CtrlButtonUp()
                     33: *    DragEnd()
                     34: *    CalcCursorOffset()
                     35: *    InitTracking()
                     36: *    DrawTrackRect()
                     37: *    CancelTracking()
                     38: *    AtOrAbove()
                     39: *    AtOrBelow()
                     40: *    PaintUnderDrag()
                     41: *    MouseToDragRect()
                     42: *    MouseToDU()
                     43: *    DragBegin()
                     44: *    CtrlHitTest()
                     45: *    DragBegin2()
                     46: *
                     47: * Comments:
                     48: *
                     49: ****************************************************************************/
                     50: 
                     51: #include "dlgedit.h"
                     52: #include "dlgfuncs.h"
                     53: #include "dlgextrn.h"
                     54: 
                     55: #include <stdlib.h>
                     56: 
                     57: STATICFN VOID CalcCursorOffset(POINT *ppt);
                     58: STATICFN VOID InitTracking(VOID);
                     59: STATICFN VOID DrawTrackRect(PRECT prc, BOOL fDialog, BOOL fDraw);
                     60: STATICFN VOID CancelTracking(VOID);
                     61: STATICFN INT AtOrAbove(INT nStart, INT nGrid);
                     62: STATICFN INT AtOrBelow(INT nStart, INT nGrid);
                     63: STATICFN VOID PaintUnderDrag(HWND hwndDrag);
                     64: STATICFN VOID MouseToDragRect(INT x, INT y, PRECT prc);
                     65: STATICFN VOID MouseToDU(PPOINT ppt);
                     66: STATICFN VOID DragBegin(HWND hwnd, INT x, INT y, BOOL fHandleWindow);
                     67: STATICFN HWND CtrlHitTest(HWND hwnd, PPOINT ppt);
                     68: STATICFN VOID DragBegin2(PPOINT ppt);
                     69: 
                     70: /*
                     71:  * This contains the initial location of the mouse when going into
                     72:  * pre-drag mode.  If the mouse pointer is moved too FAR away from
                     73:  * this point, we will start the drag operation, even if the pre-drag
                     74:  * timer has not elapsed yet.
                     75:  */
                     76: static POINT gptPreDragStart;
                     77: 
                     78: 
                     79: 
                     80: /************************************************************************
                     81: * CalcCursorOffset
                     82: *
                     83: * This routine updates the gptCursorOffset point.  This is used during
                     84: * dragging operations.  It contains the offset from the mouse pointer
                     85: * at the time a dragging operation is begun and the upper left corner
                     86: * of the dragging rectangle.  This value is needed for determining
                     87: * where mouse events are occuring in relation to where the drag was
                     88: * initially begun from.
                     89: *
                     90: * Arguments:
                     91: *    POINT - offset where the mouse pointer began drag.
                     92: *
                     93: ************************************************************************/
                     94: 
                     95: STATICFN VOID CalcCursorOffset(
                     96:     POINT *ppt)
                     97: {
                     98:     RECT rc;
                     99:     POINT pt;
                    100: 
                    101:     if (gfDlgSelected) {
                    102:         gptCursorOffset = *ppt;
                    103:     }
                    104:     else {
                    105:         rc = grcSelected;
                    106:         pt = *ppt;
                    107:         DUToWinRect(&rc);
                    108: 
                    109:         ClientToScreen(gnpcSel->hwnd, &pt);
                    110:         ScreenToClient(gcd.npc->hwnd, &pt);
                    111: 
                    112:         gptCursorOffset.x = pt.x - rc.left;
                    113:         gptCursorOffset.y = pt.y - rc.top;
                    114:     }
                    115: }
                    116: 
                    117: 
                    118: 
                    119: /************************************************************************
                    120: * InitTracking
                    121: *
                    122: * This function initializes a tracking operation.  The pointer is
                    123: * changed to be the system "move" pointer if we are moving the
                    124: * control (not sizing it).
                    125: *
                    126: ************************************************************************/
                    127: 
                    128: STATICFN VOID InitTracking(VOID)
                    129: {
                    130:     if (gfDlgSelected)
                    131:         ghDCTrack = CreateDC(L"DISPLAY", NULL, NULL, NULL);
                    132:     else
                    133:         ghDCTrack = GetDC(gcd.npc->hwnd);
                    134: 
                    135:     SetROP2(ghDCTrack, R2_NOT);
                    136: }
                    137: 
                    138: 
                    139: 
                    140: /************************************************************************
                    141: * DrawTrackRect
                    142: *
                    143: * This routine draws the drag rectangle.  It is assumed that the window
                    144: * has been locked for update appropriately or this could leave garbage
                    145: * around.  The rectangle given is in dialog units, and is converted
                    146: * to window coordinates using different rules based on the value of
                    147: * fDialog.  After this routine has been called to set the rectangle,
                    148: * the HideTrackRect and ShowTrackRect functions can be called to
                    149: * temporarily hide the track rectangle, but this routine must be called
                    150: * again every time that the tracking rectangle is to be changed.
                    151: *
                    152: * Arguments:
                    153: *   PRECT prc     - Drag rectangle to draw (in dialog units).
                    154: *   BOOL fDialog  - TRUE if the control being dragged is the dialog.
                    155: *   BOOL fDraw    - If TRUE, the rectangle will be drawn.  Having this
                    156: *                   FALSE is useful to just initialize the state globals,
                    157: *                   but defer the drawing of the rectangle until the mouse
                    158: *                   is moved from its starting point.
                    159: *
                    160: ************************************************************************/
                    161: 
                    162: STATICFN VOID DrawTrackRect(
                    163:     PRECT prc,
                    164:     BOOL fDialog,
                    165:     BOOL fDraw)
                    166: {
                    167:     HideTrackRect();
                    168: 
                    169:     grcTrackWin = grcTrackDU = *prc;
                    170:     DUToWinRect(&grcTrackWin);
                    171: 
                    172:     if (fDialog) {
                    173:         AdjustWindowRectEx(&grcTrackWin, gcd.npc->flStyle, FALSE,
                    174:                 (gcd.npc->flStyle & DS_MODALFRAME) ?
                    175:                 gcd.npc->flExtStyle | WS_EX_DLGMODALFRAME :
                    176:                 gcd.npc->flExtStyle);
                    177:         ClientToScreenRect(ghwndSubClient, &grcTrackWin);
                    178:     }
                    179: 
                    180:     if (fDraw)
                    181:         ShowTrackRect();
                    182: }
                    183: 
                    184: 
                    185: 
                    186: /************************************************************************
                    187: * ShowTrackRect
                    188: *
                    189: * This routine shows the current tracking rectangle.
                    190: *
                    191: ************************************************************************/
                    192: 
                    193: VOID ShowTrackRect(VOID)
                    194: {
                    195:     if (!gfTrackRectShown) {
                    196:         MyFrameRect(ghDCTrack, &grcTrackWin, DSTINVERT);
                    197:         gfTrackRectShown = TRUE;
                    198:     }
                    199: }
                    200: 
                    201: 
                    202: 
                    203: /************************************************************************
                    204: * HideTrackRect
                    205: *
                    206: * This routine hides the current tracking rectangle.
                    207: *
                    208: ************************************************************************/
                    209: 
                    210: VOID HideTrackRect(VOID)
                    211: {
                    212:     if (gfTrackRectShown) {
                    213:         MyFrameRect(ghDCTrack, &grcTrackWin, DSTINVERT);
                    214:         gfTrackRectShown = FALSE;
                    215:     }
                    216: }
                    217: 
                    218: 
                    219: 
                    220: /************************************************************************
                    221: * CancelTracking
                    222: *
                    223: * This routine is used to cancel the display of the tracking rectangle.
                    224: * It is basically the opposite of InitTracking.
                    225: *
                    226: ************************************************************************/
                    227: 
                    228: STATICFN VOID CancelTracking(VOID)
                    229: {
                    230:     if (gfTrackRectShown) {
                    231:         HideTrackRect();
                    232: 
                    233:         if (gfDlgSelected)
                    234:             DeleteDC(ghDCTrack);
                    235:         else
                    236:             ReleaseDC(gcd.npc->hwnd, ghDCTrack);
                    237:     }
                    238: }
                    239: 
                    240: 
                    241: 
                    242: /************************************************************************
                    243: * FitRectToBounds
                    244: *
                    245: * This routine fits the given rectangle to the appropriate boundary.
                    246: * If fDialog is FALSE, the rectangle is a control and it must fall
                    247: * entirely within the area of the current dialog being edited.  If the
                    248: * rectangle is adjusted to fit, the moved edge(s) will be aligned on
                    249: * a grid boundary.  The wHandleHit parameter is used to tell this routine
                    250: * what edges are allowed to move, in other words, what edges are
                    251: * "anchored" down and what edges are being tracked.
                    252: *
                    253: * Arguments:
                    254: *   PRECT prc     - Rectangle to be adjusted to the allowed size.
                    255: *   INT nOverHang - How much the control can hang below the dialog.
                    256: *                   This is primarily for the combobox listboxes.
                    257: *   INT HandleHit - One of the DRAG_* constants.
                    258: *   BOOL fDialog  - TRUE if the rectangle is for a dialog.
                    259: *
                    260: ************************************************************************/
                    261: 
                    262: VOID FitRectToBounds(
                    263:     PRECT prc,
                    264:     INT nOverHang,
                    265:     INT HandleHit,
                    266:     BOOL fDialog)
                    267: {
                    268:     INT cxDlg;
                    269:     INT cyDlg;
                    270:     INT dx;
                    271:     INT dy;
                    272: 
                    273:     /*
                    274:      * Are we just moving the control (not sizing)?
                    275:      */
                    276:     if (HandleHit == DRAG_CENTER) {
                    277:         /*
                    278:          * We only do range checking if it is a control (not on the dialog).
                    279:          */
                    280:         if (!fDialog) {
                    281:             dx = prc->right - prc->left;
                    282:             dy = prc->bottom - prc->top;
                    283:             cxDlg = gcd.npc->rc.right - gcd.npc->rc.left;
                    284:             cyDlg = gcd.npc->rc.bottom - gcd.npc->rc.top + nOverHang;
                    285: 
                    286:             if (prc->right > cxDlg) {
                    287:                 prc->left = AtOrBelow(cxDlg - dx, gcxGrid);
                    288:                 prc->right = prc->left + dx;
                    289:             }
                    290: 
                    291:             if (prc->left < 0) {
                    292:                 prc->left = 0;
                    293:                 prc->right = prc->left + dx;
                    294:             }
                    295: 
                    296:             if (prc->bottom > cyDlg) {
                    297:                 prc->top = AtOrBelow(cyDlg - dy, gcyGrid);
                    298:                 prc->bottom = prc->top + dy;
                    299:             }
                    300: 
                    301:             if (prc->top < 0) {
                    302:                 prc->top = 0;
                    303:                 prc->bottom = prc->top + dy;
                    304:             }
                    305:         }
                    306: 
                    307:         return;
                    308:     }
                    309: 
                    310:     if (fDialog) {
                    311:         /*
                    312:          * When dealing with the dialog, we want to take into account
                    313:          * the controls so that the dialog is never sized to hide a
                    314:          * control.  This routine assumes that grcMinDialog has already
                    315:          * been set to enclose the controls.  If the dialog has no
                    316:          * controls, this rectangle is not used, but the dialog's size
                    317:          * is still limited so that it never goes negative.
                    318:          */
                    319:         /*
                    320:          * First deal with the x coordinates.
                    321:          */
                    322:         switch (HandleHit) {
                    323:             case DRAG_LEFTBOTTOM:
                    324:             case DRAG_LEFT:
                    325:             case DRAG_LEFTTOP:
                    326:                 if (npcHead) {
                    327:                     if (prc->left > grcMinDialog.left)
                    328:                         prc->left = AtOrBelow(grcMinDialog.left, gcxGrid);
                    329:                 }
                    330:                 else {
                    331:                     if (prc->left > prc->right)
                    332:                         prc->left = AtOrBelow(prc->right, gcxGrid);
                    333:                 }
                    334: 
                    335:                 break;
                    336: 
                    337:             case DRAG_RIGHTBOTTOM:
                    338:             case DRAG_RIGHT:
                    339:             case DRAG_RIGHTTOP:
                    340:                 if (npcHead) {
                    341:                     if (prc->right < grcMinDialog.right)
                    342:                         prc->right = AtOrAbove(grcMinDialog.right, gcxGrid);
                    343:                 }
                    344:                 else {
                    345:                     if (prc->right < prc->left)
                    346:                         prc->right = AtOrAbove(prc->left, gcxGrid);
                    347:                 }
                    348: 
                    349:                 break;
                    350:         }
                    351: 
                    352:         /*
                    353:          * Now deal with the y coordinates.
                    354:          */
                    355:         switch (HandleHit) {
                    356:             case DRAG_LEFTBOTTOM:
                    357:             case DRAG_BOTTOM:
                    358:             case DRAG_RIGHTBOTTOM:
                    359:                 if (npcHead) {
                    360:                     if (prc->bottom < grcMinDialog.bottom)
                    361:                         prc->bottom = AtOrAbove(grcMinDialog.bottom, gcyGrid);
                    362:                 }
                    363:                 else {
                    364:                     if (prc->bottom < prc->top)
                    365:                         prc->bottom = AtOrAbove(prc->top, gcyGrid);
                    366:                 }
                    367: 
                    368:                 break;
                    369: 
                    370:             case DRAG_LEFTTOP:
                    371:             case DRAG_TOP:
                    372:             case DRAG_RIGHTTOP:
                    373:                 if (npcHead) {
                    374:                     if (prc->top > grcMinDialog.top)
                    375:                         prc->top = AtOrBelow(grcMinDialog.top, gcyGrid);
                    376:                 }
                    377:                 else {
                    378:                     if (prc->top > prc->bottom)
                    379:                         prc->top = AtOrBelow(prc->bottom, gcyGrid);
                    380:                 }
                    381: 
                    382:                 break;
                    383:         }
                    384:     }
                    385:     else {
                    386:         /*
                    387:          * First deal with the x coordinates.
                    388:          */
                    389:         switch (HandleHit) {
                    390:             case DRAG_LEFTBOTTOM:
                    391:             case DRAG_LEFT:
                    392:             case DRAG_LEFTTOP:
                    393:                 if (prc->left > prc->right)
                    394:                     prc->left = AtOrBelow(prc->right, gcxGrid);
                    395: 
                    396:                 if (prc->left == prc->right)
                    397:                     prc->left -= gcxGrid;
                    398: 
                    399:                 if (prc->left < 0)
                    400:                     prc->left = 0;
                    401: 
                    402:                 break;
                    403: 
                    404:             case DRAG_RIGHTBOTTOM:
                    405:             case DRAG_RIGHT:
                    406:             case DRAG_RIGHTTOP:
                    407:                 cxDlg = gcd.npc->rc.right - gcd.npc->rc.left;
                    408:                 if (prc->right > cxDlg)
                    409:                     prc->right = AtOrBelow(cxDlg, gcxGrid);
                    410: 
                    411:                 if (prc->right < prc->left)
                    412:                     prc->right = AtOrAbove(prc->left, gcxGrid);
                    413: 
                    414:                 if (prc->right == prc->left)
                    415:                     prc->right += gcxGrid;
                    416: 
                    417:                 break;
                    418:         }
                    419: 
                    420:         /*
                    421:          * Now deal with the y coordinates.
                    422:          */
                    423:         switch (HandleHit) {
                    424:             case DRAG_LEFTTOP:
                    425:             case DRAG_TOP:
                    426:             case DRAG_RIGHTTOP:
                    427:                 if (prc->top > prc->bottom)
                    428:                     prc->top = AtOrBelow(prc->bottom, gcyGrid);
                    429: 
                    430:                 if (prc->top == prc->bottom)
                    431:                     prc->top -= gcyGrid;
                    432: 
                    433:                 if (prc->top < 0)
                    434:                     prc->top = 0;
                    435: 
                    436:                 break;
                    437: 
                    438:             case DRAG_LEFTBOTTOM:
                    439:             case DRAG_BOTTOM:
                    440:             case DRAG_RIGHTBOTTOM:
                    441:                 cyDlg = gcd.npc->rc.bottom - gcd.npc->rc.top;
                    442: 
                    443:                 /*
                    444:                  * Note that if there is an overhang allowed, then
                    445:                  * we do not limit how FAR down the bottom of the
                    446:                  * control can be.
                    447:                  */
                    448:                 if (prc->bottom > cyDlg && !nOverHang)
                    449:                     prc->bottom = AtOrBelow(cyDlg, gcyGrid);
                    450: 
                    451:                 if (prc->bottom < prc->top)
                    452:                     prc->bottom = AtOrAbove(prc->top, gcyGrid);
                    453: 
                    454:                 if (prc->bottom == prc->top)
                    455:                     prc->bottom += gcyGrid;
                    456: 
                    457:                 break;
                    458:         }
                    459:     }
                    460: }
                    461: 
                    462: 
                    463: 
                    464: /************************************************************************
                    465: * AtOrAbove
                    466: *
                    467: * This routine takes a number, and returns the closest number that
                    468: * is equal to or above that number and is an integral of the given
                    469: * grid value.
                    470: *
                    471: * Arguments:
                    472: *   INT nStart - Starting number (can be negative).
                    473: *   INT nGrid  - Grid value.
                    474: *
                    475: ************************************************************************/
                    476: 
                    477: STATICFN INT AtOrAbove(
                    478:     INT nStart,
                    479:     INT nGrid)
                    480: {
                    481:     register INT nAbove;
                    482: 
                    483:     nAbove = (nStart / nGrid) * nGrid;
                    484: 
                    485:     if (nStart > 0 && nStart != nAbove)
                    486:         nAbove += nGrid;
                    487: 
                    488:     return nAbove;
                    489: }
                    490: 
                    491: 
                    492: 
                    493: /************************************************************************
                    494: * AtOrBelow
                    495: *
                    496: * This routine takes a number, and returns the closest number that
                    497: * is equal to or below that number and is an integral of the given
                    498: * grid value.
                    499: *
                    500: * Arguments:
                    501: *   INT nStart - Starting number (can be negative).
                    502: *   INT nGrid  - Grid value.
                    503: *
                    504: ************************************************************************/
                    505: 
                    506: STATICFN INT AtOrBelow(
                    507:     INT nStart,
                    508:     INT nGrid)
                    509: {
                    510:     register INT nBelow;
                    511: 
                    512:     nBelow = (nStart / nGrid) * nGrid;
                    513: 
                    514:     if (nStart < 0 && nStart != nBelow)
                    515:         nBelow -= nGrid;
                    516: 
                    517:     return nBelow;
                    518: }
                    519: 
                    520: 
                    521: 
                    522: /************************************************************************
                    523: * GetOverHang
                    524: *
                    525: * This function returns the height that the control can overhang the
                    526: * bottom of the dialog.  This is currently only meaningful for comboboxes.
                    527: * If the control is not a combobox, zero is returned.
                    528: *
                    529: * Arguments:
                    530: *   INT iType - Type of control (W_* constant).
                    531: *   INT cy    - Height of the control (in DU's).
                    532: *
                    533: ************************************************************************/
                    534: 
                    535: INT GetOverHang(
                    536:     INT iType,
                    537:     INT cy)
                    538: {
                    539:     if (iType != W_COMBOBOX)
                    540:         return 0;
                    541: 
                    542:     return max(cy - COMBOEDITHEIGHT, 0);
                    543: }
                    544: 
                    545: 
                    546: 
                    547: /************************************************************************
                    548: * GridizeRect
                    549: *
                    550: * This function "gridizes" coordinates in a rectangle.  The current
                    551: * grid values are used.  The fsGrid flag can contain OR'd together
                    552: * GRIDIZE_* values that specify which points to apply the gridding to.
                    553: * Upon return, all coordinates specified will have been rounded to the
                    554: * nearest grid boundary.
                    555: *
                    556: * If GRIDIZE_SAMESIZE is specified, the size of the control will be
                    557: * kept the same.  This overrides the GRIDIZE_RIGHT and GRIDIZE_BOTTOM
                    558: * flags.  In other words, any delta applied to left or top will
                    559: * be added to right and bottom to retain the original size of the
                    560: * rectangle.
                    561: *
                    562: * Arguments:
                    563: *   PRECT prc       - Rectangle to adjust to the current grid.
                    564: *   INT fGridFlags  - GRIDIZE_* flags.  Specifies which points to gridize.
                    565: *
                    566: ************************************************************************/
                    567: 
                    568: VOID GridizeRect(
                    569:     PRECT prc,
                    570:     INT fGridFlags)
                    571: {
                    572:     register INT nTemp;
                    573:     INT leftOld = prc->left;
                    574:     INT topOld = prc->top;
                    575: 
                    576:     if (fGridFlags & GRIDIZE_LEFT) {
                    577:         nTemp = AtOrBelow(prc->left, gcxGrid);
                    578: 
                    579:         if (prc->left - nTemp > gcxGrid / 2)
                    580:             nTemp += gcxGrid;
                    581: 
                    582:         prc->left = nTemp;
                    583:     }
                    584: 
                    585:     if (fGridFlags & GRIDIZE_TOP) {
                    586:         nTemp = AtOrBelow(prc->top, gcyGrid);
                    587: 
                    588:         if (prc->top - nTemp > gcyGrid / 2)
                    589:             nTemp += gcyGrid;
                    590: 
                    591:         prc->top = nTemp;
                    592:     }
                    593: 
                    594:     /*
                    595:      * Do they want to retain the same size of the rectangle?
                    596:      */
                    597:     if (fGridFlags & GRIDIZE_SAMESIZE) {
                    598:         /*
                    599:          * Shift the right coordinate over by the delta that
                    600:          * was applied to the left.
                    601:          */
                    602:         prc->right += prc->left - leftOld;
                    603:         prc->bottom += prc->top - topOld;
                    604:     }
                    605:     else {
                    606:         if (fGridFlags & GRIDIZE_RIGHT) {
                    607:             nTemp = AtOrBelow(prc->right, gcxGrid);
                    608: 
                    609:             if (prc->right - nTemp > gcxGrid / 2)
                    610:                 nTemp += gcxGrid;
                    611: 
                    612:             prc->right = nTemp;
                    613:         }
                    614: 
                    615:         if (fGridFlags & GRIDIZE_BOTTOM) {
                    616:             nTemp = AtOrBelow(prc->bottom, gcyGrid);
                    617: 
                    618:             if (prc->bottom - nTemp > gcyGrid / 2)
                    619:                 nTemp += gcyGrid;
                    620: 
                    621:             prc->bottom = nTemp;
                    622:         }
                    623:     }
                    624: }
                    625: 
                    626: 
                    627: 
                    628: /************************************************************************
                    629: * SizeDragToControl
                    630: *
                    631: * This routine sizes and positions the drag window associated with a
                    632: * control, based on the current size and position of the control.
                    633: *
                    634: * It takes into account the different origin that controls and dialogs
                    635: * have, and sizes the drag window to fit around the control properly.
                    636: * The Z order of the drag window is NOT changed.
                    637: *
                    638: * This routine should only be called for controls, not the dialog.
                    639: *
                    640: * Arguments:
                    641: *   NPCTYPE npc - Control whose drag window needs to be sized.
                    642: *
                    643: ************************************************************************/
                    644: 
                    645: VOID SizeDragToControl(
                    646:     NPCTYPE npc)
                    647: {
                    648:     RECT rc;
                    649: 
                    650:     rc = npc->rc;
                    651:     DUToWinRect(&rc);
                    652: 
                    653:     InflateRect(&rc, CHANDLESIZE / 2, CHANDLESIZE / 2);
                    654: 
                    655:     SetWindowPos(npc->hwndDrag, NULL, rc.left, rc.top,
                    656:             rc.right - rc.left, rc.bottom - rc.top,
                    657:             SWP_NOACTIVATE | SWP_NOZORDER);
                    658: }
                    659: 
                    660: 
                    661: 
                    662: /************************************************************************
                    663: * DragWndProc
                    664: *
                    665: * This is the window procedure for the "drag" class.  This window
                    666: * is placed behind a control and is what the user grabs to size a
                    667: * window with the mouse.
                    668: *
                    669: ************************************************************************/
                    670: 
                    671: WINDOWPROC DragWndProc(
                    672:     HWND hwnd,
                    673:     UINT msg,
                    674:     WPARAM wParam,
                    675:     LPARAM lParam)
                    676: {
                    677:     POINT pt;
                    678: 
                    679:     switch (msg) {
                    680:         case WM_PAINT:
                    681:             {
                    682:                 PAINTSTRUCT ps;
                    683:                 HDC hDC;
                    684: 
                    685:                 PaintUnderDrag(hwnd);
                    686: 
                    687:                 hDC = BeginPaint(hwnd, &ps);
                    688:                 DrawHandles(hwnd, hDC,
                    689:                         (gnpcSel && hwnd == gnpcSel->hwndDrag) ? TRUE : FALSE);
                    690:                 EndPaint(hwnd, &ps);
                    691:             }
                    692: 
                    693:             break;
                    694: 
                    695:         case WM_NCHITTEST:
                    696:             ((pt).x = ((*((POINTS *)&(lParam)))).x, (pt).y = ((*((POINTS *)&(lParam)))).y);
                    697:             ScreenToClient(hwnd, &pt);
                    698: 
                    699:             if (HandleHitTest(hwnd, pt.x, pt.y) == DRAG_CENTER)
                    700:                 return HTTRANSPARENT;
                    701:             else
                    702:                 return HTCLIENT;
                    703: 
                    704:         case WM_SETCURSOR:
                    705:             /*
                    706:              * Defeat the system changing cursors on us.  We do it based
                    707:              * on our own hit testing.
                    708:              */
                    709:             break;
                    710: 
                    711:         case WM_LBUTTONDOWN:
                    712:             ((pt).x = ((*((POINTS *)&(lParam)))).x, (pt).y = ((*((POINTS *)&(lParam)))).y);
                    713:             CtrlButtonDown(hwnd, pt.x, pt.y, TRUE);
                    714:             break;
                    715: 
                    716:         case WM_MOUSEMOVE:
                    717:             ((pt).x = ((*((POINTS *)&(lParam)))).x, (pt).y = ((*((POINTS *)&(lParam)))).y);
                    718:             CtrlMouseMove(hwnd, TRUE, pt.x, pt.y);
                    719:             break;
                    720: 
                    721:         case WM_LBUTTONUP:
                    722:             ((pt).x = ((*((POINTS *)&(lParam)))).x, (pt).y = ((*((POINTS *)&(lParam)))).y);
                    723:             CtrlButtonUp(pt.x, pt.y);
                    724:             break;
                    725: 
                    726:         case WM_RBUTTONDOWN:
                    727:         case WM_MBUTTONDOWN:
                    728:         case WM_LBUTTONDBLCLK:
                    729:         case WM_RBUTTONDBLCLK:
                    730:         case WM_MBUTTONDBLCLK:
                    731:             /*
                    732:              * Prevents calling SetFocus when the middle or right
                    733:              * mouse buttons are pressed (or doubleclicked).
                    734:              */
                    735:             break;
                    736: 
                    737:         case WM_NCCALCSIZE:
                    738:             /*
                    739:              * The client area is the entire control.
                    740:              */
                    741:             break;
                    742: 
                    743:         case WM_DESTROY:
                    744:             /*
                    745:              * When destroying the drag window, we must be sure and
                    746:              * remove the properties associated with it.
                    747:              */
                    748:             UNSETPCINTOHWND(hwnd);
                    749:             break;
                    750: 
                    751:         default:
                    752:             return DefWindowProc(hwnd, msg, wParam, lParam);
                    753:     }
                    754: 
                    755:     return 0L;
                    756: }
                    757: 
                    758: 
                    759: 
                    760: /************************************************************************
                    761: * DrawHandles
                    762: *
                    763: * This routine draws the drag handles for a drag window.  The handles
                    764: * will be solid (filled) if fCurrentSelection is TRUE, or hollow if it
                    765: * is FALSE.
                    766: *
                    767: * Arguments:
                    768: *   HWND hwnd              - Drag window handle.
                    769: *   HDC hDC                - DC to use to draw in this window.
                    770: *   BOOL fCurrentSelection - TRUE if this control is the "current"
                    771: *                            selection.
                    772: *
                    773: ************************************************************************/
                    774: 
                    775: VOID DrawHandles(
                    776:     HWND hwnd,
                    777:     HDC hDC,
                    778:     BOOL fCurrentSelection)
                    779: {
                    780:     RECT rc;
                    781:     INT xMid;
                    782:     INT yMid;
                    783:     INT x2;
                    784:     INT y2;
                    785:     HBITMAP hbmOld;
                    786: 
                    787:     GetWindowRect(hwnd, &rc);
                    788:     OffsetRect(&rc, -rc.left, -rc.top);
                    789: 
                    790:     /*
                    791:      * Precalculate some points.
                    792:      */
                    793:     xMid = ((rc.right + 1) / 2) - (CHANDLESIZE / 2);
                    794:     yMid = ((rc.bottom + 1) / 2) - (CHANDLESIZE / 2);
                    795:     x2 = rc.right - CHANDLESIZE;
                    796:     y2 = rc.bottom - CHANDLESIZE;
                    797: 
                    798:     /*
                    799:      * Draw a solid box if this is the currently selected
                    800:      * control, otherwise draw a hollow box.
                    801:      */
                    802:     if (fCurrentSelection)
                    803:         hbmOld = SelectObject(ghDCMem, ghbmDragHandle);
                    804:     else
                    805:         hbmOld = SelectObject(ghDCMem, ghbmDragHandle2);
                    806: 
                    807:     BitBlt(hDC, 0, 0, CHANDLESIZE, CHANDLESIZE,
                    808:             ghDCMem, 0, 0, SRCCOPY);
                    809:     BitBlt(hDC, xMid, 0, CHANDLESIZE, CHANDLESIZE,
                    810:             ghDCMem, 0, 0, SRCCOPY);
                    811:     BitBlt(hDC, x2, 0, CHANDLESIZE, CHANDLESIZE,
                    812:             ghDCMem, 0, 0, SRCCOPY);
                    813:     BitBlt(hDC, x2, yMid, CHANDLESIZE, CHANDLESIZE,
                    814:             ghDCMem, 0, 0, SRCCOPY);
                    815:     BitBlt(hDC, x2, y2, CHANDLESIZE, CHANDLESIZE,
                    816:             ghDCMem, 0, 0, SRCCOPY);
                    817:     BitBlt(hDC, xMid, y2, CHANDLESIZE, CHANDLESIZE,
                    818:             ghDCMem, 0, 0, SRCCOPY);
                    819:     BitBlt(hDC, 0, y2, CHANDLESIZE, CHANDLESIZE,
                    820:             ghDCMem, 0, 0, SRCCOPY);
                    821:     BitBlt(hDC, 0, yMid, CHANDLESIZE, CHANDLESIZE,
                    822:             ghDCMem, 0, 0, SRCCOPY);
                    823: 
                    824:     SelectObject(ghDCMem, hbmOld);
                    825: }
                    826: 
                    827: 
                    828: 
                    829: /************************************************************************
                    830: * PaintUnderDrag
                    831: *
                    832: * This function is used during a paint operation for a visible drag
                    833: * window.  It checks underneath the area to update and forces any
                    834: * windows down there to paint themselves, in such an order as to cause
                    835: * the last one painted to be the visually top window.  This is necessary
                    836: * to implement the drag windows as "transparent" windows.  After this
                    837: * routine finishes, the caller can paint the "handles".  The caller must
                    838: * call this routine before calling BeginPaint, or the update area
                    839: * will be null and nothing will get painted.
                    840: *
                    841: * It is assumed that the drag windows are for controls, not for the
                    842: * dialog.
                    843: *
                    844: * Arguments:
                    845: *   HWND hwndDrag - Drag window to paint under.
                    846: *
                    847: ************************************************************************/
                    848: 
                    849: STATICFN VOID PaintUnderDrag(
                    850:     HWND hwndDrag)
                    851: {
                    852:     RECT rc;
                    853:     RECT rcInt;
                    854:     RECT rcUpdate;
                    855:     HWND hwnd;
                    856:     HWND hwndControl;
                    857:     NPCTYPE npc;
                    858: 
                    859:     /*
                    860:      * Get our corresponding control window.
                    861:      */
                    862:     hwndControl = (PCFROMHWND(hwndDrag))->hwnd;
                    863: 
                    864:     /*
                    865:      * Get the update rectangle and convert to screen coords.
                    866:      */
                    867:     GetUpdateRect(hwndDrag, &rcUpdate, TRUE);
                    868:     ClientToScreenRect(hwndDrag, &rcUpdate);
                    869: 
                    870:     /*
                    871:      * Start enumerating windows.
                    872:      */
                    873:     hwnd = hwndDrag;
                    874:     while (hwnd = GetWindow(hwnd, GW_HWNDNEXT)) {
                    875:         /*
                    876:          * Skip invisible drag windows.
                    877:          */
                    878:         if (IsWindowVisible(hwnd)) {
                    879:             /*
                    880:              * Does the window rectangle intersect the update rectangle?
                    881:              */
                    882:             GetWindowRect(hwnd, &rc);
                    883:             if (IntersectRect(&rcInt, &rc, &rcUpdate)) {
                    884:                 npc = PCFROMHWND(hwnd);
                    885: 
                    886:                 if (npc->hwndDrag == hwnd || !npc->fSelected) {
                    887:                     ScreenToClientRect(hwnd, &rcInt);
                    888:                     InvalidateRect(hwnd, &rcInt, TRUE);
                    889:                     UpdateWindow(hwnd);
                    890:                 }
                    891: 
                    892:                 if (npc->hwndDrag == hwnd)
                    893:                     break;
                    894:             }
                    895:         }
                    896:     }
                    897: 
                    898:     /*
                    899:      * Finally, paint the control associated with this drag window.
                    900:      */
                    901:     InvalidateRect(hwndControl, NULL, TRUE);
                    902:     UpdateWindow(hwndControl);
                    903: }
                    904: 
                    905: 
                    906: 
                    907: /************************************************************************
                    908: * HandleHitTest
                    909: *
                    910: * This routine takes a point from a mouse button press on a drag window
                    911: * and returns which "handle" was hit, if any.
                    912: *
                    913: * The coordinates are given in zero based coordinates of the drag
                    914: * window.
                    915: *
                    916: * Arguments:
                    917: *   HWND hwnd   - Drag window handle the x,y point is relative to.
                    918: *   INT x       - Mouse X location (in the drag's client coordinates).
                    919: *   INT y       - Mouse Y location (in the drag's client coordinates).
                    920: *
                    921: * Returns:
                    922: *   One of the DRAG_* constants.  If no handle was hit, the
                    923: *   return will be DRAG_CENTER.
                    924: *
                    925: ************************************************************************/
                    926: 
                    927: INT HandleHitTest(
                    928:     HWND hwnd,
                    929:     INT x,
                    930:     INT y)
                    931: {
                    932:     RECT rc;
                    933:     INT xMidStart;
                    934:     INT yMidStart;
                    935: 
                    936:     /*
                    937:      * If there are multiple controls selected, or if the control
                    938:      * type does not allow sizing, defeat the ability to size
                    939:      * with the handles by returning DRAG_CENTER.
                    940:      */
                    941:     if (gcSelected > 1 || !(PCFROMHWND(hwnd))->pwcd->fSizeable)
                    942:         return DRAG_CENTER;
                    943: 
                    944:     /*
                    945:      * Get the window rectangle and cause it to be zero-origined.
                    946:      */
                    947:     GetWindowRect(hwnd, &rc);
                    948:     OffsetRect(&rc, -rc.left, -rc.top);
                    949: 
                    950:     /*
                    951:      * Calculate the starting points for the handles
                    952:      * that are not on a corner.
                    953:      */
                    954:     xMidStart = ((rc.right + 1) / 2) - (CHANDLESIZE / 2);
                    955:     yMidStart = ((rc.bottom + 1) / 2) - (CHANDLESIZE / 2);
                    956: 
                    957:     if (x < CHANDLESIZE) {
                    958:         if (y < CHANDLESIZE)
                    959:             return DRAG_LEFTTOP;
                    960:         else if (y > rc.bottom - CHANDLESIZE)
                    961:             return DRAG_LEFTBOTTOM;
                    962:         else if (y >= yMidStart && y < yMidStart + CHANDLESIZE)
                    963:             return DRAG_LEFT;
                    964:     }
                    965:     else if (x > rc.right - CHANDLESIZE) {
                    966:         if (y < CHANDLESIZE)
                    967:             return DRAG_RIGHTTOP;
                    968:         else if (y > rc.bottom - CHANDLESIZE)
                    969:             return DRAG_RIGHTBOTTOM;
                    970:         else if (y >= yMidStart && y < yMidStart + CHANDLESIZE)
                    971:             return DRAG_RIGHT;
                    972:     }
                    973:     else if (x >= xMidStart && x < xMidStart + CHANDLESIZE) {
                    974:         if (y < CHANDLESIZE)
                    975:             return DRAG_TOP;
                    976:         else if (y > rc.bottom - CHANDLESIZE)
                    977:             return DRAG_BOTTOM;
                    978:     }
                    979: 
                    980:     return DRAG_CENTER;
                    981: }
                    982: 
                    983: 
                    984: 
                    985: /************************************************************************
                    986: * MouseToDragRect
                    987: *
                    988: * This routine takes the mouse pointer coordinates from a mouse message
                    989: * and produces a rectangle that contains the coordinates that the drag
                    990: * rectangle should be displayed as.  This is for tracking (moving/sizing)
                    991: * operations.  It relies on a number of globals to have been set up
                    992: * prior to the call with such things as the current control, type of
                    993: * drag, old location of the control, offset of the original mouse press
                    994: * from the origin of the control, etc.
                    995: *
                    996: * The returned rectangle is pegged to the boundaries of the dialog (if it
                    997: * is for a control), and is aligned to the current grid units.  It is in
                    998: * dialog units relative to the appropriate point based on whether it is
                    999: * for a control or the dialog, and must be converted to window points
                   1000: * before the actual drag rectangle can be drawn on the screen.
                   1001: *
                   1002: * Arguments:
                   1003: *   INT x       - Mouse X location (in window coordinates).
                   1004: *   INT y       - Mouse Y location (in window coordinates).
                   1005: *   PRECT prc   - Rectangle to return the appropriate drag rectangle
                   1006: *                 in.
                   1007: *
                   1008: ************************************************************************/
                   1009: 
                   1010: STATICFN VOID MouseToDragRect(
                   1011:     INT x,
                   1012:     INT y,
                   1013:     PRECT prc)
                   1014: {
                   1015:     POINT pt;
                   1016:     INT fGridFlags;
                   1017: 
                   1018:     pt.x = x;
                   1019:     pt.y = y;
                   1020:     MouseToDU(&pt);
                   1021: 
                   1022:     switch (gHandleHit) {
                   1023:         case DRAG_LEFTBOTTOM:
                   1024:             SetRect(prc, pt.x, grcSelected.top, grcSelected.right,
                   1025:                     (grcSelected.bottom - grcSelected.top) + pt.y);
                   1026:             fGridFlags = GRIDIZE_LEFT | GRIDIZE_BOTTOM;
                   1027:             break;
                   1028: 
                   1029:         case DRAG_BOTTOM:
                   1030:             SetRect(prc, grcSelected.left, grcSelected.top,
                   1031:                     grcSelected.right,
                   1032:                     (grcSelected.bottom - grcSelected.top) + pt.y);
                   1033:             fGridFlags = GRIDIZE_BOTTOM;
                   1034:             break;
                   1035: 
                   1036:         case DRAG_RIGHTBOTTOM:
                   1037:             SetRect(prc, grcSelected.left, grcSelected.top,
                   1038:                     (grcSelected.right - grcSelected.left) + pt.x,
                   1039:                     (grcSelected.bottom - grcSelected.top) + pt.y);
                   1040:             fGridFlags = GRIDIZE_BOTTOM | GRIDIZE_RIGHT;
                   1041:            break;
                   1042: 
                   1043:         case DRAG_RIGHT:
                   1044:             SetRect(prc, grcSelected.left, grcSelected.top,
                   1045:                     (grcSelected.right - grcSelected.left) + pt.x,
                   1046:                     grcSelected.bottom);
                   1047:             fGridFlags = GRIDIZE_RIGHT;
                   1048:             break;
                   1049: 
                   1050:         case DRAG_RIGHTTOP:
                   1051:             SetRect(prc, grcSelected.left, pt.y,
                   1052:                     (grcSelected.right - grcSelected.left) + pt.x,
                   1053:                     grcSelected.bottom);
                   1054:             fGridFlags = GRIDIZE_RIGHT | GRIDIZE_TOP;
                   1055:             break;
                   1056: 
                   1057:         case DRAG_TOP:
                   1058:             SetRect(prc, grcSelected.left, pt.y,
                   1059:                     grcSelected.right, grcSelected.bottom);
                   1060:             fGridFlags = GRIDIZE_TOP;
                   1061:             break;
                   1062: 
                   1063:         case DRAG_LEFTTOP:
                   1064:             SetRect(prc, pt.x, pt.y, grcSelected.right, grcSelected.bottom);
                   1065:             fGridFlags = GRIDIZE_LEFT | GRIDIZE_TOP;
                   1066:             break;
                   1067: 
                   1068:         case DRAG_LEFT:
                   1069:             SetRect(prc, pt.x, grcSelected.top,
                   1070:                     grcSelected.right, grcSelected.bottom);
                   1071:             fGridFlags = GRIDIZE_LEFT;
                   1072:             break;
                   1073: 
                   1074:         case DRAG_CENTER:
                   1075:             SetRect(prc, pt.x, pt.y,
                   1076:                     (grcSelected.right - grcSelected.left) + pt.x,
                   1077:                     (grcSelected.bottom - grcSelected.top) + pt.y);
                   1078:             fGridFlags = GRIDIZE_LEFT | GRIDIZE_TOP | GRIDIZE_SAMESIZE;
                   1079:             break;
                   1080:     }
                   1081: 
                   1082:     GridizeRect(prc, fGridFlags);
                   1083:     FitRectToBounds(prc, gnOverHang, gHandleHit, gfDlgSelected);
                   1084: }
                   1085: 
                   1086: 
                   1087: 
                   1088: /************************************************************************
                   1089: * MouseToDU
                   1090: *
                   1091: * This routine converts the point at ppt from window coordinates
                   1092: * for the current control into the closest Dialog Unit point.
                   1093: *
                   1094: * This routine normally assumes that the point is relative to the selected
                   1095: * control, and will convert the point into DU's.  The current control
                   1096: * can either be the current dialog or one of its child controls.
                   1097: * The DU's returned will be appropriate for the type of control.  If
                   1098: * it is the dialog, they will be relative to the apps client area.
                   1099: * If it is a control, they will be relative to the "client" area of
                   1100: * the current dialog.
                   1101: *
                   1102: * If there is no current selection (such as when dropping a new control),
                   1103: * the point is assumed to already be relative to the dialog and it will
                   1104: * will not be mapped.  This only applies when called with a point for a
                   1105: * control, not a dialog.
                   1106: *
                   1107: * Arguments:
                   1108: *   PPOINT ppt - Point to convert.
                   1109: *
                   1110: ************************************************************************/
                   1111: 
                   1112: STATICFN VOID MouseToDU(
                   1113:     PPOINT ppt)
                   1114: {
                   1115:     if (gfDlgSelected) {
                   1116:         /*
                   1117:          * Map the points from the dialog to the app client.
                   1118:          */
                   1119:         ClientToScreen(gcd.npc->hwnd, ppt);
                   1120:         ScreenToClient(ghwndSubClient, ppt);
                   1121: 
                   1122:         /*
                   1123:          * Subtract the cursor offset.
                   1124:          */
                   1125:         ppt->x -= gptCursorOffset.x;
                   1126:         ppt->y -= gptCursorOffset.y;
                   1127:     }
                   1128:     else {
                   1129:         /*
                   1130:          * Map the points from the control to the dialog window,
                   1131:          * but only if there is a current selection.  There will
                   1132:          * not be a current selection when dropping a new control,
                   1133:          * and the point must already be relative to the dialog!
                   1134:          */
                   1135:         if (gnpcSel) {
                   1136:             ClientToScreen(gnpcSel->hwnd, ppt);
                   1137:             ScreenToClient(gcd.npc->hwnd, ppt);
                   1138:         }
                   1139: 
                   1140:         /*
                   1141:          * Subtract the cursor offset, then the dialogs frame
                   1142:          * controls offset.
                   1143:          */
                   1144:         ppt->x -= gptCursorOffset.x;
                   1145:         ppt->y -= gptCursorOffset.y;
                   1146:     }
                   1147: 
                   1148:     /*
                   1149:      * Convert this position to dialog units.
                   1150:      */
                   1151:     WinToDUPoint(ppt);
                   1152: }
                   1153: 
                   1154: 
                   1155: 
                   1156: /************************************************************************
                   1157: * CtrlButtonDown
                   1158: *
                   1159: * This routine is called by the control and drag window procs when
                   1160: * the left mouse button is pressed.  It checks for the Ctrl modifier key
                   1161: * then passes control on to the appropriate routine.
                   1162: *
                   1163: * When hwnd is the dialog itself, fHandleWindow must be TRUE, even
                   1164: * if a handle was not hit, because of the special-case code that must
                   1165: * be done for the dialog (it doesn't have a separate drag window).
                   1166: *
                   1167: * Arguments:
                   1168: *   HWND hwnd          - Window handle, can be a drag window or control.
                   1169: *   INT x              - X mouse location (window coordinates).
                   1170: *   INT y              - Y mouse location (window coordinates).
                   1171: *   BOOL fHandleWindow - TRUE if a handle was clicked on, or FALSE if the
                   1172: *                        body of a control was clicked on.
                   1173: *
                   1174: ************************************************************************/
                   1175: 
                   1176: VOID CtrlButtonDown(
                   1177:     HWND hwnd,
                   1178:     INT x,
                   1179:     INT y,
                   1180:     BOOL fHandleWindow)
                   1181: {
                   1182:     POINT pt;
                   1183:     HWND hwndHit;
                   1184:     INT nOverHang;
                   1185: 
                   1186:     /*
                   1187:      * Discard all mouse messages during certain operations.
                   1188:      */
                   1189:     if (gfDisabled)
                   1190:         return;
                   1191: 
                   1192:     /*
                   1193:      * Also, be sure any outstanding changes get applied
                   1194:      * without errors.
                   1195:      */
                   1196:     if (!StatusApplyChanges())
                   1197:         return;
                   1198: 
                   1199:     if (gCurTool != W_NOTHING) {
                   1200:         nOverHang = GetOverHang(gpwcdCurTool->iType, gpwcdCurTool->cyDefault);
                   1201:         DragNewBegin(gpwcdCurTool->cxDefault,
                   1202:                 gpwcdCurTool->cyDefault, nOverHang);
                   1203:     }
                   1204:     else {
                   1205:         /*
                   1206:          * If the Control key is down, duplicate the control, unless
                   1207:          * it is the dialog (mouse duplicate of the dialog is not
                   1208:          * supported).
                   1209:          */
                   1210:         if ((GetKeyState(VK_CONTROL) & 0x8000) &&
                   1211:                 (PCFROMHWND(hwnd))->pwcd->iType != W_DIALOG) {
                   1212:             /*
                   1213:              * First, figure out which control was hit and select it.
                   1214:              */
                   1215:             if (fHandleWindow) {
                   1216:                 hwndHit = hwnd;
                   1217:             }
                   1218:             else {
                   1219:                 pt.x = x;
                   1220:                 pt.y = y;
                   1221:                 hwndHit = CtrlHitTest(hwnd, &pt);
                   1222:             }
                   1223: 
                   1224:             SelectControl(PCFROMHWND(hwndHit), TRUE);
                   1225: 
                   1226:             /*
                   1227:              * If there is still a selection, begin dragging a copy
                   1228:              * of it.  The check here is necessary because the prior
                   1229:              * call to SelectControl can unselect the last selected
                   1230:              * control if the Shift key was held down.
                   1231:              */
                   1232:             if (gcSelected)
                   1233:                 Duplicate();
                   1234:         }
                   1235:         else {
                   1236:             /*
                   1237:              * Start a drag operation.  This can be either moving or sizing
                   1238:              * the control, depending on fHandleWindow and where the mouse
                   1239:              * click is at.
                   1240:              */
                   1241:             DragBegin(hwnd, x, y, fHandleWindow);
                   1242:         }
                   1243:     }
                   1244: }
                   1245: 
                   1246: 
                   1247: 
                   1248: /************************************************************************
                   1249: * DragNewBegin
                   1250: *
                   1251: * This routine begins a drag operation when dropping a new control, or
                   1252: * group of controls.  It is NOT used when dragging existing controls.
                   1253: *
                   1254: * Arguments:
                   1255: *   INT cx        - Width of the new control.
                   1256: *   INT cy        - Height of the new control.
                   1257: *   INT nOverHang - How much the control can overhang the dialog bottom.
                   1258: *
                   1259: ************************************************************************/
                   1260: 
                   1261: VOID DragNewBegin(
                   1262:     INT cx,
                   1263:     INT cy,
                   1264:     INT nOverHang)
                   1265: {
                   1266:     POINTS mpt;
                   1267:     POINT pt;
                   1268:     DWORD dwPos;
                   1269: 
                   1270:     /*
                   1271:      * Always be sure the focus is where we want it, not on something
                   1272:      * like the status ribbon or "Esc" won't work to cancel the tracking.
                   1273:      */
                   1274:     SetFocus(ghwndMain);
                   1275: 
                   1276:     /*
                   1277:      * Cancel any current selection, and set some state globals.
                   1278:      */
                   1279:     CancelSelection(TRUE);
                   1280:     gHandleHit = DRAG_CENTER;
                   1281:     gState = STATE_DRAGGINGNEW;
                   1282:     SetCursor(hcurMove);
                   1283: 
                   1284:     /*
                   1285:      * The cursor offset is set to be located in the middle of the
                   1286:      * new control.  This causes the pointer to be initially located
                   1287:      * exactly in the center.
                   1288:      */
                   1289:     gptCursorOffset.x = cx;
                   1290:     gptCursorOffset.y = cy;
                   1291:     DUToWinPoint(&gptCursorOffset);
                   1292:     gptCursorOffset.x /= 2;
                   1293:     gptCursorOffset.y /= 2;
                   1294: 
                   1295:     /*
                   1296:      * Set a global with the overhang.  This is used all during the
                   1297:      * drag operation we are starting.
                   1298:      */
                   1299:     gnOverHang = nOverHang;
                   1300: 
                   1301:     /*
                   1302:      * Now we make up a dummy rectangle for the new control.  We start
                   1303:      * it at (0,0) with a size of cx and cy.  The point where the mouse
                   1304:      * was when the command was done is obtained and mapped to the dialog
                   1305:      * (it is assumed that only controls will be done here, not a dialog).
                   1306:      * The new control rectangle is then converted to be at this location,
                   1307:      * it is gridized, the tracking rectangle is shown and we are off.
                   1308:      */
                   1309:     SetRect(&grcSelected, 0, 0, cx, cy);
                   1310:     dwPos = GetMessagePos();
                   1311:     mpt = (*((POINTS *)&(dwPos)));
                   1312:     ((pt).x = (mpt).x, (pt).y = (mpt).y);
                   1313:     ScreenToClient(gcd.npc->hwnd, &pt);
                   1314:     MouseToDragRect(pt.x, pt.y, &grcSelected);
                   1315:     InitTracking();
                   1316:     DrawTrackRect(&grcSelected, FALSE, TRUE);
                   1317: 
                   1318:     /*
                   1319:      * Display the initial coordinates.
                   1320:      */
                   1321:     StatusSetCoords(&grcSelected);
                   1322: 
                   1323:     /*
                   1324:      * The mouse messages will come through the dialog subclass proc for
                   1325:      * these kinds of operations.
                   1326:      */
                   1327:     SetCapture(gcd.npc->hwnd);
                   1328: }
                   1329: 
                   1330: 
                   1331: 
                   1332: /************************************************************************
                   1333: * DragBegin
                   1334: *
                   1335: * This routine begins a drag operation for either moving a control or
                   1336: * sizing it.  The tracking rectangle is not actually drawn until the
                   1337: * mouse moves by a grid unit, however.
                   1338: *
                   1339: * To begin a drag on the dialog itself, fHandleWindow must be TRUE, even
                   1340: * if a handle was not hit, because of the special-case code that must
                   1341: * be done for the dialog (it doesn't have a separate drag window).
                   1342: *
                   1343: * Arguments:
                   1344: *   HWND hwnd          - Window handle, can be a drag window or control.
                   1345: *   INT x              - Starting X mouse location (window coordinates).
                   1346: *   INT y              - Starting Y mouse location (window coordinates).
                   1347: *   BOOL fHandleWindow - TRUE if the drag is happening because a drag
                   1348: *                        handle was clicked on, or FALSE if the drag is
                   1349: *                        happening because the body of a control is
                   1350: *                        clicked on.
                   1351: *
                   1352: *
                   1353: ************************************************************************/
                   1354: 
                   1355: STATICFN VOID DragBegin(
                   1356:     HWND hwnd,
                   1357:     INT x,
                   1358:     INT y,
                   1359:     BOOL fHandleWindow)
                   1360: {
                   1361:     NPCTYPE npcT;
                   1362:     HWND hwndHit;
                   1363:     POINT pt;
                   1364:     NPCTYPE npc;
                   1365:     BOOL fPrevSelect = FALSE;
                   1366:     INT nBottom;
                   1367: 
                   1368:     /*
                   1369:      * Always be sure the focus is where we want it, not on something
                   1370:      * like the status ribbon or "Esc" won't work to cancel the tracking.
                   1371:      */
                   1372:     SetFocus(ghwndMain);
                   1373: 
                   1374:     pt.x = x;
                   1375:     pt.y = y;
                   1376: 
                   1377:     /*
                   1378:      * Is this drag happening because a drag handle was clicked on?
                   1379:      */
                   1380:     if (fHandleWindow) {
                   1381:         /*
                   1382:          * Find out which handle was clicked on.  It is assumed that
                   1383:          * hwnd is a drag window.
                   1384:          */
                   1385:         gHandleHit = HandleHitTest(hwnd, pt.x, pt.y);
                   1386:         hwndHit = hwnd;
                   1387:     }
                   1388:     else {
                   1389:         /*
                   1390:          * The body of a control was clicked on.  Set a global to say
                   1391:          * that we are moving a control, then find out which control
                   1392:          * was hit (with our own hit testing).
                   1393:          */
                   1394:         gHandleHit = DRAG_CENTER;
                   1395:         hwndHit = CtrlHitTest(hwnd, &pt);
                   1396:     }
                   1397: 
                   1398:     /*
                   1399:      * Find out if the control clicked on was the currently selected
                   1400:      * control already.
                   1401:      */
                   1402:     npc = PCFROMHWND(hwndHit);
                   1403:     if (npc == gnpcSel)
                   1404:         fPrevSelect = TRUE;
                   1405: 
                   1406:     /*
                   1407:      * Select the control.  This can return FALSE if the control is
                   1408:      * unselected (shift key is down and the control is already selected).
                   1409:      */
                   1410:     if (!SelectControl(npc, TRUE))
                   1411:         return;
                   1412: 
                   1413:     /*
                   1414:      * If the dialog is selected, we make a rectangle that encloses all
                   1415:      * the controls.  This will be used to limit the size that the dialog
                   1416:      * can be sized to so that it cannot cover any existing controls.
                   1417:      */
                   1418:     if (gfDlgSelected) {
                   1419:         /*
                   1420:          * Seed the rectangle with impossible values.
                   1421:          */
                   1422:         SetRect(&grcMinDialog, 32000, 32000, -32000, -32000);
                   1423: 
                   1424:         /*
                   1425:          * Loop through all the controls, expanding the rectangle to
                   1426:          * fit around all the controls.
                   1427:          */
                   1428:         for (npcT = npcHead; npcT; npcT = npcT->npcNext) {
                   1429:             if (npcT->rc.left < grcMinDialog.left)
                   1430:                 grcMinDialog.left = npcT->rc.left;
                   1431: 
                   1432:             if (npcT->rc.right > grcMinDialog.right)
                   1433:                 grcMinDialog.right = npcT->rc.right;
                   1434: 
                   1435:             if (npcT->rc.top < grcMinDialog.top)
                   1436:                 grcMinDialog.top = npcT->rc.top;
                   1437: 
                   1438:             /*
                   1439:              * When calculating the bottom boundary of the controls,
                   1440:              * make the rectangle shorter by the ovehang amount.  This
                   1441:              * allows the dialog to be sized up so that it covers
                   1442:              * parts of controls with overhang (comboboxes).
                   1443:              */
                   1444:             nBottom = npcT->rc.bottom - GetOverHang(npcT->pwcd->iType,
                   1445:                     npcT->rc.bottom - npcT->rc.top);
                   1446:             if (nBottom > grcMinDialog.bottom)
                   1447:                 grcMinDialog.bottom = nBottom;
                   1448:         }
                   1449: 
                   1450:         OffsetRect(&grcMinDialog, gcd.npc->rc.left, gcd.npc->rc.top);
                   1451:     }
                   1452: 
                   1453:     /*
                   1454:      * If the control clicked on was already the anchor, go right into
                   1455:      * dragging mode.  If it was not, go into pre-drag mode, which will
                   1456:      * defer the calculation of offsets, etc., until after a certain
                   1457:      * small amount of time so the mouse can be "debounced".
                   1458:      */
                   1459:     if (fPrevSelect) {
                   1460:         DragBegin2(&pt);
                   1461:     }
                   1462:     else {
                   1463:         gState = STATE_PREDRAG;
                   1464: 
                   1465:         /*
                   1466:          * Save the point in a global.  If the mouse pointer is moved
                   1467:          * too FAR away from this point, we will start the drag operation
                   1468:          * even if the pre-drag time has not elapsed yet.
                   1469:          */
                   1470:         gptPreDragStart = pt;
                   1471: 
                   1472:         /*
                   1473:          * Start the pre-drag timer.
                   1474:          */
                   1475:         SetTimer(hwndHit, TID_PREDRAG, gmsecPreDrag, NULL);
                   1476:     }
                   1477: 
                   1478:     /*
                   1479:      * The mouse messages from now on will go to the window clicked on,
                   1480:      * either the drag window or the control window.
                   1481:      */
                   1482:     SetCapture(hwndHit);
                   1483: }
                   1484: 
                   1485: 
                   1486: 
                   1487: /************************************************************************
                   1488: * DragBegin2
                   1489: *
                   1490: * This routine continues the initiation of a drag operation started
                   1491: * by DragBegin.  It is separate because it calculates offsets based
                   1492: * on where the mouse pointer is, and these calculations can be deferred
                   1493: * until a later time than when DragBegin was called so that the mouse
                   1494: * can be "debounced".
                   1495: *
                   1496: * Arguments:
                   1497: *   POINT ppt - Starting mouse location (window coordinates).
                   1498: *
                   1499: ************************************************************************/
                   1500: 
                   1501: STATICFN VOID DragBegin2(
                   1502:     PPOINT ppt)
                   1503: {
                   1504:     gState = STATE_DRAGGING;
                   1505: 
                   1506:     /*
                   1507:      * Set the pointer to the "move" pointer if we are moving.
                   1508:      * Otherwise, the pointer should already be set to the proper
                   1509:      * sizing pointer.
                   1510:      */
                   1511:     if (gHandleHit == DRAG_CENTER)
                   1512:         SetCursor(hcurMove);
                   1513: 
                   1514:     /*
                   1515:      * Save away the initial offset of the cursor.
                   1516:      */
                   1517:     CalcCursorOffset(ppt);
                   1518: 
                   1519:     /*
                   1520:      * Initialize the track rectangle.  Note we are calling DrawTrackRect
                   1521:      * with FALSE.
                   1522:      */
                   1523:     DrawTrackRect(&grcSelected, gfDlgSelected, FALSE);
                   1524: }
                   1525: 
                   1526: 
                   1527: 
                   1528: /****************************************************************************
                   1529: * CtrlHitTest
                   1530: *
                   1531: * This routine walks the list of controls and determines which one is
                   1532: * "hit" by this point.  If a hit is found, the point is also converted
                   1533: * to coordinates for the hit window.
                   1534: *
                   1535: * There is a special case when hitting controls over a groupbox.
                   1536: * Controls within a groupbox will always be hit instead of the
                   1537: * groupbox itself.
                   1538: *
                   1539: * Arguments:
                   1540: *   HWND hwnd  - Window handle the coordinates are relative to.
                   1541: *   PPOINT ppt - Window point where the click occurred (window coords).
                   1542: *
                   1543: * Returns:
                   1544: *   The hwnd of the "hit" control will be returned.  If no control was hit,
                   1545: *   the hwnd that was passed in is returned.
                   1546: *
                   1547: ****************************************************************************/
                   1548: 
                   1549: STATICFN HWND CtrlHitTest(
                   1550:     HWND hwnd,
                   1551:     PPOINT ppt)
                   1552: {
                   1553:     NPCTYPE npc;
                   1554:     RECT rc;
                   1555:     HWND hwndHit = (HWND)NULL;
                   1556:     BOOL fGroupHit = FALSE;
                   1557: 
                   1558:     for (npc = npcHead; npc; npc = npc->npcNext) {
                   1559:         GetWindowRect(npc->hwnd, &rc);
                   1560:         ScreenToClientRect(npc->hwnd, &rc);
                   1561:         MyMapWindowRect(npc->hwnd, hwnd, &rc);
                   1562: 
                   1563:         /*
                   1564:          * Is this a hit, and was there either no control hit as
                   1565:          * yet, or this control is not a groupbox, or the control
                   1566:          * that was previously hit was a groupbox also?
                   1567:          */
                   1568:         if (PtInRect(&rc, *ppt) &&
                   1569:                 (!hwndHit || npc->pwcd->iType != W_GROUPBOX || fGroupHit)) {
                   1570:             hwndHit = npc->hwnd;
                   1571:             if (npc->pwcd->iType == W_GROUPBOX)
                   1572:                 fGroupHit = TRUE;
                   1573:             else
                   1574:                 fGroupHit = FALSE;
                   1575:         }
                   1576:     }
                   1577: 
                   1578:     if (hwndHit) {
                   1579:         MapWindowPoint(hwnd, hwndHit, ppt);
                   1580:         return hwndHit;
                   1581:     }
                   1582:     else {
                   1583:         return hwnd;
                   1584:     }
                   1585: }
                   1586: 
                   1587: 
                   1588: 
                   1589: /****************************************************************************
                   1590: * PreDragTimeout
                   1591: *
                   1592: * This function handles the WM_TIMER message from the control window
                   1593: * proc.  It is used so that the dragging of a newly selected control
                   1594: * can be deferred for a small period of time to "debounce" the mouse.
                   1595: *
                   1596: * This function is also called if the mouse is moved too much during the
                   1597: * debounce time, effectively cutting the debounce time short.
                   1598: *
                   1599: * Arguments:
                   1600: *   HWND hwnd      - Window handle the timer came from.
                   1601: *   BOOL fTimedOut - TRUE if the predrag is ending because the timer
                   1602: *                    expired.  FALSE if the predrag is ending because
                   1603: *                    the mouse was moved too FAR.
                   1604: *
                   1605: ****************************************************************************/
                   1606: 
                   1607: VOID PreDragTimeout(
                   1608:     HWND hwnd,
                   1609:     BOOL fTimedOut)
                   1610: {
                   1611:     POINT pt;
                   1612: 
                   1613:     /*
                   1614:      * The debounce time is over and the mouse button is still
                   1615:      * down.  Get the current mouse pointer location and go into
                   1616:      * drag mode.
                   1617:      */
                   1618:     if (gState == STATE_PREDRAG) {
                   1619:         /*
                   1620:          * If we timed out (the mouse was not moved a large distance),
                   1621:          * eat any small movement that may have been done during the
                   1622:          * predrag time by setting the mouse cursor back to the location
                   1623:          * that it started at.  Note that we do not do this if the mouse
                   1624:          * was moved a large distance, because the efect would be
                   1625:          * noticeable for that case, and we want the control to be
                   1626:          * moved then anyways.
                   1627:          */
                   1628:         if (fTimedOut) {
                   1629:             pt = gptPreDragStart;
                   1630:             ClientToScreen(hwnd, &pt);
                   1631:             SetCursorPos(pt.x, pt.y);
                   1632:         }
                   1633: 
                   1634:         DragBegin2(&gptPreDragStart);
                   1635:     }
                   1636: 
                   1637:     KillTimer(hwnd, TID_PREDRAG);
                   1638: }
                   1639: 
                   1640: 
                   1641: 
                   1642: /************************************************************************
                   1643: * CtrlMouseMove
                   1644: *
                   1645: * This routine handles the mouse move messages for controls, the dialog,
                   1646: * drag windows and when dropping a new control.
                   1647: *
                   1648: * During a drag operation, the tracking rectangle will be adjusted.
                   1649: * If there is not a drag operation is effect, the mouse cursor will
                   1650: * be changed to a sizing pointer if it is over a drag handle.  If not
                   1651: * over a drag handle, the pointer will be changed back to the arrow.
                   1652: *
                   1653: * Arguments:
                   1654: *   HWND hwnd        - Window handle the x and y are relative to.
                   1655: *   BOOL fDragWindow - TRUE if hwnd is a drag window.
                   1656: *   INT x            - X location of the mouse movement (window coords).
                   1657: *   INT y            - Y location of the mouse movement (window coords).
                   1658: *
                   1659: ************************************************************************/
                   1660: 
                   1661: VOID CtrlMouseMove(
                   1662:     HWND hwnd,
                   1663:     BOOL fDragWindow,
                   1664:     INT x,
                   1665:     INT y)
                   1666: {
                   1667:     RECT rc;
                   1668:     RECT rc2;
                   1669:     HCURSOR hcur = NULL;
                   1670: 
                   1671:     /*
                   1672:      * Discard all mouse messages during certain operations
                   1673:      * (but still set the pointer properly).
                   1674:      */
                   1675:     if (gfDisabled) {
                   1676:         SetCursor(hcurArrow);
                   1677:         return;
                   1678:     }
                   1679: 
                   1680:     switch (gState) {
                   1681:         case STATE_PREDRAG:
                   1682:             /*
                   1683:              * If the mouse was moved too FAR, consider the
                   1684:              * pre-drag time elapsed and go into drag mode.
                   1685:              */
                   1686:             if (abs(gptPreDragStart.x - x) > gcxPreDragMax ||
                   1687:                     abs(gptPreDragStart.y - y) > gcyPreDragMax)
                   1688:                 PreDragTimeout(hwnd, FALSE);
                   1689: 
                   1690:             break;
                   1691: 
                   1692:         case STATE_DRAGGING:
                   1693:         case STATE_DRAGGINGNEW:
                   1694:             MouseToDragRect(x, y, &rc);
                   1695: 
                   1696:             if (!EqualRect(&rc, &grcTrackDU)) {
                   1697:                 /*
                   1698:                  * If the tracking rectangle is not shown, this means that
                   1699:                  * this is the first significant mouse move since the start
                   1700:                  * of a drag operation, and we need to lock the window, get
                   1701:                  * our clip DC, etc.
                   1702:                  */
                   1703:                 if (!gfTrackRectShown)
                   1704:                     InitTracking();
                   1705: 
                   1706:                 DrawTrackRect(&rc, gfDlgSelected, TRUE);
                   1707: 
                   1708:                 if (gcSelected > 1) {
                   1709:                     /*
                   1710:                      * Since there are multiple controls selected,
                   1711:                      * rc will be the rectangle that surrounds them
                   1712:                      * all.  We really want to just show the anchor
                   1713:                      * controls new position, so we have to do a
                   1714:                      * little math to calculate and display it.
                   1715:                      */
                   1716:                     rc2 = gnpcSel->rc;
                   1717:                     OffsetRect(&rc2, rc.left - grcSelected.left,
                   1718:                             rc.top - grcSelected.top);
                   1719:                     StatusSetCoords(&rc2);
                   1720:                 }
                   1721:                 else {
                   1722:                     /*
                   1723:                      * Either a single control is being dragged or
                   1724:                      * a new control is being dropped.
                   1725:                      */
                   1726:                     StatusSetCoords(&rc);
                   1727:                 }
                   1728:             }
                   1729: 
                   1730:             break;
                   1731: 
                   1732:         case STATE_SELECTING:
                   1733:             OutlineSelectDraw(x, y);
                   1734:             break;
                   1735: 
                   1736:         default:
                   1737:             /*
                   1738:              * Is there a tool selected?
                   1739:              */
                   1740:             if (gCurTool != W_NOTHING) {
                   1741:                 hcur = hcurDropTool;
                   1742:             }
                   1743:             else {
                   1744:                 /*
                   1745:                  * If hwnd is a drag window, see if the pointer is over
                   1746:                  * over any of the handles and change it to one of the
                   1747:                  * sizing pointers if necessary.  Otherwise set the pointer
                   1748:                  * to the default arrow pointer.
                   1749:                  */
                   1750:                 if (fDragWindow) {
                   1751:                     switch (HandleHitTest(hwnd, x, y)) {
                   1752:                         case DRAG_LEFTBOTTOM:
                   1753:                         case DRAG_RIGHTTOP:
                   1754:                             hcur = hcurSizeNESW;
                   1755:                             break;
                   1756: 
                   1757:                         case DRAG_LEFTTOP:
                   1758:                         case DRAG_RIGHTBOTTOM:
                   1759:                             hcur = hcurSizeNWSE;
                   1760:                             break;
                   1761: 
                   1762:                         case DRAG_BOTTOM:
                   1763:                         case DRAG_TOP:
                   1764:                             hcur = hcurSizeNS;
                   1765:                             break;
                   1766: 
                   1767:                         case DRAG_RIGHT:
                   1768:                         case DRAG_LEFT:
                   1769:                             hcur = hcurSizeWE;
                   1770:                             break;
                   1771: 
                   1772:                         case DRAG_CENTER:
                   1773:                         default:
                   1774:                             hcur = hcurArrow;
                   1775:                             break;
                   1776:                     }
                   1777:                 }
                   1778:                 else {
                   1779:                     hcur = hcurArrow;
                   1780:                 }
                   1781:             }
                   1782: 
                   1783:             break;
                   1784:     }
                   1785: 
                   1786:     if (hcur)
                   1787:         SetCursor(hcur);
                   1788: }
                   1789: 
                   1790: 
                   1791: 
                   1792: /************************************************************************
                   1793: * DragCancel
                   1794: *
                   1795: * This function cancels any drag operation in effect.  It handles
                   1796: * such things as erasing any visible tracking rectangle, freeing any
                   1797: * "copy" data, setting globals and updating the status display.  It
                   1798: * can be used no matter how the drag operation was started.
                   1799: *
                   1800: ************************************************************************/
                   1801: 
                   1802: VOID DragCancel(VOID)
                   1803: {
                   1804:     HWND hwnd;
                   1805: 
                   1806:     switch (gState) {
                   1807:         case STATE_PREDRAG:
                   1808:             /*
                   1809:              * Stop the timer.  Note that this assumes the timer
                   1810:              * was attached to the capture window.  This should
                   1811:              * be safe (see the associated SetTimer).
                   1812:              */
                   1813:             if (hwnd = GetCapture())
                   1814:                 KillTimer(hwnd, TID_PREDRAG);
                   1815: 
                   1816:             break;
                   1817: 
                   1818:         case STATE_DRAGGING:
                   1819:         case STATE_DRAGGINGNEW:
                   1820:             CancelTracking();
                   1821: 
                   1822:             if (gpResCopy) {
                   1823:                 MyFree(gpResCopy);
                   1824:                 gpResCopy = NULL;
                   1825:             }
                   1826: 
                   1827:             break;
                   1828:     }
                   1829: 
                   1830:     gState = STATE_NORMAL;
                   1831:     ReleaseCapture();
                   1832:     SetCursor(hcurArrow);
                   1833: 
                   1834:     StatusUpdate();
                   1835:     StatusSetEnable();
                   1836: }
                   1837: 
                   1838: 
                   1839: 
                   1840: /************************************************************************
                   1841: * CtrlButtonUp
                   1842: *
                   1843: * This function is called when the left mouse button is released.  Depending
                   1844: * on the mode, it will complete the operation started when the button
                   1845: * was pressed down.
                   1846: *
                   1847: * Arguments:
                   1848: *   INT x - Mouse X location (in window coords).
                   1849: *   INT y - Mouse Y location (in window coords).
                   1850: *
                   1851: ************************************************************************/
                   1852: 
                   1853: VOID CtrlButtonUp(
                   1854:     INT x,
                   1855:     INT y)
                   1856: {
                   1857:     /*
                   1858:      * Discard all mouse messages during certain operations.
                   1859:      */
                   1860:     if (gfDisabled)
                   1861:         return;
                   1862: 
                   1863:     switch (gState) {
                   1864:         case STATE_PREDRAG:
                   1865:             /*
                   1866:              * They released the mouse button during the debounce time,
                   1867:              * so cancel the drag.
                   1868:              */
                   1869:             DragCancel();
                   1870:             break;
                   1871: 
                   1872:         case STATE_DRAGGING:
                   1873:         case STATE_DRAGGINGNEW:
                   1874:             DragEnd(x, y);
                   1875:             break;
                   1876: 
                   1877:         case STATE_SELECTING:
                   1878:             OutlineSelectEnd(x, y);
                   1879:             break;
                   1880: 
                   1881:         default:
                   1882:             break;
                   1883:     }
                   1884: }
                   1885: 
                   1886: 
                   1887: 
                   1888: /************************************************************************
                   1889: * DragEnd
                   1890: *
                   1891: * This function completes all kinds of drag operations.  If dragging a
                   1892: * new control, it will be dropped at the specified location.  If dragging
                   1893: * an existing control, it will be positioned to the given location.
                   1894: *
                   1895: * Arguments:
                   1896: *   INT x - X location the control ended up at (in window coords).
                   1897: *   INT y - Y location the control ended up at (in window coords).
                   1898: *
                   1899: ************************************************************************/
                   1900: 
                   1901: VOID DragEnd(
                   1902:     INT x,
                   1903:     INT y)
                   1904: {
                   1905:     PDIALOGBOXHEADER pdbh;
                   1906:     PCONTROLDATA pcd;
                   1907:     INT cControls;
                   1908:     RECT rc;
                   1909:     INT i;
                   1910:     INT cx;
                   1911:     INT cy;
                   1912: 
                   1913:     CancelTracking();
                   1914:     MouseToDragRect(x, y, &rc);
                   1915: 
                   1916:     if (gState == STATE_DRAGGING) {
                   1917:         PositionControl(&rc);
                   1918:     }
                   1919:     else {
                   1920:         if (gpResCopy) {
                   1921:             pdbh = (PDIALOGBOXHEADER)SkipResHeader(gpResCopy);
                   1922:             cControls = (INT)pdbh->NumberOfItems;
                   1923:             pcd = SkipDialogBoxHeader(pdbh);
                   1924:             cx = rc.left - grcCopy.left;
                   1925:             cy = rc.top - grcCopy.top;
                   1926: 
                   1927:             /*
                   1928:              * Loop through all the controls, adjusting their position
                   1929:              * according to where the drag rectangle ended up.
                   1930:              */
                   1931:             for (i = 0; i < cControls; i++) {
                   1932:                 /*
                   1933:                  * Add cx and cy to the resource's x and y fields.
                   1934:                  */
                   1935:                 pcd->x += (WORD)cx;
                   1936:                 pcd->y += (WORD)cy;
                   1937: 
                   1938:                 pcd = SkipControlData(pcd);
                   1939:             }
                   1940: 
                   1941:             /*
                   1942:              * Now we go and create all the controls, adding them to
                   1943:              * the current dialog.  It is assumed that the image in
                   1944:              * gpResCopy specifies controls to add, and not a dialog
                   1945:              * to create!
                   1946:              */
                   1947:             if (ResToDialog(gpResCopy, FALSE)) {
                   1948:                 gfResChged = gfDlgChanged = TRUE;
                   1949:                 ShowFileStatus(FALSE);
                   1950:             }
                   1951: 
                   1952:             MyFree(gpResCopy);
                   1953:             gpResCopy = NULL;
                   1954: 
                   1955:             StatusUpdate();
                   1956:             StatusSetEnable();
                   1957:         }
                   1958:         else {
                   1959:             /*
                   1960:              * Drop the new control.
                   1961:              */
                   1962:             DropControl(gpwcdCurTool, &rc);
                   1963: 
                   1964:             if (!gfToolLocked)
                   1965:                 ToolboxSelectTool(W_NOTHING, FALSE);
                   1966:         }
                   1967:     }
                   1968: 
                   1969:     gState = STATE_NORMAL;
                   1970:     ReleaseCapture();
                   1971:     SetCursor(hcurArrow);
                   1972: }

unix.superglobalmegacorp.com

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