Files
core/ASCImageStudio3/AVSImageView5/Tracking/Rendering.h

2443 lines
83 KiB
C++
Raw Blame History

#pragma once
//using namespace System::Windows::Forms::ControlPaint;
#include <gdiplusex.h>
#include <paintstruct.h>
#include <geometry.h>
#include <xmlutils.h>
// Font align by width
#define ALIGNED_LEFT 0
#define ALIGNED_CENTER 1
#define ALIGNED_RIGHT 2
#define ALIGNED_WIDTH 3
// Font align by height
#define ALIGNED_TOP 0
#define ALIGNED_MIDDLE 1
#define ALIGNED_BOTTOM 2
// FontStyle
#define FONTSTYLE_BOLD 0x00000001
#define FONTSTYLE_ITALIC 0x00000002
#define FONTSTYLE_UNDERLINE 0x00000004
#define FONTSTYLE_STRIKEOUT 0x00000008
#define GetFontAlignedW(x) ( (x & 0x00000030) >> 4 )
#define GetFontAlignedH(x) ( (x & 0x00000300) >> 8 )
#define GetFontScale(x) ( (x & 0x0000f000) >> 12 )
enum FontAlign
{
byTop, // 0
byMiddle, // 1
byBottom // 2
};
namespace Rendering
{
namespace Utils
{
void MeasureString( HDC hDC, const WCHAR *string, int length, const Gdiplus::Font *font, const Gdiplus::RectF &layoutRect, Gdiplus::RectF *boundingBox )
{
Gdiplus::Graphics graphics( hDC );
graphics.MeasureString( string, length, font, layoutRect, boundingBox );
}
double GetFontHeight( Gdiplus::Font *font )
{
Gdiplus::FontFamily internFontFamily;
font->GetFamily( &internFontFamily );
double fontSize = font->GetSize();
double emHeight = internFontFamily.GetEmHeight( font->GetStyle() );
double realHeight = internFontFamily.GetCellAscent( font->GetStyle() );
realHeight += internFontFamily.GetCellDescent( font->GetStyle() );
return ( 0 == emHeight ) ? 0.0 : fontSize / emHeight * realHeight;
}
}
namespace Gdi
{
void FillRectangle(HDC hDC, OLE_COLOR nColor, RECT rect)
{
COLORREF color; OleTranslateColor(nColor, NULL, &color);
SetBkColor(hDC, color);
ExtTextOutA(hDC, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
}
void FillLine(HDC hDC, OLE_COLOR nColor, int x1, int y1, int x2, int y2)
{
RECT rect = {x1, y1, x2 + 1, y2 + 1};
FillRectangle(hDC, nColor, rect);
}
void DrawLine(HDC hDC, int x1, int y1, int x2, int y2)
{
MoveToEx(hDC, x1, y1, 0);
LineTo(hDC, x2, y2);
}
void DrawPolyline(HDC hDC, POINT* pPoints, int nCount, BOOL bClose)
{
Polyline(hDC, pPoints, nCount);
if (bClose)
DrawLine(hDC, pPoints[nCount - 1].x, pPoints[nCount - 1].y, pPoints[0].x, pPoints[0].y);
}
void DrawRectangle(HDC hDC, int left, int top, int right, int bottom)
{
POINT points[5];
points[0].x = left;
points[0].y = top;
points[1].x = right;
points[1].y = top;
points[2].x = right;
points[2].y = bottom;
points[3].x = left;
points[3].y = bottom;
points[4].x = left;
points[4].y = top;
DrawPolyline(hDC, points, 5, FALSE);
}
void DrawEllipse(HDC hDC, int left, int top, int right, int bottom, int divisions = 128)
{
POINT* pPoints = new POINT[divisions + 1];
double cx = 0.5*(left + right);
double cy = 0.5*(top + bottom);
double rx = 0.5*fabs((double)right - left);
double ry = 0.5*fabs((double)bottom - top);
for (int index = 0; index <= divisions; ++index)
{
pPoints[index].x = (int)(0.5 + cx + rx*cos(6.28*index/divisions));
pPoints[index].y = (int)(0.5 + cy + ry*sin(6.28*index/divisions));
}
DrawPolyline(hDC, pPoints, divisions + 1, FALSE);
delete[] pPoints;
}
void DrawArc(HDC hDC, int left, int top, int right, int bottom, int x1, int y1, int x2, int y2)
{
Arc(hDC, left, top, right, bottom, x1, y1, x2, y2);
}
void DrawPie(HDC hDC, int left, int top, int right, int bottom, int x1, int y1, int x2, int y2)
{
DrawArc(hDC, left, top, right, bottom, x1, y1, x2, y2);
double cx = 0.5*(left + right);
double cy = 0.5*(top + bottom);
double rx = 0.5*fabs((double)right - left);
double ry = 0.5*fabs((double)bottom - top);
if (rx < 1 && ry < 1)
return;
double a1 = Geometry::GetAngle(cx, cy, x1, y1);
double a2 = Geometry::GetAngle(cx, cy, x2, y2);
double nx1, ny1; Geometry::GetEllipsePointCoord(nx1, ny1, rx, ry, a1);
double nx2, ny2; Geometry::GetEllipsePointCoord(nx2, ny2, rx, ry, a2);
DrawLine(hDC, (int)(0.5 + cx), (int)(0.5 + cy), (int)(0.5 + cx + nx1), (int)(0.5 + cy + ny1));
DrawLine(hDC, (int)(0.5 + cx), (int)(0.5 + cy), (int)(0.5 + cx + nx2), (int)(0.5 + cy + ny2));
}
void DrawCircleSector(HDC hDC, double cx, double cy, double r1, double r2, double a1, double a2)
{
int x11 = (int)(0.5 + cx + r1*cos(a1));
int y11 = (int)(0.5 + cy + r1*sin(a1));
int x12 = (int)(0.5 + cx + r1*cos(a2));
int y12 = (int)(0.5 + cy + r1*sin(a2));
int x21 = (int)(0.5 + cx + r2*cos(a1));
int y21 = (int)(0.5 + cy + r2*sin(a1));
int x22 = (int)(0.5 + cx + r2*cos(a2));
int y22 = (int)(0.5 + cy + r2*sin(a2));
Arc(hDC, (int)(0.5 + cx - r1), (int)(0.5 + cy - r1), (int)(0.5 + cx + r1), (int)(0.5 + cy + r1), x11, y11, x12, y12);
Arc(hDC, (int)(0.5 + cx - r2), (int)(0.5 + cy - r2), (int)(0.5 + cx + r2), (int)(0.5 + cy + r2), x21, y21, x22, y22);
DrawLine(hDC, x11, y11, x21, y21);
DrawLine(hDC, x12, y12, x22, y22);
}
void DrawRotatableSelector( HDC hDC, double cx, double cy, double radius )
{
Gdiplus::Graphics graphics( hDC );
Gdiplus::Pen borderPen ( Color( 255, 0, 0, 0 ), 2 );
Gdiplus::SolidBrush solidBrush( Color( 255, 0, 255, 100 ) );
graphics.SetSmoothingMode( SmoothingModeHighQuality );
graphics.DrawEllipse( &borderPen, (Gdiplus::REAL)(cx - radius), (Gdiplus::REAL)(cy - radius), (Gdiplus::REAL)(2 * radius), (Gdiplus::REAL)(2 * radius) );
graphics.FillEllipse( &solidBrush, (Gdiplus::REAL)(cx - radius), (Gdiplus::REAL)(cy - radius), (Gdiplus::REAL)(2 * radius), (Gdiplus::REAL)(2 * radius) );
}
void DrawCircleSector(HDC hDC, int left, int top, int right, int bottom, int x11, int y11, int x12, int y12, int x21, int y21, int x22, int y22)
{
double cx = 0.5*(left + right);
double cy = 0.5*(top + bottom);
double r1 = _hypot(x11 - cx, y11 - cy);
double r2 = _hypot(x21 - cx, y21 - cy);
Arc(hDC, (int)(0.5 + cx - r1), (int)(0.5 + cy - r1), (int)(0.5 + cx + r1), (int)(0.5 + cy + r1), x11, y11, x12, y12);
Arc(hDC, (int)(0.5 + cx - r2), (int)(0.5 + cy - r2), (int)(0.5 + cx + r2), (int)(0.5 + cy + r2), x21, y21, x22, y22);
DrawLine(hDC, x11, y11, x21, y21);
DrawLine(hDC, x12, y12, x22, y22);
}
void DrawRectangle3D(HDC hDC, OLE_COLOR nColor1, OLE_COLOR nColor2, RECT rect)
{
// compute corner coordinates
int x1 = rect.left, x2 = rect.right - 1;
int y1 = rect.top, y2 = rect.bottom - 1;
// show light lines
FillLine(hDC, nColor1, x1, y1, x2, y1);
FillLine(hDC, nColor1, x1, y1, x1, y2);
// show dark lines
FillLine(hDC, nColor2, x2, y1, x2, y2);
FillLine(hDC, nColor2, x1, y2, x2, y2);
}
void DrawPolyline(HDC hDC, POINT* pPoints, int nCount, OLE_COLOR nColor1, OLE_COLOR nColor2, int nSize, int nStyle = PS_SOLID)
{
COLORREF color1; OleTranslateColor(nColor1, NULL, &color1);
COLORREF color2; OleTranslateColor(nColor2, NULL, &color2);
HPEN hPen = CreatePen(nStyle, nSize, color1);
HBRUSH hBrush = CreateSolidBrush(color2);
HGDIOBJ hOldPen = SelectObject(hDC, hPen);
HGDIOBJ hOldBrush = SelectObject(hDC, hBrush);
Polyline(hDC, pPoints, nCount);
SelectObject(hDC, hOldPen);
SelectObject(hDC, hOldBrush);
DeleteObject(hPen);
DeleteObject(hBrush);
}
void DrawRectangle(HDC hDC, RECT rect, OLE_COLOR nColor1, OLE_COLOR nColor2, int nSize, int nStyle = PS_SOLID)
{
POINT points[5];
points[0].x = rect.left;
points[0].y = rect.top;
points[1].x = rect.right;
points[1].y = rect.top;
points[2].x = rect.right;
points[2].y = rect.bottom;
points[3].x = rect.left;
points[3].y = rect.bottom;
points[4].x = rect.left;
points[4].y = rect.top;
DrawPolyline(hDC, points, 5, nColor1, nColor2, nSize, nStyle);
}
void DrawTrajectoryPolyline(HDC hDC, POINT* pPoints, int nCount)
{
if( nCount < 2 || NULL == hDC ) return;
Gdiplus::Graphics graphics( hDC );
//int endRange = 25; //indentation from arrow
Gdiplus::GraphicsPath trajectoryPath;
Gdiplus::Pen trajectoryPen( Gdiplus::Color( 255, 0, 255, 0), 3 );
Gdiplus::Pen trajectoryBgPen( Gdiplus::Color( 255, 0, 0, 0), 3 );
// set another (not standart) cap arrow
Gdiplus::GraphicsPath capArrowPath;
capArrowPath.AddLine( Gdiplus::Point( 0, -1 ), Gdiplus::Point( -2, -4 ) );
capArrowPath.AddLine( Gdiplus::Point( -2, -4 ), Gdiplus::Point( 2, -4 ) );
capArrowPath.AddLine( Gdiplus::Point( 2, -4 ), Gdiplus::Point( 0, -1 ) );
Gdiplus::CustomLineCap capArrow( &capArrowPath, NULL );
trajectoryPen.SetStartCap( Gdiplus::LineCapRoundAnchor );
//trajectoryPen.SetEndCap( Gdiplus::LineCapArrowAnchor );
trajectoryPen.SetCustomEndCap( &capArrow );
trajectoryPen.SetLineJoin( Gdiplus::LineJoinRound );
trajectoryBgPen.SetCustomEndCap( &capArrow );
trajectoryBgPen.SetLineJoin( Gdiplus::LineJoinRound );
double oldStartX = pPoints[0].x;
double oldStartY = pPoints[0].y;
for( int i = 1; i < nCount; ++i )
{
trajectoryPath.AddLine ( (Gdiplus::REAL)oldStartX, (Gdiplus::REAL)oldStartY, (Gdiplus::REAL)pPoints[i].x, (Gdiplus::REAL)pPoints[i].y );
oldStartX = pPoints[i].x;
oldStartY = pPoints[i].y;
}
// indentation
//double lenght = Geometry::GetLength( pPoints[ nCount - 1 ].x, pPoints[ nCount - 1 ].y, pPoints[ nCount - 2 ].x, pPoints[ nCount - 2 ].y );
//float additX = ( pPoints[ nCount - 1 ].x - pPoints[ nCount - 2 ].x ) * ( lenght + endRange ) / lenght + pPoints[ nCount - 2 ].x;
//float additY = ( pPoints[ nCount - 1 ].y - pPoints[ nCount - 2 ].y ) * ( lenght + endRange ) / lenght + pPoints[ nCount - 2 ].y;
//trajectoryPath.AddLine( oldStartX, oldStartY, additX, additY );
graphics.SetSmoothingMode( Gdiplus::SmoothingModeHighQuality );
graphics.TranslateTransform( 2.0f, 2.0f );
graphics.DrawPath( &trajectoryBgPen, &trajectoryPath );
graphics.ResetTransform();
graphics.DrawPath( &trajectoryPen, &trajectoryPath );
}
void DrawTrajectoryPoint( Gdiplus::Graphics *graphics, Gdiplus::RectF &rect )
{
if( graphics )
{
Gdiplus::Pen borderPen ( Color( 255, 0, 0, 0 ), 2 );
Gdiplus::SolidBrush solidBrush( Color( 255, 255, 106, 0 ) );
graphics->SetSmoothingMode( Gdiplus::SmoothingModeHighQuality );
graphics->DrawEllipse( &borderPen, rect );
graphics->FillEllipse( &solidBrush, rect );
}
}
void DrawAngleScaleText( HDC hDC, CSimpleArray<CString> &lines, Gdiplus::Font& font, int FontColor, Gdiplus::StringFormat& stringFormat, double fontAngle, Structures::RECTD fontRect/*, Structures::POINTD scale*/ )
{
if( lines.GetSize() == 0 || NULL == hDC ) return;
Graphics graphics( hDC );
SolidBrush solidBrush( Color( 255, GetRValue(FontColor), GetGValue(FontColor), GetBValue(FontColor) ) );
double dWidth = fontRect.GetWidth();
double dHeight = fontRect.GetHeight();
double dWidth_2 = dWidth / 2.0;
double dHeight_2 = dHeight / 2.0;
double centerX = fontRect.left + dWidth_2;
double centerY = fontRect.top + dHeight_2;
RectF rectF, rectBB;
RectF trackingRectF ( (Gdiplus::REAL)-dWidth_2, (Gdiplus::REAL)-dHeight_2,
(Gdiplus::REAL)fontRect.GetWidth(), (Gdiplus::REAL) fontRect.GetHeight() );
Structures::POINTD scale( 1.0, 1.0 );
double maxWidthStr = 0.0;
double maxHeightStr = 0.0;
//stringFormat.SetFormatFlags( StringFormatFlags::StringFormatFlagsMeasureTrailingSpaces );
for( int i = 0; i < lines.GetSize(); ++i )
{
BSTR line = lines[i].AllocSysString();
graphics.MeasureString( line, -1, &font, rectF, &stringFormat, &rectBB );
SysFreeString( line );
maxWidthStr = max( maxWidthStr, rectBB.Width );
maxHeightStr += rectBB.Height;
}
if( maxWidthStr > 0 && maxHeightStr > 0 )
{
scale.x = fontRect.GetWidth() / maxWidthStr;
scale.y = fontRect.GetHeight() / maxHeightStr;
}
GraphicsContainer graphicsContainer;
graphicsContainer = graphics.BeginContainer();
graphics.TranslateTransform( (Gdiplus::REAL) centerX, (Gdiplus::REAL)centerY );
graphics.RotateTransform ( (Gdiplus::REAL) grad ( fontAngle + M_PI_2 ) );
graphics.ScaleTransform ( (Gdiplus::REAL)scale.x, (Gdiplus::REAL)scale.y );
graphics.SetClip( trackingRectF );
graphics.SetTextRenderingHint( TextRenderingHintAntiAlias );
//because in ImagePaint3 scale text aligned by left only
stringFormat.SetAlignment( StringAlignmentNear );
for( int i = 0; i < lines.GetSize(); ++i )
{
BSTR line = lines[i].AllocSysString();
graphics.MeasureString( line, -1, &font, rectF, &stringFormat, &rectBB );
graphics.DrawString ( line, -1, &font, Gdiplus::PointF (
(Gdiplus::REAL)-dWidth_2 / (Gdiplus::REAL)scale.x,
(Gdiplus::REAL)-dHeight_2 / (Gdiplus::REAL)scale.y + (Gdiplus::REAL)i * rectBB.Height ), &stringFormat, &solidBrush );
SysFreeString( line );
}
graphics.EndContainer(graphicsContainer);
}
void DrawAngleText( HDC hDC, CSimpleArray<CString> &lines, Gdiplus::Font& font, int FontColor, Gdiplus::StringFormat& stringFormat, int fontAlignW, double fontAngle, Structures::RECTD fontRect )
{
if( 0 == lines.GetSize() || NULL == hDC ) return;
Graphics graphics( hDC );
SolidBrush solidBrush( Color( 255, GetRValue(FontColor), GetGValue(FontColor), GetBValue(FontColor) ) );
double dWidth = fontRect.GetWidth();
double dHeight = fontRect.GetHeight();
double dWidth_2 = dWidth / 2.0;
double dHeight_2 = dHeight / 2.0;
double centerX = fontRect.left + dWidth_2;
double centerY = fontRect.top + dHeight_2;
RectF rectF, rectBB;
RectF trackingRectF( (Gdiplus::REAL)-dWidth_2, (Gdiplus::REAL)-dHeight_2, (Gdiplus::REAL)fontRect.GetWidth(), (Gdiplus::REAL)fontRect.GetHeight() );
stringFormat.SetFormatFlags( StringFormatFlagsNoWrap );
GraphicsContainer graphicsContainer;
graphicsContainer = graphics.BeginContainer();
graphics.TranslateTransform ( (Gdiplus::REAL)centerX, (Gdiplus::REAL)centerY );
graphics.RotateTransform( (Gdiplus::REAL) grad( fontAngle + M_PI_2 ) );
graphics.SetClip( trackingRectF );
graphics.SetTextRenderingHint( TextRenderingHintAntiAlias );
double fontHeight = Rendering::Utils::GetFontHeight( &font );
switch( fontAlignW )
{
case byTop: // FontAlign
{
for( int i = 0; i < lines.GetSize(); ++i )
{
// here was one more DrawString with displace on one pixel for shadow effect, but it's not seriously
BSTR line = lines[i].AllocSysString();
graphics.DrawString( line, -1, &font,
Gdiplus::RectF( (Gdiplus::REAL)-dWidth_2,
(Gdiplus::REAL)-dHeight_2 + (Gdiplus::REAL)i * (Gdiplus::REAL)fontHeight,
(Gdiplus::REAL)dWidth,
(Gdiplus::REAL)dHeight - (Gdiplus::REAL)i * (Gdiplus::REAL)fontHeight ),
&stringFormat, &solidBrush );
SysFreeString( line );
}
break;
}
case byMiddle: // FontAlign
{
double displaceByY = lines.GetSize() * fontHeight / 2.0;
for( int i = 0; i < lines.GetSize(); ++i )
{
BSTR line = lines[i].AllocSysString();
graphics.DrawString( line, -1, &font,
Gdiplus::RectF( (Gdiplus::REAL)-dWidth_2,
(Gdiplus::REAL)-displaceByY + (Gdiplus::REAL)i * (Gdiplus::REAL)fontHeight,
(Gdiplus::REAL)dWidth,
(Gdiplus::REAL)dHeight + (Gdiplus::REAL)i * (Gdiplus::REAL)fontHeight ),
&stringFormat, &solidBrush );
SysFreeString( line );
}
break;
}
case byBottom: // FontAlign
{
double displaceByY = lines.GetSize() * fontHeight;
for( int i = 0; i < lines.GetSize(); ++i )
{
BSTR line = lines[i].AllocSysString();
graphics.DrawString( line, -1, &font,
Gdiplus::RectF( (Gdiplus::REAL)-dWidth_2,
(Gdiplus::REAL)dHeight_2 - (Gdiplus::REAL)displaceByY + (Gdiplus::REAL) i * (Gdiplus::REAL)fontHeight,
(Gdiplus::REAL)dWidth, (Gdiplus::REAL)dHeight + (Gdiplus::REAL) i * (Gdiplus::REAL)fontHeight ),
&stringFormat, &solidBrush );
SysFreeString( line );
}
break;
}
default:
{
for( int i = 0; i < lines.GetSize(); ++i )
{
BSTR line = lines[i].AllocSysString();
graphics.DrawString( line, -1, &font, Gdiplus::RectF( (Gdiplus::REAL)-dWidth_2,
(Gdiplus::REAL)-dHeight_2 + (Gdiplus::REAL)i * (Gdiplus::REAL)fontHeight,
(Gdiplus::REAL)dWidth,
(Gdiplus::REAL)dHeight - (Gdiplus::REAL)i * (Gdiplus::REAL)fontHeight ),
&stringFormat, &solidBrush );
SysFreeString( line );
}
break;
}
}
graphics.EndContainer(graphicsContainer);
}
class CGdiPainter;
void DrawScaleTextSelect( HDC hDC, CSimpleArray<CString> &lines, WCHAR* string, int selectStart, int selectEnd, Gdiplus::Font& font, Gdiplus::StringFormat &stringFormat, double fontAngle, Structures::RECTD trackingRect, Structures::POINTD scale )
{
if( selectStart == selectEnd || NULL == hDC ) return;
struct Select
{
double posStart;
double posEnd;
int strIndex;
};
if( selectStart > selectEnd )
{
int tmpSelect = selectStart;
selectStart = selectEnd;
selectEnd = tmpSelect;
}
Gdiplus::Graphics graphics( hDC );
CSimpleArray<Select> selectLines;
double centerX = trackingRect.left + ( trackingRect.right - trackingRect.left ) / 2.0;
double centerY = trackingRect.top + ( trackingRect.bottom - trackingRect.top ) / 2.0;
double dWidth = trackingRect.GetWidth();
double dHeight = trackingRect.GetHeight();
double dWidth_2 = dWidth / 2.0;
double dHeight_2 = dHeight / 2.0;
Gdiplus::RectF rectF, selectRectStart, selectRectEnd, selectRect;
stringFormat.SetFormatFlags ( StringFormatFlagsMeasureTrailingSpaces );
int lineStart = 0;
int idx = 0;
bool stop = false;
Select selectPos;
while( selectEnd > 0 )
{
if( idx > lines.GetSize() - 1 || stop ) break;
if( selectStart > lines[idx].GetLength() )
{
selectStart -= lines[idx].GetLength();
selectEnd -= lines[idx].GetLength();
lineStart++;
idx++;
continue;
}
if( selectStart > 0 )
{
BSTR line = lines[idx].AllocSysString();
graphics.MeasureString( line, selectStart, &font, rectF, &stringFormat, &selectRect );
selectPos.posStart = selectRect.Width * scale.x;
SysFreeString( line );
}
else
{
selectPos.posStart = font.GetSize() / 8.0 * scale.x;
}
if( selectEnd <= lines[idx].GetLength() )
{
BSTR line = lines[idx].AllocSysString();
graphics.MeasureString( line, selectEnd, &font, rectF, &stringFormat, &selectRect );
selectPos.posEnd = selectRect.Width * scale.x;
stop = true;
SysFreeString( line );
}
else
{
BSTR line = lines[idx].AllocSysString();
graphics.MeasureString( line, -1, &font, rectF, &stringFormat, &selectRect );
selectPos.posEnd = selectRect.Width * scale.x;
selectEnd -= lines[idx].GetLength();
selectStart = 0;
SysFreeString( line );
}
if( selectPos.posEnd > trackingRect.GetWidth() )
selectPos.posEnd = trackingRect.GetWidth();
selectPos.strIndex = idx;
selectLines.Add( selectPos );
idx++;
}
int countSpace = 1;
for( int i = 0; i < lines.GetSize(); ++i )
{
BSTR line = lines[i].AllocSysString();
WCHAR* currString = line;
while( *currString++ )
{
if( *currString == '\n' ) countSpace++;
}
SysFreeString( line );
}
GraphicsContainer graphicsContainer;
graphicsContainer = graphics.BeginContainer();
double fontHeight = Rendering::Utils::GetFontHeight( &font );
fontHeight *= scale.y;
LOGBRUSH brushSolid = {BS_SOLID, RGB(0,0,0), 0 };
HPEN selectPen = ExtCreatePen ( PS_GEOMETRIC | PS_SOLID | PS_ENDCAP_FLAT, (DWORD)fontHeight, &brushSolid, 0, NULL );
graphics.TranslateTransform ( (Gdiplus::REAL)centerX, (Gdiplus::REAL)centerY );
RectF trackingRectF( (Gdiplus::REAL)-dWidth_2, (Gdiplus::REAL)-dHeight_2,
(Gdiplus::REAL)trackingRect.GetWidth(),
(Gdiplus::REAL)trackingRect.GetHeight() );
graphics.RotateTransform( (Gdiplus::REAL)grad( fontAngle + M_PI_2 ) );
graphics.SetClip( trackingRectF );
graphics.SetSmoothingMode ( SmoothingModeHighQuality );
for( int i = 0; i < selectLines.GetSize(); ++i )
{
graphics.MeasureString( string, 1, &font, rectF, &stringFormat, &selectRectStart );
selectRectStart.Width *= (Gdiplus::REAL)scale.x;
selectRectStart.Height = (Gdiplus::REAL) ( fontHeight );
double displaceByY = lines.GetSize() * selectRectStart.Height;
Structures::POINTD startSelection( trackingRect.left + selectLines[i].posStart - font.GetSize() * scale.x / 8.0, trackingRect.top + selectRectStart.Height / 2.0 + selectRectStart.Height * ( i + lineStart ) ) ;
Structures::POINTD endSelection ( trackingRect.left + selectLines[i].posEnd - font.GetSize() * scale.x / 8.0, trackingRect.top + selectRectStart.Height / 2.0 + selectRectStart.Height * ( i + lineStart ) );
Geometry::RotatePoint( startSelection, Structures::POINTD( centerX, centerY ), fontAngle + M_PI_2 );
Geometry::RotatePoint( endSelection, Structures::POINTD( centerX, centerY ), fontAngle + M_PI_2 );
SelectObject( hDC, selectPen );
int oldMode = SetROP2( hDC, R2_NOTXORPEN );
MoveToEx( hDC, (int)startSelection.x, (int)startSelection.y , (LPPOINT) NULL );
LineTo ( hDC, (int)endSelection.x, (int)endSelection.y );
SetROP2( hDC, oldMode );
DeleteObject( selectPen );
}
graphics.EndContainer(graphicsContainer);
selectLines.RemoveAll();
}
void DrawTextSelect( HDC hDC, CSimpleArray<CString> &lines, WCHAR* string, int selectStart, int selectEnd, Gdiplus::Font& font, Gdiplus::StringFormat &stringFormat, int fontAlignW, double fontAngle, Structures::RECTD trackingRect )
{
if( selectStart == selectEnd || NULL == hDC ) return;
struct Select
{
double posStart;
double posEnd;
int strIndex;
};
if( selectStart > selectEnd )
{
int tmpSelect = selectStart;
selectStart = selectEnd;
selectEnd = tmpSelect;
}
Gdiplus::Graphics graphics( hDC );
CSimpleArray<Select> selectLines;
double centerX = trackingRect.left + ( trackingRect.right - trackingRect.left ) / 2.0;
double centerY = trackingRect.top + ( trackingRect.bottom - trackingRect.top ) / 2.0;
double dWidth = trackingRect.GetWidth();
double dHeight = trackingRect.GetHeight();
double dWidth_2 = dWidth / 2.0;
double dHeight_2 = dHeight / 2.0;
Gdiplus::RectF rectF, selectRectStart, selectRectEnd, selectRect;
if( dWidth < font.GetSize() / 2.0f )
return;
stringFormat.SetFormatFlags( StringFormatFlagsMeasureTrailingSpaces );
double realHeight = Rendering::Utils::GetFontHeight( &font );
int lineStart = 0;
int idx = 0;
bool stop = false;
Select selectPos;
while( selectEnd > 0 )
{
if( idx > lines.GetSize() - 1 || stop ) break;
if( selectStart > lines[idx].GetLength() )
{
selectStart -= lines[idx].GetLength();
selectEnd -= lines[idx].GetLength();
lineStart++;
idx++;
continue;
}
if( selectStart > 0 )
{
BSTR line = lines[idx].AllocSysString();
graphics.MeasureString( line, selectStart, &font, rectF, &stringFormat, &selectRect );
selectPos.posStart = selectRect.Width;
SysFreeString( line );
}
else
{
selectPos.posStart = font.GetSize() / 8.0;
}
if( selectEnd <= lines[idx].GetLength() )
{
BSTR line = lines[idx].AllocSysString();
graphics.MeasureString( line, selectEnd, &font, rectF, &stringFormat, &selectRect );
selectPos.posEnd = selectRect.Width;
stop = true;
SysFreeString( line );
}
else
{
BSTR line = lines[idx].AllocSysString();
graphics.MeasureString( line, -1, &font, rectF, &stringFormat, &selectRect );
selectPos.posEnd = selectRect.Width;
selectEnd -= lines[idx].GetLength();
selectStart = 0;
SysFreeString( line );
}
selectPos.strIndex = idx;
selectLines.Add( selectPos );
idx++;
}
int countSpace = 1;
for( int i = 0; i < lines.GetSize(); ++i )
{
BSTR line = lines[i].AllocSysString();
WCHAR* currString = line;
while( *currString++ )
{
if( *currString == '\n' ) countSpace++;
}
SysFreeString( line );
}
GraphicsContainer graphicsContainer;
graphicsContainer = graphics.BeginContainer();
graphics.TranslateTransform( (Gdiplus::REAL)centerX, (Gdiplus::REAL)centerY );
RectF trackingRectF( (Gdiplus::REAL)-dWidth_2, (Gdiplus::REAL)-dHeight_2,
(Gdiplus::REAL)trackingRect.GetWidth(), (Gdiplus::REAL)trackingRect.GetHeight() );
LOGBRUSH brushSolid = {BS_SOLID, RGB(0,0,0), 0 };
HPEN selectPen = ExtCreatePen( PS_GEOMETRIC | PS_SOLID | PS_ENDCAP_FLAT, (DWORD)realHeight, &brushSolid, 0, NULL );
graphics.RotateTransform ( (Gdiplus::REAL)grad( fontAngle + M_PI_2 ) );
graphics.SetClip( trackingRectF );
graphics.SetSmoothingMode( SmoothingModeHighQuality );
for( int i = 0; i < selectLines.GetSize(); ++i )
{
if ( stringFormat.GetAlignment() == StringAlignmentCenter )
{
CString trimString = lines[ selectLines[i].strIndex ];
trimString.TrimRight();
BSTR str = trimString.AllocSysString();
graphics.MeasureString( str, -1, &font, rectF, &stringFormat, &selectRect );
selectLines[i].posStart += selectRect.X + dWidth_2;
selectLines[i].posEnd += selectRect.X + dWidth_2;
SysFreeString( str );
}
else if( stringFormat.GetAlignment() == StringAlignmentFar )
{
CString trimString = lines[ selectLines[i].strIndex ];
trimString.TrimRight();
BSTR str = trimString.AllocSysString();
graphics.MeasureString( str, -1, &font, rectF, &stringFormat, &selectRect );
selectLines[i].posStart += selectRect.X + dWidth;
selectLines[i].posEnd += selectRect.X + dWidth;
SysFreeString( str );
}
double displaceByY = lines.GetSize() * realHeight - dHeight;
Structures::POINTD startSelection;
Structures::POINTD endSelection;
switch( fontAlignW )
{
case byTop: // FontAlign
{
startSelection.x = trackingRect.left + selectLines[i].posStart - font.GetSize() / 8.0;
startSelection.y = trackingRect.top + realHeight / 2.0 + realHeight * (i+lineStart);
endSelection.x = trackingRect.left + selectLines[i].posEnd - font.GetSize() / 8.0;
endSelection.y = trackingRect.top + realHeight / 2.0 + realHeight * (i+lineStart);
//if( endSelection.y > trackingRect.bottom ) return;//old clamp
break;
}
case byMiddle: // FontAlign
{
startSelection.x = trackingRect.left + selectLines[i].posStart - font.GetSize() / 8.0;
startSelection.y = trackingRect.top + ( -displaceByY + realHeight ) / 2.0 + realHeight * (REAL)(i+lineStart);
endSelection.x = trackingRect.left + selectLines[i].posEnd - font.GetSize() / 8.0;
endSelection.y = trackingRect.top + ( -displaceByY + realHeight ) / 2.0 + realHeight * (REAL)(i+lineStart);
//if( endSelection.y < trackingRect.top ) continue;//old clamp
//if( endSelection.y > trackingRect.bottom ) return;//old clamp
break;
}
case byBottom: // FontAlign
{
startSelection.x = trackingRect.left + selectLines[i].posStart - font.GetSize() / 8.0;
startSelection.y = trackingRect.top - displaceByY + realHeight / 2.0 + realHeight * (REAL)(i+lineStart);
endSelection.x = trackingRect.left + selectLines[i].posEnd - font.GetSize() / 8.0;
endSelection.y = trackingRect.top - displaceByY + realHeight / 2.0 + realHeight * (REAL)(i+lineStart);
//if( endSelection.y < trackingRect.top ) continue;//old clamp
break;
}
default:
{
startSelection.x = trackingRect.left + selectLines[i].posStart - font.GetSize() / 8.0;
startSelection.y = trackingRect.top + realHeight / 2.0 + realHeight * (i+lineStart);
endSelection.x = trackingRect.left + selectLines[i].posEnd - font.GetSize() / 8.0;
endSelection.y = trackingRect.top + realHeight / 2.0 + realHeight * (i+lineStart);
//if( endSelection.y > trackingRect.bottom ) return; //old clamp
break;
}
}
Structures::POINTD center = Structures::POINTD( centerX, centerY );
double angle = fontAngle + M_PI_2;
Geometry::RotatePoint( startSelection, center, angle );
Geometry::RotatePoint( endSelection, center, angle );
Structures::POINTD leftTop ( trackingRect.left, trackingRect.top );
Structures::POINTD rightTop ( trackingRect.right, trackingRect.top );
Structures::POINTD rightBottom ( trackingRect.right, trackingRect.bottom );
Structures::POINTD leftBottom ( trackingRect.left, trackingRect.bottom );
Geometry::RotatePoint( leftTop, center, angle );
Geometry::RotatePoint( rightTop, center, angle );
Geometry::RotatePoint( rightBottom, center, angle );
Geometry::RotatePoint( leftBottom, center, angle );
POINT points[4];
points[0].x = (long)leftTop.x;
points[0].y = (long)leftTop.y;
points[1].x = (long)rightTop.x;
points[1].y = (long)rightTop.y;
points[2].x = (long)rightBottom.x;
points[2].y = (long)rightBottom.y;
points[3].x = (long)leftBottom.x;
points[3].y = (long)leftBottom.y;
HRGN clipRegn = CreatePolygonRgn( points, 4, ALTERNATE );
SelectClipRgn( hDC, clipRegn );
SelectObject( hDC, selectPen );
int oldMode = SetROP2( hDC, R2_NOTXORPEN );
MoveToEx( hDC, (int)startSelection.x, (int)startSelection.y , (LPPOINT) NULL );
LineTo( hDC, (int)endSelection.x, (int)endSelection.y );
SetROP2( hDC, oldMode );
DeleteObject( selectPen );
DeleteObject( clipRegn );
SelectClipRgn( hDC, NULL );
}
graphics.EndContainer(graphicsContainer);
selectLines.RemoveAll();
}
void DrawScaleCaret( HDC hDC, CSimpleArray<CString> &lines, Gdiplus::StringFormat &stringFormat, int posCaret, Gdiplus::Font &font, double fontAngle, Structures::RECTD trackingRect, Structures::POINTD scale )
{
if( NULL == hDC ) return;
Gdiplus::Graphics graphics( hDC );
RectF orig, strBB, chBB, caretRect, allStringRect;
double displaceByY = 0.0;
double displaceByX = 0.0;
double centerX = trackingRect.left + ( trackingRect.right - trackingRect.left ) / 2.0;
double centerY = trackingRect.top + ( trackingRect.bottom - trackingRect.top ) / 2.0;
double dWidth = trackingRect.GetWidth();
double dHeight = trackingRect.GetHeight();
double dWidth_2 = dWidth / 2.0;
double dHeight_2 = dHeight / 2.0;
bool bEmtyString = false;
bool isLastString = false;
Gdiplus::RectF rectF, fontRect;
Gdiplus::Pen fillCaretColor ( Gdiplus::Color( 255, 0, 0, 0 ), 2.0 );
Gdiplus::Pen borderCaretColor ( Gdiplus::Color( 255, 255, 255, 255 ), 4.0 );
int internCaretPos = posCaret;
int index = 0;
double fontHeight = Rendering::Utils::GetFontHeight( &font );
double fontHeightScale = fontHeight * scale.y;
if( 0 == lines.GetSize() ) bEmtyString = true;
if( !bEmtyString )
{
for( index = 0; index < lines.GetSize(); index++ )
{
if( internCaretPos <= lines[index].GetLength() ) break;
internCaretPos -= lines[index].GetLength();
}
if( ( internCaretPos == lines[index].GetLength() || internCaretPos == lines[index].GetLength() - 1 )
&& (index + 1) < lines.GetSize()
&& lines[index][lines[index].GetLength() - 1] == '\n' )
{
internCaretPos = 0;
index++;
}
else if( ( internCaretPos == lines[index].GetLength() || internCaretPos == lines[index].GetLength() - 1 )
&& (index + 1) == lines.GetSize()
&& lines[index][lines[index].GetLength() - 1] == '\n' )
{
isLastString = true;
internCaretPos = 0;
}
stringFormat.SetFormatFlags ( StringFormatFlagsMeasureTrailingSpaces );
CString trimString = lines[index];
trimString.TrimRight();
BSTR str = trimString.AllocSysString();
graphics.MeasureString( str, -1, &font, orig, &stringFormat, &allStringRect );
SysFreeString( str );
allStringRect.Width *= (Gdiplus::REAL)scale.x;
allStringRect.Height = (Gdiplus::REAL) ( fontHeightScale );
if( internCaretPos == 0 )
{
if( 0 == allStringRect.Height )
{
BSTR line = lines[0].AllocSysString();
graphics.MeasureString( line, -1, &font, orig, &stringFormat, &allStringRect );
SysFreeString( line );
allStringRect.Width *= (Gdiplus::REAL)scale.x;
allStringRect.Height = (Gdiplus::REAL) ( fontHeightScale );
}
caretRect = RectF ( 0.0f, 0.0f, (Gdiplus::REAL)font.GetSize() / 5.0f * (Gdiplus::REAL)scale.x, (Gdiplus::REAL)allStringRect.Height );
}
else
{
BSTR str = trimString.AllocSysString();
graphics.MeasureString( str, internCaretPos, &font, orig, &stringFormat, &caretRect );
SysFreeString( str );
caretRect.Width *= (Gdiplus::REAL) scale.x;
caretRect.Height = (Gdiplus::REAL) ( fontHeightScale );
}
}
else
{
caretRect.X = 0;
caretRect.Y = 0;
caretRect.Width = 5;
caretRect.Height = (Gdiplus::REAL) ( trackingRect.GetHeight() );
}
GraphicsContainer graphicsContainer;
graphicsContainer = graphics.BeginContainer();
graphics.TranslateTransform ( (Gdiplus::REAL)centerX, (Gdiplus::REAL)centerY );
RectF trackingRectF( (Gdiplus::REAL)-dWidth_2, (Gdiplus::REAL)-dHeight_2,
(Gdiplus::REAL)trackingRect.GetWidth(), (Gdiplus::REAL)trackingRect.GetHeight() );
caretRect.Width += (Gdiplus::REAL) ( -dWidth_2 );
displaceByY = lines.GetSize() * fontHeightScale;
graphics.RotateTransform ( (Gdiplus::REAL)grad( fontAngle + M_PI_2 ) );
graphics.SetClip ( trackingRectF );
if( caretRect.Y + caretRect.Height <= dHeight )
{
caretRect.Y = (Gdiplus::REAL) ( -dHeight_2 + ( isLastString ? index + 1 : index ) * fontHeightScale );
graphics.DrawLine ( &borderCaretColor,
(Gdiplus::REAL) caretRect.Width - (Gdiplus::REAL)font.GetSize() * (Gdiplus::REAL)scale.x / 8.0f,
(Gdiplus::REAL)caretRect.Y - 1.0f,
(Gdiplus::REAL)caretRect.Width - (Gdiplus::REAL)font.GetSize() * (Gdiplus::REAL)scale.x / 8.0f,
(Gdiplus::REAL)caretRect.Y + (Gdiplus::REAL)caretRect.Height + 1.0f );
graphics.DrawLine ( &fillCaretColor,
(Gdiplus::REAL) caretRect.Width - (Gdiplus::REAL)font.GetSize() * (Gdiplus::REAL)scale.x / 8.0f,
(Gdiplus::REAL)caretRect.Y,
(Gdiplus::REAL)caretRect.Width - (Gdiplus::REAL)font.GetSize() * (Gdiplus::REAL)scale.x / 8.0f,
(Gdiplus::REAL)caretRect.Y + (Gdiplus::REAL)caretRect.Height );
}
graphics.EndContainer( graphicsContainer );
}
void DrawCaret( HDC hDC, CSimpleArray<CString> &lines, Gdiplus::StringFormat &stringFormat, int fontAlignW, int posCaret, Gdiplus::Font &font, double fontAngle, Structures::RECTD trackingRect )
{
if( NULL == hDC ) return;
Gdiplus::Graphics graphics( hDC );
RectF orig, strBB, chBB, caretRect, allStringRect;
double displaceByY = 0.0;
double displaceByX = 0.0;
double centerX = trackingRect.left + ( trackingRect.right - trackingRect.left ) / 2.0;
double centerY = trackingRect.top + ( trackingRect.bottom - trackingRect.top ) / 2.0;
double dWidth = trackingRect.GetWidth();
double dHeight = trackingRect.GetHeight();
double dWidth_2 = dWidth / 2.0;
double dHeight_2 = dHeight / 2.0;
bool bEmtyString = false;
bool isLastString = false;
//if( dWidth < font.GetSize() + font.GetSize() / 8.0 ) return;
if( 0 == lines.GetSize() ) bEmtyString = true;
Gdiplus::RectF rectF, fontRect;
Gdiplus::Pen fillCaretColor ( Gdiplus::Color( 255, 0, 0, 0 ), 2.0 );
Gdiplus::Pen borderCaretColor ( Gdiplus::Color( 255, 255, 255, 255 ), 4.0 );
int internCaretPos = posCaret;
int index = 0;
double fontHeight = Rendering::Utils::GetFontHeight( &font );
if( !bEmtyString )
{
for( index = 0; index < lines.GetSize(); index++ )
{
if( internCaretPos <= lines[index].GetLength() ) break;
internCaretPos -= lines[index].GetLength();
}
if( ( internCaretPos == lines[index].GetLength() || internCaretPos == lines[index].GetLength() - 1 )
&& (index + 1) < lines.GetSize()
&& lines[index][lines[index].GetLength() - 1] == '\n' )
{
internCaretPos = 0;
index++;
}
else if( ( internCaretPos == lines[index].GetLength() || internCaretPos == lines[index].GetLength() - 1 )
&& (index + 1) == lines.GetSize()
&& lines[index][lines[index].GetLength() - 1] == '\n' )
{
isLastString = true;
internCaretPos = 0;
}
stringFormat.SetFormatFlags( StringFormatFlagsMeasureTrailingSpaces );
//char buff[32];
//sprintf( buff, "line num %d caret pos %d\n", index, internCaretPos );
//::OutputDebugStringA( buff );
CString trimString = lines[index];
trimString.TrimRight();
BSTR str = trimString.AllocSysString();
graphics.MeasureString( str, -1, &font, orig, &stringFormat, &allStringRect );
SysFreeString( str );
if( internCaretPos == 0 )
{
if( 0 == fontHeight )
{
BSTR line = lines[0].AllocSysString();
graphics.MeasureString( line, -1, &font, orig, &stringFormat, &allStringRect );
SysFreeString( line );
}
caretRect = RectF ( 0.0f, 0.0f, font.GetSize() / 5.0f, (Gdiplus::REAL)fontHeight );
}
else
{
BSTR line = trimString.AllocSysString();
graphics.MeasureString( str, internCaretPos, &font, orig, &stringFormat, &caretRect );
caretRect.Height = (Gdiplus::REAL) ( fontHeight );
SysFreeString( str );
}
}
else
{
caretRect.X = 0;
caretRect.Y = 0;
caretRect.Width = 5;
caretRect.Height = (Gdiplus::REAL) ( fontHeight );
}
GraphicsContainer graphicsContainer;
graphicsContainer = graphics.BeginContainer();
graphics.TranslateTransform ( (Gdiplus::REAL)centerX, (Gdiplus::REAL)centerY );
RectF trackingRectF( (Gdiplus::REAL)-dWidth_2, (Gdiplus::REAL)-dHeight_2,
(Gdiplus::REAL)trackingRect.GetWidth(), (Gdiplus::REAL)trackingRect.GetHeight() );
if( stringFormat.GetAlignment() == StringAlignmentNear )
caretRect.Width += (Gdiplus::REAL) ( -dWidth_2 );
else if ( stringFormat.GetAlignment() == StringAlignmentCenter )
{
caretRect.Offset ( ( caretRect.Width - allStringRect.Width ) / 2.0f, 0.0f );
if( !bEmtyString ) caretRect.Width += ( lines[index][0] == '\r' ) ? 0 : caretRect.X;
if( isLastString ) caretRect.Width = font.GetSize() / 5;
}
else if( stringFormat.GetAlignment() == StringAlignmentFar )
{
if( bEmtyString )
caretRect.Width += (Gdiplus::REAL) ( dWidth_2 - 5.0 );
else
{
caretRect.Offset( caretRect.Width - allStringRect.Width, 0.0 );
caretRect.Width += ( lines[index][0] == '\r' ) ?
(Gdiplus::REAL) ( dWidth_2 - font.GetSize() / 5 ) :
(Gdiplus::REAL) ( caretRect.X + dWidth_2 );
}
if( isLastString )
caretRect.Width = (Gdiplus::REAL) ( dWidth_2 );
}
displaceByY = lines.GetSize() * fontHeight;
graphics.RotateTransform ( (Gdiplus::REAL)grad( fontAngle + M_PI_2 ) );
graphics.SetClip( trackingRectF );
switch( fontAlignW )
{
case byTop:
{
caretRect.Y = (Gdiplus::REAL) ( -dHeight_2 + ( isLastString ? index + 1 : index ) * fontHeight );
break;
}
case byMiddle:
{
caretRect.Y = (Gdiplus::REAL) ( -displaceByY / 2.0 + ( isLastString ? index + 1 : index ) * fontHeight );
if( bEmtyString ) caretRect.Y -= (Gdiplus::REAL) ( fontHeight / 2.0 );
break;
}
case byBottom:
{
caretRect.Y = (Gdiplus::REAL) ( dHeight_2 - displaceByY + ( isLastString ? index + 1 : index ) * fontHeight );
if( bEmtyString ) caretRect.Y -= (Gdiplus::REAL) ( fontHeight );
break;
}
default:
{
caretRect.Y = (Gdiplus::REAL) ( -dHeight_2 + ( isLastString ? index + 1 : index ) * fontHeight );
}
}
graphics.DrawLine( &borderCaretColor, caretRect.Width - font.GetSize() / 8, caretRect.Y - 1, caretRect.Width - font.GetSize() / 8, caretRect.Y + caretRect.Height + 1);
graphics.DrawLine( &fillCaretColor, caretRect.Width - font.GetSize() / 8, caretRect.Y, caretRect.Width - font.GetSize() / 8, caretRect.Y + caretRect.Height );
graphics.EndContainer( graphicsContainer );
}
class CGdiObject
{
protected:
HDC m_hDC;
int m_nBkColor;
int m_nOldBkColor;
int m_nROP;
int m_nOldROP;
HPEN m_hPen;
HGDIOBJ m_hOldPen;
HBRUSH m_hBrush;
HGDIOBJ m_hOldBrush;
public:
CGdiObject()
{
m_hDC = 0;
m_nROP = -1;
m_nOldROP = -1;
m_nBkColor = -1;
m_nOldBkColor = -1;
m_hPen = 0;
m_hOldPen = 0;
m_hBrush = 0;
m_hOldBrush = 0;
}
~CGdiObject()
{
m_hDC = 0;
Destroy();
}
BOOL Valid()
{
if (m_hDC)
return TRUE;
return FALSE;
}
void Create(HDC hDC)
{
Destroy();
if (!hDC)
return;
m_hDC = hDC;
}
virtual void Destroy()
{
if (m_hDC)
{
if (m_hPen)
SelectObject(m_hDC, m_hOldPen);
if (m_hBrush)
SelectObject(m_hDC, m_hOldBrush);
if (m_nROP >= 0)
SetROP2(m_hDC, m_nOldROP);
if (m_nBkColor >= 0)
SetBkColor(m_hDC, m_nOldBkColor);
}
if (m_hPen)
DeleteObject(m_hPen);
if (m_hBrush)
DeleteObject(m_hBrush);
m_hDC = 0;
m_nROP = -1;
m_nOldROP = -1;
m_nBkColor = -1;
m_nOldBkColor = -1;
m_hPen = 0;
m_hOldPen = 0;
m_hBrush = 0;
m_hOldBrush = 0;
}
};
class CGdiPen : public CGdiObject
{
public:
// nStyle - PS_SOLID, PS_DOT, ...
// nSize - size of the pen in pixels (valid only for PS_SOLID)
// nColor1, nColor2 - color of the pen: valid COLORREF or -1 for invisible or -2 for xor painting
void Create(HDC hDC, int nColor1, int nColor2, int nSize = 1, int nStyle = PS_SOLID)
{
Destroy();
if (!hDC)
return;
m_hDC = hDC;
HPEN hPen = 0;
HBRUSH hBrush = 0;
// select ROP mode
if (TRUE)
{
if (nColor1 == -2 || nColor2 == -2)
m_nOldROP = SetROP2(hDC, R2_NOTXORPEN);
else
m_nOldROP = SetROP2(hDC, R2_COPYPEN);
}
// create pen
if (TRUE)
{
if (nColor1 == -2 || nColor1 >= 0)
{
m_hPen = CreatePen(nStyle, nSize, max(0, nColor1));
hPen = m_hPen;
}
else // if (nCOlor == -1)
{
hPen = (HPEN)GetStockObject(NULL_PEN);
}
}
// create brush
if (TRUE)
{
if (nColor2 == -2)
hBrush = (HBRUSH)GetStockObject(BLACK_BRUSH);
else if (nColor2 == -1)
hBrush = (HBRUSH)GetStockObject(NULL_BRUSH);
else // if (nColor2 > 0)
{
m_hBrush = CreateSolidBrush(nColor2);
m_nBkColor = nColor2;
hBrush = m_hBrush;
}
}
// select create objects
if (TRUE)
{
if (hPen)
m_hOldPen = SelectObject(hDC, hPen);
if (hBrush)
m_hOldBrush = SelectObject(hDC, hBrush);
if (m_nBkColor >= 0)
m_nOldBkColor = SetBkColor(hDC, m_nBkColor);
}
}
};
class CGdiPainter
{
protected:
HDC m_hDC;
CGdiPen m_oPen;
public:
CGdiPainter()
{
m_hDC = 0;
}
~CGdiPainter()
{
Destroy();
}
void Create(HDC hDC)
{
m_hDC = hDC;
}
void Destroy()
{
m_oPen.Destroy();
}
void SetPen(int nColor1, int nColor2, int nSize = 1, int nStyle = PS_SOLID)
{
m_oPen.Create(m_hDC, nColor1, nColor2, nSize, nStyle);
}
};
}
namespace Xml
{
class CXmlPainter
{
protected:
GdiPlusEx::CGdiPlusImage* m_pImage;
GdiPlusEx::CGdiPlusGraphics m_oGraphics;
protected:
BOOL BeginPaint()
{
EndPaint();
if (!IsValid())
return FALSE;
return m_oGraphics.CreateFromImage(m_pImage);
}
void EndPaint()
{
m_oGraphics.Destroy();
}
void ApplyFormat(Painter::CFormat& oFormat)
{
Gdiplus::Graphics* pGraphics = (Gdiplus::Graphics*)m_oGraphics;
if (!pGraphics)
return;
if (oFormat.AntiAliasPen)
pGraphics->SetSmoothingMode(SmoothingModeAntiAlias);
else
pGraphics->SetSmoothingMode(SmoothingModeNone);
if (oFormat.AntiAliasText)
pGraphics->SetTextRenderingHint(TextRenderingHintAntiAlias);
else
pGraphics->SetTextRenderingHint(TextRenderingHintSystemDefault);
}
void PaintLine(Painter::CPen& oPen, Painter::CLine& oLine)
{
Gdiplus::Graphics* pGraphics = (Gdiplus::Graphics*)m_oGraphics;
if (!pGraphics)
return;
Gdiplus::Pen* pPen = oPen.GetPen();
if (!pPen)
return;
pGraphics->DrawLine(pPen, (float)oLine.X1, (float)oLine.Y1, (float)oLine.X2, (float)oLine.Y2);
}
void PaintRectangle(Painter::CPen& oPen, Painter::CBrush& oBrush, Painter::CRectangle& oRectangle)
{
Gdiplus::Graphics* pGraphics = (Gdiplus::Graphics*)m_oGraphics;
if (!pGraphics)
return;
Gdiplus::Brush* pBrush = oBrush.GetBrush();
if (pBrush)
pGraphics->FillRectangle(pBrush, (float)oRectangle.Left, (float)oRectangle.Top, (float)oRectangle.Width, (float)oRectangle.Height);
Gdiplus::Pen* pPen = oPen.GetPen();
if (pPen)
pGraphics->DrawRectangle(pPen, (float)oRectangle.Left, (float)oRectangle.Top, (float)oRectangle.Width, (float)oRectangle.Height);
}
void PaintEllipse(Painter::CPen& oPen, Painter::CBrush& oBrush, Painter::CEllipse& oEllipse)
{
Gdiplus::Graphics* pGraphics = (Gdiplus::Graphics*)m_oGraphics;
if (!pGraphics)
return;
Gdiplus::Brush* pBrush = oBrush.GetBrush();
if (pBrush)
pGraphics->FillEllipse(pBrush, (float)oEllipse.Left, (float)oEllipse.Top, (float)oEllipse.Width, (float)oEllipse.Height);
Gdiplus::Pen* pPen = oPen.GetPen();
if (pPen)
pGraphics->DrawEllipse(pPen, (float)oEllipse.Left, (float)oEllipse.Top, (float)oEllipse.Width, (float)oEllipse.Height);
}
void PaintText(Painter::CBrush& oBrush, Painter::CFont& oFont, Painter::CFormat& oFormat, Painter::CText& oText)
{
Gdiplus::Graphics* pGraphics = (Gdiplus::Graphics*)m_oGraphics;
if (!pGraphics)
return;
Gdiplus::Brush* pBrush = oBrush.GetBrush();
Gdiplus::Font* pFont = oFont.GetFont();
if (!pBrush || !pFont)
return;
Gdiplus::StringFormat oStringAlignment;
Gdiplus::StringFormat* pStringAlignment = oFormat.GetStringFormat();
if (!pStringAlignment)
{
oStringAlignment.SetLineAlignment(Gdiplus::StringAlignmentCenter);
oStringAlignment.SetAlignment(Gdiplus::StringAlignmentCenter);
pStringAlignment = &oStringAlignment;
}
Gdiplus::RectF oRect((float)oText.Left, (float)oText.Top, (float)oText.Width, (float)oText.Height);
BSTR bstrText = oText.Text.AllocSysString();
pGraphics->DrawString(bstrText, oText.Text.GetLength(), pFont, oRect, pStringAlignment, pBrush);
SysFreeString(bstrText);
}
void TransformCrop(Painter::CBrush* pBrushClear, Painter::CTransformCrop& oTransform)
{
Gdiplus::Graphics* pGraphics = (Gdiplus::Graphics*)m_oGraphics;
if (!pGraphics)
return;
Gdiplus::Bitmap* pBitmapDst = (Gdiplus::Bitmap*)(*m_pImage);
Gdiplus::Bitmap* pBitmapSrc = pBitmapDst->Clone(0, 0, pBitmapDst->GetWidth(), pBitmapDst->GetHeight(), PixelFormat32bppRGB);
if (oTransform.ClearBackground)
{
Gdiplus::Brush* pBrush = pBrushClear->GetBrush();
if (pBrush)
pGraphics->FillRectangle(pBrush, 0, 0, pBitmapDst->GetWidth(), pBitmapDst->GetHeight());
}
pGraphics->DrawImage(pBitmapSrc, (float)oTransform.Left, (float)oTransform.Top, (float)oTransform.Width, (float)oTransform.Height);
}
public:
CXmlPainter()
{
m_pImage = NULL;
}
~CXmlPainter()
{
}
BOOL IsValid()
{
if (m_pImage && m_pImage->IsValid())
return TRUE;
return FALSE;
}
BOOL IsPainting()
{
return m_oGraphics.IsValid();
}
void SetImage(GdiPlusEx::CGdiPlusImage* pImage)
{
m_pImage = pImage;
}
GdiPlusEx::CGdiPlusImage* GetImage()
{
return m_pImage;
}
void PaintXml(CString strXml)
{
XmlUtils::CXmlReader oReader;
if (!oReader.SetXmlString(strXml))
return;
int nLayerIndex = 0;
if (!BeginPaint())
return;
// read all layers from the file and paint them
while (true)
{
CString strLayerIndex; strLayerIndex.Format(_T("layer%d"), nLayerIndex);
oReader.ReadRootNode();
if (!oReader.ReadNode(strLayerIndex))
break;
CString strXml;
Painter::CPen oPen;
Painter::CBrush oBrush;
Painter::CFont oFont;
Painter::CFormat oFormat;
// read painting settings
if (true)
{
oReader.ReadRootNode();
oReader.ReadNode(strLayerIndex);
if (oReader.ReadNode(_T("format")))
{
strXml = oReader.ReadNodeXml();
oFormat.FromXmlString(strXml);
ApplyFormat(oFormat);
}
oReader.ReadRootNode();
oReader.ReadNode(strLayerIndex);
if (oReader.ReadNode(_T("pen")))
{
strXml = oReader.ReadNodeXml();
oPen.FromXmlString(strXml);
}
oReader.ReadRootNode();
oReader.ReadNode(strLayerIndex);
if (oReader.ReadNode(_T("brush")))
{
strXml = oReader.ReadNodeXml();
oBrush.FromXmlString(strXml);
}
oReader.ReadRootNode();
oReader.ReadNode(strLayerIndex);
if (oReader.ReadNode(_T("font")))
{
strXml = oReader.ReadNodeXml();
oFont.FromXmlString(strXml);
}
}
// read graphics primitives
if (true)
{
oReader.ReadRootNode();
oReader.ReadNode(strLayerIndex);
if (oReader.ReadNode(_T("line")))
{
strXml = oReader.ReadNodeXml();
Painter::CLine oLine;
oLine.FromXmlString(strXml);
PaintLine(oPen, oLine);
}
oReader.ReadRootNode();
oReader.ReadNode(strLayerIndex);
if (oReader.ReadNode(_T("rectangle")))
{
strXml = oReader.ReadNodeXml();
Painter::CRectangle oRectangle;
oRectangle.FromXmlString(strXml);
PaintRectangle(oPen, oBrush, oRectangle);
}
oReader.ReadRootNode();
oReader.ReadNode(strLayerIndex);
if (oReader.ReadNode(_T("ellipse")))
{
strXml = oReader.ReadNodeXml();
Painter::CEllipse oEllipse;
oEllipse.FromXmlString(strXml);
PaintEllipse(oPen, oBrush, oEllipse);
}
oReader.ReadRootNode();
oReader.ReadNode(strLayerIndex);
if (oReader.ReadNode(_T("text")))
{
strXml = oReader.ReadNodeXml();
Painter::CText oText;
oText.FromXmlString(strXml);
PaintText(oBrush, oFont, oFormat, oText);
}
}
// read and apply transforms
if (true)
{
oReader.ReadRootNode();
oReader.ReadNode(strLayerIndex);
if (oReader.ReadNode(_T("transform-crop")))
{
strXml = oReader.ReadNodeXml();
Painter::CTransformCrop oTransform;
oTransform.FromXmlString(strXml);
TransformCrop(&oBrush, oTransform);
}
}
nLayerIndex++;
}
EndPaint();
}
};
}
namespace TextRendering
{
inline CStringW NormNonBreakingSpaces ( CStringW Input, bool InsertSpace = 0 )
{
if ( false == InsertSpace )
return Input;
if ( Input.GetLength() > 3 )
{
if ( Input.GetAt ( Input.GetLength() - 1 ) == L' ' )
{
Input.Insert ( Input.GetLength() - 1, L'\xA0' ); // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
return Input;
}
if ( Input.GetAt ( Input.GetLength() - 3 ) == L' ' )
{
Input.Insert ( Input.GetLength() - 3, L'\xA0' ); // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
}
}
return Input;
}
inline void DrawAngleScaleTextW ( HDC hDC, CSimpleArray<CStringW> &lines, Gdiplus::Font& font, int FontColor, Gdiplus::StringFormat& stringFormat, double fontAngle, Structures::RECTD fontRect/*, Structures::POINTD scale*/ )
{
if( lines.GetSize() == 0 || NULL == hDC ) return;
Graphics graphics( hDC );
SolidBrush solidBrush( Color( 255, GetRValue(FontColor), GetGValue(FontColor), GetBValue(FontColor) ) );
double dWidth = fontRect.GetWidth();
double dHeight = fontRect.GetHeight();
double dWidth_2 = dWidth / 2.0;
double dHeight_2 = dHeight / 2.0;
double centerX = fontRect.left + dWidth_2;
double centerY = fontRect.top + dHeight_2;
RectF rectF, rectBB;
RectF trackingRectF ( (Gdiplus::REAL)-dWidth_2, (Gdiplus::REAL)-dHeight_2,
(Gdiplus::REAL)fontRect.GetWidth(), (Gdiplus::REAL) fontRect.GetHeight() );
Structures::POINTD scale ( 1.0, 1.0 );
double maxWidthStr = 0.0;
double maxHeightStr = 0.0;
//stringFormat.SetFormatFlags( StringFormatFlags::StringFormatFlagsMeasureTrailingSpaces );
for( int i = 0; i < lines.GetSize(); ++i )
{
//BSTR line = lines[i].AllocSysString();
graphics.MeasureString ( NormNonBreakingSpaces ( lines[i] ), -1, &font, rectF, &stringFormat, &rectBB );
//SysFreeString( line );
maxWidthStr = max( maxWidthStr, rectBB.Width );
maxHeightStr += rectBB.Height;
}
if ( maxWidthStr > 0 && maxHeightStr > 0 )
{
scale.x = fontRect.GetWidth() / maxWidthStr;
scale.y = fontRect.GetHeight() / maxHeightStr;
}
GraphicsContainer graphicsContainer;
graphicsContainer = graphics.BeginContainer();
graphics.TranslateTransform( (Gdiplus::REAL) centerX, (Gdiplus::REAL)centerY );
graphics.RotateTransform ( (Gdiplus::REAL) grad ( fontAngle + M_PI_2 ) );
graphics.ScaleTransform ( (Gdiplus::REAL)scale.x, (Gdiplus::REAL)scale.y );
graphics.SetClip( trackingRectF );
graphics.SetTextRenderingHint( TextRenderingHintAntiAlias );
//because in ImagePaint3 scale text aligned by left only
stringFormat.SetAlignment( StringAlignmentNear );
for( int i = 0; i < lines.GetSize(); ++i )
{
//BSTR line = lines[i].AllocSysString();
graphics.MeasureString ( NormNonBreakingSpaces ( lines[i] ), -1, &font, rectF, &stringFormat, &rectBB );
graphics.DrawString ( NormNonBreakingSpaces ( lines[i] ), -1, &font, Gdiplus::PointF (
(Gdiplus::REAL)-dWidth_2 / (Gdiplus::REAL)scale.x,
(Gdiplus::REAL)-dHeight_2 / (Gdiplus::REAL)scale.y + (Gdiplus::REAL)i * rectBB.Height ), &stringFormat, &solidBrush );
//SysFreeString( line );
}
graphics.EndContainer(graphicsContainer);
}
inline void DrawAngleTextW ( HDC hDC, CSimpleArray<CStringW> &lines, Gdiplus::Font& font, int FontColor, Gdiplus::StringFormat& stringFormat, int fontAlignW, double fontAngle, Structures::RECTD fontRect )
{
if ( 0 == lines.GetSize() || NULL == hDC )
return;
Graphics graphics( hDC );
SolidBrush solidBrush( Color( 255, GetRValue(FontColor), GetGValue(FontColor), GetBValue(FontColor) ) );
double dWidth = fontRect.GetWidth();
double dHeight = fontRect.GetHeight();
double dWidth_2 = dWidth / 2.0;
double dHeight_2 = dHeight / 2.0;
double centerX = fontRect.left + dWidth_2;
double centerY = fontRect.top + dHeight_2;
RectF rectF, rectBB;
RectF trackingRectF( (Gdiplus::REAL)-dWidth_2, (Gdiplus::REAL)-dHeight_2, (Gdiplus::REAL)fontRect.GetWidth(), (Gdiplus::REAL)fontRect.GetHeight() );
stringFormat.SetFormatFlags( StringFormatFlagsNoWrap );
GraphicsContainer graphicsContainer;
graphicsContainer = graphics.BeginContainer();
graphics.TranslateTransform ( (Gdiplus::REAL)centerX, (Gdiplus::REAL)centerY );
graphics.RotateTransform( (Gdiplus::REAL) grad( fontAngle + M_PI_2 ) );
graphics.SetClip( trackingRectF );
graphics.SetTextRenderingHint( TextRenderingHintAntiAlias );
double fontHeight = Rendering::Utils::GetFontHeight( &font );
switch( fontAlignW )
{
case byTop: // FontAlign
{
for( int i = 0; i < lines.GetSize(); ++i )
{
//BSTR line = lines[i].AllocSysString();
graphics.DrawString ( NormNonBreakingSpaces ( lines[i] ), -1, &font,
Gdiplus::RectF( (Gdiplus::REAL)-dWidth_2,
(Gdiplus::REAL)-dHeight_2 + (Gdiplus::REAL)i * (Gdiplus::REAL)fontHeight,
(Gdiplus::REAL)dWidth,
(Gdiplus::REAL)dHeight - (Gdiplus::REAL)i * (Gdiplus::REAL)fontHeight ),
&stringFormat, &solidBrush );
//SysFreeString( line );
}
break;
}
case byMiddle: // FontAlign
{
double displaceByY = lines.GetSize() * fontHeight / 2.0;
for( int i = 0; i < lines.GetSize(); ++i )
{
//BSTR line = lines[i].AllocSysString();
graphics.DrawString( NormNonBreakingSpaces ( lines[i] ), -1, &font,
Gdiplus::RectF( (Gdiplus::REAL)-dWidth_2,
(Gdiplus::REAL)-displaceByY + (Gdiplus::REAL)i * (Gdiplus::REAL)fontHeight,
(Gdiplus::REAL)dWidth,
(Gdiplus::REAL)dHeight + (Gdiplus::REAL)i * (Gdiplus::REAL)fontHeight ),
&stringFormat, &solidBrush );
//SysFreeString( line );
}
break;
}
case byBottom: // FontAlign
{
double displaceByY = lines.GetSize() * fontHeight;
for( int i = 0; i < lines.GetSize(); ++i )
{
//BSTR line = lines[i].AllocSysString();
graphics.DrawString( NormNonBreakingSpaces ( lines[i] ), -1, &font,
Gdiplus::RectF( (Gdiplus::REAL)-dWidth_2,
(Gdiplus::REAL)dHeight_2 - (Gdiplus::REAL)displaceByY + (Gdiplus::REAL) i * (Gdiplus::REAL)fontHeight,
(Gdiplus::REAL)dWidth, (Gdiplus::REAL)dHeight + (Gdiplus::REAL) i * (Gdiplus::REAL)fontHeight ),
&stringFormat, &solidBrush );
//SysFreeString( line );
}
break;
}
default:
{
for( int i = 0; i < lines.GetSize(); ++i )
{
//BSTR line = lines[i].AllocSysString();
graphics.DrawString( NormNonBreakingSpaces ( lines[i] ), -1, &font, Gdiplus::RectF( (Gdiplus::REAL)-dWidth_2,
(Gdiplus::REAL)-dHeight_2 + (Gdiplus::REAL)i * (Gdiplus::REAL)fontHeight,
(Gdiplus::REAL)dWidth,
(Gdiplus::REAL)dHeight - (Gdiplus::REAL)i * (Gdiplus::REAL)fontHeight ),
&stringFormat, &solidBrush );
//SysFreeString( line );
}
break;
}
}
graphics.EndContainer(graphicsContainer);
}
inline void DrawScaleTextSelectW ( HDC hDC, CSimpleArray<CStringW> &lines, WCHAR* string, int selectStart, int selectEnd, Gdiplus::Font& font, Gdiplus::StringFormat &stringFormat, double fontAngle, Structures::RECTD trackingRect, Structures::POINTD scale )
{
if( selectStart == selectEnd || NULL == hDC ) return;
struct Select
{
double posStart;
double posEnd;
int strIndex;
};
if( selectStart > selectEnd )
{
int tmpSelect = selectStart;
selectStart = selectEnd;
selectEnd = tmpSelect;
}
Gdiplus::Graphics graphics( hDC );
CSimpleArray<Select> selectLines;
double centerX = trackingRect.left + ( trackingRect.right - trackingRect.left ) / 2.0;
double centerY = trackingRect.top + ( trackingRect.bottom - trackingRect.top ) / 2.0;
double dWidth = trackingRect.GetWidth();
double dHeight = trackingRect.GetHeight();
double dWidth_2 = dWidth / 2.0;
double dHeight_2 = dHeight / 2.0;
Gdiplus::RectF rectF, selectRectStart, selectRectEnd, selectRect;
stringFormat.SetFormatFlags ( StringFormatFlagsMeasureTrailingSpaces );
int lineStart = 0;
int idx = 0;
bool stop = false;
Select selectPos;
while( selectEnd > 0 )
{
if( idx > lines.GetSize() - 1 || stop ) break;
if( selectStart > lines[idx].GetLength() )
{
selectStart -= lines[idx].GetLength();
selectEnd -= lines[idx].GetLength();
lineStart++;
idx++;
continue;
}
if( selectStart > 0 )
{
//BSTR line = lines[idx].AllocSysString();
graphics.MeasureString( lines[idx], selectStart, &font, rectF, &stringFormat, &selectRect );
selectPos.posStart = selectRect.Width * scale.x;
//SysFreeString( line );
}
else
{
selectPos.posStart = font.GetSize() / 8.0 * scale.x;
}
if( selectEnd <= lines[idx].GetLength() )
{
//BSTR line = lines[idx].AllocSysString();
graphics.MeasureString( lines[idx], selectEnd, &font, rectF, &stringFormat, &selectRect );
selectPos.posEnd = selectRect.Width * scale.x;
stop = true;
//SysFreeString( line );
}
else
{
//BSTR line = lines[idx].AllocSysString();
graphics.MeasureString( lines[idx], -1, &font, rectF, &stringFormat, &selectRect );
selectPos.posEnd = selectRect.Width * scale.x;
selectEnd -= lines[idx].GetLength();
selectStart = 0;
//SysFreeString( line );
}
if( selectPos.posEnd > trackingRect.GetWidth() )
selectPos.posEnd = trackingRect.GetWidth();
selectPos.strIndex = idx;
selectLines.Add( selectPos );
idx++;
}
int countSpace = 1;
for( int i = 0; i < lines.GetSize(); ++i )
{
BSTR line = lines[i].AllocSysString();
WCHAR* currString = line;
while( *currString++ )
{
if( *currString == L'\n' ) countSpace++;
}
SysFreeString( line );
}
GraphicsContainer graphicsContainer;
graphicsContainer = graphics.BeginContainer();
double fontHeight = Rendering::Utils::GetFontHeight( &font );
fontHeight *= scale.y;
LOGBRUSH brushSolid = {BS_SOLID, RGB(0,0,0), 0 };
HPEN selectPen = ExtCreatePen ( PS_GEOMETRIC | PS_SOLID | PS_ENDCAP_FLAT, (DWORD)fontHeight, &brushSolid, 0, NULL );
graphics.TranslateTransform ( (Gdiplus::REAL)centerX, (Gdiplus::REAL)centerY );
RectF trackingRectF( (Gdiplus::REAL)-dWidth_2, (Gdiplus::REAL)-dHeight_2,
(Gdiplus::REAL)trackingRect.GetWidth(),
(Gdiplus::REAL)trackingRect.GetHeight() );
graphics.RotateTransform( (Gdiplus::REAL)grad( fontAngle + M_PI_2 ) );
graphics.SetClip( trackingRectF );
graphics.SetSmoothingMode ( SmoothingModeHighQuality );
for( int i = 0; i < selectLines.GetSize(); ++i )
{
graphics.MeasureString( string, 1, &font, rectF, &stringFormat, &selectRectStart );
selectRectStart.Width *= (Gdiplus::REAL)scale.x;
selectRectStart.Height = (Gdiplus::REAL) ( fontHeight );
double displaceByY = lines.GetSize() * selectRectStart.Height;
Structures::POINTD startSelection( trackingRect.left + selectLines[i].posStart - font.GetSize() * scale.x / 8.0, trackingRect.top + selectRectStart.Height / 2.0 + selectRectStart.Height * ( i + lineStart ) ) ;
Structures::POINTD endSelection ( trackingRect.left + selectLines[i].posEnd - font.GetSize() * scale.x / 8.0, trackingRect.top + selectRectStart.Height / 2.0 + selectRectStart.Height * ( i + lineStart ) );
Geometry::RotatePoint( startSelection, Structures::POINTD( centerX, centerY ), fontAngle + M_PI_2 );
Geometry::RotatePoint( endSelection, Structures::POINTD( centerX, centerY ), fontAngle + M_PI_2 );
SelectObject( hDC, selectPen );
int oldMode = SetROP2( hDC, R2_NOTXORPEN );
MoveToEx( hDC, (int)startSelection.x, (int)startSelection.y , (LPPOINT) NULL );
LineTo ( hDC, (int)endSelection.x, (int)endSelection.y );
SetROP2( hDC, oldMode );
DeleteObject( selectPen );
}
graphics.EndContainer(graphicsContainer);
selectLines.RemoveAll();
}
inline void DrawScaleCaretW ( HDC hDC, CSimpleArray<CStringW> &lines, Gdiplus::StringFormat &stringFormat, int posCaret, Gdiplus::Font &font, double fontAngle, Structures::RECTD trackingRect, Structures::POINTD scale )
{
if( NULL == hDC ) return;
Gdiplus::Graphics graphics( hDC );
RectF orig, strBB, chBB, caretRect, allStringRect;
double displaceByY = 0.0;
double displaceByX = 0.0;
double centerX = trackingRect.left + ( trackingRect.right - trackingRect.left ) / 2.0;
double centerY = trackingRect.top + ( trackingRect.bottom - trackingRect.top ) / 2.0;
double dWidth = trackingRect.GetWidth();
double dHeight = trackingRect.GetHeight();
double dWidth_2 = dWidth / 2.0;
double dHeight_2 = dHeight / 2.0;
bool bEmtyString = false;
bool isLastString = false;
Gdiplus::RectF rectF, fontRect;
Gdiplus::Pen fillCaretColor ( Gdiplus::Color( 255, 0, 0, 0 ), 2.0 );
Gdiplus::Pen borderCaretColor ( Gdiplus::Color( 255, 255, 255, 255 ), 4.0 );
int internCaretPos = posCaret;
int index = 0;
double fontHeight = Rendering::Utils::GetFontHeight( &font );
double fontHeightScale = fontHeight * scale.y;
if( 0 == lines.GetSize() ) bEmtyString = true;
if( !bEmtyString )
{
for( index = 0; index < lines.GetSize(); index++ )
{
if( internCaretPos <= lines[index].GetLength() ) break;
internCaretPos -= lines[index].GetLength();
}
if( ( internCaretPos == lines[index].GetLength() || internCaretPos == lines[index].GetLength() - 1 )
&& (index + 1) < lines.GetSize()
&& lines[index][lines[index].GetLength() - 1] == '\n' )
{
internCaretPos = 0;
index++;
}
else if( ( internCaretPos == lines[index].GetLength() || internCaretPos == lines[index].GetLength() - 1 )
&& (index + 1) == lines.GetSize()
&& lines[index][lines[index].GetLength() - 1] == '\n' )
{
isLastString = true;
internCaretPos = 0;
}
stringFormat.SetFormatFlags ( StringFormatFlagsMeasureTrailingSpaces );
CStringW trimString = lines[index];
trimString.TrimRight();
//BSTR str = trimString.AllocSysString();
graphics.MeasureString( trimString, -1, &font, orig, &stringFormat, &allStringRect );
//SysFreeString( str );
allStringRect.Width *= (Gdiplus::REAL)scale.x;
allStringRect.Height = (Gdiplus::REAL) ( fontHeightScale );
if( internCaretPos == 0 )
{
if( 0 == allStringRect.Height )
{
//BSTR line = lines[0].AllocSysString();
graphics.MeasureString( lines[0], -1, &font, orig, &stringFormat, &allStringRect );
//SysFreeString( line );
allStringRect.Width *= (Gdiplus::REAL)scale.x;
allStringRect.Height = (Gdiplus::REAL) ( fontHeightScale );
}
caretRect = RectF ( 0.0f, 0.0f, (Gdiplus::REAL)font.GetSize() / 5.0f * (Gdiplus::REAL)scale.x, (Gdiplus::REAL)allStringRect.Height );
}
else
{
//BSTR str = trimString.AllocSysString();
graphics.MeasureString( trimString, internCaretPos, &font, orig, &stringFormat, &caretRect );
//SysFreeString( str );
caretRect.Width *= (Gdiplus::REAL) scale.x;
caretRect.Height = (Gdiplus::REAL) ( fontHeightScale );
}
}
else
{
caretRect.X = 0;
caretRect.Y = 0;
caretRect.Width = 5;
caretRect.Height = (Gdiplus::REAL) ( trackingRect.GetHeight() );
}
GraphicsContainer graphicsContainer;
graphicsContainer = graphics.BeginContainer();
graphics.TranslateTransform ( (Gdiplus::REAL)centerX, (Gdiplus::REAL)centerY );
RectF trackingRectF( (Gdiplus::REAL)-dWidth_2, (Gdiplus::REAL)-dHeight_2,
(Gdiplus::REAL)trackingRect.GetWidth(), (Gdiplus::REAL)trackingRect.GetHeight() );
caretRect.Width += (Gdiplus::REAL) ( -dWidth_2 );
displaceByY = lines.GetSize() * fontHeightScale;
graphics.RotateTransform ( (Gdiplus::REAL)grad( fontAngle + M_PI_2 ) );
graphics.SetClip ( trackingRectF );
if( caretRect.Y + caretRect.Height <= dHeight )
{
caretRect.Y = (Gdiplus::REAL) ( -dHeight_2 + ( isLastString ? index + 1 : index ) * fontHeightScale );
graphics.DrawLine ( &borderCaretColor,
(Gdiplus::REAL) caretRect.Width - (Gdiplus::REAL)font.GetSize() * (Gdiplus::REAL)scale.x / 8.0f,
(Gdiplus::REAL)caretRect.Y - 1.0f,
(Gdiplus::REAL)caretRect.Width - (Gdiplus::REAL)font.GetSize() * (Gdiplus::REAL)scale.x / 8.0f,
(Gdiplus::REAL)caretRect.Y + (Gdiplus::REAL)caretRect.Height + 1.0f );
graphics.DrawLine ( &fillCaretColor,
(Gdiplus::REAL) caretRect.Width - (Gdiplus::REAL)font.GetSize() * (Gdiplus::REAL)scale.x / 8.0f,
(Gdiplus::REAL)caretRect.Y,
(Gdiplus::REAL)caretRect.Width - (Gdiplus::REAL)font.GetSize() * (Gdiplus::REAL)scale.x / 8.0f,
(Gdiplus::REAL)caretRect.Y + (Gdiplus::REAL)caretRect.Height );
}
graphics.EndContainer( graphicsContainer );
}
inline void DrawTextSelectW ( HDC hDC, CSimpleArray<CStringW> &lines, WCHAR* string, int selectStart, int selectEnd, Gdiplus::Font& font, Gdiplus::StringFormat &stringFormat, int fontAlignW, double fontAngle, Structures::RECTD trackingRect )
{
if( selectStart == selectEnd || NULL == hDC ) return;
struct Select
{
double posStart;
double posEnd;
int strIndex;
};
if( selectStart > selectEnd )
{
int tmpSelect = selectStart;
selectStart = selectEnd;
selectEnd = tmpSelect;
}
Gdiplus::Graphics graphics( hDC );
CSimpleArray<Select> selectLines;
double centerX = trackingRect.left + ( trackingRect.right - trackingRect.left ) / 2.0;
double centerY = trackingRect.top + ( trackingRect.bottom - trackingRect.top ) / 2.0;
double dWidth = trackingRect.GetWidth();
double dHeight = trackingRect.GetHeight();
double dWidth_2 = dWidth / 2.0;
double dHeight_2 = dHeight / 2.0;
Gdiplus::RectF rectF, selectRectStart, selectRectEnd, selectRect;
if( dWidth < font.GetSize() / 2.0f )
return;
stringFormat.SetFormatFlags( StringFormatFlagsMeasureTrailingSpaces );
double realHeight = Rendering::Utils::GetFontHeight( &font );
int lineStart = 0;
int idx = 0;
bool stop = false;
Select selectPos;
while( selectEnd > 0 )
{
if( idx > lines.GetSize() - 1 || stop ) break;
if( selectStart > lines[idx].GetLength() )
{
selectStart -= lines[idx].GetLength();
selectEnd -= lines[idx].GetLength();
lineStart++;
idx++;
continue;
}
if( selectStart > 0 )
{
//BSTR line = lines[idx].AllocSysString();
graphics.MeasureString( lines[idx], selectStart, &font, rectF, &stringFormat, &selectRect );
selectPos.posStart = selectRect.Width;
//SysFreeString( line );
}
else
{
selectPos.posStart = font.GetSize() / 8.0;
}
if( selectEnd <= lines[idx].GetLength() )
{
//BSTR line = lines[idx].AllocSysString();
graphics.MeasureString( lines[idx], selectEnd, &font, rectF, &stringFormat, &selectRect );
selectPos.posEnd = selectRect.Width;
stop = true;
//SysFreeString( line );
}
else
{
//BSTR line = lines[idx].AllocSysString();
graphics.MeasureString( lines[idx], -1, &font, rectF, &stringFormat, &selectRect );
selectPos.posEnd = selectRect.Width;
selectEnd -= lines[idx].GetLength();
selectStart = 0;
//SysFreeString( line );
}
selectPos.strIndex = idx;
selectLines.Add( selectPos );
idx++;
}
int countSpace = 1;
for( int i = 0; i < lines.GetSize(); ++i )
{
BSTR line = lines[i].AllocSysString();
WCHAR* currString = line;
while( *currString++ )
{
if( *currString == '\n' ) countSpace++;
}
SysFreeString( line );
}
GraphicsContainer graphicsContainer;
graphicsContainer = graphics.BeginContainer();
graphics.TranslateTransform( (Gdiplus::REAL)centerX, (Gdiplus::REAL)centerY );
RectF trackingRectF( (Gdiplus::REAL)-dWidth_2, (Gdiplus::REAL)-dHeight_2,
(Gdiplus::REAL)trackingRect.GetWidth(), (Gdiplus::REAL)trackingRect.GetHeight() );
LOGBRUSH brushSolid = {BS_SOLID, RGB(0,0,0), 0 };
HPEN selectPen = ExtCreatePen( PS_GEOMETRIC | PS_SOLID | PS_ENDCAP_FLAT, (DWORD)realHeight, &brushSolid, 0, NULL );
graphics.RotateTransform ( (Gdiplus::REAL)grad( fontAngle + M_PI_2 ) );
graphics.SetClip( trackingRectF );
graphics.SetSmoothingMode( SmoothingModeHighQuality );
for( int i = 0; i < selectLines.GetSize(); ++i )
{
if ( stringFormat.GetAlignment() == StringAlignmentCenter )
{
CStringW trimString = lines [ selectLines[i].strIndex ];
trimString.TrimRight();
//BSTR str = trimString.AllocSysString();
graphics.MeasureString( trimString, -1, &font, rectF, &stringFormat, &selectRect );
selectLines[i].posStart += selectRect.X + dWidth_2;
selectLines[i].posEnd += selectRect.X + dWidth_2;
//SysFreeString( str );
}
else if( stringFormat.GetAlignment() == StringAlignmentFar )
{
CStringW trimString = lines [ selectLines[i].strIndex ];
trimString.TrimRight();
//BSTR str = trimString.AllocSysString();
graphics.MeasureString( trimString, -1, &font, rectF, &stringFormat, &selectRect );
selectLines[i].posStart += selectRect.X + dWidth;
selectLines[i].posEnd += selectRect.X + dWidth;
//SysFreeString( str );
}
double displaceByY = lines.GetSize() * realHeight - dHeight;
Structures::POINTD startSelection;
Structures::POINTD endSelection;
switch( fontAlignW )
{
case byTop: // FontAlign
{
startSelection.x = trackingRect.left + selectLines[i].posStart - font.GetSize() / 8.0;
startSelection.y = trackingRect.top + realHeight / 2.0 + realHeight * (i+lineStart);
endSelection.x = trackingRect.left + selectLines[i].posEnd - font.GetSize() / 8.0;
endSelection.y = trackingRect.top + realHeight / 2.0 + realHeight * (i+lineStart);
//if( endSelection.y > trackingRect.bottom ) return;//old clamp
break;
}
case byMiddle: // FontAlign
{
startSelection.x = trackingRect.left + selectLines[i].posStart - font.GetSize() / 8.0;
startSelection.y = trackingRect.top + ( -displaceByY + realHeight ) / 2.0 + realHeight * (REAL)(i+lineStart);
endSelection.x = trackingRect.left + selectLines[i].posEnd - font.GetSize() / 8.0;
endSelection.y = trackingRect.top + ( -displaceByY + realHeight ) / 2.0 + realHeight * (REAL)(i+lineStart);
//if( endSelection.y < trackingRect.top ) continue;//old clamp
//if( endSelection.y > trackingRect.bottom ) return;//old clamp
break;
}
case byBottom: // FontAlign
{
startSelection.x = trackingRect.left + selectLines[i].posStart - font.GetSize() / 8.0;
startSelection.y = trackingRect.top - displaceByY + realHeight / 2.0 + realHeight * (REAL)(i+lineStart);
endSelection.x = trackingRect.left + selectLines[i].posEnd - font.GetSize() / 8.0;
endSelection.y = trackingRect.top - displaceByY + realHeight / 2.0 + realHeight * (REAL)(i+lineStart);
//if( endSelection.y < trackingRect.top ) continue;//old clamp
break;
}
default:
{
startSelection.x = trackingRect.left + selectLines[i].posStart - font.GetSize() / 8.0;
startSelection.y = trackingRect.top + realHeight / 2.0 + realHeight * (i+lineStart);
endSelection.x = trackingRect.left + selectLines[i].posEnd - font.GetSize() / 8.0;
endSelection.y = trackingRect.top + realHeight / 2.0 + realHeight * (i+lineStart);
//if( endSelection.y > trackingRect.bottom ) return; //old clamp
break;
}
}
Structures::POINTD center = Structures::POINTD( centerX, centerY );
double angle = fontAngle + M_PI_2;
Geometry::RotatePoint( startSelection, center, angle );
Geometry::RotatePoint( endSelection, center, angle );
Structures::POINTD leftTop ( trackingRect.left, trackingRect.top );
Structures::POINTD rightTop ( trackingRect.right, trackingRect.top );
Structures::POINTD rightBottom ( trackingRect.right, trackingRect.bottom );
Structures::POINTD leftBottom ( trackingRect.left, trackingRect.bottom );
Geometry::RotatePoint( leftTop, center, angle );
Geometry::RotatePoint( rightTop, center, angle );
Geometry::RotatePoint( rightBottom, center, angle );
Geometry::RotatePoint( leftBottom, center, angle );
POINT points[4];
points[0].x = (long)leftTop.x;
points[0].y = (long)leftTop.y;
points[1].x = (long)rightTop.x;
points[1].y = (long)rightTop.y;
points[2].x = (long)rightBottom.x;
points[2].y = (long)rightBottom.y;
points[3].x = (long)leftBottom.x;
points[3].y = (long)leftBottom.y;
HRGN clipRegn = CreatePolygonRgn( points, 4, ALTERNATE );
SelectClipRgn( hDC, clipRegn );
SelectObject( hDC, selectPen );
int oldMode = SetROP2( hDC, R2_NOTXORPEN );
MoveToEx( hDC, (int)startSelection.x, (int)startSelection.y , (LPPOINT) NULL );
LineTo( hDC, (int)endSelection.x, (int)endSelection.y );
SetROP2( hDC, oldMode );
DeleteObject( selectPen );
DeleteObject( clipRegn );
SelectClipRgn( hDC, NULL );
}
graphics.EndContainer(graphicsContainer);
selectLines.RemoveAll();
}
inline void DrawCaretW ( HDC hDC, CSimpleArray<CStringW> &lines, Gdiplus::StringFormat &stringFormat, int fontAlignW, int posCaret, Gdiplus::Font &font, double fontAngle, Structures::RECTD trackingRect )
{
if ( NULL == hDC )
return;
Gdiplus::Graphics graphics( hDC );
RectF orig, strBB, chBB, caretRect, allStringRect;
double displaceByY = 0.0;
double displaceByX = 0.0;
double centerX = trackingRect.left + ( trackingRect.right - trackingRect.left ) / 2.0;
double centerY = trackingRect.top + ( trackingRect.bottom - trackingRect.top ) / 2.0;
double dWidth = trackingRect.GetWidth();
double dHeight = trackingRect.GetHeight();
double dWidth_2 = dWidth / 2.0;
double dHeight_2 = dHeight / 2.0;
bool bEmtyString = false;
bool isLastString = false;
//if( dWidth < font.GetSize() + font.GetSize() / 8.0 ) return;
if( 0 == lines.GetSize() ) bEmtyString = true;
Gdiplus::RectF rectF, fontRect;
Gdiplus::Pen fillCaretColor ( Gdiplus::Color( 255, 0, 0, 0 ), 2.0 );
Gdiplus::Pen borderCaretColor ( Gdiplus::Color( 255, 255, 255, 255 ), 4.0 );
int internCaretPos = posCaret;
int index = 0;
double fontHeight = Rendering::Utils::GetFontHeight( &font );
if( !bEmtyString )
{
for( index = 0; index < lines.GetSize(); index++ )
{
if( internCaretPos <= lines[index].GetLength() ) break;
internCaretPos -= lines[index].GetLength();
}
if( ( internCaretPos == lines[index].GetLength() || internCaretPos == lines[index].GetLength() - 1 )
&& (index + 1) < lines.GetSize()
&& lines[index][lines[index].GetLength() - 1] == '\n' )
{
internCaretPos = 0;
index++;
}
else if( ( internCaretPos == lines[index].GetLength() || internCaretPos == lines[index].GetLength() - 1 )
&& (index + 1) == lines.GetSize()
&& lines[index][lines[index].GetLength() - 1] == '\n' )
{
isLastString = true;
internCaretPos = 0;
}
stringFormat.SetFormatFlags( StringFormatFlagsMeasureTrailingSpaces );
//char buff[32];
//sprintf( buff, "line num %d caret pos %d\n", index, internCaretPos );
//::OutputDebugStringA( buff );
CStringW trimString = lines[index];
//trimString.TrimRight();
trimString.Delete ( trimString.GetLength () - 2, 2 );
//!!!!!!!!!!!
//BSTR str = trimString.AllocSysString();
graphics.MeasureString ( trimString, -1, &font, orig, &stringFormat, &allStringRect );
//SysFreeString( str );
if ( internCaretPos == 0 )
{
if ( 0 == fontHeight )
{
//BSTR line = lines[0].AllocSysString();
graphics.MeasureString( NormNonBreakingSpaces ( lines[0] ), -1, &font, orig, &stringFormat, &allStringRect );
//SysFreeString( line );
}
caretRect = RectF ( 0.0f, 0.0f, font.GetSize() / 5.0f, (Gdiplus::REAL)fontHeight );
}
else
{
//BSTR line = trimString.AllocSysString();
graphics.MeasureString ( trimString, internCaretPos, &font, orig, &stringFormat, &caretRect );
caretRect.Height = (Gdiplus::REAL) ( fontHeight );
//SysFreeString( str );
}
}
else
{
caretRect.X = 0;
caretRect.Y = 0;
caretRect.Width = 5;
caretRect.Height = (Gdiplus::REAL) ( fontHeight );
}
GraphicsContainer graphicsContainer;
graphicsContainer = graphics.BeginContainer();
graphics.TranslateTransform ( (Gdiplus::REAL)centerX, (Gdiplus::REAL)centerY );
RectF trackingRectF( (Gdiplus::REAL)-dWidth_2, (Gdiplus::REAL)-dHeight_2,
(Gdiplus::REAL)trackingRect.GetWidth(), (Gdiplus::REAL)trackingRect.GetHeight() );
if ( stringFormat.GetAlignment() == StringAlignmentNear )
{
caretRect.Width += (Gdiplus::REAL) ( -dWidth_2 );
}
else if ( stringFormat.GetAlignment() == StringAlignmentCenter )
{
caretRect.Offset ( ( caretRect.Width - allStringRect.Width ) / 2.0f, 0.0f );
if( !bEmtyString ) caretRect.Width += ( lines[index][0] == '\r' ) ? 0 : caretRect.X;
if( isLastString ) caretRect.Width = font.GetSize() / 5;
}
else if( stringFormat.GetAlignment() == StringAlignmentFar )
{
if( bEmtyString )
caretRect.Width += (Gdiplus::REAL) ( dWidth_2 - 5.0 );
else
{
caretRect.Offset( caretRect.Width - allStringRect.Width, 0.0 );
caretRect.Width += ( lines[index][0] == '\r' ) ?
(Gdiplus::REAL) ( dWidth_2 - font.GetSize() / 5 ) :
(Gdiplus::REAL) ( caretRect.X + dWidth_2 );
}
if( isLastString )
caretRect.Width = (Gdiplus::REAL) ( dWidth_2 );
}
displaceByY = lines.GetSize() * fontHeight;
graphics.RotateTransform ( (Gdiplus::REAL)grad( fontAngle + M_PI_2 ) );
graphics.SetClip( trackingRectF );
switch( fontAlignW )
{
case byTop:
{
caretRect.Y = (Gdiplus::REAL) ( -dHeight_2 + ( isLastString ? index + 1 : index ) * fontHeight );
break;
}
case byMiddle:
{
caretRect.Y = (Gdiplus::REAL) ( -displaceByY / 2.0 + ( isLastString ? index + 1 : index ) * fontHeight );
if( bEmtyString ) caretRect.Y -= (Gdiplus::REAL) ( fontHeight / 2.0 );
break;
}
case byBottom:
{
caretRect.Y = (Gdiplus::REAL) ( dHeight_2 - displaceByY + ( isLastString ? index + 1 : index ) * fontHeight );
if( bEmtyString ) caretRect.Y -= (Gdiplus::REAL) ( fontHeight );
break;
}
default:
{
caretRect.Y = (Gdiplus::REAL) ( -dHeight_2 + ( isLastString ? index + 1 : index ) * fontHeight );
}
}
graphics.DrawLine ( &borderCaretColor, caretRect.Width - font.GetSize() / 8, caretRect.Y - 1, caretRect.Width - font.GetSize() / 8, caretRect.Y + caretRect.Height + 1);
graphics.DrawLine ( &fillCaretColor, caretRect.Width - font.GetSize() / 8, caretRect.Y, caretRect.Width - font.GetSize() / 8, caretRect.Y + caretRect.Height );
graphics.EndContainer ( graphicsContainer );
}
}
}