Click here to Skip to main content
15,885,366 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 833.5K   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 would be nice.

#ifndef WTL_DW_DOCKMISC_H_INCLUDED_
#define WTL_DW_DOCKMISC_H_INCLUDED_

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

#include <cassert>
#include <SimpleSplitterBar.h>

namespace dockwins{

#ifdef DF_AUTO_HIDE_FEATURES

#ifdef HTOBJECT
#define HTPIN HTOBJECT
#else
#define HTPIN 19
#endif

#endif

#ifndef DF_AUTO_HIDE_FEATURES
template <class TSplitterBar,/* DWORD TDockFrameStyle=0,*/
			DWORD t_dwStyle = 0, DWORD t_dwExStyle = 0>
struct CDockingFrameTraitsT : CWinTraits <t_dwStyle,t_dwExStyle>
{
	typedef TSplitterBar CSplitterBar;
};

typedef CDockingFrameTraitsT< CSimpleSplitterBar<5>,
		WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
		WS_EX_APPWINDOW | WS_EX_WINDOWEDGE> CDockingFrameTraits;


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

#endif
//////////////////messages///////////////////////////
#define WMDF_FIRST  (WM_USER)
#define WMDF_LAST	(WMDF_FIRST+1)

#define WMDF_NDOCKSTATECHANGED	(WMDF_FIRST)
//wParam MAKEWPARAM(DOCK=TRUE\UNDOCK=FALSE,bHorizontal)
//lParam hBar

#define DOCKED2HORIZONTAL(wParam) (HIWORD(wParam))

#define WMDF_DOCK				(WMDF_FIRST+1)
//WMDF_DOCK'z codes:
#define DC_ACCEPT				(1)
#define DC_DOCK					(2)
#define DC_UNDOCK				(3)
#define DC_GETDOCKPOSITION		(4)
#define DC_SETDOCKPOSITION		(5)

#define DC_ADJUSTDRAGRECT		(7)
#define DC_REPLACE				(8)
#define DC_ISBOX				(9)
#define DC_ACTIVATE				(10)

#define DC_ISPINNED				(11)
#define DC_PINUP				(12)

#define DC_GETMINDIST			(13)

#define HDOCKBAR				HWND
#define HNONDOCKBAR				(0)

//WMDF_DOCK'z structures
typedef struct tagDFMHDR
{
	HWND		hWnd;
	HDOCKBAR	hBar;
	UINT		code;
}DFMHDR;

typedef struct tagDFDOCKREPLACE
{
	DFMHDR	hdr;
	HWND	hWnd;
}DFDOCKREPLACE;

typedef struct tagDFDOCKRECT
{
	DFMHDR	hdr;
	RECT	rect;
	DWORD	flag;
}DFDOCKRECT;

typedef struct tagDFDOCKPOS
{
	DFMHDR			hdr;
	DWORD			dwDockSide;
	union
	{
		struct
		{
			unsigned long	nBar;
			float			fPctPos;
			unsigned long	nWidth;
			unsigned long	nHeight;
		};
		RECT	rcFloat;
	};
	unsigned long	nIndex;
}DFDOCKPOS;

typedef struct tagDFDOCKPOSEX
{
	DFDOCKPOS	dockPos;
	RECT		rect;
	BOOL		bDocking;
	BOOL		bVisible;
} DFDOCKPOSEX;

typedef struct tagDFPINUP
{
	DFMHDR			hdr;
	DWORD			dwDockSide;
	unsigned long	nWidth;
	DWORD			dwFlags;
	unsigned long	n;
	HWND*			phWnds;
} DFPINUP;

#define DFPU_VISUALIZE	(1)

class CDockingSide
{
	enum
	{
		mskVertical=1,	//horizontal or vertical
		mskTop=2,			//top or bottom
		mskSide=3
	};
public:
	enum
	{
		sTop=2,sBottom=0,
		sLeft=3,sRight=1,
		sSingle=4,			// only one window in row (or col)
		sInvalid=8,
		sActive=16,
		sPinned=32
	};
	CDockingSide(DWORD side=sInvalid):m_side(side)
	{
	}
	bool IsHorizontal() const
	{
		assert(IsValid());
		return ((m_side&mskVertical)==0);
	}
	bool IsTop() const
	{
		assert(IsValid());
		return ((m_side&mskTop)!=0);
	}
	DWORD Side() const
	{
		assert(IsValid());
		return m_side&mskSide;
	}
	bool IsSingle() const
	{
		assert(IsValid());
		return ((m_side&sSingle)!=0);
	}
	bool IsPinned() const
	{
		assert(IsValid());
		return ((m_side&sPinned)!=0);
	}
	bool IsActive() const
	{
		return ((m_side&sActive)!=0);
	}
	bool IsValid() const
	{
		return ((m_side&sInvalid)==0);
	}
	bool Invalidate()
	{
		Invalidate(m_side);
	}
	static void Invalidate(DWORD& side)
	{
		side|=sInvalid;
	}
	operator DWORD() const
	{
		return m_side;
	}
protected:
	DWORD m_side;
};

class COrientedRect : public CRect
{
public:
	COrientedRect(bool bHorizontal,unsigned long thickness)
		:m_thickness(thickness),m_bHorizontal(bHorizontal)
	{
	}
	void SetOrientation(bool bHorizontal)
	{
		m_bHorizontal=bHorizontal;
	}
	bool GetOrientation() const
	{
		return m_bHorizontal;
	}
	bool IsHorizontal() const
	{
		return m_bHorizontal;
	}
	long GetThickness() const
	{
		return m_thickness;
	}
	bool CalculateRect(CRect& rc,bool bTop)
	{
		CopyRect(rc);
		if(IsHorizontal())
		{
			if(bTop)
				rc.top=bottom=top+GetThickness();
			else
				rc.bottom=top=bottom-GetThickness();
		}
		else
		{
			if(bTop)
				rc.left=right=left+GetThickness();
			else
				rc.right=left=right-GetThickness();
		}
		return true;
	}
protected:
	bool			m_bHorizontal;
	unsigned long	m_thickness;
};

class CDWStyle
{
public:
	enum
	{
		mskIgnoreSysSettings=0x00000001,//depend on system setings (Show window contents while dragging)
		mskGhostDrag=0x00000002,		//Show window contents while dragging
		mskAnimation=0x00000004			//Animate pinned window
	};
	enum
	{
		sIgnoreSysSettings=mskIgnoreSysSettings,
		sUseSysSettings=0,
		sFullDrag=0,
		sGhostDrag=mskGhostDrag,
		sAnimation=mskAnimation,
		sNoAnimation=0
	};
	CDWStyle(DWORD style=0)
		:m_style(style)
	{
	}
	bool IgnoreSystemSettings() const
	{
		return ((m_style&mskIgnoreSysSettings)!=0);
	}
	bool GhostDrag() const
	{
		return ((m_style&mskGhostDrag)!=0);
	}
	bool IsAnimationEnabled() const
	{
		return ((m_style&mskAnimation)!=0);
	}
	CDWStyle Set(const CDWStyle& style)
	{
		m_style=style;
		return *this;
	}
	CDWStyle Set(DWORD mask,const CDWStyle& style)
	{
		m_style&=(~mask);
		m_style|=style;
		return *this;
	}
	CDWStyle Toggle(DWORD mask)
	{
		DWORD imask=~mask;
		DWORD tmask=(~m_style)&mask;
		m_style=(m_style&imask)|tmask;
		return *this;
	}
	operator DWORD() const
	{
		return m_style;
	}
protected:
	DWORD m_style;
};

class CDWSettings
{
protected:
	class CSettings
	{
	public:
		typedef CDWStyle CStyle;

