//#define OEMRESOURCE
#include "wutils.h"
#include "miniwnd.h"
#include "objekte.h"
#include <stdio.h>
// Ein Wald aus 3 Bäumen, nur Pseudoknoten
NODE Anker[3];
// Anker[0] = TOPMOST, Anker[1] = NORMAL, Anker[2] = HIDDEN
MINIWND *FocusOwner;
GITTER *gitter;
COLORREF MixColor(COLORREF c1, COLORREF c2, int f1=128);
/*********************************************
** Quasi-globale Variablen für Hintergrund **
*********************************************/
COLORREF GridColor;
POINT step; // Gitternetz-Schrittweite
POINT tick;
POINT Kaestel={10,8};
POINT SubTick={5,5};
POINT bmext; // (nicht mehr!!) Bitmap-Größe
RECT Rand; // Gitternetz-Rand (im Client-Bereich)
POINT Mitte;
COLORREF BackColor;
HPEN XorPen;
HBITMAP blt[2]={(HBITMAP)TRUE,(HBITMAP)TRUE};
HBITMAP NullBitmap[2];
POINT lastmouse; // Fadenkreuz-Position
HDC bltdc[2];
HPEN BackPen;
HPEN GridPen;
HBRUSH BackBrush;
COLORREF AuswahlFarbe;
HBRUSH AuswahlPinsel; // für <fokussierte>? Elemente
POINT ClientExt; // auch Größe der beiden Hintergrund-Bitmaps
UINT DispOpt; // Anzeige- und Gitter-Optionen (=0)
void Gitternetz(HDC dc) {
int x,y;
HPEN OldPen;
OldPen=(HPEN)SelectObject(dc,GridPen);
if (step.x>1) for(x=Rand.left; x<Rand.right; x+=step.x) //waagerecht
Line(dc,x,Rand.top,x,Rand.bottom);
if (step.y>1) for(y=Rand.top; y<Rand.bottom; y+=step.y) //senkrecht
Line(dc,Rand.left,y,Rand.right,y);
if (DispOpt & DO_TICK) {
int from,to,j;
if (tick.x>1) {
j=(tick.y+1)>>1; if (!j) j++; // mindestens 1 sichtbares Pixel
from=Mitte.y-j;
to=Mitte.y+j+1; // Line() selbst lässt das letzte Pixel weg
for (x=Rand.left; x<Rand.right; x+=tick.x)
if ((x-Mitte.x)%step.x) Line(dc,x,from,x,to);
}
if (tick.y>1) {
j=(tick.x+1)>>1; if (!j) j++;
from=Mitte.x-j;
to=Mitte.x+j+1;
for (y=Rand.top; y<Rand.bottom; y+=tick.y)
if ((y-Mitte.y)%step.y) Line(dc,from,y,to,y);
}
}
SelectObject(dc,OldPen);
}
void SetDispOpt(UINT ADispOpt, UINT force) {
//Display-Options-Bits setzen, ggf. weitere Datenstrukturen anlegen bzw. entfernen
force|=DispOpt^ADispOpt;
if (force&DO_GRID) {
if (DispOpt&DO_GRID) DeleteObject(GridPen);
if (ADispOpt&DO_GRID) {
GridPen=CreatePen(PS_SOLID,0,GridColor);
if (!GridPen) ADispOpt&=~DO_GRID;
}
}
if (force&DO_TB) {
if (DispOpt&DO_TB) {
SelectObject(bltdc[1],NullBitmap[1]);
DeleteObject(blt[1]);
DeleteDC(bltdc[1]);
}
if (ADispOpt&DO_TB) {
HDC dc=GetDC(MainWnd);
bltdc[1]=CreateCompatibleDC(dc);
blt[1]=CreateCompatibleBitmap(dc,ClientExt.x,ClientExt.y);
NullBitmap[1]=(HBITMAP)SelectObject(bltdc[1],blt[1]);
ReleaseDC(MainWnd,dc);
if (blt[1]) ADispOpt|=DO_TB_INVAL;
else ADispOpt&=~DO_TB;
}
}
if (force&DO_DB) {
if (DispOpt&DO_DB) {
SelectObject(bltdc[0],NullBitmap[0]);
DeleteObject(blt[0]);
DeleteDC(bltdc[0]);
}
if (ADispOpt&DO_DB) {
HDC dc=GetDC(MainWnd);
bltdc[0]=CreateCompatibleDC(dc);
blt[0]=CreateCompatibleBitmap(dc,ClientExt.x,ClientExt.y);
NullBitmap[0]=(HBITMAP)SelectObject(bltdc[0],blt[0]);
ReleaseDC(MainWnd,dc);
if (blt[0]) ADispOpt|=DO_DB_INVAL; // Eigentlich Rechteck oder Region,
else ADispOpt&=~DO_DB; // aber das wird zu kompliziert...
}
}
if (force&DO_CROSS) {
if (DispOpt&DO_CROSS) DeleteObject(XorPen);
if (ADispOpt&DO_CROSS) XorPen=CreatePen(PS_SOLID,0,0x404040L); // unauffällig
}
if (force&DO_BACK) {
if (DispOpt&DO_BACK) {
DeletePen(BackPen);
DeleteBrush(AuswahlPinsel);
DeleteBrush(BackBrush);
}
if (ADispOpt&DO_BACK) {
BackBrush=CreateSolidBrush(BackColor);
AuswahlFarbe=MixColor(GetSysColor(COLOR_HIGHLIGHT),BackColor);
AuswahlPinsel=CreateSolidBrush(AuswahlFarbe);
BackPen=CreatePen(PS_SOLID,0,BackColor);
}
}
if (force&(DO_LINE|DO_TICK)) Inval(true);
DispOpt=ADispOpt;
}
void wmSize(int x, int y) { // Behandlung von WM_SIZE
ClientExt.x=x;
ClientExt.y=y;
tick.x=(ClientExt.x-1)/Kaestel.x/SubTick.x;
tick.y=(ClientExt.y-1)/Kaestel.y/SubTick.y;
step.x=tick.x*SubTick.x;
step.y=tick.y*SubTick.y;
bmext.x=step.x*Kaestel.x+1;
bmext.y=step.y*Kaestel.y+1;
SetRect(&Rand,0,0,bmext.x,bmext.y);
OffsetRect(&Rand,(ClientExt.x-bmext.x)/2,
(ClientExt.y-bmext.y)/2);
Mitte.x=(Rand.left+Rand.right)>>1;
Mitte.y=(Rand.top+Rand.bottom)>>1;
Inval(true);
}
void Fadenkreuz(HDC dc) {
int OldROP;
HPEN OldPen;
if ((unsigned)lastmouse.x<(unsigned)ClientExt.x
&& (unsigned)lastmouse.y<(unsigned)ClientExt.y) {
OldROP=SetROP2(dc,R2_XORPEN);
OldPen=SelectPen(dc,XorPen);
Line(dc,0,lastmouse.y,ClientExt.x,lastmouse.y);
Line(dc,lastmouse.x,0,lastmouse.x,ClientExt.y);
SelectPen(dc,OldPen);
SetROP2(dc,OldROP);
}
}
void MaleHinterGraf(HDC dc) {
HBRUSH br=SelectBrush(dc,BackBrush);
PatBlt(dc,0,0,ClientExt.x,ClientExt.y,PATCOPY);
SelectBrush(dc,br);
// if (DispOpt&DO_GRID) Gitternetz(dc);
if (Anker[1].sub) Anker[1].sub->Paint(dc);
}
void MaleGraf(HDC dc) {
int i;
for (i=0; i<numkanal; i++) kanal[i].MaleKurve(dc);
// for (i=0; i<numkanal; i++) kanal[i].RelayMsg(M_PAINT,(WPARAM)dc,0);
if (DispOpt&DO_CROSS) Fadenkreuz(dc);
// XAdjust_Paint(dc,&xadjust);
if (Anker[0].sub) Anker[0].sub->Paint(dc);
}
void BltAlles(HDC dc) {
// Hintergrundraster und -Elemente einkopieren, ggf. malen lassen
if (DispOpt&DO_TB) {
if (DispOpt&DO_TB_INVAL) { // TB_INVAL muss auch immer DB_INVAL hinter sich ziehen!
MaleHinterGraf(bltdc[1]); // hintenliegende Elemente
DispOpt&=~DO_TB_INVAL;
}
BitBlt(dc,0,0,ClientExt.x,ClientExt.y,bltdc[1],0,0,SRCCOPY);
}else MaleHinterGraf(dc);
// Vordergrund-Graf und -Elemente darüber malen lassen
MaleGraf(dc); // Kurvenzug und vornliegende Elemente
}
void _stdcall ShowPopupMenu(HMENU m, int x, int y) {
ClientToScreen(MainWnd,(LPPOINT)&x);
TrackPopupMenu(m,TPM_LEFTALIGN|TPM_RIGHTBUTTON,x,y,0,MainWnd,NULL);
}
/*************************************************************
** Knoten und Mini-Fenster (als Basis für weitere Fenster) **
*************************************************************/
KNOTEN::~KNOTEN() {
while(sub) delete sub; remove();
}
void KNOTEN::SetParent(NODE*p) {
// Knoten einfügen, als erstes Kind von <p>!
// Verändert einen evtl. vorhandenen Unterbaum nicht!!
remove(); // Falls noch eingehängt
next=p->sub; p->sub=this; // Neues erstes Kind
if (next) next->prev=this; // Neuer Vorgänger für Nachfolger
prev=NULL; // Kein eigener Vorgänger
parent=p;
}
void KNOTEN::SetSibling(KNOTEN*b) {
// Knoten einfügen, ENTWEDER als erstes Kind von <p> ODER vor <b>!
// Verändert einen evtl. vorhandenen Unterbaum nicht!!
remove(); // falls noch eingehängt
next=b;
prev=b->prev; b->prev=this;
if (prev) prev->next=this;
parent=b->parent; // gleiches Elter
}
void KNOTEN::remove() {
// Knoten aushängen; Kinder bleiben hängen!
if (!parent) return; // <>0 wenn überhaupt eingehängt
if (prev) {prev->next=next; prev=NULL;}
else parent->sub=next;
if (next) {next->prev=prev; next=NULL;}
parent=NULL;
}
void KNOTEN::Paint(HDC dc) { // von unten nach oben
if (next) next->Paint(dc);
if (sub) sub ->Paint(dc);
}
bool KNOTEN::RelayMsg(UINT Msg, WPARAM wParam, LPARAM lParam) {
return bool( // von oben nach unten
sub && sub ->RelayMsg(Msg,wParam,lParam)
|| next && next->RelayMsg(Msg,wParam,lParam));
}
#if 0
void MINIWND::ToolMessage(UINT Msg) {
TOOLINFO ti;
InitStruct(&ti,sizeof(ti));
ti.hwnd=::MainWnd;
ti.uId=id;
CopyRect(&ti.rect,&rcitem);
ti.hinst=::HInstance;
ti.lpszText=(PTSTR)hint;
SendMessage(::Tooltip,Msg,0,(LPARAM)(LPTOOLINFO)&ti);
#else
void MINIWND::ToolMessage(UINT) {
#endif
Inval();
}
MINIWND::MINIWND(NODE*p):KNOTEN(p) {
SetRect(&rcitem,0,0,1,1);
hint=NULL;
id=0;
style=0;
ToolMessage(TTM_ADDTOOL);
state=0;
}
MINIWND::MINIWND(NODE*p,RECT*r,LPCTSTR h,UINT i, BYTE st):KNOTEN(p) {
CopyRect(&rcitem,r);
hint=h;
id=i;
style=st;
ToolMessage(TTM_ADDTOOL);
state=0;
}
void MINIWND::SetParent(NODE*p) {
KNOTEN::SetParent(p);
Inval();
}
void MINIWND::Schieb(int dx,int dy,bool MitMaus) {
if (!(dx|dy)) return;
Inval();
if (state&0x20 && MitMaus) { // Maus verschieben
POINT pt;
GetCursorPos(&pt);
pt.x+=dx; pt.y+=dy;
SetCursorPos(pt.x,pt.y);
}
OffsetRect(&rcitem,dx,dy);
Moved();
}
void MINIWND::SetState(BYTE st) {
if (state==st) return;
state=st;
Inval();
}
void MINIWND::SetState(BYTE and, BYTE xor) {
SetState((state&and)^xor);
}
void MINIWND::Paint(HDC dc) {
KNOTEN::Paint(dc);
if (state&STA_SELECTED) FillRect(dc,&rcitem,AuswahlPinsel);
if (FocusOwner==this) DrawFocusRect(dc,&rcitem);
}
bool MINIWND::RelayMsg(UINT Msg,WPARAM wParam,LPARAM lParam) {
switch (Msg) {
case WM_SYSCOLORCHANGE:
case WM_SIZE: return KNOTEN::RelayMsg(Msg,wParam,lParam);
case WM_MOUSELEAVE: SetState(~STA_HOVER,0); break; // immer HOVER aus!
case WM_NCHITTEST: {
SetState(~STA_HOVER, // Dieses HOVER-Bit ist "echtes" Hover.
PtInRectS(&rcitem,MAKEPOINTS(lParam))?STA_HOVER:0);
where=0; // im Innern
if ((unsigned)(GET_X_LPARAM(lParam)-rcitem.left)<4) where|=1; // links
if ((unsigned)(rcitem.right-GET_X_LPARAM(lParam))<5) where|=2; // rechts
if ((unsigned)(GET_Y_LPARAM(lParam)-rcitem.top)<4) where|=4; // oben
if ((unsigned)(rcitem.bottom-GET_Y_LPARAM(lParam))<5)where|=8; // unten
}break;
case WM_SETCURSOR: {
LPCTSTR curs=IDC_ARROW;
if (style&1) curs=IDC_SIZEWE; // Inneres
if (style&2) curs=IDC_SIZENS;
if (!(~style&3)) curs=IDC_SIZEALL;
if (style&4 && where&3) curs=IDC_SIZEWE; // Ränder
if (style&8 && where&12) curs=IDC_SIZENS;
if (!(~style&12)) {
if (!(~where&5) || !(~where&10)) curs=IDC_SIZENWSE; // Ecken
if (!(~where&6) || !(~where&9)) curs=IDC_SIZENESW;
}
SetCursor(LoadCursor(0,curs));
}break;
case WM_LBUTTONDOWN: {
FocusOwner=this;
Inval();
}nobreak;
case WM_LBUTTONDBLCLK:
case WM_MBUTTONDOWN:
case WM_MBUTTONDBLCLK:
case WM_RBUTTONDOWN:
case WM_RBUTTONDBLCLK: {
if (state&1) return true; // andere Maustaste schon gedrückt
if (state&2) return true; // disabled
state|=0x11; // Maustaste gedrückt setzen
drag=MAKEPOINTS(lParam); // Anklickposition (absolut) merken
}return true;
case WM_LBUTTONUP:
case WM_MBUTTONUP:
case WM_RBUTTONUP: state&=~0x11; return true;
case WM_MOUSEMOVE: {
if (!(state&0x01)) return true; // Gedrückter Zustand?
if (!(style&15)) return true;
Inval();
drag.x=(short)(GET_X_LPARAM(lParam)-drag.x); // Schlepp-Entfernung seit letztem Ereignis
drag.y=(short)(GET_Y_LPARAM(lParam)-drag.y);
if (style&4 && where&3) { // Rand (=Größe) ändern
if (where&1) rcitem.left+=drag.x;
if (where&2) rcitem.right+=drag.x;
}else if (style&1) OffsetRect(&rcitem,drag.x,0); // verschieben
if (style&8 && where&12) { // Rand
if (where&4) rcitem.top+=drag.y;
if (where&8) rcitem.bottom+=drag.y;
}else if (style&2) OffsetRect(&rcitem,0,drag.y);
drag=MAKEPOINTS(lParam);
Moved();
}return true;
}
return true;
}
// Zur Zustellung von Mausereignissen sowie WM_MOUSEHOVER/WM_MOUSELEAVE
// (wenn keine Taste gedrückt bzw. sobald sie außerhalb losgelassen wurde)
// Für WM_MOUSEFIRST..WM_MOUSELAST, WM_NCHITTEST, WM_SETCURSOR
MINIWND* _stdcall MINIWND::MiniWndFromPoint(POINTS ps) {
for (int i=0; i<2; i++) { // Unsichtbare nicht eingerechnet
for (MINIWND *p=(MINIWND*)Anker[i].sub; p; p=(MINIWND*)p->next) {
for (MINIWND *q=(MINIWND*)p->sub; q; q=(MINIWND*)q->next) {
if (PtInRectS(&q->rcitem,ps)) return q; // sieht blöd aus!
}
if (PtInRectS(&p->rcitem,ps)) return p;
}
}
return NULL;
}
COLORREF GetWinIniColor(PCTSTR key, COLORREF c) {
TCHAR s[32];
int rgb[3];
#define cb ((PBYTE)&c)
rgb[0]=cb[0];
rgb[1]=cb[1];
rgb[2]=cb[2];
wvsprintf(s,T("%i %i %i"),(va_list)rgb);
GetProfileString(T("colors"),key,s,s,elemof(s));
_stscanf(s,T("%i %i %i"),rgb+0,rgb+1,rgb+2);
cb[0]=(BYTE)rgb[0];
cb[1]=(BYTE)rgb[1];
cb[2]=(BYTE)rgb[2];
#undef cb
return c;
}
// TOOLTIP: Zu tun: Bei Verlassen des Client-Bereiches Tooltips verschwinden lassen!
TOOLTIP::TOOLTIP():MINIWND(&Anker[2]) {
GdiObj=0;
CreateGdiObj();
}
TOOLTIP::~TOOLTIP() {
DeleteGdiObj();
}
void TOOLTIP::DeleteGdiObj() {
if (Back && GdiObj&1) DeleteBrush(Back);
if (Pen && GdiObj&2) DeletePen (Pen);
if (Font && GdiObj&4) DeleteFont (Font);
GdiObj=0;
}
void TOOLTIP::CreateGdiObj() {
#ifdef WIN32
TextColor=GetSysColor(COLOR_INFOTEXT);
#else
TextColor=GetWinIniColor(T("InfoText"),0x000000L);
#endif
if (TextColor) {
Pen=CreatePen(PS_SOLID,0,TextColor);
GdiObj|=1;
}else Pen=GetStockPen(BLACK_PEN);
#ifdef WIN32
BackColor=GetSysColor(COLOR_INFOBK);
#else
BackColor=GetWinIniColor(T("InfoWindow"),0xE1FFFFL);
#endif
HDC dc=GetDC(MainWnd);
BackColor=GetNearestColor(dc,BackColor);
ReleaseDC(MainWnd,dc);
Back=CreateSolidBrush(BackColor);
GdiObj|=2;
#ifdef WIN32
Font=GetStockFont(DEFAULT_GUI_FONT);
#else
Font=CreateFont(-8,0,0,0,0,0,0,0,0,0,0,0,0,T("Helv"));
GdiObj|=4;
#endif
}
void TOOLTIP::Paint(HDC dc) {
RECT r;
CopyRect(&r,&rcitem);
SelectPen(dc,Pen);
SelectBrush(dc,Back);
RoundRect(dc,r.left,r.top,r.right,r.bottom,8,8);
InsetRect(&r,4,4);
SetTextColor(dc,TextColor);
SetBkColor(dc,BackColor);
SelectFont(dc,Font);
DrawText(dc,hintbuf,-1,&r,DT_WORDBREAK);
}
void _cdecl TOOLTIP::SetTip(PCRECT nohide,LPCTSTR tip,...) {
if (HIWORD(tip) && IsBadStringPtr(tip,64)) tip=NULL;
SetTimer(MainWnd,222,5000,NULL); // Zum Verschwinden lassen
// hint=tip;
SetParent(tip?Anker+0:Anker+2); // vorne - oder verstecken
if (!tip) return;
if (!HIWORD(tip)) {
TCHAR s[256];
LoadString(HInstance,(UINT)tip,s,elemof(s));
tip=s;
}
// Inval();
TCHAR s[256];
wvsprintf(s,tip,(va_list)(&tip+1));
if (!lstrcmp(s,hintbuf)) return; // keine String-Änderung
lstrcpy(hintbuf,s);
HDC dc=GetDC(MainWnd);
POINT pt;
GetCursorPos(&pt);
ScreenToClient(MainWnd,&pt);
pt.y+=20; // respektvoller Abstand
SetRect(&rcitem,pt.x,pt.y,pt.x,pt.y);
SelectFont(dc,Font);
DrawText(dc,hintbuf,-1,&rcitem,DT_CALCRECT);
ReleaseDC(MainWnd,dc);
InflateRect(&rcitem,4,4); // Rand dazu
RECT R2;
SetRect(&R2,0,0,ClientExt.x,ClientExt.y);
MoveRectIntoRect(&rcitem,&R2); // Innen halten
if (nohide)
MoveRectNoIntersect(&rcitem,nohide,&R2);
Inval();
}
bool TOOLTIP::RelayMsg(UINT Msg, WPARAM wParam, LPARAM lParam) {
switch (Msg) {
case WM_SYSCOLORCHANGE: DeleteGdiObj(); CreateGdiObj(); break;
case WM_TIMER: if (wParam==222) { /*killtip:*/
KillTimer(MainWnd,wParam);
SetParent(Anker+2);
// SetTip(NULL,NULL);
}break;
// case WM_MOUSEMOVE: goto killtip;
}
return MINIWND::RelayMsg(Msg,wParam,lParam);
}
GITTER::GITTER():MINIWND(&Anker[1],&Rand,T("Gitternetz"),0,12) {};
bool GITTER::RelayMsg(UINT Msg, WPARAM wParam, LPARAM lParam) {
MINIWND::RelayMsg(Msg,wParam,lParam);
if (Msg==WM_MOUSEMOVE && state&STA_HOVER) tip->SetTip(NULL,MAKEINTRESOURCE(22));
// Hier natütlich OHNE Flächenfreihaltung! (NULL)
return false;
}
/***************************************************
** MYBUTTON: Look and feel eines Windows-Knopfes **
***************************************************/
MYBUTTON::MYBUTTON(NODE*parent,RECT*rc,LPCTSTR hint,UINT id,EBild bmidx)
:MINIWND(parent,rc,hint,id,0) { // Parameter durchreichen
bild=bmidx;
}
void MYBUTTON::SetState(BYTE st) {
// diese Version ohne Beeinflussung von STA_HOVER
if (st&2) state&=~0x11;
MINIWND::SetState((BYTE)((state&0x20)|(st&~0x20)));
}
void MYBUTTON::Enable(BOOL en) {
SetState((BYTE)(en?state&~2:state|2));
}
typedef struct {signed char x,y;} BPOINT; // Byte-Punktkoordinate
static void PunktTrans(POINT *d, const BPOINT *s, BYTE bits,int num) {
do{
d->x=s->x; // unverändert kopieren
d->y=s->y;
if (bits&2) { // 90-°-Drehung im Uhrzeigersinn
d->y=d->x;
d->x=-s->y;
}
if (bits&4) { // 180-°-Drehung
d->x=-d->x;
d->y=-d->y;
}
d++; s++;
}while (--num);
}
static void _stdcall Line3(HDC dc,int x1,int y1,int x2,int y2,int x3,int y3,HPEN pen) {
SelectPen(dc,pen); // Nur für Lager-Objekte!
#ifdef _M_IX86
Polyline(dc,(LPPOINT)&x1,3);
#else
POINT p[3]={{x1,y1},{x2,y2},{x3,y3}};
Polyline(dc,p,3);
#endif
}
static void _stdcall Line3(HDC dc,int x1,int y1,int x2,int y2,int x3,int y3,COLORREF cr) {
HPEN pen=CreatePen(PS_SOLID,0,cr);
HPEN open=SelectPen(dc,pen);
#ifdef _M_IX86
Polyline(dc,(LPPOINT)&x1,3);
#else
POINT p[3]={{x1,y1},{x2,y2},{x3,y3}};
Polyline(dc,p,3);
#endif
SelectPen(dc,open);
DeletePen(pen);
}
/**************************************************************
** Ein Funktions-Array <PaintFunc> zur Bemalung der Buttons **
**************************************************************/
// Die Größe der Buttons könnte - oder sollte - sich noch ändern auf ca. 20 Pixel
static void _fastcall PaintTiefer(HDC dc, BYTE dreh) { // dreh=2 zur Rechtsdrehung
static const BPOINT poly1[]={{-5,-5},{5,-5},{-4,4},{4,4}}; // Entartetes Poly
POINT poly[elemof(poly1)];
PunktTrans(poly,poly1,dreh,elemof(poly1));
Polygon(dc,poly,elemof(poly));
}
static void _fastcall PaintHoeher(HDC dc, BYTE dreh) { // dreh=2 zur Drehung
static const BPOINT poly1[]={{-5,-1},{0,-6},{5,-1}, // Großes Dreieck hoch
{-4, 1},{4, 1},{0, 5}}; // Kleines Dreieck runter
POINT poly[elemof(poly1)];
PunktTrans(poly,poly1,dreh,elemof(poly1));
// static const int Ecken[]={3,3};
// PolyPolygon(dc,poly,Ecken,elemof(Ecken)); // Zwei Polygone
Polygon(dc,poly,3); // Bei Win16 ist PolyPolygon zu umständlich,
Polygon(dc,poly+3,3); // bei Win32 lt. MSDN "schaumgebremst".
}
static void PaintENGER (HDC dc) {PaintTiefer(dc,2);}
static void PaintWEITER(HDC dc) {PaintHoeher(dc,2);}
static void PaintTIEFER(HDC dc) {PaintTiefer(dc,0);}
static void PaintHOEHER(HDC dc) {PaintHoeher(dc,0);}
static void PaintEINAUS(HDC dc) {
Ellipse (dc,-4,-4,+6,+6); // "Netzschalter"-Beschriftung
Rectangle(dc,-1,-6,+3,+2);
}
static void PaintPLAY(HDC dc) { // "Play"-Dreieck
static const BPOINT poly1[]={{-4,-5},{-4,5},{5,0}}; // Dreieck
POINT poly[elemof(poly1)];
PunktTrans(poly,poly1,0,elemof(poly1));
Polygon(dc,poly,elemof(poly));
}
static void PaintPAUSE(HDC dc) { // 2 "Pause"-Rechtecke
Rectangle(dc,-4,-5, 0,+5);
Rectangle(dc,+1,-5,+5,+5);
}
static void(*const PaintFunc[])(HDC dc)={
PaintENGER,PaintWEITER,PaintTIEFER,PaintHOEHER,
PaintEINAUS,PaintPLAY,PaintPAUSE};
void MYBUTTON::Paint(HDC dc) {
KNOTEN::Paint(dc); // Hier: kein Fokusrechteck oder Selektbitmap malen
FillRect(dc,&rcitem,GetStockBrush(LTGRAY_BRUSH)); // Immer in dieser Farbe
if (!(state&STA_GRAYED)) { // Rand, wenn drückbar
Line3(dc, rcitem.left, rcitem.bottom-2,
rcitem.left, rcitem.top,
rcitem.right-1, rcitem.top,
GetStockPen(state&1?BLACK_PEN:WHITE_PEN));
if (state&(STA_HOVER|STA_FOCUSED)) {
Line3(dc, rcitem.left+1, rcitem.bottom-3,
rcitem.left+1, rcitem.top+1,
rcitem.right-2, rcitem.top+1, state&1?0x808080L:0xE0E0E0L);
Line3(dc, rcitem.left+1, rcitem.bottom-2,
rcitem.right-2, rcitem.bottom-2,
rcitem.right-2, rcitem.top, state&1?0xE0E0E0L:0x808080L);
}
Line3(dc, rcitem.left, rcitem.bottom-1,
rcitem.right-1, rcitem.bottom-1,
rcitem.right-1, rcitem.top-1,
GetStockPen(state&1?WHITE_PEN:BLACK_PEN));
}
POINT mitte;
mitte.x=(rcitem.left+rcitem.right)/2;
mitte.y=(rcitem.top+rcitem.bottom)/2;
if (state&1) mitte.y++; else mitte.x--;
SetViewportOrgEx(dc,mitte.x,mitte.y,NULL);
SelectPen(dc,GetStockPen(WHITE_PEN)); // Immer weißen Rand um Symbolik(?)
SelectBrush(dc,GetStockBrush(state&STA_GRAYED?GRAY_BRUSH:BLACK_BRUSH));
PaintFunc[bild](dc);
SetViewportOrgEx(dc,0,0,NULL);
}
bool MYBUTTON::RelayMsg(UINT Msg, WPARAM wParam, LPARAM lParam) {
if (!(state&2)) switch (Msg) { // Eingaben nur wenn nicht deaktiviert
case WM_LBUTTONDOWN:
case WM_LBUTTONDBLCLK: { // Äußeres Programm muss Capture setzen!
// DWORD keydelay;
SetState(0x31);
SendMessage(MainWnd,WM_COMMAND,id,0);
// SystemParametersInfo(SPI_GETKEYBOARDDELAY,0,&keydelay,0);
// *(UINT*)&keydelay=250*((UINT)keydelay+1); // Formel!!
// SetTimer(MainWnd,22,(UINT)keydelay,NULL);
}break;
case WM_MOUSEHOVER: {
tip->SetTip(&rcitem,hint);
}break;
case WM_MOUSEMOVE: {
if (!(state&0x10)) break;
SetState((BYTE)(state&0x20?0x31:0x10));
}break;
case WM_LBUTTONUP: {
SetState(0x00);
KillTimer(MainWnd,22);
}break;
/*
case WM_TIMER: switch (wParam) {
case 22: {
DWORD keyspeed;
if (!(state&0x10)) break;
if (!(state&0x20)) break;
SystemParametersInfo(SPI_GETKEYBOARDSPEED,0,&keyspeed,0);
if ((UINT)keyspeed) *(UINT*)&keyspeed=1000/(UINT)keyspeed; // Frequenz in Zeit
SetTimer(MainWnd,22,(UINT)keyspeed,NULL);
SendMessage(MainWnd,WM_COMMAND,id,lParam);
}break;
}break;
*/
}
return MINIWND::RelayMsg(Msg,wParam,lParam);
}
/********************************************************
** Klasse M_K: Basis für Massesymbol und Triggerkreuz **
********************************************************/
void M_K::CalcRect(RECT*rcitem) {
// von <mitte> Rechteck berechnen, ggf. in Client-Bereich einziehen und
// <mitte> nachziehen
RECT r;
SetRect(&r,0,0,ClientExt.x-1,ClientExt.y-1);
SetRect(rcitem,mitte.x-10,mitte.y-10,mitte.x+11,mitte.y+11);
aussen=MoveRectIntoRect(rcitem,&r);
if (aussen) {
mitte.x=(rcitem->left+rcitem->right)/2;
mitte.y=(rcitem->top+rcitem->bottom)/2;
}
}
void M_K::SetGdiObjekte(COLORREF farbe) {
if (PolygonPinsel && DeleteBrush(PolygonPinsel)) PolygonPinsel=0;
// if (PfeilStift && DeletePen(PfeilStift)) PfeilStift=0;
if (!HIBYTE(HIWORD(farbe))) { // kein "Abmelde-Kode"
// PfeilStift=CreatePen(PS_SOLID,2,farbe);
PolygonPinsel=CreateSolidBrush(farbe);
}
}
void M_K::PaintPoly(HDC dc,const POINT *p, int n) {
MINIWND::Paint(dc);
HPEN open=SelectPen(dc,BackPen);
HBRUSH obr=SelectBrush(dc,PolygonPinsel);
SetViewportOrgEx(dc,mitte.x,mitte.y,NULL);
Hilfspfeil(dc);
Polygon(dc,p,n);
SetViewportOrgEx(dc,0,0,NULL);
SelectBrush(dc,obr);
SelectPen(dc,open);
}
void M_K::Hilfspfeil(HDC dc) { // Ein Pfeil ist ein 7-Eck!
static const BPOINT PolyW[]={ // Gerader Pfeil (West)
{-6,-11},{-11,-6},{-6,-1},{-6,-4},{-3,-4},{-3,-8},{-6,-8}};
static const BPOINT PolyNW[]={ // Schräger Pfeil (Nord-West)
{-2,-10},{-10,-10},{-10,-2},{-7,-5},{-5,-3},{-3,-5},{-5,-7}};
static const BYTE rand2richtung[16]={8,0,2,1,4,8,3,8,6,7,8,8,5,8,8,8};
POINT poly[9]; // für Aufruf von Polygon()
BYTE bits=rand2richtung[aussen&15]; // Rand-Bits (4 bit) in Richtung (3 bit)
if (bits==8) return; // unmögliche Kombinationen für Rand-Bits
// Himmelsrichtung: Bit 0: 45°, Bit 1: 90°, Bit 2: 180°
PunktTrans(poly,bits&1?PolyNW:PolyW,bits,elemof(PolyW));
Polygon(dc,poly,elemof(PolyW));
}
/*************************************
** Das Massesymbol, eins pro Kanal **
*************************************/
MASSE::MASSE(KANAL*k): M_K(&Anker[1]) {
TCHAR buf[64];
this->k=k;
UpdateGdiObjekte();
_sntprintf(buf,elemof(buf),T("Massesymbol Kanal %s (Shift+Pfeil vertikal)"),k->name);
// M_CREATESTRUCT mcs;
// mcs.p=;
CalcRect(&rcitem);
hint=buf;
id=k->idhigh+333;
style=2;
// MINIWND::Init(&mcs);
}
void MASSE::Paint(HDC dc) {
static const POINT Form[]={
{-2,-8},{-2,-2},{-7,-2},{-7,+2},{+7,+2},{+7,-2},{+2,-2},{+2,-8}};
M_K::PaintPoly(dc,Form,elemof(Form)); // Verkettete zeichnen (Gitter usw.)
}
bool MASSE::RelayMsg(UINT Msg,WPARAM wParam,LPARAM lParam) {
switch (Msg) {
case WM_LBUTTONUP: if (!(state&1)) break; state&=~1; nobreak;
case WM_SIZE: Update(WAS_YNUL); return MINIWND::RelayMsg(Msg,wParam,lParam);
case WM_SYSCOLORCHANGE: Update(WAS_FARBE); break;
// case WM_NCHITTEST:
// MessageBeep((UINT)-1);
// if (state&0x20) _asm int 3;
// break;
}
MINIWND::RelayMsg(Msg,wParam,lParam);
switch (Msg) {
case WM_MOUSEHOVER: tip->SetTip(&rcitem,MAKEINTRESOURCE(21),(LPCTSTR)k->name);
case WM_MOUSEMOVE: { // Gedrückt bewegen
if (!(state&1)) break;
mitte.x=(rcitem.left+rcitem.right)/2;
mitte.y=(rcitem.top+rcitem.bottom)/2;
k->SetNulllinie((Mitte.y-mitte.y)/(float)step.y);
}break;
case WM_RBUTTONDOWN: {
if (!(state&1)) break;
state&=~1;
ShowPopupMenu(k->submenu,MAKEPOINTS(lParam).x,MAKEPOINTS(lParam).y);
}break;
case WM_MOUSEWHEEL: {
int delta;
#ifdef WIN32
delta=(short)HIWORD(wParam);
#else
delta=(short)LOWORD(GetMessageExtraInfo()); //??
#endif
k->SetAblenkung(delta<0?T("+?"):T("-?"));
}break;
}
return true;
}
void MASSE::CalcRect(RECT *rcitem) {
mitte.x=(-10*(numkanal-1)+k->kn*20)+Mitte.x;
mitte.y=Mitte.y-rund(k->nulllinie*step.y);
M_K::CalcRect(rcitem);
}
bool MASSE::Update(BYTE was) {
if (was&WAS_FARBE) UpdateGdiObjekte();
if (was&WAS_YNUL) {
if (state&1) return true; // Solange gedrückt, nicht "unterm Arsch" wegsetzen
Inval();
CalcRect(&rcitem);
Moved();
}return true;
}
void MASSE::UpdateGdiObjekte() {SetGdiObjekte(k->farbe);}
/************************************************************************
** Das Triggersymbol, eins pro Trigger (aber davon gibt's nur einen!) **
************************************************************************/
KREUZ::KREUZ(TRIGG*t): M_K(&Anker[1]) {
this->t=t;
UpdateGdiObjekte();
CalcRect(&rcitem);
hint=T("Triggerkreuz (Pegel und Position) (Strg+Pfeiltasten)");
id=0;
style=3;
// MINIWND::Init(&mcs);
}
void KREUZ::Paint(HDC dc) {
static const BPOINT Form4[]={{-2,+8},{-2,+2},{-8,+2}}; // ¼ Kreuz
POINT Form[12],*p;
BYTE bits;
for (p=Form,bits=0; bits<8; bits+=(BYTE)2) {
PunktTrans(p,Form4,bits,3); p+=3;
}
M_K::PaintPoly(dc,Form,elemof(Form));
}
bool KREUZ::RelayMsg(UINT Msg, WPARAM wParam, LPARAM lParam) {
switch (Msg) {
case WM_LBUTTONUP: if (!(state&1)) break; state&=~1; nobreak;
case WM_SIZE: Update(WAS_TPEGEL|WAS_TPRETRIG); return MINIWND::RelayMsg(Msg,wParam,lParam);
case WM_SYSCOLORCHANGE: UpdateGdiObjekte(); break;
}
MINIWND::RelayMsg(Msg,wParam,lParam);
switch (Msg) {
case WM_MOUSEHOVER: tip->SetTip(&rcitem,MAKEINTRESOURCE(20)); break;
case WM_MOUSEMOVE: {
if (!(state&1)) break;
mitte.x=(rcitem.left+rcitem.right)/2;
mitte.y=(rcitem.top+rcitem.bottom)/2;
t->SetPretrig(iitrafo(mitte.x,
Rand.left,Rand.right-1,0,100));
t->SetPegel((Mitte.y-mitte.y)/
(float)step.y-t->k->nulllinie);
}break;
case WM_RBUTTONDOWN: {
if (!(state&1)) break;
state&=~1;
ShowPopupMenu(t->submenu,MAKEPOINTS(lParam).x,MAKEPOINTS(lParam).y);
}break;
}
return true;
}
void KREUZ::CalcRect(RECT*rcitem) {
mitte.x=iitrafo(t->pretrig,0,100,Rand.left,Rand.right-1);
mitte.y=Mitte.y-rund((t->pegel+t->k->nulllinie)*step.y);
M_K::CalcRect(rcitem);
}
bool KREUZ::Update(BYTE was) { // Position an Prätrigger und Triggerpegel halten
if (was&(WAS_TQUELLE|WAS_FARBE)) UpdateGdiObjekte();
if (!(was&(WAS_TPEGEL|WAS_TPRETRIG|WAS_TQUELLE))) return true;
if (state&1) return true; // Nicht "unterm Arsch" wegsetzen lassen!
Inval();
CalcRect(&rcitem);
Moved();
return true;
}
void KREUZ::UpdateGdiObjekte() {SetGdiObjekte(t->k->farbe);}
Detected encoding: UTF-8 | 0
|