Click here to Skip to main content
15,886,016 members
Articles / Desktop Programming / MFC

Resize/Reposition the Controls in a Dialog at your Pleasure

Rate me:
Please Sign up or sign in to vote.
4.55/5 (38 votes)
1 Mar 2006CPOL7 min read 238.2K   8.8K   65  
You can resize or reposition the controls in your dialog derived from CSizingDialog to anywhere you wish just by specifying some simple strings or numbers. In addition, most kinds of controls almost don't flicker when moving, which is often a problem in some other solutions.
////////////////////////////////////////////////////////////////////////////
// SizingDialog.cpp :  implementation file
//
// Copyright 2005 Xia Xiongjun( ���۾� ), All Rights Reserved.
//
// E-mail: xj-14@163.com
//
// This source file may be copyed, modified, redistributed  by any means
// PROVIDING that this notice and the authors name and all copyright notices
// remain intact, and PROVIDING it is NOT sold for profit without the authors
// expressed written consent. The author accepts no liability for any 
// damage/loss of business that this product may cause.
//
////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "SizingDialog.h"
#include ".\SizingDialog.h"

////////////////////////////////////////////////////////////////////////////
// class CCtrlInfo

CCtrlInfo::CCtrlInfo(LPCRECT rcInit /*= NULL*/,
		double dRateLeft /*= 0.0*/,  double dRateRight  /*= 0.0*/, 
		double dRateTop  /*= 0.0*/,  double dRateBottom /*= 0.0*/)
	: m_rcInit    (rcInit)
	, m_dRateLeft (dRateLeft),  m_dRateRight  (dRateRight)
	, m_dRateTop  (dRateTop),   m_dRateBottom (dRateBottom)
{
}

CCtrlInfo::~CCtrlInfo(void)
{
}

BOOL CCtrlInfo::Modify(LPCRECT rcInit,
		double dRateLeft /*= 0.0*/,  double dRateRight    /*= 0.0*/, 
		double dRateTop  /*= 0.0*/,  double dRateBottom   /*= 0.0*/) 
{
	m_rcInit    = rcInit;
	m_dRateLeft = dRateLeft;  m_dRateRight  = dRateRight;
	m_dRateTop  = dRateTop;   m_dRateBottom = dRateBottom;

	return TRUE;
}

BOOL CCtrlInfo::Modify(const CWnd* pCtrl, const CWnd* pParent, 
		LPCTSTR lpszString, char chSpr /*= '+'*/)
{
	ASSERT(::IsWindow(pCtrl->m_hWnd));
	ASSERT(::IsWindow(pParent->m_hWnd));
	ASSERT(::IsChild(pParent->m_hWnd, pCtrl->m_hWnd));

	pCtrl->GetWindowRect(&m_rcInit);
	pParent->ScreenToClient(&m_rcInit);

	// XR: Get position information from Initialization string
	CString str = lpszString;
	str.Remove(' ');
	str.MakeUpper();

	int nLen = str.GetLength();
	int posSpr = -1;
	int posSprNext = 0;
	while(posSprNext != -1)
	{
		CString strSection;
		posSprNext = str.Find(chSpr, posSpr + 1);  // XR: default separator between sections is '+'
		if (posSprNext == -1)
			strSection = str.Mid(posSpr + 1, nLen - posSpr - 1);
		else
			strSection = str.Mid(posSpr + 1, posSprNext - posSpr - 1);
		
		if (!this->ExtractOptions(strSection, pCtrl, pParent))
			return FALSE;

		posSpr = posSprNext;
	}
	return TRUE;
}

BOOL CCtrlInfo::ExtractOptions(LPCTSTR lpszSection, 
		const CWnd* pCtrl /*= NULL*/, const CWnd* pParent /*= NULL*/) 
{
	CString strWord;
	double dCoef;
	this->GetCoefficientAndWord(lpszSection, strWord, dCoef);

	if (strWord.IsEmpty())
		strWord = _T("R");
	
	// XR: synchronize with the right/bottom border of the window in 
	// horizontal/vertical direction.
	// XR: dCoef is the factor which you can specify to determine the degree
	// how the controls' position is affected by the parent window border.
	// dCoef is set to 1.0 when you don't specify a value for it.
	if (strWord == _T("X") || strWord == _T("Y") || strWord == _T("XY"))
	{
		if (strWord != _T("Y"))
			m_dRateLeft = m_dRateRight = dCoef;
		if (strWord != _T("X"))
			m_dRateTop = m_dRateBottom = dCoef;
	}

	// XR: only the right/bottom border of the controls will synchronize with 
	// the right/bottom border of the window in horizontal/vertical direction.
	else if (strWord == _T("C")  || strWord == _T("CXY") ||
		     strWord == _T("CX") || strWord == _T("CY"))
	{
		if (strWord != _T("CY"))
		{
			m_dRateLeft = 0.0;
			m_dRateRight = dCoef;
		}
		if (strWord != _T("CX"))
		{
			m_dRateTop = 0.0;
			m_dRateBottom = dCoef;
		}
	}

	// XR: keep the position and size of the controls and the window's client area 
	// be in same proportion when resizing the window.
	else if (strWord == _T("R")  || strWord == _T("RXY") ||	
			 strWord == _T("RX") || strWord == _T("RY"))
	{
		ASSERT(::IsWindow(pCtrl->m_hWnd));
		ASSERT(::IsWindow(pParent->m_hWnd));
		ASSERT(::IsChild(pParent->m_hWnd, pCtrl->m_hWnd));

		CRect rcWnd;
		pParent->GetClientRect(&rcWnd);

		if (strWord != _T("RY"))
		{
			m_dRateLeft   = dCoef*(m_rcInit.left   - rcWnd.left)/rcWnd.Width();
			m_dRateRight  = dCoef*(m_rcInit.right  - rcWnd.left)/rcWnd.Width();
		}
		if (strWord != _T("RX"))
		{
			m_dRateTop    = dCoef*(m_rcInit.top    - rcWnd.top )/rcWnd.Height();
			m_dRateBottom = dCoef*(m_rcInit.bottom - rcWnd.top )/rcWnd.Height();
		}
	}

	// XR: Error
	else
	{
		CString strErr;
		strErr.Format(_T("'%s' is not predefined keyword"), strWord);
		MessageBox(NULL, strErr, _T("There is something wrong in the expression describing control position"), 
			MB_OK | MB_ICONEXCLAMATION);
		return FALSE;
	}

	return TRUE;
}

// XR: Get coefficient and word from a string such as "0.5X" or "(-1.02)XY" or "(-12.36R)"
void CCtrlInfo::GetCoefficientAndWord(LPCTSTR lpszSection,
									  CString& strWord, double& dCoef) const
{
	strWord = lpszSection;
	dCoef   = 1.0;

	CString str(lpszSection);
	int nLen = str.GetLength();

	CString strCoef;
	char ch = str.GetAt(0);

	if ( ch == '(' )
	{
		int nIndex = str.ReverseFind( ')' );

		if (nIndex == -1)				// XR: No the other bracket
			return;
		if (nIndex == nLen -1)			// XR: All the string is bracketed
			return this->GetCoefficientAndWord
					(strWord.Mid(1, nLen-2), strWord, dCoef);

		strWord = str.Right(nLen - nIndex -1);
		strCoef = str.Mid(1, nIndex - 1);
		if (!strCoef.IsEmpty())
			dCoef = ::atof(strCoef);

		return;
	}

	for (int i = 0; i < nLen; i++)
	{
		ch = str.GetAt(i);
		if (::isdigit(ch) || ch == '.' || ch == 'E'
			|| ch == '+' || ch == '-' || ::isspace(ch))
			strCoef.AppendChar(ch);
		else
		{
			strWord = str.Right(nLen - i);
			break;
		}
	}
	if (i == nLen)
		strWord.Empty();
	if (!strCoef.IsEmpty())
		dCoef = ::atof(strCoef);
}


////////////////////////////////////////////////////////////////////////////
// CSizingDialog dialog

// XR: Global functions
BOOL IsGroupBox(const CWnd *pWnd);
void ResizeGroupBox(CWnd* pGBox, const CWnd* pParent, const CCtrlInfo* pInfo,
		double dx, double dy);
void GetGroupBoxRgn(const CWnd* pGBox, const CWnd* pParent, CRect* pRc);
void AdjGroupBoxRgn(CRect* pRc, int adj, int nAlign);
void GetWindowTextSize(const CWnd* pWnd, CSize& sz);