		CSettings()
		{
			Update();
		}

		void Update()
		{
			if(!m_style.IgnoreSystemSettings())
			{
				BOOL bFullDrag;
				BOOL bRes=::SystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0, &bFullDrag, 0);
				if(bRes)
					m_style.Set(CStyle::mskGhostDrag | CStyle::mskAnimation,
										bFullDrag
											? ( CStyle::sFullDrag | CStyle::sAnimation)
											: ( CStyle::sGhostDrag | CStyle::sNoAnimation));
			}
			HFONT hFont=reinterpret_cast<HFONT>(::GetStockObject(DEFAULT_GUI_FONT));
			assert(hFont);
			if(hFont!=m_hfont)
			{
				m_hfont=hFont;
				LOGFONT lf;
				m_hfont.GetLogFont(&lf);
				lf.lfOutPrecision = OUT_TT_ONLY_PRECIS;
				lf.lfEscapement   = 2700;
				lf.lfOrientation  = 2700;
				m_vfont.Attach( ::CreateFontIndirect(&lf) );
				assert(m_vfont.m_hFont);
			}
			::ZeroMemory(&m_ncm, sizeof(m_ncm));
			m_ncm.cbSize = sizeof(m_ncm);
			if(::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(m_ncm), &m_ncm, 0))
			{
				LOGFONT lf = m_ncm.lfSmCaptionFont;
				lf.lfWeight = FW_NORMAL;
				m_hfontSmCaption.Attach( ::CreateFontIndirect(&lf) );
				assert(m_hfontSmCaption.m_hFont);
				lf.lfOutPrecision = OUT_TT_ONLY_PRECIS;
				lf.lfEscapement   = 2700;
				lf.lfOrientation  = 2700;
				m_vfontSmCaption.Attach( ::CreateFontIndirect(&lf) );
				assert(m_vfontSmCaption.m_hFont);
			}

