Exemple #1
0
//////////////////
// Initialize map: set up all the next/prev pointers. This converts the
// linear array to a more convenient linked list. Called from END_WINDOW_MAP.
//
WINRECT* WINRECT::InitMap(WINRECT* pWinMap, WINRECT* parent)
{
	assert(pWinMap);

	WINRECT* pwrc = pWinMap;  // current table entry
	WINRECT* prev = NULL;	  // previous entry starts out none

	while (!pwrc->IsEndGroup()) {
		pwrc->prev=prev;
		pwrc->next=NULL;
		if (prev)
			prev->next = pwrc;
		prev = pwrc;
		if (pwrc->IsGroup()) {
			pwrc = InitMap(pwrc+1,pwrc); // recurse! Returns end-of-grp
			assert(pwrc->IsEndGroup());
		}
		pwrc++;
	}
	// safety checks
	assert(pwrc->IsEndGroup());
	assert(prev);
	assert(prev->next==NULL);
	return parent ? pwrc : NULL;
}
//////////////////
// 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
		}
	}
}
Exemple #3
0
//////////////////
// Get the parent of a given WINRECT. To find the parent, chase the prev
// pointer to the start of the list, then take the item before that in
// memory.
//
WINRECT* WINRECT::Parent()
{
	WINRECT* pEntry;
	for (pEntry=this; pEntry->Prev(); pEntry=pEntry->Prev()) {
		; // go backwards to the end
	}
	// the entry before the first child is the group
	WINRECT *parent = pEntry-1;
	assert(parent->IsGroup());
	return parent;
}
//////////////////
// 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);
}
//////////////////
// 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);
	}
}
//////////////////
// 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!
	}
}
Exemple #10
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));
}