Sicher sind vielen Lesern schon Programme begegnet, die zwar mit MenĂŒleisten, Dialogen und sonstigen GEM-Objekten arbeiten, aber keine * .RSC Datei benötigen. Typisches Beispiel: Tempus der Editor von CCD. Der folgende Beitrag und das dazugehörende Listing zeigen, wie man in seinen eigenen C-Programmen die Resource Datei in den Programmcode integriert.
Der Sinn der Resource
In letzter Zeit hat sich auf dem Gebiet der BenutzeroberflĂ€chen einiges getan. Ein Personal Computer (im Sinne des Wortes, und nicht eines bestimmten Herstellers) ist ohne Bildschirmgrafik und Maus kaum noch an den Mann oder die Frau zu bringen. Auf die Schnittstelle zum Benutzer (Neuhochdeutsch: Userinterface) wird immer mehr Wert gelegt und so bleibt es nicht mehr den Informatikern ĂŒberlassen sich darĂŒber Gedanken zu machen, wie die Software mit dem Benutzer kommuniziert, sondern zunehmend werden Spezialisten der Fachgebiete Ergonomie und Psychologie zu solchen Aufgaben herangezogen. Software-Ergonomie ist das aktuelle Schlagwort, und wird es wohl auch noch eine Weile bleiben. DarĂŒber darf jedoch die Softwaretechnik nicht vergessen werden. Und genau unter diese Rubrik fĂ€llt das Konzept der Resourcedatei. Der Trend geht deutlich zu einer Trennung zwischen den Funktionen und der BenutzeroberflĂ€che eines Programms. Dies dient im Wesentlichen der PortabilitĂ€t von Programmen. Wer schon einmal versucht hat ein Programm von Rechner X auf Rechner Y zu portieren, dem ist sicher aufgefallen, daĂ die Probleme zum gröĂten Teil in der Ein-/Ausgabe auftreten und damit an der Schnittstelle zum Benutzer. Ein weiterer Punkt ist die Ăbersetzung von einer Landessprache in eine Andere. Speziell in dieser Hinsicht muĂ man das Konzept von GEM loben. Man kann Programme, deren Benutzerschnittstelle komplett in der Resource-Datei definiert ist, in eine andere Landessprache ĂŒbersetzen, ohne im Besitz des Quelltextes zu sein und ohne neu zu compilieren. Man benötigt dazu lediglich ein Programm zum Editieren der Resource-Dateien von GEM. Ein solches Programm ist das RCS (Resource Construction Set) aus dem Entwicklungspaket fĂŒr den ATARI ST. Es ist fĂŒr 15 Mark bei der ST-Computer erhĂ€ltlich (siehe Public Domain Service).
FĂŒr den Software-Entwickler haben die Resourcen den Vorteil, daĂ die optische PrĂ€sentation der BenutzeroberflĂ€che interaktiv geĂ€ndert werden kann und bei einer Ănderung nicht neu compiliert werden muĂ. AuĂerdem wird die Bildschirmausgabe automatisch an die Bildschirmauflösung angepaĂt.
Nachdem ich nun einige Argumente fĂŒr die Resourcedateien genannt habe denken Sie sicher âist doch eine prima Sache, wozu also dieser Artikel?â. Dazu ist zunĂ€chst zu bemerken, daĂ nicht alles Gold ist, was glĂ€nzt. Sicher hatten sie auch schon die Meldung âResourcedatei nicht gefundenâ auf Ihrem Bildschirm. Sicher haben Sie sich auch schon geĂ€rgert, daĂ der Bootvorgang bei Accessories, die eine Resourcedatei benutzen lĂ€nger dauert. Und auĂerdem ist das Inhaltsverzeichnis einer Diskette kĂŒrzer, wenn nicht jedes Programm zusĂ€tzlich eine Resourcedatei hat. Bestimmt fallen Ihnen auch noch mehr GrĂŒnde ein, warum es unter UmstĂ€nden praktisch ist, wenn die Resourcen im Programm integriert sind. Genug Theorie, jetzt folgt die Praxis.
Voraussetzung ist...
das bereits erwĂ€hnte RCS von Digital Research. Dieses Programm ist nĂ€mlich als einziges seiner Art in der Lage, die erzeugten Resourcedateien auch als C Quelltext abzuspeichern. Das bedeutet nicht, daĂ die Resourcedatei auch mit diesem Programm erstellt werden muĂ, es wird lediglich benötigt, um die Resourcen in C umzuwandeln. Dazu wĂ€hlt man im 'Globalâ MenĂŒ des RCS den Punkt 'Outputâ an. In der darauf folgenden Dialogbox klickt man in das KĂ€stchen unter dem Text 'Source File for Resourceâ. Danach lĂ€dt man seine Resourcedatei und speichert sie sofort wieder ab. Auf der Diskette sollte sich dann eine Datei mit Namen âRSC.Câ befinden, vorausgesetzt Ihre Resourcedatei heiĂt âRSC. RSCâ. Als nĂ€chstes startet man einen Editor seiner Wahl und Ă€ndert in dem hier abgedruckten Listing in Zeile 4 und 5 den Vornamen der Dateien ârsc.hâ und ârsc.câ entsprechend dem Namen seiner eigenen Resourcedatei um. AnschlieĂend compiliert man das Ganze und linkt es zu seinem Programm dazu. Alles funktioniert wie vorher, nur daĂ die Resourcedatei jetzt nicht mehr von Diskette geladen wird, sondern im Programm enthalten ist. Das warâs eigentlich schon. FĂŒr die Interessierten unter den Lesern noch ein paar Worte zu der Funktion der Routine.
So gehtâs
In Zeile 21 und 22 wird GEM die Adresse der Objektpointertabelle mitgeteilt. Diese wird z. B. fĂŒr die Funktion RSRC_GADDR benötigt. In der FOR-Schleife 'Do Objectsâ werden die Objektkoordinaten vom Zeichenformat in das aktuelle Bildschirmformat umgerechnet. Dazu muĂ man wissen, daĂ die Anfangskoordinaten eines Objekts und dessen Höhe und Breite auf ganz besondere Weise abgespeichert sind. Jeder Wert ist in einem 16 Bit Wort unter gebracht, dessen Low- und High-Byte unterschiedliche Bedeutung haben. Betrachten wir einmal die ob_heigh-Komponente eines Objekts. Im Low-Byte steht die Objekthöhe in Zeichen und im High-Byte die Anzahl der einzelnen Pixel. Ein Zeichen ist je nach eingestellter Bildschirmauflösung 8 oder 16 Pixel hoch. Wenn also ein Farbmonitor angeschlossen ist und die Zeichenhöhe 8 Pixel betrĂ€gt, ergibt sich die Objekthöhe zu
Low-Byte * 8 + High-Byte
Analoges gilt fĂŒr die Objekt breite und die X-Y Koordinaten. Im abgedruckten Listing wurde die Multiplikation durch eine Schiebeoperation ersetzt. Die Umrechnung der Koordinaten erfolgt in den Zeilen 30 bis 37.
In dem folgenden Switch-Statement wird in der Objektspezifikation ein Pointer auf die dem Objekttyp zugeordnete Struktur eingetragen. In den 6 For-Schleifen ab Zeile 63 wird das Gleiche fĂŒr die einzelnen Strukturen auf die eine Objektspezifikation zeigen kann gemacht.
Den Linker ĂŒberlistet
Die Routine habe ich ârsrc_loadâ genannt, weil dadurch die Möglichkeit besteht vorhandene Programme ohne eine Ănderung am Quelltext, nur durch neues Linken so zu modifizieren, daĂ keine Resourcedatei mehr benötigt wird. Das funktioniert deshalb, weil der Linker die Funktion ârsrc_loadâ zuerst in einem der Objektfiles sucht und sie nur dann aus der Library holt, wenn er sie nicht gefunden hat. So ist es möglich, durch HinzufĂŒgen oder Weglassen eines Objekts beim Linken zu steuern, ob die Resourcedatei geladen wird, oder im Programm integriert ist.
In KĂŒrze gibt es einen neuen Leckerbissen aus der GEM-KĂŒche. Jedes Fenster bekommt seine eigene MenĂŒleiste. Wie das geht werde ich in einer der nĂ€chsten Ausgaben verraten.
(JL)
#include <osbind.h> /* wird fuer Getrez benoetigt */
#include <obdefs.h> /* typdefinitionen fuer AES-Structs */
#include "rac.h" /* .H Datei der Reaource */
#include "rsc.c" /* .C Datei dea Quelltextes der Resource */
#define WHITEBAK NORMAL /* Leider noetig, keine Ahnung wofuer */
#define HIGH 2 /* Returnwert von Getrez fuer 640x400 */
extern int global[]; /* Globale GEM Variablen */
int rsrc_load(RscFile)
char *RscFile; /* der Ordnung wegen, wird nicht benutzt */
{
int dx,
dy,
Obj;
OBJECT **GEM_rsc;
GEM_rsc = (OBJECT **) &global[5];
*GEM_rsc = (OBJECT *) &rs_trindex[0];
dx = dy = 3;
if (Getrez() == HIGH) dy = 4;
/*
* Do Objects
*/
for(Obj = 0;Obj < NUM_OBS;Obj++) {
rs_object[Obj].ob_x = ((rs_object[Obj].ob_x & 0x00ff) << dx) + (rs_object(Obj).ob_x >> 8);
rs_object[Obj].ob_y = ((rs_object[Obj].ob_y & 0x00ff) << dy) +(rs_object[Obj].ob_y >> 8);
rs_object[Obj].ob_width = ((rs_object[Obj].ob_width & 0x00ff) << dx) +(rs_object[Obj].ob_width >> 8);
rs_object[Obj].ob_height =((rs_object[Obj].ob_height & 0x00ff) << dy) + (rs_object[Obj].ob_height >> 8);
switch(rs_object[Obj].ob_type) {
case G_FTEXT :
case G_BOXTEXT :
case G_FBOXTEXT :
case G_TEXT : {
rs_object[Obj].ob_spec = (char *) &rs_tedinfo[(int)rs_object[Obj].ob_spec];
break;
}
case G_BUTTON :
case G_TITLE :
case G_STRING : {
rs_object[Obj].ob_spec = (char *) rs_strings[(int) rs_object[Obj].ob_spec];
break;
}
case G_ICON : {
rs_object[Obj].ob_spec = (char *) (&rs_iconblk[(int) rs_object[Obj].ob_spec]);
break;
}
case G_IMAGE : {
rs_object[Obj].ob_spec = (char *) (&rs_bitblk[(int) rs_object[Obj].ob_spec]);
break;
}
}
}
/*
* Do Textinfos
*/
for(Obj = 0;Obj < NUM_TI;Obj++) {
rs_tedinfo[Obj].te_ptext = ra_strings[(int)rs_tedinfo[Obj].te_ptext];
rs_tedinfo[Obj].te_ptmplt = rs_strings[(int)rs_tedinfo[Obj].te_ptmplt];
rs_tedinfo[Obj].te_pvalid = rs_strings[(int)rs_tedinfo[Obj].te_pvalid];
}
/*
* Do IconBlocks
*/
for(Obj = 0;Obj < NUM_IB;Obj++) {
rs_iconblk[Obj].ib_pmask = rs_imdope[(int) rs_iconblk[Obj].ib_pmask].image;
rs_iconblk[Obj].ib_pdata = rs_imdope[(int) rs_iconblk[Obj].ib_pdata].image;
rs_iconblk[Obj].ib_ptext = rs_strings[(int) rs_iconblk[Obj].ib_ptext];
}
/*
* Do Bitimages
*/
for(Obj = 0;Obj < NUM_BB;Obj++) {
rs_bitblk[Obj].bi_pdata = rs_imdope[(int) rs_bitblk[Obj].bi_pdata].image;
}
/*
* Do FreeStrings
*/
for(Obj = 0;Obj < NUM_FRSTR;Obj++) {
rs_frstr[Obj] = (long) rs_strings[(int) rs_frstr[Obj]];
}
/*
* Do Freeimages
*/
for(Obj = 0;Obj < NUM_FRIMG;Obj++) {
rs_frimg[Obj] = (long) &rs_bitblk[(int) rs_frimg[Obj]];
}
/*
* Do TreeIndex
*/
for(Obj = 0;Obj < NUM_TREE;Obj++) {
rs_trindex[Obj] = (long) &rs_object[(int) rs_trindex[Obj]];
}
return(1); /* Kein Fehler, woher auch :-) */
}