			m_hHResizeCursor=::LoadCursor(NULL, IDC_SIZENS );
			m_hVResizeCursor=::LoadCursor(NULL, IDC_SIZEWE );
			m_colorCoolCtrlBackground=CreateCoolCtrlBackgroundColor();
			m_colorAutoHideBarText=CreateCoolCtrlTextColor();
		}
		static COLORREF CreateCoolCtrlTextColor()
		{
			COLORREF clrBtnTxt=::GetSysColor(COLOR_BTNTEXT);
			COLORREF clrGrayTxt=::GetSysColor(COLOR_GRAYTEXT);
			int red =   GetRValue(clrBtnTxt);
			int green = GetGValue(clrBtnTxt);
			int blue =  GetBValue(clrBtnTxt);

			red+=(GetRValue(clrGrayTxt)-red)/3*2;
			green+=(GetGValue(clrGrayTxt)-green)/3*2;
			blue+=(GetBValue(clrGrayTxt)-blue)/3*2;

			return RGB(red, green, blue);
		}
//I stole the code for background brush color from the cool Daniel Bowen's(dbowen@es.com)
//class CDotNetTabCtrlImpl(DotNetTabCtrl.h) to make background of the auto-hide bars and
//the tab controls identically.
		static COLORREF CreateCoolCtrlBackgroundColor()
		{
			COLORREF clrBtnFace = ::GetSysColor(COLOR_BTNFACE);
			// This is a brave attempt to mimic the algorithm that Visual Studio.Net
			// uses to calculate the tab's background color and inactive tab color.
			// The other colors that VS.Net uses seems to be standard ones,
			// but these two colors are calculated.
			BYTE nRed = 0, nGreen = 0, nBlue = 0, nMax = 0;

			// Early experiments seemed to reveal that the background color is dependant
			// on COLOR_BTNFACE.  The following algorithm is just an attempt
			// to match several empirical results.  I tested with 20 variations
			// on COLOR_BTNFACE and kept track of what the tab background became.
			// I then brought the numbers into Excel, and started crunching on the numbers
			// until I came up with a formula that seems to pretty well match.

			nRed = GetRValue(clrBtnFace);
			nGreen = GetGValue(clrBtnFace);
			nBlue = GetBValue(clrBtnFace);

			nMax = (nRed > nGreen) ? ((nRed > nBlue) ? nRed : nBlue) : ((nGreen > nBlue) ? nGreen : nBlue);
			const BYTE nMagicBackgroundOffset = (nMax > (0xFF - 35)) ? (BYTE)(0xFF - nMax) : (BYTE)35;
			if(nMax == 0)
			{
				nRed = (BYTE)(nRed + nMagicBackgroundOffset);
				nGreen = (BYTE)(nGreen + nMagicBackgroundOffset);
				nBlue = (BYTE)(nBlue + nMagicBackgroundOffset);
			}
			else
			{
				nRed = (BYTE)(nRed + (nMagicBackgroundOffset*(nRed/(double)nMax) + 0.5));
				nGreen = (BYTE)(nGreen + (nMagicBackgroundOffset*(nGreen/(double)nMax) + 0.5));
				nBlue = (BYTE)(nBlue + (nMagicBackgroundOffset*(nBlue/(double)nMax) + 0.5));
			}

			return RGB(nRed, nGreen, nBlue);
		}
		CStyle SetStyle(const CStyle& style)
		{
			m_style=style;
			return m_style;
		}
		CStyle GetStyle() const
		{
			return m_style;
		}
		bool IgnoreSystemSettings() const
		{
			return m_style.IgnoreSystemSettings();
		}
		bool GhostDrag() const
		{
			return m_style.GhostDrag();
		}
		bool IsAnimationEnabled() const
		{
			return m_style.IsAnimationEnabled();
		}
		HFONT HSysFont() const
		{
			return m_hfont;
		}
		HFONT VSysFont() const
		{
			return m_vfont;
		}
		HFONT HSmCaptionFont() const
		{
			return m_hfontSmCaption;
		}
		HFONT VSmCaptionFont() const
		{
			return m_vfontSmCaption;
		}
		long CXMinIcon() const
		{
			return ::GetSystemMetrics(SM_CXSMICON);
		}
		long CYMinIcon() const
		{
			return ::GetSystemMetrics(SM_CYSMICON);
		}
		int CXSmCaption() const
		{
			return m_ncm.iSmCaptionWidth;
		}
		int CYSmCaption() const
		{
			return m_ncm.iSmCaptionHeight;
		}
		COLORREF AutoHideBarTextColor() const
		{
			return m_colorAutoHideBarText;
		}
		COLORREF CoolCtrlBackgroundColor() const
		{
			return m_colorCoolCtrlBackground;
		}
		HCURSOR	HResizeCursor() const
		{
			return m_hHResizeCursor;
		}
		HCURSOR	VResizeCursor() const
		{
			return m_hVResizeCursor;
		}
	protected:
		COLORREF			m_colorCoolCtrlBackground;
		COLORREF			m_colorAutoHideBarText;
		CStyle				m_style;
		CFont				m_vfont;
		CFontHandle			m_hfont;
		CFont				m_hfontSmCaption;
		CFont				m_vfontSmCaption;
		HCURSOR				m_hHResizeCursor;
		HCURSOR				m_hVResizeCursor;
		NONCLIENTMETRICS	m_ncm;

	};
public:
	typedef CSettings::CStyle CStyle;
	void Update() const
	{
		settings.Update();
	}
	CStyle SetStyle(const CStyle& style) const
	{
		return settings.SetStyle(style);
	}
	CStyle GetStyle() const
	{
		return settings.GetStyle();
	}
	bool IgnoreSystemSettings() const
	{
		return settings.IgnoreSystemSettings();
	}
	bool GhostDrag() const
	{
		return settings.GhostDrag();
	}
	bool IsAnimationEnabled() const
	{
		return settings.IsAnimationEnabled();
	}

	HFONT HSysFont() const
	{
		return settings.HSysFont();
	}
	HFONT VSysFont() const
	{
		return settings.VSysFont();
	}
	HFONT HSmCaptionFont() const
	{
		return settings.HSmCaptionFont();
	}
	HFONT VSmCaptionFont() const
	{
		return settings.VSmCaptionFont();
	}
	long CXMinIcon() const
	{
		return settings.CXMinIcon();
	}
	long CYMinIcon() const
	{
		return settings.CYMinIcon();
	}
	int CXSmCaption() const
	{
		return settings.CXSmCaption();
	}
	int CYSmCaption() const
	{
		return settings.CYSmCaption();
	}
	COLORREF AutoHideBarTextColor() const
	{
		return settings.AutoHideBarTextColor();
	}
	COLORREF CoolCtrlBackgroundColor() const
	{
		return settings.CoolCtrlBackgroundColor();
	}
	HCURSOR	HResizeCursor() const
	{
		return settings.HResizeCursor();
	}
	HCURSOR	VResizeCursor() const
	{
		return settings.VResizeCursor();
	}

protected:
	static CSettings settings;
};

void DrawEllipsisText(CDC& dc,LPCTSTR sText,int n,LPRECT prc,bool bHorizontal);

}//namespace dockwins
#endif // WTL_DW_DOCKMISC_H_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