?? atldock.h
字號:
#ifndef __ATL_DOCK_H__
#define __ATL_DOCK_H__
/////////////////////////////////////////////////////////////////////////////
// atldock.h - Docking framework for the WTL library
//
// Written by Bjarke Viksoe (bjarke@viksoe.dk)
// Thanks to Mike Simon for adding the ability to close a view.
// Copyright (c) 2000-2002 Bjarke Viksoe.
//
// This code may be used in compiled form in any way you desire. This
// file may be redistributed 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 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.
//
#pragma once
#ifndef __cplusplus
#error ATL requires C++ compilation (use a .cpp suffix)
#endif
#ifndef __ATLAPP_H__
#error atldock.h requires atlapp.h to be included first
#endif
// Dock positions
#define DOCK_LEFT 0
#define DOCK_TOP 1
#define DOCK_RIGHT 2
#define DOCK_BOTTOM 3
#define DOCK_FLOAT 4
#define DOCK_HIDDEN 5
#define DOCK_LASTKNOWN 6
// Extended dock styles
#define DCK_EX_DESTROYONCLOSE 0x00000001
#define DCK_EX_REMEMBERSIZE 0x00000002
// Control style flags
#define DCK_NOLEFT 1<<DOCK_LEFT
#define DCK_NOTOP 1<<DOCK_TOP
#define DCK_NORIGHT 1<<DOCK_RIGHT
#define DCK_NOBOTTOM 1<<DOCK_BOTTOM
#define DCK_NOSPLITTER 0x00000100L
#define DCK_NOFLOAT 0x00000200L
#define DCK_NOHIDE 0x00000400L
#define ATL_SIMPLE_DOCKVIEW_STYLE \
(WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS)
// Docked child command chaining macro
#define CHAIN_DOCK_CHILD_COMMANDS(hwnd) \
if(uMsg == WM_COMMAND) \
{ \
if(::IsWindowVisible(hwnd)) \
::SendMessage(hwnd, uMsg, wParam, lParam); \
}
// Docking position helpers
inline bool IsDockedVertically(short Side) { return (Side == DOCK_LEFT) || (Side == DOCK_RIGHT); };
inline bool IsDocked(short Side) { return (Side == DOCK_TOP) || (Side == DOCK_BOTTOM) || (Side == DOCK_LEFT) || (Side == DOCK_RIGHT); };
#define DOCK_INFO_CHILD 0x1000
// Minimum size of docking pane
#define MIN_DOCKPANE_SIZE 28
// Default width/height of docking pane
#define DEFAULT_DOCKPANE_SIZE 170
// Default size of floating window rectangle
#define DEFAULT_FLOAT_SIZE 120
// The splitter size in pixels
#define DEFAULT_SPLITTER_SIZE 6
#define WM_DOCK_QUERYRECT WM_USER+840
#define WM_DOCK_QUERYTRACK WM_USER+841
#define WM_DOCK_UNDOCK WM_USER+842
#define WM_DOCK_UNFLOAT WM_USER+843
#define WM_DOCK_DOCK WM_USER+844
#define WM_DOCK_FLOAT WM_USER+845
#define WM_DOCK_UPDATELAYOUT WM_USER+846
#define WM_DOCK_REPOSITIONWINDOW WM_USER+847
#define WM_DOCK_SETSPLITTER WM_USER+848
#define WM_DOCK_CLIENT_CLOSE WM_USER+849
class CDockingPaneChildWindow;
class CFloatingWindow;
struct DOCKCONTEXT
{
HWND hwndDocked; // The docked pane
HWND hwndFloated; // The floating pane
HWND hwndChild; // The view window
HWND hwndOrigPrnt; // The original parent window
short Side; // Dock state
short LastSide; // Last dock state
RECT rcWindow; // Preferred window size
SIZE sizeFloat; // Last window size (floating)
HWND hwndRoot; // Main dock window
//
DWORD dwFlags; // Extra flags
bool bKeepSize; // Recommend using current size and avoid rescale
};
typedef CSimpleValArray<DOCKCONTEXT*> CDockMap;
struct TRACKINFO
{
HWND hWnd;
DOCKCONTEXT* pCtx;
POINT ptPos;
POINT ptStart;
RECT rc;
short Side;
};
///////////////////////////////////////////////////////
// CSplitterBar
#pragma warning(disable : 4100)
template< class T >
class CSplitterBar
{
public:
LONG m_cxySplitter;
bool m_bTracking;
bool m_bDragging;
static HCURSOR s_hVertCursor;
static HCURSOR s_hHorizCursor;
CDCHandle m_dc;
POINT m_ptStartDragPoint;
POINT m_ptEndDragPoint;
POINT m_ptDeltaDragPoint;
RECT m_rcTracker;
SIZE m_sizeTracker;
RECT m_rcTrackerBounds;
CSplitterBar() :
m_bTracking(false), m_bDragging(false)
{
if( s_hVertCursor == NULL ) {
::EnterCriticalSection(&_Module.m_csStaticDataInit);
s_hVertCursor = ::LoadCursor(NULL, IDC_SIZENS);
s_hHorizCursor = ::LoadCursor(NULL, IDC_SIZEWE);
::LeaveCriticalSection(&_Module.m_csStaticDataInit);
}
m_sizeTracker.cx = ::GetSystemMetrics(SM_CXFRAME);
m_sizeTracker.cy = ::GetSystemMetrics(SM_CYFRAME);
m_cxySplitter = DEFAULT_SPLITTER_SIZE;
}
LRESULT OnSetCursor(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
{
T* pT = static_cast<T*>(this);
DWORD dwPos = ::GetMessagePos();
POINT ptPos = { GET_X_LPARAM(dwPos), GET_Y_LPARAM(dwPos) };
pT->ScreenToClient(&ptPos);
if( ::PtInRect(&pT->m_rcSplitter, ptPos) ) return 1;
bHandled = FALSE;
return 0;
}
void DrawGhostBar()
{
ATLASSERT(!m_dc.IsNull());
RECT rect = m_rcTracker;
if( !::IsRectEmpty(&rect) ) {
// Invert the brush pattern (looks just like frame window sizing)
CBrush brush = CDCHandle::GetHalftoneBrush();
if( brush.m_hBrush != NULL ) {
ATLASSERT(!m_dc.IsNull());
CBrushHandle brushOld = m_dc.SelectBrush(brush);
m_dc.PatBlt(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, PATINVERT);
m_dc.SelectBrush(brushOld);
}
}
}
void DrawDragBar()
{
ATLASSERT(!m_dc.IsNull());
RECT rect = m_rcTracker;
if( !::IsRectEmpty(&rect) ) {
// Invert the brush pattern (looks just like frame window sizing)
CBrush brush = CDCHandle::GetHalftoneBrush();
if( brush.m_hBrush != NULL ) {
ATLASSERT(!m_dc.IsNull());
CBrushHandle brushOld = m_dc.SelectBrush(brush);
m_dc.PatBlt(rect.left + m_sizeTracker.cx, rect.top, rect.right - rect.left - (m_sizeTracker.cx * 2), m_sizeTracker.cy, PATINVERT);
m_dc.PatBlt(rect.left, rect.bottom - m_sizeTracker.cy, rect.right - rect.left, m_sizeTracker.cy, PATINVERT);
m_dc.PatBlt(rect.left, rect.top, m_sizeTracker.cx, rect.bottom - rect.top - m_sizeTracker.cy, PATINVERT);
m_dc.PatBlt(rect.right - m_sizeTracker.cx, rect.top, m_sizeTracker.cx, rect.bottom - rect.top - m_sizeTracker.cy, PATINVERT);
m_dc.SelectBrush(brushOld);
}
}
}
void DrawSplitterBar(CDCHandle dc, bool bVertical, RECT& rect)
{
if( ::IsRectEmpty(&rect) ) return;
dc.FillRect(&rect, ::GetSysColorBrush(COLOR_3DFACE));
dc.DrawEdge(&rect, EDGE_RAISED, (bVertical ? (BF_TOP|BF_BOTTOM) : (BF_LEFT|BF_RIGHT)));
}
bool PtInSplitter(POINT& pt, short Side, DWORD dwFlags, RECT& rcSplitter)
{
if( !IsDocked(Side) ) return false;
if( m_bTracking ) return false;
if( (dwFlags & DCK_NOSPLITTER) != 0 ) return false;
if( !::PtInRect(&rcSplitter, pt) ) return false;
return true;
}
// Track loop
bool Track(bool bDragging)
{
T* pT = static_cast<T*>(this);
StartTracking(bDragging);
// Get messages until capture lost or cancelled/accepted
while( ::GetCapture() == pT->m_hWnd ) {
MSG msg;
if( !::GetMessage(&msg, NULL, 0, 0) ) {
::PostQuitMessage(msg.wParam);
break;
}
switch( msg.message ) {
case WM_LBUTTONUP:
if( m_bDragging ) pT->OnEndDrag(); else pT->OnEndResize();
CancelTracking();
return true;
case WM_MOUSEMOVE:
if( m_bDragging ) pT->OnMove(msg.pt); else pT->OnStretch(msg.pt);
break;
case WM_KEYUP:
if( m_bDragging ) pT->OnKey((int) msg.wParam, false) ;
break;
case WM_KEYDOWN:
if( m_bDragging ) pT->OnKey((int) msg.wParam, true);
if( msg.wParam == VK_ESCAPE ) {
CancelTracking();
return false;
}
break;
case WM_SYSKEYDOWN:
case WM_LBUTTONDOWN:
case WM_RBUTTONDOWN:
CancelTracking();
return false;
default:
// Just dispatch rest of the messages
::DispatchMessage(&msg);
break;
}
}
CancelTracking();
return false;
}
void StartTracking(bool bDragging)
{
ATLASSERT(!m_bTracking);
T* pT = static_cast<T*>(this);
// Capture window
m_bTracking = true;
pT->SetCapture();
// Make sure no updates are pending
pT->RedrawWindow(NULL, NULL, RDW_ALLCHILDREN|RDW_UPDATENOW);
// Lock Window update while dragging over desktop
ATLASSERT(m_dc.IsNull());
HWND hWnd = ::GetDesktopWindow();
m_dc = ::GetDCEx(hWnd, NULL, ::LockWindowUpdate(hWnd) ? DCX_WINDOW|DCX_CACHE|DCX_LOCKWINDOWUPDATE : DCX_WINDOW|DCX_CACHE);
ATLASSERT(!m_dc.IsNull());
// Draw the initial focus rect
m_bDragging = bDragging;
if( m_bDragging ) DrawDragBar(); else DrawGhostBar();
return;
}
void CancelTracking()
{
ATLASSERT(m_bTracking);
if( !m_bTracking ) return;
// Erase the focus rect
if( m_bDragging ) DrawDragBar(); else DrawGhostBar();
// Let window updates free
::LockWindowUpdate(NULL);
HWND hWnd = ::GetDesktopWindow();
if( !m_dc.IsNull() ) ::ReleaseDC(hWnd, m_dc.Detach());
// Release the capture
::ReleaseCapture();
m_bTracking = false;
}
// Overridables
void OnEndDrag() { };
void OnEndResize() { };
void OnKey(int nCode, bool bDown) { };
void OnMove(POINT& pt) { };
void OnStretch(POINT& pt) { };
};
template<class T> HCURSOR CSplitterBar<T>::s_hVertCursor = NULL;
template<class T> HCURSOR CSplitterBar<T>::s_hHorizCursor = NULL;
#pragma warning(default : 4100)
///////////////////////////////////////////////////////
// CFloatingWindow
typedef CWinTraits<WS_OVERLAPPED|WS_CAPTION|WS_THICKFRAME|WS_SYSMENU, WS_EX_TOOLWINDOW|WS_EX_WINDOWEDGE> CFloatWinTraits;
template< class T, class TBase = CWindow, class TWinTraits = CFloatWinTraits >
class ATL_NO_VTABLE CFloatingWindowImpl :
public CWindowImpl< T, TBase, TWinTraits >,
public CSplitterBar<CFloatingWindowImpl>
{
public:
DECLARE_WND_CLASS_EX(NULL, CS_DBLCLKS, NULL)
typedef CFloatingWindowImpl< T , TBase, TWinTraits > thisClass;
BEGIN_MSG_MAP(CFloatingWindowImpl)
MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
MESSAGE_HANDLER(WM_SIZE, OnSize)
MESSAGE_HANDLER(WM_SYSCOMMAND, OnSysCommand)
MESSAGE_HANDLER(WM_MENUCHAR, OnMenuChar)
MESSAGE_HANDLER(WM_GETMINMAXINFO, OnMsgForward)
MESSAGE_HANDLER(WM_DOCK_UPDATELAYOUT, OnSize)
MESSAGE_HANDLER(WM_NCACTIVATE, OnNcActivate)
MESSAGE_HANDLER(WM_NCLBUTTONDOWN, OnLeftButtonDown)
MESSAGE_HANDLER(WM_NCRBUTTONDOWN, OnRightButtonDown)
MESSAGE_HANDLER(WM_NCLBUTTONDBLCLK, OnButtonDblClick)
END_MSG_MAP()
DOCKCONTEXT* m_pCtx;
CFloatingWindowImpl(DOCKCONTEXT* pCtx) :
m_pCtx(pCtx)
{
}
HWND Create(HWND hWndParent, RECT& rcPos, LPCTSTR szWindowName = NULL,
DWORD dwStyle = 0, DWORD dwExStyle = 0,
UINT nID = 0, LPVOID lpCreateParam = NULL)
{
ATLASSERT(m_pCtx);
if( m_pCtx->dwFlags & DCK_NOHIDE ) dwStyle = T::GetWndStyle(dwStyle) & ~WS_SYSMENU;
return CWindowImpl< T, TBase, TWinTraits >::Create(hWndParent, rcPos, szWindowName, dwStyle, dwExStyle, nID, lpCreateParam);
}
virtual void OnFinalMessage(HWND /*hWnd*/)
{
delete (T*) this;
}
// Message handlers
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;
}
LRESULT OnNcActivate(UINT uMsg, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)
{
return DefWindowProc(uMsg, IsWindowEnabled(), lParam);
}
LRESULT OnLeftButtonDown(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
SetFocus();
if( wParam == HTCAPTION ) {
// Get cursor point and start a tracking look
POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
m_ptStartDragPoint = m_ptEndDragPoint = pt;
GetWindowRect(&m_rcTracker);
// Enter tracking loop
bool res = Track(true);
if( res ) {
// Determine if we landed over a docking pane or just moved around...
TRACKINFO ti = { m_hWnd, m_pCtx, m_ptEndDragPoint.x, m_ptEndDragPoint.y, m_ptStartDragPoint.x, m_ptStartDragPoint.y };
::SendMessage(m_pCtx->hwndRoot, WM_DOCK_QUERYTRACK, 0, (LPARAM) &ti);
if( ti.Side == DOCK_FLOAT ) {
MoveWindow(&ti.rc, TRUE);
}
else {
::SendMessage(m_pCtx->hwndRoot, WM_DOCK_UNFLOAT, 0, (LPARAM) m_pCtx);
::SendMessage(m_pCtx->hwndRoot, WM_DOCK_DOCK, ti.Side, (LPARAM) m_pCtx);
}
return 0;
}
return 1;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -