//#define OEMRESOURCE #include "wutils.h" #include "miniwnd.h" #include "objekte.h" #include #include "quelle.h" #include // fabs, log, floor, exp //#include "inout.h" //#include "dso.h" /*Zu verarbeitende Tasten (Idee): 1..9 Kanalumschaltung (Fokusrechteck) A,B Zeitbasis (Fokusrechteck) T Triggerung (Fokus) M Messung (Fokus) Pfeil links-rechts Zeitbasis Shift+Pfeil links-rechts Triggerverzögerung Strg+Pfeil links-rechts Triggerverzögerung Pfeil hoch/runter Y-Ablenkung (fokussierter Kanal) Shift+Pfeil hoch/runter Y-Position Strg+Pfeil hoch/runter Triggerpegel TAB Fokus weiterschalten Shift+TAB Fokus zurückschalten ( c Kopplung weiterschalten ( Shift+C Kopplung zurückschalten ( Strg+C Kopplungs-Menü = Gleichspannungskopplung ~ Wechselspannungskopplung _ Massekopplung p Tastkopf weiterschalten ( Shift+P Tastkopf zurückschalten ( Strg+P Tastkopf-Menü ! Tastkopf 1:1/10:1 # Tastkopf-Dialog - Invertierung Leer, Pause Stop,Start Einfg, Enter Kanal-Trace als Referenz speichern Entf Referenzspeicher löschen */ #ifdef WIN32 #define WriteStruct WritePrivateProfileStruct #define GetStruct GetPrivateProfileStruct #else #define min(a,b) ((a)<(b)?(a):(b)) #define max(a,b) ((a)>(b)?(a):(b)) extern "C" { // Suffix X: Windows 3x, Suffix Y: Win9x BOOL WINAPI WritePrivateProfileStructX(LPCSTR,LPCSTR,LPVOID,UINT,LPCSTR); BOOL WINAPI GetPrivateProfileStructX(LPCSTR,LPCSTR,LPVOID,UINT,LPCSTR); BOOL WINAPI CheckMenuRadioItemX(HMENU m,UINT i,UINT j,UINT k,UINT p); BOOL WINAPI SetMenuDefaultItemX(HMENU m,UINT i,UINT p); BOOL WINAPI WritePrivateProfileStructY(LPCSTR,LPCSTR,LPVOID,UINT,LPCSTR); BOOL WINAPI GetPrivateProfileStructY(LPCSTR,LPCSTR,LPVOID,UINT,LPCSTR); BOOL WINAPI CheckMenuRadioItemY(HMENU m,UINT i,UINT j,UINT k,UINT p); BOOL WINAPI SetMenuDefaultItemY(HMENU m,UINT i,UINT p); } BOOL WINAPI (*WriteStruct)(LPCSTR,LPCSTR,LPVOID,UINT,LPCSTR) =WritePrivateProfileStructX; BOOL WINAPI (*GetStruct)(LPCSTR,LPCSTR,LPVOID,UINT,LPCSTR) =GetPrivateProfileStructX; BOOL WINAPI (*CheckMenuRadioItem)(HMENU,UINT,UINT,UINT,UINT) =CheckMenuRadioItemX; BOOL WINAPI (*SetMenuDefaultItem)(HMENU,UINT,UINT) =SetMenuDefaultItemX; #endif HWND MainWnd; // Hauptfenster HMENU MainMenu; HMENU OsziMenu; // Der komplett dynamische Menü-Teil HWND hSetupDlg; // Nichtmodaler Setup-Dialog HWND hDisplayDlg; HWND hKBHand; // Dialog-Keyboard-Handler (für nichtmodale Dialoge) #if 0 HWND Tooltip; #endif TOOLTIP *tip; COLORREF CustColors[16]; TCHAR sDecimal[2]; // Dezimaltrennzeichen von Windows TCHAR sDezimal[2]; // mein Dezimaltrennzeichen ('.', ',' oder '?') TCHAR sMikro[2]; // Mikro-Zeichen (µ, in Arabien, Russland: u) TCHAR sKanalFormat[8]; // Format-String für Kanal (Standard: Y%d) int iKanalStart; // Nummer des ersten Kanals (Standard: 1) TCHAR WindowTitle[64]; TCHAR StdProfile[MAX_PATH]; // mit Pfad, Zusammensetzung in WinMain TCHAR HelpFileName[]=T("OSZI.HLP"); static const TCHAR sProzentI[]=T("%i,%i,%i,%i,%i"); #define sInt (sProzentI+12) // wie T("%d") #define sLeer (sProzentI+14) // wie T("") static const TCHAR IniFileName[] =T("OSZI.INI"); static const TCHAR WndClassName[]=T("OSZI"); static const TCHAR HauptSektion[]=T("Elbe"); // Nicht der Fluss aus dem Fichtelgebirge static const TCHAR S_Position[] =T("Position"); WORD wPrefix=MAKEWORD(-4,3); // piko bis Giga const int NumZeitMenu=1; // = Anzahl an Zeitbasen const int NumTrigMenu=1; // Anzahl Trigger (stets 1) (grau im Rollbetrieb) int NumKanalMenu=1; // Anzahl Kanäle im Menü // max. MaxKanalMenu+1(!), dann heißt der letzte Eintrag "Weitere Kanäle..." int MaxKanalMenu; // =16 von INI-Datei, mindestens 4 HBRUSH EditBrushes[3]; // "wichtigste" Farbe mit höchstem Index ATOM atom; // zum Zugriff auf Hintergrundfarbe bei Edit-Feldern (GetProp) HWND hZeitDlg; int ZeitDlgCurSel; // aktuelle Auswahl im Zeitbasis-Dialog //HWND hTrigDlg; // Zukunftsmusik HWND hKanalDlg; UINT wm_helpmsg; // Globale Daten zur Interpretation der Sample-Daten (außer Samplerate) WAVEHDR WaveHdr; // Zeiger auf ganz viele(?) Sampledaten // mit unkonventioneller Belegung der Felder! #define GetSample st.getsample //GETSAMPLE GetSample; // Funktionszeiger zum Sample lesen #define BlockAlign st.blockalign //UINT BlockAlign; // Größe eines Samples für alle Kanäle float FullScale; // 1<, Position , zum Menü Position // kopieren, dabei Menü-ID um erhöhen. Ggf. werden ganze // Popup-Untermenüs kopiert, siehe CopyPopupMenu(). // Bitmaps (MF_BITMAP) und Checkmark-Bitmaps werden zz. nicht mit kopiert! TCHAR buf[64]; UINT state,id; HMENU sub; GetMenuString(sm,si,buf,elemof(buf),MF_BYPOSITION); sub=GetSubMenu(sm,si); state=GetMenuState(sm,si,MF_BYPOSITION); if (sub) { state&=0xFF; // nur LOW-Byte ist gültig, state|=MF_POPUP; // "checked" kann es ja trotzdem sein! id=(UINT)CopyPopupMenu(sub,inc); }else id=GetMenuItemID(sm,si)+inc; InsertMenu(dm,di,MF_BYPOSITION|state,id,buf); } HMENU CopyPopupMenu(HMENU m, UINT inc) { // Erstellt vom Popup-Menü eine Kopie mit um erhöhten Menu-IDs. int j=GetMenuItemCount(m); HMENU n=CreatePopupMenu(); for (int i=0; i&&? TCHAR s[64]; int l=GetMenuString(m,pos,s,elemof(s),MF_BYPOSITION); /* if (l>=64-1-lstrlen(a)) return; if (s[l]) { _asm nop; } s[l]=0; // Windows-Bug töten*/ lstrcpy(AfterTab(s),a); SetMenuString(m,pos,s); } void AppendAndereToMenu(HMENU m, UINT id) { // Hängt den String "&andere..." an das (Popup-)Menü an // Für X-Ablenkung, Samplerate und Y-Ablenkung TCHAR s[64]; LoadString(HInstance,205/*andere...*/,s,elemof(s)); InsertMenu(m,(UINT)-1,MF_BYPOSITION,id,s); } void MenuRadioNextDefault(HMENU m, UINT sub, UINT item) { // CheckMenuRadioItem für's ganze Menü, sowie nächstes "enabeltes" Item // zur Vorgabe machen m=GetSubMenu(m,sub); sub=GetMenuItemCount(m); CheckMenuRadioItem(m,0,sub-1,item,MF_BYPOSITION); for (UINT i=item;;) { // Vom nächsten Item an 1x rundherum i++; if (i>=sub) i=0; if (!(GetMenuState(m,i,MF_BYPOSITION)&(MF_DISABLED|MF_GRAYED))) { SetMenuDefaultItem(m,i,MF_BYPOSITION); break; } if (i==item) break; } } void MenuEnable(HMENU m, UINT pos, UINT mask) { // Wie EnableMenuGroup; bei Deaktivieren des Häkchens wird das nächste // aktive Bit eingestellt und WM_COMMAND verschickt m=GetSubMenu(m,pos); pos=GetMenuItemCount(m); EnableMenuGroup(m,0,pos-1,mask,MF_BYPOSITION); for (UINT i=0; i=pos) j=0; if (!(GetMenuState(m,j,MF_BYPOSITION)&MF_GRAYED)) { SendMessage(MainWnd,WM_COMMAND,GetMenuItemID(m,j),0); break; } if (j==i) break; } } } } bool FarbAuswahl(HWND w,COLORREF&cr) { CHOOSECOLOR cc; InitStruct(&cc,sizeof(cc)); cc.hwndOwner=w; cc.rgbResult=cr; cc.lpCustColors=CustColors; cc.Flags=CC_RGBINIT|CC_SHOWHELP|CC_FULLOPEN; if (!ChooseColor(&cc)) return false; cr=cc.rgbResult; return true; } int String2Index(PCTSTR p, PCTSTR n) { // Ermittelt String-Nummer von in String-Liste

, -1 bei keinem Treffer // p zeigt auf aneinandergekettete nullterminierte Strings, mit Extra-Null am Ende // Der String-Vergleich erfolgt case-insensitiv (lstrcmpi) for (int i=0; *p; p+=lstrlen(p)+1,i++) if (!lstrcmpi(n,p)) return i; return -1; } PCTSTR Index2String(PCTSTR p, int i) { // Gegenfunktion, liefert String zum Index, NULL wenn ungültig for (;*p;p+=lstrlen(p)+1,i--) if (!i) return p; return NULL; } int hsz2Index(HSZ*p, int hszlen, HSZ n) { //Liefert nullbasierten Index des String-Handles for (int i=0; i für "++" oder "+?" ohne gedrückte SHIFT-Taste, // liefert für "+" oder "+?" mit gedrückter SHIFT-Taste, // bei '-' statt '+' negative Werte, andernfalls 0 int r=0; switch (s[0]) { case '+': case '-': switch (s[1]) { case '?': if (s[2]) break; r=GetKeyState(VK_SHIFT)<0?sm:big; break; case 0: r=sm; break; default: if (s[0]==s[1] && !s[2]) r=big; } } if (s[0]=='-') r=-r; return r; } /* BYTE PointIntoRect(const RECT*rc, POINT*pt) { // Zieht Punkt ins Rechteck und markiert jede der Bewegung im Rückgabewert BYTE r=0; if (pt->x< rc->left) {pt->x=rc->left; r|=1;} // links if (pt->x>=rc->right) {pt->x=rc->right; r|=2;} // rechts if (pt->y< rc->top) {pt->y=rc->top; r|=4;} // oben if (pt->y>=rc->bottom){pt->y=rc->bottom; r|=8;} // unten return r; } */ COLORREF MixColor(COLORREF c1, COLORREF c2, int f1=128) { // Farbe c1 und c2 komponentenweise mischen, mit f1 als Gewicht für // 1. Farbe (0 = nur 2. Farbe, 256 = nur 1. Farbe) COLORREF r; int f2=256-f1; // 2. Faktor #define KOMP(cr) ((PBYTE)&(cr)) // Farbkomponenten als Array[0..2] for (int i=0; i<3; i++) KOMP(r)[i]=HIBYTE(KOMP(c1)[i]*f1+KOMP(c2)[i]*f2); KOMP(r)[3]=0; #undef KOMP return r; } /******************************************* ** Spielereien mit dem Hintergrundraster ** *******************************************/ void _stdcall Line(HDC dc, int x1, int y1, int x2, int y2) { #ifdef _M_IX86 Polyline(dc,(POINT*)&x1,2); #else POINT p[2]={{x1,y1},{x2,y2}}; Polyline(dc,p,2); #endif } void Inval(bool background, LPRECT rcitem) { //Bildschirm/Doppelpuffer-Bitmap ungültig machen; //Triple-Puffer-Bitmap nur wenn background=true //LPRECT für korrekte NULL-Übergabe! if (background) DispOpt|=DO_TB_INVAL; DispOpt|=DO_DB_INVAL; InvalidateRect(MainWnd,rcitem,FALSE); } POINT WinBitmapExt={16,16}; #if 0 HBITMAP WinBitmaps[]={ (HBITMAP)OBM_LFARROW,(HBITMAP)OBM_LFARROWD,(HBITMAP)OBM_LFARROWI, (HBITMAP)OBM_RGARROW,(HBITMAP)OBM_RGARROWD,(HBITMAP)OBM_RGARROWI, (HBITMAP)OBM_UPARROW,(HBITMAP)OBM_UPARROWD,(HBITMAP)OBM_UPARROWI, (HBITMAP)OBM_DNARROW,(HBITMAP)OBM_DNARROWD,(HBITMAP)OBM_DNARROWI, (HBITMAP)OBM_CLOSE}; void LoadWinBitmaps(void) { int i; BITMAP bm; for (i=0; i behalten, q muss positiv sein! z=z<0?-q:q; } // Gleitkommazahlen sind mit ihrem Rundungseffekt die blanke Katastrophe!! static const float Reihe[]={ // von 1n bis 1G, sind 55 Werte 1E-9F,2E-9F,5E-9F,1E-8F,2E-8F,5E-8F,1E-7F,2E-7F,5E-7F, 1E-6F,2E-6F,5E-6F,1E-5F,2E-5F,5E-5F,1E-4F,2E-4F,5E-4F, 1E-3F,2E-3F,5E-3F,1E-2F,2E-2F,5E-2F,1E-1F,2E-1F,5E-1F, 1E+0F,2E+0F,5E+0F,1E+1F,2E+1F,5E+1F,1E+2F,2E+2F,5E+2F, 1E+3F,2E+3F,5E+3F,1E+4F,2E+4F,5E+4F,1E+5F,2E+5F,5E+5F, 1E+6F,2E+6F,5E+6F,1E+7F,2E+7F,5E+7F,1E+8F,2E+8F,5E+8F, 1E+9F}; int NextFloat(float &v, int updown) { // Liefert zu gegebener Zahl die nächste oder vorherige im "Raster" // Ermittelt die nächste (=1) oder vorhergehende (=-1) // Zahl im 1-2-5-Raster, im obigen Raster. Das Vorzeichen wird beibehalten. // Bei =0 wird zum nächsten 1-2-5-Raster aufgerundet. // Liefert Reihen-Index (braucht man kaum!) int m; // Wüste halbieren: Halbwüste: ich trau' mich vorerst nicht! float z=(float)fabs(v); for (m=0;m0) updown--; // wenn dazwischen: m ist schon "nächster" Index exakt: m+=updown; if (m<0) z=0; // Notbremse 1 else if (m>=elemof(Reihe)) z=1E38F; // Notbremse 2 else z=Reihe[m]; SetBetrag(v,z); return m; } // Zweite Version mit Begrenzung void NextFloat(float &v, int updown, float limit) { NextFloat(v,updown); if (updown>=0) { if (fabs(v)>limit) SetBetrag(v,limit); }else{ if (fabs(v) wird ein Präfix ausgewählt, * der eine Wiedergabe der physikalischen Größe mit 1..3 * Vorkommastellen erlaubt. * In landet der Wert zum "Behandeln" der Daten vor Ausgabe. * das kommt für dieses Problem zupass. * Unsauber ist das Problem "Kilogramm", die Basiseinheit ist hier "Gramm", * die "Tonne" erfordert Extrawürste beim Aufrufer. * Bei bestimmten Zeichensätzen (Kyrillisch, Arabisch) ist die Umsetzung * von µ in u bzw. in Symbolschriftart oder besser Unicode erforderlich. */ int i; i=number?rndint(log(fabs(number))/log1000-0.5):0; //Typecast ohne floor() rundet zu Null: falsch! if (i<(signed char)LOBYTE(minmax)) i=0; // Präfix unerwünscht if (i>(signed char)HIBYTE(minmax)) i=0; multiplier=(float)exp(-i*log1000); return ISO_Prefixes[i+6]; } PTSTR Prefix2Ptr(TCHAR c) { // Präfix korrigieren und Pointer liefern switch (c) { case 'µ': case 'u': return ISO_Prefixes+4; case 0: case '\'': c=' '; // Apostroph zur Unterdrückung des Vorsatzes } // bspw. bei "mol", "at", "atm" return StrChr(ISO_Prefixes,c); } TCHAR GetDecimal() { // aktuelles Dezimaltrennzeichen nehmen if (*sDezimal!='?') return *sDezimal; return *sDecimal; } void Float2String(PTSTR s, float v, WORD minmax, PCTSTR Einheit,int precis=3) { TCHAR prefix[]=T("\0"); // 2 Zeichen mit Nullen TCHAR *p, buf[16]; float multiplier; *prefix=MakePrefix(v,multiplier,minmax); if (*prefix==' ') *prefix=0; // kein String _sntprintf(buf,elemof(buf),T("%.*G"),precis,v*multiplier); p=StrChr(buf,'.'); if (p) *p=GetDecimal(); // Ersetzen Punkt durch Komma (nach Systemsteuerung) wsprintf(s,T("%s %s%s"),buf,prefix,Einheit); } bool String2Float(PCTSTR s, float&z, PTSTR e) { // Konvertiert Zahl, ggf. Einheitenvorsatz und Einheit, nach und // Maximale Länge der Einheit (ohne Vorsatz): 3 Zeichen, (Puffergröße=4) PTSTR p; double v; int i,j,k,l; p=StrChr((PTSTR)s,GetDecimal()); // Das benutzerdefinierte Zeichen ... if (!p) p=StrChr((PTSTR)s,','); // oder ein Komma ... if (p) *p='.'; // durch Punkt ersetzen l=lstrlen(s); i=_stscanf(s,T("%lf%n %") ELENSTR T("s%n"),&v,&j,e,&k); e[ELEN-1]=0; // zwangsterminieren if (i==1 && j==l) { // nur Zahl gegeben: OK *e=0; goto okay; } if (i==2 && k==l && *e) { // Zahl und Einheit... if (e[1]) { // Vorsatz möglich? (Nur mit Einheit! Bspw: m=Meter) p=Prefix2Ptr(*e); // Gefahr: min -> Milli-Inch if (p) { j=int(p-ISO_Prefixes)-6; v*=exp(j*log1000); // mit »float v« gibt's Rundungsfehler! lstrcpy(e,e+1); } } okay: z=(float)v; return true; } return false; } /********************************************* ** Strukturen, die zu Klassen mutierten... ** *********************************************/ // globale Version fürs Testen... bool GetNameList(PCTSTR n, PTSTR buf, BYTE*bitnr) { // Namen mit Nullen trennen, Liste mit Doppelnull anschließen (max. 16 Bytes), // Wertigkeit zu speichern (Zeiger darf NULL sein, wenn ungewünscht) // Zur Feststellung von Gruppenzugehörigkeit. int i,bit; TCHAR hack[32]; PTSTR p,q; lstrcpyn(hack,n,elemof(buf)); // in den Zerhack-Puffer n=hack; for (;;) { bit=0; // Ohne Angabe Bit=0 setzen while (*n==' ') n++; // Führende Leerzeichen übergehen if (!*n) break; // Stringende erreicht p=StrChr(n,' '); if (p) *p=0; // am Leerzeichen zerhacken q=StrChr(n,':'); if (q) { *q=0; // am Doppelpunkt zerhacken if (_stscanf(q+1,sInt,&bit)!=1) return false; // falsche Bitnummer } i=lstrlen(n); if ((unsigned)(i-1)>6) return false; // Name zu kurz oder zu lang lstrcpy(buf,n); buf+=i+1; // Ziel vorrücken if (bitnr) *bitnr++=(BYTE)bit; if (p) n=p+1; // Quelle vorrücken else break; // Stringende erreicht } *buf=0; // Doppel-Null return true; } int flimit(float f, int u, int o) { // Runden und begrenzen if (f>o) return o; if (f Stück) QUELLE *quelle=NULL; // Datenquelle-Objekt (1 Stück) // Ich komme wohl doch nicht ohne eine Gruppen-Liste aus... int numgruppe; GRUPPE *gruppe; // Gruppen-Objekte (bloß Namen), Stück! void MacheGruppenListe() { // aktualisiert und an Hand der Kanal-Namen: // Bei nur einem Kanal gibt es gar keine Gruppen, // ab zwei am Ende stets die Gruppe "Alle Kanäle / Beide Kanäle" GRUPPE *gp; KANAL *kp,*kj; TCHAR buf[32]; PTSTR p; int i,j,k; numgruppe=0; if (numkanal<=1) return; gp=gruppe; // vorn mit dem Füllen anfangen if (!gp) return; // Puffer noch nicht angefordert (beim Lesen der .INI) for (i=0,kp=kanal; iGetNameList(buf,NULL)) continue; for (p=buf; *p; p+=lstrlen(p)+1) { for (j=i+1; jHatName(p)) continue; for (k=0; kname,p,elemof(gp->name)); gp->ref=2; gp++; numgruppe++; if (numgruppe==numkanal) return; schondrin:; } } } gp->name[0]=0; gp->ref=numkanal; // Zuletzt "alle/beide Kanäle" anhängen numgruppe++; } #if 0 bool GRUPPE::SetNulllinie(PTSTR s,PTSTR t) { float z,v; EINHEIT e; if (!String2Float(s,z,e)) return false; if (e[0] && lstrcmp(e,einheit)) return false; // falsche Einheit if (!String2Float(t,v,e)) return false; if (e[0] && lstrcmp(e,einheit)) return false; // falsche Einheit for (int i=0; iInval(); SetRect(&nagel->rcitem,rcitem.left-WinBitmapExt.x, rcitem.top,rcitem.left,rcitem.top+WinBitmapExt.y); nagel->Moved(); // Eigentlich: bei unten liegenden Fenstern Systemmenü nach unten ausrichten; // bei RTL-System an rechte Kante setzen, niemals außerhalb des Fensters // sowie Test auf "herausfallende" Fenster! }break; case WM_MOUSEMOVE: { MINIWND::RelayMsg(Msg,wParam,lParam); hitkode=0; if (!(state&0x20)) return false; int x=MAKEPOINTS(lParam).x-rcitem.left; for (int i=0; iEnable(k->divmax); // Rück-Verbindung... knopf[1]->Enable(k->mindiv); k->GetVar(2,buf); // Ablenkung wnsprintf(string1,elemof(string1),T("%c %s = %s %c"), sTastkopf2[k->GetTastkopfIndex()], k->name, buf, sKopplung2[k->kopplung]); HDC dc=GetDC(MainWnd); int spclen2=TextWidth(dc,sTastkopf2,1)/2; // Breite halbes Leerzeichen grenzen[0]=TextWidth(dc,string1,1)+spclen2; // Tastkopf-Bereich PTSTR p=StrChr(string1,'='); grenzen[1]=TextWidth(dc,string1,p); // Kanalname-Bereich p+=2; if (*p=='-') p++; grenzen[2]=TextWidth(dc,string1,p); // Vorzeichen-Bereich p=StrChr(p,0)-2; grenzen[3]=TextWidth(dc,string1,p); // Ablenkungs-Bereich p+=2; grenzen[4]=TextWidth(dc,string1,p); // Kopplungs-Bereich ReleaseDC(MainWnd,dc); int diff=rcitem.left+grenzen[4]-rcitem.right; if (diff) { rcitem.right+=diff; Moved(); // "heißes" Rechteck nachführen! knopf[0]->Schieb(diff,0,true); knopf[1]->Schieb(diff,0,true); } } if (was&(WAS_YVOR|WAS_YINV|WAS_YABL|WAS_YKOP|WAS_FARBE)) Inval(); } KANALANZEIGE::KANALANZEIGE(KANAL*k) { this->k=k; grenzen[4]=16; string1[0]=0; RECT r; // M_CREATESTRUCT mcs; // SCHEUSSLICH!! // mcs.p=&Anker[1]; // Hintergrund SetKnopfRect(&rcitem,-1); // Hier: Initiale Position #ifdef WIN32 hint=LPSTR_TEXTCALLBACK; #endif id=k->idhigh; style=0; // vorerst nicht verschiebbar! // MINIWND::Init(&mcs); // Problem: Der Defaultkonstruktor wurde schon gerufen SetKnopfRect(&r,0); knopf[0]=new MYBUTTON(this,&r,MAKEINTRESOURCE(30)/*T("Größerer Koeffizient (Pfeil runter)")*/, k->idhigh+IDC_YABL+elemof(Reihe)+1,MYBUTTON::TIEFER); SetKnopfRect(&r,1); knopf[1]=new MYBUTTON(this,&r,MAKEINTRESOURCE(31)/*T("Kleinerer Koeffizient (Pfeil rauf)")*/, k->idhigh+IDC_YABL+elemof(Reihe)+2,MYBUTTON::HOEHER); } void KANALANZEIGE::Paint(HDC dc) { ANZEIGE::Paint(dc); setTextColor(dc,k->farbe); ExtTextOut(dc,rcitem.left,rcitem.top,ETO_OPAQUE,&rcitem, string1,lstrlen(string1),0); } bool KANALANZEIGE::RelayMsg(UINT Msg,WPARAM wParam,LPARAM lParam) { switch (Msg) { #if 0 case WM_NOTIFY: { static const TCHAR Text[]=T("Tastteiler\0Kanal/Gruppe\0") T("Invertierung\0Ablenkkoeffizient (pro Teilstrich)\0Kopplung\0"); if (!hitkode) break; #define ttt ((LPTOOLTIPTEXT)lParam) if (ttt->hdr.code==TTN_NEEDTEXT) ttt->lpszText=(LPTSTR)Index2String(Text,hitkode&0x3F); #undef ttt }break; #endif case WM_SIZE: { Inval(); SetKnopfRect(&rcitem,-1); Moved(); knopf[0]->Inval(); SetKnopfRect(&knopf[0]->rcitem,0); knopf[0]->Moved(); knopf[1]->Inval(); SetKnopfRect(&knopf[1]->rcitem,1); knopf[1]->Moved(); }break; case WM_MOUSEMOVE: { TCHAR s[256]; // Aua, jedes MouseMove! LoadString(HInstance,24,s,elemof(s)); tip->SetTip(&rcitem,Index2String(s,hitkode&0x3F)); }break; case WM_RBUTTONDOWN: { HMENU m=0; switch (hitkode) { case HK_PRI+0: m=GetSubMenu(k->submenu,SUB_YVOR); break; case HK_PRI+3: m=GetSubMenu(k->submenu,SUB_YABL); break; case HK_PRI+4: m=GetSubMenu(k->submenu,SUB_YKOP); break; } if (m) ShowPopupMenu(m,MAKEPOINTS(lParam).x,MAKEPOINTS(lParam).y); }break; } return ANZEIGE::RelayMsg(Msg,wParam,lParam); } void KANALANZEIGE::SetKnopfRect(RECT*r,int idx) { if (idx<0) { // Eigenes Rechteck r->left=k->kn*160+20; r->top =ClientExt.y-20; r->right=r->left+grenzen[4]; r->bottom=r->top+WinBitmapExt.y; return; } int x=rcitem.right; int y=rcitem.top; SetRect(r,x,y,x+WinBitmapExt.x,y+WinBitmapExt.y); if (!idx) return; OffsetRect(r,WinBitmapExt.x,0); } static int _fastcall GetSampleDc(KANAL*k,LPSTR p) { return GetSample(p,k->maske); } static int _fastcall GetSampleAc(KANAL*k,LPSTR p) { int y=GetSample(p,k->maske)-GET_SUB(k->sub); k->sub+=y; // Nachkommastellen in aufheben! return y; } static int _fastcall GetSampleGnd(KANAL*,LPSTR) { return 0; } void KANAL::Konstruktor(int kn) { this->kn=kn; idhigh=kn<<10; wnsprintf(name,elemof(name),sKanalFormat,kn+iKanalStart); div=0; // "ungültig" für LadeVorgabe(), SetAblenkung() fTastkopf=0; // "ungültig" für LadeVorgabe(), SetTastkopf() kopplung=0; getsample=GetSampleDc; poly=NULL/*new POINT[zeit.samples]*/; if (kn=numkanal) { pg+=lstrlen(pg)+1; // auf "Gruppe %s" wnsprintf(buf,elemof(buf),pg,name); }else{ wnsprintf(buf,elemof(buf),pg,name); if (kn<10) InsertAmp(buf,elemof(buf),-1); // bei 2stelligen Zahlen ohne "&" } (kn?InsertMenu:ModifyMenu)(OsziMenu,NumZeitMenu+NumTrigMenu+kn,MF_BYPOSITION|MF_POPUP,(UINT)submenu,buf); if (kn) NumKanalMenu++; }else if (kn==MaxKanalMenu) { TCHAR s[32]; LoadString(HInstance,212/*"Weitere Kanäle..."*/,s,elemof(s)); InsertMenu(OsziMenu,NumZeitMenu+NumTrigMenu+kn,MF_BYPOSITION,IDC_YWEITER,s); NumKanalMenu++; } nulllinie=0; farbe=kn?0x008080L:0x000080L; // gelb? // rot? Besser wäre "ungültig" masse=new MASSE(this); anzeige=new KANALANZEIGE(this); // Verlinkung herstellen LadeVorgabe(); InfoNeu(0xFF); } void KANAL::Destruktor() { RetteVorgabe(); if (poly) delete poly; poly=NULL; delete anzeige; delete masse; if (kn) DeleteMenu(OsziMenu,NumZeitMenu+NumTrigMenu+kn,MF_BYPOSITION); } void ZEITANZEIGE::Paint(HDC dc) { ANZEIGE::Paint(dc); setTextColor(dc,z->farbe); ExtTextOut(dc,rcitem.left,rcitem.top,ETO_OPAQUE|ETO_CLIPPED,&rcitem, string1,lstrlen(string1),NULL); TCHAR buf[16]; z->GetVar(1,buf); ExtTextOut(dc,rcitem.left,rcitem.bottom,ETO_OPAQUE,NULL,buf,lstrlen(buf),NULL); } void TRIGGERANZEIGE::Paint(HDC dc) { ANZEIGE::Paint(dc); setTextColor(dc,t->farbe); ExtTextOut(dc,rcitem.left,rcitem.top,ETO_OPAQUE|ETO_CLIPPED,&rcitem, string1,lstrlen(string1),NULL); } void ZEITANZEIGE::Update(BYTE was) { if (was&(WAS_RATE|WAS_XABLENK)) { z->GetVar(0,string1); knopf[0]->Enable(z->divmax); // Rück-Verbindung... knopf[1]->Enable(z->mindiv); int diff=rcitem.left+TextWidth(string1)-rcitem.right; if (diff) { rcitem.right+=diff; Moved(); knopf[0]->Schieb(diff,0,true); knopf[1]->Schieb(diff,0,true); } } if (was&(WAS_RATE|WAS_XABLENK|WAS_FARBE)) Inval(); } const TCHAR sTrigModus[]=T("Auto\0Normal\0Single\0"); const TCHAR sTrigFlanke[]=T("+-"); const TCHAR sTrigKopplung[]=T("DC\0AC\0HF\0LF\0TVH\0TVL\0NULL\0PAT\0"); void TRIGGERANZEIGE::Update(BYTE was) { if (was&(WAS_TQUELLE|WAS_TFLANKE|WAS_TKOPPLUNG|WAS_TPEGEL|WAS_TPRETRIG)) { TCHAR buf[32]; KANAL *k=t->k; PCTSTR kop=Index2String(sTrigKopplung,t->kopplung); TRIG tr; // DEBUG! tr.what=0; ::quelle->RelayMsg(Q_SETTRIG,&tr); Float2String(buf,k->div*t->pegel,k->praefixe,k->einheit); wnsprintf(string1,elemof(string1),T("%c%s: %s %s (%d%%)"), sTrigFlanke[t->flanke],k->name,buf, kop,t->pretrig); // Anklick-Bereiche festlegen HDC dc=GetDC(MainWnd); int spclen2=TextWidth(dc,sTastkopf2,1)/2; // Breite halbes Leerzeichen grenzen[0]=TextWidth(dc,string1,1)+spclen2; // Flanken-Bereich PTSTR p=StrChr(string1,':'); grenzen[1]=TextWidth(dc,string1,p); // Kanalname-Bereich p=StrChr(p,'('); // Pegel-Bereich grenzen[2]=TextWidth(dc,string1,p-lstrlen(kop)-1); grenzen[3]=TextWidth(dc,string1,p); // Kopplungs-Bereich grenzen[4]=TextWidth(dc,string1); // Prätrigger-Bereich (ganzer String) ReleaseDC(MainWnd,dc); int diff=rcitem.left+grenzen[4]-rcitem.right; if (diff) { rcitem.right+=diff; Moved(); knopf[0]->Schieb(diff,0,true); } } if (was&(WAS_TQUELLE|WAS_TFLANKE|WAS_TKOPPLUNG|WAS_TPEGEL|WAS_TPRETRIG| WAS_FARBE)) Inval(); } ZEITANZEIGE::ZEITANZEIGE(ZEIT*z) { this->z=z; RECT r; // M_CREATESTRUCT mcs; // mcs.p=&Anker[1]; // Hintergrund SetRect(&rcitem,20,10,100,10+WinBitmapExt.y); hint=T("Zeitbasis"); // MINIWND::Init(&mcs); SetRect(&r,0,0,WinBitmapExt.x,WinBitmapExt.y); OffsetRect(&r,rcitem.right,rcitem.top); knopf[0]=new MYBUTTON(this,&r,MAKEINTRESOURCE(35)/*T("Größere Zeitbasis (Pfeil links)")*/, IDC_XABLENK+elemof(Reihe)+1,MYBUTTON::ENGER); OffsetRect(&r,WinBitmapExt.x,0); knopf[1]=new MYBUTTON(this,&r,MAKEINTRESOURCE(36)/*T("Kleinere Zeitbasis (Pfeil rechts)")*/, IDC_XABLENK+elemof(Reihe)+2,MYBUTTON::WEITER); Update(0xFF); } TRIGGERANZEIGE::TRIGGERANZEIGE(TRIGG*t) { this->t=t; RECT r; // M_CREATESTRUCT mcs; // mcs.p=&Anker[1]; // Hintergrund SetRect(&rcitem,120,10,200,10+WinBitmapExt.y); #ifdef WIN32 hint=LPSTR_TEXTCALLBACK; #endif style=0; // MINIWND::Init(&mcs); SetRect(&r,0,0,WinBitmapExt.x,WinBitmapExt.y); OffsetRect(&r,rcitem.right,rcitem.top); knopf[0]=new MYBUTTON(this,&r,MAKEINTRESOURCE(37)/*T("Start/Stopp (Leertaste)")*/, 0x229,MYBUTTON::PAUSE); Update(0xFF); } bool ZEITANZEIGE::RelayMsg(UINT Msg, WPARAM wParam, LPARAM lParam) { switch (Msg) { case WM_MOUSEMOVE: { TCHAR s[256]; // Aua, jedes MouseMove! LoadString(HInstance,16,s,elemof(s)); tip->SetTip(&rcitem,Index2String(s,hitkode&0x3F)); }break; case WM_RBUTTONDOWN: { if (!(state&0x20)) break; ShowPopupMenu(GetSubMenu(z->submenu,SUB_XABLENK), MAKEPOINTS(lParam).x,MAKEPOINTS(lParam).y); }break; } return ANZEIGE::RelayMsg(Msg,wParam,lParam); } bool TRIGGERANZEIGE::RelayMsg(UINT Msg,WPARAM wParam,LPARAM lParam) { switch (Msg) { #if 0 case WM_NOTIFY: { static const TCHAR Text[]=T("Flanke\0Quelle\0Pegel\0Kopplung\0Prätrigger\0"); if (!hitkode) break; #define ttt ((LPTOOLTIPTEXT)lParam) if (ttt->hdr.code==TTN_NEEDTEXT) ttt->lpszText=(PTSTR)Index2String(Text,hitkode&0x3F); #undef ttt }break; #endif case WM_MOUSEMOVE: { TCHAR s[256]; // Aua, jedes MouseMove! LoadString(HInstance,38,s,elemof(s)); tip->SetTip(&rcitem,s,(LPCTSTR)Index2String(s,(hitkode&0x3F)+1)); }break; case WM_RBUTTONDOWN: { HMENU m=0; switch (hitkode) { case HK_PRI+0: m=GetSubMenu(t->submenu,SUB_TFLANKE); break; case HK_PRI+1: m=GetSubMenu(t->submenu,SUB_TQUELLE); break; case HK_PRI+3: m=GetSubMenu(t->submenu,SUB_TKOPPLUNG); break; } if (m) ShowPopupMenu(m,MAKEPOINTS(lParam).x,MAKEPOINTS(lParam).y); }break; } return ANZEIGE::RelayMsg(Msg,wParam,lParam); } #ifndef WIN32 BOOL WINAPI CheckMenuRadioItemX(HMENU m,UINT i,UINT j,UINT k,UINT p) { for (; i<=j; i++) { CheckMenuItem(m,i,p|(i==k? MFT_RADIOCHECK|MF_CHECKED: MFT_RADIOCHECK|MF_UNCHECKED)); } return TRUE; } BOOL WINAPI SetMenuDefaultItemX(HMENU,UINT,UINT) { return TRUE; }; //vorerst leer, geht nur mit OwnerDraw zu lösen #endif /********************** ** Hardware-Zugriff ** **********************/ /* Mal-Routinen: Gitternetz, Kurven, Fadenkreuz, alles zusammen */ void KANAL::MaleKurve(HDC dc) { COLORREF f=farbe; int o; if (DispOpt&DO_XOR) { f^=BackColor; o=SetROP2(dc,R2_XORPEN); } if (DispOpt&DO_LINE) { HPEN KPen,OldPen; KPen=CreatePen(PS_SOLID,1,f); OldPen=(HPEN)SelectObject(dc,KPen); Polyline(dc,poly,polycount); Polyline(dc,poly+polycount,polyc2); SelectObject(dc,OldPen); DeleteObject(KPen); }else{ POINT *pp; int i; for (i=polycount+polyc2, pp=poly; i>0; i--,pp++) { SetPixel(dc,pp->x,pp->y,f); } } if (DispOpt&DO_XOR) SetROP2(dc,o); } size_t log2phys(size_t a) { // Wandelt einen logischen Sampledaten-Index in WaveHdr in einen physikalischen. // Dabei muss nur der Prätrigger-Bereich beachtet werden // BEI ROLLBETRIEB alles. // if (WaveHdr.dwFlags&WHDR_BEGINLOOP) { if (arate/zeit->div; float pixprolsb=-voltprolsb/div*step.y; // Minus weil oben positiv float pixmitte=Mitte.y-(nulllinie-voltoffset/div)*step.y; if (!WaveHdr.lpData) return; pp=(int*)poly; if (!pp) return; // Neue Samples: x=0; j=byteoffset; for (i=0; j0) NextFloat(z,i,max); else if (i<0) NextFloat(z,i,min); else if (!String2Float(s,z,e)) z=0; else if (e[0] && lstrcmp(e,T("s"))) z=0; // falsche Einheit return SetAblenkung(z); } bool ZEIT::SetAblenkung(float z) { // Bei ungültigem

erfolgt eine Initialisierung zumindest mit ! // liefert NUR "false" bei versuchtem Übergang von "gültig" zu "ungültig"! if (z<=0) { if (div>0) return false; // Kleiner/gleich Null darf es nicht sein! z=min; // Initialbedingung und keine .INI } if (div==z) return true; // Keine Änderung div=z; SetRate(samples/(div*Kaestel.x)); return InfoNeu(WAS_XABLENK); // setzt die Samplerate } bool ZEIT::SetRate(PCTSTR s) { float z; EINHEIT e; if (!String2Float(s,z,e)) z=0; else if (e[0] && lstrcmp(e,T("Sa/s")) && lstrcmp(e,T("Hz"))) z=0; return SetRate(z); } bool ZEIT::SetRate(float z) { if (z<=0) { if (rate>0) return false; z=maxrate; } if (rate==z) return true; quelle->RelayMsg(Q_SETRATE,&z); if (rate==z) return true; // immer noch unverändert! rate=z; if (zmaxrate) LadeListenVonRateMinMax(); // Neue Grenzen! Bei Soundkarten passiert so etwas return InfoNeu(WAS_RATE); } bool ZEIT::SetAnfang(PCTSTR s) { float z; EINHEIT e; if (!String2Float(s,z,e)) return false; if (e[0] && lstrcmp(e,T("s"))) return false; // Hier fehlt noch eine Umrechnung von
oder <%> return SetAnfang(z); } bool ZEIT::SetAnfang(float z) { anfang=z; // Hier fehlen Bereichstests! return InfoNeu(WAS_XANF); } bool ZEIT::SetSamples(PCTSTR s) { DWORD sa; if (_stscanf(s,T("%lu"),&sa)!=1) return false; return SetSamples(sa); } bool ZEIT::SetSamples(DWORD sa) { samples=sa; // weiter: Speicher reallozieren usw! return InfoNeu(WAS_SAMPLES); } bool String2Farbe(PCTSTR s, COLORREF &c) { bool swap=false; if (!s) return false; if (s[0]=='#') s++,swap=true; // HTML-Syntax if (_stscanf(s,T("%lx"),&c)!=1) return false; if (swap) { ((PBYTE)&c)[3]=((PBYTE)&c)[2]; // Farbangabe BGR (Windows) statt RGB (HTML) ((PBYTE)&c)[2]=((PBYTE)&c)[0]; ((PBYTE)&c)[0]=((PBYTE)&c)[3]; ((PBYTE)&c)[3]=0; } return true; } bool Farbe2String(PTSTR s, COLORREF &c) { if (!s) return false; // HTML-kompatibel konvertieren _sntprintf(s,32,T("#%02X%02X%02X"),((PBYTE)&c)[0],((PBYTE)&c)[1],((PBYTE)&c)[2]); return true; } /* DOPPELTER KODE: Identisch mit KANAL::SetFarbe */ bool ZEIT::SetFarbe(PCTSTR s) { COLORREF c; return (bool)(String2Farbe(s,c) && SetFarbe(c)); } bool ZEIT::SetFarbe(COLORREF c) { if (c==BackColor) return false; if (c==GridColor) return false; if (farbe==c) return true; // Kurzschluss wenn gleich farbe=c; return InfoNeu(WAS_FARBE); // FEHLT: Paletteneintrag beschaffen } static TCHAR sZeitVar[]=T("Ablenkung\0Rate\0Abtastwerte\0Farbe\0"); static HSZ hszZeitVar[3]; bool ZEIT::SetVar(int i, PCTSTR s) { switch (i) { case 0: return SetAblenkung(s); case 1: return kn?SetAnfang(s):SetRate(s); case 2: return SetSamples(s); case 3: return SetFarbe(s); } return false; } bool ZEIT::SetVar(PCTSTR n, PCTSTR s) { return SetVar(String2Index(sZeitVar,n),s); } bool ZEIT::SetVar(HSZ hsz,PCTSTR s) { return SetVar(hsz2Index(hszZeitVar,elemof(hszZeitVar),hsz),s); } bool ZEIT::GetVar(int i, PTSTR s) { switch (i) { case 0: Float2String(s,div,MAKEWORD(-4,0),T("s"),5); break; case 1: if (kn) Float2String(s,anfang,MAKEWORD(-4,0),T("s"),5); else Float2String(s,rate,MAKEWORD(0,3),T("Sa/s"),5); break; case 2: wsprintf(s,T("%lu"),samples); break; case 3: Farbe2String(s,farbe); break; default: return false; } return true; } bool ZEIT::GetVar(PCTSTR n, PTSTR s) { return GetVar(String2Index(sZeitVar,n),s); } bool ZEIT::GetVar(HSZ hsz,PTSTR s) { return GetVar(hsz2Index(hszZeitVar,elemof(hszZeitVar),hsz),s); } /* DREIFACHER KODE: Identisch mit KANAL::SetFarbe */ bool TRIGG::SetFarbe(PCTSTR s) { COLORREF c; return (bool)(String2Farbe(s,c) && SetFarbe(c)); } bool TRIGG::SetFarbe(COLORREF c) { if (c==BackColor) return false; if (c==GridColor) return false; if (farbe==c) return true; // Kurzschluss wenn gleich farbe=c; return InfoNeu(WAS_FARBE); // FEHLT: Paletteneintrag beschaffen } static TCHAR sTriggerVar[]=T("Flanke\0Quelle\0Pegel\0Kopplung\0Prätrigger\0Farbe\0"); static HSZ hszTriggerVar[6]; bool TRIGG::SetVar(int i, PCTSTR s) { switch (i) { case 0: return SetFlanke(s); case 1: return SetQuelle(s); case 2: return SetPegel(s); case 3: return SetKopplung(s); case 4: return SetPretrig(s); case 5: return SetFarbe(s); } return false; } bool TRIGG::SetVar(PCTSTR n, PCTSTR s) { return SetVar(String2Index(sTriggerVar,n),s); } bool TRIGG::SetVar(HSZ hsz,PCTSTR s) { return SetVar(hsz2Index(hszTriggerVar,elemof(hszTriggerVar),hsz),s); } bool TRIGG::GetVar(int i, PTSTR s) { switch (i) { case 0: wsprintf(s,T("%c"),sTrigFlanke[flanke]); break; case 1: wsprintf(s,sInt,quelle); break; // hier: numerisch case 2: Float2String(s,pegel,0,T("div")); break; // hier: in "div" case 3: lstrcpy(s,Index2String(sTrigKopplung,kopplung)); break; case 4: wsprintf(s,T("%d %%"),pretrig); break; case 5: Farbe2String(s,farbe); break; default: return false; } return true; } bool TRIGG::GetVar(PCTSTR n, PTSTR s) { return GetVar(String2Index(sTriggerVar,n),s); } bool TRIGG::GetVar(HSZ hsz,PTSTR s) { return GetVar(hsz2Index(hszTriggerVar,elemof(hszTriggerVar),hsz),s); } void ZEIT::LadeListenVonRateMinMax() { SYSINFO si; quelle->RelayMsg(Q_GETSYSINFO,&si); minrate=si.rateminmax[0]; maxrate=si.rateminmax[1]; LadeRateListe(); min=10/maxrate; // wären 10 Samples pro div, bissel wenig!? max=(float)si.depth/Kaestel.x/minrate; if (si.flags&Q_CONTINUOUS) max=100; // 100 Sekunden pro Teilstrich?? LadeAblenkListe(); } void ZEIT::LadeVorgabe() { samples=1000; // Harte, zurzeit idiotische Vorgabe!! LadeListenVonRateMinMax(); PCTSTR p; int i; for (p=sZeitVar,i=0; *p; p+=lstrlen(p)+1,i++) { TCHAR buf[32]; GetString(name,p,sLeer,buf,elemof(buf)); SetVar(i,buf); } // InfoNeu(WAS_XABLENK|WAS_RATE); } #define WM_INFONEU (WM_USER+1234) // wParam=WAS-Maske, lParam=this-Strukturptr. bool ZEIT::InfoNeu(BYTE was) { if (submenu) { TCHAR s1[32],s2[32]; if (was&(WAS_XABLENK|WAS_RATE)) { TCHAR buf[64]; Float2String(s1,div,MAKEWORD(-4,0),T("s")); if (kn) { Float2String(s2,anfang,MAKEWORD(-4,0),T("s")); }else{ Float2String(s2,rate,MAKEWORD(0,3),T("Sa"),5); // Langform } wnsprintf(buf,elemof(buf),T("%s @ %s"),s1,s2); SetMenuStringAfterTab(OsziMenu,kn,buf); } if (was&WAS_XABLENK) { Markiere(submenu,SUB_XABLENK,IDC_XABLENK,div); lstrcat(s1,T("/div")); SetMenuStringAfterTab(submenu,SUB_XABLENK,s1); // if (!(was&WAS_RATE)) SetRate(samples/(div*Kaestel.x)); // Rekursionsgefahr? } if (was&WAS_RATE) { Markiere(submenu,SUB_RATE,IDC_RATE,rate); lstrcat(s2,T("/s")); SetMenuStringAfterTab(submenu,SUB_RATE,s2); } if (was&WAS_FARBE) { Farbe2String(s1,farbe); SetMenuStringAfterTab(submenu,SUB_XFARBE,s1); } } if (anzeige) anzeige->Update(was); if (hZeitDlg && (unsigned)ZeitDlgCurSel==kn) PostMessage(hZeitDlg,WM_INFONEU,was,(LPARAM)this); return true; // liefert stets true als bequeme Rückgabe für SetXxx() } bool TRIGG::InfoNeu(BYTE was) { if (submenu) { if (was&WAS_TMODUS) { MenuRadioNextDefault(submenu,SUB_TMODUS,modus); SetMenuStringAfterTab(submenu,SUB_TMODUS,Index2String(sTrigModus,modus)); } if (was&WAS_TQUELLE) { TRIGINFO ti; ::quelle->RelayMsg(Q_GETTRIGINFO,&ti); MenuEnable(submenu,SUB_TFLANKE,ti.edges); MenuEnable(submenu,SUB_TKOPPLUNG,ti.couplings); MenuRadioNextDefault(submenu,SUB_TQUELLE,quelle); SetMenuStringAfterTab(submenu,SUB_TQUELLE,k->name); } if (was&WAS_TFLANKE) { MenuRadioNextDefault(submenu,SUB_TFLANKE,flanke); SetMenuStringAfterTab(submenu,SUB_TFLANKE,flanke?T("v"):T("^")); } if (was&WAS_TKOPPLUNG) { MenuRadioNextDefault(submenu,SUB_TKOPPLUNG,kopplung); SetMenuStringAfterTab(submenu,SUB_TKOPPLUNG,Index2String(sTrigKopplung,kopplung)); } if (was&(WAS_TMODUS|WAS_TQUELLE|WAS_TFLANKE|WAS_TKOPPLUNG)) { TCHAR s[32]; wnsprintf(s,elemof(s),T("%s %c%s %s"), Index2String(sTrigModus,modus), flanke?'-':'+', k->name, Index2String(sTrigKopplung,kopplung)); SetMenuStringAfterTab(OsziMenu,NumZeitMenu,s); } if (was&WAS_TPEGEL) { TCHAR s[32]; GetVar(2,s); SetMenuStringAfterTab(submenu,SUB_TPEGEL,s); } if (was&WAS_TPRETRIG) { TCHAR s[32]; GetVar(4,s); SetMenuStringAfterTab(submenu,SUB_TPRETRIG,s); } if (was&WAS_FARBE) { TCHAR s[32]; Farbe2String(s,farbe); SetMenuStringAfterTab(submenu,SUB_TFARBE,s); } } if (anzeige) anzeige->Update(was); if (kreuz) kreuz->Update(was); return true; // liefert stets true als bequeme Rückgabe für SetXxx() } void TRIGG::LadeVorgabe() { TRIGINFO ti; ::quelle->RelayMsg(Q_GETTRIGINFO,&ti); quelle=0; // FEHLT: Menüs erstellen (gehört eher zum Konstruktor!) PCTSTR p; int i; for (p=sTriggerVar,i=0; *p; p+=lstrlen(p)+1,i++) { TCHAR buf[32]; GetString(name,p,sLeer,buf,elemof(buf)); SetVar(i,buf); } InfoNeu(0xFF); // alles } bool ZEIT::RetteVorgabe() { bool r=true; PCTSTR p; int i; for (p=sZeitVar,i=0; *p; p+=lstrlen(p)+1,i++) { TCHAR buf[32]; GetVar(i,buf); r=bool(WriteString(name,p,buf)!=0 && r); } return r; } bool TRIGG::RetteVorgabe() { bool r=true; PCTSTR p; int i; // Eigentlich ein Iterator fällig! for (p=sTriggerVar,i=0; *p; p+=lstrlen(p)+1,i++) { TCHAR buf[32]; GetVar(i,buf); r=bool(WriteString(name,p,buf)!=0 && r); } return r; } void ZEIT::Konstruktor(int kn) { this->kn=kn; idhigh=kn<<10; div=0; // ungültiger Wert rate=0; // noch ein ungültiger Wert wnsprintf(name,elemof(name),T("%c"),'A'+kn); submenu=GetSubMenu(OsziMenu,0); if (kn) submenu=CopyPopupMenu(submenu,idhigh); TCHAR sZeitbasis[32],buf[32]; LoadString(HInstance,202,sZeitbasis,elemof(sZeitbasis)); wnsprintf(buf,elemof(buf),sZeitbasis,name); // Name der Zeitbasis einsetzen if (kn<10) InsertAmp(buf,elemof(buf),-1); (kn?InsertMenu:ModifyMenu)(OsziMenu,kn,MF_BYPOSITION|MF_POPUP,(UINT)submenu,buf); anzeige=new ZEITANZEIGE(this); // Verlinkung herstellen LadeVorgabe(); } void TRIGG::LadeQuelleMenu() { TCHAR s[64]; SYSINFO si; ::quelle->RelayMsg(Q_GETSYSINFO,&si); HMENU m=CreatePopupMenu(); TCHAR fmt[32]; LoadString(HInstance,208/*"Kanal %s"*/,fmt,elemof(fmt)); for (int i=0; iMaxKanalMenu) continue; // keinen Menüeintrag erzeugen! if (i==MaxKanalMenu) LoadString(HInstance,212/*"&Weitere Kanäle..."*/,s,elemof(s)); else{ wnsprintf(s,elemof(s),fmt,::kanal[i].name); if (i<10) InsertAmp(s,elemof(s),-1); // vor letztes (Zahl-)Zeichen } }else LoadString(HInstance,204/*"&Extern"*/,s,elemof(s)); InsertMenu(m,(UINT)-1,MF_BYPOSITION,IDC_TQUELLE+(i<<10),s); } SetMenuPopup(submenu,SUB_TQUELLE,m); } void TRIGG::Konstruktor(int) { wnsprintf(name,elemof(name),T("%c"),'T'); submenu=GetSubMenu(OsziMenu,NumZeitMenu); modus=TM_AUTO; quelle=0; LadeQuelleMenu(); flanke=TF_STEIG; kopplung=TK_DC; SetQuelle(0); // besser: vom Oszi holen! pretrig=0; pegel=0; LadeVorgabe(); anzeige=new TRIGGERANZEIGE(this); // Verlinkung herstellen kreuz=new KREUZ(this); InfoNeu(0xFF); } void ZEIT::Destruktor() { RetteVorgabe(); delete anzeige; if (kn) DeleteMenu(OsziMenu,kn,MF_BYPOSITION); } void TRIGG::Destruktor() { RetteVorgabe(); if (quelle>=numkanal) delete k; delete kreuz; delete anzeige; } void ZEIT::LadeAblenkListe() { // Aufrufen bei LadeXVorgabe HMENU m; m=CreatePopupMenu(); float z; float e; int idx; TCHAR buf[64]; z=min; e=max; for (idx=NextFloat(z,0); z<=e; idx=NextFloat(z,1)) { Float2String(buf,z,MAKEWORD(-4,0),T("s"),5); // von ps bis s InsertMenu(m,0,MF_BYPOSITION|MFT_RADIOCHECK,IDC_XABLENK+idx+idhigh,buf); // Rückwärts einsortieren! } AppendAndereToMenu(m,elemof(Reihe)+IDC_XABLENK); SetMenuPopup(submenu,SUB_XABLENK,m); } void AppendRateToMenu(HMENU m, UINT id, float z) { // Hängt Samplerate an Popup-Menü mit ID an // Hilfsfunktion für ZEIT::LadeRateListe TCHAR buf[32]; Float2String(buf,z,MAKEWORD(0,3),T("Sa"),5); // hier: Kurz-Einheit! InsertMenu(m,(UINT)-1,MF_BYPOSITION|MFT_RADIOCHECK,id,buf); // Vorwärts sortieren } void ZEIT::LadeRateListe() { // Erzeugt Popup-Menü mit Sampleraten, inklusive absolut minimaler // und maximaler, soweit unterschiedlich von der 1-2-5-Reihe // Aufrufen bei ZEIT::LadeVorgabe und wenn sich (plötzlich) // minimale und maximale Samplerate ändert(e) HMENU m; int idx; float z; m=CreatePopupMenu(); z=minrate; idx=NextFloat(z,0); if (z!=minrate) AppendRateToMenu(m,IDC_RATE+elemof(Reihe)+3+idhigh,minrate); for (; z<=maxrate; idx=NextFloat(z,1)) { AppendRateToMenu(m,IDC_RATE+idx+idhigh,z); if (z==maxrate) goto keinmax; } if (minrate!=maxrate) AppendRateToMenu(m,IDC_RATE+elemof(Reihe)+4+idhigh,maxrate); keinmax: AppendAndereToMenu(m,IDC_RATE+elemof(Reihe)+idhigh); SetMenuPopup(submenu,SUB_RATE,m); } bool TRIGG::SetModus(MODUS m) { if (m>TM_SINGLE) return false; if (modus==TM_AUTO) KillTimer(MainWnd,3); modus=m; if (modus==TM_AUTO) SetTimer(MainWnd,3,500,NULL); return InfoNeu(WAS_TMODUS); } bool TRIGG::SetModus(PCTSTR s) { int m=String2Index(sTrigModus,s); if (m<0 && _stscanf(s,sInt,&m)!=1) return false; return SetModus((MODUS)m); } bool TRIGG::SetFlanke(FLANKE f) { if ((unsigned)f>=2) return false; if (flanke==f) return true; flanke=f; TRIG t; t.what=TRIG_EDGE; t.edge=(BYTE)f; ::quelle->RelayMsg(Q_SETTRIG,&t); // kann simuliert werden...??? return InfoNeu(WAS_TFLANKE); } bool TRIGG::SetFlanke(PCTSTR s) { int fl; if (!s) return false; if (!s[1]) { if (*s==sTrigFlanke[0]) {fl=0; goto habs;} if (*s==sTrigFlanke[1]) {fl=1; goto habs;} } if (_stscanf(s,sInt,&fl)!=1) return false; habs: return SetFlanke((FLANKE)fl); } bool TRIGG::SetQuelle(int q) { if (quelle!=q) { TRIG t; t.what=TRIG_SOURCE; t.source=(BYTE)q; ::quelle->RelayMsg(Q_SETTRIG,&t); } if (quelle>=numkanal) delete k; // Dummy-Kanal löschen quelle=q; if (quellename,T("Ext")); k->div=1; k->praefixe=0; lstrcpy(k->einheit,T("V")); k->nulllinie=0; k->farbe=farbe; SetPegel(0.0); } return InfoNeu(WAS_TQUELLE); } bool TRIGG::SetQuelle(PCTSTR s) { // in div oder der Einheit des Kanals int q=numkanal; if (!lstrcmpi(s,T("Ext"))) goto habs; if (kanal) for (q=0; q if (abs(rndint(p-0.5))>2*Kaestel.y) return false; if (fabs(p)<1E-3) p=0; // Sollte sicher Null sein if (!k) return false; TRIG t; t.what=TRIG_LEVEL; t.level=rund(p*k->div/k->voltprolsb); // SoftTrigger sofort setzen! Kontinuierliche Datenquellen brauchen's nicht ::quelle->RelayMsg(Q_SETTRIG,&t); pegel=t.level*k->voltprolsb/k->div; // RÜCK-BERECHNUNG! if (pegel==p) return true; return InfoNeu(WAS_TPEGEL); } bool TRIGG::SetPegel(PCTSTR s) { // Sonderfälle: +, ++, +? float p; EINHEIT e; int i=String2UpDown(s,1,10); if (i) p=pegel+i*0.1F; else{ String2Float(s,p,e); if (*e) { if (!lstrcmp(e,k->einheit)) { p/=k->div; // Volt / Volt/div = div }else if (lstrcmpi(e,T("div"))) return false; } } return SetPegel(p); } bool TRIGG::SetKopplung(KOPPLUNG k) { if ((unsigned)k>7) return false; TRIG t; t.what=TRIG_COUPLING; t.coupling=(BYTE)k; ::quelle->RelayMsg(Q_SETTRIG,&t); // Simulation?? kopplung=k; return InfoNeu(WAS_TKOPPLUNG); } bool TRIGG::SetKopplung(PCTSTR s) { int k; if (!s) return false; k=String2Index(sTrigKopplung,s); if (k<0 && _stscanf(s,sInt,&k)!=1) return false; return SetKopplung((KOPPLUNG)k); } bool TRIGG::SetPretrig(int pt) { if (pt<-100) return false; if (pt>100) return false; TRIG t; t.what=TRIG_PRE; t.pre=MulDiv(pt,(int)zeit->samples,100); ::quelle->RelayMsg(Q_SETTRIG,&t); pretrig=pt; return InfoNeu(WAS_TPRETRIG); } bool TRIGG::SetPretrig(PCTSTR s) { int pt; float t; EINHEIT e; pt=String2UpDown(s,1,10); if (pt) pt+=pretrig; else{ if (!String2Float(s,t,e)) return false; pt=rund(t); // Wenn ohne Einheit, dann in Prozent if (*e) { if (!lstrcmp(e,T("s"))) { pt=rund(t*100/zeit->div/Kaestel.x); }else if (!lstrcmpi(e,T("div"))) { pt=rund(t*100/Kaestel.x); }else if (lstrcmp(e,T("%"))) return false; } } return SetPretrig(pt); } void ZeigeSimul(HMENU m, UINT idx, BYTE echt) { TCHAR s[64],*p; GetMenuString(m,idx,s,elemof(s),MF_BYPOSITION); p=AfterTab(s); if (echt) *--p=0; // ohne Simulation else LoadString(HInstance,213,p,int(s+elemof(s)-p)); //"simuliert" SetMenuString(m,idx,s); } /**************************************************************************** ** Wegen der fehlenden with-Anweisung ersparen Objekte in C++ tatsächlich ** ** Schreibarbeit; deshalb fortan Y-bezogenes als Memberfunktionen ** ****************************************************************************/ static TCHAR sKanalVar[]=T("Name\0Tastkopf\0Ablenkung\0Kopplung\0Nulllinie\0Farbe\0"); static HSZ hszKanalVar[6]; void KANAL::LadeVorgabe() { CHANINFO ci; ci.ch=(BYTE)kn; quelle->RelayMsg(Q_GETCHANINFO,&ci); min=ci.voltminmax[0]*5; // minimal: 5 Stufen pro div Auflösung max=ci.voltminmax[1]*FullScale*numkanal; // maximal: alle Traces geradeso byteoffset=ci.byteoffset; maske=ci.mask; if (submenu) { HMENU m=GetSubMenu(submenu,SUB_YKOP); // DC-Kopplung kann nicht aus AC simuliert werden! EnableMenuItem(m,0, ci.couplings&CHANINFO_DC?MF_ENABLED|MF_BYPOSITION:MF_GRAYED|MF_BYPOSITION); ZeigeSimul(m,1,(BYTE)(ci.couplings&CHANINFO_AC)); ZeigeSimul(m,2,(BYTE)(ci.couplings&CHANINFO_GND)); } CHAN c; c.ch=(BYTE)kn; c.what=0; // Nur lesen quelle->RelayMsg(Q_SETCHAN,&c); kopplung=c.coupling; voltprolsb=c.volt; voltoffset=c.dcoffset; // div=chan.volt*fullscale/fTastkopf/Kaestel.y; // NextFloat(div,0); TCHAR buf[32]; PCTSTR p; int i; for (p=sKanalVar,i=0; *p; p+=lstrlen(p)+1,i++) { GetString(name,p,sLeer,buf,elemof(buf)); SetVar(i,buf); } idhigh=kn<<10; if (poly) delete poly; poly=new POINT[(int)zeit->samples]; } bool KANAL::RetteVorgabe() { bool r=true; int i; PCTSTR p; for (p=sKanalVar,i=0; *p; p+=lstrlen(p)+1,i++) { TCHAR buf[32]; GetVar(i,buf); r=bool(WriteString(name,p,buf)!=0 && r); } return r; } void KANAL::LadeAblenkListe() { // AUFRUFEN bei Änderung von Datenquelle oder Tastteiler, oder Vorzeichen! HMENU m=CreatePopupMenu(); float z=min/*fTastkopf*/; float e=max/*fTastkopf*/; int idx; TCHAR buf[64]; for (idx=NextFloat(z,0); z<=e; idx=NextFloat(z,+1)) { Float2String(buf,div<0?-z:z,praefixe,einheit); InsertMenu(m,0,MF_BYPOSITION|MFT_RADIOCHECK,idx+IDC_YABL+idhigh,buf); } SetMenuPopup(submenu,SUB_YABL,m); } int KANAL::GetTastkopfIndex() { // fürs Menü usw. if (lstrcmp(einheit,T("V"))) return 2; if (fTastkopf==1) return 0; if (fTastkopf==10) return 1; return 2; } bool KANAL::SetNamen(PCTSTR s) { TCHAR buf[32]; int l=lstrlen(s); if (l>=elemof(sNamen)) return false; // zu lang if (!lstrcmp(s,sNamen)) return true; // Gleich geblieben if (!::GetNameList(s,buf,NULL)) return false; // ungültige Syntax lstrcpy(sNamen,s); return InfoNeu(WAS_YNAM); } bool KANAL::SetTastkopf(PCTSTR s) { float z,n; EINHEIT e; int i,j,k,l=lstrlen(s); if (l>=elemof(sTastkopf)) goto falsch; // zu lang zum Speichern lstrcpy(e,T("V")); e[ELEN-1]=0; // zwangsterminieren i=_stscanf(s,T("%f:%f%n %") ELENSTR T("[^ -\x40[-`{-\x7F]/V%n"),&z,&n,&j,e,&k); if (i==2 && j==l) goto ok; if (i==3 && k==l) goto ok; // 2. Versuch der Interpretation i=_stscanf(s,T("%f%") ELENSTR T("[^ -@[-`{-\x7F]:%fV%n"),&z,e,&n,&k); if (i==3 && k==l) { ok: if (!n || !z || !e[0]) goto falsch; lstrcpy(einheit,e); praefixe=wPrefix; // vom Setup (normalerweise p..G) // Die Begrenzung der Vorsätze ist einheiten-abhängig, etwa: // keine Kilosekunden (max=0), Megagramm (max=1, Tonne keine hübsche // Alternative, denn es gibt keine Kilotonne, außer bei Sprengstoff), // weder Milli- noch Kilomol (min=max=0), ebenso bei (Bruttoregister)Tonne usw. if (!e[1]) switch (e[0]) { case 's': ((BYTE*)&praefixe)[1]=0; break; // Sekunden (keine Kilosek.) case 'm': // Meter (keine Megameter) case 'g': ((BYTE*)&praefixe)[1]=1; break; // Gramm (keine Megagramm) case 't': praefixe=0; // Tonne (keine Vorsätze) } z/=n; // rechenwirksames Tastkopf-Verhältnis (10:1->10) n=fTastkopf; // vorheriges Tastkopf-Verhältnis retten fTastkopf=z; // neues Tastkopf-Verhältnis setzen if (n) { z/=n; // z/n = Verhältnis beider (1:1->10:1 -> z=10) min*=z; max*=z; // Grenzen für (sinnvolle) Koeffizienten ändern SetAblenkung(div*z); // "div" ändern, da voltprolsb konstant bleiben soll } lstrcpy(sTastkopf,s); return InfoNeu(WAS_YVOR); } falsch: if (!fTastkopf) SetTastkopf(T("1:1")); // jaja, Rekursion! return false; // 2 Zahlen müssen es mindestens sein! } // Kopplungs-Strings in Zahl 0..2 umwandeln bool IsKopplung1(PCTSTR s, UINT&v) { int k=String2Index(sKopplung1,s); if (k<0) return false; v=k; return true; } bool IsKopplung2(PCTSTR s, UINT&v) { if (!s[0]) return false; if (s[1]) return false; PCTSTR p=StrChr(sKopplung2,s[0]); if (!p) return false; v=UINT(p-sKopplung2); return true; } bool KANAL::SetAblenkung(PCTSTR s) { // Bei ungültigem
erfolgt auf jeden Fall eine Initialisierung float z=0; EINHEIT e; int l=lstrlen(s); UINT k=kopplung; if (l) { IsKopplung2(s+--l,k); // SCHIFFBRUCH BEI DBCS!!! z=div; int i=String2UpDown(s,1,1); if (i>0) NextFloat(z,i,max/*fTastkopf*/); else if (i<0) NextFloat(z,i,min/*fTastkopf*/); else if (!String2Float(s,z,e)) z=0; else if (e[0] && lstrcmp(e,einheit)) z=0; // falsche Einheit } SetKopplung(k); return SetAblenkung(z); } bool KANAL::SetAblenkung(float z) { // Negative Zahlen führen entsprechend zur Invertierung CHAN chan; BYTE was=WAS_YABL; if (!z) { if (div) return false; // Null darf es nicht werden! z=max; // max = Linksanschlag } if (div==z) return true; if (div*z<0) was|=WAS_YINV; // Invertierung dazu div=z; chan.what=CHAN_VOLT; chan.ch=(BYTE)kn; chan.volt=z*Kaestel.y/fTastkopf/FullScale; quelle->RelayMsg(Q_SETCHAN,&chan); voltprolsb=chan.volt; // rücklesen, zur Skalierung voltoffset=chan.dcoffset; if (trig && trig->k==this) trig->SetPegel(trig->pegel); return InfoNeu(was); } bool KANAL::SetNulllinie(PCTSTR s) { // wird vom Dialog und von DDEPOKE aufgerufen float z=nulllinie; EINHEIT e; int i=String2UpDown(s,1,1); if (i) z+=i; else{ if (!String2Float(s,z,e)) return false; if (*e) { if (!lstrcmp(e,einheit)) z/=div; else if (lstrcmpi(e,T("div"))) return false; // falsche Einheit } } return SetNulllinie(z); // in div } bool KANAL::SetNulllinie(float z) { CHAN c; if (nulllinie==z) return true; nulllinie=z; c.what=CHAN_DCOFFSET; c.ch=(BYTE)kn; c.dcoffset=z*div; quelle->RelayMsg(Q_SETCHAN,&c); // Falls die Quelle einen Offset beherrscht... voltoffset=c.dcoffset; // rücklesen if (trig && trig->k==this && trig->kreuz) trig->kreuz->Update(WAS_TPEGEL); return InfoNeu(WAS_YNUL); } bool KANAL::SetKopplung(PCTSTR s) { UINT k; if (!s) return false; if (!IsKopplung1(s,k) && !IsKopplung2(s,k)) return false; return SetKopplung(k); } bool KANAL::SetKopplung(UINT k) { if (k>=3) return false; // Etwas anderes als DC,AC,GND gibt es nicht if (kopplung==k) return true; // (Noch nicht!) CHAN c; c.ch=(BYTE)kn; c.what=(BYTE)CHAN_COUPLING; c.coupling=(BYTE)(k); if (!quelle->RelayMsg(Q_SETCHAN,&c)) return false; kopplung=k; if (k==CHAN_DC && c.coupling==CHAN_AC) kopplung=CHAN_AC; // DC-Kopplung kann nicht simuliert werden! Menüpunkt ist grau. getsample=GetSampleDc; if (k==CHAN_AC && c.coupling==CHAN_DC) getsample=GetSampleAc; // Simulation der AC-Kopplung mittels GetSampleAc if (k==CHAN_GND && c.coupling!=CHAN_GND) getsample=GetSampleGnd; // Simulation der GND-Kopplung durch brutales Null-Liefern return InfoNeu(WAS_YKOP); } // Andere Kopplungen, wie Klemmung+, Klemmung- usw. sind denkbar. bool KANAL::SetFarbe(PCTSTR s) { COLORREF c; return (bool)(String2Farbe(s,c) && SetFarbe(c)); } bool KANAL::SetFarbe(COLORREF c) { if (c==BackColor) return false; if (c==GridColor) return false; if (farbe==c) return true; // Kurzschluss wenn gleich farbe=c; return InfoNeu(WAS_FARBE); // FEHLT: Stift, Pinsel, Paletteneinträge beschaffen } bool GRUPPE::SetVar(int i, PCTSTR s) { bool r=true; for (int k=0; k invertieren bei _echter_ Inversion Float2String(buf,div,praefixe,einheit); wnsprintf(s,elemof(s),T("%c %s %c"), sTastkopf2[GetTastkopfIndex()], buf, sKopplung2[kopplung]); } bool KANAL::InfoNeu(BYTE was) { TCHAR buf[64]; HMENU m; // Untermenü if (submenu) { // Kanäle >16 oder so bekommen kein Untermenü... if (was&(WAS_YVOR|WAS_YINV)) { LadeAblenkListe(); } if (was&WAS_YVOR) { int j=GetTastkopfIndex(); m=GetSubMenu(submenu,SUB_YVOR); CheckMenuRadioItem(m,0,2,j,MF_BYPOSITION); if (j<2) j^=1; // bei User-Tastkopf bleibt die Vorgabe benutzerdefiniert SetMenuDefaultItem(m,j,MF_BYPOSITION); SetMenuStringAfterTab(submenu,SUB_YVOR,sTastkopf); } if (was&WAS_YINV) { // zieht stets WAS_YABL nach sich bool neg=bool(div<0); CheckMenuItem(submenu,SUB_YINV, neg?MF_BYPOSITION|MF_CHECKED:MF_BYPOSITION|MF_UNCHECKED); SetMenuStringAfterTab(submenu,SUB_YINV,neg?T("--"):T("+")); } if (was&WAS_YABL) { Markiere(submenu,SUB_YABL,IDC_YABL+idhigh,div); Float2String(buf,div,praefixe,einheit); lstrcat(buf,T("/div")); SetMenuStringAfterTab(submenu,SUB_YABL,buf); } if (was&WAS_YKOP) { m=GetSubMenu(submenu,SUB_YKOP); CheckMenuRadioItem(m,0,2,kopplung,MF_BYPOSITION); SetMenuDefaultItem(m,GetMenuState(m,0,MF_BYPOSITION)==MF_GRAYED?kopplung==1?2:1: kopplung==0?1:0,MF_BYPOSITION); SetMenuStringAfterTab(submenu,SUB_YKOP,Index2String(sKopplung1,kopplung)); } if (was&WAS_YNUL) { CalcGraf(); Inval(false); } if (was&(WAS_YVOR|WAS_YABL|WAS_YKOP)) { GetInfoString(buf); SetMenuStringAfterTab(OsziMenu,NumZeitMenu+NumTrigMenu+kn,buf); } if (was&WAS_YNUL) { Float2String(buf,nulllinie,0,T("div")); SetMenuStringAfterTab(submenu,SUB_YNUL,buf); } if (was&WAS_YNAM) { SetMenuStringAfterTab(submenu,SUB_YNAM,sNamen); } if (was&WAS_FARBE) { Farbe2String(buf,farbe); SetMenuStringAfterTab(submenu,SUB_YFARBE,buf); } } if (was&WAS_YNAM) MacheGruppenListe(); if (masse) masse->Update(was); if (anzeige) anzeige->Update(was); // Zu tun: hKanalDlg, DDEADV aktualisieren return true; } bool KANAL::HatName(PCTSTR n) { // Testet, ob Name enthalten ist // Liefert auch bei Kanalbezeichnung (bspw. "Y1") // sowie wenn n=NULL (bedeutet hier "alle Kanäle") TCHAR buf[32],*p; if (!n) return true; if (!*n) return true; if (!lstrcmpi(n,name)) return true; GetNameList(buf,NULL); for (p=buf; *p; p+=lstrlen(p)+1) { if (!lstrcmpi(p,n)) return true; } return false; } /**************************************************** ** Dialoge (erst modusbehaftete, dann modusfreie) ** ****************************************************/ static int LoadWinPos(HWND Wnd, PCTSTR key) { // Liefert den Sichtbarkeitsstatus, auch bei Wnd=0, zum Wieder-Öffnen des Dialogs // Lädt Position und, wenn gegeben und WS_THICKFRAME, auch die Größe TCHAR buf[32]; WINDOWPLACEMENT wp; RECT r; int showCmd; InitStruct(&wp,sizeof(wp)); if (Wnd) GetWindowPlacement(Wnd,&wp); GetString(S_Position,key,sLeer,buf,elemof(buf)); switch (_stscanf(buf,sProzentI,&r.left,&r.top,&r.right,&r.bottom,&showCmd)) { case 2: r.right=wp.showCmd; nobreak; case 3: { // feste Fenstergröße showCmd=r.right; r.right=r.left+wp.rcNormalPosition.right-wp.rcNormalPosition.left; r.bottom=r.top+wp.rcNormalPosition.bottom-wp.rcNormalPosition.top; }break; case 4: showCmd=wp.showCmd; nobreak; case 5: if (!Wnd || GetWindowStyle(Wnd)&WS_THICKFRAME) break; default: return SW_HIDE; // Alles andere ist Fehler! } // (auch einem Fenster ohne WS_THICKFRAME die Größe setzen zu wollen) if (Wnd) { MoveRectIntoFullScreen(&r); // Bei Win32 angeblich nicht notwendig CopyRect(&wp.rcNormalPosition,&r); // if (showCmd) wp.showCmd=showCmd; // nie "hidden" setzen SetWindowPlacement(Wnd,&wp); } return showCmd; } static void SaveWinPos(HWND Wnd, PCTSTR key, bool state=false) { // Setzt den Sichtbarkeitsstatus auf SW_HIDE wenn state=false ist // Speichert Position -- sowie Größe wenn Fenster WS_THICKFRAME hat WINDOWPLACEMENT wp; TCHAR buf[32],*p=buf; if (!Wnd) return; // Fenster muss noch vorhanden sein! InitStruct(&wp,sizeof(wp)); GetWindowPlacement(Wnd,&wp); if (!state) wp.showCmd=0; p+=wsprintf(p,sProzentI+9,wp.rcNormalPosition.left,wp.rcNormalPosition.top); if (GetWindowStyle(Wnd)&WS_THICKFRAME) p+=wsprintf(p,sProzentI+8, wp.rcNormalPosition.right,wp.rcNormalPosition.bottom); if (wp.showCmd) wsprintf(p,sProzentI+11,wp.showCmd); WriteString(S_Position,key,buf); } static INT_PTR CALLBACK AboutDlgProc(HWND Wnd, UINT Msg, WPARAM wParam, LPARAM){ switch (Msg) { case WM_INITDIALOG: { LoadWinPos(Wnd,T("Über")); }return TRUE; case WM_COMMAND: switch (LOWORD(wParam)){ case 1: case 2: SaveWinPos(Wnd,T("Über")); EndDialog(Wnd,wParam); }break; } return FALSE; } bool ScanXY(PCTSTR s, PPOINT p) { // sscanf auf String der Form %dx%d ausführen und in p speichern, // dabei werden beide Koordinaten auf 2..100 begrenzt // Liefert false bei Fehler int x,y; if (_stscanf(s,T("%dx%d"),&x,&y)==2 && 2<=x && x<=100 && 2<=y && y<=100) { p->x=x; p->y=y; return true; } return false; } void PrintXY(PTSTR s, const POINT *p) { _sntprintf(s,32,T("%dx%d"),p->x,p->y); } bool ScanPr(PCTSTR s, WORD &pr) { TCHAR a,e; PTSTR pa,pe; if (_stscanf(s,T("%c..%c"),&a,&e)!=2) return false; pa=Prefix2Ptr(a); if (!pa) return false; pe=Prefix2Ptr(e); if (!pe) return false; if (pa>pe) return false; pr=MAKEWORD(pa-ISO_Prefixes-6,pe-ISO_Prefixes-6); return true; } void PrintPr(PTSTR s, WORD pr) { _sntprintf(s,32,T("%c..%c"),ISO_Prefixes[(signed char)LOBYTE(pr)+6], ISO_Prefixes[(signed char)HIBYTE(pr)+6]); } /********************************** ** Allgemeine Dialog-Behandlung ** **********************************/ #define WM_CHECKDIALOG (WM_USER+2) // konsequente Fortsetzung vom #define WM_TAKEDIALOG (WM_USER+3) // WM_INITDIALOG-Konzept, oder? // In beiden F„llen ist lParam=DWL_USER=Parameter von ...Dialog...Param // WM_CHECKDIALOG muss im Fehlerfall mindestens eins von beiden tun: // LOWORD(lParam) auf die fehlerhafte Fenster-ID setzen, // HIWORD(lParam) auf die String-ID fr MessageBox setzen // und damit MyDlgHandler aufrufen - oder DWL_DLGRESULT setzen #define IDAPPLY 3 #define IDAUTOAPPLY 4 #define IDTIMEDAPPLY 5 #define IDHELP 9 #define PROP_DDEADV 1 // DDEADVISE aktiv (normal gelb) #define PROP_DIVERS 2 // Verschiedene Werte in Gruppe (normal grau) #define PROP_ERROR 4 // Fehler (normal rot) void ChangeProp(HWND Wnd, UINT and, UINT xor) { UINT o=(UINT)GetProp(Wnd,MAKEINTATOM(atom)); UINT n=(o&and)^xor; if (o==n) return; if (n) SetProp(Wnd,MAKEINTATOM(atom),(HANDLE)n); else RemoveProp(Wnd,MAKEINTATOM(atom)); InvalidateRect(Wnd,NULL,TRUE); } void ChangeProp(HWND Wnd, UINT id, UINT and, UINT xor) { ChangeProp(GetDlgItem(Wnd,id),and,xor); } #define WM_SHOWITEMS (WM_USER+100) #define AutoUpdate_id 3 #define AutoUpdate_ms 500 #define EN_STEPUP (EN_VSCROLL+0x10) #define EN_STEPDOWN (EN_STEPUP+1) WNDPROC DefEditProc; LRESULT CALLBACK EditHook(HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam) { UINT dir=0; switch (Msg) { case WM_KEYDOWN: switch (wParam) { case VK_UP: dir=EN_STEPUP; break; case VK_DOWN: dir=EN_STEPDOWN; break; }break; case WM_VSCROLL: switch (LOWORD(wParam)) { case SB_LINEUP: dir=EN_STEPUP; break; case SB_LINEDOWN: dir=EN_STEPDOWN; break; }break; case WM_DESTROY: ChangeProp(Wnd,0,0); break; } if (dir) { SendMessage(CONTROLPARAMS3(WM_COMMAND,Wnd,dir)); return 0; } return CallWindowProc(DefEditProc,Wnd,Msg,wParam,lParam); } // Standard-Dialogprozedur für meine Dialoge (modal oder moduslos): // * Position aus INI-Datei speichern/wiederherstellen // * WM_ACTIVATE, WM_HELP behandeln // * alle einzeiligen EDITs subklassifizieren für UpDown BOOL MyDlgHandler(HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam, UINT id, HWND *wp, PTSTR PosKey) { switch (Msg) { case WM_INITDIALOG: { SetWindowLongPtr(Wnd,DWLP_USER,lParam); // Compiler beruhigen (nur Win32) if (PosKey) LoadWinPos(Wnd,PosKey); for (HWND w=GetFirstChild(Wnd); w; w=GetNextSibling(w)) { TCHAR s[8]; GetClassName(w,s,elemof(s)); if (!lstrcmpi(s,T("EDIT"))) DefEditProc=SubclassWindow(w,EditHook); } }return TRUE; // Fokus setzen _lassen_ case WM_ACTIVATE: if (wp) hKBHand=wParam?Wnd:0; break; case WM_HELP: { WinHelp(Wnd,HelpFileName,HELP_CONTEXTPOPUP, MAKELONG(id,((LPCHELPINFO)lParam)->iCtrlId)); }break; #ifdef WIN32 case WM_CTLCOLOREDIT: { #else case WM_CTLCOLOR: if (HIWORD(lParam)==CTLCOLOR_EDIT){ #endif int i=(int)GetProp(Wnd,MAKEINTATOM(atom)); if (i) { SetBkMode((HDC)wParam,TRANSPARENT); return (BOOL)EditBrushes[bsf(i)]; // Nummer des höchsten Bits! } }return TRUE; case WM_TIMER: if (wParam==AutoUpdate_id) { KillTimer(Wnd,wParam); SendMessage(Wnd,WM_COMMAND,IDTIMEDAPPLY,0); }break; case WM_CHECKDIALOG: SetWindowLongPtr(Wnd,DWLP_MSGRESULT,lParam); nobreak; case WM_TAKEDIALOG: return TRUE; // kein DefDlgProc case WM_COMMAND: { switch (LOWORD(wParam)){ case IDHELP: WinHelp(Wnd,HelpFileName,HELP_CONTEXT,id); break; case IDAUTOAPPLY: { BOOL state=IsDlgButtonChecked(Wnd,IDAUTOAPPLY)-1; EnableDlgItem(Wnd,IDAPPLY,state); if (state) break; }nobreak; case IDTIMEDAPPLY: case IDAPPLY: case IDOK: { lParam=SendMessage(Wnd,WM_CHECKDIALOG,0,GetWindowLongPtr(Wnd,DWLP_USER)); if (lParam) { if (LOWORD(wParam)<=IDAPPLY) { // Ohne explizite Aufforderung nicht meckern if (LOWORD(lParam)) SetEditFocus(Wnd,LOWORD(lParam)); if (HIWORD(lParam)) MBox(Wnd,HIWORD(lParam),MB_OK|MB_ICONEXCLAMATION); } break; // BUG: Nicht immer Edit! } SendMessage(Wnd,WM_TAKEDIALOG,0,GetWindowLongPtr(Wnd,DWLP_USER)); if (LOWORD(wParam)!=IDOK) break; } case IDCANCEL: { if (PosKey) SaveWinPos(Wnd,PosKey); if (wp) { *wp=0; DestroyWindow(Wnd); }else{ EndDialog(Wnd,LOWORD(wParam)); } }break; } switch (GET_WM_COMMAND_CMD(wParam,lParam)) { case CBN_EDITCHANGE: { TCHAR s[12]; GetClassName((HWND)lParam,s,elemof(s)); if (lstrcmpi(s,T("COMBOBOX"))) break; }nobreak; case EN_CHANGE: { ChangeProp((HWND)lParam,~PROP_ERROR,0); // bei Änderung nicht rot!? if (IsDlgButtonChecked(Wnd,4) && !SetTimer(Wnd,AutoUpdate_id,AutoUpdate_ms,NULL)) PostMessage(Wnd,WM_TIMER,AutoUpdate_id,0); }break; } } } return FALSE; } void FarbRechteck(HDC dc,LPCRECT rc,COLORREF f) { // Zeichnet (für Dialogboxen) umrandete Rechecke mit der Farbe f ausgefüllt // Umrandung ist schwarz; weiß bei dunkler Farbe. Inhalt zweigeteilt. HPEN p; HBRUSH br; int m; RECT r; CopyRect(&r,rc); m=(r.left+r.right)>>1; // 1. Pattern-Farbe (links) r.right=m; br=CreateSolidBrush(f); FillRect(dc,&r,br); DeleteBrush(br); r.right=rc->right; // 2. Einheitliche Farbe (rechts) r.left=m; br=CreateSolidBrush(GetNearestColor(dc,f)); FillRect(dc,&r,br); DeleteBrush(br); r.left=rc->left; // 3. Rand (schwarz oder weiß [keine Farbkomponente >=128]) p=SelectPen(dc,GetStockPen(f&0x808080L?BLACK_PEN:WHITE_PEN)); br=SelectBrush(dc,GetStockBrush(HOLLOW_BRUSH)); // nur Rand Rectangle(dc,r.left,r.top,r.right,r.bottom); SelectBrush(dc,br); SelectPen(dc,p); } static INT_PTR CALLBACK DisplayDlgProc(HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam){ switch (Msg) { case WM_INITDIALOG: { TCHAR s[32]; SetCheckboxGroup(Wnd,101,108,DispOpt); PrintXY(s,&Kaestel); SetDlgItemText(Wnd,120,s); PrintXY(s,&SubTick); SetDlgItemText(Wnd,121,s); #ifndef WIN32 KillTimer(Wnd,3); // In 16-bit-Windows erforderlich? #endif }break; case WM_TIMER: { TCHAR s[32]; KillTimer(Wnd,wParam); if (GetModifiedEditItemText(Wnd,120,s,elemof(s))) { if (ScanXY(s,&Kaestel)) { wmSize(ClientExt.x,ClientExt.y); }else MessageBeep(MB_ICONEXCLAMATION); } if (GetModifiedEditItemText(Wnd,121,s,elemof(s))) { if (ScanXY(s,&SubTick)) { wmSize(ClientExt.x,ClientExt.y); }else MessageBeep(MB_ICONEXCLAMATION); } }break; case WM_COMMAND: switch (LOWORD(wParam)){ case 101: case 102: case 103: case 104: case 105: case 108: { SetDispOpt(DispOpt^(1<<(wParam-101)),0); }break; case 120: case 121: { if (GET_WM_COMMAND_CMD(wParam,lParam)==EN_CHANGE) SetTimer(Wnd,3,500,NULL); }break; case 122: { Kaestel.x=10; Kaestel.y=8; SubTick.x=5; SubTick.y=5; DisplayDlgProc(Wnd,WM_INITDIALOG,0,0); wmSize(ClientExt.x,ClientExt.y); }break; case 111: if (FarbAuswahl(Wnd,GridColor)) SetDispOpt(DispOpt,DO_GRID); break; case 112: if (FarbAuswahl(Wnd,BackColor)) SetDispOpt(DispOpt,DO_BACK); break; case 1: DisplayDlgProc(Wnd,WM_TIMER,3,0); // evtl. Editfelder übernehmen }break; } return MyDlgHandler(Wnd,Msg,wParam,lParam,112,&hDisplayDlg,T("Anzeige")); } // Grundlegende Einstellungen: Kanalnamen-Präfix, Zählweise (MODAL) // Bonus: Ist eine Einstellung von Zählweise und Dezimaltrenner // per Modifikation der OSZI.INI gemacht worden, dann ist kein RadioButton // aktiv, und beim Übernehmen wird, wenn nichts gecheckt, dann auch // nicht verändert. Wenn also bspw. Oktal-Zählung, Start ab 200, // 5 reservierte Stellen und ein „ oder TEN (Punkt in der Mitte für Chinesen) // als Dezimaltrenner bevorzugt werden, dann bitteschön! static INT_PTR CALLBACK GrundDlgProc(HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam){ static const TCHAR sPunktKomma[]=T("?.,"); switch (Msg) { case WM_INITDIALOG: { TCHAR s[32]; {PTSTR p; lstrcpy(s,sKanalFormat); p=StrChr(s,'%'); if (p) { *p++=0; // Präfix von Formatanweisung trennen if (*p=='0') { CheckDlgButton(Wnd,107,TRUE); // Führende Null (bei 1 Stelle) p+=2; } switch (*p) { case 'd': case 'i': case 'u': CheckDlgButton(Wnd,104,TRUE); break; // dezimal zählen case 'x': case 'X': CheckDlgButton(Wnd,105,TRUE); break; // hexadezimal zählen } } } SetDlgItemText(Wnd,101,s); // Präfix if ((unsigned)iKanalStart<2) CheckDlgButton(Wnd,102+iKanalStart,TRUE); SetDlgItemText(Wnd,111,sMikro); SetDlgItemInt(Wnd,112,MaxKanalMenu,FALSE); GetDlgItemText(Wnd,120,s,elemof(s)); TCHAR buf[32]; _sntprintf(buf,elemof(buf),s,*sDecimal); SetDlgItemText(Wnd,120,buf); {PCTSTR p; p=StrChr(sPunktKomma,*sDezimal); if (p) CheckDlgButton(Wnd,120+int(p-sPunktKomma),TRUE); } CheckDlgButton(Wnd,123,TRUE); // Ausrichtung "von links nach rechts" PrintPr(s,wPrefix); SetDlgItemText(Wnd,125,s); }break; case WM_CHECKDIALOG: { // Zwangweise zusammenstellen, bei fehlenden Angaben Vorgabe lParam=0; TCHAR *p=sKanalFormat+GetDlgItemText(Wnd,101,sKanalFormat,4); *p++='%'; if (IsDlgButtonChecked(Wnd,107)) {*p++='0'; *p++='2';} *p++=IsDlgButtonChecked(Wnd,105) ? 'X' : 'd'; *p=0; iKanalStart=1-IsDlgButtonChecked(Wnd,102); // ohne Angabe "ab 1" wählen TCHAR m[2],s[8]; GetDlgItemText(Wnd,111,m,elemof(m)); if (*m!='u' && (unsigned)*m<0x80) {lParam=111; break;} UINT i=GetDlgItemInt(Wnd,112,NULL,FALSE); if (i<4) {lParam=112; break;} i=GetRadioCheck(Wnd,120,122); if ((int)i>=0) *sDezimal=sPunktKomma[i]; // des Users Wunsch ist des Users Himmelreich! GetDlgItemText(Wnd,125,s,elemof(s)); WORD pr; if (!ScanPr(s,pr)) {lParam=125; break;} *sMikro=ISO_Prefixes[4]=*m; // Nur u oder Sonderzeichen akzeptieren! MaxKanalMenu=i; wPrefix=pr; }break; } return MyDlgHandler(Wnd,Msg,wParam,lParam,110,NULL,T("Grundlage")); } /******************************** ** Ein Super-Zeitbasis-Dialog ** ********************************/ INT_PTR CALLBACK ZeitDlgProc(HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam){ switch (Msg) { case WM_INITDIALOG: { int i; HWND w=GetDlgItem(Wnd,100); for (i=0; iGetVar(0,buf); SetDlgItemText(Wnd,101,buf); // PROP fehlt noch! } if (was&(WAS_RATE|WAS_XANF)) { z->GetVar(1,buf); SetDlgItemText(Wnd,102,buf); } if (was&WAS_SAMPLES) { z->GetVar(2,buf); SetDlgItemText(Wnd,103,buf); } if (was&WAS_FARBE) InvalidateRect(GetDlgItem(Wnd,112),NULL,TRUE); #undef z #undef was }break; case WM_DRAWITEM: { // Farbe für Zeitbasis #define dis ((LPDRAWITEMSTRUCT)lParam) FarbRechteck(dis->hDC,&dis->rcItem,zeit[ZeitDlgCurSel].farbe); #undef dis }break; case WM_COMMAND: switch(LOWORD(wParam)) { case 100: switch (GET_WM_COMMAND_CMD(wParam,lParam)) { case CBN_SELCHANGE: { ZeitDlgCurSel=ComboBox_GetCurSel((HWND)lParam); PostMessage(Wnd,WM_SHOWITEMS,0,0); PostMessage(Wnd,WM_INFONEU,0xFF,(LPARAM)(zeit+ZeitDlgCurSel)); } }break; case 101: switch (GET_WM_COMMAND_CMD(wParam,lParam)) { case EN_STEPUP: zeit[ZeitDlgCurSel].SetAblenkung(T("++")); break; case EN_STEPDOWN: zeit[ZeitDlgCurSel].SetAblenkung(T("--")); break; }break; case 108: { // weitere Zeitbasis // keine Ahnung, wie weiter! }break; case 109: { // Zeitbasis löschen }break; case 110: zeit[ZeitDlgCurSel].FarbAuswahl(Wnd); break; }break; case WM_CHECKDIALOG: { lParam=0; TCHAR s[32]; GetDlgItemText(Wnd,101,s,elemof(s)); if (!zeit->SetAblenkung(s)) lParam=MAKELONG(101,201); } } return MyDlgHandler(Wnd,Msg,wParam,lParam,IDC_XABLENK,&hZeitDlg,T("ZeitDlg")); } /*************************************************** ** Der Super-Dialog für alle Kanal-Einstellungen ** ***************************************************/ bool GetEditText(int zero_idx,PTSTR buf) { HWND w=GetDlgItem(hKanalDlg,101+zero_idx); if (!GetModifiedEditText(w,buf,32)) return false; ChangeProp(w,~PROP_ERROR,0); InvalidateRect(w,NULL,TRUE); return true; } void SetEditText(int zero_idx,PTSTR buf) { // Wird auch bei DDEPOKE aufgerufen! HWND w=GetDlgItem(hKanalDlg,101+zero_idx); ChangeProp(w,~PROP_ERROR,0); SetWindowText(w,buf); Edit_SetModify(w,FALSE); KillTimer(hKanalDlg,AutoUpdate_id); } void LadeKanalComboBox() { HWND hCombo=GetDlgItem(hKanalDlg,100); // Combobox TCHAR buf[32],KanalGruppe[32],*pg=KanalGruppe; KANAL *k; GRUPPE *g; int i,item; item=ComboBox_GetCurSel(hCombo); ComboBox_ResetContent(hCombo); LoadString(HInstance,208,KanalGruppe,elemof(KanalGruppe)); // "Kanal %s\0Gruppe %s" for (i=0,k=kanal; iname); if (k->sNamen[0]) { lstrcat(buf,T(": ")); lstrcat(buf,k->sNamen); } ComboBox_AddString(hCombo,buf); } if (numkanal>=2 && !IsWindowVisible(GetDlgItem(hKanalDlg,106))) { // Knopf "Gruppen zeigen" pg+=lstrlen(pg)+1; // auf "Gruppe %s" for (i=0,g=gruppe; iname[0]) { _sntprintf(buf,elemof(buf),pg,g->name); // "Gruppe " }else{ // "Alle Kanäle" / "Beide Kanäle" LoadString(HInstance,numkanal==2?207:206,buf,elemof(buf)); } ComboBox_AddString(hCombo,buf); } } ComboBox_SetCurSel(hCombo,item); } #define WM_SETKANAL (WM_USER+101) // lParam=Kanal int KanalDlgCurSel; INT_PTR CALLBACK KanalDlgProc(HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam) { int i; switch (Msg) { case WM_INITDIALOG: { hKanalDlg=Wnd; // for (i=102; i<=105; i++) // DefEditProc=SubclassWindow(GetDlgItem(Wnd,i),EditHook); LadeKanalComboBox(); PostMessage(Wnd,WM_SETKANAL,0,lParam); }break; case WM_SHOWITEMS: { //HIBYTE(wParam)=zu schaltende Fenster, //LOBYTE(wParam)=Sichtbarkeits-Zustände HWND w; //Bit0=Name, Bit1=Tastkopf, Bit2=Ablenkung, int show; //Bit3=DC-Pegel, Bit4=DC-Stufung, Bit5=Gruppen-Knopf for (i=101; i<=108; i++) if (HIBYTE(LOWORD(wParam))&1) { w=GetDlgItem(Wnd,i); show=LOBYTE(LOWORD(wParam))&1?SW_SHOW:SW_HIDE; ShowWindow(w,show); if (i<=105) ShowWindow(GetPrevSibling(w),show); // Beschriftung switch (i) { case 103: // das /div hinter dem Ablekkoeffizienten case 108: ShowWindow(GetNextSibling(w),show); } wParam>>=1; } if (HIBYTE(LOWORD(wParam))&1) // HIER STIMMT WAS NICHT! ShowWindow(GetDlgItem(Wnd,5),LOBYTE(LOWORD(wParam))&1?SW_SHOW:SW_HIDE); }break; case WM_SETKANAL: { SendMessage(Wnd,WM_SHOWITEMS,HIWORD(lParam),0); HWND hCombo=GetDlgItem(Wnd,100); if (ComboBox_GetCurSel(hCombo)!=LOBYTE(LOWORD(lParam))) { for (i=101; i<=105; i++) { if ((BOOL)SendDlgItemMessage(Wnd,i,EM_GETMODIFY,0,0)) { TCHAR name[32]; ComboBox_GetLBText(hCombo,ComboBox_GetCurSel(hCombo),name); switch (MBox(Wnd,209,MB_YESNOCANCEL|MB_ICONQUESTION,(LPSTR)name)) { case IDOK: SendMessage(Wnd,WM_COMMAND,3,0); nobreak; // vorerst! case IDCANCEL: return FALSE; } break; } } i=LOBYTE(LOWORD(lParam)); ComboBox_SetCurSel(hCombo,i); if (HIBYTE(LOWORD(lParam))) SetEditFocus(Wnd,100+HIBYTE(LOWORD(lParam))); goto set_vars; } }break; case WM_DRAWITEM: { #define dis ((LPDRAWITEMSTRUCT)lParam) if (KanalDlgCurSelhDC,&dis->rcItem,kanal[KanalDlgCurSel].farbe); #undef dis }break; case WM_COMMAND: switch (LOWORD(wParam)) { case 100: switch (GET_WM_COMMAND_CMD(wParam,lParam)) { case CBN_SELCHANGE: { KanalDlgCurSel=ComboBox_GetCurSel((HWND)lParam); if (KanalDlgCurSel<0) break; // eigentlich: alle Items ausschalten! SendMessage(Wnd,WM_SHOWITEMS, KanalDlgCurSel>=numkanal?0x5150:0x5101,0); // Staffelung // jetzt noch die übrigen Werte setzen... set_vars: TCHAR s[32]; if (KanalDlgCurSelGetVar(0,s); SetDlgItemText(Wnd,101,s); k->GetVar(1,s); SetDlgItemText(Wnd,102,s); k->GetVar(2,s); SetDlgItemText(Wnd,103,s); // wsprintf(s+lstrlen(s),T(" %c"),T("=~_")[k->kopplung]); k->GetVar(4,s); SetDlgItemText(Wnd,104,s); }else{ GRUPPE *g=gruppe+KanalDlgCurSel-numkanal; g->GetVar(1,s); SetDlgItemText(Wnd,102,s); g->GetVar(2,s); SetDlgItemText(Wnd,103,s); // wsprintf(s+lstrlen(s),T(" %c"),T("=~_")[k->kopplung]); g->GetVar(4,s); SetDlgItemText(Wnd,104,s); } }break; }break; case 101: case 102: case 103: case 104: case 105: switch (GET_WM_COMMAND_CMD(wParam,lParam)) { // case EN_CHANGE: { // ChangeProp((HWND)lParam,~PROP_DIVERS,0); // bei Änderung nicht grau!? // if (IsDlgButtonChecked(Wnd,4)) SetTimer(Wnd,AutoUpdate_id,AutoUpdate_ms,NULL); // }break; case EN_STEPUP: case EN_STEPDOWN: switch (LOWORD(wParam)){ case 103: { TCHAR buf[32]; UINT kn=(UINT)SendDlgItemMessage(Wnd,100,CB_GETCURSEL,0,0); if (!GetEditText(2,buf) || kanal[kn].SetAblenkung(buf)) SendMessage(MainWnd,WM_COMMAND, (kn<<10)+IDC_YABL+elemof(Reihe)+ GET_WM_COMMAND_CMD(wParam,lParam)-EN_STEPUP+1,0); }break; }break; }break; case 106: { // ShowWindow((HWND)lParam,SW_HIDE); // Knopf verschwindet SendMessage(Wnd,WM_SHOWITEMS,0x2F0E,0); // aber noch keine Staffelung LadeKanalComboBox(); }break; case 110: if (KanalDlgCurSelSetVar(0,buf)) { lParam=MAKELONG(101,201); ChangeProp(Wnd,101,~PROP_ERROR,PROP_ERROR); } if (GetEditText(1,buf) && !k->SetVar(1,buf)) { lParam=MAKELONG(102,201); ChangeProp(Wnd,102,~PROP_ERROR,PROP_ERROR); } if (GetEditText(2,buf) && !k->SetVar(2,buf)) { lParam=MAKELONG(103,201); ChangeProp(Wnd,103,~PROP_ERROR,PROP_ERROR); } if (GetEditText(3,buf) && !k->SetVar(4/*!!*/,buf)) { lParam=MAKELONG(104,201); ChangeProp(Wnd,104,~PROP_ERROR,PROP_ERROR); } }break; } // switch return MyDlgHandler(Wnd,Msg,wParam,lParam,IDC_YABL,&hKanalDlg,T("KanalDlg")); } void StartDlg(HWND&Wnd, UINT DlgID, DLGPROC DlgProc, LPARAM lParam) { if (!Wnd) Wnd=CreateDialogParam( HInstance,MAKEINTRESOURCE(DlgID),MainWnd,DlgProc,lParam); else{ SetActiveWindow(Wnd); SendMessage(Wnd,WM_SETKANAL,0,lParam); } } void StartKanalDlg(LPARAM lParam) { /* Bit-Belegung von lParam: 7:0 Kanal- oder Gruppennummer 15:8 Zu fokussierende Edit-Zeile: 1=Namen, 2=Tastkopf,3=Ablenkung,4=Offset 16 Sichtbarkeit von NAMEN-Eingabezeile 17 Sichtbarkeit von TASTKOPF-Eingabezeile usw. 18 ABLENKUNG 19 OFFSET 20 STUFUNG (nur bei Gruppe) 21 GRUPPEN-Knopf 24 Schalten NAMEN-Sichtbarkeit usw.*/ StartDlg(hKanalDlg,IDC_YABL,KanalDlgProc,lParam); } void CreateEditBrushes() { static DWORD XOR[]={0x7F0000L,0x1F1F1FL,0x3F3F00L}; // gelb,grau,rot for (int i=0; imodus==TRIGG::TM_SINGLE) { FlashWindow(MainWnd,TRUE); // Trigger-Blitz FlashWindow(MainWnd,FALSE); } Running=neu; if (trig && trig->anzeige && trig->anzeige->knopf[0]) { trig->anzeige->knopf[0]->bild=neu?MYBUTTON::PAUSE:MYBUTTON::PLAY; trig->anzeige->knopf[0]->Inval(); } quelle->RelayMsg(Running ? Q_ARM : Q_UNARM, NULL); ZeigBildFrequenz(); } void ToggleStopRun(void) { SetStopRun(Running?T_STOP:T_WAIT); // nicht korrekt wenn eh' ohne Trigger! } bool Idle(void) { if (!quelle) return true; if (!Running) return true; if (!trig) return true; // if (!quelle->buffer) return true; // quelle->state&=~Q_FULL; // Sofern keine alten Daten (also alles "neu"), alles auf alt setzen lassen // und Trigger suchen mittels dwFlags=0 (InQueue-Bit löschen) if (WaveHdr.dwUser==WaveHdr.dwBufferLength) { WaveHdr.dwFlags=0; // Neu initialisieren WaveHdr.dwBytesRecorded=0; // Null neue Daten WaveHdr.dwUser=0; // Alles alte Daten (PROBLEM MIT PRÄTRIGGER-DATEN!!!) // Software-Trigger initialisieren if (st.pre>(long)WaveHdr.dwBufferLength) st.pre=WaveHdr.dwBufferLength; WaveHdr.reserved=st.pre; // begrenzen! st.Reset(); if (trig->modus==TRIGG::TM_AUTO) SetTimer(MainWnd,3,500,NULL); } if (!FindTrigger(/*TimeOut:100*/)) // keine neuen Daten? return WaveHdr.dwFlags&WHDR_PREPARED ? false : true; // Sobald Trigger entdeckt, ggf. Fenstertitel umändern if (WaveHdr.dwBytesRecorded>WaveHdr.reserved) SetStopRun(T_AUTO); // Sofern SINGLE, wenn Puffer voll, Aufnahme abschalten if (trig->modus==TRIGG::TM_SINGLE && WaveHdr.dwBytesRecorded==WaveHdr.dwBufferLength) SetStopRun(T_STOP); for (int i=0; iSetState(masse->state&and^xor); // if (::trig && ::trig->k==this && ::trig->kreuz) // ::trig->kreuz->SetState(::trig->kreuz->state&and^xor); if (anzeige) anzeige->SetState(and,xor); } */ int aktkanal; // aktiver Kanal für Tastatureingabe KANAL *aktk; int aktzeit; // aktive Zeitbasis für Tastatureingabe ZEIT *aktz; void SetAktKanal(int a) { if (a<0) a=numkanal-1; else if (a>=numkanal) a=0; aktkanal=a; if (aktk && aktk->anzeige) aktk->anzeige->SetState(~STA_SELECTED,0); aktk=kanal+a; if (aktk && aktk->anzeige) aktk->anzeige->SetState(~STA_SELECTED,STA_SELECTED); } void SetAktZeit(int a) { if (a<0) a=NumZeitMenu-1; else if (a>=NumZeitMenu) a=0; // Ungültiges erzeugt fehlende Zeitbasen - oder? aktzeit=a; // Zurzeit nur eine Zeitbasis! if (aktz && aktz->anzeige) aktz->anzeige->SetState(~STA_SELECTED,0); aktz=zeit+a; if (aktz && aktz->anzeige) aktz->anzeige->SetState(~STA_SELECTED,STA_SELECTED); } void SetDatenquelle(EDatenquelle neu) { SetStopRun(T_STOP); if (Datenquelle==neu) return; if (Datenquelle>0) { // falls bereits initialisiert CheckMenuItem(MainMenu,120+Datenquelle-1,MF_UNCHECKED); } if (trig) {trig->Destruktor(); delete trig; trig=0;} if (quelle) { if (numkanal) quelle->RelayMsg(Q_DONE,0); // macht selber "unarm" delete quelle; quelle=NULL; } if (kanal) { for (int i=numkanal-1; i>=0; i--) kanal[i].Destruktor(); delete[]kanal; kanal=NULL; } aktk=NULL; if (gruppe) {delete[]gruppe; gruppe=NULL;} // Gruppen sind "dumm"! if (zeit) {zeit->Destruktor(); delete zeit; zeit=0;} aktz=NULL; if (WaveHdr.lpData) { GlobalFree(WaveHdr.lpData); WaveHdr.lpData=NULL;} WaveHdr.lpNext=NULL; numkanal=0; Datenquelle=neu; if (!Datenquelle) return; CheckMenuItem(MainMenu,120+Datenquelle-1,MF_CHECKED); switch (Datenquelle) { case ZUFALL: quelle=new Q_ZUFALL; break; case DSO220: quelle=new Q_DSO220; break; case SOUND: quelle=new Q_SOUND; break; } if (!quelle->RelayMsg(Q_INIT,0)) return; SYSINFO si; quelle->RelayMsg(Q_GETSYSINFO,&si); numkanal=si.numchan; if (!numkanal) return; GetSample=si.getsample; // die wichtigsten Daten herauskopieren BlockAlign=si.blockalign; FullScale=(float)(1L<Konstruktor(0); WaveHdr.dwBufferLength=1000L*BlockAlign; WaveHdr.lpData=(LPSTR)GlobalAlloc(GMEM_FIXED,WaveHdr.dwBufferLength); WaveHdr.dwBytesRecorded=0; // keine neuen Daten WaveHdr.dwUser=WaveHdr.dwBufferLength; // keine alten Daten WaveHdr.dwFlags=0; // keine Statusbits kanal=new KANAL[numkanal]; for (int i=0; iKonstruktor(0); SetAktKanal(aktkanal); // Zeiger neu setzen SetAktZeit(aktzeit); SetStopRun(T_WAIT); } BYTE HandleKeyDownUp(BYTE down, WPARAM key) { // Zentrale Verwaltung der Hotkeys, die zur besseren Visualisierung die // Anzeige-Schaltflächen mit betätigen. Liefert Flags: MK_SHIFT und MK_CONTROL BYTE mk=0; ANZEIGE *a=NULL; int idx=0; if (GetKeyState(VK_SHIFT)<0) mk|=MK_SHIFT; if (GetKeyState(VK_CONTROL)<0)mk|=MK_CONTROL; switch (key) { case VK_SHIFT: { // Massesymbol hervorheben if (!(mk&MK_CONTROL) && aktk && aktk->masse) aktk->masse->SetState((BYTE)~STA_SELECTED,(BYTE)(down?STA_SELECTED:0)); }break; case VK_CONTROL: { // Triggersymbol hervorheben if (trig && trig->kreuz) trig->kreuz->SetState((BYTE)~STA_SELECTED,(BYTE)(down?STA_SELECTED:0)); }break; case VK_TAB: { if (down) SetAktKanal(aktkanal+(mk&MK_SHIFT?-1:+1)); }break; case VK_APPS: case VK_SPACE: { if (mk&MK_CONTROL) { if (down && trig && trig->kreuz) ShowPopupMenu(trig->submenu,trig->kreuz->mitte.x,trig->kreuz->mitte.y); break; } if (mk&MK_SHIFT) { if (down && aktk && aktk->masse) ShowPopupMenu(aktk->submenu,aktk->masse->mitte.x,aktk->masse->mitte.y); break; } if (key==VK_APPS) break; }nobreak; case VK_PAUSE: { if (trig) a=trig->anzeige; // Wenn PortTalk fehlt, gibt's keinen Trigger }break; case VK_LEFT: goto A; case VK_RIGHT: idx=1; A:{ if (mk&MK_CONTROL) break; a=aktz->anzeige; }break; case VK_SUBTRACT: case VK_DOWN: goto B; case VK_ADD: case VK_UP: idx=1; B:{ if (mk&MK_CONTROL) break; if (aktk) a=aktk->anzeige; }break; } if (a) { // Anzeige existiert MYBUTTON *b=a->knopf[idx]; if (b && !(b->state&2)) { // Knopf existiert, und nicht disabled b->SetState(down); UpdateWindow(MainWnd); // rcitem-Aktualisierung vorziehen } } return mk; } static void LoadConfig(void) { TCHAR buf[16]; // Globales GetString(HauptSektion,T("KanalFormat"),T("Y%d,1"),buf,elemof(buf)); _stscanf(buf,T("%7[^,],%d"),sKanalFormat,&iKanalStart); sKanalFormat[7]=0; GetStruct(HauptSektion,T("Farben"),CustColors,sizeof(CustColors),StdProfile); GetString(HauptSektion,T("Mikro"),T("µ"),sMikro,elemof(sMikro)); ISO_Prefixes[4]=*sMikro; GetString(HauptSektion,T("Dezimaltrenner"),T("?"),sDezimal,elemof(sDezimal)); GetString(HauptSektion,T("Hintergrund"),T("#FFFFFF"),buf,elemof(buf)); String2Farbe(buf,BackColor); GetString(HauptSektion,T("Gitternetz"),T("#008000"),buf,elemof(buf)); String2Farbe(buf,GridColor); MaxKanalMenu=GetInt(HauptSektion,T("MaxKanalMenü"),16); if (MaxKanalMenu<4) MaxKanalMenu=4; if (GetString(HauptSektion,T("Kästel"),sLeer,buf,elemof(buf))) ScanXY(buf,&Kaestel); if (GetString(HauptSektion,T("SubTick"),sLeer,buf,elemof(buf))) ScanXY(buf,&SubTick); if (GetString(HauptSektion,T("Vorsätze"),sLeer,buf,elemof(buf))) ScanPr(buf,wPrefix); // Hintergrund SetDispOpt(GetInt(HauptSektion,T("Anzeige"), DO_GRID|DO_DB|DO_LINE|DO_TICK|DO_CROSS|DO_BACK),0); gitter=new GITTER; // Konstruktor wird gerufen // Trigger // Kanäle SetDatenquelle((EDatenquelle)GetInt(HauptSektion,T("Datenquelle"),1)); } static void SaveConfig(void) { TCHAR buf[16]; _sntprintf(buf,elemof(buf),sInt,Datenquelle); WriteString(HauptSektion,T("Datenquelle"),buf); WriteStruct(HauptSektion,T("Farben"),CustColors,sizeof(CustColors),StdProfile); WriteString(HauptSektion,T("Mikro"),sMikro); WriteString(HauptSektion,T("Dezimaltrenner"),sDezimal); _sntprintf(buf,elemof(buf),T("%s,%d"),sKanalFormat,iKanalStart); WriteString(HauptSektion,T("KanalFormat"),buf); Farbe2String(buf,BackColor); WriteString(HauptSektion,T("Hintergrund"),buf); Farbe2String(buf,GridColor); WriteString(HauptSektion,T("Gitternetz"),buf); _sntprintf(buf,elemof(buf),T("%u"),DispOpt); WriteString(HauptSektion,T("Anzeige"),buf); _sntprintf(buf,elemof(buf),sInt,MaxKanalMenu); WriteString(HauptSektion,T("MaxKanalMenü"),buf); PrintXY(buf,&Kaestel); WriteString(HauptSektion,T("Kästel"),buf); PrintXY(buf,&SubTick); WriteString(HauptSektion,T("SubTick"),buf); PrintPr(buf, wPrefix); WriteString(HauptSektion,T("Vorsätze"),buf); } void SendAlleNachricht(UINT Msg, WPARAM wParam, LPARAM lParam) { if (Anker[0].sub) Anker[0].sub->RelayMsg(Msg,wParam,lParam); if (Anker[1].sub) Anker[1].sub->RelayMsg(Msg,wParam,lParam); if (Anker[2].sub) Anker[2].sub->RelayMsg(Msg,wParam,lParam); } static MINIWND *HoverWnd; // Fenster, das Mausnachrichten erhält static WPARAM ButtonState; // Momentaner Maustastenstatus MK_xxx void SendMausNachricht(UINT Msg, WPARAM wParam, LPARAM lParam) { if (HoverWnd) HoverWnd->RelayMsg(Msg,wParam,lParam); } void CheckHover(LPARAM lParam) { if (ButtonState) return;// HOVER nicht bei gedrückter Maustaste wechseln MINIWND *p=MINIWND::MiniWndFromPoint(MAKEPOINTS(lParam)); if (p==HoverWnd) return; SendMausNachricht(WM_MOUSELEAVE,0,lParam); // Tschüss sagen HoverWnd=p; SendMausNachricht(WM_MOUSEHOVER,0,lParam); // Hallo sagen } void MausNachricht(UINT Msg, WPARAM wParam, LPARAM lParam) { // Maus-Verarbeitung, Eintritts- und Austritts-Feststellung switch (Msg) { case WM_NCHITTEST: case WM_MOUSEWHEEL: { // Diese beiden kommen in Bildschirmkoordinaten ScreenToClientS(MainWnd,(POINTS*)&lParam); }break; case WM_MOUSEMOVE: { if (wParam&(MK_LBUTTON|MK_RBUTTON|MK_MBUTTON)) SetCapture(MainWnd); // Hier System-Mausfang setzen else ReleaseCapture(); }break; case WM_SETCURSOR: SendMausNachricht(Msg,wParam,lParam); return; default: if (MsgWM_MOUSELAST) return; } WPARAM bsc=ButtonState; // um nicht 2x CheckHover aufrufen zu müssen... CheckHover(lParam); // mein lParam=POINTS! if (WM_MOUSEFIRST<=Msg && Msg<=WM_MOUSELAST) ButtonState=wParam&(MK_LBUTTON|MK_RBUTTON|MK_MBUTTON); bsc^=ButtonState; // Änderungs-Bits gesetzt SendMausNachricht(Msg,wParam,lParam); if (bsc) CheckHover(lParam); // alles in Client-Koordinaten! } LRESULT CALLBACK MainWndProc(HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam){ #if 0 if (WM_MOUSEFIRST<=Msg && Msg<=WM_MOUSELAST && Tooltip) { MSG msg; msg.hwnd=Wnd; msg.message=Msg; msg.wParam=wParam; msg.lParam=lParam; SendMessage(Tooltip,TTM_RELAYEVENT,0,(LPARAM)&msg); } #endif MausNachricht(Msg,wParam,lParam); switch (Msg) { case WM_CREATE: { MainWnd=Wnd; MainMenu=GetMenu(Wnd); // LoadWinBitmaps(); atom=GlobalAddAtom(T("Oszi-Edit-BackColor")); CreateEditBrushes(); SendMessage(Wnd,WM_WININICHANGE,0,0); #if 0 Tooltip=CreateWindow(TOOLTIPS_CLASS,NULL,TTS_ALWAYSTIP,0,0,0,0, 0,0,HInstance,NULL); #endif if (waveInGetNumDevs()) EnableMenuItem(MainMenu,122,MF_ENABLED); // eigentlich ein Fall für ConfigChanged... oder? PostMessage(Wnd,WM_USER+10,LoadWinPos(Wnd,T("Oszi")),0); OsziMenu=GetSubMenu(MainMenu,2); tip=new TOOLTIP; LoadConfig(); if (LoadWinPos(0,T("Anzeige"))) PostMessage(Wnd,WM_COMMAND,112,0); if (LoadWinPos(0,T("Grundlage"))) PostMessage(Wnd,WM_COMMAND,112,0); if (LoadWinPos(0,T("ZeitDlg"))) StartDlg(hZeitDlg,IDC_XABLENK, ZeitDlgProc,MAKELONG(MAKEWORD(0,1),0x0303)); if (LoadWinPos(0,T("KanalDlg"))) StartDlg(hKanalDlg,IDC_YABL, KanalDlgProc,MAKELONG(MAKEWORD(0,1),0xFFFF)); // SetTimer(Wnd,1,20,NULL); SetTimer(Wnd,2,1000,NULL); // zur Berechnung der Bilder pro Sekunde // static TRACKMOUSEEVENT tme={sizeof(tme),TME_HOVER|TME_LEAVE,0,HOVER_DEFAULT}; // tme.hwndTrack=Wnd; // _TrackMouseEvent(&tme); wm_helpmsg=RegisterWindowMessage(HELPMSGSTRING); }break; case WM_USER+10: { if (wParam) ShowWindow(Wnd,(int)wParam); // macht in WM_CREATE Murks!! }break; case WM_PAINT:{ PAINTSTRUCT ps; BeginPaint(Wnd,&ps); if (DispOpt&DO_DB) { if (DispOpt&DO_DB_INVAL) BltAlles(bltdc[0]); BitBlt(ps.hdc,0,0,ClientExt.x,ClientExt.y,bltdc[0],0,0,SRCCOPY); }else{ BltAlles(ps.hdc); } EndPaint(Wnd,&ps); Bilder++; }return 0; case WM_TIMER: { lParam=GetMessagePos(); ScreenToClientS(Wnd,(LPPOINTS)&lParam); if ((LOWORD(lParam)>=(unsigned)ClientExt.x || HIWORD(lParam)>=(unsigned)ClientExt.y) && KillTimer(Wnd,222)) tip->SetParent(Anker+2); // SendMessage(Wnd,WM_MOUSEMOVE,ButtonState,lParam); //DAMIT LÄSST SICH KEIN MENÜ BEDIENEN! // MausNachricht(WM_MOUSEMOVE,ButtonState,GetMessagePos()); switch (wParam) { case 1: Idle(); break; case 2: ZeigBildFrequenz(); break; case 3: { KillTimer(Wnd,wParam); WaveHdr.dwFlags|=WHDR_ENDLOOP; // ausbrechen lassen if ((long)WaveHdr.reserved<0) WaveHdr.reserved=0; }break; } SendAlleNachricht(Msg,wParam,lParam); }return 0; // besser: gerichtet mittels wParam als MINIWND-Zeiger case WM_NCMOUSEMOVE: { if (KillTimer(Wnd,222)) tip->SetParent(Anker+2); }break; case WM_MOUSEMOVE:{ HDC dc=GetDC(Wnd); if (DispOpt&DO_DB) Fadenkreuz(); Fadenkreuz(dc); lastmouse.x=GET_X_LPARAM(lParam); lastmouse.y=GET_Y_LPARAM(lParam); Fadenkreuz(dc); if (DispOpt&DO_DB) Fadenkreuz(); ReleaseDC(Wnd,dc); }return 0; // case WM_NCHITTEST: _asm int 3; break; case WM_SIZE: { wmSize((short)LOWORD(lParam),(short)HIWORD(lParam)); SetDispOpt(DispOpt,DO_DB|DO_TB); // (beide) Puffer neu allokieren lassen! for (int i=0; iSetPegel(T("+?")); break; case VK_DOWN: trig->SetPegel(T("-?")); break; case VK_LEFT: trig->SetPretrig(T("-?")); break; case VK_RIGHT: trig->SetPretrig(T("+?")); break; }else switch (wParam) { case VK_SPACE: case VK_PAUSE: { if (HIBYTE(HIWORD(lParam))&0x40) break; // ohne Autorepeat! ToggleStopRun(); }break; case VK_ADD: case VK_UP: if (mk&MK_SHIFT) aktk->SetNulllinie(T("++")); else aktk->SetAblenkung(T("--")); break; case VK_SUBTRACT: case VK_DOWN: if (mk&MK_SHIFT) aktk->SetNulllinie(T("--")); else aktk->SetAblenkung(T("++")); break; case VK_LEFT: aktz->SetAblenkung(T("+?")); break; case VK_RIGHT: aktz->SetAblenkung(T("-?")); break; } }break; case WM_KEYUP: HandleKeyDownUp(0,wParam); break; case WM_CHAR: switch ((TCHAR)wParam) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': SetAktKanal(((TCHAR)wParam-'0'-iKanalStart+10)%10); break; case 'a': case 'b': case 'c': case 'd': SetAktZeit((TCHAR)wParam-'a'); break; case '=': aktk->SetKopplung((UINT)0); break; case '~': aktk->SetKopplung(1); break; case '_': aktk->SetKopplung(2); break; case '!': aktk->SetTastkopf(aktk->GetTastkopfIndex()?T("1:1"):T("10:1")); break; case '/': aktk->SetAblenkung(-aktk->div); break; }return 0; case WM_COMMAND: { UINT id=wParam&0x3FF; // Menü-ID (10 bit) UINT kn=LOWORD(wParam)>>10; // Kanalnummer (6 bit) KANAL *k=::kanal+kn; ZEIT *z=::zeit +kn; UINT j; if ((j=id-IDC_XABLENK)SetAblenkung(Reihe[j]); }else if ((j=id-IDC_RATE)SetRate(Reihe[j]); }else if ((j=id-IDC_YABL)SetAblenkung(Reihe[j]); }else switch (id) { // enthält Kanalnummer case IDC_XABLENK+elemof(Reihe): StartDlg(hZeitDlg,IDC_XABLENK,ZeitDlgProc, MAKELONG(MAKEWORD(kn,1),0x0301)); break; case IDC_XABLENK+elemof(Reihe)+1: z->SetAblenkung(T("++")); break; case IDC_XABLENK+elemof(Reihe)+2: z->SetAblenkung(T("--")); break; case IDC_RATE+elemof(Reihe): case IDC_XANFANG: StartDlg(hZeitDlg,IDC_XABLENK,ZeitDlgProc, MAKELONG(MAKEWORD(kn,2),0x0302)); break; case IDC_XFARBE: z->FarbAuswahl(Wnd); break; case IDC_YVOR+0: k->SetTastkopf(T("1:1")); break; case IDC_YVOR+1: k->SetTastkopf(T("10:1")); break; case IDC_YVOR+2: StartKanalDlg(MAKELONG(MAKEWORD(kn,2),0xFF22U)); break; case IDC_YKOP+0: // DC case IDC_YKOP+1: // AC case IDC_YKOP+2: { // GND k->SetKopplung(id-IDC_YKOP); }break; case IDC_YINV: k->SetAblenkung(-k->div); break; case IDC_YNAME: StartKanalDlg(MAKELONG(MAKEWORD(kn,1),0xFF21U)); break; case IDC_YFARBE: k->FarbAuswahl(Wnd); break; case IDC_YABL+elemof(Reihe): StartKanalDlg(MAKELONG(MAKEWORD(kn,3),0xFF24U)); break; case IDC_YABL+elemof(Reihe)+1: k->SetAblenkung(T("++")); break; case IDC_YABL+elemof(Reihe)+2: k->SetAblenkung(T("--")); break; case 109: SendMessage(Wnd,WM_CLOSE,0,0); break; case 110: DialogBox(HInstance,MAKEINTRESOURCE(110),Wnd,GrundDlgProc); break; case 112: StartDlg(hDisplayDlg,112,DisplayDlgProc,0); break; case 113: { DLGINFO di; di.parent=Wnd; di.kbHand=&hKBHand; quelle->RelayMsg(Q_SETUPDLG,&di); }break; case 120: case 121: case 122: SetDatenquelle(EDatenquelle(LOWORD(wParam)-120+1)); break; case IDC_TMODUS: trig->SetModus((TRIGG::MODUS)kn); break; case IDC_TQUELLE: trig->SetQuelle(kn); break; case IDC_TFLANKE: trig->SetFlanke((TRIGG::FLANKE)kn); break; case IDC_TKOPPLUNG: trig->SetKopplung((TRIGG::KOPPLUNG)kn); break; case IDC_TFARBE: trig->FarbAuswahl(Wnd); break; case 0x229: ToggleStopRun(); break; case 191: WinHelp(Wnd,HelpFileName,HELP_INDEX,0); break; case 192: WinHelp(Wnd,HelpFileName,HELP_CONTEXT,192); break; case 199: DialogBox(HInstance,MAKEINTRESOURCE(199),Wnd,AboutDlgProc); break; } }return 0; case WM_CLOSE: case WM_ENDSESSION: { if (hDisplayDlg)SaveWinPos(hDisplayDlg,T("Anzeige"),true); if (hZeitDlg) SaveWinPos(hZeitDlg, T("ZeitDlg"),true); if (hKanalDlg) SaveWinPos(hKanalDlg, T("KanalDlg"),true); SaveConfig(); SaveWinPos(Wnd,T("Oszi"),true); WriteString(NULL,NULL,NULL); // Flush WinHelp(Wnd,HelpFileName,HELP_QUIT,0); }break; case WM_DESTROY: { SetDatenquelle(EDatenquelle(0)); SetDispOpt(0,0); DeleteEditBrushes(); GlobalDeleteAtom(atom); // FreeWinBitmaps(); KillTimer(Wnd,1); PostQuitMessage(0); }return 0; } if (Msg==wm_helpmsg) WinHelp(Wnd,HelpFileName,HELP_CONTEXT,88); return DefWindowProc(Wnd,Msg,wParam,lParam); } void CALLBACK WinMainCRTStartup() { static WNDCLASS wc={ CS_DBLCLKS|CS_HREDRAW|CS_VREDRAW|CS_BYTEALIGNCLIENT, MainWndProc,0,0,0,0,0,0,MAKEINTRESOURCE(100),WndClassName}; LoadString(HInstance,200,WindowTitle,elemof(WindowTitle)); MBoxTitle=WindowTitle; // Zeiger für setzen HInstance=GetModuleHandle(NULL); {OSVERSIONINFO vi; InitStruct(&vi,sizeof(vi)); if (!GetVersionEx(&vi)) { #ifdef UNICODE CHAR buf[256]; LoadStringA(HInstance,210,buf,elemof(buf)); MessageBoxA(0,buf,NULL,MB_OK|MB_ICONSTOP); // Zwang: ANSI-Version #endif return; } if (vi.dwPlatformId==VER_PLATFORM_WIN32s) MBox(0,210,MB_OK|MB_ICONASTERISK); // Empfehlung: 16bit } InitCommonControls(); GetModuleFileName(HInstance,StdProfile,elemof(StdProfile)); lstrcpy(GetFileNamePtr(StdProfile),(PTSTR)IniFileName); wc.hInstance=HInstance; wc.hIcon=LoadIcon(HInstance,MAKEINTRESOURCE(100)); RegisterClass(&wc); CreateWindowEx(WS_EX_ACCEPTFILES,WndClassName,MBoxTitle, WS_VISIBLE|WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT, 0,0,HInstance,NULL); MSG msg; for(;;){ while (PeekMessage(&msg,0,0,0,PM_REMOVE)) { if (msg.message==WM_QUIT) goto raus; if (hKBHand && IsDialogMessage(hKBHand,&msg)) continue; TranslateMessage(&msg); DispatchMessage(&msg); } if (Idle()) WaitMessage(); } raus: #ifndef WIN32 UnhookWindowsHookEx(MessageHook); #endif ExitProcess((UINT)msg.wParam); }