SELECT.C
资源名称:MSDN_VC98.zip [点击查看]
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:59k
源码类别:
Windows编程
开发平台:
Visual C++
- /******************************************************************************
- * This is a part of the Microsoft Source Code Samples.
- * Copyright (C) 1993-1997 Microsoft Corporation.
- * All rights reserved.
- * This source code is only intended as a supplement to
- * Microsoft Development Tools and/or WinHelp documentation.
- * See these sources for detailed information regarding the
- * Microsoft samples programs.
- ******************************************************************************/
- /****************************** Module Header *******************************
- * Module Name: select.c
- *
- * Contains routines for selecting and positioning controls.
- *
- * Functions:
- *
- * SelectControl()
- * SelectControl2()
- * RedrawSelection()
- * SetAnchorToFirstSel()
- * SelectNext()
- * SelectPrevious()
- * UnSelectControl()
- * CalcSelectedRect()
- * CancelSelection()
- * OutlineSelectBegin()
- * OutlineSelectDraw()
- * OutlineSelectCancel()
- * OutlineSelectEnd()
- * MyFrameRect()
- * MoveControl()
- * PositionControl()
- * RepositionDialog()
- * SaveDlgClientRect()
- * SizeToText()
- * AlignControls()
- * ArrangeSpacing()
- * ArrangeSize()
- * ArrangePushButtons()
- * InvalidateDlgHandles()
- * OutlineSelectHide()
- * OutlineSelectSetRect()
- * PositionControl2()
- * SizeCtrlToText()
- * QueryTextExtent()
- *
- * Comments:
- *
- ****************************************************************************/
- #include "dlgedit.h"
- #include "dlgfuncs.h"
- #include "dlgextrn.h"
- STATICFN VOID InvalidateDlgHandles(VOID);
- STATICFN VOID OutlineSelectHide(VOID);
- STATICFN VOID OutlineSelectSetRect(INT x, INT y);
- STATICFN HANDLE PositionControl2(NPCTYPE npc, PRECT prc, HANDLE hwpi);
- STATICFN BOOL SizeCtrlToText(NPCTYPE npc);
- STATICFN INT QueryTextExtent(HWND hwnd, LPTSTR pszText, BOOL fWordBreak);
- static POINT gptOutlineSelect;
- static RECT grcOutlineSelect;
- static RECT grcOutlineSelectLimit;
- static BOOL gfOutlineSelectShown = FALSE;
- /************************************************************************
- * SelectControl
- *
- * This routine selects a control, showing its drag window and handles.
- * If fCheckShift is TRUE and the shift key is down, this routine adds
- * the control to the existing selection, unless the control is already
- * selected, in which case it is removed from the existing selection.
- *
- * This routine handles the case where a controls is clicked on to select
- * it, and this may cause other controls to be unselected. If it is
- * known for sure that a control should be selected or added to the
- * existing selection, SelectControl2 can be used instead.
- *
- * Arguments:
- * NPCTYPE npc = The control to select.
- * BOOL fCheckShift = TRUE if the state of the shift key should be
- * taken into consideration.
- *
- * Returns:
- * The return will be FALSE if the control was just unselected.
- *
- ************************************************************************/
- BOOL SelectControl(
- NPCTYPE npc,
- BOOL fCheckShift)
- {
- BOOL fShiftDown;
- BOOL fSelectDone = TRUE;
- if (npc->pwcd->iType == W_DIALOG) {
- if (gnpcSel == npc)
- return TRUE;
- CancelSelection(FALSE);
- SelectControl2(npc, FALSE);
- }
- else {
- if (fCheckShift)
- fShiftDown = (GetKeyState(VK_SHIFT) & 0x8000) ? TRUE : FALSE;
- else
- fShiftDown = FALSE;
- if (npc->fSelected) {
- /*
- * If the shift key is down, and they are NOT trying to
- * select the dialog, toggle the selection of this control
- * to off.
- */
- if (fShiftDown && npc->pwcd->iType != W_DIALOG) {
- UnSelectControl(npc);
- CalcSelectedRect();
- fSelectDone = FALSE;
- }
- else {
- if (gnpcSel == npc)
- return TRUE;
- else
- SelectControl2(npc, FALSE);
- }
- }
- else {
- /*
- * If they are NOT holding the shift key down, or the
- * dialog is selected, cancel the selection first.
- */
- if (!fShiftDown || gcd.npc->fSelected == TRUE)
- CancelSelection(FALSE);
- SelectControl2(npc, FALSE);
- }
- }
- StatusUpdate();
- StatusSetEnable();
- return fSelectDone;
- }
- /************************************************************************
- * SelectControl2
- *
- * This routine is the worker for SelectControl. It does the actual
- * work to "select" a control, updating globals and showing the drag
- * windows with handles.
- *
- * This routine handles the special case where we are selecting a
- * control that is already selected. The editor has the concept of
- * a control being selected, as well as there being the currently
- * selected control (pointed to by gnpcSel). There can be the case
- * where there are multiple controls selected, but only one will be
- * the current selection (usually the last one clicked on). This
- * routine will never unselect other controls. This must be done
- * prior to here, if appropriate.
- *
- * Arguments:
- * NPCTYPE npc = The control to make the current selection.
- * BOOL fDontUpdate = TRUE if the selection should NOT be redrawn
- * after the specified control is added to it.
- * This allows painting to be deferred until
- * later if a number of controls are being
- * selected in a loop. It also does not call
- * CalcSelectedRect (this MUST be done later
- * for drags to work, however!).
- * Comments:
- *
- * If fDontUpdate is TRUE, the selection will not be redrawn, and it
- * is required that CalcSelectedRect be called before doing any drag
- * operations.
- *
- ************************************************************************/
- VOID SelectControl2(
- NPCTYPE npc,
- BOOL fDontUpdate)
- {
- BOOL fUpdate = FALSE;
- /*
- * Is the control already selected?
- */
- if (npc->fSelected) {
- /*
- * It is already selected (hwndDrag is visible). If it is
- * not the current selection, we want all drag windows to
- * be redrawn in the proper order to update their appearance.
- */
- if (gnpcSel != npc)
- fUpdate = TRUE;
- }
- else {
- /*
- * The control is not yet selected. If another control is
- * currently selected, we want all drag windows to be
- * updated so that their handle appearance gets updated.
- */
- if (gnpcSel)
- fUpdate = TRUE;
- /*
- * Flip its flag and add to the selected count.
- */
- npc->fSelected = TRUE;
- gcSelected++;
- }
- gnpcSel = npc;
- if (!fDontUpdate)
- CalcSelectedRect();
- if (npc->pwcd->iType == W_DIALOG) {
- gfDlgSelected = TRUE;
- InvalidateDlgHandles();
- }
- else {
- gfDlgSelected = FALSE;
- ShowWindow(npc->hwndDrag, SW_SHOW);
- if (fUpdate && !fDontUpdate)
- RedrawSelection();
- }
- }
- /************************************************************************
- * RedrawSelection
- *
- * This function cause all the selected drag windows to be invalidated.
- * This is necessary whenever one of them changes, because of the very
- * touchy painting order that has to be maintained. Without invalidating
- * all of them as a unit, there are cases where handles do not get
- * properly painted.
- *
- ************************************************************************/
- VOID RedrawSelection(VOID)
- {
- NPCTYPE npc;
- if (!gcSelected) {
- return;
- }
- else if (gcSelected == 1) {
- InvalidateRect(gfDlgSelected ? gnpcSel->hwnd : gnpcSel->hwndDrag,
- NULL, TRUE);
- }
- else {
- for (npc = npcHead; npc; npc = npc->npcNext) {
- if (npc->fSelected)
- InvalidateRect(npc->hwndDrag, NULL, TRUE);
- }
- }
- }
- /************************************************************************
- * SetAnchorToFirstSel
- *
- * This function makes the current selection (the anchor) be the
- * first selected control. It is used after making a group selection,
- * and ensures that the control that ends up being the anchor is
- * consistently the first one in Z-order.
- *
- * Arguments:
- * BOOL fDontUpdate = TRUE if the selection should NOT be redrawn.
- *
- ************************************************************************/
- VOID SetAnchorToFirstSel(
- BOOL fDontUpdate)
- {
- NPCTYPE npc;
- if (gcSelected) {
- for (npc = npcHead; npc; npc = npc->npcNext) {
- if (npc->fSelected) {
- SelectControl2(npc, fDontUpdate);
- break;
- }
- }
- }
- }
- /************************************************************************
- * SelectNext
- *
- * This selects the next control in the dialog box. The enumeration
- * includes the dialog box itself, and wraps around.
- *
- ************************************************************************/
- VOID SelectNext(VOID)
- {
- NPCTYPE npcSelect;
- /*
- * Disable the tabbing functions if there is no dialog
- * or if the dialog is already selected and there are
- * no controls (the tabs would be a noop in this case).
- */
- if (!gfEditingDlg || (gfDlgSelected && !npcHead))
- return;
- /*
- * Is nothing selected?
- */
- if (!gnpcSel) {
- /*
- * Select the first control, unless there are none, in which
- * case select the dialog.
- */
- if (npcHead)
- npcSelect = npcHead;
- else
- npcSelect = gcd.npc;
- }
- else {
- /*
- * Is the dialog selected?
- */
- if (gfDlgSelected) {
- /*
- * Select the first control, unless there are none, in which
- * case do nothing.
- */
- if (npcHead)
- npcSelect = npcHead;
- else
- npcSelect = NULL;
- }
- else {
- /*
- * Find the current control. If there is one after it,
- * select it, otherwise wrap around to the dialog and
- * select it.
- */
- if (gnpcSel->npcNext)
- npcSelect = gnpcSel->npcNext;
- else
- npcSelect = gcd.npc;
- }
- }
- if (npcSelect)
- SelectControl(npcSelect, FALSE);
- }
- /************************************************************************
- * SelectPrevious
- *
- * This selects the previous control in the dialog box. The enumeration
- * includes the dialog box itself, and wraps around.
- *
- ************************************************************************/
- VOID SelectPrevious(VOID)
- {
- NPCTYPE npc;
- NPCTYPE npcSelect;
- /*
- * Disable the tabbing functions if there is no dialog
- * or if the dialog is already selected and there are
- * no controls (the tabs would be a noop in this case).
- */
- if (!gfEditingDlg || (gfDlgSelected && !npcHead))
- return;
- /*
- * Is nothing selected?
- */
- if (!gnpcSel) {
- /*
- * Select the last control, unless there are none, in which
- * case select the dialog.
- */
- if (npcHead) {
- npc = npcHead;
- while (npc->npcNext)
- npc = npc->npcNext;
- npcSelect = npc;
- }
- else {
- npcSelect = gcd.npc;
- }
- }
- else {
- /*
- * Is the dialog selected?
- */
- if (gfDlgSelected) {
- /*
- * Select the last control, unless there are none, in which
- * case select nothing.
- */
- if (npcHead) {
- npc = npcHead;
- while (npc->npcNext)
- npc = npc->npcNext;
- npcSelect = npc;
- }
- else {
- npcSelect = NULL;
- }
- }
- else {
- /*
- * If the first control is selected, select the dialog.
- * Otherwise hunt for and select the previous control.
- */
- if (npcHead == gnpcSel) {
- npcSelect = gcd.npc;
- }
- else {
- npc = npcHead;
- while (npc->npcNext != gnpcSel)
- npc = npc->npcNext;
- npcSelect = npc;
- }
- }
- }
- if (npcSelect)
- SelectControl(npcSelect, FALSE);
- }
- /************************************************************************
- * UnSelectControl
- *
- * This unselects the specified control, hiding its drag window and handles.
- *
- * Arguments:
- * NPCTYPE npc = The control to deselect.
- *
- ************************************************************************/
- VOID UnSelectControl(
- NPCTYPE npc)
- {
- npc->fSelected = FALSE;
- gcSelected--;
- /*
- * We don't have a current selection if there are no selected
- * windows, or if the control we are unselecting was the current
- * selection.
- */
- if (!gcSelected || npc == gnpcSel)
- gnpcSel = NULL;
- if (npc->pwcd->iType == W_DIALOG) {
- gfDlgSelected = FALSE;
- InvalidateDlgHandles();
- }
- else {
- ShowWindow(npc->hwndDrag, SW_HIDE);
- }
- /*
- * Are there still some selected controls, and was the control
- * we just unselected the current selection? If so, we need
- * to set the current selection to something.
- */
- if (gcSelected && !gnpcSel)
- SetAnchorToFirstSel(FALSE);
- }
- /************************************************************************
- * InvalidateDlgHandles
- *
- * This function invalidates the handles for the dialog. This is
- * used as an optimization so that the entire dialog does not need
- * to be invalidated just to force the handles to be drawn.
- *
- ************************************************************************/
- STATICFN VOID InvalidateDlgHandles(VOID)
- {
- RECT rc;
- RECT rcClient;
- RECT rcFrame;
- POINT pt;
- INT xOffset;
- INT yOffset;
- /*
- * Redraw the dialog border.
- */
- SetWindowPos(gcd.npc->hwnd, NULL, 0, 0, 0, 0,
- SWP_DRAWFRAME | SWP_NOACTIVATE |
- SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
- /*
- * Get the frame and client rectangles.
- */
- GetWindowRect(gcd.npc->hwnd, &rcFrame);
- GetClientRect(gcd.npc->hwnd, &rcClient);
- /*
- * Determine the offset from the frame origin to the client
- * origin.
- */
- pt.x = pt.y = 0;
- ClientToScreen(gcd.npc->hwnd, &pt);
- xOffset = rcFrame.left - pt.x;
- yOffset = rcFrame.top - pt.y;
- /*
- * Make the frame rectangle zero based.
- */
- OffsetRect(&rcFrame, -rcFrame.left, -rcFrame.top);
- rc.left = 0;
- rc.top = 0;
- rc.right = CHANDLESIZE;
- rc.bottom = CHANDLESIZE;
- OffsetRect(&rc, xOffset, yOffset);
- InvalidateRect(gcd.npc->hwnd, &rc, TRUE);
- rc.left = ((rcFrame.right + 1) / 2) - (CHANDLESIZE / 2);
- rc.top = 0;
- rc.right = rc.left + CHANDLESIZE;
- rc.bottom = CHANDLESIZE;
- OffsetRect(&rc, xOffset, yOffset);
- InvalidateRect(gcd.npc->hwnd, &rc, TRUE);
- rc.left = rcFrame.right - CHANDLESIZE;
- rc.top = 0;
- rc.right = rcFrame.right;
- rc.bottom = CHANDLESIZE;
- OffsetRect(&rc, xOffset, yOffset);
- InvalidateRect(gcd.npc->hwnd, &rc, TRUE);
- rc.left = rcFrame.right - CHANDLESIZE;
- rc.top = ((rcFrame.bottom + 1) / 2) - (CHANDLESIZE / 2);
- rc.right = rcFrame.right;
- rc.bottom = rc.top + CHANDLESIZE;
- OffsetRect(&rc, xOffset, yOffset);
- InvalidateRect(gcd.npc->hwnd, &rc, TRUE);
- rc.left = rcFrame.right - CHANDLESIZE;
- rc.top = rcFrame.bottom - CHANDLESIZE;
- rc.right = rcFrame.right;
- rc.bottom = rcFrame.bottom;
- OffsetRect(&rc, xOffset, yOffset);
- InvalidateRect(gcd.npc->hwnd, &rc, TRUE);
- rc.left = ((rcFrame.right + 1) / 2) - (CHANDLESIZE / 2);
- rc.top = rcFrame.bottom - CHANDLESIZE;
- rc.right = rc.left + CHANDLESIZE;
- rc.bottom = rcFrame.bottom;
- OffsetRect(&rc, xOffset, yOffset);
- InvalidateRect(gcd.npc->hwnd, &rc, TRUE);
- rc.left = 0;
- rc.top = rcFrame.bottom - CHANDLESIZE;
- rc.right = CHANDLESIZE;
- rc.bottom = rcFrame.bottom;
- OffsetRect(&rc, xOffset, yOffset);
- InvalidateRect(gcd.npc->hwnd, &rc, TRUE);
- rc.left = 0;
- rc.top = ((rcFrame.bottom + 1) / 2) - (CHANDLESIZE / 2);
- rc.right = CHANDLESIZE;
- rc.bottom = rc.top + CHANDLESIZE;
- OffsetRect(&rc, xOffset, yOffset);
- InvalidateRect(gcd.npc->hwnd, &rc, TRUE);
- }
- /************************************************************************
- * CalcSelectedRect
- *
- * This routine updates the gwrcSelected rectangle. This is used during
- * dragging operations. It contains the minimum rectangle that spans
- * all the selected controls. If there are no selected controls, the
- * contents of this global are not defined. This routine must be called
- * every time that a control is selected of unselected to keep this
- * rectangle updated, or tracking will not work properly.
- *
- ************************************************************************/
- VOID CalcSelectedRect(VOID)
- {
- NPCTYPE npc;
- INT nBottom;
- INT nBottomLowest;
- /*
- * Nothing is selected. The rectangle values are considered
- * undefined, so we can quit.
- */
- if (!gcSelected)
- return;
- if (gcSelected == 1) {
- /*
- * Only one control is selected. Set the rectangle to its
- * rectangle. Note that since the dialog cannot be selected
- * along with other controls, this handles the case where the
- * dialog is selected.
- */
- grcSelected = gnpcSel->rc;
- gnOverHang = GetOverHang(gnpcSel->pwcd->iType,
- gnpcSel->rc.bottom - gnpcSel->rc.top);
- }
- else {
- /*
- * Seed the rectangle with impossible values.
- */
- SetRect(&grcSelected, 32000, 32000, -32000, -32000);
- nBottomLowest = 0;
- /*
- * Loop through all the controls, expanding the rectangle to
- * fit around all the selected controls.
- */
- for (npc = npcHead; npc; npc = npc->npcNext) {
- if (npc->fSelected) {
- if (npc->rc.left < grcSelected.left)
- grcSelected.left = npc->rc.left;
- if (npc->rc.right > grcSelected.right)
- grcSelected.right = npc->rc.right;
- if (npc->rc.top < grcSelected.top)
- grcSelected.top = npc->rc.top;
- nBottom = npc->rc.bottom - GetOverHang(npc->pwcd->iType,
- npc->rc.bottom - npc->rc.top);
- if (nBottom > nBottomLowest)
- nBottomLowest = nBottom;
- if (npc->rc.bottom > grcSelected.bottom)
- grcSelected.bottom = npc->rc.bottom;
- }
- }
- gnOverHang = grcSelected.bottom - nBottomLowest;
- }
- }
- /************************************************************************
- * CancelSelection
- *
- * This unselects all selected controls.
- *
- * Arguments:
- * BOOL fUpdate - If TRUE, the status ribbon is updated.
- *
- ************************************************************************/
- VOID CancelSelection(
- BOOL fUpdate)
- {
- if (gcSelected) {
- while (gcSelected)
- UnSelectControl(gnpcSel);
- if (fUpdate) {
- StatusUpdate();
- StatusSetEnable();
- }
- }
- }
- /************************************************************************
- * OutlineSelectBegin
- *
- * This function begins an Outline Selection operation. This will
- * draw a tracking rectangle on the screen that can be used to enclose
- * controls. When the selection is completed, all the enclosed controls
- * will be selected.
- *
- * The x and y coordinates are relative to the dialog window, not it's
- * client.
- *
- * Arguments:
- * INT x - Starting X location (window coords).
- * INT y - Starting Y location (window coords).
- *
- ************************************************************************/
- VOID OutlineSelectBegin(
- INT x,
- INT y)
- {
- /*
- * Always be sure the focus is where we want it, not on something
- * like the status ribbon or "Esc" won't work to cancel the tracking.
- */
- SetFocus(ghwndMain);
- /*
- * Remember the starting point. It comes in coords relative to the
- * window, and the DC we are getting is one for the dialog's client,
- * so we have to map it from window coords to the client's coords.
- */
- gptOutlineSelect.x = x;
- gptOutlineSelect.y = y;
- MapDlgClientPoint(&gptOutlineSelect, FALSE);
- gState = STATE_SELECTING;
- ghwndTrackOver = gcd.npc->hwnd;
- ghDCTrack = GetDC(ghwndTrackOver);
- SetROP2(ghDCTrack, R2_NOT);
- /*
- * Get the rectangle for the client area of the dialog. This is
- * used to limit the tracking.
- */
- GetClientRect(gcd.npc->hwnd, &grcOutlineSelectLimit);
- OutlineSelectDraw(x, y);
- /*
- * The mouse messages from now on will go to the dialog window,
- * so that the following routines can know that the mouse movement
- * points are relative to that window.
- */
- SetCapture(gcd.npc->hwnd);
- SetCursor(hcurOutSel);
- }
- /************************************************************************
- * OutlineSelectDraw
- *
- * This routine draws the outline selection rectangle. It is assumed
- * that the window has been locked for update appropriately or this
- * could leave garbage around. The outline selection rectangle is
- * drawn from the starting point in gptOutlineSelect to the given
- * x,y location.
- *
- * Arguments:
- * INT x - Mouse X location (window coords relative to the dialog).
- * INT y - Mouse Y location (window coords relative to the dialog).
- *
- ************************************************************************/
- VOID OutlineSelectDraw(
- INT x,
- INT y)
- {
- OutlineSelectHide();
- OutlineSelectSetRect(x, y);
- MyFrameRect(ghDCTrack, &grcOutlineSelect, DSTINVERT);
- gfOutlineSelectShown = TRUE;
- }
- /************************************************************************
- * OutlineSelectHide
- *
- * This routine hides the current outline selection rectangle.
- *
- ************************************************************************/
- STATICFN VOID OutlineSelectHide(VOID)
- {
- if (gfOutlineSelectShown) {
- MyFrameRect(ghDCTrack, &grcOutlineSelect, DSTINVERT);
- gfOutlineSelectShown = FALSE;
- }
- }
- /************************************************************************
- * OutlineSelectSetRect
- *
- * This function takes an x,y point and makes a rectangle that goes
- * from this point to the starting outline selection point. The cases
- * are handled where the new point has negative coordinates relative
- * to the starting point, and the rectangle produced is limited to
- * the rectangle in grcOutlineSelectLimit.
- *
- * The rectangle is placed into the global grcOutlineSelect. The
- * global point gwptOutlineSelect is assumed to have previously been
- * set to the starting point of the outline selection.
- *
- * The x and y coordinates are relative to the dialog window, not it's
- * client.
- *
- * Arguments:
- * INT x - Mouse X location (window coords relative to the dialog).
- * INT y - Mouse Y location (window coords relative to the dialog).
- *
- ************************************************************************/
- STATICFN VOID OutlineSelectSetRect(
- INT x,
- INT y)
- {
- POINT pt;
- /*
- * The point is coming in relative to the upper left of the
- * dialog window. It needs to be mapped to points relative
- * to the client of the dialog window.
- */
- pt.x = x;
- pt.y = y;
- MapDlgClientPoint(&pt, FALSE);
- if (pt.x > gptOutlineSelect.x) {
- grcOutlineSelect.left = gptOutlineSelect.x;
- grcOutlineSelect.right = pt.x;
- }
- else {
- grcOutlineSelect.left = pt.x;
- grcOutlineSelect.right = gptOutlineSelect.x;
- }
- if (pt.y > gptOutlineSelect.y) {
- grcOutlineSelect.top = gptOutlineSelect.y;
- grcOutlineSelect.bottom = pt.y;
- }
- else {
- grcOutlineSelect.top = pt.y;
- grcOutlineSelect.bottom = gptOutlineSelect.y;
- }
- if (grcOutlineSelect.left < grcOutlineSelectLimit.left)
- grcOutlineSelect.left = grcOutlineSelectLimit.left;
- if (grcOutlineSelect.right > grcOutlineSelectLimit.right)
- grcOutlineSelect.right = grcOutlineSelectLimit.right;
- if (grcOutlineSelect.top < grcOutlineSelectLimit.top)
- grcOutlineSelect.top = grcOutlineSelectLimit.top;
- if (grcOutlineSelect.bottom > grcOutlineSelectLimit.bottom)
- grcOutlineSelect.bottom = grcOutlineSelectLimit.bottom;
- }
- /************************************************************************
- * OutlineSelectCancel
- *
- * This routine is used to cancel the display of the outline selection
- * rectangle.
- *
- ************************************************************************/
- VOID OutlineSelectCancel(VOID)
- {
- OutlineSelectHide();
- ReleaseDC(ghwndTrackOver, ghDCTrack);
- gState = STATE_NORMAL;
- ReleaseCapture();
- SetCursor(hcurArrow);
- }
- /************************************************************************
- * OutlineSelectEnd
- *
- * This function completes an outline selection operation. All the
- * enclosed controls will be selected. If the Shift key is down,
- * the enclosed controls will be added to the selection, otherwise the
- * current selection will be cancelled first.
- *
- * The current selection will only be cancelled if there is
- * at least one new control enclosed. This is so that simply clicking and
- * releasing the mouse without enclosing any controls leaves the current
- * selection alone.
- *
- * Arguments:
- * INT x - Mouse X location (dialog client coords).
- * INT y - Mouse Y location (dialog client coords).
- *
- ************************************************************************/
- VOID OutlineSelectEnd(
- INT x,
- INT y)
- {
- NPCTYPE npc;
- BOOL fFirstOne = TRUE;
- OutlineSelectCancel();
- OutlineSelectSetRect(x, y);
- /*
- * If the mouse was not moved at all, consider this a request
- * to select the dialog instead of an outline selection operation.
- */
- if (grcOutlineSelect.left == grcOutlineSelect.right &&
- grcOutlineSelect.top == grcOutlineSelect.bottom) {
- SelectControl(gcd.npc, FALSE);
- return;
- }
- /*
- * Convert the selected rectangle to dialog units.
- */
- WinToDURect(&grcOutlineSelect);
- for (npc = npcHead; npc; npc = npc->npcNext) {
- /*
- * Do the rectangles intersect?
- */
- if (npc->rc.left < grcOutlineSelect.right &&
- grcOutlineSelect.left < npc->rc.right &&
- npc->rc.bottom > grcOutlineSelect.top &&
- grcOutlineSelect.bottom > npc->rc.top) {
- if (fFirstOne) {
- /*
- * If the Shift key is not held down, cancel any outstanding
- * selections.
- */
- if (!(GetKeyState(VK_SHIFT) & 0x8000))
- CancelSelection(FALSE);
- fFirstOne = FALSE;
- }
- /*
- * If the control is not selected, select it.
- */
- if (!npc->fSelected)
- SelectControl2(npc, TRUE);
- }
- }
- /*
- * Update some things if there was at least one control enclosed.
- */
- if (!fFirstOne) {
- SetAnchorToFirstSel(TRUE);
- StatusUpdate();
- StatusSetEnable();
- RedrawSelection();
- CalcSelectedRect();
- }
- }
- /************************************************************************
- * MyFrameRect
- *
- * This function draws a one-pixel width rectangle using the given
- * raster operation.
- *
- * Arguments:
- * HDC hDC - DC to use.
- * PRECT prc - Rectangle to draw the frame around.
- * DWORD dwRop - RasterOp to use (DSTINVERT, BLACKNESS, etc.).
- *
- ************************************************************************/
- VOID MyFrameRect(
- HDC hDC,
- PRECT prc,
- DWORD dwRop)
- {
- INT x;
- INT y;
- POINT pt;
- x = prc->right - (pt.x = prc->left);
- y = prc->bottom - (pt.y = prc->top);
- PatBlt(hDC, pt.x, pt.y, x, 1, dwRop);
- pt.y = prc->bottom - 1;
- PatBlt(hDC, pt.x, pt.y, x, 1, dwRop);
- pt.y = prc->top;
- PatBlt(hDC, pt.x, pt.y, 1, y, dwRop);
- pt.x = prc->right - 1;
- PatBlt(hDC, pt.x, pt.y, 1, y, dwRop);
- }
- /************************************************************************
- * MoveControl
- *
- * This function moves the current control to the next grid boundary in
- * the specified direction.
- *
- * Arguments:
- * WPARAM vKey - Virtual key code that was pressed.
- *
- ************************************************************************/
- VOID MoveControl(
- WPARAM vKey)
- {
- RECT rc;
- INT dx;
- INT dy;
- /*
- * Nothing is selected.
- */
- if (!gcSelected)
- return;
- rc = grcSelected;
- switch (vKey) {
- case VK_UP:
- dx = 0;
- if (!(dy = -(rc.top % gcyGrid)))
- dy = -gcyGrid;
- break;
- case VK_DOWN:
- dx = 0;
- dy = gcyGrid - (rc.top % gcyGrid);
- break;
- case VK_RIGHT:
- dx = gcxGrid - (rc.left % gcxGrid);
- dy = 0;
- break;
- case VK_LEFT:
- if (!(dx = -(rc.left % gcxGrid)))
- dx = -gcxGrid;
- dy = 0;
- break;
- }
- OffsetRect(&rc, dx, dy);
- FitRectToBounds(&rc, gnOverHang, DRAG_CENTER, gfDlgSelected);
- gHandleHit = DRAG_CENTER;
- PositionControl(&rc);
- }
- /************************************************************************
- * PositionControl
- *
- * This function positions and sizes the current control. Both the control
- * window and its associated drag window are moved at the same time. The
- * coordinates in the control, and the status window display are updated.
- * The given rectangle is in dialog units, and it should have already been
- * range limited and grid aligned as appropriate.
- *
- * Arguments:
- * NPWRECT nprc - The rectangle to size/position the control with.
- *
- ************************************************************************/
- VOID PositionControl(
- PRECT prc)
- {
- INT cx;
- INT cy;
- RECT rcT;
- NPCTYPE npcT;
- HANDLE hwpi;
- if (gcSelected == 1) {
- /*
- * Did nothing change?
- */
- if (EqualRect(prc, &gnpcSel->rc))
- return;
- /*
- * Only a single control is selected. Move it.
- */
- PositionControl2(gnpcSel, prc, NULL);
- /*
- * Is the dialog selected, being sized (not just moved), and
- * does it have at least one control?
- */
- if (gfDlgSelected && gHandleHit != DRAG_CENTER && npcHead) {
- cx = prc->left - grcSelected.left;
- cy = prc->top - grcSelected.top;
- /*
- * Did the top or left edge of the dialog move?
- */
- if (cx || cy) {
- /*
- * Loop through all the controls. Move all of them by
- * the dialog movement delta.
- */
- hwpi = BeginDeferWindowPos(cWindows * 2);
- for (npcT = npcHead; npcT; npcT = npcT->npcNext) {
- SetRect(&rcT, npcT->rc.left - cx, npcT->rc.top - cy,
- npcT->rc.right - cx, npcT->rc.bottom - cy);
- hwpi = PositionControl2(npcT, &rcT, hwpi);
- }
- EndDeferWindowPos(hwpi);
- }
- }
- }
- else {
- /*
- * Did nothing change?
- */
- if (EqualRect(prc, &grcSelected))
- return;
- /*
- * There is a group of controls selected.
- * Calculate how much the group rectangle was moved.
- * It is assumed that a group of controls cannot be
- * sized, only moved.
- */
- cx = prc->left - grcSelected.left;
- cy = prc->top - grcSelected.top;
- /*
- * Loop through all the controls. Move all the selected
- * ones by the group delta.
- */
- hwpi = BeginDeferWindowPos(gcSelected * 2);
- for (npcT = npcHead; npcT; npcT = npcT->npcNext) {
- if (npcT->fSelected) {
- SetRect(&rcT,
- npcT->rc.left + cx, npcT->rc.top + cy,
- npcT->rc.right + cx, npcT->rc.bottom + cy);
- GridizeRect(&rcT,
- GRIDIZE_LEFT | GRIDIZE_TOP | GRIDIZE_SAMESIZE);
- FitRectToBounds(&rcT,
- GetOverHang(npcT->pwcd->iType,
- npcT->rc.bottom - npcT->rc.top),
- DRAG_CENTER, gfDlgSelected);
- hwpi = PositionControl2(npcT, &rcT, hwpi);
- }
- }
- EndDeferWindowPos(hwpi);
- }
- CalcSelectedRect();
- StatusSetCoords(&gnpcSel->rc);
- gfResChged = gfDlgChanged = TRUE;
- ShowFileStatus(FALSE);
- }
- /************************************************************************
- * PositionControl2
- *
- * This function positions and sizes a single control. Both the control
- * window and its associated drag window are moved at the same time. The
- * coordinates in the control are updated.
- *
- * The given rectangle is in dialog units, and it should have already been
- * range limited and grid aligned as appropriate.
- *
- * Arguments:
- * NPCTYPE npc - The control to position.
- * PRECT prc - The rectangle to size/position the control with.
- * HANDLE hwpi - Handle that has been returned from a BeginDeferWindowPos
- * call. If this parameter is not NULL, the calls to
- * position the control and drag window will use this
- * handle.
- *
- * Returns:
- *
- * The return will be the hwpi handle that is currently being used.
- * The variable that the caller is using must be updated with the
- * return value each call, because each call to DeferWindowPos can
- * possibly change this value.
- *
- ************************************************************************/
- STATICFN HANDLE PositionControl2(
- NPCTYPE npc,
- PRECT prc,
- HANDLE hwpi)
- {
- RECT rc;
- RECT rcDrag;
- HANDLE hwpi2;
- /*
- * Make a local copy of the rectangle.
- */
- rc = *prc;
- /*
- * Start calculating the new position. Begin by mapping the dialog
- * points to window coordinates.
- */
- DUToWinRect(&rc);
- if (npc->pwcd->iType == W_DIALOG) {
- InvalidateDlgHandles();
- AdjustWindowRectEx(&rc, npc->flStyle, FALSE,
- (npc->flStyle & DS_MODALFRAME) ?
- npc->flExtStyle | WS_EX_DLGMODALFRAME : npc->flExtStyle);
- ClientToScreenRect(ghwndSubClient, &rc);
- MoveWindow(npc->hwnd, rc.left, rc.top,
- rc.right - rc.left, rc.bottom - rc.top, TRUE);
- /*
- * Update the control structure with the new rectangle.
- */
- npc->rc = *prc;
- /*
- * Since this was the dialog that was just positioned, we need to
- * recalculate and save the size of its "client" area.
- */
- SaveDlgClientRect(npc->hwnd);
- }
- else {
- rcDrag = rc;
- InflateRect(&rcDrag, CHANDLESIZE / 2, CHANDLESIZE / 2);
- if (hwpi)
- hwpi2 = hwpi;
- else
- hwpi2 = BeginDeferWindowPos(2);
- hwpi2 = DeferWindowPos(hwpi2, npc->hwndDrag, NULL,
- rcDrag.left, rcDrag.top,
- rcDrag.right - rcDrag.left, rcDrag.bottom - rcDrag.top,
- SWP_NOACTIVATE | SWP_NOZORDER);
- hwpi2 = DeferWindowPos(hwpi2, npc->hwnd, NULL, rc.left, rc.top,
- rc.right - rc.left, rc.bottom - rc.top,
- SWP_NOACTIVATE | SWP_NOZORDER);
- if (!hwpi)
- EndDeferWindowPos(hwpi2);
- /*
- * Update the control structure with the new rectangle.
- */
- npc->rc = *prc;
- InvalidateRect(npc->hwndDrag, NULL, TRUE);
- }
- return hwpi2;
- }
- /************************************************************************
- * RepositionDialog
- *
- * This routine forces the dialog to be moved to the location that
- * is stored in it's npc rectangle. This is necessary after the
- * main application has been moved, because the dialog is relative
- * to the app's window and does not automatically move with it.
- *
- ************************************************************************/
- VOID RepositionDialog(VOID)
- {
- PositionControl2(gcd.npc, &gcd.npc->rc, NULL);
- }
- /************************************************************************
- * SaveDlgClientRect
- *
- * This routine saves away a global that will contain the offset, in window
- * coordinates, of the origin of the "client" area for the current dialog.
- *
- * Arguments:
- * HWND hwndDlg - The dialog window.
- *
- ************************************************************************/
- VOID SaveDlgClientRect(
- HWND hwndDlg)
- {
- RECT rcFrame;
- POINT pt;
- GetWindowRect(hwndDlg, &rcFrame);
- GetClientRect(hwndDlg, &grcDlgClient);
- pt.x = pt.y = 0;
- ClientToScreen(hwndDlg, &pt);
- OffsetRect(&grcDlgClient, pt.x - rcFrame.left, pt.y - rcFrame.top);
- }
- /************************************************************************
- * SizeToText
- *
- * This function will size all the selected controls to fit their text.
- * This is to support the "Size to text" command of the "Edit" menu.
- *
- * Globals are updated appropriately if anything actually had to change.
- *
- ************************************************************************/
- VOID SizeToText(VOID)
- {
- NPCTYPE npc;
- BOOL fSized = FALSE;
- /*
- * Loop through all the controls.
- */
- for (npc = npcHead; npc; npc = npc->npcNext) {
- /*
- * Is the control selected, and can it be sized to its text?
- */
- if (npc->fSelected && npc->pwcd->fSizeToText)
- fSized |= SizeCtrlToText(npc);
- }
- /*
- * Was anything modified?
- */
- if (fSized) {
- CalcSelectedRect();
- StatusSetCoords(&gnpcSel->rc);
- gfResChged = gfDlgChanged = TRUE;
- ShowFileStatus(FALSE);
- }
- }
- /************************************************************************
- * SizeCtrlToText
- *
- * This function sizes a single control so that it just fits its text.
- * This does not make sense for all controls (see the fSizeToText flag
- * in the awcd array), and there are different rules for the different
- * types of controls.
- *
- * Arguments:
- * NPCTYPE npc - The control to size.
- *
- * Returns:
- *
- * The return value is TRUE if the control was modified (sized) or
- * FALSE if it was not.
- *
- ************************************************************************/
- STATICFN BOOL SizeCtrlToText(
- NPCTYPE npc)
- {
- RECT rc;
- INT x;
- INT cxLowern;
- switch (npc->pwcd->iType) {
- case W_CHECKBOX:
- /*
- * Take the width of the text, plus some pixels for the square.
- */
- x = QueryTextExtent(npc->hwnd, npc->text, TRUE) + 20;
- x = MulDiv(x, 4, gcd.cxChar) + 1;
- break;
- case W_PUSHBUTTON:
- /*
- * The UITF definition of the size of a pushbutton says
- * that the left and right margins should be approximately
- * the width of a lowercase "n". In any event, the width
- * cannot be less than the default size.
- */
- cxLowern = QueryTextExtent(npc->hwnd, L"n", FALSE);
- x = QueryTextExtent(npc->hwnd, npc->text, FALSE) + (2 * cxLowern);
- x = MulDiv(x, 4, gcd.cxChar);
- if (x < awcd[W_PUSHBUTTON].cxDefault)
- x = awcd[W_PUSHBUTTON].cxDefault;
- break;
- case W_RADIOBUTTON:
- /*
- * Take the width of the text, plus some for the circle.
- */
- x = QueryTextExtent(npc->hwnd, npc->text, TRUE) + 20;
- x = MulDiv(x, 4, gcd.cxChar) + 1;
- break;
- case W_TEXT:
- /*
- * Take the width of the text.
- */
- x = QueryTextExtent(npc->hwnd, npc->text, TRUE);
- x = MulDiv(x, 4, gcd.cxChar) + 1;
- break;
- case W_CUSTOM:
- /*
- * Call out to the custom control and let it decide
- * how wide the text should be.
- */
- x = CallCustomSizeToText(npc);
- break;
- default:
- x = -1;
- break;
- }
- /*
- * Does it need to be sized?
- */
- if (x != -1 && x != npc->rc.right - npc->rc.left) {
- /*
- * Now that we know the size we want the control, position
- * it to change that size. Note that we do NOT gridize
- * the left edge here. The user probably just wants the
- * right edge of the control to be adjusted to fit the new
- * text, and probably does not want the left edge shifting
- * on them.
- */
- rc = npc->rc;
- rc.right = rc.left + x;
- FitRectToBounds(&rc,
- GetOverHang(npc->pwcd->iType, npc->rc.bottom - npc->rc.top),
- DRAG_CENTER, gfDlgSelected);
- PositionControl2(npc, &rc, NULL);
- return TRUE;
- }
- return FALSE;
- }
- /************************************************************************
- * QueryTextExtent
- *
- * This function takes a window handle and text, and will return the
- * number of pixels that the specified text is wide in that window.
- * It is used to determine how wide a control needs to be to display
- * its text.
- *
- * The font set into the current dialog is taken into consideration
- * when calculating the size.
- *
- * Arguments:
- * HWND hwnd - The control window handle.
- * LPTSTR pszText - The text of the control.
- * BOOL fWordBreak - TRUE if this text will be drawn with DT_WORDBREAK.
- *
- * Returns:
- *
- * The number of pixels wide the selected text is.
- *
- ************************************************************************/
- STATICFN INT QueryTextExtent(
- HWND hwnd,
- LPTSTR pszText,
- BOOL fWordBreak)
- {
- HDC hDC;
- INT iHeight;
- RECT rc;
- INT nLen;
- HFONT hfontOld;
- if (!pszText || *pszText == CHAR_NULL)
- return 0;
- hDC = GetDC(hwnd);
- /*
- * If there is a valid font, select it into the DC. Note that
- * we look at gcd.hFont instead of gcd.fFontSpecified, because
- * it is possible to specify a font for the dialog but not have
- * been able to create it.
- */
- if (gcd.hFont)
- hfontOld = SelectObject(hDC, gcd.hFont);
- /*
- * First, calculate the length of the text.
- */
- rc.left = rc.top = 0;
- rc.right = 10000;
- rc.bottom = 10000;
- nLen = lstrlen(pszText);
- DrawText(hDC, pszText, nLen, &rc,
- DT_CALCRECT | DT_NOCLIP | DT_EXPANDTABS);
- /*
- * First save the height of the line. This works because the
- * DrawText call above with DT_CALCRECT will always draw on
- * a single line. Then we move the upwards the rectangle to draw
- * in a large amount, so that it is outside the dimensions of
- * the control. Finally, we do a real draw of the text,
- * increasing the width a little each time until we are able
- * to draw entirely on one line. This is inefficient, but it does
- * ensure that the returned width will be enough to actually
- * draw the string.
- */
- if (fWordBreak) {
- iHeight = rc.bottom - rc.top;
- rc.top -= 10000;
- rc.bottom -= 10000;
- while (TRUE) {
- /*
- * Determine if we have enough width to draw on a single
- * line yet.
- */
- if (DrawText(hDC, pszText, nLen, &rc,
- DT_NOCLIP | DT_EXPANDTABS | DT_WORDBREAK) == iHeight)
- break;
- /*
- * Nope, push the right margin out and try again...
- */
- rc.right++;
- }
- }
- if (gcd.hFont)
- SelectObject(hDC, hfontOld);
- ReleaseDC(hwnd, hDC);
- return rc.right - rc.left;
- }
- /************************************************************************
- * AlignControls
- *
- * This function will align all the selected controls. The point to
- * align to is always taken from the currently selected control.
- *
- * In all cases, the resulting desired position of the control will be
- * gridized and limited to the dialogs "client" area. The size of the
- * controls will not be changed.
- *
- * Arguments:
- * INT cmd - The alignment menu command.
- *
- * The following are valid values for cmd:
- *
- * MENU_ALIGNLEFT - Align to the left edge.
- * MENU_ALIGNVERT - Align to the center vertically.
- * MENU_ALIGNRIGHT - Align to the right edge.
- * MENU_ALIGNTOP - Align to the top edge.
- * MENU_ALIGNHORZ - Align to the center horizontally.
- * MENU_ALIGNBOTTOM - Align to the bottom edge.
- *
- ************************************************************************/
- VOID AlignControls(
- INT cmd)
- {
- register INT sDelta;
- NPCTYPE npc;
- RECT rc;
- BOOL fMove;
- BOOL fModified = FALSE;
- /*
- * Loop through all the controls. Align all the selected ones.
- */
- for (npc = npcHead; npc; npc = npc->npcNext) {
- if (npc->fSelected && npc != gnpcSel) {
- rc = npc->rc;
- fMove = FALSE;
- switch (cmd) {
- case MENU_ALIGNLEFT:
- if (sDelta = gnpcSel->rc.left - rc.left) {
- fMove = TRUE;
- rc.left += sDelta;
- rc.right += sDelta;
- }
- break;
- case MENU_ALIGNVERT:
- if (sDelta =
- (((gnpcSel->rc.right - gnpcSel->rc.left) / 2)
- + gnpcSel->rc.left) -
- (((rc.right - rc.left) / 2) +
- rc.left)) {
- fMove = TRUE;
- rc.left += sDelta;
- rc.right += sDelta;
- }
- break;
- case MENU_ALIGNRIGHT:
- if (sDelta = gnpcSel->rc.right - rc.right) {
- fMove = TRUE;
- rc.left += sDelta;
- rc.right += sDelta;
- }
- break;
- case MENU_ALIGNTOP:
- if (sDelta = gnpcSel->rc.top - rc.top) {
- fMove = TRUE;
- rc.top += sDelta;
- rc.bottom += sDelta;
- }
- break;
- case MENU_ALIGNHORZ:
- if (sDelta =
- (((gnpcSel->rc.bottom - gnpcSel->rc.top) / 2)
- + gnpcSel->rc.top) -
- (((rc.bottom - rc.top) / 2) +
- rc.top)) {
- fMove = TRUE;
- rc.top += sDelta;
- rc.bottom += sDelta;
- }
- break;
- case MENU_ALIGNBOTTOM:
- if (sDelta = gnpcSel->rc.bottom - rc.bottom) {
- fMove = TRUE;
- rc.top += sDelta;
- rc.bottom += sDelta;
- }
- break;
- }
- if (fMove) {
- GridizeRect(&rc,
- GRIDIZE_LEFT | GRIDIZE_TOP | GRIDIZE_SAMESIZE);
- FitRectToBounds(&rc, GetOverHang(npc->pwcd->iType,
- npc->rc.bottom - npc->rc.top),
- DRAG_CENTER, FALSE);
- if (!EqualRect(&rc, &npc->rc)) {
- PositionControl2(npc, &rc, NULL);
- fModified = TRUE;
- }
- }
- }
- }
- if (fModified) {
- RedrawSelection();
- CalcSelectedRect();
- gfResChged = gfDlgChanged = TRUE;
- ShowFileStatus(FALSE);
- StatusUpdate();
- }
- }
- /************************************************************************
- * ArrangeSpacing
- *
- * This function will evenly space all the selected controls. The
- * currently selected control is not moved (unless it has to be gridized)
- * and any previous controls in Z order will be evenly spaced to the
- * left or above the anchor, and all controls following in Z order will
- * be evenly spaced below or to the right of the anchor.
- *
- * The spacing values used are gxSpace and gySpace.
- *
- * In all cases, the resulting desired position of the control will be
- * gridized and limited to the dialogs "client" area. The size of the
- * controls is not changed.
- *
- * Arguments:
- * INT cmd - The Arrange/Even spacing menu command.
- *
- * The following are valid values for cmd:
- *
- * MENU_SPACEHORZ - Space the controls left and right.
- * MENU_SPACEVERT - Space all the controls up and down.
- *
- ************************************************************************/
- VOID ArrangeSpacing(
- INT cmd)
- {
- NPCTYPE npc;
- RECT rc;
- BOOL fModified = FALSE;
- INT x;
- INT y;
- INT cPreceding;
- INT xTotalWidth;
- INT yTotalWidth;
- cPreceding = 0;
- xTotalWidth = 0;
- yTotalWidth = 0;
- for (npc = npcHead; npc; npc = npc->npcNext) {
- if (npc->fSelected) {
- if (npc == gnpcSel)
- break;
- cPreceding++;
- xTotalWidth += npc->rc.right - npc->rc.left;
- yTotalWidth += npc->rc.bottom - npc->rc.top;
- }
- }
- x = gnpcSel->rc.left;
- y = gnpcSel->rc.top;
- if (cPreceding) {
- x -= xTotalWidth + (gxSpace * cPreceding);
- y -= yTotalWidth + (gySpace * cPreceding);
- }
- /*
- * Loop through all the controls. Space all the selected ones.
- */
- for (npc = npcHead; npc; npc = npc->npcNext) {
- if (npc->fSelected) {
- rc = npc->rc;
- switch (cmd) {
- case MENU_SPACEVERT:
- rc.top = y;
- rc.bottom = y + (npc->rc.bottom - npc->rc.top);
- y = rc.bottom + gySpace;
- break;
- case MENU_SPACEHORZ:
- rc.left = x;
- rc.right = x + (npc->rc.right - npc->rc.left);
- x = rc.right + gxSpace;
- break;
- }
- GridizeRect(&rc, GRIDIZE_LEFT | GRIDIZE_TOP | GRIDIZE_SAMESIZE);
- FitRectToBounds(&rc, GetOverHang(npc->pwcd->iType,
- npc->rc.bottom - npc->rc.top),
- DRAG_CENTER, FALSE);
- if (!EqualRect(&rc, &npc->rc)) {
- PositionControl2(npc, &rc, NULL);
- fModified = TRUE;
- }
- }
- }
- if (fModified) {
- RedrawSelection();
- CalcSelectedRect();
- gfResChged = gfDlgChanged = TRUE;
- ShowFileStatus(FALSE);
- StatusUpdate();
- }
- }
- /************************************************************************
- * ArrangeSize
- *
- * This function will evenly size all the selected controls. The
- * currently selected control determines the size that the other
- * controls will be set to in the given dimension.
- *
- * In all cases, the resulting size of the control will be gridized and
- * limited to the dialogs "client" area.
- *
- * Arguments:
- * INT cmd - The Arrange/Same size menu command.
- *
- * The following are valid values for cmd:
- *
- * MENU_ARRSIZEWIDTH - Size the widths of the controls.
- * MENU_ARRSIZEHEIGHT - Size the heights of the controls.
- *
- ************************************************************************/
- VOID ArrangeSize(
- INT cmd)
- {
- NPCTYPE npc;
- RECT rc;
- BOOL fModified = FALSE;
- INT cx;
- INT cy;
- cx = gnpcSel->rc.right - gnpcSel->rc.left;
- cy = gnpcSel->rc.bottom - gnpcSel->rc.top;
- /*
- * Loop through all the controls, operating on the selected ones.
- */
- for (npc = npcHead; npc; npc = npc->npcNext) {
- /*
- * Is the control selected, and is it sizeable?
- */
- if (npc->fSelected && npc->pwcd->fSizeable) {
- rc = npc->rc;
- switch (cmd) {
- case MENU_ARRSIZEWIDTH:
- rc.right = npc->rc.left + cx;
- break;
- case MENU_ARRSIZEHEIGHT:
- rc.top = npc->rc.bottom - cy;
- break;
- }
- GridizeRect(&rc, GRIDIZE_LEFT | GRIDIZE_TOP |
- GRIDIZE_RIGHT | GRIDIZE_BOTTOM);
- FitRectToBounds(&rc, GetOverHang(npc->pwcd->iType,
- npc->rc.bottom - npc->rc.top),
- DRAG_CENTER, FALSE);
- if (!EqualRect(&rc, &npc->rc)) {
- PositionControl2(npc, &rc, NULL);
- fModified = TRUE;
- }
- }
- }
- if (fModified) {
- RedrawSelection();
- CalcSelectedRect();
- gfResChged = gfDlgChanged = TRUE;
- ShowFileStatus(FALSE);
- StatusUpdate();
- }
- }
- /************************************************************************
- * ArrangePushButtons
- *
- * This function will arrange push buttons along either the bottom of
- * the dialog or along the right side of the dialog. It will operate
- * on the selected buttons (which button is currently selected does not
- * matter) but this function can also be used if buttons are not selected
- * in a couple of special cases. If either the dialog or nothing is
- * selected, ALL the push buttons in the dialog will be arranged.
- *
- * The margin values used are gxMargin and gyMargin, and the spacing
- * between buttons is gxMinPushSpace, gxMaxPushSpace and gyPushSpace.
- *
- * In all cases, the resulting desired position of the buttons will be
- * gridized and limited to the dialogs "client" area. The size of the
- * push buttons is not changed.
- *
- * Arguments:
- * INT cmd - The Arrange/Push buttons menu command.
- *
- * The following are valid values for cmd:
- *
- * MENU_ARRPUSHBOTTOM - Arrange push buttons along the bottom.
- * MENU_ARRPUSHRIGHT - Arrange push buttons along the right side.
- *
- ************************************************************************/
- VOID ArrangePushButtons(
- INT cmd)
- {
- NPCTYPE npc;
- RECT rc;
- BOOL fModified = FALSE;
- INT x; // Note: These values must be signed.
- INT y;
- INT cxDlg;
- INT cButtons;
- INT xTotal;
- INT xInterSpace;
- switch (cmd) {
- case MENU_ARRPUSHBOTTOM:
- cxDlg = gcd.npc->rc.right - gcd.npc->rc.left;
- y = (gcd.npc->rc.bottom - gcd.npc->rc.top) - gyMargin;
- for (cButtons = 0, xTotal = 0, npc = npcHead; npc;
- npc = npc->npcNext) {
- if (npc->pwcd->iType == W_PUSHBUTTON &&
- (!gcSelected || gfDlgSelected || npc->fSelected)) {
- cButtons++;
- xTotal += npc->rc.right - npc->rc.left;
- }
- }
- if (cButtons == 1) {
- x = (cxDlg - xTotal) / 2;
- xInterSpace = 0;
- }
- else {
- xInterSpace = (cxDlg - xTotal) / (cButtons + 1);
- if (xInterSpace > gxMaxPushSpace)
- xInterSpace = gxMaxPushSpace;
- else if (xInterSpace < gxMinPushSpace)
- xInterSpace = gxMinPushSpace;
- x = (cxDlg - ((cButtons - 1) * xInterSpace) - xTotal) / 2;
- if (x < 0)
- x = 0;
- if (x < gxMargin && xInterSpace > gxMinPushSpace) {
- xInterSpace = (cxDlg - xTotal - (2 * gxMargin))
- / (cButtons - 1);
- if (xInterSpace < gxMinPushSpace)
- xInterSpace = gxMinPushSpace;
- x = (cxDlg - ((cButtons - 1) * xInterSpace) - xTotal)
- / 2;
- if (x < 0)
- x = 0;
- }
- }
- break;
- case MENU_ARRPUSHRIGHT:
- x = (gcd.npc->rc.right - gcd.npc->rc.left) - gxMargin;
- y = gyMargin;
- break;
- }
- /*
- * Loop through all the controls.
- */
- for (npc = npcHead; npc; npc = npc->npcNext) {
- /*
- * We will arrange this control only if it is a pushbutton,
- * and only if one of the following is true: there are no
- * controls selected, or the dialog itself is selected, or
- * there are some controls selected and this pushbutton is
- * one of them.
- */
- if (npc->pwcd->iType == W_PUSHBUTTON &&
- (!gcSelected || gfDlgSelected || npc->fSelected)) {
- rc = npc->rc;
- switch (cmd) {
- case MENU_ARRPUSHBOTTOM:
- rc.left = x;
- rc.top = y - (npc->rc.bottom - npc->rc.top);
- rc.bottom = y;
- rc.right = rc.left + (npc->rc.right - npc->rc.left);
- x = rc.right + xInterSpace;
- break;
- case MENU_ARRPUSHRIGHT:
- rc.left = x - (npc->rc.right - npc->rc.left);
- rc.bottom = y + (npc->rc.bottom - npc->rc.top);
- rc.right = x;
- rc.top = y;
- y = rc.bottom + gyPushSpace;
- break;
- }
- GridizeRect(&rc, GRIDIZE_LEFT | GRIDIZE_TOP | GRIDIZE_SAMESIZE);
- FitRectToBounds(&rc, GetOverHang(npc->pwcd->iType,
- npc->rc.bottom - npc->rc.top),
- DRAG_CENTER, FALSE);
- if (!EqualRect(&rc, &npc->rc)) {
- PositionControl2(npc, &rc, NULL);
- fModified = TRUE;
- }
- }
- }
- if (fModified) {
- if (gfDlgSelected || !gcSelected)
- InvalidateRect(gcd.npc->hwnd, NULL, TRUE);
- CalcSelectedRect();
- gfResChged = gfDlgChanged = TRUE;
- ShowFileStatus(FALSE);
- StatusUpdate();
- }
- }