Click here to Skip to main content
15,886,578 members
Articles / Desktop Programming / WTL

WTL Docking Windows

Rate me:
Please Sign up or sign in to vote.
4.89/5 (73 votes)
21 Nov 20077 min read 839.9K   14.1K   215  
This is an implementation of docking windows for the WTL library
// 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_DOCKINGFRAME_H__00E099AA_F8A4_40A6_8368_4FF0870CC58D__INCLUDED_)
#define AFX_DOCKINGFRAME_H__00E099AA_F8A4_40A6_8368_4FF0870CC58D__INCLUDED_

#include <atlframe.h>
#include <DockMisc.h>
#include <PackageWindow.h>

namespace dockwins{
/////////////////CDockingFrameImplBase

template <class T, class TBase,class TWinTraits = CDockingFrameTraits >
class ATL_NO_VTABLE CDockingFrameImplBase : public TBase
{
	typedef CDockingFrameImplBase<T,TBase,TWinTraits> thisClass;
	typedef TBase baseClass;
	typedef TWinTraits CTraits; 
	typedef CTraits::CSplitterBar	CSplitterBar;
	typedef CPackageWindowFrame<CTraits> CPackageFrame; 
	typedef CSubWndFramesPackage<CPackageFrame,CTraits>	CWndPackage;
    typedef CDockingBarStyle	CStyle;
public:
	CDockingFrameImplBase()
		:m_vPackage(false),m_hPackage(true)
	{
	}
    CStyle GetStyle() const
    {
        return m_style;
    }
	
    CStyle SetStyle(const CStyle& style)
    {
		CStyle prevStyle=m_style;
        m_style=style;
		return prevStyle;
    }
	void ApplySystemSettings()
	{
		if(!m_style.IgnoreSystemSettings())
		{
			BOOL bFullDrag;
			BOOL bRes=::SystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0, &bFullDrag, 0);
			if(bRes&&(m_style.GhostDrag()==(bFullDrag!=FALSE)))
			{
				CStyle style=m_style;
				style.Set(CStyle::mskGhostDrag,bFullDrag ? CStyle::sFullDrag : CStyle::sGhostDrag);
				SetStyle(style);
				m_vPackage.SystemSettingsChange();
				m_hPackage.SystemSettingsChange();
			}
		}
	}
	bool InitializeDockingFrame(CStyle style=CStyle::sUseSysSettings)
	{
		SetStyle(style);	
		T* pThis = static_cast<T*>(this);
		pThis->ApplySystemSettings();
		pThis->UpdateLayout();
		m_vPackage.Insert(&m_hPackage,m_vPackage);
		m_vPackage.UpdateLayout(m_vPackage);
		m_hPackage.Insert(&m_hWndClient,m_vPackage);		

		return true;		
	}

	void UpdateLayout(BOOL bResizeBars = TRUE)
	{
		CRect rc;
		GetClientRect(&rc);
		UpdateBarsPosition(rc, bResizeBars);
		m_vPackage.UpdateLayout(rc);
	}
	void Draw(CDC& dc)
	{
		m_vPackage.Draw(dc);
		m_hPackage.Draw(dc);
	}

	HCURSOR GetCursor(const CPoint& pt)
	{
		HCURSOR hCursor=NULL;
		if(m_hPackage.PtInRect(pt))
			hCursor=m_hPackage.GetCursor(pt);
		else
		{
			if(m_vPackage.PtInRect(pt))
				hCursor=m_vPackage.GetCursor(pt);
		}
		return hCursor;
	}

	bool StartSliding(const CPoint& pt)
	{
		bool bRes;
		if(m_hPackage.PtInRect(pt))
			bRes=m_hPackage.StartSliding(m_hWnd,pt,m_style.GhostDrag());
		else
			bRes=m_vPackage.StartSliding(m_hWnd,pt,m_style.GhostDrag());
		if(bRes)
			RedrawWindow(NULL,NULL,RDW_INVALIDATE | RDW_UPDATENOW | 
									((m_hWndClient==NULL)?RDW_ERASE:0));
		return bRes;
	}

