#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,
};
Vorgefundene Kodierung: UTF-8 | 0
|