Click here to Skip to main content
15,896,557 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 856.3K   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_WNDFRMPKG_H__4C823036_1E4A_4DD5_8C4D_5E480DCED39F__INCLUDED_)
#define AFX_WNDFRMPKG_H__4C823036_1E4A_4DD5_8C4D_5E480DCED39F__INCLUDED_

#ifndef __ATLMISC_H__
        #error WndFrmPkg.h requires atlmisc.h to be included first
#endif

#include <memory>
#include <ssec.h>
#include <DDTracker.h>
#ifdef USE_BOOST
#include<boost/smart_ptr.hpp>
#endif

namespace dockwins{

template< class TFrame = CWndFrame , class TTraits = CDockingFrameTraits>
class CWndFramesPackageBase
{
	typedef TFrame CFrame;
	typedef TTraits CTraits;
	typedef CTraits::CSplitterBar	CSplitterBar;
	typedef CWndFramesPackageBase<CFrame,TTraits> thisClass;
protected:
	typedef CFrame::position	position;
	typedef ssection<CFrame,spraits<CFrame,position,position,CSplitterBar::sbThickness> > CFrames;

	typedef CFrames::iterator				iterator;
	typedef CFrames::reverse_iterator		reverse_iterator;
	typedef CFrames::const_iterator			const_iterator;
	typedef CFrames::const_reverse_iterator	const_reverse_iterator;

	typedef bounds_type<position> CBounds;
protected:
	enum {splitterSize=CSplitterBar::sbThickness};
	
	struct CEmbeddedSplitterBar : public CSplitterBar
	{
		CEmbeddedSplitterBar(bool bHorizontal,position vertex,const CRect& rcClient)
				:CSplitterBar(bHorizontal)
		{
            if(IsHorizontal())
            {
                    top=vertex;
                    bottom=top+GetThickness();
                    left=rcClient.left;
                    right=rcClient.right;
            }
            else
            {
                    left=vertex;
                    right=left+GetThickness();
                    top=rcClient.top;
                    bottom=rcClient.bottom;
            }
		
		}
	};
	class CEmbeddedSplitterBarPainter
	{
	public:
		CEmbeddedSplitterBarPainter(CDC& dc,bool bHorizontal,const CRect& rc)
			:m_dc(dc),m_rc(rc),m_bHorizontal(bHorizontal)
		{
		}
		void operator()(const CFrame& ref) const
		{
			CEmbeddedSplitterBar splitter(m_bHorizontal,ref,m_rc);
			splitter.Draw(m_dc);
		}
	protected:
		const	CRect& m_rc;
		bool	m_bHorizontal;
		CDC&	m_dc;
	};

	class CSplitterMoveTrackerBase : public IDDTracker//CDDTrackerBaseT<CSizeTrackerBase>
	{
	protected:
		void SetPosition()
		{
			assert(m_bounds.bind(m_pos)==m_pos);
			m_frames.set_position(m_i,m_pos);
			m_owner.Arrange(m_rc);
		}
	public:
		CSplitterMoveTrackerBase(thisClass& owner,const CPoint& pt,const CRect& rc)
			:m_owner(owner),m_frames(owner.m_frames),m_rc(rc)
		{
			position pos=owner.IsHorizontal() ? pt.x : pt.y;
			m_i=m_frames.locate(pos);
			if(m_i!=m_frames.end())
			{
				m_pos=(*m_i);
				m_offset=pos-m_pos;
				m_frames.get_effective_bounds(m_i,m_bounds);
			}
		}
		operator iterator() const
		{
			return m_i;
		}
        void OnMove(long x, long y)
        {
			position pos = m_owner.IsHorizontal() ? x : y;
			pos=m_bounds.bind(pos-m_offset);
			if(pos!=m_pos)
			{
				m_pos=pos;
				Move();
			}
		}
		virtual void Move()=0;
		
	protected:
		thisClass&		m_owner;
		CFrames&		m_frames;
		iterator		m_i;
		CBounds			m_bounds;
		position		m_pos;
		position		m_offset;
		const CRect&	m_rc;
	};

	friend class CSplitterMoveTrackerBase;