	bool AdjustDragRect(DFDOCKRECT* pHdr)
	{
		CRect rc;
		GetClientRect(&rc);
		int limit=rc.Width()/3;
		if(pHdr->rect.right-pHdr->rect.left>limit)
			pHdr->rect.right=pHdr->rect.left+limit;

		limit=GetSystemMetrics(SM_CXMIN);
		if(pHdr->rect.right-pHdr->rect.left<limit)
			pHdr->rect.right=pHdr->rect.left+limit;

		limit=rc.Height()/3;
		if(pHdr->rect.bottom-pHdr->rect.top>limit)
			pHdr->rect.bottom=pHdr->rect.top+limit;
		
		limit=GetSystemMetrics(SM_CYMIN);
		if(pHdr->rect.bottom-pHdr->rect.top<limit)
			pHdr->rect.bottom=pHdr->rect.top+limit;

		return true;
	}

	LRESULT AcceptDock(DFDOCKRECT* pHdr)
	{
		ScreenToClient(&(pHdr->rect));
		pHdr->hdr.hBar=m_hWnd;
		LRESULT lRes=m_vPackage.AcceptDock(pHdr);
		if(!lRes)
			pHdr->hdr.hBar=HNONDOCKBAR;
		ClientToScreen(&(pHdr->rect));
		return lRes;
	}

	LRESULT Dock(DFDOCKRECT* pHdr)
	{
		LRESULT lRes=FALSE;
		ScreenToClient(&(pHdr->rect));
		if(m_hPackage.PtInRect(CPoint(pHdr->rect.left,pHdr->rect.top))
			&&
			!((pHdr->rect.right-pHdr->rect.left==m_vPackage.Width()) 
				&&	pHdr->rect.left ==m_vPackage.left) )
			lRes=m_hPackage.Dock(pHdr);
		else
			lRes=m_vPackage.Dock(pHdr);
		ClientToScreen(&(pHdr->rect));
		RedrawWindow(NULL,NULL,RDW_INVALIDATE | RDW_UPDATENOW | 
									((m_hWndClient==NULL)?RDW_ERASE:0));
		return lRes;
	}
	LRESULT Undock(DFMHDR* pHdr)
	{
		bool bRes;
		assert(::IsWindow(pHdr->hWnd));
		if(CDockingBarStyle::GetStyle(pHdr->hWnd).IsHorizontal())
			bRes=m_vPackage.Undock(pHdr,NULL);
		else
			bRes=m_hPackage.Undock(pHdr,m_hWndClient);
		RedrawWindow(NULL,NULL,RDW_INVALIDATE | RDW_UPDATENOW | 
									((m_hWndClient==NULL)?RDW_ERASE:0));
		return bRes;
	}
	template<class T>
	bool DockWindow(T& dockWnd,CDockingSide side,unsigned long nBar,float fPctPos,unsigned long	nWidth, unsigned long nHeight)
	{
		if(dockWnd.IsDocking())
			dockWnd.Undock();

		DFDOCKPOS dockHdr;
		dockHdr.hdr.hWnd=dockWnd.m_hWnd;
		dockHdr.hdr.hBar=m_hWnd;
		dockHdr.hdr.code=DC_SETDOCKPOSITION;

		dockHdr.dwDockSide=side;
		dockHdr.nBar=nBar;
		dockHdr.fPctPos=fPctPos;
		dockHdr.nWidth=nWidth;
		dockHdr.nHeight=nHeight;
		return SetDockingPosition(&dockHdr);
	}

