📄 atldock.h
字号:
HideWindow(hWnd);
// Remove context from map in case of repaint
m_map.Remove(pCtx);
ATLASSERT(::IsWindow(pCtx->hwndOrigPrnt));
::SetParent( pCtx->hwndChild, pCtx->hwndOrigPrnt );
if( ::IsWindow(pCtx->hwndDocked )) ::DestroyWindow(pCtx->hwndDocked);
if( ::IsWindow(pCtx->hwndFloated )) ::DestroyWindow(pCtx->hwndFloated);
// Destroy context. Allocated in AddWindow()...
delete pCtx;
return TRUE;
}
BOOL DockWindow(HWND hWnd, short Side, int iRequestedSize = 0)
{
T* pT = static_cast<T*>(this);
DOCKCONTEXT* pCtx = _GetContext(hWnd);
ATLASSERT(pCtx);
if( pCtx == NULL ) return FALSE;
::ShowWindow(pCtx->hwndChild, SW_SHOWNOACTIVATE);
if( Side == DOCK_LASTKNOWN ) Side = pCtx->LastSide;
if( !IsDocked(Side) ) return FALSE;
return pT->_DockWindow(pCtx, Side, iRequestedSize);
}
BOOL FloatWindow(HWND hWnd, RECT& rc)
{
T* pT = static_cast<T*>(this);
DOCKCONTEXT* pCtx = _GetContext(hWnd);
ATLASSERT(pCtx);
if( pCtx == NULL ) return FALSE;
::ShowWindow(pCtx->hwndChild, SW_SHOWNOACTIVATE);
pCtx->rcWindow = rc;
return pT->_FloatWindow(pCtx);
}
BOOL HideWindow(HWND hWnd)
{
T* pT = static_cast<T*>(this);
DOCKCONTEXT* pCtx = _GetContext(hWnd);
ATLASSERT(pCtx);
if( pCtx == NULL ) return FALSE;
::ShowWindow(pCtx->hwndChild, SW_HIDE);
if( pCtx->Side == DOCK_FLOAT ) return pT->_UnFloatWindow(pCtx);
else if( IsDocked(pCtx->Side) ) return pT->_UnDockWindow(pCtx);
return TRUE;
}
void GetWindowState(HWND hWnd, int& DockState, RECT& rect) const
{
const DOCKCONTEXT* pCtx = _GetContext(hWnd);
ATLASSERT(pCtx);
if( pCtx == NULL ) return;
DockState = pCtx->Side;
::GetWindowRect(::GetParent(hWnd), &rect);
}
int GetPaneSize(short Side) const
{
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();
}
void EnableModeless(BOOL bEnable)
{
for( int i = 0; i < m_map.GetSize(); i++ ) {
if( ::IsWindow(m_map[i]->hwndFloated) ) ::EnableWindow(m_map[i]->hwndFloated, bEnable);
}
}
// Call this method from an message idle-handler (such as the
// WTL CIdleHandler::OnIdle() handler). It makes sure to
// keep the docked panes' caption updated with respect to current
// keyboard focus.
virtual BOOL OnIdle()
{
static HWND s_hwndLastActive = NULL;
HWND hwndFocus = ::GetFocus();
HWND hwndCurrent = NULL;
for( int i = 0; i < m_map.GetSize(); i++ ) {
const DOCKCONTEXT* pCtx = m_map[i];
if( IsDocked(pCtx->Side) && ::IsChild(pCtx->hwndDocked, hwndFocus) ) hwndCurrent = pCtx->hwndDocked;
}
if( s_hwndLastActive != hwndCurrent ) {
if( ::IsWindow(s_hwndLastActive) ) ::InvalidateRect(s_hwndLastActive, NULL, TRUE);
if( ::IsWindow(hwndCurrent) ) ::InvalidateRect(hwndCurrent, NULL, TRUE);
s_hwndLastActive = hwndCurrent;
}
return TRUE;
}
// 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];
}
m_map.RemoveAll();
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->pCtx->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->pCtx->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->pCtx->sizeFloat.cx, rc.top + pTI->pCtx->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->pCtx->Side;
return 0;
}
// Or is the point inside one of the other docking areas?
for( short i = 0; i < 4; i++ ) {
if( pTI->pCtx->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 OnClientClose(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
{
DOCKCONTEXT* pCtx = (DOCKCONTEXT*) lParam;
// Make sure to bring focus back to this app!
::SetForegroundWindow(m_hWnd);
SetFocus();
// Hide or destroy view
if( m_dwExtStyle & DCK_EX_DESTROYONCLOSE ) {
HWND hWnd = pCtx->hwndChild;
// Commit suicide
RemoveWindow(hWnd);
::DestroyWindow(hWnd);
}
else {
// Send the actual dock/float message instead
SendMessage((UINT) wParam, 0, (LPARAM) pCtx);
// HACK: Send notification to child (note the funky message type)
::SendMessage(pCtx->hwndChild, WM_COMPACTING, 0, 0L);
}
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( (int) rect.right - m_panes[DOCK_RIGHT].m_cy, (int) 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( (int) rcClient.bottom - m_panes[DOCK_BOTTOM].m_cy, (int) 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();
}
if( iRequestedSize < 10 ) iRequestedSize = 0;
// Set the new size of the pane (subject to readjustment)
::SetRectEmpty(&ctx->rcWindow);
(bVertical ? ctx->rcWindow.bottom : ctx->rcWindow.right) = iRequestedSize;
// Signal that we would like to retain this size after
// first being laid out...
ctx->bKeepSize = iRequestedSize > 0;
// Dock
m_panes[Side].DockWindow(ctx);
PostMessage(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) const
{
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 + -