📄 docktabsplitpane.h
字号:
parentVerSplitter->SetSplitterPane( SPLIT_PANE_RIGHT, newSplitterWnd, false);
parentVerSplitter->GetSplitterPaneRect( SPLIT_PANE_RIGHT, &newSplitterRect);
}
} else if ( NULL != ( horSplitPair = this->horSplitterMap.Lookup( targetPaneParent))) {
// it is a horizontal splitter
parentHorSplitter = horSplitPair->m_value;
if ( parentHorSplitter->GetSplitterPane( SPLIT_PANE_LEFT) == targetPane->m_hWnd) {
parentHorSplitter->SetSplitterPane( SPLIT_PANE_LEFT, newSplitterWnd, false);
parentHorSplitter->GetSplitterPaneRect( SPLIT_PANE_LEFT, &newSplitterRect);
} else if ( parentHorSplitter->GetSplitterPane( SPLIT_PANE_RIGHT) == targetPane->m_hWnd) {
parentHorSplitter->SetSplitterPane( SPLIT_PANE_RIGHT, newSplitterWnd, false);
parentHorSplitter->GetSplitterPaneRect( SPLIT_PANE_RIGHT, &newSplitterRect);
}
}
}
::SetWindowPos( newSplitterWnd, HWND_TOP, newSplitterRect.left, newSplitterRect.top, newSplitterRect.Width(), newSplitterRect.Height(), SWP_HIDEWINDOW);
// set panes for the new splitter
if ( isVertical) {
int newPaneID;
int targetPaneID;
verSplitter->SetSplitterPos( -1, false);
if ( where == Pane::TabPaneHitTest_Left) {
targetPaneID = SPLIT_PANE_RIGHT;
newPaneID = SPLIT_PANE_LEFT;
verSplitter->SetSplitterPanes( newPane->m_hWnd, targetPane->m_hWnd, false);
} else {
targetPaneID = SPLIT_PANE_LEFT;
newPaneID = SPLIT_PANE_RIGHT;
verSplitter->SetSplitterPanes( targetPane->m_hWnd, newPane->m_hWnd, false);
}
verSplitter->GetSplitterPaneRect( targetPaneID, &targetPaneRect);
verSplitter->GetSplitterPaneRect( newPaneID, &newPaneRect);
} else {
int newPaneID;
int targetPaneID;
horSplitter->SetSplitterPos(-1, false);
if ( where == Pane::TabPaneHitTest_Top) {
targetPaneID = SPLIT_PANE_RIGHT;
newPaneID = SPLIT_PANE_LEFT;
horSplitter->SetSplitterPanes( newPane->m_hWnd, targetPane->m_hWnd, false);
} else {
targetPaneID = SPLIT_PANE_LEFT;
newPaneID = SPLIT_PANE_RIGHT;
horSplitter->SetSplitterPanes( targetPane->m_hWnd, newPane->m_hWnd, false);
}
horSplitter->GetSplitterPaneRect( targetPaneID, &targetPaneRect);
horSplitter->GetSplitterPaneRect( newPaneID, &newPaneRect);
}
// get the new splitter visible
::SetWindowPos( newSplitterWnd, 0, 0, 0, 0, 0, SWP_NOZORDER | SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOOWNERZORDER);
// Set new window position for the new pane, the target pane and the new splitter window
newPane->SetWindowPos( HWND_TOP, newPaneRect.left, newPaneRect.top, newPaneRect.Width(), newPaneRect.Height(), SWP_SHOWWINDOW);
targetPane->SetWindowPos( HWND_TOP, targetPaneRect.left, targetPaneRect.top, targetPaneRect.Width(), targetPaneRect.Height(), SWP_SHOWWINDOW);
// Set focus to the new pane
newPane->SetFocus();
this->currentPane = newPane;
// if there is no tab left in the source pane it needs to be destroyed
HWND sourcePaneParentWnd = sourcePane->GetParent();
if ( sourcePane->isEmpty() && sourcePaneParentWnd != this->m_hWnd) {
// important:
// destroy the source pane via the message queue becouse this call maybe done by a tab control
// belonging to the source pane. we don't want to destroy it before it ends.
this->PostMessage( WM_USER_DESTROY_PANE, 0, (LPARAM) sourcePane->m_hWnd);
}
} // splitWithCurrentTab( Pane* sourcePane, Pane* targetPane, Pane::TabPaneHitTest where)
HSplitter* lookUpHSplitter( HWND splitterWnd) {
CAtlMap< HWND, HSplitter*>::CPair* splitterPair = this->horSplitterMap.Lookup( splitterWnd);
if ( NULL == splitterPair)
return NULL;
return splitterPair->m_value;
} // HSplitter* lookUpHSplitter( HWND splitterWnd)
VSplitter* lookUpVSplitter( HWND splitterWnd) {
CAtlMap< HWND, VSplitter*>::CPair* splitterPair = this->verSplitterMap.Lookup( splitterWnd);
if ( NULL == splitterPair)
return NULL;
return splitterPair->m_value;
} // HSplitter* lookUpHSplitter( HWND splitterWnd)
Pane* lookUpPane( HWND clientViewWnd) {
CAtlMap< HWND, Pane*>::CPair* clientPanePair = this->clientViewPaneMap.Lookup( clientViewWnd);
if ( NULL == clientPanePair)
return NULL;
return clientPanePair->m_value;
} // Pane* lookUpPane( HWND clientViewWnd)
Pane* lookUpPaneWnd( HWND paneWnd) {
CAtlMap< HWND, Pane*>::CPair* clientPanePair = this->paneMap.Lookup( paneWnd);
if ( NULL == clientPanePair)
return NULL;
return clientPanePair->m_value;
} // Pane* lookUpPaneWnd( HWND paneWnd)
Pane* getNextPane( HWND hWnd) {
Pane* result = this->lookUpPaneWnd( hWnd);
// check if hwnd is a Pane
if ( NULL != result)
return result;
HWND splitter[2];
memset( splitter, 0, sizeof(splitter));
HWND childWnd = ::GetWindow( hWnd, GW_CHILD);
int i = 0;
while ( NULL != childWnd) {
if ( NULL != ( result = this->lookUpPaneWnd( childWnd)))
break;
// TODO need to keep a beakpoint for debugging more time
if ( NULL != this->lookUpHSplitter( childWnd) || NULL != this->lookUpHSplitter( childWnd))
// dangerous code, but we know that there are no more than two splitters ;)
splitter[i++] = childWnd;
childWnd = ::GetWindow( hWnd, GW_HWNDNEXT);
}
if ( NULL == result) {
if ( NULL != splitter[0])
result = getNextPane( ::GetWindow( splitter[0], GW_CHILD));
else if ( NULL != splitter[1])
result = getNextPane( ::GetWindow( splitter[1], GW_CHILD));
}
return result;
}
bool setCurrentPane( HWND paneWnd) {
Pane* pane = this->lookUpPaneWnd( paneWnd);
if ( NULL != pane) {
this->currentPane = pane;
return true;
} else
return false;
}
void removeAll() {
if ( NULL != this->dragContext)
delete dragContext;
POSITION position;
if ( position = this->paneMap.GetStartPosition())
do
delete this->paneMap.GetNextValue( position);
while ( position);
this->paneMap.RemoveAll();
if ( position = this->verSplitterMap.GetStartPosition())
do
delete this->verSplitterMap.GetNextValue( position);
while ( position);
this->verSplitterMap.RemoveAll();
if ( position = this->horSplitterMap.GetStartPosition())
do
delete this->horSplitterMap.GetNextValue( position);
while ( position);
this->horSplitterMap.RemoveAll();
}
void updateLayout() {
if ( NULL == this->rootWnd)
return;
CRect rect;
this->GetClientRect( rect);
::SetWindowPos( this->rootWnd, HWND_TOP, rect.left, rect.top, rect.Width(), rect.Height(), SWP_SHOWWINDOW);
return;
}
//----------------- public interface
public:
// Constructor/Destructor
SplitPane( CallBackListener* cbListener = NULL, bool tabOnTop = false)
: currentPane( NULL)
, rootWnd( NULL)
, dragContext( NULL)
, cbListener( cbListener)
, tabOnTop( tabOnTop)
{}
~SplitPane() {
this->removeAll();
if ( NULL != this->m_hWnd)
this->DestroyWindow();
}
// CallBackListener interface
void clientActivate( HWND childWnd, HWND clientViewWnd) {
this->setCurrentPane( childWnd);
if ( NULL != this->cbListener)
this->cbListener->clientActivate( this->m_hWnd, clientViewWnd);
return;
}
void clientDblClick( HWND childWnd, HWND clientViewWnd) {
if ( NULL != this->cbListener)
this->cbListener->clientDblClick( this->m_hWnd, clientViewWnd);
return;
}
void clientCloseClick( HWND childWnd, HWND clientViewWnd) {
if ( NULL != this->cbListener)
this->cbListener->clientCloseClick( this->m_hWnd, clientViewWnd);
return;
}
void dragStart( HWND srcPane, HWND clientViewWnd, long x, long y, DWORD keysPressed) {
ATLASSERT( NULL == this->dragContext);
this->dragContext = new DragContext();
}
void dragOver( HWND srcPane, HWND clientViewWnd, long x, long y, DWORD keysPressed) {
ATLASSERT( NULL != this->dragContext);
Pane* targetPane = this->getPane( x, y);
if ( NULL != targetPane) {
CPoint hitPoint( x, y);
this->dragContext->tabPaneHitTest = targetPane->hitTest( &hitPoint);
if ( this->dragContext->tabPaneHitTest != Pane::TabPaneHitTest_Unknown) {
// determine a source pane
CAtlMap< HWND, Pane*>::CPair* sourcePanePair = this->paneMap.Lookup( srcPane);
if ( NULL != sourcePanePair) {
Pane* sourcePane;
sourcePane = sourcePanePair->m_value;
if ( sourcePane != targetPane || sourcePane->clientCount() > 1) {
// draw hit area only if there is more than one tab in the source tab
// or if the target pane is not the same as the source tab.
CRect rect;
targetPane->getTabPageRect( &rect);
switch ( this->dragContext->tabPaneHitTest) {
case Pane::TabPaneHitTest_Top: rect.bottom /= 2; break;
case Pane::TabPaneHitTest_Right: rect.left = rect.right / 2; break;
case Pane::TabPaneHitTest_Left: rect.right /= 2; break;
case Pane::TabPaneHitTest_Bottom: rect.top = rect.bottom / 2; break;
}
// Draw a track rectangle
this->dragContext->drawTrackRectangle( targetPane->m_hWnd, &rect);
}
}
}
} else
this->dragContext->clearTrackRectangle();
}
void dragDrop( HWND srcPane, HWND clientViewWnd, long x, long y, DWORD keysPressed) {
ATLASSERT( NULL != this->dragContext);
Pane* sourcePane;
Pane* targetPane;
this->dragContext->clearTrackRectangle();
switch( this->dragContext->tabPaneHitTest) {
case Pane::TabPaneHitTest_Unknown:
break;
case Pane::TabPaneHitTest_TabArea:
targetPane = this->getPane( x, y);
sourcePane = this->paneMap.Lookup( srcPane)->m_value;
if ( NULL != targetPane && NULL != sourcePane && targetPane != sourcePane)
this->moveCurrentTab( sourcePane, targetPane);
break;
default:
targetPane = this->getPane( x, y);
sourcePane = this->paneMap.Lookup( srcPane)->m_value;
if ( NULL != targetPane && NULL != sourcePane)
this->splitWithCurrentTab( sourcePane, targetPane, this->dragContext->tabPaneHitTest);
}
// Remove drag context
delete this->dragContext;
this->dragContext = NULL;
}
void dragCancel( HWND srcPane, HWND clientViewWnd) {
ATLASSERT( NULL != this->dragContext);
delete this->dragContext;
this->dragContext = NULL;
}
// public methods
enum TargetArea {
targetLeft
, targetTop
, targetRight
, targetBottom
};
void splitClientView( HWND sourceWnd, HWND targetWnd, TargetArea targetArea) {
ATLASSERT( ::IsWindow( sourceWnd));
ATLASSERT( ::IsWindow( targetWnd));
Pane* sourcePane = this->lookUpPane( sourceWnd);
Pane* targetPane = this->lookUpPane( targetWnd);
ATLASSERT( NULL != sourcePane);
ATLASSERT( NULL != targetPane);
Pane::TabPaneHitTest tabPaneHitTest;
switch ( targetArea) {
case targetLeft: tabPaneHitTest = Pane::TabPaneHitTest_Left; break;
case targetTop: tabPaneHitTest = Pane::TabPaneHitTest_Top; break;
case targetRight: tabPaneHitTest = Pane::TabPaneHitTest_Right; break;
case targetBottom: tabPaneHitTest = Pane::TabPaneHitTest_Bottom; break;
default:
ATLASSERT( FALSE);
}
this->setFocusTo( sourceWnd);
this->splitWithCurrentTab( sourcePane, targetPane, tabPaneHitTest);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -