📄 atldock.h
字号:
ctx->bKeepSize = false;
// Create docking child
TDockWindow *wndDock;
ATLTRY(wndDock = new TDockWindow(ctx));
if( wndDock==NULL ) return;
wndDock->Create(m_hWnd, rcDefault, NULL);
ATLASSERT(::IsWindow(wndDock->m_hWnd));
ctx->hwndDocked = *wndDock;
// Create floating child
TFloatWindow *wndFloat;
TCHAR szCaption[128]; // max text length is 127 for floating caption
::GetWindowText(hWnd, szCaption, sizeof(szCaption)/sizeof(TCHAR));
ATLTRY(wndFloat = new TFloatWindow(ctx));
if( wndFloat==NULL ) return;
wndFloat->Create(m_hWnd, rcDefault, szCaption);
ATLASSERT(::IsWindow(wndFloat->m_hWnd));
ctx->hwndFloated = *wndFloat;
::SetParent(ctx->hwndChild, ctx->hwndDocked);
// Add Context to master list
m_map.Add(ctx);
}
BOOL DockWindow(HWND hWnd, short Side, int iRequestedSize=0)
{
T* pT = static_cast<T*>(this);
DOCKCONTEXT *ctx = _GetContext(hWnd);
ATLASSERT(ctx);
if( ctx==NULL ) return FALSE;
if( Side==DOCK_LASTKNOWN ) Side = ctx->LastSide;
if( !IsDocked(Side) ) return FALSE;
return pT->_DockWindow(ctx, Side, iRequestedSize);
}
BOOL FloatWindow(HWND hWnd, RECT &rc)
{
T* pT = static_cast<T*>(this);
DOCKCONTEXT *ctx = _GetContext(hWnd);
ATLASSERT(ctx);
if( ctx==NULL ) return FALSE;
ctx->rcWindow = rc;
return pT->_FloatWindow(ctx);
}
BOOL HideWindow(HWND hWnd)
{
T* pT = static_cast<T*>(this);
DOCKCONTEXT *ctx = _GetContext(hWnd);
ATLASSERT(ctx);
if( ctx==NULL ) return FALSE;
if( ctx->Side==DOCK_FLOAT ) return pT->_UnFloatWindow(ctx);
else if( IsDocked(ctx->Side) ) return pT->_UnDockWindow(ctx);
return FALSE;
}
void GetWindowState(HWND hWnd, int &DockState, RECT &rect)
{
DOCKCONTEXT *ctx = _GetContext(hWnd);
ATLASSERT(ctx);
if( ctx==NULL ) return;
DockState = ctx->Side;
::GetWindowRect(::GetParent(hWnd), &rect);
}
int GetPaneSize(short Side)
{
ATLASSERT(IsDocked(Side));
int cy = m_panes[Side].m_cy;
if( cy==0 ) cy = m_panes[Side].m_cyOld;
return cy;
}
void SetPaneSize(short Side, int Size)
{
ATLASSERT(IsDocked(Side));
m_panes[Side].m_cy = ( m_panes[Side].m_map.GetSize()==0 ? 0 : Size );
m_panes[Side].m_cyOld = Size;
T* pT = static_cast<T*>(this);
pT->UpdateLayout();
}
// Message handlers
LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
for( short i=0; i<4; i++ ) {
m_panes[i].m_Side = i;
m_panes[i].Create(m_hWnd, rcDefault, NULL, WS_CHILD|WS_VISIBLE);
}
m_sizeBorder.cx = ::GetSystemMetrics(SM_CXEDGE);
m_sizeBorder.cy = ::GetSystemMetrics(SM_CYEDGE);
return 0;
}
LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
for( int i=0; i<m_map.GetSize(); i++ ) {
if( ::IsWindow(m_map[i]->hwndDocked) ) ::DestroyWindow(m_map[i]->hwndDocked);
if( ::IsWindow(m_map[i]->hwndFloated) ) ::DestroyWindow(m_map[i]->hwndFloated);
delete m_map[i];
}
return 0;
}
LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
return 1; // handled, no background painting needed
}
LRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
T* pT = static_cast<T*>(this);
pT->UpdateLayout();
return 0;
}
// Custom defined messages
LRESULT OnQueryRect(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
{
// wParam: Side
// lParam: LPRECT
LPRECT prc = (LPRECT)lParam;
ATLASSERT(prc);
switch( (short)wParam ) {
case DOCK_LEFT:
case DOCK_TOP:
case DOCK_RIGHT:
case DOCK_BOTTOM:
::GetWindowRect(m_panes[wParam], prc);
break;
case DOCK_INFO_CHILD:
::GetWindowRect(m_hwndClient, prc);
break;
default:
ATLASSERT(false);
}
return 0;
}
LRESULT OnQueryTrack(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)
{
// lParam: TRACKINFO *
TRACKINFO *pTI = (TRACKINFO *)lParam;
ATLASSERT(pTI);
POINT &pt = pTI->ptPos;
RECT rc;
if( pTI->ctx->dwFlags & DCK_NOFLOAT ) {
// If we're not allowed to float, we're still docked to where we came from
::GetWindowRect(pTI->hWnd, &rc);
pTI->rc = rc;
::OffsetRect(&pTI->rc, pt.x-pTI->ptStart.x, pt.y-pTI->ptStart.y);
pTI->Side = pTI->ctx->Side;
}
else {
// But by default, we're floating in the skies
::GetWindowRect(pTI->hWnd, &rc);
::SetRect(&pTI->rc, rc.left, rc.top, rc.left+pTI->ctx->sizeFloat.cx, rc.top+pTI->ctx->sizeFloat.cy);
::OffsetRect(&pTI->rc, pt.x-pTI->ptStart.x, pt.y-pTI->ptStart.y);
pTI->Side = DOCK_FLOAT;
}
// Pressing CTRL key gives default floating
if( ::GetKeyState(VK_CONTROL)<0 ) return 0;
// Are we perhaps hovering over the tracked window?
::GetWindowRect(pTI->hWnd, &rc);
if( ::PtInRect(&rc, pt) ) {
pTI->rc = rc;
::OffsetRect(&pTI->rc, pt.x-pTI->ptStart.x, pt.y-pTI->ptStart.y);
pTI->Side = pTI->ctx->Side;
return 0;
}
// Or is the point inside one of the other docking areas?
for( short i=0; i<4; i++ ) {
if( pTI->ctx->dwFlags & (1<<i) ) continue; // DCK_NOxxx flag?
if( m_panes[i].m_cy==0 ) {
// Simulate docking areas that are currently invisible
::GetWindowRect(m_hWnd, &rc);
switch( m_panes[i].m_Side ) {
case DOCK_LEFT: rc.right = rc.left + DEFAULT_DOCKPANE_SIZE; break;
case DOCK_RIGHT: rc.left = rc.right - DEFAULT_DOCKPANE_SIZE; break;
case DOCK_TOP: rc.bottom = rc.top + DEFAULT_DOCKPANE_SIZE; break;
case DOCK_BOTTOM: rc.top = rc.bottom - DEFAULT_DOCKPANE_SIZE; break;
}
}
else {
::GetWindowRect(m_panes[i], &rc);
}
if( ::PtInRect(&rc, pt) ) {
pTI->Side = i;
pTI->rc = rc;
return 0;
}
}
return 0;
}
LRESULT OnDock(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
{
T* pT = static_cast<T*>(this);
pT->_DockWindow((DOCKCONTEXT *)lParam,(short)wParam,0);
return 0;
}
LRESULT OnUnDock(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)
{
T* pT = static_cast<T*>(this);
pT->_UnDockWindow((DOCKCONTEXT *)lParam);
return 0;
}
LRESULT OnFloat(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)
{
T* pT = static_cast<T*>(this);
pT->_FloatWindow((DOCKCONTEXT *)lParam);
return 0;
}
LRESULT OnUnFloat(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)
{
T* pT = static_cast<T*>(this);
pT->_UnFloatWindow((DOCKCONTEXT *)lParam);
return 0;
}
LRESULT OnRepositionWindow(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
{
T* pT = static_cast<T*>(this);
pT->_RepositionWindow((DOCKCONTEXT *)lParam, (int)wParam);
return 0;
}
// Overridables
void UpdateLayout()
{
RECT rect;
GetClientRect(&rect);
RECT rcClient = rect;
if( m_panes[DOCK_TOP].m_cy>0 ) {
::SetWindowPos(m_panes[DOCK_TOP], NULL, rect.left, rect.top, rect.right-rect.left, m_panes[DOCK_TOP].m_cy, SWP_NOZORDER | SWP_NOACTIVATE);
rcClient.top += m_panes[DOCK_TOP].m_cy;
}
if( m_panes[DOCK_LEFT].m_cy>0 ) {
::SetWindowPos(m_panes[DOCK_LEFT], NULL, rect.left, rcClient.top, m_panes[DOCK_LEFT].m_cy, rect.bottom - rcClient.top, SWP_NOZORDER | SWP_NOACTIVATE);
rcClient.left += m_panes[DOCK_LEFT].m_cy;
}
if( m_panes[DOCK_RIGHT].m_cy>0 ) {
int left = max( rect.right-m_panes[DOCK_RIGHT].m_cy, rcClient.left );
::SetWindowPos(m_panes[DOCK_RIGHT], NULL, left, rcClient.top, m_panes[DOCK_RIGHT].m_cy, rect.bottom-rcClient.top, SWP_NOZORDER | SWP_NOACTIVATE);
rcClient.right -= m_panes[DOCK_RIGHT].m_cy;
}
if( m_panes[DOCK_BOTTOM].m_cy>0 ) {
int top = max( rcClient.bottom-m_panes[DOCK_BOTTOM].m_cy, rcClient.top );
::SetWindowPos(m_panes[DOCK_BOTTOM], NULL, rcClient.left, top, rcClient.right-rcClient.left, m_panes[DOCK_BOTTOM].m_cy, SWP_NOZORDER | SWP_NOACTIVATE);
rcClient.bottom -= m_panes[DOCK_BOTTOM].m_cy;
}
if( ::IsWindow(m_hwndClient) ) {
// Adjust borders around docking panes
DWORD dwExtStyle = (DWORD)::GetWindowLong(m_hwndClient, GWL_EXSTYLE);
bool bClientEdge = ((dwExtStyle & WS_EX_CLIENTEDGE)!=0);
if( bClientEdge ) {
if( m_panes[DOCK_TOP].m_cy>0 ) rcClient.top -= m_sizeBorder.cy;
if( m_panes[DOCK_LEFT].m_cy>0 ) rcClient.left -= m_sizeBorder.cx;
if( m_panes[DOCK_RIGHT].m_cy>0 ) rcClient.right += m_sizeBorder.cx;
if( m_panes[DOCK_BOTTOM].m_cy>0 ) rcClient.bottom += m_sizeBorder.cy;
}
// Map client rectangle to windows's coord system
::MapWindowPoints(m_hWnd, ::GetParent(m_hwndClient), (LPPOINT)&rcClient, sizeof(rcClient)/sizeof(POINT));
::SetWindowPos(m_hwndClient, NULL, rcClient.left, rcClient.top, rcClient.right - rcClient.left, rcClient.bottom - rcClient.top, SWP_NOZORDER);
}
}
BOOL _DockWindow(DOCKCONTEXT *ctx, short Side, int iRequestedSize)
{
ATLASSERT(ctx);
ATLASSERT(IsDocked(Side));
ATLASSERT(ctx->Side==DOCK_HIDDEN); // Undock before redock
if( !IsDocked(Side) ) return FALSE;
if( ctx->Side!=DOCK_HIDDEN ) return FALSE;
bool bVertical = IsDockedVertically(Side);
// Make up a new panel size
if( iRequestedSize<=0 ) {
RECT rc;
::GetClientRect(m_panes[Side], &rc);
iRequestedSize = bVertical ? rc.bottom-rc.top : rc.right-rc.left;
if( m_panes[Side].m_map.GetSize()>0 ) iRequestedSize /= m_panes[Side].m_map.GetSize();
}
// Set the new size of the pane (subject to readjustment)
::SetRectEmpty(&ctx->rcWindow);
(bVertical ? ctx->rcWindow.bottom : ctx->rcWindow.right) = iRequestedSize;
ctx->bKeepSize = true;
// Dock
m_panes[Side].DockWindow(ctx);
SendMessage(WM_DOCK_UPDATELAYOUT);
return TRUE;
}
BOOL _FloatWindow(DOCKCONTEXT *ctx)
{
ATLASSERT(ctx);
ATLASSERT(ctx->Side==DOCK_HIDDEN); // Undock before float
if( ctx->Side!=DOCK_HIDDEN ) return FALSE;
ctx->Side = DOCK_FLOAT;
::SetParent(ctx->hwndChild, ctx->hwndFloated);
::SetWindowPos(ctx->hwndFloated, NULL, ctx->rcWindow.left, ctx->rcWindow.top, ctx->rcWindow.right-ctx->rcWindow.left, ctx->rcWindow.bottom-ctx->rcWindow.top, SWP_NOZORDER);
::SendMessage(ctx->hwndFloated, WM_DOCK_UPDATELAYOUT, 0,0);
::ShowWindow(ctx->hwndFloated, SW_SHOWNORMAL);
return TRUE;
}
BOOL _UnDockWindow(DOCKCONTEXT *ctx)
{
ATLASSERT(ctx);
ATLASSERT(IsDocked(ctx->Side));
if( !IsDocked(ctx->Side) ) return FALSE;
m_panes[ctx->Side].UnDockWindow(ctx);
ctx->Side = DOCK_HIDDEN;
SendMessage(WM_DOCK_UPDATELAYOUT);
return TRUE;
}
BOOL _UnFloatWindow(DOCKCONTEXT *ctx)
{
ATLASSERT(ctx);
ATLASSERT(ctx->Side==DOCK_FLOAT);
if( ctx->Side!=DOCK_FLOAT ) return FALSE;
::ShowWindow(ctx->hwndFloated, SW_HIDE);
ctx->Side = DOCK_HIDDEN;
return TRUE;
}
BOOL _RepositionWindow(DOCKCONTEXT *ctx, int iPos)
{
ATLASSERT(ctx);
ATLASSERT(IsDocked(ctx->Side));
if( !IsDocked(ctx->Side) ) return FALSE;
m_panes[ctx->Side].RepositionWindow(ctx,iPos);
return TRUE;
}
DOCKCONTEXT *_GetContext(HWND hWnd)
{
ATLASSERT(::IsWindow(hWnd));
for( int i=0; i<m_map.GetSize(); i++ ) if( m_map[i]->hwndChild==hWnd ) return m_map[i];
ATLASSERT(!"Docking Window not found; use AddWindow() to add it");
return NULL;
}
};
class CDockingWindow : public CDockingWindowImpl<CDockingWindow>
{
public:
DECLARE_WND_CLASS_EX(_T("WTL_DockingWindow"), CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS, NULL)
};
#endif // __ATL_DOCK_H__
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -