Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version
Go to top

Project Line Counter Add-In v2.10 for VS.NET and VC6

, 29 Jun 2003
Get statistics about your source code with a click of a button
linecount_dll.zip
LineCount.dll
WWhizInterface.mod
LineCount.chm
linecount_src.zip
LineCount.dsw
LineCount_VC5.dsw
LineCount.dsp
LineCount_VC5.dsp
LineCount.odl
LineCount.def
LineCount.clw
Help
arrowrt.gif
Index.hhk
LineCount.chm
LineCount.hhp
mailto.gif
metl011.gif
PLC.gif
small_exclamation.gif
TOC.hhc
weblink.gif
res
idr_main.ico
project.ico
TBarLrge.bmp
TBarMedm.bmp
title.ico
ExtrnSrc
Release
LineCount.dll
WWhizInterface.mod
LineCount.chm
plc110src.zip
plc111.zip
WWhizInterfaceInstaller210Beta1.exe
LineCount.dll
LineCount.chm
plc111src.zip
WWhizInterfaceInstaller210Beta1.exe
LineCount.dll
LineCount.chm
Source
LineCount.dsw
LineCount_VC5.dsw
LineCount.dsp
LineCount_VC5.dsp
LineCount.odl
LineCount.def
Help
.cvsignore
Index.hhk
LineCount.hhp
PLC.gif
TOC.hhc
arrowrt.gif
mailto.gif
metl011.gif
small_exclamation.gif
weblink.gif
res
TBarLrge.bmp
TBarMedm.bmp
idr_main.ico
project.ico
title.ico
ExtrnSrc
Debug
WWhizInterface2D.mod
plc150.zip
WWhizInterfaceInstaller212.exe
LineCount.dll
LineCount.chm
Reports
SampleAnalysis.xls
Simple-BW.xsl
Simple-Color.xsl
plc150src.zip
WWhizInterfaceInstaller212.exe
LineCount.dll
LineCount.chm
SampleAnalysis.xls
Simple-BW.xsl
Simple-Color.xsl
LineCount.dsw
LineCount.dsp
LineCount.odl
LineCount.def
LineCount.clw
.cvsignore
TOC.hhc
linecount.hhp
arrowrt.gif
Index.hhk
PLC.gif
mailto.gif
small_exclamation.gif
weblink.gif
info_dot_small.gif
TBarLrge.bmp
idr_main.ico
project.ico
HdrDownA.bmp
HdrUpA.bmp
title.ico
info.ico
TBarMedm.bmp
WWhizInterface2D.mod
plc200.zip
LineCount.cab
WWhizInterface30VC6_1016.exe
plc200src.zip
.cvsignore
LineCount.def
LineCount.dsp
LineCount.dsw
LineCount.odl
ResizableLib
.cvsignore
ResizableLib.dsp
ResizableLib.dsw
.cvsignore
Index.hhk
LineCount.hhp
PLC.gif
TOC.hhc
arrowrt.gif
info_dot_small.gif
mailto.gif
small_exclamation.gif
weblink.gif
ObjModelVC6
ObjModelVC7
MSADDNDR.tlh
MSO.tlh
dte.tlh
HdrDownA.bmp
HdrUpA.bmp
LineCountVC6.rgs
LineCountVC7.rgs
TBarLrge.bmp
TBarMedm.bmp
idr_main.ico
info.ico
lcgo.bmp
project.ico
title.ico
WWhizInterface2D.mod
plc210.zip
SetupPLC210.exe
plc210src.zip
.cvsignore
LineCount.def
LineCount.dsp
LineCount.dsw
LineCount.odl
.cvsignore
ResizableLib.dsp
ResizableLib.dsw
.cvsignore
Index.hhk
LineCount.hhp
PLC.gif
TOC.hhc
arrowrt.gif
info_dot_small.gif
mailto.gif
small_exclamation.gif
weblink.gif
MSADDNDR.tlh
MSO.tlh
dte.tlh
HdrDownA.bmp
HdrUpA.bmp
LineCountVC6.rgs
LineCountVC7.rgs
TBarLrge.bmp
TBarMedm.bmp
gallery.xsl
idr_main.ico
info.ico
lcgo.bmp
project.ico
title.ico
WWhizInterface2D.mod
// ResizableLayout.cpp: implementation of the CResizableLayout class.
//
/////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2000-2001 by Paolo Messina
// (http://www.geocities.com/ppescher - ppescher@yahoo.com)
//
// The contents of this file are subject to the Artistic License (the "License").
// You may not use this file except in compliance with the License. 
// You may obtain a copy of the License at:
// http://www.opensource.org/licenses/artistic-license.html
//
// If you find this code useful, credits would be nice!
//
/////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "ResizableLayout.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

