#include "xy.h"
/*********
* Skale *
*********/
Scale::Scale(XY*_parent,int _side,const wchar_t*_name):
a(0),e(10),O(0),F(1),
parent(_parent),side(_side),
name(_name),format(L"%.2f") {
font[0]=new Gdiplus::Font(Gdiplus::GenericSansSerifFontFamily,10);
font[1]=new Gdiplus::Font(Gdiplus::GenericSansSerifFontFamily,10,Gdiplus::FontStyleBold);
brush[0]=new Gdiplus::SolidBrush(color[0]);
brush[1]=new Gdiplus::SolidBrush(color[1]);
}
Scale::~Scale() {
delete brush[1];
delete brush[0];
delete font[1];
delete font[0];
}
void Scale::onPaint(Gdiplus::Graphics&g) {
Gdiplus::StringFormat sf;
sf.SetLineAlignment(Gdiplus::StringAlignmentCenter);
Gdiplus::PointF p1,p2;
Gdiplus::Pen pen(color[0]);
for each(Label lbl in labels) {
p1.X=(float)left; p1.Y=scale(lbl.position);
p2.X=p1.X+4; p2.Y=p1.Y;
g.DrawLine(&pen,p1,p2);
g.DrawString(lbl.string,-1,font[0],p2,&sf,brush[0]);
}
if (name) {
sf.SetFormatFlags(Gdiplus::StringFormatFlagsDirectionVertical);
sf.SetAlignment(Gdiplus::StringAlignmentCenter);
sf.SetLineAlignment(Gdiplus::StringAlignmentNear);
g.DrawString(name,-1,font[1],p1,&sf,brush[1]);
}
}
// Der Unterschied zwischen „DirectionVertical“ und „Rotation“ fällt erst bei Chinesisch/Japanisch auf.
void Scale::onSize() {
}
void Scale::distributeTicks(Gdiplus::Graphics&g) {
}
// Hier: siz.cx = Überhang (links und rechts), siz.cy = benötigte Höhe
void Scale::needSpace(Gdiplus::Graphics&g,SIZE&siz) const{
// TODO: Iteriere über alle Labels, füge Achsenbezeichnung hinzu
Gdiplus::PointF pt(0,0);
Gdiplus::RectF bbox;
g.MeasureString(L"X",-1,font[0],pt,&bbox);
siz.cx=(int)bbox.Width>>1; // Hälfte
siz.cy=(int)bbox.Height;
if (name && *name) siz.cy<<=1; // 2×
}
/***********
* XY-Graf *
***********/
XY::XY(HWND Wnd):wnd(Wnd) {
Gdiplus::GdiplusStartupInput gpsi;
Gdiplus::GdiplusStartup(&gdiplusToken,&gpsi,0);
xscale=new Scale(this);
yscales.push_back(new Scale(this,4));
Label lbl={L"Hase",1,0};
yscales[0]->labels.push_back(lbl);
yscales[0]->name=L"Mein Name";
}
XY::~XY() {
delete xscale;
for each(Scale*ys in yscales) delete ys;
Gdiplus::GdiplusShutdown(gdiplusToken);
}
void XY::onSize(int cx, int cy) {
Gdiplus::Graphics g(wnd);
SetRect(&rcPlot,0,0,cx,cy);
// Pass 1: Größe der Plot-Ränder bestimmen
int xextra=0,yextra=0;
SIZE siz;
xscale->needSpace(g,siz);
rcPlot.bottom-=siz.cy;
xextra=siz.cx;
// Schleifenkonstruktion MSVC6
for(std::vector<Scale*>::iterator ysi=yscales.begin();ysi!=yscales.end();++ysi) {
Scale*ys=*ysi;
ys->needSpace(g,siz);
if (ys->side&2) rcPlot.right-=siz.cx; else rcPlot.left+=siz.cx;
if (yextra<siz.cy) yextra=siz.cy;
}
if (rcPlot.left<xextra) rcPlot.left=xextra;
if (rcPlot.top<yextra) rcPlot.top=yextra;
if (rcPlot.right>cx-xextra) rcPlot.right=cx-xextra;
if (rcPlot.bottom>cx-yextra) rcPlot.bottom=cy-yextra;
// Pass 2: Skalen platzieren
SetRect(xscale,rcPlot.left,rcPlot.bottom,rcPlot.right,cy);
xscale->calcFO();
int l=rcPlot.left, r=rcPlot.right;
// Schleifenkonstruktion VC2008
for each(Scale*ys in yscales) {
ys->needSpace(g,siz);
if (ys->side&2) {
SetRect(ys,r,rcPlot.top,r+siz.cx,rcPlot.bottom);
r+=siz.cx;
}else{
SetRect(ys,l-siz.cx,rcPlot.top,l,rcPlot.bottom);
l-=siz.cx;
}
ys->calcFO();
}
// Pass 3: Skalierungen aktualisieren
for each(Scale*ys in yscales) ys->onSize();
}
static void circle(Gdiplus::Graphics&g,Gdiplus::Pen*pen,Gdiplus::PointF¢er,float dia=10.0) {
g.DrawEllipse(pen,center.X-dia/2,center.Y-dia/2,dia,dia);
}
void XY::onPaint(Gdiplus::Graphics&g) {
Rect rcClient;
GetClientRect(wnd,&rcClient);
g.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);
g.DrawLine(new Gdiplus::Pen(Gdiplus::Color()),rcClient.left,rcClient.top,rcClient.right,rcClient.bottom);
Gdiplus::Pen pen(Gdiplus::Color(255,0,0,255),3);
g.DrawLine(&pen,rcPlot.left,rcPlot.bottom,rcPlot.right,rcPlot.top);
#if 1
{using namespace Gdiplus;
static const wchar_t vText[]= L"Vertikaler Text: الباب 你好";
Font*font = new Font(FontFamily::GenericSansSerif(),14);
PointF pt(40,20);
StringFormat sf;
sf.SetLineAlignment(StringAlignmentCenter);
Brush*brush = new SolidBrush(Color(255, 0, 0, 255));
Pen*pen=new Pen(Color(0,255,0));
RectF bbox;
g.MeasureString(vText,-1,font,pt,&sf,&bbox);
sf.SetFormatFlags(StringFormatFlagsDirectionVertical); // Nur für Chinesisch relevant!
circle(g,pen,pt,bbox.Height);
g.DrawString(vText,-1,font,pt,&sf,brush);
sf.SetFormatFlags(0);
g.RotateTransform(90);
g.MeasureString(vText,-1,font,pt,&sf,&bbox);
pt.X+=bbox.Height;
PointF pt2=pt;
g.TransformPoints(CoordinateSpaceWorld,CoordinateSpacePage,&pt2,1);
circle(g,pen,pt2,bbox.Height);
g.DrawString(L"Von links lesbar: الباب 你好",-1,font,pt2,&sf,brush); // von links lesbar (auch das Chinesisch)
g.RotateTransform(180);
pt.X+=bbox.Height;
pt2=pt;
g.TransformPoints(CoordinateSpaceWorld,CoordinateSpacePage,&pt2,1);
sf.SetAlignment(StringAlignmentFar);
circle(g,pen,pt2,bbox.Height);
g.DrawString(L"Von rechts lesbar: الباب 你好",-1,font,pt2,&sf,brush); // von rechts lesbar
delete font;
delete brush;
delete pen;
}
#else
Gdiplus::Font fnt(Gdiplus::GenericSansSerifFontFamily,10);
Gdiplus::PointF org(20,20);
Gdiplus::SolidBrush br(Gdiplus::Color(128,0,255));
g.DrawString(L"Hier",-1,&fnt,org,&br);
#endif
// MoveToEx(ps.hdc,rcPlot.left,rcPlot.bottom,0);
// LineTo(ps.hdc,rcPlot.right,rcPlot.top);
xscale->onPaint(g);
// Schleifenkonstruktion MSVC2017
// for(auto ys:yscales) ys->onPaint(ps); // alle Y-Skalen
for each (Scale*ys in yscales) ys->onPaint(g); // alle Y-Skalen
for each (Plot*pl in plots) pl->onPaint(g);
}
LRESULT XY::wndproc(UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_SIZE: onSize(GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam)); return 0;
case WM_PAINT: {
PAINTSTRUCT ps;
Gdiplus::Graphics g(BeginPaint(wnd,&ps));
onPaint(g);
EndPaint(wnd,&ps);
}return 0;
case WM_PRINTCLIENT: {
Gdiplus::Graphics g((HDC)wParam);
onPaint(g);
}return 0;
}
return DefWindowProc(wnd,msg,wParam,lParam);
}
LRESULT CALLBACK XY::wndproc(HWND Wnd, UINT msg, WPARAM wParam, LPARAM lParam) {
XY*self=(XY*)GetWindowLong(Wnd,0);
if (!self) {
self=new XY(Wnd);
SetWindowLong(Wnd,0,(LONG_PTR)self);
}
LRESULT ret=self->wndproc(msg,wParam,lParam);
if (msg==WM_NCDESTROY) delete self;
return ret;
}
BOOL XY::init() {
static const WNDCLASS wc={
CS_DBLCLKS|CS_HREDRAW|CS_VREDRAW|CS_PARENTDC,
wndproc,
0,
sizeof(XY*),
0,
0,
0,
HBRUSH(COLOR_WINDOW+1),
0,MAKEINTRESOURCE(42)
};
return RegisterClass(&wc);
}
Vorgefundene Kodierung: ASCII (7 bit) | 9
|