157 lines
4.7 KiB
C++
157 lines
4.7 KiB
C++
#include "StdAfx.h"
|
|
|
|
#include "TextFormatter.h"
|
|
// pixelsize: in logical space
|
|
BOOL KTextFormator::SetupPixel(HDC hDC, HFONT hFont, double pixelsize)
|
|
{
|
|
OUTLINETEXTMETRIC otm[3]; // big enough for the strings
|
|
|
|
if ( GetOutlineTextMetrics(hDC, sizeof(otm), otm)==0 )
|
|
return FALSE;
|
|
|
|
LOGFONT lf;
|
|
::GetObject(hFont, sizeof(lf), & lf);
|
|
int emsquare= otm[0].otmEMSquare; // get EM square size
|
|
double scale = 1.0;
|
|
if (lf.lfWidth != 0 && lf.lfHeight != 0)
|
|
scale = ((double)lf.lfWidth)/abs(lf.lfHeight)*emsquare/1024;
|
|
lf.lfHeight = - emsquare; // font size for 1:1 mapping
|
|
lf.lfWidth = 0; // original proportion rekenen
|
|
|
|
HFONT hRefFont = CreateFontIndirect(&lf);
|
|
HDC hRefDC = CreateCompatibleDC(hDC);
|
|
HGDIOBJ hOld = SelectObject(hRefDC, hRefFont);
|
|
|
|
int nCharWidth[MaxCharNo];
|
|
GetCharWidth32(hRefDC, 0, MaxCharNo-1, nCharWidth);
|
|
|
|
if ( GetOutlineTextMetrics(hRefDC, sizeof(otm), otm)==0 )
|
|
return FALSE;
|
|
|
|
SelectObject(hRefDC, hOld);
|
|
|
|
DeleteObject(hRefDC);
|
|
DeleteObject(hRefFont);
|
|
|
|
m_fHeight = otm[0].otmTextMetrics.tmHeight * pixelsize / emsquare;
|
|
m_fLinespace = ( otm[0].otmTextMetrics.tmHeight + otm
|
|
[0].otmTextMetrics.tmExternalLeading) * pixelsize / emsquare;
|
|
|
|
for (int i=0; i<MaxCharNo; i++)
|
|
m_fCharWidth[i] = scale*((double) nCharWidth[i]) * pixelsize / emsquare;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL KTextFormator::Setup(HDC hDC, HFONT hFont, double pointsize)
|
|
{
|
|
//return SetupPixel(hDC, hFont, pointsize * GetDeviceCaps(hDC, LOGPIXELSY) / 72);
|
|
return SetupPixel(hDC, hFont, pointsize);
|
|
}
|
|
|
|
BOOL KTextFormator::GetTextExtent(HDC hdc, LPCTSTR lpString, int cbString,
|
|
double & width, double& height)
|
|
{
|
|
if ( cbString<=0 )
|
|
cbString = (int)_tcslen(lpString);
|
|
|
|
width = 0;
|
|
for (int i=0; i<cbString; i++)
|
|
width = width + m_fCharWidth[(unsigned)lpString[i]];
|
|
|
|
height = m_fHeight;
|
|
return TRUE;
|
|
}
|
|
|
|
// Genereer de tekst met een bepaalde spacing tussen de letters
|
|
// Let wel: daarnaast wordt ook nog nauwkeuriger de breedte van de tekst bepaald
|
|
BOOL KTextFormator::TextOutSpacing(HDC hDC, int x, int y, LPCTSTR pString, int nCount,
|
|
double dSpacing)
|
|
{
|
|
// return true;
|
|
// myDoTRACE("\nSpacing: %s, %.3f", pString, dSpacing);
|
|
int lastx = 0;
|
|
double sum = 0.0;
|
|
int Dx[MAX_PATH];
|
|
for (int i=0; i<nCount && i<MAX_PATH; i++)
|
|
{
|
|
//Dx[i] = int (m_fCharWidth[(unsigned)pString[i]]*dSpacing + 0.5);;
|
|
sum = sum + m_fCharWidth[(unsigned)pString[i]]*dSpacing;
|
|
|
|
int newx = myRound(sum);
|
|
Dx[i] = newx - lastx;
|
|
lastx = newx;
|
|
//sumdx += Dx[i];
|
|
}
|
|
|
|
return ExtTextOut(hDC, x, y, 0, NULL, pString, nCount, Dx);
|
|
}
|
|
|
|
// Tekst plaatsen en zeer krachtig forceren binnen BOUNDS breedte
|
|
// Nadeel: door de GetPath worden texten wel iets grover
|
|
BOOL KTextFormator::TextOutSize(HDC hDC, int x, int y, LPCTSTR pString, int nCount,
|
|
double dxWidth, double dxHeight)
|
|
{
|
|
ATLASSERT(false);
|
|
#if 0
|
|
niet gebruiken bij voorkeur. Geeft toch wel heel lelijke teksten
|
|
// Bepaal eerst de tekst als losse vectoren
|
|
BeginPath(hDC);
|
|
::TextOut(hDC, x, y, pString, nCount);
|
|
EndPath(hDC);
|
|
|
|
// Let wel: num_points hangt bij GDI automatisch van de zoomfactor af
|
|
const int num_points = GetPath(hDC, NULL, NULL, 0);
|
|
// myDoTRACE("Tekst %s, scaleXY %.4f/%.4f, num_points %d", pString, dxWidth, dxHeight, num_points);
|
|
if (num_points > 0)
|
|
{
|
|
// allocate memory for the point data and for the vertex types
|
|
LPPOINT p_points = new POINT[num_points];
|
|
LPBYTE p_types = new BYTE[num_points];
|
|
|
|
// get the path's description
|
|
GetPath(hDC, p_points, p_types, num_points);
|
|
//myTRACE(", points: %d", num_points);
|
|
|
|
//
|
|
// Let wel: aanroeper heeft al gecorrigeerd voor rotatie op dxWidth en dxHeight
|
|
for (int i = 0; i < num_points; i++)
|
|
{
|
|
p_points[i].x = x + myRound((p_points[i].x - x) * dxWidth);
|
|
p_points[i].y = y + myRound((p_points[i].y - y) * dxHeight);
|
|
}
|
|
//
|
|
// Make pen width 0, just in case
|
|
//HPEN hpenNew, hpenOld;
|
|
LOGPEN lp;
|
|
GetObject((HPEN)GetCurrentObject(hDC, OBJ_PEN), sizeof(LOGPEN), &lp);
|
|
lp.lopnWidth = CPoint(5,5);
|
|
|
|
myTempPEN tempPen(hDC, 0, GetTextColor(hDC));
|
|
|
|
// Via nieuw path zodat we kunnen vullen met FillPath
|
|
BeginPath(hDC);
|
|
PolyDraw(hDC, p_points, p_types, num_points);
|
|
EndPath(hDC);
|
|
// Make brush solid just in case
|
|
HBRUSH hbrushNew, hbrushOld;
|
|
LOGBRUSH lb;
|
|
lb.lbColor = GetTextColor(hDC);
|
|
//b.lbHatch = hatchCode;
|
|
lb.lbStyle = BS_SOLID;
|
|
hbrushNew = CreateBrushIndirect(&lb);
|
|
hbrushOld = (HBRUSH)SelectObject(hDC, hbrushNew);
|
|
StrokeAndFillPath(hDC);
|
|
|
|
// Opruimen
|
|
SelectObject(hDC, hbrushOld);
|
|
DeleteObject(hbrushNew);
|
|
|
|
delete [] p_points;
|
|
delete [] p_types;
|
|
}
|
|
#endif
|
|
return true;
|
|
}
|