Annotation of mstools/samples/sdktools/dlgedit/drag.c, revision 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.