Annotation of mstools/samples/sdktools/dlgedit/select.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: select.c
        !            14: *
        !            15: * Contains routines for selecting and positioning controls.
        !            16: *
        !            17: * Functions:
        !            18: *
        !            19: *    SelectControl()
        !            20: *    SelectControl2()
        !            21: *    RedrawSelection()
        !            22: *    SetAnchorToFirstSel()
        !            23: *    SelectNext()
        !            24: *    SelectPrevious()
        !            25: *    UnSelectControl()
        !            26: *    CalcSelectedRect()
        !            27: *    CancelSelection()
        !            28: *    OutlineSelectBegin()
        !            29: *    OutlineSelectDraw()
        !            30: *    OutlineSelectCancel()
        !            31: *    OutlineSelectEnd()
        !            32: *    MyFrameRect()
        !            33: *    MoveControl()
        !            34: *    PositionControl()
        !            35: *    RepositionDialog()
        !            36: *    SaveDlgClientRect()
        !            37: *    SizeToText()
        !            38: *    AlignControls()
        !            39: *    ArrangeSpacing()
        !            40: *    ArrangeSize()
        !            41: *    ArrangePushButtons()
        !            42: *    InvalidateDlgHandles()
        !            43: *    OutlineSelectHide()
        !            44: *    OutlineSelectSetRect()
        !            45: *    PositionControl2()
        !            46: *    SizeCtrlToText()
        !            47: *    QueryTextExtent()
        !            48: *
        !            49: * Comments:
        !            50: *
        !            51: ****************************************************************************/
        !            52: 
        !            53: #include "dlgedit.h"
        !            54: #include "dlgfuncs.h"
        !            55: #include "dlgextrn.h"
        !            56: 
        !            57: 
        !            58: STATICFN VOID InvalidateDlgHandles(VOID);
        !            59: STATICFN VOID OutlineSelectHide(VOID);
        !            60: STATICFN VOID OutlineSelectSetRect(INT x, INT y);
        !            61: STATICFN HANDLE PositionControl2(NPCTYPE npc, PRECT prc, HANDLE hwpi);
        !            62: STATICFN BOOL SizeCtrlToText(NPCTYPE npc);
        !            63: STATICFN INT QueryTextExtent(HWND hwnd, LPTSTR pszText, BOOL fWordBreak);
        !            64: 
        !            65: static POINT gptOutlineSelect;
        !            66: static RECT grcOutlineSelect;
        !            67: static RECT grcOutlineSelectLimit;
        !            68: static BOOL gfOutlineSelectShown = FALSE;
        !            69: 
        !            70: 
        !            71: 
        !            72: /************************************************************************
        !            73: * SelectControl
        !            74: *
        !            75: * This routine selects a control, showing its drag window and handles.
        !            76: * If fCheckShift is TRUE and the shift key is down, this routine adds
        !            77: * the control to the existing selection, unless the control is already
        !            78: * selected, in which case it is removed from the existing selection.
        !            79: *
        !            80: * This routine handles the case where a controls is clicked on to select
        !            81: * it, and this may cause other controls to be unselected.  If it is
        !            82: * known for sure that a control should be selected or added to the
        !            83: * existing selection, SelectControl2 can be used instead.
        !            84: *
        !            85: * Arguments:
        !            86: *   NPCTYPE npc      = The control to select.
        !            87: *   BOOL fCheckShift = TRUE if the state of the shift key should be
        !            88: *                      taken into consideration.
        !            89: *
        !            90: * Returns:
        !            91: *   The return will be FALSE if the control was just unselected.
        !            92: *
        !            93: ************************************************************************/
        !            94: 
        !            95: BOOL SelectControl(
        !            96:     NPCTYPE npc,
        !            97:     BOOL fCheckShift)
        !            98: {
        !            99:     BOOL fShiftDown;
        !           100:     BOOL fSelectDone = TRUE;
        !           101: 
        !           102:     if (npc->pwcd->iType == W_DIALOG) {
        !           103:         if (gnpcSel == npc)
        !           104:             return TRUE;
        !           105: 
        !           106:         CancelSelection(FALSE);
        !           107:         SelectControl2(npc, FALSE);
        !           108:     }
        !           109:     else {
        !           110:         if (fCheckShift)
        !           111:             fShiftDown = (GetKeyState(VK_SHIFT) & 0x8000) ? TRUE : FALSE;
        !           112:         else
        !           113:             fShiftDown = FALSE;
        !           114: 
        !           115:         if (npc->fSelected) {
        !           116:             /*
        !           117:              * If the shift key is down, and they are NOT trying to
        !           118:              * select the dialog, toggle the selection of this control
        !           119:              * to off.
        !           120:              */
        !           121:             if (fShiftDown && npc->pwcd->iType != W_DIALOG) {
        !           122:                 UnSelectControl(npc);
        !           123:                 CalcSelectedRect();
        !           124:                 fSelectDone = FALSE;
        !           125:             }
        !           126:             else {
        !           127:                 if (gnpcSel == npc)
        !           128:                     return TRUE;
        !           129:                 else
        !           130:                     SelectControl2(npc, FALSE);
        !           131:             }
        !           132:         }
        !           133:         else {
        !           134:             /*
        !           135:              * If they are NOT holding the shift key down, or the
        !           136:              * dialog is selected, cancel the selection first.
        !           137:              */
        !           138:             if (!fShiftDown || gcd.npc->fSelected == TRUE)
        !           139:                 CancelSelection(FALSE);
        !           140: 
        !           141:             SelectControl2(npc, FALSE);
        !           142:         }
        !           143:     }
        !           144: 
        !           145:     StatusUpdate();
        !           146:     StatusSetEnable();
        !           147: 
        !           148:     return fSelectDone;
        !           149: }
        !           150: 
        !           151: 
        !           152: 
        !           153: /************************************************************************
        !           154: * SelectControl2
        !           155: *
        !           156: * This routine is the worker for SelectControl.  It does the actual
        !           157: * work to "select" a control, updating globals and showing the drag
        !           158: * windows with handles.
        !           159: *
        !           160: * This routine handles the special case where we are selecting a
        !           161: * control that is already selected.  The editor has the concept of
        !           162: * a control being selected, as well as there being the currently
        !           163: * selected control (pointed to by gnpcSel).  There can be the case
        !           164: * where there are multiple controls selected, but only one will be
        !           165: * the current selection (usually the last one clicked on).  This
        !           166: * routine will never unselect other controls.  This must be done
        !           167: * prior to here, if appropriate.
        !           168: *
        !           169: * Arguments:
        !           170: *   NPCTYPE npc      = The control to make the current selection.
        !           171: *   BOOL fDontUpdate = TRUE if the selection should NOT be redrawn
        !           172: *                      after the specified control is added to it.
        !           173: *                      This allows painting to be deferred until
        !           174: *                      later if a number of controls are being
        !           175: *                      selected in a loop.  It also does not call
        !           176: *                      CalcSelectedRect (this MUST be done later
        !           177: *                      for drags to work, however!).
        !           178: * Comments:
        !           179: *
        !           180: * If fDontUpdate is TRUE, the selection will not be redrawn, and it
        !           181: * is required that CalcSelectedRect be called before doing any drag
        !           182: * operations.
        !           183: *
        !           184: ************************************************************************/
        !           185: 
        !           186: VOID SelectControl2(
        !           187:     NPCTYPE npc,
        !           188:     BOOL fDontUpdate)
        !           189: {
        !           190:     BOOL fUpdate = FALSE;
        !           191: 
        !           192:     /*
        !           193:      * Is the control already selected?
        !           194:      */
        !           195:     if (npc->fSelected) {
        !           196:         /*
        !           197:          * It is already selected (hwndDrag is visible).  If it is
        !           198:          * not the current selection, we want all drag windows to
        !           199:          * be redrawn in the proper order to update their appearance.
        !           200:          */
        !           201:         if (gnpcSel != npc)
        !           202:             fUpdate = TRUE;
        !           203:     }
        !           204:     else {
        !           205:         /*
        !           206:          * The control is not yet selected.  If another control is
        !           207:          * currently selected, we want all drag windows to be
        !           208:          * updated so that their handle appearance gets updated.
        !           209:          */
        !           210:         if (gnpcSel)
        !           211:             fUpdate = TRUE;
        !           212: 
        !           213:         /*
        !           214:          * Flip its flag and add to the selected count.
        !           215:          */
        !           216:         npc->fSelected = TRUE;
        !           217:         gcSelected++;
        !           218:     }
        !           219: 
        !           220:     gnpcSel = npc;
        !           221: 
        !           222:     if (!fDontUpdate)
        !           223:         CalcSelectedRect();
        !           224: 
        !           225:     if (npc->pwcd->iType == W_DIALOG) {
        !           226:         gfDlgSelected = TRUE;
        !           227:         InvalidateDlgHandles();
        !           228:     }
        !           229:     else {
        !           230:         gfDlgSelected = FALSE;
        !           231:         ShowWindow(npc->hwndDrag, SW_SHOW);
        !           232: 
        !           233:         if (fUpdate && !fDontUpdate)
        !           234:             RedrawSelection();
        !           235:     }
        !           236: }
        !           237: 
        !           238: 
        !           239: 
        !           240: /************************************************************************
        !           241: * RedrawSelection
        !           242: *
        !           243: * This function cause all the selected drag windows to be invalidated.
        !           244: * This is necessary whenever one of them changes, because of the very
        !           245: * touchy painting order that has to be maintained.  Without invalidating
        !           246: * all of them as a unit, there are cases where handles do not get
        !           247: * properly painted.
        !           248: *
        !           249: ************************************************************************/
        !           250: 
        !           251: VOID RedrawSelection(VOID)
        !           252: {
        !           253:     NPCTYPE npc;
        !           254: 
        !           255:     if (!gcSelected) {
        !           256:         return;
        !           257:     }
        !           258:     else if (gcSelected == 1) {
        !           259:         InvalidateRect(gfDlgSelected ? gnpcSel->hwnd : gnpcSel->hwndDrag,
        !           260:                 NULL, TRUE);
        !           261:     }
        !           262:     else {
        !           263:         for (npc = npcHead; npc; npc = npc->npcNext) {
        !           264:             if (npc->fSelected)
        !           265:                 InvalidateRect(npc->hwndDrag, NULL, TRUE);
        !           266:         }
        !           267:     }
        !           268: }
        !           269: 
        !           270: 
        !           271: 
        !           272: /************************************************************************
        !           273: * SetAnchorToFirstSel
        !           274: *
        !           275: * This function makes the current selection (the anchor) be the
        !           276: * first selected control.  It is used after making a group selection,
        !           277: * and ensures that the control that ends up being the anchor is
        !           278: * consistently the first one in Z-order.
        !           279: *
        !           280: * Arguments:
        !           281: *   BOOL fDontUpdate = TRUE if the selection should NOT be redrawn.
        !           282: *
        !           283: ************************************************************************/
        !           284: 
        !           285: VOID SetAnchorToFirstSel(
        !           286:     BOOL fDontUpdate)
        !           287: {
        !           288:     NPCTYPE npc;
        !           289: 
        !           290:     if (gcSelected) {
        !           291:         for (npc = npcHead; npc; npc = npc->npcNext) {
        !           292:             if (npc->fSelected) {
        !           293:                 SelectControl2(npc, fDontUpdate);
        !           294:                 break;
        !           295:             }
        !           296:         }
        !           297:     }
        !           298: }
        !           299: 
        !           300: 
        !           301: 
        !           302: /************************************************************************
        !           303: * SelectNext
        !           304: *
        !           305: * This selects the next control in the dialog box.  The enumeration
        !           306: * includes the dialog box itself, and wraps around.
        !           307: *
        !           308: ************************************************************************/
        !           309: 
        !           310: VOID SelectNext(VOID)
        !           311: {
        !           312:     NPCTYPE npcSelect;
        !           313: 
        !           314:     /*
        !           315:      * Disable the tabbing functions if there is no dialog
        !           316:      * or if the dialog is already selected and there are
        !           317:      * no controls (the tabs would be a noop in this case).
        !           318:      */
        !           319:     if (!gfEditingDlg || (gfDlgSelected && !npcHead))
        !           320:         return;
        !           321: 
        !           322:     /*
        !           323:      * Is nothing selected?
        !           324:      */
        !           325:     if (!gnpcSel) {
        !           326:         /*
        !           327:          * Select the first control, unless there are none, in which
        !           328:          * case select the dialog.
        !           329:          */
        !           330:         if (npcHead)
        !           331:             npcSelect = npcHead;
        !           332:         else
        !           333:             npcSelect = gcd.npc;
        !           334:     }
        !           335:     else {
        !           336:         /*
        !           337:          * Is the dialog selected?
        !           338:          */
        !           339:         if (gfDlgSelected) {
        !           340:             /*
        !           341:              * Select the first control, unless there are none, in which
        !           342:              * case do nothing.
        !           343:              */
        !           344:             if (npcHead)
        !           345:                 npcSelect = npcHead;
        !           346:             else
        !           347:                 npcSelect = NULL;
        !           348:         }
        !           349:         else {
        !           350:             /*
        !           351:              * Find the current control.  If there is one after it,
        !           352:              * select it, otherwise wrap around to the dialog and
        !           353:              * select it.
        !           354:              */
        !           355:             if (gnpcSel->npcNext)
        !           356:                 npcSelect = gnpcSel->npcNext;
        !           357:             else
        !           358:                 npcSelect = gcd.npc;
        !           359:         }
        !           360:     }
        !           361: 
        !           362:     if (npcSelect)
        !           363:         SelectControl(npcSelect, FALSE);
        !           364: }
        !           365: 
        !           366: 
        !           367: 
        !           368: /************************************************************************
        !           369: * SelectPrevious
        !           370: *
        !           371: * This selects the previous control in the dialog box.  The enumeration
        !           372: * includes the dialog box itself, and wraps around.
        !           373: *
        !           374: ************************************************************************/
        !           375: 
        !           376: VOID SelectPrevious(VOID)
        !           377: {
        !           378:     NPCTYPE npc;
        !           379:     NPCTYPE npcSelect;
        !           380: 
        !           381:     /*
        !           382:      * Disable the tabbing functions if there is no dialog
        !           383:      * or if the dialog is already selected and there are
        !           384:      * no controls (the tabs would be a noop in this case).
        !           385:      */
        !           386:     if (!gfEditingDlg || (gfDlgSelected && !npcHead))
        !           387:         return;
        !           388: 
        !           389:     /*
        !           390:      * Is nothing selected?
        !           391:      */
        !           392:     if (!gnpcSel) {
        !           393:         /*
        !           394:          * Select the last control, unless there are none, in which
        !           395:          * case select the dialog.
        !           396:          */
        !           397:         if (npcHead) {
        !           398:             npc = npcHead;
        !           399:             while (npc->npcNext)
        !           400:                 npc = npc->npcNext;
        !           401: 
        !           402:             npcSelect = npc;
        !           403:         }
        !           404:         else {
        !           405:             npcSelect = gcd.npc;
        !           406:         }
        !           407:     }
        !           408:     else {
        !           409:         /*
        !           410:          * Is the dialog selected?
        !           411:          */
        !           412:         if (gfDlgSelected) {
        !           413:             /*
        !           414:              * Select the last control, unless there are none, in which
        !           415:              * case select nothing.
        !           416:              */
        !           417:             if (npcHead) {
        !           418:                 npc = npcHead;
        !           419:                 while (npc->npcNext)
        !           420:                     npc = npc->npcNext;
        !           421: 
        !           422:                 npcSelect = npc;
        !           423:             }
        !           424:             else {
        !           425:                 npcSelect = NULL;
        !           426:             }
        !           427:         }
        !           428:         else {
        !           429:             /*
        !           430:              * If the first control is selected, select the dialog.
        !           431:              * Otherwise hunt for and select the previous control.
        !           432:              */
        !           433:             if (npcHead == gnpcSel) {
        !           434:                 npcSelect = gcd.npc;
        !           435:             }
        !           436:             else {
        !           437:                 npc = npcHead;
        !           438:                 while (npc->npcNext != gnpcSel)
        !           439:                     npc = npc->npcNext;
        !           440: 
        !           441:                 npcSelect = npc;
        !           442:             }
        !           443:         }
        !           444:     }
        !           445: 
        !           446:     if (npcSelect)
        !           447:         SelectControl(npcSelect, FALSE);
        !           448: }
        !           449: 
        !           450: 
        !           451: 
        !           452: /************************************************************************
        !           453: * UnSelectControl
        !           454: *
        !           455: * This unselects the specified control, hiding its drag window and handles.
        !           456: *
        !           457: * Arguments:
        !           458: *     NPCTYPE npc = The control to deselect.
        !           459: *
        !           460: ************************************************************************/
        !           461: 
        !           462: VOID UnSelectControl(
        !           463:     NPCTYPE npc)
        !           464: {
        !           465:     npc->fSelected = FALSE;
        !           466:     gcSelected--;
        !           467: 
        !           468:     /*
        !           469:      * We don't have a current selection if there are no selected
        !           470:      * windows, or if the control we are unselecting was the current
        !           471:      * selection.
        !           472:      */
        !           473:     if (!gcSelected || npc == gnpcSel)
        !           474:         gnpcSel = NULL;
        !           475: 
        !           476:     if (npc->pwcd->iType == W_DIALOG) {
        !           477:         gfDlgSelected = FALSE;
        !           478:         InvalidateDlgHandles();
        !           479:     }
        !           480:     else {
        !           481:         ShowWindow(npc->hwndDrag, SW_HIDE);
        !           482:     }
        !           483: 
        !           484:     /*
        !           485:      * Are there still some selected controls, and was the control
        !           486:      * we just unselected the current selection?  If so, we need
        !           487:      * to set the current selection to something.
        !           488:      */
        !           489:     if (gcSelected && !gnpcSel)
        !           490:         SetAnchorToFirstSel(FALSE);
        !           491: }
        !           492: 
        !           493: 
        !           494: 
        !           495: /************************************************************************
        !           496: * InvalidateDlgHandles
        !           497: *
        !           498: * This function invalidates the handles for the dialog.  This is
        !           499: * used as an optimization so that the entire dialog does not need
        !           500: * to be invalidated just to force the handles to be drawn.
        !           501: *
        !           502: ************************************************************************/
        !           503: 
        !           504: STATICFN VOID InvalidateDlgHandles(VOID)
        !           505: {
        !           506:     RECT rc;
        !           507:     RECT rcClient;
        !           508:     RECT rcFrame;
        !           509:     POINT pt;
        !           510:     INT xOffset;
        !           511:     INT yOffset;
        !           512: 
        !           513:     /*
        !           514:      * Redraw the dialog border.
        !           515:      */
        !           516:     SetWindowPos(gcd.npc->hwnd, NULL, 0, 0, 0, 0,
        !           517:             SWP_DRAWFRAME | SWP_NOACTIVATE |
        !           518:             SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
        !           519: 
        !           520:     /*
        !           521:      * Get the frame and client rectangles.
        !           522:      */
        !           523:     GetWindowRect(gcd.npc->hwnd, &rcFrame);
        !           524:     GetClientRect(gcd.npc->hwnd, &rcClient);
        !           525: 
        !           526:     /*
        !           527:      * Determine the offset from the frame origin to the client
        !           528:      * origin.
        !           529:      */
        !           530:     pt.x = pt.y = 0;
        !           531:     ClientToScreen(gcd.npc->hwnd, &pt);
        !           532:     xOffset = rcFrame.left - pt.x;
        !           533:     yOffset = rcFrame.top - pt.y;
        !           534: 
        !           535:     /*
        !           536:      * Make the frame rectangle zero based.
        !           537:      */
        !           538:     OffsetRect(&rcFrame, -rcFrame.left, -rcFrame.top);
        !           539: 
        !           540:     rc.left = 0;
        !           541:     rc.top = 0;
        !           542:     rc.right = CHANDLESIZE;
        !           543:     rc.bottom = CHANDLESIZE;
        !           544:     OffsetRect(&rc, xOffset, yOffset);
        !           545:     InvalidateRect(gcd.npc->hwnd, &rc, TRUE);
        !           546: 
        !           547:     rc.left = ((rcFrame.right + 1) / 2) - (CHANDLESIZE / 2);
        !           548:     rc.top = 0;
        !           549:     rc.right = rc.left + CHANDLESIZE;
        !           550:     rc.bottom = CHANDLESIZE;
        !           551:     OffsetRect(&rc, xOffset, yOffset);
        !           552:     InvalidateRect(gcd.npc->hwnd, &rc, TRUE);
        !           553: 
        !           554:     rc.left = rcFrame.right - CHANDLESIZE;
        !           555:     rc.top = 0;
        !           556:     rc.right = rcFrame.right;
        !           557:     rc.bottom = CHANDLESIZE;
        !           558:     OffsetRect(&rc, xOffset, yOffset);
        !           559:     InvalidateRect(gcd.npc->hwnd, &rc, TRUE);
        !           560: 
        !           561:     rc.left = rcFrame.right - CHANDLESIZE;
        !           562:     rc.top = ((rcFrame.bottom + 1) / 2) - (CHANDLESIZE / 2);
        !           563:     rc.right = rcFrame.right;
        !           564:     rc.bottom = rc.top + CHANDLESIZE;
        !           565:     OffsetRect(&rc, xOffset, yOffset);
        !           566:     InvalidateRect(gcd.npc->hwnd, &rc, TRUE);
        !           567: 
        !           568:     rc.left = rcFrame.right - CHANDLESIZE;
        !           569:     rc.top = rcFrame.bottom - CHANDLESIZE;
        !           570:     rc.right = rcFrame.right;
        !           571:     rc.bottom = rcFrame.bottom;
        !           572:     OffsetRect(&rc, xOffset, yOffset);
        !           573:     InvalidateRect(gcd.npc->hwnd, &rc, TRUE);
        !           574: 
        !           575:     rc.left = ((rcFrame.right + 1) / 2) - (CHANDLESIZE / 2);
        !           576:     rc.top = rcFrame.bottom - CHANDLESIZE;
        !           577:     rc.right = rc.left + CHANDLESIZE;
        !           578:     rc.bottom = rcFrame.bottom;
        !           579:     OffsetRect(&rc, xOffset, yOffset);
        !           580:     InvalidateRect(gcd.npc->hwnd, &rc, TRUE);
        !           581: 
        !           582:     rc.left = 0;
        !           583:     rc.top = rcFrame.bottom - CHANDLESIZE;
        !           584:     rc.right = CHANDLESIZE;
        !           585:     rc.bottom = rcFrame.bottom;
        !           586:     OffsetRect(&rc, xOffset, yOffset);
        !           587:     InvalidateRect(gcd.npc->hwnd, &rc, TRUE);
        !           588: 
        !           589:     rc.left = 0;
        !           590:     rc.top = ((rcFrame.bottom + 1) / 2) - (CHANDLESIZE / 2);
        !           591:     rc.right = CHANDLESIZE;
        !           592:     rc.bottom = rc.top + CHANDLESIZE;
        !           593:     OffsetRect(&rc, xOffset, yOffset);
        !           594:     InvalidateRect(gcd.npc->hwnd, &rc, TRUE);
        !           595: }
        !           596: 
        !           597: 
        !           598: 
        !           599: /************************************************************************
        !           600: * CalcSelectedRect
        !           601: *
        !           602: * This routine updates the gwrcSelected rectangle.  This is used during
        !           603: * dragging operations.  It contains the minimum rectangle that spans
        !           604: * all the selected controls.  If there are no selected controls, the
        !           605: * contents of this global are not defined.  This routine must be called
        !           606: * every time that a control is selected of unselected to keep this
        !           607: * rectangle updated, or tracking will not work properly.
        !           608: *
        !           609: ************************************************************************/
        !           610: 
        !           611: VOID CalcSelectedRect(VOID)
        !           612: {
        !           613:     NPCTYPE npc;
        !           614:     INT nBottom;
        !           615:     INT nBottomLowest;
        !           616: 
        !           617:     /*
        !           618:      * Nothing is selected.  The rectangle values are considered
        !           619:      * undefined, so we can quit.
        !           620:      */
        !           621:     if (!gcSelected)
        !           622:         return;
        !           623: 
        !           624:     if (gcSelected == 1) {
        !           625:         /*
        !           626:          * Only one control is selected.  Set the rectangle to its
        !           627:          * rectangle.  Note that since the dialog cannot be selected
        !           628:          * along with other controls, this handles the case where the
        !           629:          * dialog is selected.
        !           630:          */
        !           631:         grcSelected = gnpcSel->rc;
        !           632:         gnOverHang = GetOverHang(gnpcSel->pwcd->iType,
        !           633:                 gnpcSel->rc.bottom - gnpcSel->rc.top);
        !           634:     }
        !           635:     else {
        !           636:         /*
        !           637:          * Seed the rectangle with impossible values.
        !           638:          */
        !           639:         SetRect(&grcSelected, 32000, 32000, -32000, -32000);
        !           640:         nBottomLowest = 0;
        !           641: 
        !           642:         /*
        !           643:          * Loop through all the controls, expanding the rectangle to
        !           644:          * fit around all the selected controls.
        !           645:          */
        !           646:         for (npc = npcHead; npc; npc = npc->npcNext) {
        !           647:             if (npc->fSelected) {
        !           648:                 if (npc->rc.left < grcSelected.left)
        !           649:                     grcSelected.left = npc->rc.left;
        !           650: 
        !           651:                 if (npc->rc.right > grcSelected.right)
        !           652:                     grcSelected.right = npc->rc.right;
        !           653: 
        !           654:                 if (npc->rc.top < grcSelected.top)
        !           655:                     grcSelected.top = npc->rc.top;
        !           656: 
        !           657:                 nBottom = npc->rc.bottom - GetOverHang(npc->pwcd->iType,
        !           658:                         npc->rc.bottom - npc->rc.top);
        !           659:                 if (nBottom > nBottomLowest)
        !           660:                     nBottomLowest = nBottom;
        !           661: 
        !           662:                 if (npc->rc.bottom > grcSelected.bottom)
        !           663:                     grcSelected.bottom = npc->rc.bottom;
        !           664:             }
        !           665:         }
        !           666: 
        !           667:         gnOverHang = grcSelected.bottom - nBottomLowest;
        !           668:     }
        !           669: }
        !           670: 
        !           671: 
        !           672: 
        !           673: /************************************************************************
        !           674: * CancelSelection
        !           675: *
        !           676: * This unselects all selected controls.
        !           677: *
        !           678: * Arguments:
        !           679: *   BOOL fUpdate - If TRUE, the status ribbon is updated.
        !           680: *
        !           681: ************************************************************************/
        !           682: 
        !           683: VOID CancelSelection(
        !           684:     BOOL fUpdate)
        !           685: {
        !           686:     if (gcSelected) {
        !           687:         while (gcSelected)
        !           688:             UnSelectControl(gnpcSel);
        !           689: 
        !           690:         if (fUpdate) {
        !           691:             StatusUpdate();
        !           692:             StatusSetEnable();
        !           693:         }
        !           694:     }
        !           695: }
        !           696: 
        !           697: 
        !           698: 
        !           699: /************************************************************************
        !           700: * OutlineSelectBegin
        !           701: *
        !           702: * This function begins an Outline Selection operation.  This will
        !           703: * draw a tracking rectangle on the screen that can be used to enclose
        !           704: * controls.  When the selection is completed, all the enclosed controls
        !           705: * will be selected.
        !           706: *
        !           707: * The x and y coordinates are relative to the dialog window, not it's
        !           708: * client.
        !           709: *
        !           710: * Arguments:
        !           711: *   INT x   - Starting X location (window coords).
        !           712: *   INT y   - Starting Y location (window coords).
        !           713: *
        !           714: ************************************************************************/
        !           715: 
        !           716: VOID OutlineSelectBegin(
        !           717:     INT x,
        !           718:     INT y)
        !           719: {
        !           720:     /*
        !           721:      * Always be sure the focus is where we want it, not on something
        !           722:      * like the status ribbon or "Esc" won't work to cancel the tracking.
        !           723:      */
        !           724:     SetFocus(ghwndMain);
        !           725: 
        !           726:     /*
        !           727:      * Remember the starting point.  It comes in coords relative to the
        !           728:      * window, and the DC we are getting is one for the dialog's client,
        !           729:      * so we have to map it from window coords to the client's coords.
        !           730:      */
        !           731:     gptOutlineSelect.x = x;
        !           732:     gptOutlineSelect.y = y;
        !           733:     MapDlgClientPoint(&gptOutlineSelect, FALSE);
        !           734: 
        !           735:     gState = STATE_SELECTING;
        !           736:     ghwndTrackOver = gcd.npc->hwnd;
        !           737:     ghDCTrack = GetDC(ghwndTrackOver);
        !           738:     SetROP2(ghDCTrack, R2_NOT);
        !           739: 
        !           740:     /*
        !           741:      * Get the rectangle for the client area of the dialog.  This is
        !           742:      * used to limit the tracking.
        !           743:      */
        !           744:     GetClientRect(gcd.npc->hwnd, &grcOutlineSelectLimit);
        !           745:     OutlineSelectDraw(x, y);
        !           746: 
        !           747:     /*
        !           748:      * The mouse messages from now on will go to the dialog window,
        !           749:      * so that the following routines can know that the mouse movement
        !           750:      * points are relative to that window.
        !           751:      */
        !           752:     SetCapture(gcd.npc->hwnd);
        !           753: 
        !           754:     SetCursor(hcurOutSel);
        !           755: }
        !           756: 
        !           757: 
        !           758: 
        !           759: /************************************************************************
        !           760: * OutlineSelectDraw
        !           761: *
        !           762: * This routine draws the outline selection rectangle.  It is assumed
        !           763: * that the window has been locked for update appropriately or this
        !           764: * could leave garbage around.  The outline selection rectangle is
        !           765: * drawn from the starting point in gptOutlineSelect to the given
        !           766: * x,y location.
        !           767: *
        !           768: * Arguments:
        !           769: *   INT x   - Mouse X location (window coords relative to the dialog).
        !           770: *   INT y   - Mouse Y location (window coords relative to the dialog).
        !           771: *
        !           772: ************************************************************************/
        !           773: 
        !           774: VOID OutlineSelectDraw(
        !           775:     INT x,
        !           776:     INT y)
        !           777: {
        !           778:     OutlineSelectHide();
        !           779:     OutlineSelectSetRect(x, y);
        !           780:     MyFrameRect(ghDCTrack, &grcOutlineSelect, DSTINVERT);
        !           781:     gfOutlineSelectShown = TRUE;
        !           782: }
        !           783: 
        !           784: 
        !           785: 
        !           786: /************************************************************************
        !           787: * OutlineSelectHide
        !           788: *
        !           789: * This routine hides the current outline selection rectangle.
        !           790: *
        !           791: ************************************************************************/
        !           792: 
        !           793: STATICFN VOID OutlineSelectHide(VOID)
        !           794: {
        !           795:     if (gfOutlineSelectShown) {
        !           796:         MyFrameRect(ghDCTrack, &grcOutlineSelect, DSTINVERT);
        !           797:         gfOutlineSelectShown = FALSE;
        !           798:     }
        !           799: }
        !           800: 
        !           801: 
        !           802: 
        !           803: /************************************************************************
        !           804: * OutlineSelectSetRect
        !           805: *
        !           806: * This function takes an x,y point and makes a rectangle that goes
        !           807: * from this point to the starting outline selection point.  The cases
        !           808: * are handled where the new point has negative coordinates relative
        !           809: * to the starting point, and the rectangle produced is limited to
        !           810: * the rectangle in grcOutlineSelectLimit.
        !           811: *
        !           812: * The rectangle is placed into the global grcOutlineSelect.  The
        !           813: * global point gwptOutlineSelect is assumed to have previously been
        !           814: * set to the starting point of the outline selection.
        !           815: *
        !           816: * The x and y coordinates are relative to the dialog window, not it's
        !           817: * client.
        !           818: *
        !           819: * Arguments:
        !           820: *   INT x   - Mouse X location (window coords relative to the dialog).
        !           821: *   INT y   - Mouse Y location (window coords relative to the dialog).
        !           822: *
        !           823: ************************************************************************/
        !           824: 
        !           825: STATICFN VOID OutlineSelectSetRect(
        !           826:     INT x,
        !           827:     INT y)
        !           828: {
        !           829:     POINT pt;
        !           830: 
        !           831:     /*
        !           832:      * The point is coming in relative to the upper left of the
        !           833:      * dialog window.  It needs to be mapped to points relative
        !           834:      * to the client of the dialog window.
        !           835:      */
        !           836:     pt.x = x;
        !           837:     pt.y = y;
        !           838:     MapDlgClientPoint(&pt, FALSE);
        !           839: 
        !           840:     if (pt.x > gptOutlineSelect.x) {
        !           841:         grcOutlineSelect.left = gptOutlineSelect.x;
        !           842:         grcOutlineSelect.right = pt.x;
        !           843:     }
        !           844:     else {
        !           845:         grcOutlineSelect.left = pt.x;
        !           846:         grcOutlineSelect.right = gptOutlineSelect.x;
        !           847:     }
        !           848: 
        !           849:     if (pt.y > gptOutlineSelect.y) {
        !           850:         grcOutlineSelect.top = gptOutlineSelect.y;
        !           851:         grcOutlineSelect.bottom = pt.y;
        !           852:     }
        !           853:     else {
        !           854:         grcOutlineSelect.top = pt.y;
        !           855:         grcOutlineSelect.bottom = gptOutlineSelect.y;
        !           856:     }
        !           857: 
        !           858:     if (grcOutlineSelect.left < grcOutlineSelectLimit.left)
        !           859:         grcOutlineSelect.left = grcOutlineSelectLimit.left;
        !           860: 
        !           861:     if (grcOutlineSelect.right > grcOutlineSelectLimit.right)
        !           862:         grcOutlineSelect.right = grcOutlineSelectLimit.right;
        !           863: 
        !           864:     if (grcOutlineSelect.top < grcOutlineSelectLimit.top)
        !           865:         grcOutlineSelect.top = grcOutlineSelectLimit.top;
        !           866: 
        !           867:     if (grcOutlineSelect.bottom > grcOutlineSelectLimit.bottom)
        !           868:         grcOutlineSelect.bottom = grcOutlineSelectLimit.bottom;
        !           869: }
        !           870: 
        !           871: 
        !           872: 
        !           873: /************************************************************************
        !           874: * OutlineSelectCancel
        !           875: *
        !           876: * This routine is used to cancel the display of the outline selection
        !           877: * rectangle.
        !           878: *
        !           879: ************************************************************************/
        !           880: 
        !           881: VOID OutlineSelectCancel(VOID)
        !           882: {
        !           883:     OutlineSelectHide();
        !           884:     ReleaseDC(ghwndTrackOver, ghDCTrack);
        !           885: 
        !           886:     gState = STATE_NORMAL;
        !           887:     ReleaseCapture();
        !           888:     SetCursor(hcurArrow);
        !           889: }
        !           890: 
        !           891: 
        !           892: 
        !           893: /************************************************************************
        !           894: * OutlineSelectEnd
        !           895: *
        !           896: * This function completes an outline selection operation.  All the
        !           897: * enclosed controls will be selected.  If the Shift key is down,
        !           898: * the enclosed controls will be added to the selection, otherwise the
        !           899: * current selection will be cancelled first.
        !           900: *
        !           901: * The current selection will only be cancelled if there is
        !           902: * at least one new control enclosed.  This is so that simply clicking and
        !           903: * releasing the mouse without enclosing any controls leaves the current
        !           904: * selection alone.
        !           905: *
        !           906: * Arguments:
        !           907: *   INT x   - Mouse X location (dialog client coords).
        !           908: *   INT y   - Mouse Y location (dialog client coords).
        !           909: *
        !           910: ************************************************************************/
        !           911: 
        !           912: VOID OutlineSelectEnd(
        !           913:     INT x,
        !           914:     INT y)
        !           915: {
        !           916:     NPCTYPE npc;
        !           917:     BOOL fFirstOne = TRUE;
        !           918: 
        !           919:     OutlineSelectCancel();
        !           920:     OutlineSelectSetRect(x, y);
        !           921: 
        !           922:     /*
        !           923:      * If the mouse was not moved at all, consider this a request
        !           924:      * to select the dialog instead of an outline selection operation.
        !           925:      */
        !           926:     if (grcOutlineSelect.left == grcOutlineSelect.right &&
        !           927:             grcOutlineSelect.top == grcOutlineSelect.bottom) {
        !           928:         SelectControl(gcd.npc, FALSE);
        !           929:         return;
        !           930:     }
        !           931: 
        !           932:     /*
        !           933:      * Convert the selected rectangle to dialog units.
        !           934:      */
        !           935:     WinToDURect(&grcOutlineSelect);
        !           936: 
        !           937:     for (npc = npcHead; npc; npc = npc->npcNext) {
        !           938:         /*
        !           939:          * Do the rectangles intersect?
        !           940:          */
        !           941:         if (npc->rc.left < grcOutlineSelect.right &&
        !           942:                 grcOutlineSelect.left < npc->rc.right &&
        !           943:                 npc->rc.bottom > grcOutlineSelect.top &&
        !           944:                 grcOutlineSelect.bottom > npc->rc.top) {
        !           945:             if (fFirstOne) {
        !           946:                 /*
        !           947:                  * If the Shift key is not held down, cancel any outstanding
        !           948:                  * selections.
        !           949:                  */
        !           950:                 if (!(GetKeyState(VK_SHIFT) & 0x8000))
        !           951:                     CancelSelection(FALSE);
        !           952: 
        !           953:                 fFirstOne = FALSE;
        !           954:             }
        !           955: 
        !           956:             /*
        !           957:              * If the control is not selected, select it.
        !           958:              */
        !           959:             if (!npc->fSelected)
        !           960:                 SelectControl2(npc, TRUE);
        !           961:         }
        !           962:     }
        !           963: 
        !           964:     /*
        !           965:      * Update some things if there was at least one control enclosed.
        !           966:      */
        !           967:     if (!fFirstOne) {
        !           968:         SetAnchorToFirstSel(TRUE);
        !           969:         StatusUpdate();
        !           970:         StatusSetEnable();
        !           971:         RedrawSelection();
        !           972:         CalcSelectedRect();
        !           973:     }
        !           974: }
        !           975: 
        !           976: 
        !           977: 
        !           978: /************************************************************************
        !           979: * MyFrameRect
        !           980: *
        !           981: * This function draws a one-pixel width rectangle using the given
        !           982: * raster operation.
        !           983: *
        !           984: * Arguments:
        !           985: *   HDC hDC     - DC to use.
        !           986: *   PRECT prc   - Rectangle to draw the frame around.
        !           987: *   DWORD dwRop - RasterOp to use (DSTINVERT, BLACKNESS, etc.).
        !           988: *
        !           989: ************************************************************************/
        !           990: 
        !           991: VOID MyFrameRect(
        !           992:     HDC hDC,
        !           993:     PRECT prc,
        !           994:     DWORD dwRop)
        !           995: {
        !           996:     INT x;
        !           997:     INT y;
        !           998:     POINT pt;
        !           999: 
        !          1000:     x = prc->right  - (pt.x = prc->left);
        !          1001:     y = prc->bottom - (pt.y = prc->top);
        !          1002: 
        !          1003:     PatBlt(hDC, pt.x, pt.y, x, 1, dwRop);
        !          1004:     pt.y = prc->bottom - 1;
        !          1005:     PatBlt(hDC, pt.x, pt.y, x, 1, dwRop);
        !          1006:     pt.y = prc->top;
        !          1007:     PatBlt(hDC, pt.x, pt.y, 1, y, dwRop);
        !          1008:     pt.x = prc->right - 1;
        !          1009:     PatBlt(hDC, pt.x, pt.y, 1, y, dwRop);
        !          1010: }
        !          1011: 
        !          1012: 
        !          1013: 
        !          1014: /************************************************************************
        !          1015: * MoveControl
        !          1016: *
        !          1017: * This function moves the current control to the next grid boundary in
        !          1018: * the specified direction.
        !          1019: *
        !          1020: * Arguments:
        !          1021: *   WPARAM vKey - Virtual key code that was pressed.
        !          1022: *
        !          1023: ************************************************************************/
        !          1024: 
        !          1025: VOID MoveControl(
        !          1026:     WPARAM vKey)
        !          1027: {
        !          1028:     RECT rc;
        !          1029:     INT dx;
        !          1030:     INT dy;
        !          1031: 
        !          1032:     /*
        !          1033:      * Nothing is selected.
        !          1034:      */
        !          1035:     if (!gcSelected)
        !          1036:         return;
        !          1037: 
        !          1038:     rc = grcSelected;
        !          1039: 
        !          1040:     switch (vKey) {
        !          1041:         case VK_UP:
        !          1042:             dx = 0;
        !          1043:             if (!(dy = -(rc.top % gcyGrid)))
        !          1044:                 dy = -gcyGrid;
        !          1045:             break;
        !          1046: 
        !          1047:         case VK_DOWN:
        !          1048:             dx = 0;
        !          1049:             dy = gcyGrid - (rc.top % gcyGrid);
        !          1050:             break;
        !          1051: 
        !          1052:         case VK_RIGHT:
        !          1053:             dx = gcxGrid - (rc.left % gcxGrid);
        !          1054:             dy = 0;
        !          1055:             break;
        !          1056: 
        !          1057:         case VK_LEFT:
        !          1058:             if (!(dx = -(rc.left % gcxGrid)))
        !          1059:                 dx = -gcxGrid;
        !          1060:             dy = 0;
        !          1061:             break;
        !          1062:     }
        !          1063: 
        !          1064:     OffsetRect(&rc, dx, dy);
        !          1065:     FitRectToBounds(&rc, gnOverHang, DRAG_CENTER, gfDlgSelected);
        !          1066:     gHandleHit = DRAG_CENTER;
        !          1067:     PositionControl(&rc);
        !          1068: }
        !          1069: 
        !          1070: 
        !          1071: 
        !          1072: /************************************************************************
        !          1073: * PositionControl
        !          1074: *
        !          1075: * This function positions and sizes the current control.  Both the control
        !          1076: * window and its associated drag window are moved at the same time.  The
        !          1077: * coordinates in the control, and the status window display are updated.
        !          1078: * The given rectangle is in dialog units, and it should have already been
        !          1079: * range limited and grid aligned as appropriate.
        !          1080: *
        !          1081: * Arguments:
        !          1082: *   NPWRECT nprc - The rectangle to size/position the control with.
        !          1083: *
        !          1084: ************************************************************************/
        !          1085: 
        !          1086: VOID PositionControl(
        !          1087:     PRECT prc)
        !          1088: {
        !          1089:     INT cx;
        !          1090:     INT cy;
        !          1091:     RECT rcT;
        !          1092:     NPCTYPE npcT;
        !          1093:     HANDLE hwpi;
        !          1094: 
        !          1095:     if (gcSelected == 1) {
        !          1096:         /*
        !          1097:          * Did nothing change?
        !          1098:          */
        !          1099:         if (EqualRect(prc, &gnpcSel->rc))
        !          1100:             return;
        !          1101: 
        !          1102:         /*
        !          1103:          * Only a single control is selected.  Move it.
        !          1104:          */
        !          1105:         PositionControl2(gnpcSel, prc, NULL);
        !          1106: 
        !          1107:         /*
        !          1108:          * Is the dialog selected, being sized (not just moved), and
        !          1109:          * does it have at least one control?
        !          1110:          */
        !          1111:         if (gfDlgSelected && gHandleHit != DRAG_CENTER && npcHead) {
        !          1112:             cx = prc->left - grcSelected.left;
        !          1113:             cy = prc->top - grcSelected.top;
        !          1114: 
        !          1115:             /*
        !          1116:              * Did the top or left edge of the dialog move?
        !          1117:              */
        !          1118:             if (cx || cy) {
        !          1119:                 /*
        !          1120:                  * Loop through all the controls.  Move all of them by
        !          1121:                  * the dialog movement delta.
        !          1122:                  */
        !          1123:                 hwpi = BeginDeferWindowPos(cWindows * 2);
        !          1124:                 for (npcT = npcHead; npcT; npcT = npcT->npcNext) {
        !          1125:                     SetRect(&rcT, npcT->rc.left - cx, npcT->rc.top - cy,
        !          1126:                             npcT->rc.right - cx, npcT->rc.bottom - cy);
        !          1127:                     hwpi = PositionControl2(npcT, &rcT, hwpi);
        !          1128:                 }
        !          1129:                 EndDeferWindowPos(hwpi);
        !          1130:             }
        !          1131:         }
        !          1132:     }
        !          1133:     else {
        !          1134:         /*
        !          1135:          * Did nothing change?
        !          1136:          */
        !          1137:         if (EqualRect(prc, &grcSelected))
        !          1138:             return;
        !          1139: 
        !          1140:         /*
        !          1141:          * There is a group of controls selected.
        !          1142:          * Calculate how much the group rectangle was moved.
        !          1143:          * It is assumed that a group of controls cannot be
        !          1144:          * sized, only moved.
        !          1145:          */
        !          1146:         cx = prc->left - grcSelected.left;
        !          1147:         cy = prc->top - grcSelected.top;
        !          1148: 
        !          1149:         /*
        !          1150:          * Loop through all the controls.  Move all the selected
        !          1151:          * ones by the group delta.
        !          1152:          */
        !          1153:         hwpi = BeginDeferWindowPos(gcSelected * 2);
        !          1154:         for (npcT = npcHead; npcT; npcT = npcT->npcNext) {
        !          1155:             if (npcT->fSelected) {
        !          1156:                 SetRect(&rcT,
        !          1157:                         npcT->rc.left + cx, npcT->rc.top + cy,
        !          1158:                         npcT->rc.right + cx, npcT->rc.bottom + cy);
        !          1159:                 GridizeRect(&rcT,
        !          1160:                         GRIDIZE_LEFT | GRIDIZE_TOP | GRIDIZE_SAMESIZE);
        !          1161:                 FitRectToBounds(&rcT,
        !          1162:                         GetOverHang(npcT->pwcd->iType,
        !          1163:                         npcT->rc.bottom - npcT->rc.top),
        !          1164:                         DRAG_CENTER, gfDlgSelected);
        !          1165:                 hwpi = PositionControl2(npcT, &rcT, hwpi);
        !          1166:             }
        !          1167:         }
        !          1168:         EndDeferWindowPos(hwpi);
        !          1169:     }
        !          1170: 
        !          1171:     CalcSelectedRect();
        !          1172:     StatusSetCoords(&gnpcSel->rc);
        !          1173:     gfResChged = gfDlgChanged = TRUE;
        !          1174:     ShowFileStatus(FALSE);
        !          1175: }
        !          1176: 
        !          1177: 
        !          1178: 
        !          1179: /************************************************************************
        !          1180: * PositionControl2
        !          1181: *
        !          1182: * This function positions and sizes a single control.  Both the control
        !          1183: * window and its associated drag window are moved at the same time.  The
        !          1184: * coordinates in the control are updated.
        !          1185: *
        !          1186: * The given rectangle is in dialog units, and it should have already been
        !          1187: * range limited and grid aligned as appropriate.
        !          1188: *
        !          1189: * Arguments:
        !          1190: *   NPCTYPE npc - The control to position.
        !          1191: *   PRECT prc   - The rectangle to size/position the control with.
        !          1192: *   HANDLE hwpi - Handle that has been returned from a BeginDeferWindowPos
        !          1193: *                 call.  If this parameter is not NULL, the calls to
        !          1194: *                 position the control and drag window will use this
        !          1195: *                 handle.
        !          1196: *
        !          1197: * Returns:
        !          1198: *
        !          1199: * The return will be the hwpi handle that is currently being used.
        !          1200: * The variable that the caller is using must be updated with the
        !          1201: * return value each call, because each call to DeferWindowPos can
        !          1202: * possibly change this value.
        !          1203: *
        !          1204: ************************************************************************/
        !          1205: 
        !          1206: STATICFN HANDLE PositionControl2(
        !          1207:     NPCTYPE npc,
        !          1208:     PRECT prc,
        !          1209:     HANDLE hwpi)
        !          1210: {
        !          1211:     RECT rc;
        !          1212:     RECT rcDrag;
        !          1213:     HANDLE hwpi2;
        !          1214: 
        !          1215:     /*
        !          1216:      * Make a local copy of the rectangle.
        !          1217:      */
        !          1218:     rc = *prc;
        !          1219: 
        !          1220:     /*
        !          1221:      * Start calculating the new position.  Begin by mapping the dialog
        !          1222:      * points to window coordinates.
        !          1223:      */
        !          1224:     DUToWinRect(&rc);
        !          1225: 
        !          1226:     if (npc->pwcd->iType == W_DIALOG) {
        !          1227:         InvalidateDlgHandles();
        !          1228: 
        !          1229:         AdjustWindowRectEx(&rc, npc->flStyle, FALSE,
        !          1230:                 (npc->flStyle & DS_MODALFRAME) ?
        !          1231:                 npc->flExtStyle | WS_EX_DLGMODALFRAME : npc->flExtStyle);
        !          1232:         ClientToScreenRect(ghwndSubClient, &rc);
        !          1233:         MoveWindow(npc->hwnd, rc.left, rc.top,
        !          1234:                 rc.right - rc.left, rc.bottom - rc.top, TRUE);
        !          1235: 
        !          1236:         /*
        !          1237:          * Update the control structure with the new rectangle.
        !          1238:          */
        !          1239:         npc->rc = *prc;
        !          1240: 
        !          1241:         /*
        !          1242:          * Since this was the dialog that was just positioned, we need to
        !          1243:          * recalculate and save the size of its "client" area.
        !          1244:          */
        !          1245:         SaveDlgClientRect(npc->hwnd);
        !          1246:     }
        !          1247:     else {
        !          1248:         rcDrag = rc;
        !          1249:         InflateRect(&rcDrag, CHANDLESIZE / 2, CHANDLESIZE / 2);
        !          1250: 
        !          1251:         if (hwpi)
        !          1252:             hwpi2 = hwpi;
        !          1253:         else
        !          1254:             hwpi2 = BeginDeferWindowPos(2);
        !          1255: 
        !          1256:         hwpi2 = DeferWindowPos(hwpi2, npc->hwndDrag, NULL,
        !          1257:                 rcDrag.left, rcDrag.top,
        !          1258:                 rcDrag.right - rcDrag.left, rcDrag.bottom - rcDrag.top,
        !          1259:                 SWP_NOACTIVATE | SWP_NOZORDER);
        !          1260: 
        !          1261:         hwpi2 = DeferWindowPos(hwpi2, npc->hwnd, NULL, rc.left, rc.top,
        !          1262:                 rc.right - rc.left, rc.bottom - rc.top,
        !          1263:                 SWP_NOACTIVATE | SWP_NOZORDER);
        !          1264: 
        !          1265:         if (!hwpi)
        !          1266:             EndDeferWindowPos(hwpi2);
        !          1267: 
        !          1268:         /*
        !          1269:          * Update the control structure with the new rectangle.
        !          1270:          */
        !          1271:         npc->rc = *prc;
        !          1272: 
        !          1273:         InvalidateRect(npc->hwndDrag, NULL, TRUE);
        !          1274:     }
        !          1275: 
        !          1276:     return hwpi2;
        !          1277: }
        !          1278: 
        !          1279: 
        !          1280: 
        !          1281: /************************************************************************
        !          1282: * RepositionDialog
        !          1283: *
        !          1284: * This routine forces the dialog to be moved to the location that
        !          1285: * is stored in it's npc rectangle.  This is necessary after the
        !          1286: * main application has been moved, because the dialog is relative
        !          1287: * to the app's window and does not automatically move with it.
        !          1288: *
        !          1289: ************************************************************************/
        !          1290: 
        !          1291: VOID RepositionDialog(VOID)
        !          1292: {
        !          1293:     PositionControl2(gcd.npc, &gcd.npc->rc, NULL);
        !          1294: }
        !          1295: 
        !          1296: 
        !          1297: 
        !          1298: /************************************************************************
        !          1299: * SaveDlgClientRect
        !          1300: *
        !          1301: * This routine saves away a global that will contain the offset, in window
        !          1302: * coordinates, of the origin of the "client" area for the current dialog.
        !          1303: *
        !          1304: * Arguments:
        !          1305: *   HWND hwndDlg - The dialog window.
        !          1306: *
        !          1307: ************************************************************************/
        !          1308: 
        !          1309: VOID SaveDlgClientRect(
        !          1310:     HWND hwndDlg)
        !          1311: {
        !          1312:     RECT rcFrame;
        !          1313:     POINT pt;
        !          1314: 
        !          1315:     GetWindowRect(hwndDlg, &rcFrame);
        !          1316:     GetClientRect(hwndDlg, &grcDlgClient);
        !          1317:     pt.x = pt.y = 0;
        !          1318:     ClientToScreen(hwndDlg, &pt);
        !          1319:     OffsetRect(&grcDlgClient, pt.x - rcFrame.left, pt.y - rcFrame.top);
        !          1320: }
        !          1321: 
        !          1322: 
        !          1323: 
        !          1324: /************************************************************************
        !          1325: * SizeToText
        !          1326: *
        !          1327: * This function will size all the selected controls to fit their text.
        !          1328: * This is to support the "Size to text" command of the "Edit" menu.
        !          1329: *
        !          1330: * Globals are updated appropriately if anything actually had to change.
        !          1331: *
        !          1332: ************************************************************************/
        !          1333: 
        !          1334: VOID SizeToText(VOID)
        !          1335: {
        !          1336:     NPCTYPE npc;
        !          1337:     BOOL fSized = FALSE;
        !          1338: 
        !          1339:     /*
        !          1340:      * Loop through all the controls.
        !          1341:      */
        !          1342:     for (npc = npcHead; npc; npc = npc->npcNext) {
        !          1343:         /*
        !          1344:          * Is the control selected, and can it be sized to its text?
        !          1345:          */
        !          1346:         if (npc->fSelected && npc->pwcd->fSizeToText)
        !          1347:             fSized |= SizeCtrlToText(npc);
        !          1348:     }
        !          1349: 
        !          1350:     /*
        !          1351:      * Was anything modified?
        !          1352:      */
        !          1353:     if (fSized) {
        !          1354:         CalcSelectedRect();
        !          1355:         StatusSetCoords(&gnpcSel->rc);
        !          1356:         gfResChged = gfDlgChanged = TRUE;
        !          1357:         ShowFileStatus(FALSE);
        !          1358:     }
        !          1359: }
        !          1360: 
        !          1361: 
        !          1362: 
        !          1363: /************************************************************************
        !          1364: * SizeCtrlToText
        !          1365: *
        !          1366: * This function sizes a single control so that it just fits its text.
        !          1367: * This does not make sense for all controls (see the fSizeToText flag
        !          1368: * in the awcd array), and there are different rules for the different
        !          1369: * types of controls.
        !          1370: *
        !          1371: * Arguments:
        !          1372: *   NPCTYPE npc - The control to size.
        !          1373: *
        !          1374: * Returns:
        !          1375: *
        !          1376: * The return value is TRUE if the control was modified (sized) or
        !          1377: * FALSE if it was not.
        !          1378: *
        !          1379: ************************************************************************/
        !          1380: 
        !          1381: STATICFN BOOL SizeCtrlToText(
        !          1382:     NPCTYPE npc)
        !          1383: {
        !          1384:     RECT rc;
        !          1385:     INT x;
        !          1386:     INT cxLowern;
        !          1387: 
        !          1388:     switch (npc->pwcd->iType) {
        !          1389:         case W_CHECKBOX:
        !          1390:             /*
        !          1391:              * Take the width of the text, plus some pixels for the square.
        !          1392:              */
        !          1393:             x = QueryTextExtent(npc->hwnd, npc->text, TRUE) + 20;
        !          1394:             x = MulDiv(x, 4, gcd.cxChar) + 1;
        !          1395:             break;
        !          1396: 
        !          1397:         case W_PUSHBUTTON:
        !          1398:             /*
        !          1399:              * The UITF definition of the size of a pushbutton says
        !          1400:              * that the left and right margins should be approximately
        !          1401:              * the width of a lowercase "n".  In any event, the width
        !          1402:              * cannot be less than the default size.
        !          1403:              */
        !          1404:             cxLowern = QueryTextExtent(npc->hwnd, L"n", FALSE);
        !          1405:             x = QueryTextExtent(npc->hwnd, npc->text, FALSE) + (2 * cxLowern);
        !          1406:             x = MulDiv(x, 4, gcd.cxChar);
        !          1407: 
        !          1408:             if (x < awcd[W_PUSHBUTTON].cxDefault)
        !          1409:                 x = awcd[W_PUSHBUTTON].cxDefault;
        !          1410: 
        !          1411:             break;
        !          1412: 
        !          1413:         case W_RADIOBUTTON:
        !          1414:             /*
        !          1415:              * Take the width of the text, plus some for the circle.
        !          1416:              */
        !          1417:             x = QueryTextExtent(npc->hwnd, npc->text, TRUE) + 20;
        !          1418:             x = MulDiv(x, 4, gcd.cxChar) + 1;
        !          1419:             break;
        !          1420: 
        !          1421:         case W_TEXT:
        !          1422:             /*
        !          1423:              * Take the width of the text.
        !          1424:              */
        !          1425:             x = QueryTextExtent(npc->hwnd, npc->text, TRUE);
        !          1426:             x = MulDiv(x, 4, gcd.cxChar) + 1;
        !          1427:             break;
        !          1428: 
        !          1429:         case W_CUSTOM:
        !          1430:             /*
        !          1431:              * Call out to the custom control and let it decide
        !          1432:              * how wide the text should be.
        !          1433:              */
        !          1434:             x = CallCustomSizeToText(npc);
        !          1435:             break;
        !          1436: 
        !          1437:         default:
        !          1438:             x = -1;
        !          1439:             break;
        !          1440:     }
        !          1441: 
        !          1442:     /*
        !          1443:      * Does it need to be sized?
        !          1444:      */
        !          1445:     if (x != -1 && x != npc->rc.right - npc->rc.left) {
        !          1446:         /*
        !          1447:          * Now that we know the size we want the control, position
        !          1448:          * it to change that size.  Note that we do NOT gridize
        !          1449:          * the left edge here.  The user probably just wants the
        !          1450:          * right edge of the control to be adjusted to fit the new
        !          1451:          * text, and probably does not want the left edge shifting
        !          1452:          * on them.
        !          1453:          */
        !          1454:         rc = npc->rc;
        !          1455:         rc.right = rc.left + x;
        !          1456:         FitRectToBounds(&rc,
        !          1457:                 GetOverHang(npc->pwcd->iType, npc->rc.bottom - npc->rc.top),
        !          1458:                 DRAG_CENTER, gfDlgSelected);
        !          1459:         PositionControl2(npc, &rc, NULL);
        !          1460: 
        !          1461:         return TRUE;
        !          1462:     }
        !          1463: 
        !          1464:     return FALSE;
        !          1465: }
        !          1466: 
        !          1467: 
        !          1468: 
        !          1469: /************************************************************************
        !          1470: * QueryTextExtent
        !          1471: *
        !          1472: * This function takes a window handle and text, and will return the
        !          1473: * number of pixels that the specified text is wide in that window.
        !          1474: * It is used to determine how wide a control needs to be to display
        !          1475: * its text.
        !          1476: *
        !          1477: * The font set into the current dialog is taken into consideration
        !          1478: * when calculating the size.
        !          1479: *
        !          1480: * Arguments:
        !          1481: *   HWND hwnd       - The control window handle.
        !          1482: *   LPTSTR pszText  - The text of the control.
        !          1483: *   BOOL fWordBreak - TRUE if this text will be drawn with DT_WORDBREAK.
        !          1484: *
        !          1485: * Returns:
        !          1486: *
        !          1487: * The number of pixels wide the selected text is.
        !          1488: *
        !          1489: ************************************************************************/
        !          1490: 
        !          1491: STATICFN INT QueryTextExtent(
        !          1492:     HWND hwnd,
        !          1493:     LPTSTR pszText,
        !          1494:     BOOL fWordBreak)
        !          1495: {
        !          1496:     HDC hDC;
        !          1497:     INT iHeight;
        !          1498:     RECT rc;
        !          1499:     INT nLen;
        !          1500:     HFONT hfontOld;
        !          1501: 
        !          1502:     if (!pszText || *pszText == CHAR_NULL)
        !          1503:         return 0;
        !          1504: 
        !          1505:     hDC = GetDC(hwnd);
        !          1506: 
        !          1507:     /*
        !          1508:      * If there is a valid font, select it into the DC.  Note that
        !          1509:      * we look at gcd.hFont instead of gcd.fFontSpecified, because
        !          1510:      * it is possible to specify a font for the dialog but not have
        !          1511:      * been able to create it.
        !          1512:      */
        !          1513:     if (gcd.hFont)
        !          1514:         hfontOld = SelectObject(hDC, gcd.hFont);
        !          1515: 
        !          1516:     /*
        !          1517:      * First, calculate the length of the text.
        !          1518:      */
        !          1519:     rc.left = rc.top = 0;
        !          1520:     rc.right = 10000;
        !          1521:     rc.bottom = 10000;
        !          1522:     nLen = lstrlen(pszText);
        !          1523:     DrawText(hDC, pszText, nLen, &rc,
        !          1524:             DT_CALCRECT | DT_NOCLIP | DT_EXPANDTABS);
        !          1525: 
        !          1526:     /*
        !          1527:      * First save the height of the line.  This works because the
        !          1528:      * DrawText call above with DT_CALCRECT will always draw on
        !          1529:      * a single line.  Then we move the upwards the rectangle to draw
        !          1530:      * in a large amount, so that it is outside the dimensions of
        !          1531:      * the control.  Finally, we do a real draw of the text,
        !          1532:      * increasing the width a little each time until we are able
        !          1533:      * to draw entirely on one line.  This is inefficient, but it does
        !          1534:      * ensure that the returned width will be enough to actually
        !          1535:      * draw the string.
        !          1536:      */
        !          1537:     if (fWordBreak) {
        !          1538:         iHeight = rc.bottom - rc.top;
        !          1539:         rc.top -= 10000;
        !          1540:         rc.bottom -= 10000;
        !          1541:         while (TRUE) {
        !          1542:             /*
        !          1543:              * Determine if we have enough width to draw on a single
        !          1544:              * line yet.
        !          1545:              */
        !          1546:             if (DrawText(hDC, pszText, nLen, &rc,
        !          1547:                     DT_NOCLIP | DT_EXPANDTABS | DT_WORDBREAK) == iHeight)
        !          1548:                 break;
        !          1549: 
        !          1550:             /*
        !          1551:              * Nope, push the right margin out and try again...
        !          1552:              */
        !          1553:             rc.right++;
        !          1554:         }
        !          1555:     }
        !          1556: 
        !          1557:     if (gcd.hFont)
        !          1558:         SelectObject(hDC, hfontOld);
        !          1559: 
        !          1560:     ReleaseDC(hwnd, hDC);
        !          1561: 
        !          1562:     return rc.right - rc.left;
        !          1563: }
        !          1564: 
        !          1565: 
        !          1566: 
        !          1567: /************************************************************************
        !          1568: * AlignControls
        !          1569: *
        !          1570: * This function will align all the selected controls.  The point to
        !          1571: * align to is always taken from the currently selected control.
        !          1572: *
        !          1573: * In all cases, the resulting desired position of the control will be
        !          1574: * gridized and limited to the dialogs "client" area.  The size of the
        !          1575: * controls will not be changed.
        !          1576: *
        !          1577: * Arguments:
        !          1578: *   INT cmd - The alignment menu command.
        !          1579: *
        !          1580: *   The following are valid values for cmd:
        !          1581: *
        !          1582: *   MENU_ALIGNLEFT      - Align to the left edge.
        !          1583: *   MENU_ALIGNVERT      - Align to the center vertically.
        !          1584: *   MENU_ALIGNRIGHT     - Align to the right edge.
        !          1585: *   MENU_ALIGNTOP       - Align to the top edge.
        !          1586: *   MENU_ALIGNHORZ      - Align to the center horizontally.
        !          1587: *   MENU_ALIGNBOTTOM    - Align to the bottom edge.
        !          1588: *
        !          1589: ************************************************************************/
        !          1590: 
        !          1591: VOID AlignControls(
        !          1592:     INT cmd)
        !          1593: {
        !          1594:     register INT sDelta;
        !          1595:     NPCTYPE npc;
        !          1596:     RECT rc;
        !          1597:     BOOL fMove;
        !          1598:     BOOL fModified = FALSE;
        !          1599: 
        !          1600:     /*
        !          1601:      * Loop through all the controls.  Align all the selected ones.
        !          1602:      */
        !          1603:     for (npc = npcHead; npc; npc = npc->npcNext) {
        !          1604:         if (npc->fSelected && npc != gnpcSel) {
        !          1605:             rc = npc->rc;
        !          1606:             fMove = FALSE;
        !          1607: 
        !          1608:             switch (cmd) {
        !          1609:                 case MENU_ALIGNLEFT:
        !          1610:                     if (sDelta = gnpcSel->rc.left - rc.left) {
        !          1611:                         fMove = TRUE;
        !          1612:                         rc.left += sDelta;
        !          1613:                         rc.right += sDelta;
        !          1614:                     }
        !          1615: 
        !          1616:                     break;
        !          1617: 
        !          1618:                 case MENU_ALIGNVERT:
        !          1619:                     if (sDelta =
        !          1620:                             (((gnpcSel->rc.right - gnpcSel->rc.left) / 2)
        !          1621:                             + gnpcSel->rc.left) -
        !          1622:                             (((rc.right - rc.left) / 2) +
        !          1623:                             rc.left)) {
        !          1624:                         fMove = TRUE;
        !          1625:                         rc.left += sDelta;
        !          1626:                         rc.right += sDelta;
        !          1627:                     }
        !          1628: 
        !          1629:                     break;
        !          1630: 
        !          1631:                 case MENU_ALIGNRIGHT:
        !          1632:                     if (sDelta = gnpcSel->rc.right - rc.right) {
        !          1633:                         fMove = TRUE;
        !          1634:                         rc.left += sDelta;
        !          1635:                         rc.right += sDelta;
        !          1636:                     }
        !          1637: 
        !          1638:                     break;
        !          1639: 
        !          1640:                 case MENU_ALIGNTOP:
        !          1641:                     if (sDelta = gnpcSel->rc.top - rc.top) {
        !          1642:                         fMove = TRUE;
        !          1643:                         rc.top += sDelta;
        !          1644:                         rc.bottom += sDelta;
        !          1645:                     }
        !          1646: 
        !          1647:                     break;
        !          1648: 
        !          1649:                 case MENU_ALIGNHORZ:
        !          1650:                     if (sDelta =
        !          1651:                             (((gnpcSel->rc.bottom - gnpcSel->rc.top) / 2)
        !          1652:                             + gnpcSel->rc.top) -
        !          1653:                             (((rc.bottom - rc.top) / 2) +
        !          1654:                             rc.top)) {
        !          1655:                         fMove = TRUE;
        !          1656:                         rc.top += sDelta;
        !          1657:                         rc.bottom += sDelta;
        !          1658:                     }
        !          1659: 
        !          1660:                     break;
        !          1661: 
        !          1662:                 case MENU_ALIGNBOTTOM:
        !          1663:                     if (sDelta = gnpcSel->rc.bottom - rc.bottom) {
        !          1664:                         fMove = TRUE;
        !          1665:                         rc.top += sDelta;
        !          1666:                         rc.bottom += sDelta;
        !          1667:                     }
        !          1668: 
        !          1669:                     break;
        !          1670:             }
        !          1671: 
        !          1672:             if (fMove) {
        !          1673:                 GridizeRect(&rc,
        !          1674:                         GRIDIZE_LEFT | GRIDIZE_TOP | GRIDIZE_SAMESIZE);
        !          1675:                 FitRectToBounds(&rc, GetOverHang(npc->pwcd->iType,
        !          1676:                         npc->rc.bottom - npc->rc.top),
        !          1677:                         DRAG_CENTER, FALSE);
        !          1678: 
        !          1679:                 if (!EqualRect(&rc, &npc->rc)) {
        !          1680:                     PositionControl2(npc, &rc, NULL);
        !          1681:                     fModified = TRUE;
        !          1682:                 }
        !          1683:             }
        !          1684:         }
        !          1685:     }
        !          1686: 
        !          1687:     if (fModified) {
        !          1688:         RedrawSelection();
        !          1689:         CalcSelectedRect();
        !          1690:         gfResChged = gfDlgChanged = TRUE;
        !          1691:         ShowFileStatus(FALSE);
        !          1692:         StatusUpdate();
        !          1693:     }
        !          1694: }
        !          1695: 
        !          1696: 
        !          1697: 
        !          1698: /************************************************************************
        !          1699: * ArrangeSpacing
        !          1700: *
        !          1701: * This function will evenly space all the selected controls.  The
        !          1702: * currently selected control is not moved (unless it has to be gridized)
        !          1703: * and any previous controls in Z order will be evenly spaced to the
        !          1704: * left or above the anchor, and all controls following in Z order will
        !          1705: * be evenly spaced below or to the right of the anchor.
        !          1706: *
        !          1707: * The spacing values used are gxSpace and gySpace.
        !          1708: *
        !          1709: * In all cases, the resulting desired position of the control will be
        !          1710: * gridized and limited to the dialogs "client" area.  The size of the
        !          1711: * controls is not changed.
        !          1712: *
        !          1713: * Arguments:
        !          1714: *   INT cmd - The Arrange/Even spacing menu command.
        !          1715: *
        !          1716: *   The following are valid values for cmd:
        !          1717: *
        !          1718: *   MENU_SPACEHORZ - Space the controls left and right.
        !          1719: *   MENU_SPACEVERT - Space all the controls up and down.
        !          1720: *
        !          1721: ************************************************************************/
        !          1722: 
        !          1723: VOID ArrangeSpacing(
        !          1724:     INT cmd)
        !          1725: {
        !          1726:     NPCTYPE npc;
        !          1727:     RECT rc;
        !          1728:     BOOL fModified = FALSE;
        !          1729:     INT x;
        !          1730:     INT y;
        !          1731:     INT cPreceding;
        !          1732:     INT xTotalWidth;
        !          1733:     INT yTotalWidth;
        !          1734: 
        !          1735:     cPreceding = 0;
        !          1736:     xTotalWidth = 0;
        !          1737:     yTotalWidth = 0;
        !          1738:     for (npc = npcHead; npc; npc = npc->npcNext) {
        !          1739:         if (npc->fSelected) {
        !          1740:             if (npc == gnpcSel)
        !          1741:                 break;
        !          1742: 
        !          1743:             cPreceding++;
        !          1744:             xTotalWidth += npc->rc.right - npc->rc.left;
        !          1745:             yTotalWidth += npc->rc.bottom - npc->rc.top;
        !          1746:         }
        !          1747:     }
        !          1748: 
        !          1749:     x = gnpcSel->rc.left;
        !          1750:     y = gnpcSel->rc.top;
        !          1751: 
        !          1752:     if (cPreceding) {
        !          1753:         x -= xTotalWidth + (gxSpace * cPreceding);
        !          1754:         y -= yTotalWidth + (gySpace * cPreceding);
        !          1755:     }
        !          1756: 
        !          1757:     /*
        !          1758:      * Loop through all the controls.  Space all the selected ones.
        !          1759:      */
        !          1760:     for (npc = npcHead; npc; npc = npc->npcNext) {
        !          1761:         if (npc->fSelected) {
        !          1762:             rc = npc->rc;
        !          1763: 
        !          1764:             switch (cmd) {
        !          1765:                 case MENU_SPACEVERT:
        !          1766:                     rc.top = y;
        !          1767:                     rc.bottom = y + (npc->rc.bottom - npc->rc.top);
        !          1768:                     y = rc.bottom + gySpace;
        !          1769:                     break;
        !          1770: 
        !          1771:                 case MENU_SPACEHORZ:
        !          1772:                     rc.left = x;
        !          1773:                     rc.right = x + (npc->rc.right - npc->rc.left);
        !          1774:                     x = rc.right + gxSpace;
        !          1775:                     break;
        !          1776:             }
        !          1777: 
        !          1778:             GridizeRect(&rc, GRIDIZE_LEFT | GRIDIZE_TOP | GRIDIZE_SAMESIZE);
        !          1779:             FitRectToBounds(&rc, GetOverHang(npc->pwcd->iType,
        !          1780:                     npc->rc.bottom - npc->rc.top),
        !          1781:                     DRAG_CENTER, FALSE);
        !          1782: 
        !          1783:             if (!EqualRect(&rc, &npc->rc)) {
        !          1784:                 PositionControl2(npc, &rc, NULL);
        !          1785:                 fModified = TRUE;
        !          1786:             }
        !          1787:         }
        !          1788:     }
        !          1789: 
        !          1790:     if (fModified) {
        !          1791:         RedrawSelection();
        !          1792:         CalcSelectedRect();
        !          1793:         gfResChged = gfDlgChanged = TRUE;
        !          1794:         ShowFileStatus(FALSE);
        !          1795:         StatusUpdate();
        !          1796:     }
        !          1797: }
        !          1798: 
        !          1799: 
        !          1800: 
        !          1801: /************************************************************************
        !          1802: * ArrangeSize
        !          1803: *
        !          1804: * This function will evenly size all the selected controls.  The
        !          1805: * currently selected control determines the size that the other
        !          1806: * controls will be set to in the given dimension.
        !          1807: *
        !          1808: * In all cases, the resulting size of the control will be gridized and
        !          1809: * limited to the dialogs "client" area.
        !          1810: *
        !          1811: * Arguments:
        !          1812: *   INT cmd - The Arrange/Same size menu command.
        !          1813: *
        !          1814: * The following are valid values for cmd:
        !          1815: *
        !          1816: *   MENU_ARRSIZEWIDTH  - Size the widths of the controls.
        !          1817: *   MENU_ARRSIZEHEIGHT - Size the heights of the controls.
        !          1818: *
        !          1819: ************************************************************************/
        !          1820: 
        !          1821: VOID ArrangeSize(
        !          1822:     INT cmd)
        !          1823: {
        !          1824:     NPCTYPE npc;
        !          1825:     RECT rc;
        !          1826:     BOOL fModified = FALSE;
        !          1827:     INT cx;
        !          1828:     INT cy;
        !          1829: 
        !          1830:     cx = gnpcSel->rc.right - gnpcSel->rc.left;
        !          1831:     cy = gnpcSel->rc.bottom - gnpcSel->rc.top;
        !          1832: 
        !          1833:     /*
        !          1834:      * Loop through all the controls, operating on the selected ones.
        !          1835:      */
        !          1836:     for (npc = npcHead; npc; npc = npc->npcNext) {
        !          1837:         /*
        !          1838:          * Is the control selected, and is it sizeable?
        !          1839:          */
        !          1840:         if (npc->fSelected && npc->pwcd->fSizeable) {
        !          1841:             rc = npc->rc;
        !          1842: 
        !          1843:             switch (cmd) {
        !          1844:                 case MENU_ARRSIZEWIDTH:
        !          1845:                     rc.right = npc->rc.left + cx;
        !          1846:                     break;
        !          1847: 
        !          1848:                 case MENU_ARRSIZEHEIGHT:
        !          1849:                     rc.top = npc->rc.bottom - cy;
        !          1850:                     break;
        !          1851:             }
        !          1852: 
        !          1853:             GridizeRect(&rc, GRIDIZE_LEFT | GRIDIZE_TOP |
        !          1854:                     GRIDIZE_RIGHT | GRIDIZE_BOTTOM);
        !          1855:             FitRectToBounds(&rc, GetOverHang(npc->pwcd->iType,
        !          1856:                     npc->rc.bottom - npc->rc.top),
        !          1857:                     DRAG_CENTER, FALSE);
        !          1858: 
        !          1859:             if (!EqualRect(&rc, &npc->rc)) {
        !          1860:                 PositionControl2(npc, &rc, NULL);
        !          1861:                 fModified = TRUE;
        !          1862:             }
        !          1863:         }
        !          1864:     }
        !          1865: 
        !          1866:     if (fModified) {
        !          1867:         RedrawSelection();
        !          1868:         CalcSelectedRect();
        !          1869:         gfResChged = gfDlgChanged = TRUE;
        !          1870:         ShowFileStatus(FALSE);
        !          1871:         StatusUpdate();
        !          1872:     }
        !          1873: }
        !          1874: 
        !          1875: 
        !          1876: 
        !          1877: /************************************************************************
        !          1878: * ArrangePushButtons
        !          1879: *
        !          1880: * This function will arrange push buttons along either the bottom of
        !          1881: * the dialog or along the right side of the dialog.  It will operate
        !          1882: * on the selected buttons (which button is currently selected does not
        !          1883: * matter) but this function can also be used if buttons are not selected
        !          1884: * in a couple of special cases.  If either the dialog or nothing is
        !          1885: * selected, ALL the push buttons in the dialog will be arranged.
        !          1886: *
        !          1887: * The margin values used are gxMargin and gyMargin, and the spacing
        !          1888: * between buttons is gxMinPushSpace, gxMaxPushSpace and gyPushSpace.
        !          1889: *
        !          1890: * In all cases, the resulting desired position of the buttons will be
        !          1891: * gridized and limited to the dialogs "client" area.  The size of the
        !          1892: * push buttons is not changed.
        !          1893: *
        !          1894: * Arguments:
        !          1895: *   INT cmd - The Arrange/Push buttons menu command.
        !          1896: *
        !          1897: *   The following are valid values for cmd:
        !          1898: *
        !          1899: *   MENU_ARRPUSHBOTTOM - Arrange push buttons along the bottom.
        !          1900: *   MENU_ARRPUSHRIGHT  - Arrange push buttons along the right side.
        !          1901: *
        !          1902: ************************************************************************/
        !          1903: 
        !          1904: VOID ArrangePushButtons(
        !          1905:     INT cmd)
        !          1906: {
        !          1907:     NPCTYPE npc;
        !          1908:     RECT rc;
        !          1909:     BOOL fModified = FALSE;
        !          1910:     INT x;                          // Note: These values must be signed.
        !          1911:     INT y;
        !          1912:     INT cxDlg;
        !          1913:     INT cButtons;
        !          1914:     INT xTotal;
        !          1915:     INT xInterSpace;
        !          1916: 
        !          1917:     switch (cmd) {
        !          1918:         case MENU_ARRPUSHBOTTOM:
        !          1919:             cxDlg = gcd.npc->rc.right - gcd.npc->rc.left;
        !          1920:             y = (gcd.npc->rc.bottom - gcd.npc->rc.top) - gyMargin;
        !          1921: 
        !          1922:             for (cButtons = 0, xTotal = 0, npc = npcHead; npc;
        !          1923:                     npc = npc->npcNext) {
        !          1924:                 if (npc->pwcd->iType == W_PUSHBUTTON &&
        !          1925:                         (!gcSelected || gfDlgSelected || npc->fSelected)) {
        !          1926:                     cButtons++;
        !          1927:                     xTotal += npc->rc.right - npc->rc.left;
        !          1928:                 }
        !          1929:             }
        !          1930: 
        !          1931:             if (cButtons == 1) {
        !          1932:                 x = (cxDlg - xTotal) / 2;
        !          1933:                 xInterSpace = 0;
        !          1934:             }
        !          1935:             else {
        !          1936:                 xInterSpace = (cxDlg - xTotal) / (cButtons + 1);
        !          1937: 
        !          1938:                 if (xInterSpace > gxMaxPushSpace)
        !          1939:                     xInterSpace = gxMaxPushSpace;
        !          1940:                 else if (xInterSpace < gxMinPushSpace)
        !          1941:                     xInterSpace = gxMinPushSpace;
        !          1942: 
        !          1943:                 x = (cxDlg - ((cButtons - 1) * xInterSpace) - xTotal) / 2;
        !          1944:                 if (x < 0)
        !          1945:                     x = 0;
        !          1946: 
        !          1947:                 if (x < gxMargin && xInterSpace > gxMinPushSpace) {
        !          1948:                     xInterSpace = (cxDlg - xTotal - (2 * gxMargin))
        !          1949:                             / (cButtons - 1);
        !          1950: 
        !          1951:                     if (xInterSpace < gxMinPushSpace)
        !          1952:                         xInterSpace = gxMinPushSpace;
        !          1953: 
        !          1954:                     x = (cxDlg - ((cButtons - 1) * xInterSpace) - xTotal)
        !          1955:                             / 2;
        !          1956:                     if (x < 0)
        !          1957:                         x = 0;
        !          1958:                 }
        !          1959:             }
        !          1960: 
        !          1961:             break;
        !          1962: 
        !          1963:         case MENU_ARRPUSHRIGHT:
        !          1964:             x = (gcd.npc->rc.right - gcd.npc->rc.left) - gxMargin;
        !          1965:             y = gyMargin;
        !          1966:             break;
        !          1967:     }
        !          1968: 
        !          1969:     /*
        !          1970:      * Loop through all the controls.
        !          1971:      */
        !          1972:     for (npc = npcHead; npc; npc = npc->npcNext) {
        !          1973:         /*
        !          1974:          * We will arrange this control only if it is a pushbutton,
        !          1975:          * and only if one of the following is true: there are no
        !          1976:          * controls selected, or the dialog itself is selected, or
        !          1977:          * there are some controls selected and this pushbutton is
        !          1978:          * one of them.
        !          1979:          */
        !          1980:         if (npc->pwcd->iType == W_PUSHBUTTON &&
        !          1981:                 (!gcSelected || gfDlgSelected || npc->fSelected)) {
        !          1982:             rc = npc->rc;
        !          1983: 
        !          1984:             switch (cmd) {
        !          1985:                 case MENU_ARRPUSHBOTTOM:
        !          1986:                     rc.left = x;
        !          1987:                     rc.top = y - (npc->rc.bottom - npc->rc.top);
        !          1988:                     rc.bottom = y;
        !          1989:                     rc.right = rc.left + (npc->rc.right - npc->rc.left);
        !          1990: 
        !          1991:                     x = rc.right + xInterSpace;
        !          1992: 
        !          1993:                     break;
        !          1994: 
        !          1995:                 case MENU_ARRPUSHRIGHT:
        !          1996:                     rc.left = x - (npc->rc.right - npc->rc.left);
        !          1997:                     rc.bottom = y + (npc->rc.bottom - npc->rc.top);
        !          1998:                     rc.right = x;
        !          1999:                     rc.top = y;
        !          2000: 
        !          2001:                     y = rc.bottom + gyPushSpace;
        !          2002: 
        !          2003:                     break;
        !          2004:             }
        !          2005: 
        !          2006:             GridizeRect(&rc, GRIDIZE_LEFT | GRIDIZE_TOP | GRIDIZE_SAMESIZE);
        !          2007:             FitRectToBounds(&rc, GetOverHang(npc->pwcd->iType,
        !          2008:                     npc->rc.bottom - npc->rc.top),
        !          2009:                     DRAG_CENTER, FALSE);
        !          2010: 
        !          2011:             if (!EqualRect(&rc, &npc->rc)) {
        !          2012:                 PositionControl2(npc, &rc, NULL);
        !          2013:                 fModified = TRUE;
        !          2014:             }
        !          2015:         }
        !          2016:     }
        !          2017: 
        !          2018:     if (fModified) {
        !          2019:         if (gfDlgSelected || !gcSelected)
        !          2020:             InvalidateRect(gcd.npc->hwnd, NULL, TRUE);
        !          2021: 
        !          2022:         CalcSelectedRect();
        !          2023:         gfResChged = gfDlgChanged = TRUE;
        !          2024:         ShowFileStatus(FALSE);
        !          2025:         StatusUpdate();
        !          2026:     }
        !          2027: }

unix.superglobalmegacorp.com

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