void CResizableLayout::ArrangeLayout() { // common vars UINT uFlags; LayoutInfo layout; CRect rectParent, rectChild; GetTotalClientRect(&rectParent); // get parent window's rect int count = m_listLayout.GetCount(); int countCB = m_listLayoutCB.GetCount(); // reposition child windows HDWP hdwp = ::BeginDeferWindowPos(count + countCB); POSITION pos = m_listLayout.GetHeadPosition(); while (pos != NULL) { // get layout info layout = m_listLayout.GetNext(pos); // calculate new child's position, size and flags for SetWindowPos CalcNewChildPosition(layout, rectParent, rectChild, uFlags); // only if size or position changed if ((uFlags & (SWP_NOMOVE|SWP_NOSIZE)) != (SWP_NOMOVE|SWP_NOSIZE)) { hdwp = ::DeferWindowPos(hdwp, layout.hWnd, NULL, rectChild.left, rectChild.top, rectChild.Width(), rectChild.Height(), uFlags); } } // for callback items you may use GetAnchorPosition to know the // new position and size of a non-callback item after resizing pos = m_listLayoutCB.GetHeadPosition(); while (pos != NULL) { // get layout info layout = m_listLayoutCB.GetNext(pos); // request layout data if (!ArrangeLayoutCallback(layout)) continue; // calculate new child's position, size and flags for SetWindowPos CalcNewChildPosition(layout, rectParent, rectChild, uFlags); // only if size or position changed if ((uFlags & (SWP_NOMOVE|SWP_NOSIZE)) != (SWP_NOMOVE|SWP_NOSIZE)) { hdwp = ::DeferWindowPos(hdwp, layout.hWnd, NULL, rectChild.left, rectChild.top, rectChild.Width(), rectChild.Height(), uFlags); } } // finally move all the windows at once ::EndDeferWindowPos(hdwp); }
/*! * This function retrieves the clipping region for the current layout. * It can be used to draw directly inside the region, without applying * clipping as the ClipChildren function does. * * @param pRegion Pointer to a CRegion object that holds the * calculated clipping region upon return * * @deprecated For anti-flickering ClipChildren should be preferred * as it is more complete for platform compatibility. * It will probably become a private function. */ void CResizableLayout::GetClippingRegion(CRgn* pRegion) const { CWnd* pWnd = GetResizableWnd(); // System's default clipping area is screen's size, // not enough for max track size, for example: // if screen is 1024 x 768 and resizing border is 4 pixels, // maximized size is 1024+4*2=1032 x 768+4*2=776, // but max track size is 4 pixels bigger 1036 x 780 (don't ask me why!) // So, if you resize the window to maximum size, the last 4 pixels // are clipped out by the default clipping region, that gets created // as soon as you call clipping functions (my guess). // reset clipping region to the whole client area CRect rect; pWnd->GetClientRect(&rect); pRegion->CreateRectRgnIndirect(&rect); // clip only anchored controls LAYOUTINFO layout; POSITION pos = m_listLayout.GetHeadPosition(); while (pos != NULL) { // get layout info layout = m_listLayout.GetNext(pos); if (::IsWindowVisible(layout.hWnd)) ClipChildWindow(layout, pRegion); } pos = m_listLayoutCB.GetHeadPosition(); while (pos != NULL) { // get layout info layout = m_listLayoutCB.GetNext(pos); // request data if (!ArrangeLayoutCallback(layout)) continue; if (::IsWindowVisible(layout.hWnd)) ClipChildWindow(layout, pRegion); } //! @todo Has XP changed this??? It doesn't seem correct anymore! /* // fix for RTL layouts (1 pixel of horz offset) if (pWnd->GetExStyle() & WS_EX_LAYOUTRTL) pRegion->OffsetRgn(-1,0); */ }
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); } } }