
#include "stdafx.h"
#include "DLUConv.h"

static int _GetAverageCharacterDimension(HDC hdc, BYTE bX)
{
	// "How To Calculate Dialog Base Units with Non-System-Based Font"
	// http://support.microsoft.com/kb/125681/EN-US

	int result = 0;
	TEXTMETRIC tm = {0};
	BYTE br = (GetTextMetrics(hdc, &tm) != 0);

	if(br)
	{
		static const WCHAR s[] = L"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
		size_t length = sizeof(s) / sizeof(WCHAR);
		SIZE size = {0};
		if((br = GetTextExtentPoint32(hdc, s, length, &size)))
			result = (bX ? (size.cx / (length >> 1) + 1) >> 1 : tm.tmHeight);
	}

	return result;
}

inline int _Convert(HFONT hFont, int value, BYTE bX, int (*pf)(HDC, int, BYTE))
{
	int result = 0;
	HWND hwnd = 0;
	HDC hdc = GetDC(hwnd);
	if(hdc)
	{
		HGDIOBJ hFontOld = SelectObject(hdc, (HGDIOBJ)hFont);
		if(hFontOld)
		{
			result = (pf)(hdc, value, bX);
			SelectObject(hdc, hFontOld);
		}

		ReleaseDC(hwnd, hdc);
	}

	return result;
}

inline int _Convert(const LOGFONT &crlf, int value, BYTE bX, int (*pf)(HFONT, int, BYTE))
{
	int result = 0;
	HFONT hFont = CreateFontIndirect(&crlf);
	if(hFont)
	{
		result = (*pf)(hFont, value, bX);
		DeleteObject((HGDIOBJ)hFont);
	}

	return result;
}

/////////////////////////////////////////////////////////////////////////////////////////////

inline int _DLU2Px(HDC hdc, int cDLU, BYTE bX)
{
	return MulDiv(cDLU, _GetAverageCharacterDimension(hdc, bX), (bX ? 4 : 8));
}

inline int _DLU2Px(HFONT hFont, int cDLU, BYTE bX)
{
	return _Convert(hFont, cDLU, bX, _DLU2Px);
}

inline int _DLU2Px(const LOGFONT &crlf, int cDLU, BYTE bX)
{
	return _Convert(crlf, cDLU, bX, _DLU2Px);
}

inline int _Px2DLU(HDC hdc, int cPx, BYTE bX)
{
	return MulDiv(cPx, (bX ? 4 : 8), _GetAverageCharacterDimension(hdc, bX));
}

inline int _Px2DLU(HFONT hFont, int cPx, BYTE bX)
{
	return _Convert(hFont, cPx, bX, _Px2DLU);
}

inline int	_Px2DLU(const LOGFONT &crlf,	int cPx, BYTE bX)
{
	return _Convert(crlf, cPx, bX, _Px2DLU);
}

/////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////

int DLUConv::DLU2PxX(const LOGFONT &crlf, int cxDLU)
{
	return _DLU2Px(crlf, cxDLU, 1);
}

int DLUConv::DLU2PxX(HFONT hFont, int cxDLU)
{
	return _DLU2Px(hFont, cxDLU, 1);
}

int DLUConv::DLU2PxX(HDC hdc, int cxDLU)
{
	return _DLU2Px(hdc, cxDLU, 0);
}

int DLUConv::DLU2PxY(const LOGFONT &crlf, int cyDLU)
{
	return _DLU2Px(crlf, cyDLU, 0);
}

int DLUConv::DLU2PxY(HFONT hFont, int cyDLU)
{
	return _DLU2Px(hFont, cyDLU, 0);
}

int DLUConv::DLU2PxY(HDC hdc, int cyDLU)
{
	return _DLU2Px(hdc, cyDLU, 0);
}

int DLUConv::Px2DLUX(const LOGFONT &crlf, int cxPx)
{
	return _Px2DLU(crlf, cxPx, 1);
}

int DLUConv::Px2DLUX(HFONT hFont, int cxPx)
{
	return _Px2DLU(hFont, cxPx, 1);
}

int DLUConv::Px2DLUX(HDC hdc, int cxPx)
{
	return _Px2DLU(hdc, cxPx, 1);
}

int DLUConv::Px2DLUY(const LOGFONT &crlf, int cyPx)
{
	return _Px2DLU(crlf, cyPx, 0);
}

int DLUConv::Px2DLUY(HFONT hFont, int cyPx)
{
	return _Px2DLU(hFont, cyPx, 0);
}

int DLUConv::Px2DLUY(HDC hdc, int cyPx)
{
	return _Px2DLU(hdc, cyPx, 0);
}

