📄 toolbarex.cpp
字号:
CClientDC cdc(this);
CDC dcOld, dcNew;
dcOld.CreateCompatibleDC(&cdc);
dcNew.CreateCompatibleDC(&cdc);
HGDIOBJ hOldBmp = ::SelectObject(dcOld.GetSafeHdc(), m_hbmImageWell);
// create the new bitmap and make it big enough to
// hold all images (old+new)
CBitmap bmpNew;
bmpNew.CreateCompatibleBitmap(
&cdc,
bitmap.bmWidth + nButtons * m_sizeImage.cx,
m_sizeImage.cy);
CBitmap * pbmpNew = dcNew.SelectObject(&bmpNew);
dcNew.BitBlt(0,0,bitmap.bmWidth,bitmap.bmHeight,&dcOld,0,0,SRCCOPY);
::SelectObject(dcOld.GetSafeHdc(), hBitmap);
dcNew.BitBlt(bitmap.bmWidth,0,m_sizeImage.cx*nButtons,bitmap.bmHeight,&dcOld,0,0,SRCCOPY);
::SelectObject(dcOld.GetSafeHdc(), hOldBmp);
dcNew.SelectObject(pbmpNew);
dcOld.DeleteDC();
dcNew.DeleteDC();
VERIFY(bmpNew.GetObject(sizeof(BITMAP), &bitmap));
HRESULT hRes = DefWindowProc(TB_ADDBITMAP, wParam, lParam);
// syncronize toolbarcontrol's bitmap with our's
AddReplaceBitmap(HBITMAP(bmpNew.Detach()));
return HRESULT(nImageCount);
}
return DefWindowProc(TB_ADDBITMAP, wParam, lParam);
}
// intercept TB_DELETEBUTTON, so we can delete controls too.
LRESULT CToolBarEx::OnDeleteButton(WPARAM wParam, LPARAM lParam) {
CWnd * pControl = GetControl(int(wParam));
if( pControl ) {
// this is the control associated with the button to delete
BOOL bMustDelete = FALSE;
if( m_pControls ) {
// It is really a good idea to add a control via the
// CToolBarEx own members. This will guarantee that
// all resources are freed.
POSITION pos = m_pControls->Find(pControl);
if( pos ) {
m_pControls->RemoveAt(pos);
bMustDelete = TRUE;
}
}
pControl->DestroyWindow();
if( bMustDelete )
delete pControl;
}
return DefWindowProc(TB_DELETEBUTTON, wParam, lParam);
}
#ifdef _MEMDC_H_
BOOL CToolBarEx::OnEraseBkgnd(CDC* pDC)
{
return IsFlatLook() ? FALSE : CToolBar::OnEraseBkgnd(pDC);
}
#endif
/////////////////////////////////////////////////////////////////////////////
// ALT-drag
// To keep the users of CToolBarEx from inserting cursor-resources, we
// create the cursors on the fly. This makes usage of CToolBarEx as easy as
// possible:
static const BYTE ANDmaskDrop[] = {
0xFF, 0xFF, 0xFF, 0xFF, // line 1
0xFF, 0xFF, 0xFF, 0xFF, // line 2
0xF3, 0xFF, 0xFF, 0xFF, // line 3
0xF1, 0xFF, 0xFF, 0xFF, // line 4
0xF0, 0xFF, 0xFF, 0xFF, // line 5
0xF0, 0x7F, 0xFF, 0xFF, // line 6
0xF0, 0x3F, 0xFF, 0xFF, // line 7
0xF0, 0x1F, 0xFF, 0xFF, // line 8
0xF0, 0x0F, 0xFF, 0xFF, // line 9
0xF0, 0x07, 0xFF, 0xFF, // line 10
0xF0, 0x03, 0xFF, 0xFF, // line 11
0xF0, 0x01, 0xFF, 0xFF, // line 12
0xF0, 0x00, 0xFF, 0xFF, // line 13
0xF0, 0x0F, 0xFF, 0xFF, // line 14
0xF0, 0x0F, 0xFF, 0xFF, // line 15
0xF1, 0x07, 0xFF, 0xFF, // line 16
0xF3, 0x07, 0xFF, 0xFF, // line 17
0xF6, 0x00, 0x00, 0x3F, // line 18
0xFE, 0x00, 0x00, 0x3F, // line 19
0xFE, 0x00, 0x00, 0x3F, // line 20
0xFE, 0x00, 0x00, 0x3F, // line 21
0xFE, 0x00, 0x00, 0x3F, // line 22
0xFE, 0x00, 0x00, 0x3F, // line 23
0xFE, 0x00, 0x00, 0x3F, // line 24
0xFE, 0x00, 0x00, 0x3F, // line 25
0xFE, 0x00, 0x00, 0x3F, // line 26
0xFF, 0xFF, 0xFF, 0xFF, // line 27
0xFF, 0xFF, 0xFF, 0xFF, // line 28
0xFF, 0xFF, 0xFF, 0xFF, // line 29
0xFF, 0xFF, 0xFF, 0xFF, // line 30
0xFF, 0xFF, 0xFF, 0xFF, // line 31
0xFF, 0xFF, 0xFF, 0xFF // line 32
};
static const BYTE XORmaskDrop[] = {
0x00, 0x00, 0x00, 0x00, // line 1
0x00, 0x00, 0x00, 0x00, // line 2
0x00, 0x00, 0x00, 0x00, // line 3
0x04, 0x00, 0x00, 0x00, // line 4
0x06, 0x00, 0x00, 0x00, // line 5
0x07, 0x00, 0x00, 0x00, // line 6
0x07, 0x80, 0x00, 0x00, // line 7
0x07, 0xC0, 0x00, 0x00, // line 8
0x07, 0xE0, 0x00, 0x00, // line 9
0x07, 0xF0, 0x00, 0x00, // line 10
0x07, 0xF8, 0x00, 0x00, // line 11
0x07, 0xFC, 0x00, 0x00, // line 12
0x07, 0xE0, 0x00, 0x00, // line 13
0x07, 0x60, 0x00, 0x00, // line 14
0x06, 0x60, 0x00, 0x00, // line 15
0x04, 0x30, 0x00, 0x00, // line 16
0x00, 0x30, 0x00, 0x00, // line 17
0x00, 0x18, 0x00, 0x00, // line 18
0x00, 0xDD, 0xFF, 0x00, // line 19
0x00, 0xAC, 0xAA, 0x00, // line 20
0x00, 0xCD, 0x55, 0x00, // line 21
0x00, 0xA0, 0xAA, 0x00, // line 22
0x00, 0xD5, 0x55, 0x00, // line 23
0x00, 0xAA, 0xAA, 0x00, // line 24
0x00, 0x00, 0x00, 0x00, // line 25
0x00, 0x00, 0x00, 0x00, // line 26
0x00, 0x00, 0x00, 0x00, // line 27
0x00, 0x00, 0x00, 0x00, // line 28
0x00, 0x00, 0x00, 0x00, // line 29
0x00, 0x00, 0x00, 0x00, // line 30
0x00, 0x00, 0x00, 0x00, // line 31
0x00, 0x00, 0x00, 0x00 // line 32
};
static const BYTE ANDmaskNoDrop[] = {
0xFF, 0xFF, 0xFF, 0xFF, // line 1
0xFF, 0xFF, 0xFF, 0xFF, // line 2
0xF3, 0xFF, 0xFF, 0xFF, // line 3
0xF1, 0xFF, 0xFF, 0xFF, // line 4
0xF0, 0xFF, 0xFF, 0xFF, // line 5
0xF0, 0x7F, 0xFF, 0xFF, // line 6
0xF0, 0x3F, 0xFF, 0xFF, // line 7
0xF0, 0x1F, 0xFF, 0xFF, // line 8
0xF0, 0x0F, 0xFF, 0xFF, // line 9
0xF0, 0x07, 0xFF, 0xFF, // line 10
0xF0, 0x03, 0xFF, 0xFF, // line 11
0xF0, 0x01, 0xFF, 0xFF, // line 12
0xF0, 0x00, 0xFF, 0xFF, // line 13
0xF0, 0x0F, 0xFF, 0xFF, // line 14
0xF0, 0x0F, 0xFF, 0xFF, // line 15
0xF1, 0x07, 0xFF, 0xFF, // line 16
0xF3, 0x07, 0xFF, 0xFF, // line 17
0xF6, 0x00, 0x00, 0x3F, // line 18
0xFE, 0x00, 0x00, 0x3F, // line 19
0xFE, 0x00, 0x00, 0x3F, // line 20
0xFE, 0x00, 0x00, 0x3F, // line 21
0xFE, 0x00, 0x00, 0x0F, // line 22
0xFE, 0x00, 0x00, 0x0F, // line 23
0xFE, 0x00, 0x00, 0x0F, // line 24
0xFE, 0x00, 0x00, 0x0F, // line 25
0xFE, 0x00, 0x00, 0x0F, // line 26
0xFF, 0xFF, 0x80, 0x0F, // line 27
0xFF, 0xFF, 0x80, 0x0F, // line 28
0xFF, 0xFF, 0x80, 0x0F, // line 29
0xFF, 0xFF, 0x80, 0x0F, // line 30
0xFF, 0xFF, 0x80, 0x0F, // line 31
0xFF, 0xFF, 0x80, 0x0F // line 32
};
static const BYTE XORmaskNoDrop[] = {
0x00, 0x00, 0x00, 0x00, // line 1
0x00, 0x00, 0x00, 0x00, // line 2
0x00, 0x00, 0x00, 0x00, // line 3
0x04, 0x00, 0x00, 0x00, // line 4
0x06, 0x00, 0x00, 0x00, // line 5
0x07, 0x00, 0x00, 0x00, // line 6
0x07, 0x80, 0x00, 0x00, // line 7
0x07, 0xC0, 0x00, 0x00, // line 8
0x07, 0xE0, 0x00, 0x00, // line 9
0x07, 0xF0, 0x00, 0x00, // line 10
0x07, 0xF8, 0x00, 0x00, // line 11
0x07, 0xFC, 0x00, 0x00, // line 12
0x07, 0xE0, 0x00, 0x00, // line 13
0x07, 0x60, 0x00, 0x00, // line 14
0x06, 0x60, 0x00, 0x00, // line 15
0x04, 0x30, 0x00, 0x00, // line 16
0x00, 0x30, 0x00, 0x00, // line 17
0x00, 0x18, 0x00, 0x00, // line 18
0x00, 0xDD, 0xFF, 0x00, // line 19
0x00, 0xAC, 0xAA, 0x00, // line 20
0x00, 0xCD, 0x55, 0x00, // line 21
0x00, 0xA0, 0x80, 0x00, // line 22
0x00, 0xD5, 0x3F, 0xE0, // line 23
0x00, 0xAA, 0xA7, 0x20, // line 24
0x00, 0x00, 0x22, 0x20, // line 25
0x00, 0x00, 0x30, 0x60, // line 26
0x00, 0x00, 0x38, 0xE0, // line 27
0x00, 0x00, 0x30, 0x60, // line 28
0x00, 0x00, 0x22, 0x20, // line 29
0x00, 0x00, 0x27, 0x20, // line 30
0x00, 0x00, 0x3F, 0xE0, // line 31
0x00, 0x00, 0x00, 0x00 // line 32
};
void CToolBarEx::OnLButtonDown(UINT nFlags, CPoint point)
{
if( ::GetAsyncKeyState(VK_MENU) & (1<<15) )
// one of the ALT keys is pressed too - begin drag operation
if( BeginDrag() )
return;
if( ::GetAsyncKeyState(VK_SHIFT) & (1<<15) )
// disable the old-style drag
return;
CToolBar::OnLButtonDown(nFlags, point);
}
void CToolBarEx::OnLButtonUp(UINT nFlags, CPoint point)
{
if( m_bDragging )
EndDrag();
else
CToolBar::OnLButtonUp(nFlags, point);
}
BOOL CToolBarEx :: BeginDrag() {
TRACE0("beginning drag operation\n");
VERIFY(!m_hDragCursor);
VERIFY(!m_hNoDragCursor);
if( !(::GetWindowLong(GetToolBarCtrl().GetSafeHwnd(),GWL_STYLE) & CCS_ADJUSTABLE) )
return FALSE; // Bar is not adjustable
register const int nBtn = GetToolBarCtrl().GetButtonCount();
const int nLastBtn = m_nLastBtn;
m_nLastBtn = -1;
CPoint pt;
::GetCursorPos(&pt);
ScreenToClient(&pt);
m_nDragButton = -1;
// have a look for whether 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;
}
BOOL CToolBarEx :: IsValidDropTarget(const CWnd * pWnd) const {
return (pWnd &&
pWnd->IsKindOf(RUNTIME_CLASS(CToolBarEx)) &&
(::GetWindowLong(((CToolBarEx*)pWnd)->GetToolBarCtrl()
.GetSafeHwnd(),GWL_STYLE) & CCS_ADJUSTABLE) &&
((const CToolBarEx*)pWnd)->GetParentFrame() == GetParentFrame())
? TRUE : FALSE;
}
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 = IsValidDropTarget(pWnd);
// If the window under the cursor is not a toolbar, then
// check whether this window is a child of a toolbar.
while( ! bToolBar && (pWnd = pWnd->GetParent()) != 0 )
bToolBar = IsValidDropTarget(pWnd);
// check whether 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.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -