#include "stdafx.h" #include "CDialogResizeHelper.h" #include "win32_op.h" static BOOL GetChildWindowRect2(HWND wnd, HWND wndChild, RECT* child) { RECT temp; if (wndChild == NULL) return FALSE; if (!GetWindowRect(wndChild, &temp)) return FALSE; if (!MapWindowPoints(NULL, wnd, (POINT*)&temp, 2)) return FALSE; *child = temp; return TRUE; } static BOOL GetChildWindowRect(HWND wnd, UINT id, RECT* child) { return GetChildWindowRect2(wnd, GetDlgItem(wnd, id), child); } bool CDialogResizeHelper::EvalRect(UINT id, CRect & out) const { for( auto iter = m_runtime.begin(); iter != m_runtime.end(); ++ iter ) { if ( iter->initData.id == id ) { out = _EvalRect(*iter, this->CurrentSize() ); return true; } } return false; } CRect CDialogResizeHelper::_EvalRect(runtime_t const & rt, CSize wndSize) const { CRect rc = rt.origRect; int delta_x = wndSize.cx - rt.origWindowSize.cx, delta_y = wndSize.cy - rt.origWindowSize.cy; const Param & e = rt.initData; rc.left += pfc::rint32(e.snapLeft * delta_x); rc.right += pfc::rint32(e.snapRight * delta_x); rc.top += pfc::rint32(e.snapTop * delta_y); rc.bottom += pfc::rint32(e.snapBottom * delta_y); return rc; } CWindow CDialogResizeHelper::ResolveWnd(runtime_t const & rt) const { if ( rt.userHWND != NULL ) return rt.userHWND; return m_thisWnd.GetDlgItem( rt.initData.id ); } CSize CDialogResizeHelper::CurrentSize() const { CRect rc; WIN32_OP_D( m_thisWnd.GetClientRect(rc) ); return rc.Size(); } void CDialogResizeHelper::OnSize(UINT, CSize newSize) { if (m_thisWnd != NULL) { HDWP hWinPosInfo = BeginDeferWindowPos((int)(m_runtime.size() + (m_sizeGrip != NULL ? 1 : 0))); for (auto iter = m_runtime.begin(); iter != m_runtime.end(); ++ iter) { CRect rc = _EvalRect(*iter, newSize); hWinPosInfo = DeferWindowPos(hWinPosInfo, ResolveWnd(*iter), 0, rc.left, rc.top, rc.Width(), rc.Height(), SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOACTIVATE | SWP_NOCOPYBITS); } if (m_sizeGrip != NULL) { RECT rc, rc_grip; if (m_thisWnd.GetClientRect(&rc) && m_sizeGrip.GetWindowRect(&rc_grip)) { DWORD flags = SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOCOPYBITS; if (IsZoomed(m_thisWnd)) flags |= SWP_HIDEWINDOW; else flags |= SWP_SHOWWINDOW; hWinPosInfo = DeferWindowPos(hWinPosInfo, m_sizeGrip, NULL, rc.right - (rc_grip.right - rc_grip.left), rc.bottom - (rc_grip.bottom - rc_grip.top), 0, 0, flags); } } EndDeferWindowPos(hWinPosInfo); //RedrawWindow(m_thisWnd, NULL, NULL, RDW_UPDATENOW | RDW_ALLCHILDREN); } SetMsgHandled(FALSE); } void CDialogResizeHelper::OnGetMinMaxInfo(LPMINMAXINFO info) const { CRect r; const DWORD dwStyle = m_thisWnd.GetWindowLong(GWL_STYLE); const DWORD dwExStyle = m_thisWnd.GetWindowLong(GWL_EXSTYLE); if (max_x && max_y) { r.left = 0; r.right = max_x; r.top = 0; r.bottom = max_y; MapDialogRect(m_thisWnd, &r); AdjustWindowRectEx(&r, dwStyle, FALSE, dwExStyle); info->ptMaxTrackSize.x = r.right - r.left; info->ptMaxTrackSize.y = r.bottom - r.top; } if (min_x && min_y) { r.left = 0; r.right = min_x; r.top = 0; r.bottom = min_y; MapDialogRect(m_thisWnd, &r); AdjustWindowRectEx(&r, dwStyle, FALSE, dwExStyle); info->ptMinTrackSize.x = r.right - r.left; info->ptMinTrackSize.y = r.bottom - r.top; } } void CDialogResizeHelper::OnInitDialog(CWindow thisWnd) { m_thisWnd = thisWnd; const auto origSize = CurrentSize(); for( auto initIter = m_initData.begin(); initIter != m_initData.end(); ++ initIter ) { CRect rc; if (GetChildWindowRect(m_thisWnd, initIter->id, &rc)) { runtime_t rt; rt.origRect = rc; rt.initData = * initIter; rt.origWindowSize = origSize; m_runtime.push_back( std::move(rt) ); } } AddSizeGrip(); SetMsgHandled(FALSE); } void CDialogResizeHelper::OnDestroy() { m_runtime.clear(); m_sizeGrip = NULL; m_thisWnd = NULL; SetMsgHandled(FALSE); } void CDialogResizeHelper::AddSizeGrip() { if (m_thisWnd != NULL && m_sizeGrip == NULL) { if (m_thisWnd.GetWindowLong(GWL_STYLE) & WS_POPUP) { m_sizeGrip = CreateWindowEx(0, WC_SCROLLBAR, _T(""), WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | SBS_SIZEGRIP | SBS_SIZEBOXBOTTOMRIGHTALIGN, 0, 0, CW_USEDEFAULT, CW_USEDEFAULT, m_thisWnd, (HMENU)0, NULL, NULL); if (m_sizeGrip != NULL) { RECT rc, rc_grip; if (m_thisWnd.GetClientRect(&rc) && m_sizeGrip.GetWindowRect(&rc_grip)) { m_sizeGrip.SetWindowPos(NULL, rc.right - (rc_grip.right - rc_grip.left), rc.bottom - (rc_grip.bottom - rc_grip.top), 0, 0, SWP_NOZORDER | SWP_NOSIZE); } } } } } void CDialogResizeHelper::InitTable(const Param* table, size_t tableSize) { m_initData.assign( table, table+tableSize ); } void CDialogResizeHelper::InitTable(const ParamOld * table, size_t tableSize) { m_initData.resize(tableSize); for (size_t walk = 0; walk < tableSize; ++walk) { const ParamOld in = table[walk]; Param entry = {}; entry.id = table[walk].id; if (in.flags & CDialogResizeHelperCompat::X_MOVE) entry.snapLeft = entry.snapRight = 1; else if (in.flags & CDialogResizeHelperCompat::X_SIZE) entry.snapRight = 1; if (in.flags & CDialogResizeHelperCompat::Y_MOVE) entry.snapTop = entry.snapBottom = 1; else if (in.flags & CDialogResizeHelperCompat::Y_SIZE) entry.snapBottom = 1; m_initData[walk] = entry; } } void CDialogResizeHelper::InitMinMax(const CRect & range) { min_x = range.left; min_y = range.top; max_x = range.right; max_y = range.bottom; } void CDialogResizeHelper::AddControl(Param const & initData, CWindow wnd) { CRect rc; if ( wnd == NULL ) { PFC_ASSERT( initData.id != 0 ); WIN32_OP_D(GetChildWindowRect(m_thisWnd, initData.id, rc)); } else { WIN32_OP_D(GetChildWindowRect2(m_thisWnd, wnd, rc)); } runtime_t rt; rt.initData = initData; rt.userHWND = wnd; rt.origRect = rc; rt.origWindowSize = this->CurrentSize(); m_runtime.push_back( std::move(rt) ); } bool CDialogResizeHelper::RemoveControl(CWindow wnd) { return pfc::remove_if_t( m_runtime, [wnd] (runtime_t const & rt) { return rt.userHWND == wnd; } ) > 0; } bool CDialogResizeHelper::HaveControl(CWindow wnd) const { for( auto i = m_runtime.begin(); i != m_runtime.end(); ++ i ) { if ( i->userHWND == wnd ) return true; } return false; }