////////////////// // Move desired rectangle by a given vector amount. // Call this when a sizer bar tells you it has moved. // void CWinMgr::MoveRect(WINRECT* pwrcMove, CPoint ptMove, CWnd* pParentWnd) { ASSERT(pwrcMove); WINRECT* prev = pwrcMove->Prev(); ASSERT(prev); WINRECT* next = pwrcMove->Next(); ASSERT(next); BOOL bIsRow = pwrcMove->Parent()->IsRowGroup(); CRect& rcNext = next->GetRect(); CRect& rcPrev = prev->GetRect(); if (bIsRow) { // a row can only be moved up or down ptMove.x = 0; rcPrev.bottom += ptMove.y; rcNext.top += ptMove.y; } else { // a column can only be moved left or right ptMove.y = 0; rcPrev.right += ptMove.x; rcNext.left += ptMove.x; } pwrcMove->GetRect() += ptMove; if (prev->IsGroup()) CalcGroup(prev, pParentWnd); if (next->IsGroup()) CalcGroup(next, pParentWnd); }
////////////////// // Move desired rectangle by a given vector amount. // Call this when a sizer bar tells you it has moved. // void CWinMgr::MoveRect(WINRECT* pwrcMove, POINT ptMove, HWND pParentWnd) { assert(pwrcMove); WINRECT* prev = pwrcMove->Prev(); assert(prev); WINRECT* next = pwrcMove->Next(); assert(next); BOOL bIsRow = pwrcMove->Parent()->IsRowGroup(); RECT& rcNext = next->GetRect(); RECT& rcPrev = prev->GetRect(); if (bIsRow) { // a row can only be moved up or down ptMove.x = 0; rcPrev.bottom += ptMove.y; rcNext.top += ptMove.y; } else { // a column can only be moved left or right ptMove.y = 0; rcPrev.right += ptMove.x; rcNext.left += ptMove.x; } OffsetRect(pwrcMove->GetRect(), ptMove); if (prev->IsGroup()) CalcGroup(prev, pParentWnd); if (next->IsGroup()) CalcGroup(next, pParentWnd); }
////////////////// // Calculate size/positions for a row or column group This is the main // algorithm. If a window is given, it's used to get the min/max size and // desired size for TOFIT types. // void CWinMgr::CalcGroup(WINRECT* pGroup, CWnd* pWnd) { // If this bombs, most likely the first entry in your map is not a group! ASSERT(pGroup && pGroup->IsGroup()); ASSERT(pWnd); // adjust total avail by margins CRect rcTotal = pGroup->GetRect(); int w,h; if (pGroup->GetMargins(w,h)) { w = min(abs(w), rcTotal.Width()/2); h = min(abs(h), rcTotal.Height()/2); rcTotal.DeflateRect(w,h); } BOOL bRow = pGroup->IsRowGroup(); // Is this a row group? // Running height or width: start with total int hwRemaining = bRow ? rcTotal.Height() : rcTotal.Width(); // First, set all rects to their minimum sizes. // This ensures that each rect gets its min size. CWinGroupIterator it; for (it=pGroup; it; it.Next()) { WINRECT* wrc = it; SIZEINFO szi; OnGetSizeInfo(szi, wrc, pWnd); int hwMin = bRow ? szi.szMin.cy : szi.szMin.cx; hwMin = min(hwMin, hwRemaining); // truncate wrc->SetHeightOrWidth(hwMin, bRow); // set hwRemaining -= hwMin; // decrement remaining height/width ASSERT(hwRemaining>=0); } // Now adjust all rects upward to desired size. Save REST rect for last. WINRECT* pRestRect = NULL; for (it=pGroup; it; it.Next()) { WINRECT* wrc = it; if (wrc->Type()==WRCT_REST) { ASSERT(pRestRect==NULL); // can only be one REST rect! pRestRect = wrc; // remember it } else { AdjustSize(wrc, bRow, hwRemaining, pWnd); } } ASSERT(hwRemaining>=0); // Adjust REST rect if any if (pRestRect) { AdjustSize(pRestRect, bRow, hwRemaining, pWnd); ASSERT(hwRemaining==0); } // All the sizes of the entries have been calculated, including // groups (but not their children). Now move all the rects so they're // adjacent to one another, without altering sizes. PositionRects(pGroup, rcTotal, bRow); // Finally, descend recursively into each subgroup. for (it=pGroup; it; it.Next()) { WINRECT* wrc = it; if (wrc->IsGroup()) CalcGroup(wrc, pWnd); // recurse! } }