// Copyright (c) 2002
// Sergey Klimov (kidd@ukr.net)
// WTL Docking windows
//
// This code is provided "as is", with absolutely no warranty expressed
// or implied. Any use is at your own risk.
//
// This code may be used in compiled form in any way you desire. This
// file may be redistributed unmodified 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. If
// the source code in this file is used in any commercial application
// then a simple email woulod be nice.
#if !defined(AFX_DOCKINGWINDOW_H__B52D9183_DF95_4DCD_8A16_937836FA5F06__INCLUDED_)
#define AFX_DOCKINGWINDOW_H__B52D9183_DF95_4DCD_8A16_937836FA5F06__INCLUDED_
#include <DDTracker.h>
namespace dockwins{
class CDocker : protected CWindow
{
public:
explicit CDocker(HWND hWnd=NULL) : CWindow(hWnd)
{
}
bool AdjustDragRect(DFDOCKRECT* pHdr) const
{
pHdr->hdr.code=DC_ADJUSTDRAGRECT;
return (::SendMessage(m_hWnd,WMDF_DOCK,NULL,reinterpret_cast<LPARAM>(pHdr))!=FALSE);
}
bool AcceptDock(DFDOCKRECT* pHdr) const
{
pHdr->hdr.code=DC_ACCEPT;
return (::SendMessage(m_hWnd,WMDF_DOCK,NULL,reinterpret_cast<LPARAM>(pHdr))!=FALSE);
}
bool Dock(DFDOCKRECT* pHdr) const
{
pHdr->hdr.code=DC_DOCK;
// return (::SendMessage(m_hWnd,WMDF_DOCK,NULL,reinterpret_cast<LPARAM>(pHdr))!=FALSE);
return (::SendMessage(pHdr->hdr.hBar,WMDF_DOCK,NULL,reinterpret_cast<LPARAM>(pHdr))!=FALSE);
}
bool Undock(DFMHDR* pHdr)
{
pHdr->code=DC_UNDOCK;
return (::SendMessage(pHdr->hBar,WMDF_DOCK,NULL,reinterpret_cast<LPARAM>(pHdr))!=FALSE);
}
bool Replace(DFDOCKREPLACE* pHdr) const
{
pHdr->hdr.code=DC_REPLACE;
return (::SendMessage(pHdr->hdr.hBar,WMDF_DOCK,NULL,reinterpret_cast<LPARAM>(pHdr))!=FALSE);
}
bool GetDockingPosition(DFDOCKPOS* pHdr) const
{
pHdr->hdr.code=DC_GETDOCKPOSITION;
return (::SendMessage(m_hWnd,WMDF_DOCK,NULL,reinterpret_cast<LPARAM>(pHdr))!=FALSE);
}
bool SetDockingPosition(DFDOCKPOS* pHdr) const
{
pHdr->hdr.hBar=m_hWnd;
pHdr->hdr.code=DC_SETDOCKPOSITION;
return (::SendMessage(m_hWnd,WMDF_DOCK,NULL,reinterpret_cast<LPARAM>(pHdr))!=FALSE);
}
operator HWND ()
{
return m_hWnd;
}
};
template < DWORD t_dwStyle = 0, DWORD t_dwExStyle = 0>
struct CDockingBarWinTraits : CWinTraits<t_dwStyle,t_dwExStyle>
{
typedef dockwins::CDocker CDocker;
};
typedef CDockingBarWinTraits<WS_OVERLAPPEDWINDOW| WS_POPUP/* WS_CHILD*/ | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,WS_EX_TOOLWINDOW/* WS_EX_CLIENTEDGE*/> CSimpleDockingBarWinTraits;
template <class T,
class TBase = CWindow,
class TWinTraits = CSimpleDockingBarWinTraits>
class ATL_NO_VTABLE CDockingWindowBaseImpl : public CWindowImpl< T, TBase, TWinTraits >
{
typedef CWindowImpl< T, TBase, TWinTraits > baseClass;
typedef CDockingWindowBaseImpl< T, TBase, TWinTraits > thisClass;
typedef TWinTraits::CDocker CDocker;
protected:
class CGhostMoveTracker : public CDDTrackerBaseT<CGhostMoveTracker>
{
//probably better use GetSystemMetrics
enum{GhostRectSideSize=3};
public:
CGhostMoveTracker(const CDocker& docker,const POINT& pt,DFDOCKRECT& dockHdr)
:m_docker(docker),m_dockHdr(dockHdr),m_dc(::GetWindowDC(NULL))
{
m_offset.cx=m_dockHdr.rect.left-pt.x;
m_offset.cy=m_dockHdr.rect.top-pt.y;
m_size.cx=m_dockHdr.rect.right-m_dockHdr.rect.left;
m_size.cy=m_dockHdr.rect.bottom-m_dockHdr.rect.top;
}
void DrawGhostRect(CDC& dc,RECT* pRect)
{
CBrush brush = CDCHandle::GetHalftoneBrush();
if(brush.m_hBrush != NULL)
{
HBRUSH hBrushOld = dc.SelectBrush(brush);
dc.PatBlt(pRect->left, pRect->top,
pRect->right-pRect->left,GhostRectSideSize, PATINVERT);
dc.PatBlt(pRect->left, pRect->bottom-GhostRectSideSize,
pRect->right-pRect->left,GhostRectSideSize, PATINVERT);
dc.PatBlt(pRect->left, pRect->top+GhostRectSideSize,
GhostRectSideSize,pRect->bottom-pRect->top-2*GhostRectSideSize, PATINVERT);
dc.PatBlt(pRect->right-GhostRectSideSize, pRect->top+GhostRectSideSize,
GhostRectSideSize,pRect->bottom-pRect->top-2*GhostRectSideSize, PATINVERT);
dc.SelectBrush(hBrushOld);
}
}
void CleanGhostRect(CDC& dc,RECT* pRect)
{
DrawGhostRect(dc,pRect);
}
void BeginDrag()
{
DrawGhostRect(m_dc,&m_dockHdr.rect);
}
void EndDrag(bool /*bCanceled*/)
{
CleanGhostRect(m_dc,&m_dockHdr.rect);
}
void OnMove(long x, long y)
{
CleanGhostRect(m_dc,&m_dockHdr.rect);
m_dockHdr.rect.left=x;
m_dockHdr.rect.top=y;
::ClientToScreen(m_dockHdr.hdr.hWnd,reinterpret_cast<POINT*>(&m_dockHdr.rect));
m_dockHdr.rect.right=m_dockHdr.rect.left+m_size.cx;
m_dockHdr.rect.bottom=m_dockHdr.rect.top+m_size.cy;
m_docker.AdjustDragRect(&m_dockHdr);
if((GetKeyState(VK_CONTROL) & 0x80000000) || !m_docker.AcceptDock(&m_dockHdr))
{
m_dockHdr.hdr.hBar=HNONDOCKBAR;
m_dockHdr.rect.left=x+m_offset.cx;
m_dockHdr.rect.top=y+m_offset.cy;
m_dockHdr.rect.right=m_dockHdr.rect.left+m_size.cx;
m_dockHdr.rect.bottom=m_dockHdr.rect.top+m_size.cy;
}
DrawGhostRect(m_dc,&m_dockHdr.rect);
}
bool ProcessWindowMessage(MSG* pMsg)
{
bool bHandled=false;
switch(pMsg->message)
{
case WM_KEYDOWN:
case WM_KEYUP:
if(pMsg->wParam==VK_CONTROL)
{
CPoint point(pMsg->pt.x,pMsg->pt.y);
::ScreenToClient(m_dockHdr.hdr.hWnd,&point);
OnMove(point.x,point.y);
bHandled=true;
}
break;
}
return bHandled;
}
protected:
const CDocker& m_docker;
CDC m_dc;
DFDOCKRECT& m_dockHdr;
SIZE m_size;
SIZE m_offset;
};
public:
CDockingWindowBaseImpl()
:m_hBarOwner(HNONDOCKBAR)
{
m_rcUndock.SetRectEmpty();
}
HWND Create(HWND hDockingFrameWnd, RECT& rcPos, LPCTSTR szWindowName = NULL,
DWORD dwStyle = 0, DWORD dwExStyle = 0,
UINT nID = 0, LPVOID lpCreateParam = NULL)
{
m_docker=CDocker(hDockingFrameWnd);
return baseClass::Create(hDockingFrameWnd, rcPos, szWindowName ,
dwStyle , dwExStyle , nID , lpCreateParam);
}
HDOCKBAR GetOwnerDockingBar() const
{
return m_hBarOwner;
}
bool GetDockingPosition(DFDOCKPOS* pHdr) const
{
bool bRes=true;
pHdr->hdr.hBar=GetOwnerDockingBar();
if(IsDocking())
{
pHdr->hdr.hWnd=m_hWnd;
// pHdr->hdr.code=DC_GETDOCKPOSITION;
bRes=m_docker.GetDockingPosition(pHdr);
}
return bRes;
}
bool GetDockingWindowPlacement(DFDOCKPOSEX* pHdr) const
{
bool bRes=true;
pHdr->bDocking=IsDocking();
if(pHdr->bDocking)
{
::CopyRect(&pHdr->rect,&m_rcUndock);
bRes=GetDockingPosition(&(pHdr->dockPos));
}
else
GetWindowRect(&pHdr->rect);
return bRes;
}
bool SetDockingPosition(DFDOCKPOS* pHdr)
{
if(IsDocking())
Undock();
pHdr->hdr.hWnd=m_hWnd;
// pHdr->hdr.code=DC_SETDOCKPOSITION;
return m_docker.SetDockingPosition(pHdr);
}
bool SetDockingWindowPlacement(DFDOCKPOSEX* pHdr)
{
bool bRes=true;
if(pHdr->bDocking)
{
bRes=SetDockingPosition(&(pHdr->dockPos));
::CopyRect(&m_rcUndock,&pHdr->rect);
}
else
{
if(IsDocking())
Undock();
bRes=(SetWindowPos(HWND_TOP,&(pHdr->rect),SWP_SHOWWINDOW | SWP_NOACTIVATE)!=FALSE);
}
return bRes;
}
bool IsDocking() const
{
return GetOwnerDockingBar()!=HNONDOCKBAR;
}
bool Float(LPCRECT pRc,UINT flags=SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_FRAMECHANGED,HWND hWndInsertAfter=HWND_TOP)
{
bool bRes=IsDocking();
if(bRes)
{
if(Undock())
bRes=(SetWindowPos(hWndInsertAfter,pRc,flags)!=FALSE);
}
return bRes;
}
bool Float()
{
bool bRes=!m_rcUndock.IsRectEmpty();
if(bRes)
bRes=Float(&m_rcUndock);
return bRes;
}
virtual bool Undock()
{
assert(IsDocking());
DFMHDR dockHdr;
// dockHdr.code=DC_UNDOCK;
dockHdr.hWnd=m_hWnd;
dockHdr.hBar=GetOwnerDockingBar();
return m_docker.Undock(&dockHdr);
}
bool OnClosing()
{
bool bRes=true;
if(IsDocking())
bRes=Undock();
return bRes;
}
virtual bool DockMe(DFDOCKRECT* pHdr)
{
return m_docker.Dock(pHdr);
}
bool BeginMoving(const POINT& point)
{
DFDOCKRECT dockHdr;
// dockHdr.hdr.code=DC_ACCEPT;
dockHdr.hdr.hWnd=m_hWnd;
dockHdr.hdr.hBar=HNONDOCKBAR;//GetOwnerDockingBar();
if(m_rcUndock.IsRectEmpty())
{
GetWindowRect(&dockHdr.rect);
// dockHdr.hdr.code=DC_ADJUSTDRAGRECT;
m_docker.AdjustDragRect(&dockHdr);
m_rcUndock.CopyRect(&dockHdr.rect);
}
GetWindowRect(&dockHdr.rect);
CPoint pt(point);
ClientToScreen(&pt);
float ratio=float(pt.x-dockHdr.rect.left)/(dockHdr.rect.right-dockHdr.rect.left);
dockHdr.rect.left=pt.x-long(ratio*m_rcUndock.Width());
ratio=float(pt.y-dockHdr.rect.top)/(dockHdr.rect.bottom-dockHdr.rect.top);
dockHdr.rect.top=pt.y-long(ratio*m_rcUndock.Height());
dockHdr.rect.right=dockHdr.rect.left+m_rcUndock.Width();
dockHdr.rect.bottom=dockHdr.rect.top+m_rcUndock.Height();
CGhostMoveTracker tracker(m_docker,point,dockHdr);
if(TrackDragAndDrop(tracker,m_hWnd))
{
CPoint ptCur;
::GetCursorPos(&ptCur);
if((dockHdr.hdr.hBar!=HNONDOCKBAR)
|| (ptCur.x!=pt.x) || (ptCur.y!=pt.y))
{
if(IsDocking())
Undock();
if(dockHdr.hdr.hBar!=HNONDOCKBAR)
// m_docker.Dock(&dockHdr);
DockMe(&dockHdr);
else
SetWindowPos(HWND_TOP,&(dockHdr.rect),SWP_SHOWWINDOW | SWP_FRAMECHANGED);
}
}
return true;
}
void OnDocked(HDOCKBAR hBar,bool /*bHorizontal*/)
{
assert(!IsDocking());
m_hBarOwner=hBar;
}
void OnUndocked(HDOCKBAR /*hBar*/)
{
assert(IsDocking());
m_hBarOwner=HNONDOCKBAR;
}
////////////////messages handlers/////////////////////////////////
BEGIN_MSG_MAP(thisClass)
MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
MESSAGE_HANDLER(WM_CLOSE, OnClose)
MESSAGE_HANDLER(WM_NCLBUTTONDOWN,OnNcLButtonDown)
MESSAGE_HANDLER(WM_WINDOWPOSCHANGED, OnWindowPosChanged)
MESSAGE_HANDLER(WMDF_NDOCKSTATECHANGED,OnDockStateChanged)
END_MSG_MAP()
LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
return 1;
}
LRESULT OnWindowPosChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
{
LPWINDOWPOS pWPos=reinterpret_cast<LPWINDOWPOS>(lParam);
if(
(pWPos->flags&SWP_SHOWWINDOW
|| ((pWPos->flags&(SWP_NOSIZE | SWP_NOMOVE))!=(SWP_NOSIZE | SWP_NOMOVE)))
&& !IsDocking()
&& IsWindowVisible()
/*&& !(pWPos->flags&SWP_HIDEWINDOW)*/)
{
m_rcUndock.left=pWPos->x;
m_rcUndock.top=pWPos->y;
m_rcUndock.right=m_rcUndock.left+pWPos->cx;
m_rcUndock.bottom=m_rcUndock.top+pWPos->cy;
}
bHandled = FALSE;
return 0;
}
LRESULT OnClose(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM/* lParam*/, BOOL& bHandled)
{
T* pThis=reinterpret_cast<T*>(this);
bHandled=!pThis->OnClosing();
return !bHandled;
}
LRESULT OnNcLButtonDown(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
bHandled=(wParam==HTCAPTION);
if(bHandled)
{
POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
if(::DragDetect(m_hWnd,pt))
{
T* pThis=static_cast<T*>(this);
pThis->ScreenToClient(&pt);
pThis->BeginMoving(pt);
}
}
return 0;
}
LRESULT OnDockStateChanged(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
{
T* pThis=static_cast<T*>(this);
if(wParam!=FALSE)
pThis->OnDocked(reinterpret_cast<HDOCKBAR>(lParam),(DOCKED2HORIZONTAL(wParam)==TRUE));
else
pThis->OnUndocked(reinterpret_cast<HDOCKBAR>(lParam));
return TRUE;
}
protected:
CDocker m_docker;
HDOCKBAR m_hBarOwner;
CRect m_rcUndock;
};
template<class T>
class CDockingWindowPlacement : public DFDOCKPOS
{
public:
CDockingWindowPlacement(T& dw)
:m_dw(dw)
{
hdr.hBar=HNONDOCKBAR;
}
bool IsVisible() const
{
assert(::IsWindow(dw.m_hWnd));
return (m_dw.IsWindowVisible()!=FALSE);
}
bool IsDocking() const
{
assert(::IsWindow(dw.m_hWnd));
return m_dw.IsDocking();
}
bool Hide()
{
assert(::IsWindow(dw.m_hWnd));
bool bRes=true;
if(m_dw.IsDocking())
{
bRes=m_dw.GetDockingPosition(this);
assert(bRes);
if(bRes)
bRes=m_dw.Undock();
assert(bRes);
}
else
hdr.hBar=HNONDOCKBAR;
return (bRes && m_dw.ShowWindow(SW_HIDE));
}
bool Show()
{
assert(::IsWindow(dw.m_hWnd));
bool bRes=true;
if(hdr.hBar!=HNONDOCKBAR)
bRes=m_dw.SetDockingPosition(this);
else
m_dw.ShowWindow(SW_SHOW);
assert(bRes);
return bRes;
}
CDockingWindowPlacement& operator = (const DFDOCKPOS& pos)
{
dwDockSide=pos.dwDockSide;
nBar=pos.nBar;
fPctPos=pos.fPctPos;
nWidth=pos.nWidth;
nHeight=pos.nHeight;
return *this;
}
protected:
T& m_dw;
};
class CCaptionBase : public COrientedRect
{
typedef COrientedRect baseClass;
public:
struct CButton: CRect
{
virtual void CalculateRect(CRect& rc,bool bHorizontal)=0;
virtual void Draw (CDC& dc)=0;
virtual void Press(HWND /*hWnd*/){};
virtual void Release(HWND /*hWnd*/){};
virtual void Hot(HWND /*hWnd*/){}
};
class CBtnClickTracker : public CDDTrackerBaseT<CBtnClickTracker>
{
public:
CBtnClickTracker(HWND hWnd,CButton& btn)
:m_hWnd(hWnd),m_btn(btn)
{
}
void BeginDrag()
{
m_btn.Press(m_hWnd);
}
void EndDrag(bool /*bCanceled*/)
{
m_btn.Release(m_hWnd);
}
protected:
HWND m_hWnd;
CButton& m_btn;
};
protected:
template<class T>
class CHotBtnTracker : public CDDTrackerBaseT<CHotBtnTracker<T> >
{
public:
CHotBtnTracker(CButton& btn,T& owner,HWND hWnd,int nHotHitTest)
:m_btn(btn),m_owner(owner),m_hWnd(hWnd),m_nHotHitTest(nHotHitTest),m_bDoAction(false)
{
CRect rc;
::GetClientRect(m_hWnd,&rc);
m_offset.x=rc.left;
m_offset.y=rc.top;
::ClientToScreen(m_hWnd,&m_offset);
::GetWindowRect(hWnd,&rc);
m_offset.x-=rc.left;
m_offset.y-=rc.top;
}
void BeginDrag()
{
m_btn.Hot(m_hWnd);
}
void EndDrag(bool /*bCanceled*/)
{
m_btn.Release(m_hWnd);
}
void OnDropLeftButton(long x, long y)
{
CPoint pt(x+m_offset.x,y+m_offset.y);
m_bDoAction=(m_owner.HitTest(pt)==m_nHotHitTest);
}
void OnMove(long x, long y)
{
CPoint pt(x+m_offset.x,y+m_offset.y);
if(m_owner.HitTest(pt)!=m_nHotHitTest)
::ReleaseCapture();
}
bool ProcessWindowMessage(MSG* pMsg)
{
bool bRes=false;
bRes=(pMsg->message==WM_LBUTTONDOWN);
if(bRes)
m_btn.Press(m_hWnd);
return bRes;
}
operator bool () const
{
return m_bDoAction;
}
protected:
bool m_bDoAction;
CPoint m_offset;
T& m_owner;
CButton& m_btn;
HWND m_hWnd;
int m_nHotHitTest;
};
public:
CCaptionBase(bool bHorizontal=true)
:COrientedRect(bHorizontal,::GetSystemMetrics(SM_CYSMCAPTION))
{
}
CCaptionBase(unsigned long thickness,bool bHorizontal=true)
:COrientedRect(bHorizontal,thickness)
{
}
bool CalculateRect(CRect& rc,bool bTop)
{
return baseClass::CalculateRect(rc,bTop);
}
LRESULT HitTest(const CPoint& /*pt*/) const
{
return HTNOWHERE;
}
void Draw(HWND /*hWnd*/,CDC& dc)
{
dc.FillRect(this,(HBRUSH)LongToPtr(COLOR_3DFACE + 1));
}
bool OnAction(HWND hWnd,unsigned int nHitTest)
{
return HotTrack(hWnd,nHitTest);
}
bool HotTrack(HWND /*hWnd*/,unsigned int /*nHitTest*/)
{
return false;
}
};
template <class TCaption,DWORD t_dwStyle = 0, DWORD t_dwExStyle = 0>
struct CDockingWindowTraits : CDockingBarWinTraits<t_dwStyle,t_dwExStyle>
{
typedef TCaption CCaption;
};
typedef CDockingWindowTraits<CCaptionBase,WS_OVERLAPPEDWINDOW | WS_POPUP/* WS_CHILD*/ | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,WS_EX_TOOLWINDOW/* WS_EX_CLIENTEDGE*/> CEmptyTitleDockingWindowTraits;
template <class T,
class TBase = CWindow,
class TDockingWinTraits = CEmptyTitleDockingWindowTraits>
class ATL_NO_VTABLE CTitleDockingWindowBaseImpl :
public CDockingWindowBaseImpl< T, TBase, TDockingWinTraits >
{
typedef CDockingWindowBaseImpl< T, TBase, TDockingWinTraits > baseClass;
typedef CTitleDockingWindowBaseImpl< T, TBase, TDockingWinTraits > thisClass;
protected:
typedef TDockingWinTraits::CCaption CCaption;
public:
LRESULT NcHitTest(const CPoint& pt)
{
LRESULT lRes=m_caption.HitTest(pt);
if(lRes==HTNOWHERE)
lRes=HTCLIENT;
else
{
if(GetCapture()==NULL)
m_caption.HotTrack(m_hWnd,lRes);
}
return lRes;
}
void GetMinMaxInfo(LPMINMAXINFO pMinMaxInfo)
{
pMinMaxInfo->ptMinTrackSize.x=0;
pMinMaxInfo->ptMinTrackSize.y=0;
}
void NcCalcSize(CRect* pRc)
{
DWORD style = GetWindowLong(GWL_STYLE);
if((style&WS_CAPTION)==0)
m_caption.SetRectEmpty();
else
m_caption.CalculateRect(*pRc,true);
}
void NcDraw(CDC& dc)
{
DWORD style = GetWindowLong(GWL_STYLE);
if((style&WS_CAPTION)!=0)
m_caption.Draw(m_hWnd,dc);
}
void OnDocked(HDOCKBAR hBar,bool bHorizontal)
{
m_caption.SetOrientation(!bHorizontal);
baseClass::OnDocked(hBar,bHorizontal);
}
void OnUndocked(HDOCKBAR hBar)
{
m_caption.SetOrientation(true);
baseClass::OnUndocked(hBar);
}
bool CloseBtnPress()
{
PostMessage(WM_CLOSE);
return false;
}
protected:
BEGIN_MSG_MAP(thisClass)
if(IsDocking())
{
MESSAGE_HANDLER(WM_GETMINMAXINFO,OnGetMinMaxInfo)
MESSAGE_HANDLER(WM_WINDOWPOSCHANGING,OnWindowPosChanging)
MESSAGE_HANDLER(WM_NCCALCSIZE, OnNcCalcSize)
MESSAGE_HANDLER(WM_NCACTIVATE, OnNcActivate)
MESSAGE_HANDLER(WM_NCHITTEST,OnNcHitTest)
MESSAGE_HANDLER(WM_NCPAINT,OnNcPaint)
MESSAGE_HANDLER(WM_SETTEXT,OnSetText)
MESSAGE_HANDLER(WM_NCLBUTTONDOWN, OnNcLButtonDown)
MESSAGE_HANDLER(WM_NCLBUTTONUP,OnNcLButtonUp)
MESSAGE_HANDLER(WM_NCLBUTTONDBLCLK,OnNcLButtonDblClk)
}
CHAIN_MSG_MAP(baseClass)
END_MSG_MAP()
LRESULT OnGetMinMaxInfo(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
{
T* pThis=static_cast<T*>(this);
LRESULT lRes=pThis->DefWindowProc(uMsg,wParam,lParam);
pThis->GetMinMaxInfo(reinterpret_cast<LPMINMAXINFO>(lParam));
return lRes;
}
LRESULT OnWindowPosChanging(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
return NULL;
}
LRESULT OnNcActivate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
{
bHandled=IsWindowEnabled();
return TRUE;
}
LRESULT OnNcCalcSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)
{
T* pThis=static_cast<T*>(this);
CRect* pRc=reinterpret_cast<CRect*>(lParam);
CPoint ptTop(pRc->TopLeft());
(*pRc)-=ptTop;
pThis->NcCalcSize(pRc);
(*pRc)+=ptTop;
return NULL;
}
LRESULT OnNcHitTest(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)
{
CPoint pt(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
T* pThis=static_cast<T*>(this);
CRect rcWnd;
GetWindowRect(&rcWnd);
pt.x-=rcWnd.TopLeft().x;
pt.y-=rcWnd.TopLeft().y;
return pThis->NcHitTest(pt);
}
LRESULT OnSetText(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
{
// LockWindowUpdate();
LRESULT lRes=DefWindowProc(uMsg,wParam,lParam);
CWindowDC dc(m_hWnd);
T* pThis=static_cast<T*>(this);
pThis->NcDraw(dc);
// LockWindowUpdate(FALSE);
return lRes;
}
LRESULT OnNcPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
CWindowDC dc(m_hWnd);
T* pThis=static_cast<T*>(this);
pThis->NcDraw(dc);
return NULL;
}
LRESULT OnNcLButtonDown(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
{
bHandled=m_caption.OnAction(m_hWnd,wParam);
return !bHandled;
}
LRESULT OnNcLButtonUp(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
{
T* pThis=static_cast<T*>(this);
switch(wParam)
{
case HTCLOSE:
bHandled=pThis->CloseBtnPress();
break;
default:
bHandled=FALSE;
}
return 0;
}
LRESULT OnNcLButtonDblClk(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
return 0;
}
protected:
CCaption m_caption;
};
template <class T,
class TBase = CWindow,
class TDockingWinTraits = CEmptyTitleDockingWindowTraits>
class ATL_NO_VTABLE CTitleDockingWindowImpl
: public CTitleDockingWindowBaseImpl< T, TBase, TDockingWinTraits >
{
typedef CTitleDockingWindowBaseImpl< T, TBase, TDockingWinTraits > baseClass;
typedef CTitleDockingWindowImpl< T, TBase, TDockingWinTraits > thisClass;
public:
CTitleDockingWindowImpl()
{
m_pos.hdr.hBar=HNONDOCKBAR;
}
virtual bool Undock()
{
assert(IsDocking());
GetDockingPosition(&m_pos);
return baseClass::Undock();
}
virtual bool Hide()
{
bool bRes=true;
if(IsDocking())
{
bRes=GetDockingPosition(&m_pos);
assert(bRes);
if(bRes)
// bRes=Undock();
bRes=Float(&m_rcUndock,SWP_HIDEWINDOW);
assert(bRes);
}
else
m_pos.hdr.hBar=HNONDOCKBAR;
return (bRes && ShowWindow(SW_HIDE));
}
virtual bool Show()
{
bool bRes=true;
if(m_pos.hdr.hBar!=HNONDOCKBAR)
bRes=SetDockingPosition(&m_pos);
else
ShowWindow(SW_SHOW);
assert(bRes);
return bRes;
}
bool Toggle()
{
bool bRes=(static_cast<T*>(this)->IsWindowVisible()!=FALSE);
if(bRes)
Hide();
else
Show();
return bRes;
}
bool GetDockingWindowPlacement(DFDOCKPOSEX* pHdr) const
{
bool bRes=baseClass::GetDockingWindowPlacement(pHdr);
pHdr->bVisible=static_cast<const T*>(this)->IsWindowVisible();
if((!pHdr->bDocking) && (!pHdr->bVisible) )
::CopyMemory(&pHdr->dockPos,&m_pos,sizeof(DFDOCKPOS));
return bRes;
}
bool SetDockingWindowPlacement(DFDOCKPOSEX* pHdr)
{
bool bRes=true;
::CopyMemory(&m_pos,&(pHdr->dockPos),sizeof(DFDOCKPOS));
if(pHdr->bVisible)
bRes=baseClass::SetDockingWindowPlacement(pHdr);
else
{
if(IsDocking())
Undock();
m_pos.hdr.hWnd=m_hWnd;
::CopyRect(&m_rcUndock,&pHdr->rect);
bRes=(SetWindowPos(NULL,&m_rcUndock,SWP_NOZORDER | SWP_HIDEWINDOW |
SWP_NOACTIVATE )!=FALSE);
}
return bRes;
}
bool CanBeClosed(unsigned long /*param*/)
{
Hide();
return false;
}
BEGIN_MSG_MAP(thisClass)
MESSAGE_HANDLER(WM_CLOSE, OnClose)
MESSAGE_HANDLER(WM_NCLBUTTONDBLCLK, OnNcLButtonDblClk)
CHAIN_MSG_MAP(baseClass)
END_MSG_MAP()
LRESULT OnClose(UINT /*uMsg*/, WPARAM wParam, LPARAM/* lParam*/, BOOL& bHandled)
{
bHandled=!(static_cast<T*>(this)->CanBeClosed(wParam));
return 0;
}
LRESULT OnNcLButtonDblClk(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
if(wParam==HTCAPTION)
{
if(IsDocking())
Float();
else
{
if(m_pos.hdr.hBar!=HNONDOCKBAR)
SetDockingPosition(&m_pos);
}
}
return 0;
}
protected:
DFDOCKPOS m_pos;
};
#define COMMAND_TOGGLE_MEMBER_HANDLER(id, member) \
if(uMsg == WM_COMMAND && id == LOWORD(wParam)) \
{ \
member.Toggle(); \
}
//please don't use CStateKeeper class anymore!
//this class is obsolete and provided only for compatibility with previous versions.
//the CTitleDockingWindowImpl class provide all functionality of CStateKeeper
template<class T>
struct CStateKeeper : public T
{
};
//please don't use CTitleExDockingWindowImpl class anymore!
//this class is obsolete and provided only for compatibility with previous versions.
//the CTitleDockingWindowImpl class provide all functionality of CTitleExDockingWindowImpl
template <class T,
class TBase = CWindow,
class TDockingWinTraits = CEmptyTitleDockingWindowTraits>
struct ATL_NO_VTABLE CTitleExDockingWindowImpl : CTitleDockingWindowImpl< T, TBase, TDockingWinTraits >
{
};
}//namespace dockwins
#endif // !defined(AFX_DOCKINGWINDOW_H__B52D9183_DF95_4DCD_8A16_937836FA5F06__INCLUDED_)