IMPLEMENT_DYNAMIC(CSizingDialog, CDialog)

CSizingDialog::CSizingDialog(UINT nIDTemplate, CWnd* pParentWnd /*= NULL*/)
	: CDialog(nIDTemplate, pParentWnd)
{
	m_rcInit.SetRectEmpty();
	ASSERT(m_mapPtToInfo.IsEmpty());
}

CSizingDialog::~CSizingDialog()
{
	POSITION pos = m_mapPtToInfo.GetStartPosition();
	while (pos != NULL)
	{
		void* pCtrl;
		CCtrlInfo* pInfo;
		m_mapPtToInfo.GetNextAssoc(pos, pCtrl, (void *&)pInfo);
		delete pInfo;
		pInfo = NULL;
	}
	m_mapPtToInfo.RemoveAll();
}

void CSizingDialog::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CSizingDialog, CDialog)
	ON_WM_CREATE()
	ON_WM_SIZE()
	ON_WM_GETMINMAXINFO()
	ON_WM_NCHITTEST()
END_MESSAGE_MAP()

// XR: Add a single control or all the controls ( when nID == NULL).

void CSizingDialog::AddResizaleCtrl(UINT nID, LPCTSTR lpszString /*= NULL*/)
{
	this->AddCtrl(nID, DT_STRING, lpszString);
}

void CSizingDialog::AddResizaleCtrl(UINT nID,
		double dRateLeft, double dRateRight, double dRateTop, double dRateBottom) 
{
	double dData[4] = {dRateLeft, dRateRight, dRateTop, dRateBottom};
	this->AddCtrl(nID, DT_NUMBER, dData);
}

void CSizingDialog::AddCtrl(UINT nID, int nDataType, LPCVOID lpData)
{
	if (nID == NULL)		// XR: all the controls
	{
		for (HWND hWnd = ::GetWindow(this->m_hWnd, GW_CHILD); hWnd != NULL;
			hWnd = ::GetNextWindow(hWnd, GW_HWNDNEXT))
		{
			UINT nIDCur = ::GetDlgCtrlID(hWnd);
			ASSERT(nIDCur != 0);
			this->AddCtrl(nIDCur, nDataType, lpData);	// XR: add all controls in turn
		}
		return;
	}

	// XR: add a single control

	CWnd* pCtrl = this->GetDlgItem(nID);
	ASSERT(::IsWindow(pCtrl->m_hWnd));

	LPCTSTR lpszString = (LPCTSTR)lpData;
	double* pDouble	= (double *)lpData;
	double& dRateLeft   = *pDouble;		pDouble++;
	double& dRateRight  = *pDouble;		pDouble++;
	double& dRateTop    = *pDouble;		pDouble++;
	double& dRateBottom = *pDouble;

	CRect rcCtrl;
	pCtrl->GetWindowRect(&rcCtrl);
	this->ScreenToClient(&rcCtrl);

	// XR: Add a new record to CMap object or update an old record

	CCtrlInfo* pInfo;
	if (!m_mapPtToInfo.Lookup(pCtrl, (void *&)pInfo))
		pInfo = new CCtrlInfo;

	if (nDataType == DT_STRING)
		pInfo->Modify(pCtrl, this, lpszString);
	else if (nDataType == DT_NUMBER)
		pInfo->Modify(rcCtrl, dRateLeft,dRateRight, dRateTop, dRateBottom);
	
	m_mapPtToInfo[pCtrl] = pInfo;
}

// XR: Add or update a control-range with the same setting
// which IDs range from nIDStart to nIDEnd.

void CSizingDialog::ModifyResizaleCtrlRange(UINT nIDStart, UINT nIDEnd, 
										 LPCTSTR lpszString /*= NULL*/) 
{
	this->AddCtrlRange(nIDStart, nIDEnd, DT_STRING, lpszString);
}

void CSizingDialog::AddResizaleCtrlRange(UINT nIDStart, UINT nIDEnd, 
										 LPCTSTR lpszString /*= NULL*/)
{
	this->AddCtrlRange(nIDStart, nIDEnd, DT_STRING, lpszString);
}

void CSizingDialog::AddResizaleCtrlRange(UINT nIDStart, UINT nIDEnd, 
		double dRateLeft, double dRateRight, double dRateTop, double dRateBottom)
{
	double dData[4] = {dRateLeft, dRateRight, dRateTop, dRateBottom};
	this->AddCtrlRange(nIDStart, nIDEnd, DT_NUMBER, dData);
}

void CSizingDialog::AddCtrlRange(UINT nIDStart, UINT nIDEnd, 
		int nDataType, LPCVOID lpData)
{
	ASSERT(nIDStart != nIDEnd);

	HWND hCtrlS, hCtrlE;
	int n;
	this->RearrangeID(nIDStart, nIDEnd, hCtrlS, hCtrlE, n);

	HWND hCtrlE_Next = ::GetNextWindow(hCtrlE, GW_HWNDNEXT);
	HWND hCtrl = hCtrlS;
	do{
		ASSERT(hCtrl != NULL);
		UINT nIDTmp = ::GetDlgCtrlID(hCtrl);
		this->AddCtrl(nIDTmp, nDataType, lpData);
		hCtrl = ::GetNextWindow(hCtrl, GW_HWNDNEXT);
	}while(hCtrl != hCtrlE_Next);
}

// XR: Add a special positioned control-range which IDs range from nIDStart to nIDEnd.

void CSizingDialog::AddResizaleCtrlArray(UINT nIDStart, UINT nIDEnd,
		double dS /*= 0.0*/, double dR /*= 1.0*/, BOOL bHori/* = TRUE*/)
// Tips: Set dR = 0.0	 to keep Ctrls Close To Border
//		 Set dR = 1.0	 to keep Ctrls Uniform
//	     Set dR = 1.0e20 to keep Intervals Constant
{
	ASSERT(nIDStart != nIDEnd);

	HWND hCtrlS, hCtrlE;
	int n;
	this->RearrangeID(nIDStart, nIDEnd, hCtrlS, hCtrlE, n);

	// XR: calculate the moving parameters for the controls
	double dI = (1.0 - n*dS)/(n + 2*dR - 1);
	int i = 0;
	HWND hCtrlE_Next = ::GetNextWindow(hCtrlE, GW_HWNDNEXT);
	HWND hCtrl = hCtrlS;
	do{
		ASSERT(hCtrl != NULL);
		UINT nIDTmp = ::GetDlgCtrlID(hCtrl);
		if (bHori)
			this->AddResizaleCtrl(nIDTmp,
				dR*dI + dS*i + dI*i, dR*dI + dS*(i + 1) + dI*i, 0.0, 0.0);
		else
			this->AddResizaleCtrl(nIDTmp, 
				0.0, 0.0, dR*dI + dS*i + dI*i, dR*dI + dS*(i + 1) + dI*i);		
		i++;
		hCtrl = ::GetNextWindow(hCtrl, GW_HWNDNEXT);
	}while(hCtrl != hCtrlE_Next);
}

// XR: correct the tab order of two specified controls' ID, 
// get their handle and the number of controls between them
void CSizingDialog::RearrangeID(UINT& nReIDS, UINT& nReIDE, 
								HWND& hCtrlS, HWND& hCtrlE, int& nNum) const
{
	ASSERT(nReIDS != nReIDE);
	ASSERT(::IsChild(this->m_hWnd, this->GetDlgItem(nReIDS)->m_hWnd));
	ASSERT(::IsChild(this->m_hWnd, this->GetDlgItem(nReIDS)->m_hWnd));

	nNum = 0;
	for (HWND hCtrl = ::GetWindow(this->m_hWnd, GW_CHILD); hCtrl != NULL; 
		 hCtrl = ::GetNextWindow(hCtrl, GW_HWNDNEXT))
	{
		UINT nIDTmp = ::GetDlgCtrlID(hCtrl);
		if (nNum == 0 && (nIDTmp == nReIDS || nIDTmp == nReIDE))
		{							// XR: First of all
			nNum++;
			if (nIDTmp == nReIDE)	// XR: correct the tab order
			{
				nIDTmp = nReIDS; 
				nReIDS = nReIDE;
				nReIDE = nIDTmp;
			}
			continue;
		}
		if (nNum > 0)				// XR: processing...
		{
			nNum++;
			if (nIDTmp == nReIDE)	// XR: end
			{
				hCtrlS = this->GetDlgItem(nReIDS)->m_hWnd;
				hCtrlE = this->GetDlgItem(nReIDE)->m_hWnd;
				break;
			}
		}
	}
}

