In diesem Monat wollen wir uns ein wenig mit der Pfaderkennung von Programmen beschäftigen, da dies besonders im Zusammenhang mit der Fileselectorbox gewisse Schwierigkeiten zu bereiten scheint. Außerdem wollen wir auf den Objekttyp ICON eingehen, aus dem viel mehr herauszuholen ist, als mancher Programmierer denkt.
Zunächst wenden wir uns aber der Pfaderkennung zu. Dazu schauen wir uns noch einmal kurz den Diskettenaufbau an. Auf jeder Diskette können eine gewisse Anzahl von Dateien abgespeichert werden. Um bei einer grossen Anzahl von Dateien eine bessere Übersicht zu gewährleisten und die Zeit des Suchens zu verkürzen, besteht zusätzlich die Möglichkeit, die Diskette in Ordner einzuteilen, in denen sich wiederum Dateien befinden. Gerade auf einer Festplatte, bei der dreihundert Dateien keine Seltenheit sind, hilft dies, die Übersicht zu gewährleisten. Beispielsweise würde man auf der obersten Ebene ausschließlich Ordner wie SPRACHEN, MALPROGRAMM, UTILITIES anlegen. In dem Ordner SPRACHEN könnten dann wiederum Ordner mit den Namen C, PASCAL, BASIC etc. liegen, in denen die entsprechenden Programme zu finden sind.
Bild 1:
Pfadname: A:\ordner ... \search.src
| | |
Diskstation die Ordner Suchkr.
Aufbau eines Pfades
Listing 1: Do_file in C
#include <gemdefs.h>
#include <obdefs.h>
#include <osbind.h>
char path[64],name[64],sr[10],ret[]64];
main()
{
int c,taste,form_key=1;
appl_init();
graf_mouse(ARROW,01);
strcpy(sr,"*.*"); /* Kann gegen beliebig ausgetauscht werden */
path[0]=0;
while (form_key==1)
{
taste=do_file(path,name,sr,ret);
if (taste==0)
form_key=form_alert(1, "[1][Taste ABBRUCH gedrückt][ OK | ABBRUCH ] ");
else
form_key=form_alert(1,"[1][Taste OK gedrückt][ OK | ABBRUCH]");
}
appl_exit();
}
/*******************************/
/* */
/* Pfad-Handhabung */
/* mit */
/* Fileselektorbox */
/* */
/* 14.07.1987 S. Höhn */
/* */
/*******************************/
/* fpath[] = Pfadname: fpath[0]=0 bedeutet Einsetzen des aktuellen
Pfades
fname[] = Dateiname: fname erscheint in der Fileselektorbox und ist
getrennt von dem eigentlichen Pfadnamen
srch[] = Extender: mögliche Pfaderweiterung wie zum Beispiel
'*.*', '*.pas', '*.c' etc.
fpn[] = kompletter Pfad: enthält Pfad wie auch den Dateiname
Rückgabewert = 0: Die Taste ABBRUCH wurde gewählt
1: Die Taste OK wurde gewählt
*/
int do_file(fpath,fname,srch,fpn)
char *fpath,*fname,*srch,*fpn;
{
char tpath[64];
char tname[64];
int i;
int key;
long str_len();
strcpy(tpath,fpath); /* alten Pfad retten */
strcpy(tname,fname); /* alten Dateinamen retten */
if(fpath[0] == '\0') /* wenn kein Pfad vorhanden */
{ /* aktuellen Pfad erstellen */
fpathfO] = Dgetdrv() + 'A'; /* Laufwerksbezeichnung holen */
strcpy(&fpath[1],":"); /* Doppelpunkt anhängen */
Dgetpath(fpn,Dgetdrv()); /* Pfad holen */
strcat(fpath,fpn); /* Pfad anhängen */
strcat(fpath,"\\"); /* Backslash anhängen */
}
strcat(fpath,srch); /* Suchpfad anhängen */
fsel_input<fpath,fname,&key); /* Fileselektorbox aufrufen */
if(key == 1) /* OK gedrückt */
{ /* Pfad und Namen zusammenkopieren */
i = strlen(fpath); /* Ende des Gesamtpfades */
while(fpath[1] != 0x5c) /* Rücksuchen bis Backslash */
i--; /* also Anfang des Suchpfades */
fpath(++il = '\0'; /* abschneiden */
strcpy(fpn, fpath); /*, Pfad kopieren */
strcat(fpn,fname); /* Namen anhängen */
}
else {
strcpy(fpath,tpath); /* Pfad wieder zurückkopieren */
strcpy(fname,tname); /* Namen zurückkopieren */
strcpy(fpn,"\0"); /* Gesamtpfad auf Null setzen */
}
return(key); /* Taste zurückgeben */
}
Listing 2: Do_file in Pascal
PROGRAM Test;
CONST {$I GEMCONST.PAS}
TYPE {$I GEMTYPE.PAS}
pathname=packed Array [1..80] of Char;
VAR pfad,name,raus,a,such:String;
x:Boolean;
{$I GEMSUBS.PAS}
FUNCTION dgetdrv:integer;
GEMDOS($19);
PROCEDURE dgetpath(VAR path:pathname;drive:integer) ;
GEMDOS($47);
FUNCTION Do_File(VAR fpath,fname,srch,fpn:String):Boolean;
VAR tpath,tname:String;
mpath:pathname;
i,f:integer;
key:boolean;
Begin
tpath:=fpath; {Pfadname retten}
tname:=fname; {Programmname retten}
If fpath='' Then {bei leerem Pfad muß der aktuelle Pfad}
Begin {genommen werden}
fpath:=concat(chr(dgetdrv + ord('A')),':'); {Diskette und }
dgetpath(mpath,dgetdrv); { aktuellen Pfad holen }
f:=1;
While mpath[f]>chr(0) Do { ankopieren )
Begin
fpath[f+2]:=mpath[f];
f:=f+1;
End;
fpath[f+2]:='\'; { Backslash anhängen }
fpath[0]:=chr(f+2); { Länge des Strings setzen }
End;
f:=length(fpath);
While fpath[f]<>'\' Do f:=f-1;
fpath[0]:=chr(f);
fpath:=concat(fpath,srch);
key:=Get_In_File(fpath,fname); {Aufruf der File-Selector-Box}
If key Then {wenn mit “OK" bestätigt wurde}
Begin {muß der neue Pfad und der neue Name}
fpn:=fname; (genommen werden)
f:=length(fpath);
While fpath[f]<>'\' Do f:=f-1;
fpath[0]:=chr(f);
f:=length(fname);
While fname[f]<>'\' Do f:=f-1;
fname:=copy(fname,f+1,length(fname)-f);
End
Else {ansonsten werden die alten Daten genommen}
Begin
fpath:=tname;
fname:=tname;
End;
Do_File:=key; {Ergebnis der Funktion wird festgesetzt}
End;
BEGIN
If Init_Gem>=0 Then
Begin
writeln('Eingabe: ');
write('Pfad: '); readln(pfad);
write('Name: '); readln(Name);
write('Such: '); readln(Such);
x:=Do_File(pfad,name,such,raus);
wr1teln('Ausgabe ');
writeln('Pfad -> ',pfad);
writeln('Name -> ',name);
writeln('Raus -> ',raus);
writeln('Ergebnis ->',x);
readln(a);
Exit_Gem;
End;
END.
Wir sehen, daß zu einem Programmnamen nicht nur der eigentliche Dateiname, sondern auch die Diskettenstation und der Pfad - dies sind die Namen der einzelnen Ordner - gehören. Ein Beispiel: Wollten wir das Programm TURBO.PRG aufrufen, das in dem Ordner PASCAL im Ordner SPRACHEN auf der Diskettenstation B liegt, so müßten wir folgenden Gesamtpfad angeben: „B:\SPRACHEN\PASCAL\TURBO.PRG“. Auffällig dabei ist, daß jeder Ordner durch das Zeichen '' (Backslash) getrennt werden muß. Mit jedem weiteren '' kommt man in der Verschachtelung eine Ebene tiefer.
Nun wollen wir die ganze Theorie etwas veranschaulichen, uns den im Betriebssystem zur Verfügung stehenden Routinen zuwenden und dabei eine C-Routine erarbeiten, die uns für die Pfadverwaltung die größte Arbeit abnimmt. Konstruieren wir uns eine Routine, die bei nicht vorhandenem Pfad den momentan aktuellen Pfad und die dazugehörige Diskettenstation heraussucht, die Fileselectorbox aufruft und dann den selektierten Namen mit dem eingestellten Pfadnamen verknüpft. Diese Routine heißt do_file() und ist in den Listings 1 (C), 2 (PASCAL) und 3 (BASIC) zu finden. Am C-Listing möchte ich nun die uns zur Verfügung stehenden Routinen erarbeiten.
Als Übergabe benötigt do_file() den Pfadnamen, den man auch einfach auf Null setzen kann, um den aktuellen Pfadnamen eintragen zu lassen; denjenigen Dateinamen, der, falls vorhanden, als Vorgabe in der Fileselectorbox erscheint und einen zusätzlichen Extender wie ’.pas’ oder '.' etc. hat, um nach bestimmten Dateien suchen zu können. Wenden wir uns also dem Ablauf der Prozedur zu.
Zunächst werden angegebener Pfad-und Dateiname in den Feldern tpath[] und tname[] zwischengespeichert. Dann wird geprüft, ob ein Pfadname angegeben wurde oder nicht. Ist kein Pfad angegeben, so muß die Prozedur den aktuellen Pfad ermitteln.
Der Gesamtpfad ist, wie in Bild 1 gut zu erkennen ist, aus verschiedenen Teilen zusammengesetzt: Laufwerksbezeichnung, Doppelpunkt, Ordner und Wildcard (Suchangabe wie zum Beispiel '.pas’). Der erste Schritt, um den Gesamtpfad zu erstellen, ist das Ermitteln des aktuellen Laufwerkes. Dies geschieht durch die Routine Dgetdrv(), die sich im GEMDOS befindet (=#=define Dgetdrv() gemdos(0xl9)). Diese Routine liefert einen Wert - angefangen bei Null - zurück, der das entsprechende Laufwerk kennzeichnet. Dabei entspricht eine Null dem Laufwerk A, eine 1 dem Laufwerk B usw. Addieren wir nun noch den ASCII-Wert des Buchstabens A (’A’) hinzu, erhalten wir die Laufwerkskennung als Buchstaben. Anschließend wird an den Buchstaben ein Doppelpunkt angehängt. Als weiteren Schritt müssen wir den aktuellen Pfad ermitteln. Auch in diesem Fall ist uns GEMDOS ein eifriger Helfer. Dgetpath() benötigt als Parameter einen String, in den der Pfad hineingeschrieben wird - in unserem Fall fpn[] - und das gewünschte Laufwerk, das wir oben schon herausgefunden haben. Diesen gewonnenen Pfad hängen wir an die Laufwerksbezeichnung an und schließen ihn mit einem Backslash ’\ vorerst ab. Als letzten Arbeitsgang vor dem Aufruf der Fileselectorbox, wird noch der Suchpfad ’ * .pas’ angefügt. Wichtig ist, daß, wenn keine bestimmten Dateien gewünscht sind, der Suchpfad ’ . * ’ angehängt wird (dies könnte auf Wunsch in die do_file()-Routine eingebaut werden, zum Beispiel durch ’if (!srch[0]) then strcat(fpath,".")'.
Nun wird die Fileselectorbox aufgerufen, in der unser Gesamtpfad in der oberen Zeile und unser Dateiname -sofern vorhanden - in der rechten Zeile erscheint. Nach dem Verlassen der Box durch Anklicken der OK-oder ABBRUCH-Taste, müssen wir eine Fallunterscheidung treffen. Hat der Benutzer die Taste ABBRUCH angewählt, so werden die alten Bedingungen wieder hergestellt, indem der zwischengespeicherte Pfadname und Dateiname in die ursprünglichen Variablen kopiert werden. Außerdem wird der Rückgabestring gelöscht, da kein sinnvoller Zusammenhang zwischen eventuell angewähltem Pfad und Namen besteht. Hat der Benutzer aber die OK-Taste angeklickt, so müssen wir aus dem Pfad und dem selektierten Namen einen Pfad herstellen, indem wir den Suchpfad mit diesem Dateinamen überschreiben und in den Rückgabestring fpn[] kopieren. Zum Schluß wird noch als Rückgabewert mitgeteilt, ob ABBRUCH (Rückgabe = 0) oder OK (Rückgabe = 1) angewählt worden war.
Wie Sie in Listing 2 und 3 sehen, haben wir diese recht nützliche Routine auch in Basic und auf mehrfachen Wunsch in PASCAL programmiert. Ich hoffe, daß die Erklärung anhand des C-Programms leicht auf die anderen Programme zu übertragen ist, zumal sie auch ausführlich dokumentiert sind. Wir haben versucht, die gleichen Bedingungen auch für BASIC zu schaffen, nur ist es allerdings zum ’Abspei-chern’ der neuen Pfade und Namen nötig, die Eingangsvariablen auch als Ausgangsvariablen zu definieren: Lästig, aber nicht anders zu machen, wenn man auf global gehaltene Variablen verzichten möchte. Noch ein Tip zur Handhabung: Die Ubergabevariablen des Aufrufes sollten global definiert werden, da die Routine beim zweiten Aufrufen dann nicht den aktuellen Pfadnamen wieder heraussuchen muß, sondern den zuletzt benutzten verwenden kann. Jetzt werden Sie sich sicher fragen, ob denn der aktuelle und der mit der Fileselectorbox angewählte Pfad nicht der gleiche seien?! Aus der Fragestellung erkennt man schon, daß dies nicht der Fall ist. Nur dann, wenn sie explizit erreichen wollen, daß der von Ihnen ausgewählte Pfad zum aktuellen Pfad wird - auf den zum Beispiel auch ein Resource-Load zugreifen würde —, müssen Sie dies dem Betriebssystem mitteilen.
Dies teilen Sie GEMDOS durch die beiden folgenden Befehle mit: Mit der Funktion DsetdrvQ übergeben Sie als Parameter die Diskettenstation, die zur aktuellen Diskettenstation gemacht werden soll. Den Pfad - ohne Laufwerksangabe - übergeben Sie dann der Funktion Dsetpath(). Damit dürften dem weiteren Programmieren in Bezug auf die Pfadverwaltung keine weiteren Probleme im Wege stehen.
Listing 3: Do_file in GFA-Basic
Num$ ="abcdefgh.doc"
Pfad$ = "A:\"
Frm_key= 1
While Frm_key=1
Gosub Do_fi1e(Pfad$,Nam$,"*.*",*Pfad$,*Nam$,*Gespfad$,*Taste)
If Taste =0 Then
Alert 1,"Taste ABBRUCH gedrückt!",1," OK | ABBRUCH “,Frm_key
Else
Alert 1,"Taste OK gedrückt!",1," OK | ABBRUCH ",Frm_key
Endif
If Frm_key=1 And Taste=1 Then
Chdrive(Asc(Left$(Pfad$,1))-Asc("A")+1)
Void Gemdos(59,L:Varptr(Pfad$))
' Chdir Pfad$
Endif
Wend
'
Procedure Do_file(Fpath$,Finame$,Srch$,Fpath%,Finame%,Fpn%,Key%)
'
Local Tpath$,Tname$,I%
Tpath$=Fpath$
Tname$=Finame$
If Finame$="" Then
Fpath$=Chr$(Gemdos(25)+Asc("A"))+ “:"+Dir$(0)+"\"
Endif
Fpath$=Fpath$+Srch$
Fileselect Fpath$,Finame$,Fpn$
If Fpn$="" Then
Fpath$=Tpath$
Finame$=Tname$
Key=0
Else
I=Len(Fpn$)
While I>0 And Mid$(Fpn$,I,1)<>"\"
Dec I
Wend
Fpath$=Left$(Fpn$,1)
Finame$=Right$(Fpn$,Len(Fpn$)-I)
Key=1
Endif
*Fpath%=Fpath$
*Finame%=Finame$
*Fpn%=Fpn$
*Key%=Key
Return
Viele unter Ihnen, die sich mit der Erstellung von Resourcen beschäftigt haben, werden sicher bemerkt haben, daß die Struktur des Icons recht aufwendig ist und daher leicht für Verwirrung sorgen kann. Deshalb wollen wir uns heute mit der ICONBLK-Struktur des Icons beschäftigen und dazu ein paar hilfreiche Routinen veröffentlichen; wir folgen damit einem Wunsch von vielen Lesern.
Listing 4: Die Iconblk-Struktur
typedef struct object
{
int ob_next; /* -> nächstes Objekt */
int ob_head; /* -> Kopf des Unterobjektes */
int ob_tail; /* -> Ende des Unterobjektes */
unsigned int ob_type; /* Objekttyp*/
unsigned int ob_flags; /* Flags */
unsigned Int ob_state; /* Status */
char *ob_spec; /* spezielle Objektinfo */
int ob_x; /* linke obere Ecke X- Koord. */
int ob_y; /* linke obere Ecke Y- Koord. */
int ob_width; /* Breite des Objektes */
int ob_height; /* Höhe des Objektes */
} OBJECT;
typedef struct icon_block
{
int *ib_pmask; /* Adresse der Maskendaten */
int *ib_pdata; /* Adresse der Bilddaten */
char *ib_ptext; /* Adresse des Icontextes */
int ib_char; /* Buchstabe incl. Farbe */
int ib_xchar; /* X-Koordinate des Buchstabens */
int ib_ychar; /* Y-Koordinate des Buchstabens */
int ib_xicon; /* X-Koordinate des Icons */
int ib_yicon; /* Y-Koordinate des Icons */
int ib_wicon; /* Breite des Icons */
int ib_hicon; /* Höhe des Icons */
int ib_xtext; /* X-Koordinate des Textes */
int ib_ytext; /* Y-koordinate des Textes */
int ib_wtext; /* Breite der Textbox */
int ib_htext; /* Höhe der Textbox */
} ICONBLK;
typedef struct bit_block /* Struktur eines Images */
{
int *bi_pdata; /* Adresse der Bilddaten */
int bi_wb; /* Breite des IMAGE in Bytes*/
int bi_hl; /* Höhe in Punkten */
int bi_x; /* X-Koordinate des Bildes*/
int bi_y; /* Y-Koordinate des Bildes*/
int bi_color; /* Farbe des IMAGE */
} BITBLK;
In Listing 4 befindet sich die erwähnte Struktur des Icons. Für diejenigen, die sich nicht mit ’C’ auskennen, sei gesagt, daß LONG 4 Bytes und INT 2 Bytes bedeuten und vergleichbar mit einem RECORD in Pascal sind. Das Element ib_xchar würde man entsprechend an der 14. Stelle bezogen auf den Anfang der Struktur finden. Zunächst aber wollen wir uns wegen des besseren Verständnisses die Struktur eines IMAGES anschauen, da ein ICON ein IMAGE mit einigen zusätzlichen Features ist.
Tabelle 1:
DATA | MASK | Ergebnis |
---|---|---|
0 | 0 | Hintergrund erscheint |
0 | 1 | Maskenfarbe |
1 | 0 | Iconfarbe |
1 | 1 | Iconfarbe |
Zunächst befindet sich als erstes Element der IMAGE-Struktur ein Zeiger auf die Datenmenge des Bildes. In der Datenmenge entspricht einem gesetzten Bit einem Punkt auf dem Bildschirm, woraus automatisch folgt, daß nur zweifarbige Bilder (gesetzter und nichtgesetzter Punkt) möglich sind. An den Stellen, an denen kein Punkt gesetzt ist, wird später der Hintergrund durchscheinen! Als nächster Eintrag befindet sich in der Struktur die Breite des IMAGES in Bytes. Da sich die Daten in einem Wortfeld befinden, muß dieser Wert gerade sein. Als nächste Einträge folgen die Höhe des Bildes in Bildschirmpunkten, X- und Y-Koor-dinate desselben sowie ein Wort, das die Farbe des IMAGEs enthält.
Zu den Koordinaten eines IMAGEs sollte noch ein wenig gesagt werden: Wie Sie sicher wissen, enthält jedes Objekt innerhalb des Baums einen Eintrag - so auch ein IMAGE oder ein ICON. Jedes Objekt hat allerdings auch eine X/Y-Koordinate sowie eine Höhe und eine Breite. Wie erwähnt, zeigt sich, daß in der IMAGE-Struktur (wie auch in der ICON-Struktur) eine zusätzliche X/Y-Koordinate vorhanden ist, woraus sich die Frage ergibt, warum eine zweifache Angabe der Koordinaten benötigt wird. Um Sinn und Zweck dieser doppelten Angabe zu verstehen, müssen wir uns daran erinnern, daß wir Objekte wie auch ICONS und IMAGES mit der Maus selektieren können. Da das AES überprüft, ob ein Objekt während eines Mausklicks 'getroffen’ wurde, muß es auch den Umfang des Objektes kennen. Dieser Umfang wird mit der X/Y-Koordinate, Breite und Höhe angegeben, die sich in der OBJECT-Struktur des Objektes befinden. Die Koordinate des IMAGES (oder ICONS) in der speziellen Struktur gibt eine Verschiebung des Bildes relativ zur in der OBJECT-Struktur gegebenen Koordinate an. Praktisch heißt das, daß man die selektierbare Zone eines Bildes sehr groß machen kann und das Bild dann in die Mitte dieser Zone postiert. Ein Tip: Wollen Sie wissen, wie groß diese Zone ist, so stellen Sie in der OBJECT-Struktur des ICONS oder IMAGES ’OUTLINED’ ein - dadurch wird dieser Bereich sichtbar. Noch ein kleiner Hinweis: Wie Sie gleich sehen werden, enthält ein ICON einen zusätzlichen Text. Achten Sie bitte darauf, daß sich der Text nicht außerhalb des selektierbaren Bereichs befindet, da ein Benutzer Ihres Programms den Text anklicken könnte und trotzdem nicht das Icon selektiert würde.
Womit’ wir beim Thema ICON wären: Was unterscheidet ein ICON von einem IMAGE? Der Unterschied liegt darin, daß man außer einer zusätzlichen Bildmanipulationsmöglichkeit einen BOXCHAR und einen STRING hinzugefügt hat. Am besten kann man sich dies an den Diskettenstationen des DESKTOPS verdeutlichen, wobei hier Buchstabe und Name des ICONs sinnvoll genutzt wurden.
Wie wir oben bei der Betrachtung der Bilddaten eines IMAGEs festgestellt haben, scheint bei einem nichtgesetzten Bit der Hintergrund durch. Um dies gezielt zu verhindern, gibt es bei einem Icon eine zusätzliche Datenmenge, die Maske. Wird in dieser Maske an einer Stelle, an der in der Bildmenge kein Punkt gesetzt worden ist, ein Bit (Punkt) gesetzt, so scheint der Hintergrund an dieser Stelle nicht durch. Ist an dieser Stelle in der Maske kein Bit gesetzt, so scheint folgerichtig der Hintergrund wie gewohnt durch. In Tabelle 1 ist besonders deutlich zu sehen, daß die Maske nur bei einem nichtgesetzten Bit in den Bilddaten eine Auswirkung hat. Wird nun ein ICON selektiert, so erscheint das Bild der Maske in der Farbe des eigentlichen Bildes und umgekehrt. Ist zum Beispiel das Bild rot und die Maske grün, so ist nach dem Selektieren die Maske rot und das Bild grün.
Nachdem wir nun wissen, wie wir das ICON benutzen können, wollen wir uns die ICONBLK-Struktur genauer anschauen. Der erste Eintrag enthält die Adresse der MASKE, während im zweitem Eintrag die Adresse der Bilddaten steht. Der dritte Eintrag ib_ptext enthält einen Zeiger auf einen String, den Text des Icons. Der nächste Eintrag ib_char ist etwas komplizierter, da er nicht nur den Buchstaben des Icons enthält, sondern auch die Farben des Bildes und der Maske. Das Wort ist folgendermaßen aufgebaut:
0000 0000 00000000
| | |
Vordergr. Hintergr. Buchstabe
"Farbwert des Icons: ib__char”
Zum Setzen des Wortes und Auseinanderziehen dieses Farbwortes habe ich die zwei Routinen make_color() und crack_color() in Listing 5 beigefügt, die diese Arbeit etwas erleichtern. Die folgenden Koordinaten des Buchstabens sind genauso relativ zu betrachten wie die nachfolgenden Koordinaten des ICONs und des Textes. Die Breite des Icons wird genauso wie bei dem IMAGE in Worten angegeben, wobei diese Zahl durch zwei teilbar sein muß. Auch die Höhe wird wie beim IMAGE in Bildschirmpunkten angegeben. Man sieht also, ein Icon bietet eine Menge an Möglichkeiten. Interessant sind noch die beiden letzten Einträge ib_wtext und ib_htext. Hiermit läßt sich sogar die Größe der Textbox einstellen, was leider oftmals nicht genutzt wird.
Listing 5
crack_color(cwort,parts)
int cwort;
CW *parts;
{
parts->vorder= (cwort>>12)&0xf;
parts->hinter= (cwort>>8)&0xf;
parts->buchstabe = cwort&Oxff;
}
int make_color(parts)
CW parts;
{
return(((parts.vorder)<<12)|((parts.hinter)<<8)|parts.buchstabe);
}
Nun möchte ich noch einige Ideen und Vorschläge zum Thema Icons einbringen. Icons sind nicht nur eine Verschönerung des Programms, sondern sollten auch zum besseren und schnelleren Verständnis häufiger als bisher eingesetzt werden. Nicht umsonst liegt auf dem DESKTOP ein Mülleimer in ICONFORM und nicht als reiner Text. Manchmal sagt ein kleines Bild mehr als viele Wörter und ist auch einprägsamer. Es stehen ihnen auch viele Möglichkeiten zu Verfügung: So können Sie zum Beispiel durch einfaches Verändern des Bilddatenzeigers und Neuzeichnen des Iconobjektes das Aussehen verändern. Wie wäre zum Beispiel ein Mülleimer in einem Ihrer Programme, der, wenn er gefüllt ist, auf einmal einen geschlossen Deckel hat. Übrigens brauchen Sie natürlich nicht für jedes Icon eine neue Bilddatenmenge. Stellen Sie sich vor, was das für das DESKTOP zur Folge hätte, denn teilweise sind dreißig und mehr Icons zu sehen. Sie lassen einfach mehrere Icons auf eine Bilddatenmenge zeigen.
Zum Schluß möchte ich Sie noch auf etwas hinweisen. Wenn Sie mit dem RCS (Resource Construction Set) von Atari arbeiten, werden Sie feststellen, daß Sie zwar Icons benutzen, diese aber nicht im RCS erstellen können. Dies geschieht mit einem sogenannten Iconeditor der verschiedensten Firmen, der es ermöglicht, eine bestimmte Datenmenge abzuspeichern, die Sie dann mit dem RCS laden können. Dabei verfahren Sie folgendermaßen: Legen Sie ein Icon in Ihre Dialogbox und selektieren Sie es. Dann können Sie unter dem Menü OPTIONS die Option LOAD anwählen. Darauf können Sie die Bilddaten und Maskendaten nacheinander laden.
Damit möchte ich mich für diesen Monat verabschieden, allerdings nicht, ohne Sie einmal mehr darauf hinzuweisen, daß Sie mir Ihre Probleme und Nöte bei der täglichen Programmierarbeit mit dem ST gerne schicken können. Übrigens, wenn Sie mitgeteilt bekommen möchten, wann ich mich Ihres Problems annehme oder ob ich es schon in anderen Ausgaben der ST-Computer getan habe, so bitte ich Sie, einen frankierten und adressierten Rückumschlag beizulegen. Und bitte, vergessen Sie bei Ihrer Anschrift die Telefonnummer nicht, denn manche Probleme könnten am Telefon sehr schnell geklärt werden. Viel Spaß beim Programmieren und bis zum nächsten Monat!
(SH)