📄 atldock.h
字号:
if( ti.Side==DOCK_FLOAT ) {
MoveWindow(&ti.rc, TRUE);
}
else {
::SendMessage(m_ctx->hwndRoot, WM_DOCK_UNFLOAT, 0, (LPARAM)m_ctx);
::SendMessage(m_ctx->hwndRoot, WM_DOCK_DOCK, ti.Side, (LPARAM)m_ctx);
}
return 0;
}
return 1;
}
bHandled = FALSE;
return 0;
}
LRESULT OnRightButtonDown(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
{
if( wParam==HTCAPTION ) return 1;
bHandled = FALSE;
return 0;
}
LRESULT OnButtonDblClick(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
{
if( wParam==HTCAPTION ) return 1;
bHandled = FALSE;
return 0;
}
LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
return 1; // handled, no background painting needed
}
LRESULT OnSysCommand(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
{
switch( wParam & 0xFFF0 ) {
case SC_CLOSE:
if( m_ctx->dwFlags & DCK_NOHIDE ) return 0;
::SendMessage(m_ctx->hwndRoot, WM_DOCK_UNFLOAT, 0, (LPARAM)m_ctx);
return 0;
}
bHandled = FALSE;
return 0;
}
LRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
T* pT = static_cast<T*>(this);
pT->UpdateLayout();
return 0;
}
void OnMove(POINT &pt)
{
TRACKINFO ti = { m_hWnd, m_ctx, pt.x, pt.y, m_ptStartDragPoint.x, m_ptStartDragPoint.y };
::SendMessage(m_ctx->hwndRoot, WM_DOCK_QUERYTRACK, 0, (LPARAM)&ti);
if( !::EqualRect(&m_rcTracker, &ti.rc) ) {
DrawDragBar();
m_rcTracker = ti.rc;
DrawDragBar();
}
m_ptEndDragPoint = pt;
}
// Overridables
void UpdateLayout()
{
RECT rc;
GetWindowRect(&rc);
m_ctx->sizeFloat.cx = rc.right-rc.left;
m_ctx->sizeFloat.cy = rc.bottom-rc.top;
GetClientRect(&rc);
::SetWindowPos(m_ctx->hwndChild, NULL, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, SWP_NOZORDER);
}
};
class CFloatingWindow : public CFloatingWindowImpl<CFloatingWindow>
{
public:
DECLARE_WND_CLASS_EX(_T("WTL_FloatingWindow"), CS_DBLCLKS, NULL)
CFloatingWindow(DOCKCONTEXT *ctx) :
CFloatingWindowImpl<CFloatingWindow>(ctx)
{
}
};
///////////////////////////////////////////////////////
// CDockingPaneChildWindow
template <class T, class TBase = CWindow, class TWinTraits = CControlWinTraits>
class ATL_NO_VTABLE CDockingPaneChildWindowImpl :
public CWindowImpl< T, TBase, TWinTraits >,
public CSplitterBar<CDockingPaneChildWindowImpl< T , TBase, TWinTraits > >
{
public:
DECLARE_WND_CLASS_EX(NULL, CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS, NULL)
typedef CDockingPaneChildWindowImpl< T , TBase, TWinTraits > thisClass;
BEGIN_MSG_MAP(thisClass)
MESSAGE_HANDLER(WM_PAINT, OnPaint)
MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
MESSAGE_HANDLER(WM_SETCURSOR, OnSetCursor)
MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove)
MESSAGE_HANDLER(WM_LBUTTONDOWN, OnButtonDown)
MESSAGE_HANDLER(WM_LBUTTONUP, OnButtonUp)
MESSAGE_HANDLER(WM_SIZE, OnSize)
MESSAGE_HANDLER(WM_DOCK_UPDATELAYOUT, OnSize)
MESSAGE_HANDLER(WM_DOCK_SETSPLITTER, OnSetSplitter)
END_MSG_MAP()
DOCKCONTEXT *m_ctx;
RECT m_rcChild;
RECT m_rcSplitter;
RECT m_rcGripper;
RECT m_rcCloseButton;
int m_cxyGripper;
int m_cxyCloseButton;
bool m_fCloseCapture;
bool m_fCloseDown;
CDockingPaneChildWindowImpl(DOCKCONTEXT *ctx) :
m_ctx(ctx), m_fCloseDown(false), m_fCloseCapture(false)
{
::SetRectEmpty(&m_rcChild);
::SetRectEmpty(&m_rcGripper);
::SetRectEmpty(&m_rcSplitter);
::SetRectEmpty(&m_rcCloseButton);
//m_cxyGripper = ::GetSystemMetrics(SM_CYCAPTION)*4/5;
//m_cxyCloseButton = m_cxyGripper-2;
m_cxyGripper = ::GetSystemMetrics(SM_CYSMCAPTION);
m_cxyCloseButton = ::GetSystemMetrics(SM_CYSMSIZE)-4;
}
virtual void OnFinalMessage(HWND /*hWnd*/)
{
delete this;
}
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 OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
T* pT = static_cast<T*>(this);
CPaintDC dc(m_hWnd);
dc.ExcludeClipRect(&m_rcChild);
RECT rc;
GetClientRect(&rc);
dc.IntersectClipRect(&rc);
dc.FillRect(&rc, (HBRUSH)LongToPtr(COLOR_3DFACE + 1));
short Side = m_ctx->Side;
bool bVertical = IsDockedVertically(Side);
if( m_cxySplitter>0 ) pT->DrawSplitterBar(dc.m_hDC, bVertical, m_rcSplitter);
pT->DrawGripperBar(dc.m_hDC, Side, m_rcGripper, m_rcCloseButton, m_fCloseDown);
pT->DrawPaneFrame(dc.m_hDC, Side, rc);
return 0;
}
LRESULT OnMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
{
POINT ptPos = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
if( m_fCloseCapture ) {
bool fCloseDown = ::PtInRect(&m_rcCloseButton, ptPos)==TRUE;
if( m_fCloseDown!=fCloseDown ) {
m_fCloseDown = fCloseDown;
InvalidateRect(&m_rcCloseButton);
}
}
else if( PtInSplitter(ptPos, m_ctx->Side, m_ctx->dwFlags, m_rcSplitter) ) {
bool bVertical = IsDockedVertically(m_ctx->Side);
::SetCursor( bVertical ? m_hVertCursor : m_hHorizCursor);
bHandled = FALSE;
}
return 0;
}
LRESULT OnButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)
{
POINT ptPos = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
if( ::PtInRect(&m_rcCloseButton, ptPos) ) {
m_fCloseCapture = m_fCloseDown = true;
InvalidateRect(&m_rcCloseButton);
SetCapture();
}
else if( PtInSplitter(ptPos, m_ctx->Side, m_ctx->dwFlags, m_rcSplitter) ) {
::ClientToScreen(m_hWnd, &ptPos);
m_ptStartDragPoint = m_ptEndDragPoint = m_ptDeltaDragPoint = ptPos;
//
RECT rcWin;
GetWindowRect(&rcWin);
m_rcTracker = m_rcSplitter;
::OffsetRect(&m_rcTracker, rcWin.left, rcWin.top);
//
::GetWindowRect(::GetParent(m_hWnd), &m_rcTrackerBounds);
::InflateRect(&m_rcTrackerBounds, -MIN_DOCKPANE_SIZE, -MIN_DOCKPANE_SIZE);
//
bool res = Track(false);
if( res ) {
if( IsDockedVertically(m_ctx->Side) ) {
m_ctx->rcWindow.bottom += m_ptEndDragPoint.y - m_ptStartDragPoint.y;
}
else {
m_ctx->rcWindow.right += m_ptEndDragPoint.x - m_ptStartDragPoint.x;
}
m_ctx->bKeepSize = true;
::SendMessage(GetParent(), WM_DOCK_UPDATELAYOUT, 0,0);
}
}
else if( ::PtInRect(&m_rcGripper, ptPos) ) {
::ClientToScreen(m_hWnd, &ptPos);
m_ptStartDragPoint = m_ptEndDragPoint = m_ptDeltaDragPoint = ptPos;
GetWindowRect(&m_rcTracker);
bool res = Track(true);
if( res ) {
TRACKINFO ti = { m_hWnd, m_ctx, m_ptEndDragPoint.x, m_ptEndDragPoint.y, m_ptStartDragPoint.x, m_ptStartDragPoint.y };
::SendMessage(m_ctx->hwndRoot, WM_DOCK_QUERYTRACK, 0, (LPARAM)&ti);
if( ti.Side == m_ctx->Side ) {
RECT rc;
GetWindowRect(&rc);
if( !::PtInRect(&rc, m_ptEndDragPoint) ) ::SendMessage(m_ctx->hwndRoot, WM_DOCK_REPOSITIONWINDOW, 0, (LPARAM)m_ctx);
}
else {
::SendMessage(m_ctx->hwndRoot, WM_DOCK_UNDOCK, 0, (LPARAM)m_ctx);
if( ti.Side==DOCK_FLOAT ) m_ctx->rcWindow = ti.rc;
::SendMessage(m_ctx->hwndRoot, ti.Side==DOCK_FLOAT ? WM_DOCK_FLOAT : WM_DOCK_DOCK, ti.Side, (LPARAM)m_ctx);
}
}
}
return 0;
}
LRESULT OnButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)
{
if( m_fCloseCapture ) {
m_fCloseCapture = m_fCloseDown = false;
::ReleaseCapture();
InvalidateRect(&m_rcCloseButton);
POINT ptPos = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
if( ::PtInRect(&m_rcCloseButton, ptPos) ) {
::SendMessage(m_ctx->hwndRoot, WM_DOCK_UNDOCK, 0, (LPARAM)m_ctx);
}
}
return 0;
}
void OnMove(POINT &pt)
{
TRACKINFO ti = { m_hWnd, m_ctx, pt.x, pt.y, m_ptStartDragPoint.x, m_ptStartDragPoint.y };
::SendMessage(m_ctx->hwndRoot, WM_DOCK_QUERYTRACK, 0, (LPARAM)&ti);
if( !::EqualRect(&m_rcTracker, &ti.rc) ) {
DrawDragBar();
m_rcTracker = ti.rc;
DrawDragBar();
}
m_ptDeltaDragPoint = pt;
}
void OnStretch(POINT &pt)
{
DrawGhostBar();
if( IsDockedVertically(m_ctx->Side) ) {
int nOffset = pt.y - m_ptDeltaDragPoint.y;
if( m_rcTracker.top + nOffset <= m_rcTrackerBounds.top ) nOffset = m_rcTrackerBounds.top - m_rcTracker.top;
if( m_rcTracker.bottom + nOffset >= m_rcTrackerBounds.bottom ) nOffset = m_rcTrackerBounds.bottom - m_rcTracker.bottom;
::OffsetRect(&m_rcTracker, 0,nOffset);
m_ptDeltaDragPoint.y += nOffset;
}
else {
int nOffset = pt.x - m_ptDeltaDragPoint.x;
if( m_rcTracker.left + nOffset <= m_rcTrackerBounds.left ) nOffset = m_rcTrackerBounds.left - m_rcTracker.left;
if( m_rcTracker.right + nOffset >= m_rcTrackerBounds.right ) nOffset = m_rcTrackerBounds.right - m_rcTracker.right;
::OffsetRect(&m_rcTracker, nOffset,0);
m_ptDeltaDragPoint.x += nOffset;
}
DrawGhostBar();
}
void OnEndResize()
{
m_ptEndDragPoint = m_ptDeltaDragPoint;
}
void OnEndDrag()
{
m_ptEndDragPoint = m_ptDeltaDragPoint;
}
LRESULT OnSetSplitter(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
m_cxySplitter = wParam;
return 0;
}
// Overridables
void UpdateLayout()
{
const int CHILD_GAP = 4;
bool bVertical = IsDockedVertically(m_ctx->Side);
// Reposition splitter and gripper bars
RECT rect;
GetClientRect(&rect);
if( bVertical ) {
int nGap = 0;
if( (m_ctx->dwFlags & DCK_NOHIDE)==0 ) {
nGap = CHILD_GAP + m_cxyCloseButton;
m_rcCloseButton.left = rect.right-nGap;
m_rcCloseButton.top = rect.top + 2 + (m_cxyGripper-m_cxyCloseButton)/2;
m_rcCloseButton.right = m_rcCloseButton.left + m_cxyCloseButton;
m_rcCloseButton.bottom = m_rcCloseButton.top + m_cxyCloseButton;
}
::SetRect(&m_rcGripper, rect.left, rect.top, rect.right-nGap, rect.top+m_cxyGripper);
::SetRect(&m_rcSplitter, rect.left, rect.bottom-m_cxySplitter, rect.right, rect.bottom);
rect.top += m_cxyGripper;
rect.bottom -= m_cxySplitter;
}
else {
int nGap = 0;
if( (m_ctx->dwFlags & DCK_NOHIDE)==0 ) {
nGap = CHILD_GAP + m_cxyCloseButton;
m_rcCloseButton.left = rect.left + 4;
m_rcCloseButton.top = rect.top + 2 + (m_cxyGripper-m_cxyCloseButton)/2;
m_rcCloseButton.right = m_rcCloseButton.left + m_cxyCloseButton;
m_rcCloseButton.bottom = m_rcCloseButton.top + m_cxyCloseButton;
}
::SetRect(&m_rcGripper, rect.left, rect.top+nGap, rect.left+m_cxyGripper, rect.bottom);
::SetRect(&m_rcSplitter, rect.right-m_cxySplitter, rect.top, rect.right, rect.bottom);
rect.left += m_cxyGripper;
rect.right -= m_cxySplitter;
}
// Calculate the client window area
::InflateRect(&rect, -CHILD_GAP, -CHILD_GAP);
m_rcChild = rect;
::SetWindowPos(m_ctx->hwndChild, NULL, m_rcChild.left, m_rcChild.top, m_rcChild.right-m_rcChild.left, m_rcChild.bottom-m_rcChild.top, SWP_NOZORDER | SWP_NOACTIVATE);
}
void DrawPaneFrame(CDCHandle /*dc*/, short /*Side*/, RECT& /*rc*/)
{
}
void DrawGripperBar(CDCHandle dc, short Side, RECT &rcBar, RECT &rcCloseButton, bool bCloseDown)
{
if( ::IsRectEmpty(&rcBar) ) return;
const int INSET = 4;
const int LINE_GAP = 4;
bool bVertical = IsDockedVertically(Side);
RECT rcLine;
if( bVertical ) {
::SetRect(&rcLine, rcBar.left+INSET, rcBar.top+6, rcBar.right-INSET, rcBar.top+8);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -