void CResizableGrip::UpdateSizeGrip() { if (!::IsWindow(m_wndGrip.m_hWnd)) return; // size-grip goes bottom right in the client area // (any right-to-left adjustment should go here) RECT rect; GetResizableWnd()->GetClientRect(&rect); rect.left = rect.right - m_wndGrip.m_size.cx; rect.top = rect.bottom - m_wndGrip.m_size.cy; // must stay below other children m_wndGrip.SetWindowPos(&CWnd::wndBottom, rect.left, rect.top, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOREPOSITION | (IsSizeGripVisible() ? SWP_SHOWWINDOW : SWP_HIDEWINDOW)); }
/*! * This function saves the current property sheet active page using the base * class persist method. * @sa CResizableState::WriteState * * @param pszName String that identifies stored settings * * @return Returns @a TRUE if successful, @a FALSE otherwise */ BOOL CResizableSheetState::SavePage(LPCTSTR pszName) { // saves active page index, or the initial page if problems // cannot use GetActivePage, because it always fails CPropertySheet* pSheet = DYNAMIC_DOWNCAST(CPropertySheet, GetResizableWnd()); if (pSheet == NULL) return FALSE; int page = pSheet->m_psh.nStartPage; CTabCtrl *pTab = pSheet->GetTabControl(); if (pTab != NULL) page = pTab->GetCurSel(); if (page < 0) page = pSheet->m_psh.nStartPage; CString data, id; _itot(page, data.GetBuffer(10), 10); id = CString(pszName) + ACTIVEPAGE_ENT; return WriteState(id, data); }
BOOL CResizableGrip::CreateSizeGrip(BOOL bVisible /*= TRUE*/, BOOL bTriangular /*= TRUE*/, BOOL bTransparent /*= FALSE*/) { // create grip CRect rect(0 , 0, m_wndGrip.m_size.cx, m_wndGrip.m_size.cy); BOOL bRet = m_wndGrip.Create(WS_CHILD | WS_CLIPSIBLINGS | SBS_SIZEGRIP, rect, GetResizableWnd(), 0); if (bRet) { // set options m_wndGrip.SetTriangularShape(bTriangular); m_wndGrip.SetTransparency(bTransparent); SetSizeGripVisibility(bVisible); // update position UpdateSizeGrip(); } return bRet; }
/*! * @internal This function adds or removes a control window region * to or from the specified clipping region, according to its layout * properties. */ void CResizableLayout::ClipChildWindow(const LAYOUTINFO& layout, CRgn* pRegion) const { // obtain window position CRect rect; ::GetWindowRect(layout.hWnd, &rect); #if (_WIN32_WINNT >= 0x0501) //! @todo decide when to clip client only or non-client too (themes?) //! (leave disabled meanwhile, until I find a good solution) //! @note wizard97 with watermark bitmap and themes won't look good! // if (real_WIN32_WINNT >= 0x501) // ::SendMessage(layout.hWnd, WM_NCCALCSIZE, FALSE, (LPARAM)&rect); #endif ::MapWindowPoints(NULL, GetResizableWnd()->m_hWnd, (LPPOINT)&rect, 2); // use window region if any CRgn rgn; rgn.CreateRectRgn(0,0,0,0); switch (::GetWindowRgn(layout.hWnd, rgn)) { case COMPLEXREGION: case SIMPLEREGION: rgn.OffsetRgn(rect.TopLeft()); break; default: rgn.SetRectRgn(&rect); } // get the clipping property BOOL bClipping = layout.properties.bAskClipping ? LikesClipping(layout) : layout.properties.bCachedLikesClipping; // modify region accordingly if (bClipping) pRegion->CombineRgn(pRegion, &rgn, RGN_DIFF); else pRegion->CombineRgn(pRegion, &rgn, RGN_OR); }
/*! * @internal This function calculates the new size and position of a * control in the layout and flags for @c SetWindowPos */ void CResizableLayout::CalcNewChildPosition(const LAYOUTINFO& layout, const CRect &rectParent, CRect &rectChild, UINT& uFlags) const { CWnd* pParent = GetResizableWnd(); ::GetWindowRect(layout.hWnd, &rectChild); ::MapWindowPoints(NULL, pParent->m_hWnd, (LPPOINT)&rectChild, 2); CRect rectNew; // calculate new top-left corner rectNew.left = layout.marginTopLeft.cx + rectParent.Width() * layout.anchorTopLeft.cx / 100; rectNew.top = layout.marginTopLeft.cy + rectParent.Height() * layout.anchorTopLeft.cy / 100; // calculate new bottom-right corner rectNew.right = layout.marginBottomRight.cx + rectParent.Width() * layout.anchorBottomRight.cx / 100; rectNew.bottom = layout.marginBottomRight.cy + rectParent.Height() * layout.anchorBottomRight.cy / 100; // adjust position, if client area has been scrolled rectNew.OffsetRect(rectParent.TopLeft()); // get the refresh property BOOL bRefresh = layout.properties.bAskRefresh ? NeedsRefresh(layout, rectChild, rectNew) : layout.properties.bCachedNeedsRefresh; // set flags uFlags = SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREPOSITION; if (bRefresh) uFlags |= SWP_NOCOPYBITS; if (rectNew.TopLeft() == rectChild.TopLeft()) uFlags |= SWP_NOMOVE; if (rectNew.Size() == rectChild.Size()) uFlags |= SWP_NOSIZE; // update rect rectChild = rectNew; }
void CResizableLayout::AddAnchor(HWND hWnd, CSize sizeTypeTL, CSize sizeTypeBR) { CWnd* pParent = GetResizableWnd(); // child window must be valid ASSERT(::IsWindow(hWnd)); // must be child of parent window ASSERT(::IsChild(pParent->GetSafeHwnd(), hWnd)); // top-left anchor must be valid ASSERT(sizeTypeTL != NOANCHOR); // get control's window class CString st; GetClassName(hWnd, st.GetBufferSetLength(MAX_PATH), MAX_PATH); st.ReleaseBuffer(); st.MakeUpper(); // add the style 'clipsiblings' to a GroupBox // to avoid unnecessary repainting of controls inside if (st == "BUTTON") { DWORD style = GetWindowLong(hWnd, GWL_STYLE); if ((style & 0x0FL) == BS_GROUPBOX) SetWindowLong(hWnd, GWL_STYLE, style | WS_CLIPSIBLINGS); } // window classes that don't redraw client area correctly // when the hor scroll pos changes due to a resizing BOOL hscroll = FALSE; if (st == "LISTBOX") hscroll = TRUE; // window classes that need refresh when resized BOOL refresh = NeedsRefresh(hWnd); // get parent window's rect CRect rectParent; GetTotalClientRect(&rectParent); // and child control's rect CRect rectChild; ::GetWindowRect(hWnd, &rectChild); pParent->ScreenToClient(&rectChild); // go calculate margins CSize sizeMarginTL, sizeMarginBR; if (sizeTypeBR == NOANCHOR) sizeTypeBR = sizeTypeTL; // calculate margin for the top-left corner sizeMarginTL.cx = rectChild.left - rectParent.Width() * sizeTypeTL.cx / 100; sizeMarginTL.cy = rectChild.top - rectParent.Height() * sizeTypeTL.cy / 100; // calculate margin for the bottom-right corner sizeMarginBR.cx = rectChild.right - rectParent.Width() * sizeTypeBR.cx / 100; sizeMarginBR.cy = rectChild.bottom - rectParent.Height() * sizeTypeBR.cy / 100; // add to the list LayoutInfo layout(hWnd, sizeTypeTL, sizeMarginTL, sizeTypeBR, sizeMarginBR, hscroll, refresh); // always add to head (before callbacks) m_arrLayout.InsertAt(0, layout); }
void CResizableLayout::GetTotalClientRect(LPRECT lpRect) { GetResizableWnd()->GetClientRect(lpRect); }
void CResizableLayout::ArrangeLayout() { CWnd* pParent = GetResizableWnd(); // get parent window's rect CRect rectParent; GetTotalClientRect(&rectParent); // init some vars BOOL bCallbackPassed = FALSE; int i, count = (int)m_arrLayout.GetSize(); HDWP hdwp = BeginDeferWindowPos(count); for (i=0; i<count; ++i) { LayoutInfo layout = m_arrLayout[i]; if (layout.hWnd == NULL) // callback { if (!bCallbackPassed) // first time only { bCallbackPassed = TRUE; // update previous controls EndDeferWindowPos(hdwp); // start again for callback controls hdwp = BeginDeferWindowPos(count-i); } // callbacks are added at the end, so that // you don't have multiple screen updates if (!ArrangeLayoutCallback(layout)) // request data continue; } CRect rectChild, newrc; CWnd* pWnd = CWnd::FromHandle(layout.hWnd); // temporary solution pWnd->GetWindowRect(&rectChild); pParent->ScreenToClient(&rectChild); // calculate new top-left corner newrc.left = layout.sizeMarginTL.cx + rectParent.Width() * layout.sizeTypeTL.cx / 100; newrc.top = layout.sizeMarginTL.cy + rectParent.Height() * layout.sizeTypeTL.cy / 100; // calculate new bottom-right corner newrc.right = layout.sizeMarginBR.cx + rectParent.Width() * layout.sizeTypeBR.cx / 100; newrc.bottom = layout.sizeMarginBR.cy + rectParent.Height() * layout.sizeTypeBR.cy / 100; if (!newrc.EqualRect(&rectChild)) { if (layout.bAdjHScroll) { // needs repainting, due to horiz scrolling int diff = newrc.Width() - rectChild.Width(); int max = pWnd->GetScrollLimit(SB_HORZ); layout.bNeedRefresh = FALSE; if (max > 0 && pWnd->GetScrollPos(SB_HORZ) > max - diff) { layout.bNeedRefresh = TRUE; } } // set flags DWORD flags = SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREPOSITION; //if (layout.bNeedRefresh) // flags |= SWP_NOCOPYBITS; if (newrc.TopLeft() == rectChild.TopLeft()) flags |= SWP_NOMOVE; if (newrc.Size() == rectChild.Size()) flags |= SWP_NOSIZE; hdwp = DeferWindowPos(hdwp, layout.hWnd, NULL, newrc.left, newrc.top, newrc.Width(), newrc.Height(), flags); } } // go re-arrange child windows EndDeferWindowPos(hdwp); // refresh those that need for (i=0; i<count; ++i) { LayoutInfo& layout = m_arrLayout[i]; if (layout.bNeedRefresh) { ::RedrawWindow(layout.hWnd, NULL, NULL, RDW_INVALIDATE|RDW_NOFRAME); // ::InvalidateRect(layout.hWnd, NULL, TRUE); // ::UpdateWindow(layout.hWnd); } } }