#define BS_TYPEMASK SS_TYPEMASK

void CResizableLayout::AddAnchor(HWND hWnd, CSize sizeTypeTL, CSize sizeTypeBR)
{
	CWnd* pParent = GetResizableWnd();

	// child window must be valid
	ASSERT(::IsWindow(hWnd));
	// must be child of parent window
	ASSERT(::IsChild(pParent->GetSafeHwnd(), hWnd));
	// top-left anchor must be valid
	ASSERT(sizeTypeTL != NOANCHOR);

	// get control's window class
	CString sClassName;
	GetClassName(hWnd, sClassName.GetBufferSetLength(MAX_PATH), MAX_PATH);
	sClassName.ReleaseBuffer();

	// add the style 'clipsiblings' to a GroupBox
	// to avoid unnecessary repainting of controls inside
	if (sClassName == "Button")
	{
		DWORD style = GetWindowLong(hWnd, GWL_STYLE);
		if ((style & BS_TYPEMASK) == BS_GROUPBOX)
			SetWindowLong(hWnd, GWL_STYLE, style | WS_CLIPSIBLINGS);
	}

	// get parent window's rect
	CRect rectParent;
	GetTotalClientRect(&rectParent);
	// and child control's rect
	CRect rectChild;
	::GetWindowRect(hWnd, &rectChild);
	::MapWindowPoints(NULL, pParent->m_hWnd, (LPPOINT)&rectChild, 2);

	// go calculate margins
	CSize sizeMarginTL, sizeMarginBR;

	if (sizeTypeBR == NOANCHOR)
		sizeTypeBR = sizeTypeTL;
	
	// calculate margin for the top-left corner

	sizeMarginTL.cx = rectChild.left - rectParent.Width() * sizeTypeTL.cx / 100;
	sizeMarginTL.cy = rectChild.top - rectParent.Height() * sizeTypeTL.cy / 100;
	
	// calculate margin for the bottom-right corner

	sizeMarginBR.cx = rectChild.right - rectParent.Width() * sizeTypeBR.cx / 100;
	sizeMarginBR.cy = rectChild.bottom - rectParent.Height() * sizeTypeBR.cy / 100;

	// add to the list and the map
	LayoutInfo layout(hWnd, sizeTypeTL, sizeMarginTL,
		sizeTypeBR, sizeMarginBR, sClassName);

	POSITION pos = m_listLayout.AddTail(layout);
	m_mapLayout.SetAt(hWnd, pos);
}

void CResizableLayout::AddAnchorCallback(UINT nCallbackID)
{
	// one callback control cannot rely upon another callback control's
	// size and/or position (they're updated all together at the end)
	// it can however use a non-callback control, which is updated before

	// add to the list
	LayoutInfo layout;
	layout.nCallbackID = nCallbackID;
	m_listLayoutCB.AddTail(layout);
}

BOOL CResizableLayout::ArrangeLayoutCallback(CResizableLayout::LayoutInfo& /*layout*/)
{
	ASSERT(FALSE);
	// must be overridden, if callback is used
	
	return FALSE;	// no output data
}

void CResizableLayout::ArrangeLayout()
{
	// common vars
	UINT uFlags;
	LayoutInfo layout;
	CRect rectParent, rectChild;
	GetTotalClientRect(&rectParent); // get parent window's rect
	int count = m_listLayout.GetCount();
	int countCB = m_listLayoutCB.GetCount();

	// reposition child windows
	HDWP hdwp = ::BeginDeferWindowPos(count);
	
	POSITION pos = m_listLayout.GetHeadPosition();
	while (pos != NULL)
	{
		// get layout info
		layout = m_listLayout.GetNext(pos);
		
		// calculate new child's position, size and flags for SetWindowPos
		CalcNewChildPosition(layout, rectParent, rectChild, uFlags);

		// only if size or position changed
		if ((uFlags & (SWP_NOMOVE|SWP_NOSIZE)) != (SWP_NOMOVE|SWP_NOSIZE))
		{
			hdwp = ::DeferWindowPos(hdwp, layout.hWnd, NULL, rectChild.left, rectChild.top,
				rectChild.Width(), rectChild.Height(), uFlags);
		}
	}
	::EndDeferWindowPos(hdwp);

	// force updating of non-callback windows
	// since the others may need it

	// reposition callback windows
	hdwp = ::BeginDeferWindowPos(countCB);

	pos = m_listLayoutCB.GetHeadPosition();
	while (pos != NULL)
	{
		// get layout info
		layout = m_listLayoutCB.GetNext(pos);
		// request data
		if (!ArrangeLayoutCallback(layout))
			continue;

		// calculate new child's position, size and flags for SetWindowPos
		CalcNewChildPosition(layout, rectParent, rectChild, uFlags);

		// only if size or position changed
		if ((uFlags & (SWP_NOMOVE|SWP_NOSIZE)) != (SWP_NOMOVE|SWP_NOSIZE))
		{
			hdwp = ::DeferWindowPos(hdwp, layout.hWnd, NULL, rectChild.left, rectChild.top,
				rectChild.Width(), rectChild.Height(), uFlags);
		}
	}
	::EndDeferWindowPos(hdwp);
}

void CResizableLayout::ClipChildWindow(const CResizableLayout::LayoutInfo& layout,
									   CRgn* pRegion)
{
	// obtain window position
	CRect rect;
	::GetWindowRect(layout.hWnd, &rect);
	::MapWindowPoints(NULL, GetResizableWnd()->m_hWnd, (LPPOINT)&rect, 2);

	// use window region if any
	CRgn rgn;
	rgn.CreateRectRgn(0,0,0,0);
	switch (::GetWindowRgn(layout.hWnd, rgn))
	{
	case COMPLEXREGION:
	case SIMPLEREGION:
		rgn.OffsetRgn(rect.TopLeft());
		break;

	default:
		rgn.SetRectRgn(&rect);
	}

	// go clipping?
	if (LikesClipping(layout))
		pRegion->CombineRgn(pRegion, &rgn, RGN_DIFF);
	else
		pRegion->CombineRgn(pRegion, &rgn, RGN_OR);
}

void CResizableLayout::GetClippingRegion(CRgn* pRegion)
{
	CWnd* pWnd = GetResizableWnd();

	// System's default clipping area is screen's size,
	// not enough for max track size:
	// if screen is 1024 x 768 and resizing border is 4 pixels,
	// maximized size is 1024+4*2=1032 x 768+4*2=776,
	// but max track size is 4 pixels bigger 1036 x 780 (don't ask me why!)
	// So, if you resize the window to maximum size, the last 4 pixels
	// are clipped out by the default clipping region, that gets created
	// as soon as you call clipping functions (my guess).

	// reset clipping region to the whole client area
	CRect rect;
	pWnd->GetClientRect(&rect);
	pRegion->CreateRectRgnIndirect(&rect);

	// clip only anchored controls
	LayoutInfo layout;
	POSITION pos = m_listLayout.GetHeadPosition();
	while (pos != NULL)
	{
		// get layout info
		layout = m_listLayout.GetNext(pos);
		
		if (::IsWindowVisible(layout.hWnd))
			ClipChildWindow(layout, pRegion);
	}
	pos = m_listLayoutCB.GetHeadPosition();
	while (pos != NULL)
	{
		// get layout info
		layout = m_listLayoutCB.GetNext(pos);
		// request data
		if (!ArrangeLayoutCallback(layout))
			continue;

		if (::IsWindowVisible(layout.hWnd))
			ClipChildWindow(layout, pRegion);
	}

	// fix for RTL layouts (1 pixel too-much)
	if (pWnd->GetExStyle() & WS_EX_LAYOUTRTL)
		pRegion->OffsetRgn(-1,0);
}

void CResizableLayout::EraseBackground(CDC* pDC)
{
	HWND hWnd = GetResizableWnd()->GetSafeHwnd();

	// retrieve the background brush
	HBRUSH hBrush = NULL;
	// is this a dialog box?
	ATOM atomWndClass = (ATOM)::GetClassLong(hWnd, GCW_ATOM);
	if (WC_DIALOG == MAKEINTATOM(atomWndClass))
	{
		// send a message to the dialog box
		hBrush = (HBRUSH)::SendMessage(hWnd, WM_CTLCOLORDLG,
			(WPARAM)pDC->GetSafeHdc(), (LPARAM)hWnd);
	}
	else
	{
		// take the background brush from the window's class
		hBrush = (HBRUSH)::GetClassLong(hWnd, GCL_HBRBACKGROUND);
	}

	CRgn rgn;
	GetClippingRegion(&rgn);

	::FillRgn(pDC->GetSafeHdc(), rgn, hBrush);
}

// support legacy code (will disappear in future versions)
void CResizableLayout::ClipChildren(CDC* pDC)
{
	CRgn rgn;
	GetClippingRegion(&rgn);
	// the clipping region is in device units
	rgn.OffsetRgn(-pDC->GetWindowOrg());
	pDC->SelectClipRgn(&rgn);
}

void CResizableLayout::GetTotalClientRect(LPRECT lpRect)
{
	GetResizableWnd()->GetClientRect(lpRect);
}

BOOL CResizableLayout::NeedsRefresh(const CResizableLayout::LayoutInfo& layout,
									const CRect& rectOld, const CRect& rectNew)
{
	BOOL bSameWidth = (rectNew.Width() == rectOld.Width());
	BOOL bSameHeight = (rectNew.Height() == rectOld.Height());

	if (bSameWidth && bSameHeight)
		return FALSE;

	// optimistic, no need to refresh
	BOOL bRefresh = FALSE;

	// window classes that need refresh when resized
	if (layout.sWndClass == "Static")
	{
		DWORD style = ::GetWindowLong(layout.hWnd, GWL_STYLE);

		switch (style & SS_TYPEMASK)
		{
		case SS_LEFT:
		case SS_CENTER:
		case SS_RIGHT:
			// word-wrapped text
			bRefresh = bRefresh || !bSameWidth;
			// vertically centered text
			if (style & SS_CENTERIMAGE)
				bRefresh = bRefresh || !bSameHeight;
			break;

		case SS_LEFTNOWORDWRAP:
			// text with ellipsis
			if (style & SS_ELLIPSISMASK)
				bRefresh = bRefresh || !bSameWidth;
			// vertically centered text
			if (style & SS_CENTERIMAGE)
				bRefresh = bRefresh || !bSameHeight;
			break;

		case SS_ENHMETAFILE:
		case SS_BITMAP:
		case SS_ICON:
			// images
		case SS_BLACKFRAME:
		case SS_GRAYFRAME:
		case SS_WHITEFRAME:
		case SS_ETCHEDFRAME:
			// and frames
			bRefresh = TRUE;
			break;
		}
	}

	// window classes that don't redraw client area correctly
	// when the hor scroll pos changes due to a resizing
	BOOL bHScroll = FALSE;
	if (layout.sWndClass == "ListBox")
		bHScroll = TRUE;

	// fix for horizontally scrollable windows
	if (!bSameWidth && bHScroll)
	{
		// get max scroll position
		SCROLLINFO info;
		info.cbSize = sizeof(SCROLLINFO);
		info.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
		if (::GetScrollInfo(layout.hWnd, SB_HORZ, &info))
		{
			// subtract the page size
			info.nMax -= __max(info.nPage-1,0);
		}
		// increment in width
		int nDiff = rectNew.Width() - rectOld.Width();

		// resizing will cause the text to scroll on the right
		// because the scrollbar is going beyond the right limit
		if ((info.nMax > 0) && (nDiff > 0) && (info.nPos + nDiff > info.nMax))
		{
			// needs repainting, due to horiz scrolling
			bRefresh = TRUE;
		}
	}

	return bRefresh;
}

