📄 docktabpane.h
字号:
#ifndef __DOCKTAB_PANE_H__
#define __DOCKTAB_PANE_H__
#ifndef __ATLWIN_H__
#error DockTabSplitPane.h requires atlwin.h to be included first
#endif
#ifndef __ATLSPLIT_H__
#error DockTabSplitPane.h requires atlsplit.h to be included first
#endif
#ifndef __ATLCOLL_H__
#error DockTabSplitPane.h requires atlcoll.h to be included first
#endif
#ifndef __CUSTOMTABCTRL_H__
#error DockTabSplitPane.h requires CustomTabCtrl.h to be included first
#endif
#ifndef __DOTNET_TABCTRL_H__
#error DockTabSplitPane.h requires DotNetTabCtrl.h to be included first
#endif
/*********************************************************************
DockSplitTab::TabControl and
DockSplitTab::TabPane classes implementation
Written by Igor Katrayev.
Copyright (c) 2003 Igor Katrayev.
This code may be used in compiled form in any way you desire. This
file may be redistributed unmodified by any means PROVIDING it is
not sold for profit without the authors written consent, and
providing that this notice and the authors name is included.
This code is also based of work done by Bjarke Viksoe (bjarke@viksoe.dk)
and Daniel Bowen (dbowen@es.com).
This file is provided "as is" with no expressed or implied warranty.
The author accepts no liability if it causes any damage to you or your
computer whatsoever. It's free, so don't hassle me about it.
Beware of bugs.
**********************************************************************/
namespace DockSplitTab {
class CallBackListener {
public:
// client notification
virtual void clientActivate( HWND childWnd, HWND clientViewWnd) = 0;
virtual void clientDblClick( HWND childWnd, HWND clientViewWnd) = 0;
virtual void clientCloseClick( HWND childWnd, HWND clientViewWnd) = 0;
// drag and drop notifications
virtual void dragStart( HWND childWnd, HWND clientViewWnd, long x, long y, DWORD keysPressed) = 0;
virtual void dragOver( HWND childWnd, HWND clientViewWnd, long x, long y, DWORD keysPressed) = 0;
virtual void dragDrop( HWND childWnd, HWND clientViewWnd, long x, long y, DWORD keysPressed) = 0;
virtual void dragCancel( HWND childWnd, HWND clientViewWnd) = 0;
//
void trackDragAndDrop( HWND hWnd, POINT startPoint, bool lockWindowUpdate = false) {
ATLASSERT( NULL != this);
ATLASSERT( ::IsWindow( hWnd));
if ( !::DragDetect( hWnd, startPoint))
return;
// tracker drawing conflicts with dock pane drawing
// disable drawing in the window during drag and drop operations.
if ( lockWindowUpdate)
::LockWindowUpdate( hWnd);
MSG msg;
bool dragging = false;
::SetCapture( hWnd);
while( ( ::GetCapture()==hWnd) && ( ::GetMessage( &msg, NULL, 0, 0))) {
CPoint hitPoint = CPoint( GET_X_LPARAM( msg.lParam), GET_Y_LPARAM( msg.lParam));
::ClientToScreen( hWnd, &hitPoint);
switch( msg.message) {
case WM_MOUSEMOVE:
if ( !dragging) {
dragging = true;
this->dragStart( hWnd, NULL, hitPoint.x, hitPoint.y, static_cast<DWORD>(msg.wParam));
}
this->dragOver( hWnd, NULL, hitPoint.x, hitPoint.y, static_cast<DWORD>(msg.wParam));
break;
case WM_LBUTTONUP:
if ( dragging) {
dragging = false;
this->dragDrop( hWnd, NULL, hitPoint.x, hitPoint.y, static_cast<DWORD>(msg.wParam));
}
::ReleaseCapture();
break;
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
switch ( msg.wParam) {
case VK_CONTROL:
case VK_SHIFT:
break;
default:
if ( dragging) {
dragging = false;
this->dragCancel( hWnd, NULL);
}
::ReleaseCapture();
}
default:
::TranslateMessage(&msg);
::DispatchMessage( &msg);
}
}
// tidy up
if ( dragging)
this->dragCancel( hWnd, NULL);
if ( lockWindowUpdate)
::LockWindowUpdate( NULL);
return;
}
}; // interface CallBackListenerr
class TabControlItem: public CCustomTabItem {
public:
TabControlItem()
: CCustomTabItem()
, clientViewWnd( NULL)
{}
HWND clientViewWnd;
};
class TabControl: public CDotNetTabCtrlImpl< TabControl, TabControlItem> {
// protected class members
protected:
typedef CDotNetTabCtrlImpl< TabControl, TabControlItem> baseClass;
CallBackListener* cbListener;
int height;
public:
TabControl( CallBackListener* listener)
: CDotNetTabCtrlImpl<TabControl, TabControlItem>()
, cbListener( listener)
, height( 0)
{}
// Methods
void create( HWND parentWnd, bool tabOnTop = false) {
DWORD style = TCS_FOCUSNEVER | WS_VISIBLE | WS_CHILD;//| TCS_FLATBUTTONS | TCS_BUTTONS
style = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | CTCS_SCROLL | CTCS_CLOSEBUTTON | CTCS_FLATEDGE | CTCS_BOLDSELECTEDTAB | CTCS_TOOLTIPS;
if ( !tabOnTop)
style |= CTCS_BOTTOM;
DWORD exStyle = TCS_EX_REGISTERDROP; //| TCS_EX_FLATSEPARATORS
this->Create( parentWnd, rcDefault, NULL, style, exStyle);
this->SetDlgCtrlID(0);
// calculate tab height
const int nNominalHeight = 24;
const int nNominalFontLogicalUnits = 11; // 8 point Tahoma with 96 DPI
// Initialize nFontLogicalUnits to the typical case
// appropriate for CDotNetTabCtrl
LOGFONT lfIcon = { 0 };
::SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(lfIcon), &lfIcon, 0);
int nFontLogicalUnits = -lfIcon.lfHeight;
// Use the actual font of the tab control
if( this->IsWindow()) {
HFONT hFont = this->GetFont();
if ( hFont != NULL) {
CDC dc = this->GetDC();
CFontHandle hFontOld = dc.SelectFont(hFont);
TEXTMETRIC tm = {0};
dc.GetTextMetrics(&tm);
nFontLogicalUnits = tm.tmAscent;
dc.SelectFont(hFontOld);
}
}
this->height = nNominalHeight + ( ::MulDiv(nNominalHeight, nFontLogicalUnits, nNominalFontLogicalUnits) - nNominalHeight ) / 2;
}
int getHeight() {
return this->height;
}
HWND getWND( int index) const {
ATLASSERT( 0 <= index && index < this->GetItemCount());
return this->GetItem( index)->clientViewWnd;
}
int getIndex( HWND win) const {
for ( int i=0; i<this->GetItemCount(); i++)
if ( this->GetItem( i)->clientViewWnd == win)
return i;
return -1;
}
bool removeTab( HWND clientViewWnd) {
int index = this->getIndex( clientViewWnd);
if ( index == -1)
return false;
return this->DeleteItem( index) == TRUE;
}
bool removeTab( int index) {
ATLASSERT( 0 <= index && index < this->GetItemCount());
return this->DeleteItem( index) == TRUE;
}
int getCurrentTab() const {
return this->GetCurSel();
}
int setCurrentTab( int index) {
ATLASSERT( 0 <= index && index < this->GetItemCount());
int result = this->SetCurSel( index);
if ( result > -1 && index != result)
::ShowWindow( this->getWND( result), FALSE);
return result;
}
// Message map handlers
DECLARE_WND_CLASS(_T("DockTab::TabControl"))
BEGIN_MSG_MAP( TabControl)
MESSAGE_HANDLER( WM_CREATE, OnCreate)
MESSAGE_HANDLER( WM_CONTEXTMENU, OnContextMenu)
MESSAGE_HANDLER( WM_LBUTTONDOWN, OnLButtonDown)
// MESSAGE_HANDLER( WM_LBUTTONDBLCLK, OnLDoubleClick)
MESSAGE_HANDLER( WM_MOUSEACTIVATE, OnMouseActivate)
// MESSAGE_HANDLER( WM_MOUSEMOVE, OnMouseMove)
CHAIN_MSG_MAP( baseClass)
END_MSG_MAP()
LRESULT OnMouseActivate( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) {
LRESULT result;
baseClass::ProcessWindowMessage( this->m_hWnd, uMsg, wParam, lParam, result);
if ( MA_ACTIVATE == result || MA_ACTIVATEANDEAT == result)
this->SetFocus();
return result;
}
LRESULT OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) {
CPoint hitPoint( GET_X_LPARAM( lParam), GET_Y_LPARAM( lParam));
this->ScreenToClient( &hitPoint);
CTCHITTESTINFO hci;
hci.pt.x = hitPoint.x;
hci.pt.y = hitPoint.y;
hci.flags = TCHT_ONITEM;
int tabItemTarget = this->HitTest( &hci);
if ( tabItemTarget > -1) {
this->SetCurSel( tabItemTarget);
::SendMessage( this->getWND( tabItemTarget)
, WM_CONTEXTMENU
, wParam
, lParam
);
}
return 0;
}
LRESULT OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) {
// process with the default handler. select a 駂osen item
LRESULT result;
baseClass::ProcessWindowMessage( this->m_hWnd, uMsg, wParam, lParam, result);
//CRect clientRect;
//this->GetClientRect( clientRect);
//CRect closeButtonRect = clientRect;
//CRect scrollButtonRect = clientRect;
//CRect nonClientRect = clientRect;
//this->CalcSize_CloseButton( closeButtonRect);
//this->CalcSize_ScrollButtons( scrollButtonRect);
//this->CalcSize_NonClient( nonClientRect);
CRect itemRect;
int tabItem = this->GetCurSel();
CPoint startHitPoint( GET_X_LPARAM( lParam), GET_Y_LPARAM( lParam));
if ( tabItem < 0
//|| closeButtonRect.PtInRect( startHitPoint) /***** ti does not work unfortunately*****/
//|| scrollButtonRect.PtInRect( startHitPoint)
//|| nonClientRect.PtInRect( startHitPoint)
|| !this->GetItemRect( tabItem, itemRect)
|| !itemRect.PtInRect( startHitPoint)
|| !::DragDetect( this->m_hWnd, startHitPoint)
)
return result;
HCURSOR cursorSizeWE = LoadCursor( NULL, IDC_SIZEWE);
HCURSOR oldCursor = ::GetCursor();
// do drag and drop
::SetCapture( this->m_hWnd);
HWND clientViewWnd = this->getWND( tabItem);
bool globalDrag = false;
MSG msg;
while( ( ::GetCapture()==this->m_hWnd) && ( ::GetMessage( &msg, NULL, 0, 0))) {
CTCHITTESTINFO hci;
int tabItemTarget;
switch(msg.message) {
case WM_MOUSEMOVE:
{
CPoint hitPoint( GET_X_LPARAM( msg.lParam), GET_Y_LPARAM( msg.lParam));
hci.pt.x = hitPoint.x;
hci.pt.y = hitPoint.y;
hci.flags = TCHT_ONITEM;
tabItemTarget = this->HitTest( &hci);
::SetCursor( ( tabItemTarget == tabItem && startHitPoint != hitPoint)? cursorSizeWE: oldCursor);
if ( tabItemTarget > -1 && tabItemTarget != tabItem) {
// tab shifting
if ( globalDrag) {
globalDrag = false;
this->cbListener->dragCancel( this->m_hWnd, clientViewWnd);
}
if ( tabItemTarget < tabItem) {
// shift the tab left
for ( int i=tabItem; i > tabItemTarget; i--)
this->SwapItemPositions( i-1, i);
} else if ( tabItem < tabItemTarget) {
// shift the tab right
for ( int i=tabItem; i < tabItemTarget; i++)
this->SwapItemPositions( i, i+1);
}
this->SetCurSel( tabItemTarget);
tabItem = tabItemTarget;
} else if ( tabItemTarget == -1) {
// handle drag moving
CPoint point( GET_X_LPARAM( msg.lParam), GET_Y_LPARAM( msg.lParam));
this->ClientToScreen( &point);
if ( !globalDrag) {
globalDrag = true;
if ( NULL != this->cbListener)
this->cbListener->dragStart( this->m_hWnd, clientViewWnd, point.x, point.y, static_cast<DWORD>(msg.wParam));
}
if ( NULL != this->cbListener)
this->cbListener->dragOver( this->m_hWnd, clientViewWnd, point.x, point.y, static_cast<DWORD>(msg.wParam));
}
startHitPoint = hitPoint;
break;
}
case WM_RBUTTONUP:
case WM_LBUTTONUP:
{
::ReleaseCapture();
if ( NULL != this->cbListener && globalDrag) {
CPoint point( GET_X_LPARAM( msg.lParam), GET_Y_LPARAM( msg.lParam));
this->ClientToScreen( &point);
this->cbListener->dragDrop( this->m_hWnd, clientViewWnd, point.x, point.y, static_cast<DWORD>(msg.wParam));
globalDrag = false;
}
break;
}
case WM_KEYDOWN:
if( msg.wParam != VK_ESCAPE)
break;
case WM_SYSKEYDOWN:
::ReleaseCapture();
if ( NULL != this->cbListener && globalDrag) {
this->cbListener->dragCancel( this->m_hWnd, clientViewWnd);
globalDrag = false;
}
case WM_CAPTURECHANGED:
result = 0;
break;
default:
::TranslateMessage(&msg);
::DispatchMessage( &msg);
}
}
::SetCursor( oldCursor);
::DestroyCursor( cursorSizeWE);
return result;
}
LRESULT OnPaint( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) {
return this->DefWindowProc( uMsg, wParam, lParam);
}
LRESULT OnEraseBackground( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) {
return 1;
}
};
class ClientProperties {
public:
CString caption;
CString toolTip;
int imageIndex;
};
// class Pane
class Pane
: public CWindowImpl<Pane, CWindow>
, public CallBackListener
{
//----------------- protected members
protected:
TabControl tabs;
CallBackListener* cbListener;
bool isTabsOnTop;
//----------------- protected interface
protected:
int insertTab( int index, const TCHAR* caption, HWND clientViewWnd, const TCHAR* toolTip = NULL, int imageIndex = -1) {
ATLASSERT( ::IsWindow( clientViewWnd));
::SetParent( clientViewWnd, this->m_hWnd);
TabControlItem* item = this->tabs.CreateNewItem();
item->clientViewWnd = clientViewWnd;
item->SetText( caption);
item->SetToolTip( toolTip);
item->SetImageIndex( imageIndex);
return this->tabs.InsertItem( index, item, true);
}
int getCurrentTab() const {
return this->tabs.getCurrentTab();
}
int setCurrentTab( int index) {
return this->tabs.setCurrentTab( index);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -