⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 toolbarex.cpp

📁 深入剖析Visual C++编程技术及应用实例
💻 CPP
📖 第 1 页 / 共 5 页
字号:
							pControl = GetControl(m_nDragButton);
							VERIFY(pControl != 0);
							pControl->SetParent(0);
						}

						if( nDropBtn >= 0 )
							// have to insert
							wndTBCtrl.InsertButton(nDropBtn, &tbButton);
						else
							// append the button
							wndTBCtrl.AddButtons(1, &tbButton);

						// delete the button at its original location
						// we do not need to ask the owner, because this
						// was already done in "BeginDrag()"
						wndTBCtrl.DeleteButton(
							(m_nDragButton < nDropBtn || nDropBtn < 0)
								? m_nDragButton
								: m_nDragButton+1
						);

						// Reconnect the control (if any)
						if( pControl )
							pControl->SetParent(this);

						if( m_nDragButton == wndTBCtrl.GetButtonCount()-1 )
							// remove trailing separators too
							RemoveTrailingSeparators();
					}
				}
			} else {
				// move the button to a different toolbar

				wndTBCtrl.GetButton(m_nDragButton, &tbButton);
				CToolBarCtrl & wndDropTBCtrl = m_pDropBar->GetToolBarCtrl();

				if( m_pDropBar->DoQueryInsert(tbButton, (nDropBtn>=0) ? nDropBtn : wndDropTBCtrl.GetButtonCount()) ) {
					// Get the bitmap of the dragged button and resize it to
					// the image-size of the destination-bar.
					int nDestBitmap = 0;
					if( IsControl(m_nDragButton) ) {
						CRect rc;
						GetItemRect(m_nDragButton, rc);
						nDestBitmap = rc.Width();
					} else {
						HBITMAP hBmp = GetBitmap(tbButton.iBitmap, m_pDropBar->m_sizeImage);
						CBitmap bmp;
						if( hBmp ) {
							bmp.Attach(hBmp);
							nDestBitmap = wndDropTBCtrl.AddBitmap(1, &bmp);
						}
					}
					tbButton.iBitmap = nDestBitmap;
					//tbButton.iString = nDestString;
					tbButton.iString = -1;
					BOOL bInsertOK;
					if( nDropBtn >= 0 )
						bInsertOK = wndDropTBCtrl.InsertButton(nDropBtn, &tbButton);
					else
						bInsertOK = wndDropTBCtrl.AddButtons(1, &tbButton);

					if( bInsertOK ) {
						// transfer the string too, if any (check target first)
						if( m_pDropBar->HasButtonText() && HasButtonText() )
						{
							// let the CToolBar class do all the leg work
							m_pDropBar->SetButtonText(
								m_pDropBar->CommandToIndex(tbButton.idCommand),
								GetButtonText(m_nDragButton)
							);
						}
						// check whether the dragged button was a control in real life and
						// - if so - move that control to its new parent.
						CheckMoveControl(m_pDropBar, tbButton);

						wndTBCtrl.DeleteButton(m_nDragButton);

						if( m_nDragButton == wndTBCtrl.GetButtonCount()-1 )
							// remove trailing separators too
							RemoveTrailingSeparators();

						m_pDropBar->RecalcLayout();
					}
				}
			}
		} else {
			// remove the button from the toolbar
			if( bDoMove ) {
				wndTBCtrl.DeleteButton(m_nDragButton);

				if( m_nDragButton == wndTBCtrl.GetButtonCount() )
					// remove trailing separators too
					RemoveTrailingSeparators();
			} else
				// User has aborted the drag-operation.
				// Remove the drag-border from the button
				InvalidateButton(m_nDragButton);
		}

		// Recalculate the size of the bar.and the parent
		RecalcLayout();
	}

	m_bDragging = FALSE;

	// mouse capture is not longer needed
	ReleaseCapture();
}


void CToolBarEx :: CheckMoveControl( CToolBarEx * pToolBar, const TBBUTTON & tbButton ) {
	ASSERT_VALID(pToolBar);
	CWnd * pControl = GetControl(tbButton.idCommand, TRUE);
	if( pControl ) {
		// now change the parent of the control, so that it jumps to the
		// other toolbar
		pControl->SetParent(pToolBar);

		// remove the control from our list (if it's present there) and
		// add it to the target's list
		if( m_pControls ) {
			POSITION pos = m_pControls->Find(pControl);
			if(pos) {
				m_pControls->RemoveAt(pos);
				if( ! pToolBar->m_pControls )
					pToolBar->m_pControls = new CObList();
				pToolBar->m_pControls->AddTail(pControl);
			}
		}
	}
}


void CToolBarEx :: RemoveTrailingSeparators() {
	CToolBarCtrl & wndTBCtrl = GetToolBarCtrl();
	register const int nBtn = wndTBCtrl.GetButtonCount();
	register int i = nBtn;
	while( i && IsSeparator(--i) )
		if( DoQueryDelete(i) )
			wndTBCtrl.DeleteButton(i);
}

int CToolBarEx :: FindDropButton( const CPoint & point ) {
	CPoint pt = point;
	ScreenToClient(&pt);

	CRect rc;
	// find the button which is closest to the cursor
	register const int nBtn = GetToolBarCtrl().GetButtonCount();
	for( register int i = 0 ; i < nBtn ; ++i ) {
		GetItemRect(i, rc);
		if( rc.PtInRect(pt) )
			// insert the button to drop before this button:
			return (pt.x - rc.left < rc.right - pt.x)
					? i
					: ((i==nBtn-1)
						? -1
						: i+1);
	}
	
	// have to append the button
	return -1;
}

void CToolBarEx :: GetMarkerRect( int nButton, CRect & rc ) {
	register const int nBtn = GetToolBarCtrl().GetButtonCount();
	if( nButton < 0 || nButton > nBtn ) {
		// set the marker behind the last button
		GetItemRect(nBtn-1, rc);
		rc.right += 3;
		rc.left = rc.right-6;
	} else {
		// set the marker before the given button
		GetItemRect(nButton, rc);
		rc.left -= 3;
		rc.right = rc.left+6;
	}
	rc.DeflateRect(0,1);
}

void CToolBarEx :: ShowMarker( const CRect & rcMarker, CBitmap & bmpArea ) {
	ASSERT( bmpArea.GetSafeHandle() == 0 );

	CClientDC  WinDC(this);
	CDC MemDC; MemDC.CreateCompatibleDC(&WinDC);

	bmpArea.CreateCompatibleBitmap(&WinDC, rcMarker.Width(), rcMarker.Height());
	CBitmap * pOldBmp = MemDC.SelectObject(&bmpArea);

	CPen pen(PS_SOLID, 1, RGB(0,0,0));
	CPen * pOldPen = WinDC.SelectObject(&pen);

	// save original area:
	MemDC.BitBlt(0,0,rcMarker.Width(),rcMarker.Height(),
				&WinDC, rcMarker.left, rcMarker.top, SRCCOPY);

	WinDC.MoveTo(rcMarker.TopLeft());
	WinDC.LineTo(rcMarker.right, rcMarker.top);
	WinDC.MoveTo(rcMarker.left+1, rcMarker.top+1);
	WinDC.LineTo(rcMarker.right-1, rcMarker.top+1);

	WinDC.MoveTo(rcMarker.left+2, rcMarker.top+2);
	WinDC.LineTo(rcMarker.left+2, rcMarker.bottom-2);
	WinDC.MoveTo(rcMarker.left+3, rcMarker.top+2);
	WinDC.LineTo(rcMarker.left+3, rcMarker.bottom-2);

	WinDC.MoveTo(rcMarker.left, rcMarker.bottom-1);
	WinDC.LineTo(rcMarker.right, rcMarker.bottom-1);
	WinDC.MoveTo(rcMarker.left+1, rcMarker.bottom-2);
	WinDC.LineTo(rcMarker.right-1, rcMarker.bottom-2);

	MemDC.SelectObject(pOldBmp);
	MemDC.DeleteDC();
	WinDC.SelectObject(pOldPen);
}

void CToolBarEx :: RestoreMarker( const CRect & rcArea, CBitmap & bmpArea ) {
	if( bmpArea.GetSafeHandle() == 0 )
		return;

	CClientDC  WinDC(this);
	CDC MemDC; MemDC.CreateCompatibleDC(&WinDC);

	CBitmap * pOldBmp = MemDC.SelectObject(&bmpArea);
	WinDC.BitBlt(rcArea.left, rcArea.top, rcArea.Width(), rcArea.Height(),
				&MemDC, 0, 0, SRCCOPY);

	MemDC.SelectObject(pOldBmp);
	MemDC.DeleteDC();
}

void CToolBarEx :: SetMarker( CToolBarEx * pBar, const CPoint & point ) {
	static CToolBarEx * pLastToolBar = 0;
	static CRect lastRect(0,0,0,0);
	static CBitmap bmpLastSavedArea;

	CRect rcMarker;

	// retrieve proposed rectangle for the marker
	if( pBar != 0 ) {
		int nDropBtn = pBar->FindDropButton(point);
		pBar->GetMarkerRect(nDropBtn, rcMarker);

		if(rcMarker == lastRect)
			return;		// don't need to erase/draw
	}

	// restore the previously marked area:
	if( pLastToolBar ) {
		pLastToolBar->RestoreMarker(lastRect, bmpLastSavedArea);
		bmpLastSavedArea.DeleteObject();
	}

	// draw the marker
	if( pBar != 0 ) {
		pBar->ShowMarker(rcMarker, bmpLastSavedArea);
		lastRect = rcMarker;
	}
	pLastToolBar = pBar;
}

BOOL CToolBarEx :: DoQueryDelete(int nButton) {
	ASSERT(nButton >= 0);

	TBBUTTON tbButton;
	if( ! GetToolBarCtrl().GetButton(nButton, &tbButton) ) {
		TRACE1("CToolBarEx::DoQueryDelete(): could not retrieve button %d\n", nButton);
		return FALSE;
	}

	return QueryDeleteInsert(tbButton, TRUE, nButton);
}

BOOL CToolBarEx :: QueryDeleteInsert(TBBUTTON & tbButton, BOOL bDelete, int nIndex) {
	TBNOTIFY tbn;
	memset(&tbn, 0, sizeof(TBNOTIFY));
	tbn.hdr.hwndFrom = GetSafeHwnd();
	tbn.hdr.idFrom = UINT(::GetWindowLong(tbn.hdr.hwndFrom, GWL_ID));
	tbn.hdr.code = bDelete ? TBN_QUERYDELETE : TBN_QUERYINSERT;
	tbn.iItem = nIndex;
	memcpy((void *)(&tbn.tbButton), (const void *)(&tbButton), sizeof(TBBUTTON));

	CString strText;
	if( bDelete ) {
		strText = GetButtonText(nIndex);
		tbn.cchText = strText.GetLength();
		tbn.pszText = strText.GetBuffer(tbn.cchText);
	}

	ASSERT(GetParentFrame() != 0);
	ASSERT(::IsWindow(GetParentFrame()->GetSafeHwnd()));

	BOOL bRet = GetParentFrame()->SendMessage(
					WM_NOTIFY,
					WPARAM(tbn.hdr.idFrom),
					LPARAM(&tbn)
				);
	
	if( bDelete )
		strText.ReleaseBuffer();

	return bRet;
}

void CToolBarEx::OnCaptureChanged(CWnd *pWnd) 
{
	if( m_bDragging )
		// without the mouse-capture we cannot complete the drag-operation
		EndDrag(FALSE);

	CToolBar::OnCaptureChanged(pWnd);
}


BOOL CToolBarEx :: PreTranslateMessage( MSG * pMsg ) {
	if( m_bDragging &&
		(pMsg->message == WM_KEYDOWN || pMsg->message == WM_KEYUP) && 
		int(pMsg->wParam) == VK_ESCAPE ) {

		// user pressed ESC to abort drag operation
		EndDrag(FALSE);
		return TRUE;
	}
	return CToolBar::PreTranslateMessage(pMsg);
}

void CToolBarEx::OnParentNotify(UINT message, LPARAM lParam) 
{
	if( LOWORD(message) == WM_LBUTTONDOWN && (::GetAsyncKeyState(VK_MENU) & (1<<15)) ) {
		// I see no chance to abort the child's message processing.
		// That's why we set a flag here. If we lose the focus (a click
		// in a child's area will activate that child window), then
		// we start the real drag-operation (that would return the
		// focus to the toolbar).
		// This solution is somewhat obfuscated, so if you know of
		// a better way -- let me know.
		m_bDragChild = TRUE;
		SetFocus();
	}

	CToolBar::OnParentNotify(message, lParam);
}

void CToolBarEx::OnKillFocus(CWnd* pNewWnd) 
{
	CToolBar::OnKillFocus(pNewWnd);
	
	if( m_bDragChild ) {
		// See OnParentNotify() above ...
		m_bDragChild = FALSE;
		if( GetCapture() != this )
			BeginDrag();
	}
}


/////////////////////////////////////////////////////////////////////////////
// helpers for docking 
/////////////////////////////////////////////////////////////////////////////


// We need our own version of a dock bar, because the original
// MFC implementation overlapps toolbars. CToolBarEx don't want
// such a overlapping, because this makes it impossible to draw
// a real 3d border ...
class CToolDockBar : public CDockBar {
	DECLARE_DYNAMIC(CToolDockBar)

	public:
		// this is the one and only method of interest
		virtual CSize	CalcFixedLayout(BOOL bStretch, BOOL bHorz);
};

IMPLEMENT_DYNAMIC(CToolDockBar, CDockBar);

CSize CToolDockBar::CalcFixedLayout(BOOL bStretch, BOOL bHorz)
{
	ASSERT_VALID(this);

	CSize sizeFixed = CControlBar::CalcFixedLayout(bStretch, bHorz);

	// get max size
	CSize sizeMax;
	if (!m_rectLayout.IsRectEmpty())
		sizeMax = m_rectLayout.Size();
	else
	{
		CRect rectFrame;
		CFrameWnd* pFrame = GetParentFrame();
		pFrame->GetClientRect(&rectFrame);
		sizeMax = rectFrame.Size();
	}

	// prepare for layout
	AFX_SIZEPARENTPARAMS layout;
	layout.hDWP = m_bLayoutQuery ?
		NULL : ::BeginDeferWindowPos(m_arrBars.GetSize());
	int cxBorder = 2, cyBorder = 2;
	CPoint pt(-cxBorder, -cyBorder);
	int nWidth = 0;

	BOOL bWrapped = FALSE;

	// layout all the control bars
	for (int nPos = 0; nPos < m_arrBars.GetSize(); nPos++)
	{
		CControlBar* pBar = GetDockedControlBar(nPos);
		void* pVoid = m_arrBars[nPos];

		if (pBar != NULL)
		{
			if(pBar->IsKindOf(RUNTIME_CLASS(CToolBarEx)) && ((CToolBarEx*)pBar)->IsFlatLook())
				((CToolBarEx*)pBar)->m_bReal3DBorder = TRUE,
				cxBorder = cyBorder = 0;
			else if(pBar->IsKindOf(RUNTIME_CLASS(CToolBarEx)) && !((CToolBarEx*)pBar)->IsFlatLook())
				((CToolBarEx*)pBar)->m_bReal3DBorder = FALSE,
				cxBorder = cyBorder = 2;
			else
				cxBorder = cyBorder = 2;

			if (pBar->IsVisible())
			{
				// get ideal rect for bar
				DWORD dwMode = 0;
				if ((pBar->m_dwStyle & CBRS_SIZE_DYNAMIC) &&
					(pBar->m_dwStyle & CBRS_FLOATING))
					dwMode |= LM_HORZ | LM_MRUWIDTH;
				else if (pBar->m_dwStyle & CBRS_ORIENT_HORZ)
					dwMode |= LM_HORZ | LM_HORZDOCK;
				els

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -