/// /// Copyright © 2003-2008 JetBrains s.r.o. /// You may distribute under the terms of the GNU General Public License, as published by the Free Software Foundation, version 2 (see License.txt in the repository root folder). /// // CDialogAnchor — Implements anchoring of UI controls on the WinAPI dialogs. // // This helps with implementing the resizeable dialogs // that maintain the relative layout of the conrols when resizing, // according to the anchoring information provided. // // © JetBrains Inc, 2005 // Written by (H) Serge Baltic // #include "StdAfx.h" #include ".\dialoganchor.h" CDialogAnchor::CDialogAnchor(void) { m_hwndDialog = NULL; } CDialogAnchor::~CDialogAnchor(void) { } void CDialogAnchor::Attach(HWND hwndDialog) { ASSERT(hwndDialog != NULL); // Store m_hwndDialog = hwndDialog; // Get the bounds CRect rc; GetWindowRect(m_hwndDialog, &rc); m_sizeDialog = rc.Size(); // The client rect GetClientRect(m_hwndDialog, &rc); m_sizeClient = rc.Size(); } void CDialogAnchor::AddControl(HWND hwndControl, Anchor anchor) { ASSERT(m_hwndDialog != NULL); if(m_hwndDialog == NULL) return; // Add the anchoring information (this will also save the initial sizing data) m_controls.push_back(CAnchoredControl(hwndControl, m_hwndDialog, anchor, m_sizeClient)); } void CDialogAnchor::PerformLayout() const { // Measure the dialog's client rect CRect client; GetClientRect(m_hwndDialog, &client); CSize sizeClient = client.Size(); // Layout all the controls std::vector::const_iterator cit; for(cit = m_controls.begin(); cit != m_controls.end(); ++cit) cit->PerformLayout(m_hwndDialog, sizeClient); } ///////////////////////////////////////////////////////////////////////////// // CAnchoredControl Definitions CAnchoredControl::CAnchoredControl(HWND hwnd, HWND hwndDialog, Anchor anchor, CSize sizeClient) { ASSERT(hwnd != NULL); ASSERT(hwndDialog != NULL); // Store m_hWnd = hwnd; m_anchor = anchor; // Gather the layouting info CRect rcBounds; // Bounds of the control GetWindowRect(m_hWnd, &rcBounds); // Convert to the dialog's client coordinates CPoint pt(0, 0); ClientToScreen(hwndDialog, &pt); rcBounds.OffsetRect(-pt.x, -pt.y); // Store the distances m_rcDistances = CRect(rcBounds.left, rcBounds.top, sizeClient.cx - rcBounds.right, sizeClient.cy - rcBounds.bottom); // Store the dimensions m_sizeDimensions = rcBounds.Size(); } CAnchoredControl::CAnchoredControl(const CAnchoredControl &other) { *this = other; // Use operator= } CAnchoredControl &CAnchoredControl::operator=(const CAnchoredControl &other) { m_hWnd = other.m_hWnd; m_rcDistances = other.m_rcDistances; m_anchor = other.m_anchor; m_sizeDimensions = other.m_sizeDimensions; return *this; } CAnchoredControl::~CAnchoredControl() { } void CAnchoredControl::PerformLayout(HWND hwndDialog, CSize sizeClient) const { ASSERT(m_hWnd != NULL); // Get the current control bounds CRect rcBounds; // Bounds of the control GetWindowRect(m_hWnd, &rcBounds); // Convert to the dialog's client coordinates CPoint ptClientToScreen(0, 0); ClientToScreen(hwndDialog, &ptClientToScreen); rcBounds.OffsetRect(-ptClientToScreen.x, -ptClientToScreen.y); //////////////////// // Apply anchoring, checking the anchoring flags // Horizontal anchoring if((m_anchor & anchorLeft) && (m_anchor & anchorRight)) // A sizing horizontal anchoring { rcBounds.left = m_rcDistances.left; rcBounds.right = sizeClient.cx - m_rcDistances.right; } else if(m_anchor & anchorLeft) // A non-sizing left-anchoring { rcBounds.left = m_rcDistances.left; rcBounds.right = rcBounds.left + m_sizeDimensions.cx; } else if(m_anchor & anchorRight) // A non-sizing right-anchoring { rcBounds.right = sizeClient.cx - m_rcDistances.right; rcBounds.left = rcBounds.right - m_sizeDimensions.cx; } // Vertical anchoring if((m_anchor & anchorTop) && (m_anchor & anchorBottom)) { rcBounds.top = m_rcDistances.top; rcBounds.bottom = sizeClient.cy - m_rcDistances.bottom; } else if(m_anchor & anchorTop) // A non-sizing top-anchoring { rcBounds.top = m_rcDistances.top; rcBounds.bottom = rcBounds.top + m_sizeDimensions.cy; } else if(m_anchor & anchorBottom) // A non-sizing bottom-anchoring { rcBounds.bottom = sizeClient.cy - m_rcDistances.bottom; rcBounds.top = rcBounds.bottom - m_sizeDimensions.cy; } // Apply the new size to the window SetWindowPos(m_hWnd, NULL, rcBounds.left, rcBounds.top, rcBounds.Width(), rcBounds.Height(), SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER); // Apply the new position InvalidateRect(m_hWnd, NULL, TRUE); }