	class CSplitterMoveTrackerFull : public CSplitterMoveTrackerBase
	{
	public:
		CSplitterMoveTrackerFull(thisClass& owner,const CPoint& pt,const CRect& rc)
			:CSplitterMoveTrackerBase(owner,pt,rc)
		{
		}
		void Move()
		{
			SetPosition();
		}
	};
	
	class CSplitterMoveTrackerGhost : public CSplitterMoveTrackerBase
	{
		typedef CEmbeddedSplitterBar CSplitterBar;
        typedef CSimpleSplitterBarSlider<CSplitterBar> CSlider;
	public:
		CSplitterMoveTrackerGhost(HWND hWnd,thisClass& owner,
									const CPoint& pt,const CRect& rc)
			:CSplitterMoveTrackerBase(owner,pt,rc),
			  m_dc(::GetWindowDC(NULL)),m_splitter(!owner.IsHorizontal(),m_pos,rc),m_slider(m_splitter)
		{
			CPoint point(rc.TopLeft ());
			::ClientToScreen(hWnd,&point);
			CSize offset(point.x-rc.left,point.y-rc.top);
			m_splitter+=offset;
			m_ghOffset=owner.IsHorizontal()
									?offset.cx
									:offset.cy;
		}
        void BeginDrag()
        {
            m_splitter.DrawGhostBar(m_dc);
        }
        void EndDrag(bool bCanceled)
        {
            m_splitter.CleanGhostBar(m_dc);
            if(!bCanceled)
                SetPosition();
        }
		void Move()
		{
			m_splitter.CleanGhostBar(m_dc);
			m_slider=m_pos+m_ghOffset;
			m_splitter.DrawGhostBar(m_dc);
		}

	protected:
		position		m_ghOffset;
		CSplitterBar	m_splitter;
		CSlider			m_slider;
		CDC				m_dc;
	};

protected:
    bool ArrangeH(const CRect& rc)
    {
        HDWP hdwp=reinterpret_cast<HDWP>(TRUE);
        const_iterator begin=m_frames.begin();
        const_iterator end=m_frames.end();
        if(begin!=end)
        {
            hdwp=BeginDeferWindowPos(m_frames.size());
            const_iterator next=begin;
            while((hdwp!=NULL)&&(++next!=end))
            {
                long x=(*begin)+splitterSize;
                hdwp=begin->DeferFramePos(hdwp,
											x,
											rc.top,
											(*next),
											rc.bottom);
                begin=next;
            }
            if(hdwp!=NULL)
            {
                long x=(*begin)+splitterSize;
                hdwp=begin->DeferFramePos(hdwp,
											x,
											rc.top,
											rc.right,
											rc.bottom);
                if(hdwp)
					hdwp=reinterpret_cast<HDWP>(EndDeferWindowPos(hdwp));
            }
        }
        return hdwp!=NULL;
    }

    bool ArrangeV(const CRect& rc)
    {
        HDWP hdwp=reinterpret_cast<HDWP>(TRUE);
        const_iterator begin=m_frames.begin();
        const_iterator end=m_frames.end();
        if(begin!=end)
        {
            hdwp=BeginDeferWindowPos(m_frames.size());
            const_iterator next=begin;
            while((hdwp!=NULL)&&(++next!=end))
            {
                long y=(*begin)+splitterSize;
                hdwp=begin->DeferFramePos(hdwp,
											rc.left,
											y,
											rc.right,
											(*next));
                begin=next;
            }
            if(hdwp!=NULL)
            {
                long y=(*begin)+splitterSize;
                hdwp=begin->DeferFramePos(hdwp,
											rc.left,
											y,
											rc.right,
											rc.bottom);
                if(hdwp)
					hdwp=reinterpret_cast<HDWP>(EndDeferWindowPos(hdwp));
            }
        }
        return hdwp!=NULL;
    }
    bool Arrange(const CRect& rcClient)
    {
		bool bRes;
		if(IsHorizontal())
			bRes=ArrangeH(rcClient);
		else
			bRes=ArrangeV(rcClient);
		return bRes;
    }

	CWndFramesPackageBase(bool bHorizontal)
		:m_bHorizontal(bHorizontal),m_frames(0,0)
	{
	}
public:
	bool IsHorizontal() const
	{
		return m_bHorizontal;
	}

	void SetOrientation(bool bHorizontal)
	{
		m_bHorizontal=bHorizontal;
	}
	
	HCURSOR GetCursor(const CPoint& pt,const CRect& rc) const
	{
		HCURSOR hCursor=NULL;
		position pos=IsHorizontal() ?pt.x :pt.y;
		const_iterator i=m_frames.locate(pos);
		if(i!=m_frames.end())
		{
			CEmbeddedSplitterBar splitter(!IsHorizontal(),(*i),rc);		
			hCursor=splitter.GetCursor(pt);
		}
		return hCursor;
	}
/*
	bool StartSliding(HWND hWnd,const CPoint& pt,const CRect& rc,bool bGhostMove)
	{
		std::auto_ptr<CSplitterMoveTrackerBase> pTracker;

		if(bGhostMove)
			pTracker=std::auto_ptr<CSplitterMoveTrackerBase>(
								new CSplitterMoveTrackerGhost(hWnd,*this,pt,rc));
		else
			pTracker=std::auto_ptr<CSplitterMoveTrackerBase>(
								new CSplitterMoveTrackerFull(*this,pt,rc));

		bool bRes=false;
		if(const_iterator(*pTracker)!=m_frames.end())
			 bRes=TrackDragAndDrop(*pTracker,hWnd);
		return bRes;
	}
*/
	bool StartSliding(HWND hWnd,const CPoint& pt,const CRect& rc,bool bGhostMove)
	{
		bool bRes=false;
		position pos=IsHorizontal() ?pt.x :pt.y;
		const_iterator i=m_frames.locate(pos);
		if(i!=m_frames.end())
		{
			CEmbeddedSplitterBar splitter(!IsHorizontal(),(*i),rc);		
			if(splitter.IsPtIn(pt))
			{
				std::auto_ptr<CSplitterMoveTrackerBase> pTracker;

				if(bGhostMove)
					pTracker=std::auto_ptr<CSplitterMoveTrackerBase>(
										new CSplitterMoveTrackerGhost(hWnd,*this,pt,rc));
				else
					pTracker=std::auto_ptr<CSplitterMoveTrackerBase>(
										new CSplitterMoveTrackerFull(*this,pt,rc));

				if(const_iterator(*pTracker)!=m_frames.end())
					 bRes=TrackDragAndDrop(*pTracker,hWnd);
			}
		}
		return bRes;
	}

	bool UpdateLayout(const CRect& rc)
	{
		CBounds bounds;
        if(IsHorizontal())
        {
                bounds.low=rc.left-splitterSize;
                bounds.hi=rc.right;
        }
        else
        {
                bounds.low=rc.top-splitterSize;
                bounds.hi=rc.bottom;
        }

		CBounds::distance_t limit=m_frames.distance_limit();

		if(bounds.distance()>=limit)
			m_frames.set_bounds(bounds);
		return Arrange(rc);
		
	}

	void Draw(CDC& dc,const CRect& rc) const
	{
        if(m_frames.begin()!=m_frames.end())
			std::for_each(++m_frames.begin(),m_frames.end(),CEmbeddedSplitterBarPainter(dc,!IsHorizontal(),rc));
	}

	bool AcceptDock(DFDOCKRECT* pHdr,const CRect& rc)
	{
		bool bRes=false;
		if(rc.PtInRect(CPoint(pHdr->rect.left,pHdr->rect.top)))
		{
			if(IsHorizontal())
			{
				pHdr->rect.top=rc.top;
				pHdr->rect.bottom=rc.bottom;
			}
			else
			{
				pHdr->rect.left=rc.left;
				pHdr->rect.right=rc.right;
			}
			bRes=true;
		}
		return bRes;
	}
	bool Dock(CFrame& frame,const DFDOCKRECT* pHdr,const CRect& rc)
	{
		position		  pos;
		CFrames::distance len;

		if(IsHorizontal())
		{
			pos=pHdr->rect.left;
			len=pHdr->rect.right-pHdr->rect.left;
		}
		else
		{
			pos=pHdr->rect.top;
			len=pHdr->rect.bottom-pHdr->rect.top;
		}

		iterator i=m_frames.locate(pos);
		if(i!=m_frames.end())
		{
			iterator inext=i;
			++inext;
			CBounds fbounds((*i),(inext!=m_frames.end())?(*inext):m_frames.hi());
			if((fbounds.low+(fbounds.hi-fbounds.low)/3)<pos)
				i=inext;
		}
		frame=pos;
		m_frames.insert(i,frame,len);
		
		return Arrange(rc);
	}
	bool Undock(const DFMHDR* pHdr,const CRect& rc)
	{
		iterator i=std::find_if(m_frames.begin(),m_frames.end(),CFrame::CCmp(pHdr->hWnd));
		assert(i!=m_frames.end());
		m_frames.erase(i);
		return Arrange(rc);
	}
	bool Replace(const DFDOCKREPLACE* pHdr,const CRect& rc)
	{
		iterator i=std::find_if(m_frames.begin(),m_frames.end(),CFrame::CCmp(pHdr->hdr.hWnd));
		assert(i!=m_frames.end());
		m_frames.replace(i,CFrame(0,pHdr->hWnd));
		return Arrange(rc);
	}

protected:
	bool	m_bHorizontal;
	CFrames	m_frames;
};

class CWndFrame
{
public:
	typedef long position;

	class CCmp
	{
	public:
		CCmp(HWND hWnd)	:m_hWnd(hWnd)
		{
		}
		bool operator ()(const CWndFrame& frame) const
		{
			return (frame.hwnd() == m_hWnd);
		}
	protected:
		HWND m_hWnd;
	};

	CWndFrame(position pos=0,HWND hWnd=NULL)
		:m_hWnd(hWnd),m_pos(pos)
	{
	}

	HWND hwnd() const
	{
		return m_hWnd;
	}

	operator position() const
	{
		return m_pos;
	}

	CWndFrame& operator += (position val)
	{
		m_pos+=val;
		return *this;
	}
	CWndFrame& operator -= (position val)
	{
		m_pos-=val;
		return *this;
	}
	
	CWndFrame& operator = (position pos)
	{
		m_pos=pos;
		return *this;
	}
	
	HDWP DeferFramePos(HDWP hdwp,long x1,long y1,long x2,long y2) const
	{
		return ::DeferWindowPos(hdwp,hwnd(),
								NULL,
								x1,y1,
								x2-x1,y2-y1,
								SWP_NOZORDER | SWP_NOACTIVATE);
	}

protected:
	position m_pos;
	mutable HWND m_hWnd;
};


template< class TTraits = CDockingFrameTraits >
class CWndFramesPackage : public CWndFramesPackageBase<CWndFrame,TTraits >
{
	typedef CWndFrame CFrame;
	typedef TTraits CTraits;
	typedef CTraits::CSplitterBar	CSplitterBar;
	typedef CWndFramesPackage<TTraits> thisClass;
	typedef CWndFramesPackageBase<CFrame,TTraits > baseClass;
public:
	CWndFramesPackage(bool bHorizontal):baseClass(bHorizontal)
	{
	}
	void PrepareForDocking(CWindow wnd,HDOCKBAR bar)
	{
		wnd.ShowWindow(SW_HIDE);
		DWORD style = wnd.GetWindowLong(GWL_STYLE);
		DWORD newStyle = style&(~WS_POPUP)|WS_CHILD;
		wnd.SetWindowLong( GWL_STYLE, newStyle);
		wnd.SetParent(bar);
		wnd.SendMessage(WM_NCACTIVATE,TRUE);
		wnd.SendMessage(WMDF_NDOCKSTATECHANGED,
					MAKEWPARAM(TRUE,IsHorizontal()),
					reinterpret_cast<LPARAM>(bar));
	}
	void PrepareForUndocking(CWindow wnd,HDOCKBAR bar)
	{
		wnd.ShowWindow(SW_HIDE);
		DWORD style = wnd.GetWindowLong(GWL_STYLE);
		DWORD newStyle = style&(~WS_CHILD)|WS_POPUP;
		wnd.SetWindowLong( GWL_STYLE, newStyle);
		wnd.SetParent(NULL);

		wnd.SendMessage(WMDF_NDOCKSTATECHANGED,
			FALSE,
			reinterpret_cast<LPARAM>(bar));
	}

	bool SetDockingPosition(DFDOCKPOS* pHdr,const CRect& rc)
	{
		assert(::IsWindow(pHdr->hdr.hWnd));
		CWindow wnd(pHdr->hdr.hWnd);
		PrepareForDocking(wnd,pHdr->hdr.hBar);
		position pos=m_frames.low()+position((m_frames.hi()-m_frames.low())*pHdr->fPctPos);
		m_frames.insert(CFrame(pos,pHdr->hdr.hWnd),pHdr->nHeight);
//		wnd.ShowWindow(SW_SHOWNA);
		bool bRes=Arrange(rc);
		wnd.SetWindowPos(NULL,0,0,0,0,SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED | SWP_SHOWWINDOW);
		return bRes;
	}

	bool GetDockingPosition(DFDOCKPOS* pHdr,const CRect& /*rc*/) const
	{
		assert(::IsWindow(pHdr->hdr.hWnd));
		const_iterator i=std::find_if(m_frames.begin(),m_frames.end(),CFrame::CCmp(pHdr->hdr.hWnd));
		bool bRes=(i!=m_frames.end());
		if(bRes)
		{
			position pos=*i-m_frames.low();
			pHdr->fPctPos=float(pos)/(m_frames.hi()-m_frames.low());
			pHdr->nHeight=m_frames.get_frame_size(i)-CSplitterBar::GetThickness();
//			pHdr->nWidth=IsHorizontal() ? rc.Height() : rc.Width();
//			pHdr->nWidth-=CSplitterBar::GetThickness();
			if(m_frames.size()==1)
				pHdr->dwDockSide|=CDockingSide::sSingle;
		}
		return bRes;
	}
	bool AcceptDock(DFDOCKRECT* pHdr,const CRect& rc)
	{
		return (!((m_frames.size()==1)
					&&(m_frames.begin()->hwnd()==pHdr->hdr.hWnd)))
						&&baseClass::AcceptDock(pHdr,rc);		
	}
	bool Dock(DFDOCKRECT* pHdr,const CRect& rc)
	{
		assert(::IsWindow(pHdr->hdr.hWnd));
		CWindow wnd(pHdr->hdr.hWnd);
		PrepareForDocking(wnd,pHdr->hdr.hBar);
		CFrame frame(0,pHdr->hdr.hWnd);
		bool bRes=baseClass::Dock(frame,pHdr,rc);
		wnd.SetWindowPos(NULL,0,0,0,0,SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED | SWP_SHOWWINDOW);
//		wnd.ShowWindow(SW_SHOWNA);
		return bRes;

	}
	bool Undock(DFMHDR* pHdr,const CRect& rc)
	{
		bool bRes=baseClass::Undock(pHdr,rc);
		assert(bRes);
		PrepareForUndocking(pHdr->hWnd,pHdr->hBar);
		if(m_frames.size()==0)
		{
			DFMHDR dockHdr;
			dockHdr.hWnd = pHdr->hBar;
			dockHdr.hBar = ::GetParent(pHdr->hBar);
			assert(::IsWindow(dockHdr.hBar));
			dockHdr.code=DC_UNDOCK;
			::SendMessage(dockHdr.hBar,WMDF_DOCK,NULL,reinterpret_cast<LPARAM>(&dockHdr));
            ::PostMessage(dockHdr.hWnd,WM_CLOSE,NULL,NULL);
		}
		return bRes;
	}

	bool Replace(const DFDOCKREPLACE* pHdr,const CRect& rc)
	{
		PrepareForUndocking(pHdr->hdr.hWnd,pHdr->hdr.hBar);
		PrepareForDocking(pHdr->hWnd,pHdr->hdr.hBar);
		bool bRes=baseClass::Replace(pHdr,rc);
		assert(bRes);
		::SetWindowPos(pHdr->hWnd,NULL,0,0,0,0,SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED | SWP_SHOWWINDOW);
//		::ShowWindow(pHdr->hWnd,SW_SHOWNA);
		return bRes;
	}

};

template<class T>
class CPtrFrame  
{
	typedef CPtrFrame<T> thisClass;
public:
	typedef long position;
	class CCmp
	{
	public:
		CCmp(HWND hWnd)	:m_hWnd(hWnd)
		{
		}
		bool operator ()(const thisClass& frame) const
		{
			return (frame.hwnd() == m_hWnd);
		}
	protected:
		HWND m_hWnd;
	};

	CPtrFrame(const CPtrFrame& x):m_pos(x.m_pos),m_ptr(x.m_ptr)  
	{
	}
	CPtrFrame(position pos, T* ptr)
		:m_pos(pos),m_ptr(ptr)  
	{
	}
	HWND hwnd() const
	{
		return m_ptr->operator HWND();
	}

	operator position() const
	{
		return m_pos;
	}

	thisClass& operator += (position val)
	{
		m_pos+=val;
		return *this;
	}
	thisClass& operator -= (position val)
	{
		m_pos-=val;
		return *this;
	}
	
	thisClass& operator = (position pos)
	{
		m_pos=pos;
		return *this;
	}

	HDWP DeferFramePos(HDWP hdwp,long x1,long y1,long x2,long y2) const
	{
		return m_ptr->DeferFramePos(hdwp,x1,y1,x2,y2);
	}
	T* operator ->() const
	{
		return m_ptr.get();
	}
protected:
	position m_pos;
#ifdef USE_BOOST
	mutable boost::shared_ptr<T> m_ptr;
#else
	mutable std::auto_ptr<T> m_ptr;
#endif
};


struct IFrame
{
	virtual  ~IFrame(){};
	virtual  HWND hwnd() const=0;
	operator HWND() const 
	{
		return hwnd();
	}
	virtual bool AcceptDock(DFDOCKRECT* pHdr) const=0;
	virtual HDWP DeferFramePos(HDWP hdwp,long x1,long y1,long x2,long y2) const
	{
		return ::DeferWindowPos(hdwp,hwnd(),
								NULL,
								x1,y1,
								x2-x1,y2-y1,
								SWP_NOZORDER | SWP_NOACTIVATE);
	}

};


class CWindowPtrWrapper : public IFrame
{
public:
	CWindowPtrWrapper(HWND* phWnd):m_phWnd(phWnd)
	{
	}
	virtual HWND hwnd() const
	{
		return (*m_phWnd);
	}
	virtual bool AcceptDock(DFDOCKRECT* /*pHdr*/) const
	{
		return false;
	}
	virtual HDWP DeferFramePos(HDWP hdwp,long x1,long y1,long x2,long y2) const
	{
		if(*m_phWnd!=NULL)
			hdwp=::DeferWindowPos(hdwp,hwnd(),
									NULL,
									x1,y1,
									x2-x1,y2-y1,
									SWP_NOZORDER | SWP_NOACTIVATE);
		return hdwp;
	}

protected:
	HWND* m_phWnd;
};

//TImbeddedPackegeWnd
template<class TPackageFrame,class TTraits = CDockingWindowTraits >
class CSubWndFramesPackage : 
		public CRect,
		public CWndFramesPackageBase<CPtrFrame<IFrame>,TTraits >
{
	typedef CPtrFrame<IFrame> CFrame;
	typedef TTraits CTraits;
	typedef CTraits::CSplitterBar	CSplitterBar;
	typedef CSubWndFramesPackage<TPackageFrame,TTraits> thisClass;
	typedef CWndFramesPackageBase<CFrame,TTraits >		baseClass;
	typedef TPackageFrame	CPackageFrame;
	enum {controlledLen=(15+CSplitterBar::sbThickness)};
protected:
	class CFrameWrapper : public IFrame
	{
	public:
		CFrameWrapper(thisClass* ptr):m_ptr(ptr)
		{
		}
		virtual ~CFrameWrapper()
		{
		}
		virtual  HWND hwnd() const
		{
			return NULL;
		}
		virtual bool AcceptDock(DFDOCKRECT* pHdr) const
		{
			return m_ptr->AcceptDock(pHdr);
		}
		virtual HDWP DeferFramePos(HDWP hdwp,long x1,long y1,long x2,long y2) const
		{
			m_ptr->UpdateLayout(CRect(x1,y1,x2,y2));
			return hdwp;
		}
	protected:
		thisClass* m_ptr;
	};
public:
	CSubWndFramesPackage(bool bHorizontal)
		:baseClass(bHorizontal)
	{
	}
	HCURSOR GetCursor(const CPoint& pt) const
	{
		return baseClass::GetCursor(pt,*this);
	}
	bool StartSliding(HWND hWnd,const CPoint& pt,bool bGhostMove)
	{
		return baseClass::StartSliding(hWnd,pt,*this,bGhostMove);
	}
	bool UpdateLayout(const CRect& rc)
	{
		CopyRect(rc);
		return baseClass::UpdateLayout(*this);
	}
	void Draw(CDC& dc)
	{
		baseClass::Draw(dc,*this);
	}

	bool AcceptDock(DFDOCKRECT* pHdr)
	{
		bool bRes=PtInRect(CPoint (pHdr->rect.left,pHdr->rect.top))==TRUE;
		if(bRes)
		{
			CBounds dfbounds;
			if(IsHorizontal())
			{
				dfbounds.low=pHdr->rect.left;
				dfbounds.hi=pHdr->rect.right;
			}
			else
			{
				dfbounds.low=pHdr->rect.top;
				dfbounds.hi=pHdr->rect.bottom;
			}
			const_iterator i=m_frames.locate(dfbounds.low);
			assert(i!=m_frames.end());
//			if(i!=m_frames.end())
//			{
				CBounds fbounds(m_frames.get_frame_low(i),m_frames.get_frame_hi(i));
				if(((fbounds.low+controlledLen)>dfbounds.low)
					|| //((dfbounds.low>(fbounds.low+fbounds.hi)/2) && (dfbounds.hi>=fbounds.hi)) )
					((dfbounds.low>fbounds.hi-(fbounds.hi-fbounds.low)/3) && (dfbounds.hi>=fbounds.hi)) )
					bRes=baseClass::AcceptDock(pHdr,*this);					
				else
					bRes=(*i)->AcceptDock(pHdr);
//			}
		}
		return bRes;
	}
	bool Undock(const DFMHDR* pHdr,HWND hBoundWnd)
	{
		iterator i=std::find_if(m_frames.begin(),m_frames.end(),CFrame::CCmp(pHdr->hWnd));
		assert(i!=m_frames.end());
		m_frames.erase(i,CFrame::CCmp(hBoundWnd));
		return Arrange(*this);
//		return UpdateLayout(*this);
	}
	bool Dock(DFDOCKRECT* pHdr)
	{
		CPackageFrame* ptr=CPackageFrame::CreateInstance(pHdr->hdr.hBar,!IsHorizontal());
		bool bRes=(ptr!=0);
		if(bRes)
		{
			HWND hDockWnd=pHdr->hdr.hWnd;
			pHdr->hdr.hWnd=ptr->hwnd();
			CFrame frame(0,ptr);
			bRes=baseClass::Dock(frame,pHdr,*this);
			assert(bRes);
			if(bRes)
			{
				pHdr->hdr.hWnd=hDockWnd;
				pHdr->hdr.hBar=ptr->hwnd();
				CWindow bar(pHdr->hdr.hBar);
				bar.GetWindowRect(&(pHdr->rect));
				bRes=::SendMessage(ptr->hwnd(),WMDF_DOCK,NULL,reinterpret_cast<LPARAM>(pHdr))!=FALSE;
			}
		}
		return bRes;
	}
	bool GetDockingPosition(DFDOCKPOS* pHdr,HWND hBoundWnd) const
	{
		const_iterator i=std::find_if(m_frames.begin(),m_frames.end(),CFrame::CCmp(pHdr->hdr.hBar));
		bool bRes=(i!=m_frames.end());
		if(bRes)
		{
			pHdr->nWidth=m_frames.get_frame_size(i)-CSplitterBar::GetThickness();
			CFrames::size_type dWnd=std::distance(m_frames.begin(),i);
			i=std::find_if(m_frames.begin(),m_frames.end(),CFrame::CCmp(hBoundWnd));
			assert(i!=m_frames.end());
			CFrames::size_type dBWnd=std::distance(m_frames.begin(),i);
			if(dBWnd>dWnd)
			{
				pHdr->nBar=dWnd;
				pHdr->dwDockSide|=CDockingSide::sTop;
			}
			else
			{
				pHdr->nBar=m_frames.size()-dWnd-1;
//				pHdr->dwDockSide|=0;
			}
			bRes=(::SendMessage(pHdr->hdr.hBar,WMDF_DOCK,NULL,reinterpret_cast<LPARAM>(pHdr))!=FALSE);
		}
		return bRes;
	}

	bool SetDockingPosition(DFDOCKPOS* pHdr,HWND hBoundWnd)
	{
		bool bRes=true;
		CDockingSide side(pHdr->dwDockSide);
		if(side.IsTop())
		{
			iterator i=search_n(m_frames.begin(),m_frames.end(),CFrame::CCmp(hBoundWnd),pHdr->nBar);
			assert(i!=m_frames.end());
			if(i->hwnd()==hBoundWnd || side.IsSingle())
			{
				CPackageFrame* ptr=CPackageFrame::CreateInstance(pHdr->hdr.hBar,!IsHorizontal());
				bRes=(ptr!=0);
				if(bRes)
				{
//					i=m_frames.insert(i,CFrame(*i,ptr),pHdr->nWidth);
					i=m_frames.insert(i,CFrame::CCmp(hBoundWnd),CFrame(*i,ptr),pHdr->nWidth);
					bRes=Arrange(*this);
					assert(bRes);
				}
			}
			pHdr->hdr.hBar=i->hwnd();
		}
		else
		{
			reverse_iterator ri=search_n(m_frames.rbegin(),m_frames.rend(),CFrame::CCmp(hBoundWnd),pHdr->nBar);   
			assert(ri!=m_frames.rend());
			iterator i=ri.base();
			if(/*ri->hwnd()*/(*ri).hwnd()==hBoundWnd || side.IsSingle())
			{
				CPackageFrame* ptr=CPackageFrame::CreateInstance(pHdr->hdr.hBar,!IsHorizontal());
				bRes=(ptr!=0);
				if(bRes)
				{					
					position pos=(i==m_frames.end())? m_frames.hi():*i;
					pos-=pHdr->nWidth+CSplitterBar::GetThickness();
					if(pos<m_frames.low())
						pos=m_frames.low();
//					i=m_frames.insert(i,CFrame(pos,ptr),pHdr->nWidth);
					i=m_frames.insert(i,CFrame::CCmp(hBoundWnd),CFrame(pos,ptr),pHdr->nWidth);
					bRes=Arrange(*this);
					assert(bRes);
					pHdr->hdr.hBar=i->hwnd();
				}
			}
			else 
				pHdr->hdr.hBar=/*ri->hwnd()*/(*ri).hwnd();
		}
		if(bRes)
		{
			bRes=(::SendMessage(pHdr->hdr.hBar,WMDF_DOCK,NULL,reinterpret_cast<LPARAM>(pHdr))!=FALSE);
			assert(bRes);
		}
		return bRes;
	}

	bool Insert(HWND* ptr, const CRect& rc)
	{
		DFDOCKRECT dockHdr;
		::CopyRect(&dockHdr.rect,&rc);
		CFrame frame(0, new CWindowPtrWrapper(ptr));
		return baseClass::Dock(frame,&dockHdr,*this);
	}
	bool Insert(thisClass* ptr, const CRect& rc)
	{
		DFDOCKRECT dockHdr;
		::CopyRect(&dockHdr.rect,&rc);
		CFrame frame(0, new CFrameWrapper(ptr));
		return baseClass::Dock(frame,&dockHdr,*this);
	}

	struct CSystemSettingsChange
	{
		void operator()( const CFrame& frame)
		{
			HWND hWnd=frame.hwnd();
			if(hWnd!=NULL)
			{
				assert(IsWindow(hWnd));
				::SendMessage(hWnd,WM_SETTINGCHANGE,NULL,NULL);
			}
		}
	};
	void SystemSettingsChange()
	{
		std::for_each(m_frames.begin(),m_frames.end(),CSystemSettingsChange());
	}
};

}//namespace dockwins

#endif // !defined(AFX_WNDFRMPKG_H__4C823036_1E4A_4DD5_8C4D_5E480DCED39F__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