BOOL CResizableLayout::LikesClipping(const CResizableLayout::LayoutInfo& layout)
{
	DWORD style = ::GetWindowLong(layout.hWnd, GWL_STYLE);

	// skip windows that wants background repainted
	if (layout.sWndClass == TOOLBARCLASSNAME && (style & TBSTYLE_TRANSPARENT))
		return FALSE;
	if (layout.sWndClass == "Button" && (style & BS_TYPEMASK) == BS_GROUPBOX)
		return FALSE;
	if (layout.sWndClass == "Static")
	{
		switch (style & SS_TYPEMASK)
		{
		case SS_LEFT:
		case SS_CENTER:
		case SS_RIGHT:
		case SS_SIMPLE:
		case SS_LEFTNOWORDWRAP:
			// text
		case SS_BLACKRECT:
		case SS_GRAYRECT:
		case SS_WHITERECT:
			// filled rects
		case SS_ETCHEDHORZ:
		case SS_ETCHEDVERT:
			// etched lines
		case SS_BITMAP:
			// bitmaps
			return TRUE;
			break;

		case SS_ICON:
		case SS_ENHMETAFILE:
			if (style & SS_CENTERIMAGE)
				return FALSE;
			return TRUE;
			break;

		default:
			return FALSE;
		}
	}

	// assume the others like clipping
	return TRUE;
}

void CResizableLayout::CalcNewChildPosition(const CResizableLayout::LayoutInfo& layout,
								const CRect &rectParent, CRect &rectChild, UINT& uFlags)
{
	CWnd* pParent = GetResizableWnd();

	::GetWindowRect(layout.hWnd, &rectChild);
	::MapWindowPoints(NULL, pParent->m_hWnd, (LPPOINT)&rectChild, 2);
	
	CRect rectNew;

	// calculate new top-left corner
	rectNew.left = layout.sizeMarginTL.cx + rectParent.Width() * layout.sizeTypeTL.cx / 100;
	rectNew.top = layout.sizeMarginTL.cy + rectParent.Height() * layout.sizeTypeTL.cy / 100;
	
	// calculate new bottom-right corner
	rectNew.right = layout.sizeMarginBR.cx + rectParent.Width() * layout.sizeTypeBR.cx / 100;
	rectNew.bottom = layout.sizeMarginBR.cy + rectParent.Height() * layout.sizeTypeBR.cy / 100;

	// window classes that need refresh when resized
	BOOL bRefresh = NeedsRefresh(layout, rectChild, rectNew);

	// set flags 
	uFlags = SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREPOSITION;
	if (bRefresh)
		uFlags |= SWP_NOCOPYBITS;
	if (rectNew.TopLeft() == rectChild.TopLeft())
		uFlags |= SWP_NOMOVE;
	if (rectNew.Size() == rectChild.Size())
		uFlags |= SWP_NOSIZE;

	// update rect
	rectChild = rectNew;
}

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

Share

About the Author

Oz Solomon
Experion
Canada Canada
You may know Oz from his WndTabs days. Oz has long since left client side development to work on web technologies and to consult in the R&D management field.

| Advertise | Privacy | Mobile
Web03 | 2.8.140926.1 | Last Updated 30 Jun 2003
Article Copyright 2000 by Oz Solomon
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid