Source file: /~heha/enas/Convac-Ätzer/RezEdit.zip/XYGraph.h

#pragma once
#include <windows.h>

struct rect:RECT{
 int width() const {return right-left;}
 int height() const {return bottom-top;}
 rect() {SetRectEmpty(this);}
 rect(int l,int t,int r,int b) {set(l,t,r,b);}
 rect(const rect&r)	{operator=(r);}
 void set(int l,int t,int r,int b) {SetRect(this,l,t,r,b);}
 operator=(const rect&r)	{CopyRect(this,&r);}
 void inflate(int dx,int dy) {InflateRect(this,dx,dy);}
 void offset(int dx,int dy) {OffsetRect(this,dx,dy);}
 bool equal(const RECT&r) const {return !!EqualRect(this,&r);}
 bool isEmpty() const {return !!IsRectEmpty(this);}
};

#pragma warning(disable:4530)	// C++-Behandlungsroutine verwendet, aber Entladesemantik ist nicht aktiviert.
#include <vector>

/*******************
 * Hier geht's los *
 *******************/
template<class T>struct Pair{
 T x,y;
};
template<class T>struct MinMax{
 T min,max;
 void prepare();	// Für Bereichssuche vorbereiten
 void expand(T v);	// Ein Element in Bereich einpassen (NaNs und INFs auch??)
 void verify();		// Bereichssuche beenden (mit LabVIEW-Vorgabe)
 double diff() const{return max-min;}	// für lineare Skale
 double ratio() const{return max/min;}	// für logarithmische Skale
};

struct DynData{
 virtual void ExpandMinMax(int axis,MinMax<float>&minmax) const=0;	// axis = 0 oder 1
 virtual int getLength() const=0;
 virtual void getDouble(int index,Pair<float>&v) const=0;
 virtual void add(WPARAM,LPARAM)=0;
};

struct XYGraph;

struct Scale:rect{
 XYGraph*owner;
// const char*name;
 int f;	// Flags:  Bit 0: 0 = Y (weil links!!), 1 = X
		// Bit 1: 0 = links oder oben, 1 = rechts oder unten (Bit 1:0 = Seite)
		// Bit 2: 0 = positive Skalierung (nach rechts/unten), 1 = negative Skalierung (nach links/oben)
		// Bit 3: 0 = linear, 1 = logarithmisch
		// Bit 4: 0 = manual scale, 1 = autoscale
		// Bit 5: Skale sichtbar
		// Bit 6: "name" sichtbar
		// Bit 7: Digitale Busse erweitern (?)
		// Bit 8: 0 = nameFont = Stock-Objekt oder fremd, 1 = eigener nameFont
		// Bit 9: 0 = tickPen fremdverwaltet, 1 = tickPen eigen
		// Bit 10: GridPen eigen
// Eine X-Standardachse muss demnach mit 3, eine Y-Standardachse mit 4 initialisiert werden.
// Das vererbte Rechteck bleibt stets wohlsortiert, also right>left und bottom>top.
 MinMax<float> minmax;
 float factor;
 float offset;
 int ticklen;
 const char*name;
 const char*format;	// Formatstring für Skale
 COLORREF nameColor;	// Im Gegensatz zu LabVIEW keine Einzelbuchstaben-Farben und -Fonts
 COLORREF tickColor;	// Schrift
 COLORREF majorGridColor;
 COLORREF minorGridColor;
 HPEN tickPen;		// Strich
 HPEN majorGridPen;	// Orientierunslinie im Grafen
 HPEN minorGridPen;
 HFONT nameFont;
 int width_height() const {return (&right)[f&1]-(&left)[f&1];}	// Breite oder Höhe liefern, je nach Seite zu rcPlot
 int height_width() const {return (&right)[f&1^1]-(&left)[f&1^1];}	// Höhe oder Breite liefern, je nach Seite zu rcPlot
 int repos(int xy);	// von innen nach außen repositionieren, Breite konstant haltend
 std::vector<float> ticks;
 int nk;
 Scale(XYGraph*o,int side,const char*n);
 ~Scale();
 void onSize();	// wenn Position oder Größe geändert: Ticks neu berechnen usw.
 void onSetFont();
 void setscale(float b,float e)	{minmax.min=b; minmax.max=e; autoscale();}
 void autoscale();
 virtual void paint(HDC) const=0;
 int trafo(float) const;
 float backtrafo(int) const;
 int needWidth(HDC dc);	// Berechnet szNumb und liefert benötigte Breite des Skalenstreifens
 int needExtra() const;	// Liefert Überlänge am Skalenrand; nach needWidth() aufzurufen
protected:
 void valueToString(char*,float) const;
 void measureValue(HDC,float);
 SIZE szNumb;		// (maximale) Textausdehnung für Skalen-Zahlen
};
struct XScale:Scale{
 XScale(XYGraph*owner):Scale(owner,0x73,"time"){}
 virtual void paint(HDC) const;
};
struct YScale:Scale{
 YScale(XYGraph*owner):Scale(owner,0x74,"temp"){}
 virtual void paint(HDC) const;
};

struct Plot{
 XYGraph*owner;
 const char*name;
 COLORREF lineColor;
 COLORREF fillColor;
 HPEN pen;
 HBRUSH fill;
 char marker;
 char join;
 bool visible;
 Scale*xScale,*yScale;
 DynData*data;
 Plot(XYGraph*o,DynData*d);
 ~Plot();
 void paint(HDC dc) const;
};

struct Cursor{
 Plot*plot;
 int f;		// Bit 0: 0 = X-Cursor, 1 = Y-Cursor
 float value;
 HPEN pen;
 Cursor(Plot*);
 ~Cursor();
 void paint(HDC dc) const;
};

struct XYGraph{
// rect rcPlot0;	// inklusive Rand
 rect rcPlot;	// reine Zeichenfläche
// rect rcMargin;
// HDC dc;	// für GetTextExtent
 HFONT hFont;	// Standard-Dialogschrift
 HBRUSH hbrBack;
 std::vector<XScale> xscales;
 std::vector<YScale> yscales;
 std::vector<Plot> plots;
 std::vector<Cursor> cursors;
 static LPARAM WndProc(HWND,UINT,WPARAM,LPARAM);
 LPARAM handleWndProc(HWND,UINT,WPARAM,LPARAM);
 XYGraph();
 ~XYGraph();
};

struct DynDataInt:DynData{
 std::vector<POINT>data;
 virtual int getLength() const {return data.size();}
 virtual void getDouble(int index, Pair<float>&v) const {
  v.x=data[index].x;
  v.y=data[index].y;
 }
 virtual void add(WPARAM wParam, LPARAM lParam) {
  POINT pt={wParam,lParam};
  data.push_back(pt);
 }
 virtual void ExpandMinMax(int axis,MinMax<float>&minmax) const{
  std::vector<POINT>::const_iterator i;
  for (i=data.begin(); i<data.end(); ++i) {
   minmax.expand(((int*)i)[axis]);
  }
 }
};

/*************
 * Win32-API *
 *************/
enum{
 GM_RESET	=0x401,
 GM_ADDPLOT	=0x402,
 GM_ADDPOINT	=0x403,
};
Detected encoding: ANSI (CP1252)4
Wrong umlauts? - Assume file is ANSI (CP1252) encoded