	bool SetDockingPosition(DFDOCKPOS* pHdr)
	{
		assert(pHdr->hdr.hWnd);
		bool bRes;
		CDockingSide side(pHdr->dwDockSide);
		if(side.IsHorizontal())
			bRes=m_hPackage.SetDockingPosition(pHdr,m_hWndClient);
		else
			bRes=m_vPackage.SetDockingPosition(pHdr,NULL);
		RedrawWindow(NULL,NULL,RDW_INVALIDATE | RDW_UPDATENOW | 
									((m_hWndClient==NULL)?RDW_ERASE:0));
		return bRes;
	}
	
	bool GetDockingPosition(DFDOCKPOS* pHdr) const
	{
		pHdr->dwDockSide=CDockingSide::sBottom;
		bool bRes=m_vPackage.GetDockingPosition(pHdr,NULL);
		if(!bRes)
		{
			pHdr->dwDockSide=CDockingSide::sRight;
			bRes=m_hPackage.GetDockingPosition(pHdr,m_hWndClient);		
		}
		return bRes;
	}
protected:
////////////////messages handlers//////////////////////
    BEGIN_MSG_MAP(thisClass)
		MESSAGE_HANDLER(WM_CREATE, OnCreate)
		MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange)
		MESSAGE_HANDLER(WM_PAINT, OnPaint)
		MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)
		MESSAGE_HANDLER(WM_SETCURSOR,OnSetCursor)
		MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)
/////////////////////
		MESSAGE_HANDLER(WMDF_DOCK,OnDock)
		MESSAGE_HANDLER(WMDF_STYLE,OnStyle)
		CHAIN_MSG_MAP(baseClass)
    END_MSG_MAP()

	LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
	{
		T* pThis=static_cast<T*>(this);
		pThis->InitializeDockingFrame();
		bHandled=FALSE;
		return NULL;
	}
	LRESULT OnSettingChange(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
	{
		T* pThis=static_cast<T*>(this);
		pThis->ApplySystemSettings();
		return NULL;
	}

	LRESULT OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
	{
		T* pThis=static_cast<T*>(this);
		CPaintDC dc(pThis->m_hWnd);
		pThis->Draw(dc);
		return 0;
	}
	LRESULT OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
	{
		return DefWindowProc(uMsg,wParam,lParam);
	}

	LRESULT OnSetCursor(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		T* pThis = static_cast<T*>(this);
		if((HWND)wParam == pThis->m_hWnd && LOWORD(lParam) == HTCLIENT)
		{
			DWORD dwPos = ::GetMessagePos();
            CPoint pt(GET_X_LPARAM(dwPos), GET_Y_LPARAM(dwPos));
			pThis->ScreenToClient(&pt);			
			HCURSOR hCursor=pThis->GetCursor(pt);
			bHandled=(hCursor!=NULL);
			if(bHandled)
				SetCursor(hCursor);
			return bHandled;
		}

		bHandled = FALSE;
		return 0;
	}

	LRESULT OnLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
	{
		CPoint pt( GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
		T* pThis = static_cast<T*>(this);
		bHandled=pThis->StartSliding(pt);
		return !bHandled;
	}

    LRESULT OnDock(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)
    {
		LRESULT lRes=FALSE;
		T* pThis=static_cast<T*>(this);
		DFMHDR* pHdr=reinterpret_cast<DFMHDR*>(lParam);
		switch(pHdr->code)
		{
			case DC_ADJUSTDRAGRECT:
				lRes=pThis->AdjustDragRect(reinterpret_cast<DFDOCKRECT*>(pHdr));
				break;
			case DC_ACCEPT:
				lRes=pThis->AcceptDock(reinterpret_cast<DFDOCKRECT*>(pHdr));
				break;
			case DC_DOCK:
				lRes=pThis->Dock(reinterpret_cast<DFDOCKRECT*>(pHdr));
				break;
			case DC_UNDOCK:
				lRes=pThis->Undock(pHdr);
				break;
			case DC_SETDOCKPOSITION:
				lRes=pThis->SetDockingPosition(reinterpret_cast<DFDOCKPOS*>(pHdr));
				break;
			case DC_GETDOCKPOSITION:
				lRes=pThis->GetDockingPosition(reinterpret_cast<DFDOCKPOS*>(pHdr));
				break;
		}
		return lRes;
	}

    LRESULT OnStyle(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
    {
		LRESULT lRes;
		T* pThis=static_cast<T*>(this);
		if(LOWORD(wParam))
			lRes=pThis->SetStyle(lParam/*,HIWORD(wParam)==TRUE*/);
		else
			lRes=pThis->GetStyle();
		return lRes;
	}
protected:
	CStyle			m_style;
	CWndPackage		m_vPackage;
	CWndPackage		m_hPackage;
	CRect			m_rcClient;
};

typedef CDockingFrameTraitsT< CSimpleSplitterBarEx<6>,
		WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,0> CDockingSiteTraits;

/////////////////CDockingSiteBasement
template <class T, class TBase = CWindow, class TWinTraits = CDockingSiteTraits>
class ATL_NO_VTABLE CDockingSiteBasement : public CWindowImpl<T, TBase, TWinTraits >
{
    typedef CDockingSiteBasement<T, TBase, TWinTraits >  thisClass;
public:
    DECLARE_WND_CLASS(NULL)
    CDockingSiteBasement():m_hWndClient(NULL)
    {
    }
protected:
    BEGIN_MSG_MAP(thisClass)
		MESSAGE_HANDLER(WM_SIZE, OnSize)
		MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
	END_MSG_MAP()
	LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
	{
		if(wParam != SIZE_MINIMIZED)
		{
				T* pT = static_cast<T*>(this);
				pT->UpdateLayout();
		}
		bHandled = FALSE;
		return 1;
	}
    LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
    {
            if(m_hWndClient != NULL)
                    return 1;

            bHandled = FALSE;
            return 0;
    }
protected:
    HWND m_hWndClient;
};
/////////////////CDockingSiteImpl
template <  class T,
			class TBase = CWindow,
            class TWinTraits = CDockingSiteTraits,
            class TBaseImpl = CDockingSiteBasement<T,TBase,TWinTraits> >
class CDockingSiteImpl:
    public CDockingFrameImplBase< T, TBaseImpl ,TWinTraits >
{
    typedef CDockingSiteImpl<T,TBase,TWinTraits,TBaseImpl>  thisClass;
    typedef CDockingFrameImplBase< T, TBaseImpl ,TWinTraits > baseClass;
public:
    DECLARE_WND_CLASS(_T("CDockingSiteImpl"))
    void UpdateLayout(BOOL bResizeBars = TRUE)
    {
		bResizeBars;// avoid level 4 warning
        CRect rc;
		T* pT = static_cast<T*>(this);
		pT->GetClientRect(&rc);
        m_vPackage.UpdateLayout(rc);
    }
};	

/////////////////CDockingFrameImpl

template <	class T,
            class TBase = CWindow,
            class TWinTraits = CDockingFrameTraits >
class ATL_NO_VTABLE CDockingFrameImpl:
	public CDockingFrameImplBase< T, CFrameWindowImpl< T ,TBase, TWinTraits> ,TWinTraits >
{
public:
	DECLARE_WND_CLASS(_T("CDockingFrameImpl"))
};

/////////////////CMIDIDockingFrameImpl
template <class T, 
		  class TBase = CMDIWindow, 		  
		  class TWinTraits = CDockingFrameTraits >
class ATL_NO_VTABLE CMDIDockingFrameImpl : 
	public CDockingFrameImplBase< T, CMDIFrameWindowImpl< T ,TBase, TWinTraits> ,TWinTraits >
{
public:
	DECLARE_WND_CLASS(_T("CMDIDockingFrameImpl"))
};

}//namespace dockwins
#endif // !defined(AFX_DOCKINGFRAME_H__00E099AA_F8A4_40A6_8368_4FF0870CC58D__INCLUDED_)

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Software Developer
Ireland Ireland
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions