Eine originelle File-Selector-Box

Nachdem in der ST 3/87 das Programm Tempus vorgestellt wurde, dessen File Selector Box mir sofort gefallen hat. habe ich mich entschlossen, selbst eine ähnlich komfortable zu programmieren.

Jeder kennt die Original Atari File Selector Box. Wer eine Weile mit Programmen wie 1st Word unter einer Ram-Disk gearbeitet hat, kennt das Problem: Man lädt 1st Word von Diskette und will einen Text von Ram-Disk laden. Dazu muß man umständlich mit den Cursortasten im Pfadnamen die Diskettenkennung ändern und anschließend mit der Maus das Redraw-Feld anklicken.

Bild 1

Die Lösung:

Diese Box stellt 15 Diskettenstationen zur Auswahl, wobei die angeschlossenen hervorgehoben werden und nur diese auswählbar sind. Nun braucht man nur noch den Knopf der Station anzuwählen, und der Inhalt wird angezeigt. Ebenso verhält es sich mit den Extensions.

Mit dieser Routine können Sie natürlich nicht Ihre gekauften Programme tunen, sondern nur Ihre eigenen benutzerfreundlich machen.

Der Anfang:

Zuerst schnappen Sie sich ein Resource-Construction-Set und bauen die (Dialog-) Box. Diese nennen Sie „SELECT“. Mit untenstehender Tabelle und Bild 1 sollte dies eigentlich gelingen. Bitte übernehmen Sie meine Objekt-Namen und die Verwandtschaftsverhältnisse zwischen den einzelnen Objekten. Auch sollten Sie die Stringlängen nicht unterschreiten, sonst gibt’s wieder mal Bomben. Die Nummern im .H File spielen dagegen keine Rolle. Jedoch sollten die Disk-Buttons, Extensions und Filenamen richtig geordnet werden. Die Resource speichern Sie unter dem Namen „SELECTOR.RSC“ ab.

Die Routine:

Die Routine ist im abgedruckten Programm enthalten. Das Programm selbst meldet sich in deklaration () beim GEM an, lädt das .RSC File und reserviert Platz für eine Bildschirmseite. Dann wird die File Select Box aufgerufen und die erhaltenen Pfad-und Dateinamen werden ausgedruckt. Schließlich wird das Programm ordnungsgemäß mit der Funktion ende() verlassen.

Der Aufruf für die Box lautet:

fehler = power_f_sel (pfad,name,info);

Die drei Übergabeparameter sind Pointer auf den Pfadnamen, den Dateinamen und das Selector Info. Sie werden in der Box angezeigt. Nun kann man sich eine Datei auswählen oder andere Directorys anschauen. Verlassen wird die Box mit OK, ABBRUCH oder Doppelklick auf den Dateinamen. Beim Verlassen mit ABBRUCH wird fehler = 1, sowohl pfad als auch name bleiben unverändert.

Sonst ist fehler = 0 und die aktuellen Pfad- und Dateinamen werden übermittelt.

Zur Routine:

Wenn Sie den GEM Kurs aufmerksam verfolgt haben, müßten Sie eigentlich durchblicken. Da alle Objekte mit Touchexit ausgestattet sind, wird nach fast jedem Mausblick die Kontrolle wieder von der Routine übernommen. Es werden nun alle Objekte der Reihe nach durchgegangen und geschaut, ob z.B. gerade der Closer ausgewählt wurde. Dementsprechend wird gehandelt und z.B. der Pfadname geändert. Danach wird meistens die Funktion inhalt_anzeigen (pfad,n,anzahl) aufgerufen. Dort wird der Pfad untersucht und n-te Datei als erste angezeigt.

Da ich für die Routine selbst keine globalen Variablen benutzen wollte, wird die Anzahl der Dateien der aktuellen Directorys mit Hilfe von Zeigern übergeben. Alle Doppelklicks werden unterdrückt, bis auf die der Dateiauswahlfelder.

Listing

Nummer in .H Name Art Flags Sonstiges
0 FSTOTAL Box Outlined die äußere Box
1 - Text - Text: „Pfad:“
2 FSPATH Ftext Editable Text: 49 X „A“ (Platzhalter) Template: 49 x „P“
3 - Text - Text „Dateiname:“
4 FSNAME Fboxtext Editable Text: „12345678123“ Template: „pppppppp.ppp“
5 FSDSKBOX Box Die Box, die die Diskknöpfe umschließt (Bild 1) normal unsichtbar: Border Color 0
6-20 FS AD, Button Selectable, Text: „A“, „B“-„0“
FSBD- Shadowed, Sind alles Kinder von FSDSKBOX
FSOD Touchexit, Radio Button Richtig Ordnen!
21 FSINFO Boxtext Text: 29 x „A“ Fill setzen (siehe Bild 1) Justification: Center
22 FSTOTBOX Box - Diese Box bildet das „Fenster“.
In Bild 1 ist sie rechts etwas größer gezeichnet. 23-39 Kinder von FSTOTBOX
23 FSCLOSER Boxchar Touchexit Char: DerCloser (CtrlE)
24 FSMOVEDO Boxchar Touchexit Char: Pfeil nach unten (CtrlB)
25 FSREDRAW Boxtext Touchexit Text: „12345678.123“ Justification: Center Fill gepunktet setzen
26 FSMOVEUP Bochar Touchexit Char: Pfeil nach oben (CTRLA)
27 FSROLL Box Touchexit Fill schwach gepunktet setzen Roll ist die schwach gepunktete Box am rechten „Fensterrand“ Reicht vom oberen zum unteren Pfeil
28 FSSLIDER Box Touchexit Kind von FSROLL Wird vom Programm aus vergrößert...
29 FSFBOX Box Beinhaltet die File Namen In Bild 1 rechts etwas kleiner.
30-39 FSFILEO- Text Selectable, Text: „012345678.123“
FSFILE9 Radio Button, Die Leerzeichen sind wichtig.
Touchexit Nach diesen Objekten richten Sie das „Fenster“ aus. 30-39 sind Kinder von FSFBOX
40 FSABBRUC Button Selectable, Text: „ABBRUCH“
Exit
41 FSOK Button Selectable, Text: „OK“
Exit, Default
42 FSEXTBOX Box Hat 43-47 als Kinder Unsichtbare Box (Border 0) In Bild 1 sichtbar
43-47 FSEXTEN1 - Button Selectable, Text: „*. BAS“ oder ähnliches
FSEXTEN5 Shadowed, Wichtig: unbedingt5 Zeichen
Touchexit, „*. *“ z. B. wird im Programm
Radio Button auf,,.“ geändert

Tabelle

Die Routine inhalt_anzeigen () stellt je nach übergebenen Werten das Inhaltsverzeichnis dar und setzt den Slider richtig.

Wie geht das nun mit dem Inhaltsverzeichnis?

Dazu stellt das GEMDOS zwei Funktionen bereit:

Fsfirst (name,file_attribut) gemdos (0x4e)
Fsnext() gemdos (0x4f)
Fgetdta() gemdos (0x2f)

Fsfirst sucht nach einem Eintrag mit dem Namen name. Man kann also auf diese Art und Weise nachschauen, ob sich eine bestimmte Datei auf der Diskette befindet. Ist dies nicht der Fall, so wird eine Fehlernummer (-33) zurückgeliefert. Ist die Datei vorhanden, erhält man die 0 zurück und in einem 44 Byte großen Puffer befinden sich Name, Datum und weitere Informationen. Dieser Puffer hat das Format DTABUF. Die Startadresse wird mit der Funktion Fgetdta () ermittelt. Zu Fsfirst () gehört noch der Parameter file_attribut, der die Art der Datei angibt:

0 les- und beschreibbare Datei
1 schreibgeschützte Datei
2 verborgener Eintrag (im Desktop unterdrückt)
4 verborgener System Eintrag (im Desktop unterdrückt)
8 Volume Fabel 16 Subdirectory

32 Datei wurde geschrieben und geschlossen Je nachdem, welche Dateien man angezeigt haben will, addiert man ihre Nummern und erhält so das file_attri-but. So liefert z.B. 17 alle Subdirectories, schreibgeschützte und ungeschützte Dateien. Wird nicht der ganze Name angegeben, sondern z.B. „*.C??“, wird die erste der Dateien ermittelt. An die jeweils nächste kommt man mit Fsnext().

Die Funktion anzahl_files(name) ermittelt so die Anzahl der Einträge, deren file_attribut 17 ist und deren Namen entsprechend dem Ende des Pfadnamen ist.

Falls Sie vom Programm aus die Extension Buttons verändern wollen: in der Funktion power_f_sel () wird dies am Anfang anhand von gezeigt.

Bild 2

Fehler:

Der Unterstrich (_) ... Bitte nicht benutzen, sonst stürzt er ab. Das liegt aber nicht an mir, sonder am GEM. Komisch ist nur, daß er nur abstürzt, wenn die Eingabemaske nicht alle Zeichen zuläßt und sich wie hier auf File-Namen beschränkt (PPP).

Kein Fehler, aber etwas komisch sind in Unterverzeichnissen die ersten beiden Einträge. Das erste ist ein Ordner, der Name besteht aus einem Punkt. Der zweite ist ebenfalls ein Ordner, aber mit zwei Punkten. Im zweiten Eintrag ist das übergeordnete Directory enthalten. Um den Aufwand nicht noch mehr zu vergrößern, werden die beiden einfach mit angezeigt. Man kann sie jedoch nicht auswählen.

Wenn Sie Disketten mit sehr vielen ineinander verschachtelten Subdirectorys haben (Harddisk), sollten Sie darauf achten, daß der Pfadname nicht zu lang wird. Notfalls können Sie die Box breiter machen und mehr Platz für den Pfadnamen reservieren.

Sonstiges:

Im Programm sind noch einige Funktionen enthalten, die auch zur sonstigen GEM Programmierung nützlich sind:

copy (von,nach): Kopiert 32000 Bytes (= 8000 Longwords = 1 Bildschirm) von „von“ nach „nach“. Beide Adressen müssen gerade sein! (Der Bildschirmstart ist sowieso gerade und die Funktion Malloc () zum Anfordern von neuem Speicher liefert auch einen geraden Wert).

dialog_wahl (adresse,min,max): Wird angewendet, um das ausgewählte Element von mehreren Radio Buttons zu ermitteln. Also: die Disk Buttons A-0 sind alles Radio Buttons, d.h. es kann nur eines ausgewählt werden. Man übergibt das kleinste (min hier: FSAD) und das größte Element (max hier: FSOD) und erhält das Ausgewählte zurück.

Verwendete Literatur:

ATARI ST GEM von Data Becker ATARI ST Intern von Data Becker


