#include "vipsys3.h"
#include "WndTable.h"
#include "analyzer.h"
#include <windowsx.h>
#include <stdio.h>
#include <tchar.h>
/**********************************
* Zeichenobjekte und -funktionen *
**********************************/
#define FONTNAME T("Arial") // Name of standard font used
struct TBL{ // holds GDI resources needed for painting the client area
HWND w;
HFONT fntBig,fntSmall; // fonts
HPEN penGrid; // for table styling
HBITMAP bmDblBuf; // bitmap and DC, only used for double buffering
HDC dcDblBuf;
TBL(HWND x) {w=x;}
void Make(int,int); // (Re)Creates fonts and doublebuffer bitmap for given client pixel size
void Make(); // Same but fetches the client size beforehand
void Delete();
~TBL() {Delete();} // Releases all GDI resources
int xx; // Spaltenbreite (Pixel)
int yy; // Zeilenhöhe (Pixel)
void OutLine(HDC dc, UINT id, double f[], int n);
void OutLine(HDC dc, UINT id, VAL3 v[4]);
void OutLine(HDC dc, UINT id, VAL3 v[4], VAL3 a[4], VAL3 p[4]);
void OutLine(HDC dc, UINT id, VAL2 v[4], char e);
void HandlePaint(HDC dc,LPARAM options);
private:
static HFONT MakeFont(int,int,int,LPCTSTR);
static void DeleteObj(HGDIOBJ&);
};
void TBL::DeleteObj(HGDIOBJ&obj) {
if (obj && DeleteObject(obj)) obj=0;
}
void TBL::Delete() {
if (dcDblBuf && DeleteDC(dcDblBuf)) dcDblBuf=0; // kicks out selected pen, font, and bitmap
HGDIOBJ *obj=(HGDIOBJ*)this;
for (int i=0; i<4; i++) DeleteObj(obj[i]);
}
HFONT TBL::MakeFont(int x, int y, int weight, LPCTSTR name) {
HFONT ret=CreateFont(y,x,0,0,weight,0,0,0,DEFAULT_CHARSET,0,0,0,0,name);
return ret;
}
// Font re-initialization, called when
// * window size changes
// * measurement unit or prefix changes
// * appearance changes between scope and multimeter mode
void TBL::Make(int x, int y) {
Delete();
if (Config.doubleBuf) {
HDC dc=GetDC(0);
bmDblBuf=CreateCompatibleBitmap(dc,x,y);
dcDblBuf=CreateCompatibleDC(dc);
ReleaseDC(0,dc);
SelectBitmap(dcDblBuf,bmDblBuf);
}
fntBig=MakeFont(x/30,MulDiv(y,2,8),0,FONTNAME);
xx=x/5;
yy=30;
fntSmall=MakeFont(MulDiv(xx,10,256),yy,0,FONTNAME);
}
void TBL::Make() {
RECT r;
GetClientRect(w,&r);
Make(r.right-r.left,r.bottom-r.top);
}
/*******************
* Hilfsfunktionen *
*******************/
#if 0
// blockierende Datenabfrage bis "EOF" (Seite 136)
// liefert "Anzahl Bytes", oder negative Zahl für Fehlerkode
int Query(char*d, int dlen) {
int expectblock=0;
int len=0;
static const char s[4]={0x1B,'O','\r','\n'};
for(;;){
char r[42]; // maximal 1+6+16*2+1+2 = 42 Bytes
int l=SendRecv(s,4,r,sizeof(r));
if (l<0) return l;
int a;
int e=string_decode(r,l,&a,d,dlen);
if (e<0) return e; // mit Fehler aussteigen
if (!e && a==0x1000) return len; // EOF-Block: alles fertig zusammengesetzt
if (a!=expectblock) return -7; // Fehler bei "Adresse"
d+=e; len+=e;
dlen-=e; // verbleibender Platz
expectblock++;
if (dlen<0) {
static const char s[4]={0x1B,'A','\r','\n'}; // vorzeitig abbrechen!
SendRecv(s,4);
return len;
}
}
}
LONG_PTR CALLBACK UnusedProc(HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam) {
switch (Msg) {
case WM_INITDIALOG: {
SetDlgItemTextA(Wnd,10,"\\eA\\r\\n");
}return TRUE;
case WM_COMMAND: switch (LOWORD(wParam)) {
case 1: {
char t[20];
GetDlgItemTextA(Wnd,10,t,elemof(t));
char u[20];
int l=unescape(u,t);
char r[44];
l=SendRecv(u,l,r,sizeof(r));
char j[280];
escape(j,r,l);
SetDlgItemTextA(Wnd,11,j);
// l=stringdecode(j,r,l);
if (l>=0) {
if (j[0] != (l-3)<<1) {l=-6; goto fehler;}
hexlisting(r,j+1,l-1);
SetDlgItemTextA(Wnd,12,r);
// Für ESC m 1 CR LF : (Seite 170)
if (j[2]!=0x10) {
char z[160];
numberdecode(z,j+3);
lstrcatA(z," V");
SetDlgItemTextA(Wnd,15,z);
numberdecode(z,j+6);
lstrcatA(z," A");
SetDlgItemTextA(Wnd,16,z);
numberdecode(z,j+9);
lstrcatA(z," kW");
SetDlgItemTextA(Wnd,17,z);
numberdecode(z,j+12,-3);
lstrcatA(z," °");
SetDlgItemTextA(Wnd,18,z);
}
}else fehler: SetDlgItemTextA(Wnd,12,NULL);
SetDlgItemInt(Wnd,14,l,TRUE);
}break;
case 2: EndDialog(Wnd,wParam); break;
case 5: {
char b[800];
HCURSOR oc=SetCursor(LoadCursor(0,IDC_WAIT));
DWORD tic=GetTickCount();
char t[20];
GetDlgItemTextA(Wnd,10,t,elemof(t));
char u[20];
int l=unescape(u,t);
char r[44];
l=SendRecv(u,l,r,sizeof(r));
char j[280];
escape(j,r,l);
SetDlgItemTextA(Wnd,11,j);
l=Query(b,sizeof(b));
tic=GetTickCount()-tic;
SetCursor(oc);
SetDlgItemInt(Wnd,14,l,TRUE);
wsprintfA(t,"%u ms",tic);
SetDlgItemTextA(Wnd,11,t);
if (l>=0) {
if (l>256) l=256;
char r[1000];
hexlisting(r,b,l);
SetDlgItemTextA(Wnd,12,r);
}
}break;
}
}
return FALSE;
}
#endif
static void FillBack(HDC dc, int x1, int y1, int x2, int y2) {
TRIVERTEX vert[]={
{x1,y1,0xe000,0xe000,0xe000},
{x1,y2,0xf000,0xf000,0xf000},
{x2,y2,0xff00,0xff00,0xff00},
{x2,y1,0xf000,0xf000,0xf000}};
GRADIENT_TRIANGLE Tri[]={
{0,1,2},
{0,2,3}};
GradientFill(dc,vert,elemof(vert),Tri,elemof(Tri),GRADIENT_FILL_TRIANGLE);
}
struct CELL{
unsigned colspan,rowspan;
struct HANDLERSTRUCT{
unsigned Msg; // notification message (must not changed by callee!)
unsigned x,y; // position of cell in the table
unsigned flags; // undefined; item states (e.g. highlighted for mouse hover)
HDC dc; // device context for MEASUREITEM and DRAWITEM
RECT r; // size (right/bottom) for MEASUREITEM, container for DRAWITEM
};
void (CELL::*Handler)(HANDLERSTRUCT*hs); // a "self-made virtual" function pointer - eases iteration dramatically
// virtual void Measure(HDC,SIZE*)=0;
// virtual void Paint(HDC,RECT*)=0;
void Iterator(HANDLERSTRUCT*hs) {
if (hs->Msg==WM_DESTROY) LocalFree(this);
};
inline void fill(unsigned cspan, unsigned rspan) {
colspan=cspan;
rowspan=rspan;
Handler=Iterator;
HANDLERSTRUCT hs;
hs.Msg=WM_CREATE;
(this->*Handler)(&hs);
}
static CELL*init(unsigned cspan=1,unsigned rspan=1,size_t sizeofobject=sizeof(CELL)) {
CELL*r=(CELL*)LocalAlloc(LPTR,sizeofobject);
if (r) r->fill(cspan,rspan);
return r;
};
};
struct SPAN{ // handles COLSPAN and ROWSPAN
unsigned n; // number of columns/rows of the table
unsigned changed; // changed (i.e. expanded) item?
unsigned*w; // triangular widths array (TODO: The first <n> items contain widths for each single column)
static unsigned BF(unsigned x) {return x*(x+1)/2;}; // Binomic Formula
void init(unsigned x) {w=(unsigned*)LocalAlloc(LPTR,BF(n=x)*sizeof(unsigned));};
void done() const{LocalFree(w);};
unsigned&PW(unsigned x, unsigned spanx=1) const{
// possible bugs:
if (x>=n) x=n-1;
if (x+spanx>n) spanx=n-x;
if (!spanx) spanx=1;
// calculate index
return w[(BF(n+1-spanx)-1)+x];
};
void setmax(unsigned x, unsigned spanx, unsigned w) {
unsigned&pw=PW(x,spanx);
if (pw<w) {pw=w; changed++;}
};
unsigned get(unsigned x, unsigned spanx=1) const{return PW(x,spanx);};
inline operator[] (unsigned x) const {return get(x);};
// Except that each terminal child has correct size, expands all spanning parents up to start+span
unsigned expandspans(unsigned start, unsigned span) {
unsigned wmax=0;
for (unsigned span2=1; span2<span; span2++) {
unsigned w=expandspans(start,span2); // should evaluate to the same value!!
+expandspans(start+span2,span-span2);
if (wmax<w) wmax=w;
}
if (wmax) setmax(start,span,wmax);
return get(start,span);
};
// Except that each parent has a correct size, it expands size of terminal childs
void expandchilds(unsigned start, unsigned span, unsigned w) {
setmax(start,span,w);
if (span>1) {
unsigned span2=span/2; // roughly the middle
unsigned wl,wr; // widths left and right
wl=get(start,span2);
wr=get(start+span2,span-span2);
wl=MulDiv(wl,w,wl+wr); // new left width
expandchilds(start,span2,wl);
expandspans(start,span2);
expandchilds(start+span2,span-span2,w-wl);
expandspans(start+span2,span-span2);
}
};
void adjust() { // This routine expands all spans and partial widths, if necessary
unsigned savechanged;
do{
savechanged=changed;
expandspans(0,n);
expandchilds(0,n,get(0,n));
}while (savechanged!=changed);
}
};
#pragma warning(disable:4200)
// simple table with fixed sizes (cols, rows) at initialization,
// however, cells are class pointers, NULL pointers are empty cells
struct TABLE{
SPAN cols; // columns (x extent and widths array)
SPAN rows; // rows (y extent and heights array)
CELL *td[];
// Get the place where the pointer to cell is located (for LocalAlloc, LocalReAlloc etc.)
CELL **pcell(unsigned x, unsigned y) {
#ifdef _DEBUG
if (x>=cols.n || y>=rows.n) {
OutputDebugStringA("TABLE::pcell(): index not valid\r\n");
return NULL;
}
#endif
return td+y*rows.n+x;
};
// Get the pointer to the cell
CELL *cell(int x, int y) const{
#ifdef _DEBUG
CELL**p=((TABLE*)this)->pcell(x,y); // The typecast removes the "const"
if (!p) return NULL;
return *p;
#else
return *pcell(x,y);
#endif
};
// Initalize a table structure
static TABLE* init(unsigned x,unsigned y) {
unsigned c=x*y;
TABLE*r=(TABLE*)LocalAlloc(LPTR,sizeof(TABLE)+c*sizeof(CELL*));
#ifdef _DEBUG
if (!r) OutputDebugStringA("TABLE::init(): alloc failed\r\n");
#endif
if (r) {
// r->cols.init(x);
// r->rows.init(y);
}
return r;
};
// Iterate through all cells in x-then-y order and call a function
// with the place where the pointer to cell is located (for LocalAlloc, LocalReAllc)
// void iterate(void(*f)(CELL**,CELL::HANDLERSTRUCT*),CELL::HANDLERSTRUCT*hs) {
// CELL **c=td;
// for (hs->y=0; hs->y<rows.n; hs->y++) {
// for (hs->x=0; hs->x<cols.n; hs->x++) {
// f(c,hs);
// c++;
// }
// }
// }
// static void callHandler(CELL**c,CELL::HANDLERSTRUCT*hs) {
// if (*c) (*c)->*Handler(hs);
// };
// Iterate through all cells in x-then-y order and call then Handler member function pointer,
// skipping empty (NULL) cells.
// Spanned (hidden) cells are not skipped, so take care to create spans consistently!
void iterate(CELL::HANDLERSTRUCT*hs) const{
CELL *const*c=td;
for (hs->y=0; hs->y<rows.n; hs->y++) {
for (hs->x=0; hs->x<cols.n; hs->x++) {
CELL *p;
if (p=*c) {
(p->*p->Handler)(hs);
}
c++;
}
}
// ((TABLE*)this)->iterate(callHandler,hs);
};
// Destructor for the whole table, calls destructors of the cells
void done() const{
CELL::HANDLERSTRUCT hs;
hs.Msg=WM_DESTROY;
iterate(&hs);
LocalFree((void*)this);
};
unsigned Measure(HDC dc, SIZE*sz) { // takes size, returns needed size of entire table
CELL *const*cp=td;
CELL::HANDLERSTRUCT hs;
hs.Msg=WM_PAINT;
hs.flags=0;
hs.dc=dc;
for (hs.y=0; hs.y<rows.n; hs.y++) {
for (hs.x=0; hs.x<cols.n; hs.x++) {
CELL *c=(*cp);
if (c) {
SetRect(&hs.r,0,0,0,0);
(c->*c->Handler)(&hs); // cryptic, yeah!
cols.setmax(hs.x,c->colspan,hs.r.right-hs.r.left);
rows.setmax(hs.y,c->rowspan,hs.r.bottom-hs.r.top);
}
cp++;
}
}
cols.adjust();
rows.adjust();
sz->cx=cols.get(0,cols.n);
sz->cy=rows.get(0,rows.n);
return cols.changed|rows.changed;
};
void Paint(HDC dc, const RECT*rc=0) const{
CELL *const*cp=td;
CELL::HANDLERSTRUCT hs;
hs.Msg=WM_PAINT;
hs.flags=0;
hs.dc=dc;
int yy=0; // running y pixels
for (hs.y=0; hs.y<rows.n; hs.y++) {
int xx=0; // running x pixels
for (hs.x=0; hs.x<cols.n; hs.x++) {
CELL *c=(*cp);
if (c) { // cells hidden by colspan or rowspan MUST be NULL
SetRect(&hs.r,xx,yy,xx+cols.get(hs.x,c->colspan),yy+rows.get(hs.y,c->rowspan));
RECT r;
if (!rc || IntersectRect(&r,&hs.r,rc)) (c->*c->Handler)(&hs);
}
xx+=cols[hs.x];
cp++;
}
yy+=rows[hs.y];
}
};
};
void TestTable() {
TABLE *T=TABLE::init(2,2);
unsigned x,y;
CELL **C;
for (y=0; y<T->rows.n; y++) {
for (x=0; x<T->cols.n; x++) {
*C=CELL::init();
C++;
}
}
T->done();
}
struct TH{ // table header cell item
UINT sid; // string resource index for text display
LONG_PTR par; // one free parameter for sprintf()
char dde2[4]; // second part of DDE name (e.g. "-1")
};
struct TD{ // table body cell item
double val,min,max; // data for DDE
char str[10]; // text for display, not localized (contains "." decimal point)
char unitprefix; // 0-based exponent of 10
char colspan; // colspan, 0 = unused column!
};
union COL{
TH th; // first row
TD td; // non-first rows
};
struct TR{
UINT sid; // string resource index for descriptive text display
LONG_PTR par; // one free parameter for sprintf()
UINT nid; // string resource index for name display
char name[7]; // alternative name, as UTF-8 (unused)
char ndeco; // name decoration flags: average, peak
char dde1[8]; // first part of DDE name (e.g. "Up" for U-peak), 7-bit ASCII only
BYTE ncol; // number of columns following, 0 = sub-divider ("Tariff Band")
char unitcode; // the unit code for common units, appended to each(?) <td> item
char unit[8]; // the unit for uncommon units, as UTF-8 (unused)
COL col[];
};
static PWSTR GenUnitW(PWSTR d, char unitprefix, char unitcode, char f) {
return d;
}
// obige Tabellenstruktur ausgeben
static void OutTable(HDC dc, TR*tr, int n){
// 0. Check whether table is valid
if (!tr || n<2) return;
int xx=tr[0].ncol; // the header dictates the number of possible columns
if (!xx) return; // no data column
// 1. Check for needed column widths
SPAN w;
w.init(xx+2);
for (int y=0; y<n; y++) {
TR*tr=tr+y; // TODO: Not so easy!
WCHAR t[32],s[32];
MyLoadStringW(tr->sid,t,elemof(t));
int l=wnsprintfW(s,elemof(s),t,tr->par);
SIZE size;
GetTextExtentPoint32W(dc,s,l,&size);
w.setmax(0,1,size.cx); // build maximum
l=MyLoadStringW(tr->sid,t,elemof(t));
GetTextExtentPoint32W(dc,t,l,&size);
w.setmax(1,1,size.cx); // build maximum
for (int x=0; x<tr->ncol; x++) {
if (x==xx) break; // it's a bug in given table structure
COL*col=tr->col+x;
if (y) {
MyLoadStringW(col->th.sid,t,elemof(t));
l=wnsprintfW(s,elemof(s),t,col->th.par);
}else{
l=wnsprintfW(s,elemof(s),L"%S",col->td.str);
l=GenUnitW(s+l,col->td.unitprefix,tr->unitcode,1)-s;
}
GetTextExtentPoint32W(dc,s,l,&size);
w.setmax(2+x,col->td.colspan,size.cx); // build maximum
}
}
// 2. Emit the table
}
void TBL::OutLine(HDC dc, UINT id, double f[], int n) {
POINT p; // origin
MoveToEx(dc,0,0,&p);
WCHAR s[128];
FillBack(dc,p.x,p.y,p.x+xx,p.y+yy);
int l=MyLoadStringW(id,s,elemof(s));
TextOutW(dc,p.x+1,p.y,s,l);
if (n==12) {
for (int i=0,k=0; i<4; i++) {
l=toStringW(f[k++],s,elemof(s));
StrCpyNW(s+l,L" / ",elemof(s)-l); l+=3;
l+=toStringW(f[k++],s+l,elemof(s)-l);
StrCpyNW(s+l,L" / ",elemof(s)-l); l+=3;
l+=toStringW(f[k++],s+l,elemof(s)-l);
FillBack(dc,p.x+xx*(i+1),p.y,p.x+xx*(i+2),p.y+yy);
TextOutW(dc,p.x+xx*(i+1)+1,p.y,s,l);
}
}else{
for (int i=0; i<4; i++) {
l=toStringW(f[i],s,elemof(s));
FillBack(dc,p.x+xx*(i+1),p.y,p.x+xx*(i+2),p.y+yy);
TextOutW(dc,p.x+xx*(i+1)+1,p.y,s,l);
}
}
MoveToEx(dc,p.x,p.y+yy,NULL); // next line
}
void TBL::OutLine(HDC dc, UINT id, VAL3 v[4]) {
double f[4];
for (int i=0; i<4; i++) f[i]=v[i].toFloat();
OutLine(dc,id,f,4);
}
void TBL::OutLine(HDC dc, UINT id, VAL3 v[4], VAL3 a[4], VAL3 p[4]) {
double f[12];
for (int i=0,k=0; i<4; i++) {
f[k++]=v[i].toFloat();
f[k++]=a[i].toFloat();
f[k++]=p[i].toFloat();
}
OutLine(dc,id,f,12);
}
void TBL::OutLine(HDC dc, UINT id, VAL2 v[4], char e) {
double f[4];
for (int i=0; i<4; i++) f[i]=v[i].toFloat(e);
OutLine(dc,id,f,4);
}
static STRING_ESCM escm_data;
void TBL::HandlePaint(HDC dc,LPARAM options) {
RECT r;
GetClientRect(w,&r);
if (options&PRF_ERASEBKGND) {
HBRUSH brBack=GetSysColorBrush(COLOR_WINDOW);
SelectBrush(dc,brBack);
PatBlt(dc,0,0,r.right,r.bottom,PATCOPY);
}
// if (w.hMutex && WaitForSingleObject(w.hMutex,200)) return; // timeout - should never occur, SetData() is fast
// Value (with unit) sent by multimeter
// int slen;
// SIZE size;
// WCHAR buf[32];
HFONT ofont=SelectFont(dc,fntSmall);
SetBkMode(dc,TRANSPARENT);
OutLine(dc,19,escm_data.u);
OutLine(dc,18,escm_data.i);
OutLine(dc,20,escm_data.p,escm_data.pa,escm_data.pp);
OutLine(dc,21,escm_data.s,escm_data.sa,escm_data.sp);
OutLine(dc,22,escm_data.q,escm_data.qa,escm_data.qp);
OutLine(dc,24,escm_data.c,-3);
// if (w.hMutex) ReleaseMutex(w.hMutex);
SelectFont(dc,ofont);
}
/********************
* Window procedure *
********************/
static INT_PTR CALLBACK WndProc(HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam) {
TBL*tbl=(TBL*)GetWindowLongPtr(Wnd,0);
switch (Msg) {
case WM_NCCREATE: {
tbl=new TBL(Wnd);
SetWindowLongPtr(Wnd,0,(INT_PTR)tbl);
}break;
case WM_CREATE: {
TestTable();
}break;
case WM_USER+22: { // lParam = bits indicating what portion of information has changed
if (lParam) {
if (lParam&0xA8888) tbl->Make();
if (tbl->dcDblBuf) tbl->HandlePaint(tbl->dcDblBuf,PRF_ERASEBKGND);
InvalidateRect(Wnd,NULL,TRUE);
}
}break;
case WM_SIZE: {
tbl->Make(GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam));
if (tbl->dcDblBuf) tbl->HandlePaint(tbl->dcDblBuf,PRF_ERASEBKGND);
}break;
case WM_PAINT: {
PAINTSTRUCT ps;
BeginPaint(Wnd,&ps);
SendMessage(Wnd,WM_PRINTCLIENT,(WPARAM)ps.hdc,PRF_ERASEBKGND);
EndPaint(Wnd,&ps);
}return 0;
case WM_PRINTCLIENT: {
if (tbl->dcDblBuf) {
RECT r;
GetClientRect(Wnd,&r);
BitBlt((HDC)wParam,0,0,r.right,r.bottom,tbl->dcDblBuf,0,0,SRCCOPY);
}else tbl->HandlePaint((HDC)wParam,lParam);
}break;
case WM_NCDESTROY: {
delete tbl;
}break;
}
return DefWindowProc(Wnd,Msg,wParam,lParam);
}
ATOM RegisterWndTable() {
WNDCLASS wc={
CS_BYTEALIGNWINDOW|CS_DBLCLKS|CS_HREDRAW|CS_VREDRAW,
(WNDPROC)WndProc,
0,
sizeof(void*),
ghInst,
LoadIcon(ghInst,MAKEINTRESOURCE(1)),
LoadCursor(0,IDC_ARROW),
0,
0,
TABLE_CLASS};
return RegisterClass(&wc);
}
| Detected encoding: ANSI (CP1252) | 4
|
|
|