// CSizingDialog message handlers

int CSizingDialog::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (CDialog::OnCreate(lpCreateStruct) == -1)
		return -1;

	// XR: set the dialog to be resizable, add MINIMIZEBOX and MAXIMIZEBOX.
	this->ModifyStyle(NULL, WS_SIZEBOX | WS_MINIMIZEBOX | WS_MAXIMIZEBOX);

	// XR: save Initial window size to m_rcInit
	this->GetWindowRect(&m_rcInit);

	return 0;
}

void CSizingDialog::OnGetMinMaxInfo(MINMAXINFO* lpMMI)
{
	// XR: set the minimum window size is intial size.
	lpMMI->ptMinTrackSize.x = m_rcInit.Width();
	lpMMI->ptMinTrackSize.y = m_rcInit.Height();

	CDialog::OnGetMinMaxInfo(lpMMI);
}

UINT CSizingDialog::OnNcHitTest(CPoint point)
{
	// XR: move the window when click.
	UINT nHitTest = CDialog::OnNcHitTest(point);	
	if(nHitTest == HTCLIENT)
		nHitTest = HTCAPTION;

	return nHitTest;
}

void CSizingDialog::OnSize(UINT nType, int cx, int cy)
{
	CDialog::OnSize(nType, cx, cy);

	if (!::IsWindowVisible(this->m_hWnd))
		return;
	this->ResizeControls();
}

//////////////////////////////////////////////////////
// XR: moving the controls

void CSizingDialog::ResizeControls()
{
	// XR: size of the dialog moving
	CRect rcDlg;
	this->GetWindowRect(&rcDlg);
	int dx = rcDlg.Width()  - m_rcInit.Width();
	int dy = rcDlg.Height() - m_rcInit.Height();

	// XR: move the controls
	POSITION pos = m_mapPtToInfo.GetStartPosition();
	while (pos != NULL)
	{
		CWnd* pCtrl;
		CCtrlInfo* pInfo;
		m_mapPtToInfo.GetNextAssoc(pos, (void *&)pCtrl, (void *&)pInfo);
		ASSERT(::IsChild(this->m_hWnd, pCtrl->m_hWnd));

		if (::IsGroupBox(pCtrl))
		{
			::ResizeGroupBox(pCtrl, this, pInfo, dx, dy);
			continue;
		}

		CRect rcCtrlOld;
		pCtrl->GetWindowRect(&rcCtrlOld);
		this->ScreenToClient(&rcCtrlOld);

		CRect rcCtrl = pInfo->m_rcInit;
		rcCtrl.left   += LONG(dx*pInfo->m_dRateLeft);
		rcCtrl.right  += LONG(dx*pInfo->m_dRateRight);
		rcCtrl.top    += LONG(dy*pInfo->m_dRateTop);
		rcCtrl.bottom += LONG(dy*pInfo->m_dRateBottom);

		BOOL bVisible = ::IsWindowVisible(pCtrl->m_hWnd);
		pCtrl->SetRedraw(FALSE);
		pCtrl->MoveWindow(&rcCtrl);
		if (!bVisible) 
			continue;
		pCtrl->SetRedraw(TRUE);
		
		this->InvalidateCtrlBorder(&rcCtrlOld, &rcCtrl);
		pCtrl->InvalidateRect(NULL);
	}
}

void CSizingDialog::InvalidateCtrlBorder(	// XR: erase lpRectOld - lpRectNew
	LPCRECT lpRectOld, LPCRECT lpRectNew, BOOL bErase /*= TRUE*/)
{
	CRect rcBorder;	

	// Top  Part
	if (lpRectNew->top > lpRectOld->top)
	{
		rcBorder.SetRect(lpRectOld->left, lpRectOld->top,
			lpRectOld->right, lpRectNew->top);
		this->InvalidateRect(&rcBorder, bErase);
	}

	// Bottom Part	
	if (lpRectNew->bottom < lpRectOld->bottom)
	{
		rcBorder.SetRect(lpRectOld->left, lpRectNew->bottom,
			lpRectOld->right, lpRectOld->bottom);
		this->InvalidateRect(&rcBorder, bErase);
	}

	// Left Part
	if (lpRectNew->left > lpRectOld->left)
	{
		rcBorder.SetRect(lpRectOld->left, lpRectOld->top,
			lpRectNew->left, lpRectOld->bottom);
		this->InvalidateRect(&rcBorder, bErase);
	}

	// Right Part
	if (lpRectNew->right < lpRectOld->right)
	{
		rcBorder.SetRect(lpRectNew->right, lpRectOld->top,
			lpRectOld->right, lpRectOld->bottom);
		this->InvalidateRect(&rcBorder, bErase);
	}
}


////////////////////////////////////////////////////////////////////////////
// XR: Global functions

void ResizeGroupBox(CWnd* pGBox, const CWnd* pParent, const CCtrlInfo* pInfo,
		double dx, double dy)
{
	ASSERT(::IsGroupBox(pGBox));
	ASSERT(::IsWindow(pParent->m_hWnd));
	ASSERT(::IsChild(pParent->m_hWnd, pGBox->m_hWnd));

	CRect rcGBoxOld[10];
	::GetGroupBoxRgn(pGBox, pParent, rcGBoxOld);

	CRect rcCtrl = pInfo->m_rcInit;
	rcCtrl.left   += LONG(dx*pInfo->m_dRateLeft);
	rcCtrl.right  += LONG(dx*pInfo->m_dRateRight);
	rcCtrl.top    += LONG(dy*pInfo->m_dRateTop);
	rcCtrl.bottom += LONG(dy*pInfo->m_dRateBottom);

	BOOL bVisible = ::IsWindowVisible(pGBox->m_hWnd);
	pGBox->SetRedraw(FALSE);
	pGBox->MoveWindow(&rcCtrl);
	if (!bVisible) 
		return;
	pGBox->SetRedraw(TRUE);

	CRect rcGBox[10];
	::GetGroupBoxRgn(pGBox, pParent, rcGBox);

	for (int i = 1; i < 10; i++)
		((CSizingDialog *)pParent)->InvalidateCtrlBorder(&rcGBoxOld[i], &rcGBox[i]);

	// XR: update controls
	pGBox->InvalidateRect(NULL);
}

/////////////////////////////////////////////////////////////////////////
//
// void GetGroupBoxRgn(const CWnd* pGBox, const CWnd* pParent, CRect* pRc)
//
// XR: The meanings of pRc's elements in a GroupBox, 0 means whole rectangle
//
//                    ______________9____________
//                   |							 |
//                   7							 8
//                   |_____5_____[ 4 ]_____6_____|
//                   |	                         |
//                   |							 |
//                   |							 |
//                   |							 |
//                   |							 |
//                   |							 |
//                   |							 |
//                   2							 3
//                   |							 |
//                   |							 |
//                   |							 |
//                   |							 |
//                   |							 |
//                   |							 |
//                   |							 |
//                   |_____________1_____________|
//
//
/////////////////////////////////////////////////////////////////////////