/******************************************/ /* */ /* FILE-SELECTOR-ROUTINE für ATARI ST */ /* */ /* Geschrieben in C (Megamax) von */ /* */ /* Ulrich Mast */ /* Wilhelm-Maybach-Str.9 */ /* 7303 Neuhausen / Filder */ /* */ /******************************************/ #include "gemdefs.h" #include "osbind.h" #include "obdefs.h" #include "selector.h" #define hide() graf_mouse(M_OFF,01) #define show() graf_mouse(M_ON,01) #define FEHLER 1 /******************************************/ typedef struct dta_buffer { char dummy[21]; char file_attr; int time; int date; long size; char name[14]; } OTABUF; int contrl[12],intin[128],intout[128]; int ptsin[128],ptsout[128]; int work_in[12],work_out[57],handle; long fsel_addr; char *SCREEN,*SPEICHIR,*HILf; /******************************************/ main() { char pf[80],d[80],was[80]; deklaration(); strcpy(pf, "A:\\*.*"); strcpy(d,"WASWEIS ICH"); strcpy(was," File Selector Demo "); power_f_sel(pf,d,was); Cconws(pf); printf("\n"); Cconws(d); printf("\n"); Cconin(); ende(); } /******************************************/ ende() { rsrc_free(); Mfree(SPEICHER); v_clsvwk(handle); appl_exit(); exit(0); } /******************************************/ copy(von,nach) register long *von,*nach; { register int laenge; hide(); laenge=7999; asm { loop: move.l (von)+, (nach)+ dbf laenge,loop } show(); } /******************************************/ int dialog_wahl(adresse,min,max) register long adresse; register int max; int min; { register int i,wahl; for (i=min;i<==max;i++) if (select(adresse,i)) wahl=i; return(wahl); } /******************************************/ int anzahl_files(exten) register char *exten; { register int zaehler; if(Fsfirst(exten,17)<0) return(0); for(zaehler=1;Fsnext()>=0;zaehler++); return(zaehler); } /******************************************/ int select(tree,which) register OBJECT *tree; register int which; { return(((tree+which)->ob_state&SELECTED)?1:0); } /******************************************************************/ deklaration() { int i; appl_init(); /* gem anmelden */ for(i=0;i<10;work_in[i++]=1 ); work_in[10]=2; v_opnvwk(work_in,&handle,work_out); graf_mouse(ARROW,01); if(!rsrc_load{"SELECTOR.RSC")) /* RSC laden */ { £orm_alert(1,"[1][Fatal Error ... |RSC-File fehlt ... ][Sorry]”); ende(); } if(!rsrc_gaddr(0,SELECT ,&fsel_addr )) { forn_alert(1,”[1][Irgend etwas im|RSC-File stimnt nicht.][Sorry]"); ende(); } SPEICHER=(char*)Malloc(330001); if (!SPEICHER) { form_alert(l,"[l][Nicht genug Speicher ...][Sorry]"); ende(); } HILF=SPEICHER; /* hilfsbildschirmspeicher */ SCREEN=(char*) Logbase(); /* bildschirmstart */ } /***************************************************************/ power_f_sel(pfad, name,info) char *pfad,*name,*info; { int x,y,w,h,abbruch,ab,wahl,i,k,l,disk,ab_dat,nax_anz,pos; char *text,*string,dsk,hilf[80]; OBJECT *tree; TEDINPO *ted; tree=(OBJECT *) fsel_addr; ted=(TEDINFO *) ((tree+FSINFO)->ob_spec); strcpy((ted)->te_ptext,info); ted=(TEDINFO *) ((tree+FSNAME)->ob_spec); strcpy((ted)->te_ptext,name); ted=(TEDINFO *) ((tree+FSPATH)->ob_spec); strcpy((ted)->te_ptext,pfad); ted=(TEDINFO *) ((tree+FSREDRAW)->ob_spec); strcpy((ted)->te_ptext," "); strcpy((tree+FSEXTEN5)->ob_spec,"*.*"); k=Dsetdrv (Dgetdrv ()); /*angeschlossene */ for (l=1, disk=FSAD; disk<=FSOD; l*=2, disk++) /* drives */ { /* anzeigen */ if (k & l) objc_change(fsel_addr,disk,0,x,y,w,h,SHADOWED,0); else objc_change(fsel_addr,disk,0,x,y,w,h,DISABLED,0); } dsk=*pfad; disk=(int)(dsk-'A'); if((disk<0) || (disk>15)) return(FEHLER); objc_change(fsel_addr,disk+FSAD,0,x,y,w,h,SHADOWED<-SELECTED,0) ; Dsetdrv(disk); ab_dat=1; /* erste datei anzeigen */ for(i=FSFILE0;i< =FSFILE9; i++) /* dateiennamen löschen */ { ted=(TEDINPO *) ((tree+i)->ob_spec); text=(ted)->te_ptext; *text=0; } copy(SCREEN,HILF); /* bildschirm retten */ form_center (fsel_addr,&x,&y,&w,&h) ; form_dial(0,319,199,2,2,x,y,w,h); form_dial(1,319,199,2,2,x,y,w,h); objc_draw(fsel_addr,0,3,x,y,w,h); inhalt_anzeigen(pfad,ab_dat,Snax_anz); while(1) { abbruch=form_do(fsel_addr,FSNAME); ab=abbruch & 0x7fff; /* chne doppelklick */ if ((ab=FSOK)|| (ab=FSABBRUC)) /* exit button */ { objc_change(fsel_addr,ab,0,x,y,w,h,0,0); break; } if ((ab>=FSAD)&&(ab<=FSOD)) /* disk button */ { wahl=dialog_wahl(fsel_addr,FSAD,FSOD); disk=(wahl-FSAD); if ((disk<0)|| (disk>15)) return(FEHLER); dsk=(char)(disk+'A'); ted=(TEDINFO *) ((tree+FSPATH)->ob_spec); *(ted->te_ptext)=dsk; /* pfad ändern */ Dsetdrv(disk); /* drive setzen */ objc_draw(fsel_addr,FSPATH,0,x,y,w,h); /* pfad redraw */ inhalt_anzeigen(ted->te_ptext,ab_dat,&max_anz); abbruch=ab; /* kein doppelklick */ } if ((ab>=FSEXTEN1) && (ab<=FSEXTEN5)) /* entension button */ { wahl=dialog_wahl(fsel_addr, FSEXTEN1, FSEXTEN5); ted=(TEDINFD *) ((tree+FSPATH)->ob_spec); i=strlen(ted->te_ptext); for(string=(ted->te_ptext)+i; string>=(ted->te_ptext); string--) if (*string=='\\') break; string++; strcpy(string,(tree+wahl)->ob_spec); objc_draw(fsel_addr,FSPATH,0,x,y,w,h); inhalt_anzeigen(ted->te_ptext, ab_dat, &max_anz); abbruch=ab; } if ((ab>=FSFILE0)&&(ab<=FSFILE9)) /* dateiname */ { wahl=dialog_wahl(fsel_addr,FSFILE0,FSFILE9); ted=(TEDINFO *) ((tree+wahl)->ob_spec); string=ted->te_ptext; if(*string!=0) /* eintrag vorhanden */ { if (*(string+1)==7) /* ordner */ { ted=(TEDINFD *) ((tree+FSPATH)->ob_spec); i=strlen(ted->te_ptext); for(string=(ted->te_ptext)+i;string>=(ted->te_ptext) ;string--) if (*string=='\\') break; strcpy(hilf,string); /* extension retten */ string++; ted=(TEDINFO *) ((tree+wahl)->ob_spec); text=ted->te_ptext; text+=3; for(i=0;i<12;i++) { if (*text=0) break; if(*text!=' ') *string++=*text; text++; } strcpy(string,hilf); objc_draw(fsel_addr,FSPATH,0,x,y,w,h); ted=(TEDINFO *) ((tree+FSPATH)->ob_spec); inhalt_anzeigen(ted->te_ptext,ab_dat,&max_anz); abbruch=ab; /* kein doppelklick */ } else /* datei */ { string+=3; ted=(TEDINFD *) ((tree+FSNAME)->ob_spec); text=ted->te_ptext; for(i=0;i<8;i++) *text++=*string++; string++; for(i=0;i<3;i++) *text++=*string++; *text=0; objc_draw(fsel_addr,FSNAME,0,x,y,w,h); } } } if (ab=FSREDRAW) /* redraw */ { ted=(TEDINFO *) ((tree+FSPATH)->ob_spec); inhalt_anzeigen(ted->te_ptext,ab_dat,&max_anz); abbruch=ab; } if (ab=FSMOVEUP) /* pfeil nach oben */ { if(ab_dat>1) { ab_dat--; ted=(TEDINFO *) ((tree+FSPATH)->ob_spec); inhalt_anzeigen(ted->te_ptext,ab_dat,&max_anz); } abbruch=ab; /* kein doppelklick */ } if (ab==FSMOVED0) /* pfeil nach unten */ { if(ab_dat<(max_anz-9)) { ab_dat++; ted=(TEDINFO *) ((tree+FSPATH)->ob_spec); inhalt_anzeigen(ted->te_ptext,ab_dat,Smax_anz) ; } abbruch=ab; /* kein doppelklick */ } if (ab==FSSLIDER) /* slider */ { if(max_anz>10) { pos=graf_slidebox (tree,FSROLL,FSSLIDER,1)+500/(max_anz-10) ab_dat=((max_anz-10)*pos)/1000; ab_dat++; ted=(TEDINFO *) ((tree+FSPATH)->ob_spec); inhalt_anzeigen(ted->te_ptext,ab_dat,&max_anz); } abbruch=ab; /* kein doppelklick */ } if (ab==FSROLL) /* roll - balken */ { graf_mkstate(&i,&pos,&i,&i); /* nur y-pos wichtig */ objc_offset(tree,FSSLIDER,&i,&k); if(pos>k) { ab_dat+=10; if(ab_dat>(max_anz~9)) ab_dat=max_anz-9; } else { ab_dat-=10; if (ab_dat<1) ab_dat=1; } ted=(TEDINFO *) ((tree+FSPATH)->ob_spec); inhalt_anzeigen(ted->te_ptext, ab_dat,&max_anz); abbruch=ab; /* kein doppelklick */ } if(ab=FSCLOSER) /* Schließfeld */ { ted= (TEDINFO *) ((tree+FSPATH)->ob_spec); i=strlen(ted->te_ptext); for(string=(ted->te_ptext)+i;string>=(ted->te_ptext) ;string--) if (*string=='\\') break; for(text=string-1;text>=(ted->te_ptext);text--) if (*text='\\') break; if (*text='\\') { string++; text++; strcpy(text,string); objc_draw(fsel_addr,FSPATH,0,x,y,w,h); } inhalt_anzeigen(ted->te_ptext,abjiat,Smax_anz); DTABUF *puffer; tree= (OBJECT *) fsel_addr; puffer= (DTABUF *) Fgetdta(); i=strlen(pfad); for(string=pfad+i;string>=pfad;string--) if (*string='\\') break; name=string+1; for(string=pfad+2,i=0;string<name;string++,i++) hilf[i]=*string; hilf[i]=0; Dsetpath(hilf); *anzahl=anzahl_files(name); if(*anzahl<=10) { ((tree+FSSLIDER)->ab_y) =0; ((tree+FSSLJDER)->ob_height)=((tree+FSROLL)->ob_height); abnr=1; } else { (tree+FSSLIDER)->ob_y=((tree+FSROLL)->ob_height*(abnr-1))/(*anzahl); (tree+FSSLIDER)->ob_height=((tree+FSROLL)->ob_height*10)/ (*anzahl); } ted=(TEDINFO *) ((tree+FSREDRAW)->ob_spec); text=(ted)->te_ptext; strcpy(text," "); /* sieht besser aus */ strcat(text,name); strcat(text," "); fehler=Fsfirst(name,17); for(i=2;i<abnr;i++) if(fehler>=0) fehler=Fsnext(); for (i=FSFILE0;i<=FSFILE9;i++,abnr++) { if ((abnr!=1)&&(*anzahl>0)) fehler=Fsnext(); ted=(TEDINFO *) ((tree+i)->ab_spec); text=(ted)->te_ptext; if((fehler>=0) && (*anzahl>0)) { (tree+i)->ob_flags |=SELECTABLE; /* auswählbar */ if (puffer->name[0]0=46) (tree+i)->ob_flags &= TOUCHEXIT; /* kein touchexit */ else (tree+i)->ob_flags |= TOUCHEXIT; /* touchexit */ *text++*=32; *text++=((puffer->file_attr=16) ? 7 ; 32); *text++=32; for(k=0,l=0;(puffer->name[k]!='.')&&(l<8);l++) *text++=puffer->name[k++]; for(;l<8;l++) *text++=32; for (l=0;l<4;l++) *text++=puffer->name[k++]; *text=0; } else { (tree+i)->ob_flags &= ~SELECTABLE; /* nicht auswählbar */ (tree+i)->ob_flags &= ~TOUCHEXIT; /* -kein touchexit */ (tree+i)->ob_state = NORMAL; /* nicht ausgewählt */ *text=0; } } objc_draw(fsel_addr,FSTOTBOX,2,1,1,500,380); /* filebox redraw */ } /***************************** ENDE ******************************/


Ulrich Mast


Links

Copyright-Bestimmungen: siehe Über diese Seite
Classic Computer Magazines
[ Join Now | Ring Hub | Random | << Prev | Next >> ]