|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.