void GetGroupBoxRgn(const CWnd* pGBox, const CWnd* pParent, CRect* pRc)
{
	ASSERT(::IsGroupBox(pGBox));
	ASSERT(::IsWindow(pParent->m_hWnd));
	ASSERT(::IsChild(pParent->m_hWnd, pGBox->m_hWnd));

	CRect rcGBox;
	pGBox->GetWindowRect(&rcGBox);
	pParent->ScreenToClient(&rcGBox);

	CSize sz;
	::GetWindowTextSize(pGBox, sz);

	// XR: whole rect
	pRc[0] = rcGBox;

	// XR: bottom line
	pRc[1].SetRect(		
		rcGBox.left,  rcGBox.bottom - 2,
		rcGBox.right, rcGBox.bottom);

	// XR: left line
	pRc[2].SetRect(		
		rcGBox.left,     rcGBox.top + sz.cy / 2,
		rcGBox.left + 2, rcGBox.bottom); 

	// XR: right line
	pRc[3].SetRect(
		rcGBox.right - 2, rcGBox.top + sz.cy / 2,
		rcGBox.right,     rcGBox.bottom); 

	// XR: text rect 
	CRect rcText(CPoint(0, 0), sz);

	int cxOffset = 9;

	LONG lStyle = ::GetWindowLong(pGBox->m_hWnd, GWL_STYLE);
	lStyle &= 0x00000300L;	// XR: extract the alignment property

	int nAlign = -1;		// XR: for later user
	if (lStyle == BS_CENTER)
	{
		cxOffset = (rcGBox.Width() - sz.cx) / 2;
		nAlign = 0;
	}
	else if (lStyle == BS_RIGHT)
	{
		cxOffset = rcGBox.Width() - sz.cx - 9;
		nAlign = 1;
	}

	rcText.MoveToXY(rcGBox.left + cxOffset, rcGBox.top);
	rcText.InflateRect(2, 0, 2, 2);

	pRc[4] = rcText;

	// XR: left upper line
	pRc[5].SetRect(		
		rcGBox.left, rcGBox.top + sz.cy / 2,
		rcText.left, rcGBox.top + sz.cy / 2 + 2 );

	// XR: right upper line
	pRc[6].SetRect(		
		rcText.right, rcGBox.top + sz.cy / 2,
		rcGBox.right, rcGBox.top + sz.cy / 2 + 2 );


	// XR: Additional adjustment needed if the groupbox is not created 
	// with the default style

	int adj = 0;

	LONG lStyleEx = ::GetWindowLong(pGBox->m_hWnd, GWL_EXSTYLE);

	if ((lStyleEx & WS_EX_CLIENTEDGE) == WS_EX_CLIENTEDGE)   
		adj += 2;
	if ((lStyleEx & WS_EX_DLGMODALFRAME) == WS_EX_DLGMODALFRAME) 
		adj += 3;
	if ((lStyleEx & WS_EX_STATICEDGE) == WS_EX_STATICEDGE &&
		(lStyleEx & WS_EX_DLGMODALFRAME) != WS_EX_DLGMODALFRAME) 
		adj += 1;

	if (adj != 0)
	{
		::AdjGroupBoxRgn(pRc, adj, nAlign);
	}
	else
	{
		for (int i = 7; i < 10; i++)
			pRc[i].SetRectEmpty();
	}
}

void AdjGroupBoxRgn(CRect* pRc, int a, int nAlign)
{
	ASSERT(nAlign >= -1 && nAlign <= 1);

	pRc[1].InflateRect( 0,         a,		   0,	0);
	pRc[2].InflateRect( 0,        -a,		   a,   0);
	pRc[3].InflateRect( a,        -a,		   0,   0);
	pRc[4].InflateRect( a*nAlign, -a,  -a*nAlign,   a);
	pRc[5].InflateRect( 0,        -a,  -a*nAlign,   a);
	pRc[6].InflateRect( a*nAlign, -a,		   0,   a);

	pRc[7].SetRect(pRc[0].left, pRc[0].top, pRc[0].left + a, pRc[5].top);
	pRc[8].SetRect(pRc[0].right - a, pRc[0].top, pRc[0].right, pRc[6].top);
	pRc[9].SetRect(pRc[0].left, pRc[0].top, pRc[0].right, pRc[0].top + a);
}

void GetWindowTextSize(const CWnd* pWnd, CSize& sz)
{
	ASSERT(::IsWindow(pWnd->m_hWnd));

	CString str;
	pWnd->GetWindowText(str);
	if (str.IsEmpty())
		str = _T("a");		// XR: To avoid getting zero valued sz.

	CClientDC dc((CWnd *)pWnd);
	CFont* pFont = pWnd->GetFont();
	CFont* pFontOld = dc.SelectObject(pFont);

	sz = dc.GetTextExtent(str);
	
	dc.SelectObject(pFontOld);
}

BOOL IsGroupBox(const CWnd *pWnd)
{
	HWND hWnd = pWnd->m_hWnd;
	ASSERT(::IsWindow(hWnd));

	CString str;
	::GetClassName(hWnd, str.GetBuffer(100), 100);
	str.ReleaseBuffer();

	if (str != _T("Button"))
		return FALSE;

	UINT nStyle = ((CButton *)pWnd)->GetButtonStyle();
	nStyle &= 0x0000000FL;

	return nStyle == BS_GROUPBOX;
}

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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
China China
_____________________________
Xia Xiongjun loves this site. Smile | :)

Comments and Discussions