Quelltext /~heha/ewa/Ofen/prozess.zip/msvc/prozess/xy.cpp

#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&center,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