📄 toolbarex.cpp
字号:
// have a look for wether the button is valid and
// - if so - draw a dragging border around it.
for( register int i = 0 ; i < nBtn ; ++i ) {
if( IsSeparator(i) )
continue; // real separators are not draggable
CRect rc;
GetItemRect(i, rc);
const BOOL bHasCursor = rc.PtInRect(pt);
if( bHasCursor ) {
// OK we've found the button. Now ask for deletion:
if( ! DoQueryDelete(i) )
// the app does not allow the removal ...
return FALSE;
m_nDragButton = i;
CClientDC cdc(this);
cdc.DrawDragRect(rc, CSize(2,2),0,CSize(0,0));
break;
}
}
if( m_nDragButton < 0 )
return FALSE; // nothing to drag ...
VERIFY(m_hDragCursor = ::CreateCursor(0, 4, 2, 32, 32, ANDmaskDrop, XORmaskDrop));
VERIFY(m_hNoDragCursor = ::CreateCursor(0, 4, 2, 32, 32, ANDmaskNoDrop, XORmaskNoDrop));
// capture the mouse during the drag operation
SetCapture();
// make sure we receive keyboard-input
SetFocus();
m_hOrigCursor = ::SetCursor(m_hDragCursor);
m_bDragCursor = TRUE;
m_bDragging = TRUE;
::GetCursorPos(&pt);
SetMarker(m_pDropBar=this, m_ptDrop=pt);
return m_bDragging;
}
void CToolBarEx :: DragMove() {
//TRACE0("dragmove in progress\n");
CPoint pt;
::GetCursorPos(&pt);
const CWnd * pWnd = WindowFromPoint(pt);
// is the cursor moving over an adjustable toolbar ?
BOOL bToolBar = (pWnd &&
pWnd->IsKindOf(RUNTIME_CLASS(CToolBarEx)) &&
(::GetWindowLong(((CToolBarEx*)pWnd)->GetToolBarCtrl()
.GetSafeHwnd(),GWL_STYLE) & CCS_ADJUSTABLE))
? TRUE : FALSE;
// If the window under the cursor is not a toolbar, then
// check wether this window is a child of a toolbar.
while( ! bToolBar && (pWnd = pWnd->GetParent()) != 0 )
bToolBar = (pWnd->IsKindOf(RUNTIME_CLASS(CToolBarEx)) &&
(::GetWindowLong(((CToolBarEx*)pWnd)->GetToolBarCtrl()
.GetSafeHwnd(),GWL_STYLE) & CCS_ADJUSTABLE))
? TRUE : FALSE;
// check wether we have to switch the cursor
if( bToolBar && ! m_bDragCursor ) {
::SetCursor(m_hDragCursor);
m_bDragCursor = TRUE;
} else if( ! bToolBar && m_bDragCursor ) {
::SetCursor(m_hNoDragCursor);
m_bDragCursor = FALSE;
}
SetMarker(m_pDropBar = (bToolBar ? (CToolBarEx*)pWnd : 0), m_ptDrop = pt);
}
void CToolBarEx :: EndDrag(BOOL bDoMove) {
TRACE0("ending drag operation\n");
// remove the marker
SetMarker(0, CPoint(0,0));
VERIFY(::SetCursor(m_hOrigCursor));
::DestroyCursor(m_hDragCursor);
::DestroyCursor(m_hNoDragCursor);
m_hDragCursor = 0;
m_hNoDragCursor = 0;
if( m_nDragButton >= 0 ) {
CToolBarCtrl & wndTBCtrl = GetToolBarCtrl();
register const int nBtn = wndTBCtrl.GetButtonCount();
if( m_bDragCursor && bDoMove ) {
// move the button to a different location
// make sure the last "DragMove()" has done its work correctly:
ASSERT(m_pDropBar != 0);
ASSERT_KINDOF(CToolBarEx, m_pDropBar);
ASSERT(::GetWindowLong(m_pDropBar->GetToolBarCtrl()
.GetSafeHwnd(),GWL_STYLE) & CCS_ADJUSTABLE);
// have a look for where to drop the button
int nDropBtn = m_pDropBar->FindDropButton(m_ptDrop);
TBBUTTON tbButton;
memset(&tbButton, 0, sizeof(TBBUTTON)); // not the safest, but the easiest way
// to zero out all members ;-)
if( m_pDropBar == this ) {
// move the button around, but stay on *this* toolbar
if( nDropBtn == m_nDragButton+1 || (nDropBtn < 0 && m_nDragButton == nBtn-1) ) {
// simply insert a separator before the dragged button,
// if there is still none
if( m_nDragButton > 0 && !IsSeparator(m_nDragButton-1) ) {
tbButton.iBitmap = 8;
tbButton.fsState = TBSTATE_ENABLED;
tbButton.fsStyle = TBSTYLE_SEP;
if( DoQueryInsert(tbButton, m_nDragButton) )
wndTBCtrl.InsertButton(m_nDragButton, &tbButton);
}
} else if( nDropBtn == m_nDragButton && m_nDragButton > 0 ) {
// Remove the separator immediately before the dragged button.
// if there is no such separator, then do nothing
if( IsSeparator(nDropBtn-1) )
if( DoQueryDelete(nDropBtn-1) )
wndTBCtrl.DeleteButton(nDropBtn-1);
} else {
wndTBCtrl.GetButton(m_nDragButton, &tbButton);
if( DoQueryInsert(tbButton, (nDropBtn>=0) ? nDropBtn : nBtn) ) {
CWnd * pControl = 0;
if( IsControl(m_nDragButton) ) {
// Beware: The TB_DELETEBUTTON message causes the toolbar
// to destroy the associated control.
// To avoid this we temporary set the parent of the
// control to NULL.
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 wether 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();
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -