//////////////////
// 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);
}
//////////////////
// 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);
}
//////////////////
// Position all the rects so they're as wide/high as the total and follow one
// another; ie, are adjacent. This operation leaves the height (rows) and
// width (columns) unaffected. For rows, set each row's width to rcTotal and
// one below the other; for columns, set each column as tall as rcTotal and
// each to the right of the previous.
//
void CWinMgr::PositionRects(WINRECT* pGroup, const CRect& rcTotal, BOOL bRow) {
	LONG xoryPos = bRow ? rcTotal.top : rcTotal.left;

	CWinGroupIterator it;
	for (it=pGroup; it; it.Next()) {
		WINRECT* wrc = it;
		CRect& rc = wrc->GetRect();
		if (bRow) {							 // for ROWS:
			LONG height = rc.Height();		 // height of row = total height
			rc.top    = xoryPos;				 // top = running yPos
			rc.bottom = rc.top + height;	 // ...
			rc.left   = rcTotal.left;		 // ...
			rc.right  = rcTotal.right;		 // ...
			xoryPos += height;				 // increment yPos

		} else {									 // for COLS:
			LONG width = rc.Width();		 // width = total width
			rc.left    = xoryPos;			 // left = running xPos
			rc.right   = rc.left + width;	 // ...
			rc.top     = rcTotal.top;		 // ...
			rc.bottom  = rcTotal.bottom;	 // ...
			xoryPos += width;					 // increment xPos
		}
	}
}
//////////////////
// Set each control's tofit (desired) size to current size. Useful for
// dialogs, to "remember" the current sizes as desired size.
//
void CWinMgr::InitToFitSizeFromCurrent(CWnd* pWnd) {
	ASSERT(pWnd);
	ASSERT(m_map);
	GetWindowPositions(pWnd);
	for (WINRECT* w = m_map; !w->IsEnd(); w++) {
		if (w->Type()==WRCT_TOFIT && !w->IsGroup()) {
			w->SetToFitSize(w->GetRect().Size());
		}
	}
}
//////////////////
// Set each control's tofit (desired) size to current size. Useful for
// dialogs, to "remember" the current sizes as desired size.
//
void CWinMgr::InitToFitSizeFromCurrent(HWND hWnd)
{
	assert(hWnd);
	assert(m_map);
	GetWindowPositions(hWnd);
	for (WINRECT* w = m_map; !w->IsEnd(); ++w) {
		if (w->Type()==WRCT_TOFIT && !w->IsGroup()) {
			w->SetToFitSize(RectToSize(w->GetRect()));
		}
	}
}
//////////////////
// Get size information for a single entry (WINRECT). Returns size info in
// the SIZEINFO argument. For a group, calculate size info as aggregate of
// subentries.
//
void CWinMgr::OnGetSizeInfo(SIZEINFO& szi, WINRECT* wrc, CWnd* pWnd) {
	szi.szMin = SIZEZERO;				// default min size = zero
	szi.szMax = SIZEMAX;					// default max size = infinite
	szi.szDesired = wrc->GetRect().Size();	// default desired size = current 

	if (wrc->IsGroup()) {
		// For groups, calculate min, max, desired size as aggregate of children
		szi.szDesired = SIZEZERO;
		BOOL bRow = wrc->IsRowGroup();

		CWinGroupIterator it;
		for (it=wrc; it; it.Next()) {
			WINRECT* wrc2 = it;
			SIZEINFO szi2;
			OnGetSizeInfo(szi2, wrc2, pWnd);
			if (bRow) {
				szi.szMin.cx = max(szi.szMin.cx, szi2.szMin.cx);
				szi.szMin.cy += szi2.szMin.cy;
				szi.szMax.cx = min(szi.szMax.cx, szi2.szMax.cx);
				szi.szMax.cy = min(szi.szMax.cy + szi2.szMax.cy, _INFINITY);
				szi.szDesired.cx = max(szi.szDesired.cx, szi2.szDesired.cx);
				szi.szDesired.cy += szi2.szDesired.cy;

			} else {
				szi.szMin.cx += szi2.szMin.cx;
				szi.szMin.cy = max(szi.szMin.cy, szi2.szMin.cy);
				szi.szMax.cx = min(szi.szMax.cx + szi2.szMax.cx, _INFINITY);
				szi.szMax.cy = min(szi.szMax.cy, szi2.szMax.cy);
				szi.szDesired.cx += szi2.szDesired.cx;
				szi.szDesired.cy = max(szi.szDesired.cy, szi2.szDesired.cy);
			}
		}

		// Add margins. 
		int w2,h2;
		wrc->GetMargins(w2,h2);			// get margins
		w2<<=1; h2<<=1;					// double
		szi.szMin.cx += max(0,w2);		// negative margins ==> don't include in min
		szi.szMin.cy += max(0,h2);		// ditto
		szi.szDesired.cx += abs(w2);	// for desired size, use abs vallue
		szi.szDesired.cy += abs(h2);	// ditto

	} else {
		// not a group
		WINRECT* parent = wrc->Parent();
		ASSERT(parent);
		CRect& rcParent = parent->GetRect();
		BOOL bRow = parent->IsRowGroup();
		int hw, hwMin, hwTotal, pct;

		switch (wrc->Type()) {
		case WRCT_FIXED:
			hw = hwMin = wrc->GetParam();	 // ht/wid is parameter
			if (hw<0) {							 // if fixed val is negative:
				hw = -hw;						 // use absolute val for desired..
				hwMin = 0;						 // ..and zero for minimum
			}
			if (bRow) {
				szi.szMax.cy = szi.szDesired.cy = hw;
				szi.szMin.cy = hwMin;
			} else {
				szi.szMax.cx = szi.szDesired.cx = hw;
				szi.szMin.cx = hwMin;
			}
			break;

		case WRCT_PCT:
			pct = wrc->GetParam();
			ASSERT(0<pct && pct<100);
			hwTotal = bRow ? rcParent.Height() : rcParent.Width();
			hw = (hwTotal * pct) / 100;
			szi.szDesired = bRow ? CSize(rcParent.Width(), hw) :
				CSize(hw, rcParent.Height());
			break;

		case WRCT_TOFIT:
			if (wrc->HasToFitSize()) {
				szi.szDesired = wrc->GetToFitSize();
			}
			break;

		case WRCT_REST:
			break;

		default:
			ASSERT(FALSE);
		}

		// If the entry is a window, send message to get min/max/tofit size.
		// Only set tofit size if type is TOFIT.
		//
		if (wrc->IsWindow() && pWnd) {
			CWnd* pChild = pWnd->GetDlgItem(wrc->GetID());
			if (pChild) {
				if (!pChild->IsWindowVisible() && pWnd->IsWindowVisible()) {
					// parent visible but child not ==> tofit size is zero
					// important so hidden windows use no space
					szi.szDesired = SIZEZERO;
				} else {
					szi.szAvail = rcParent.Size();
					SendGetSizeInfo(szi, pWnd, wrc->GetID());
				}
			}
		}
		szi.szDesired = maxsize(minsize(szi.szDesired,szi.szMax), szi.szMin);
	}
}
Exemple #7
0
//////////////////
// User pressed mouse: intialize and enter drag state
//
void CSizerBar::OnLButtonDown(UINT nFlags, CPoint pt)
{
	m_bDragging=TRUE;
	m_ptOriginal = m_ptPrevious = Rectify(pt);
	
	GetWindowRect(&m_rcBar); // bar location in screen coords
	
	DrawBar();					 // draw it
	SetCapture();				 // all mouse messages are MINE
	m_hwndPrevFocus = ::SetFocus(m_hWnd);  // set focus to me to get Escape key

	ASSERT(m_pWinMgr);
	CWinMgr& wm = *m_pWinMgr;

	// get WINRECTs on either side of me
	WINRECT* pwrcSizeBar = wm.FindRect(GetDlgCtrlID());
	ASSERT(pwrcSizeBar);
	WINRECT* prev = pwrcSizeBar->Prev();
	ASSERT(prev);
	WINRECT* next = pwrcSizeBar->Next();
	ASSERT(next);

	// get rectangles on eithr side of me
	CRect rcPrev = prev->GetRect();
	CRect rcNext = next->GetRect();

	// get parent window
	CWnd * pParentWnd = GetParent();
	ASSERT(pParentWnd);

	// Get size info for next/prev rectangles, so I know what the min/max
	// sizes are and don't violate them. Max size never tested.
	SIZEINFO szi;
	wm.OnGetSizeInfo(szi, prev, pParentWnd);
	CRect rcPrevMin(rcPrev.TopLeft(),szi.szMin);
	CRect rcPrevMax(rcPrev.TopLeft(),szi.szMax);

	wm.OnGetSizeInfo(szi, next, pParentWnd);
	CRect rcNextMin(rcNext.BottomRight()-szi.szMin, rcNext.BottomRight());
	CRect rcNextMax(rcNext.BottomRight()-szi.szMax, rcNext.BottomRight());

	// Initialize m_rcConstrain. This is the box the user is allowed to move
	// the sizer bar in. Can't go outside of this--would violate min/max
	// constraints of windows on either side.
	m_rcConstrain.SetRect(
		max(rcPrevMin.right, rcNextMax.left),
		max(rcPrevMin.bottom,rcNextMax.top),
		min(rcPrevMax.right, rcNextMin.left),
		min(rcPrevMax.bottom,rcNextMin.top));

	// convert to my client coords
	pParentWnd->ClientToScreen(&m_rcConstrain);
	ScreenToClient(&m_rcConstrain);

	// Now adjust m_rcConstrain for the fact the bar is not a pure line, but
	// has solid width -- so I have to make a little bigger/smaller according
	// to the offset of mouse coords within the sizer bar rect iteself.
	ClientToScreen(&pt);
	m_rcConstrain.SetRect(m_rcConstrain.TopLeft() + (pt - m_rcBar.TopLeft()),
		m_rcConstrain.BottomRight() - (m_rcBar.BottomRight()-pt));
}