Resource Datei? Nein Danke!

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 :-) */
}


Aus: ST-Computer 12 / 1987, Seite 129

Links

Copyright-Bestimmungen: siehe Über diese Seite