//#define OEMRESOURCE #include "wutils.h" #include "miniwnd.h" #include "objekte.h" #include // 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 ? 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; x1) for(y=Rand.top; y1) { 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; x1) { j=(tick.x+1)>>1; if (!j) j++; from=Mitte.x-j; to=Mitte.x+j+1; for (y=Rand.top; y>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; iPaint(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

! // 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

ODER vor ! // 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 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 Rechteck berechnen, ggf. in Client-Bereich einziehen und // 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);}