News   Magazin   Börse   Links   ArcArchie   Homepages
 Magazin  RISC OS & C-Programmierung 7: Symbole Home 
Hardware   Software   Praxis   Sonstiges  
RISC OS & C-Programmierung 7: Symbole  Alexander Ausserstorfer 4. 6. 2016 (Update: 12. 6. 2016)

Bei Symbolen (engl. icons) handelt es sich um meist rechteckige Bereiche auf dem Bildschirm, welche Text, ein Bild oder beides gemischt enthalten können.

Von Symbolen wird unter der Oberfläche von RISC OS (Wimp) intensiv Gebrauch gemacht. Die Thematik ist dermaßen umfangreich, dass wir mit dieser Folge nur eine Übersicht anbieten können. Es ist wünschenswert, dass speziellere Gebiete durch weitere Artikel behandelt werden.

Unter RISC OS stehen Symbole niemals für sich allein, sondern werden immer einem Fenster zugeordnet. Ein Fenster kann nahezu beliebig viele Symbole beliebiger Art enthalten.

Symbole können gleichzeitig zusammen mit einem Fenster oder aber auch nachträglich mittels der Funktion wimp_create_icon() erzeugt werden.

Werden die Symbole gleichzeitig mit dem Fenster erzeugt, so folgen unmittelbar dem Datenblock zur Beschreibung des Fensters die Datenblöcke zur Beschreibung der Symbole.

OSLib bietet uns hierfür eine Struktur vom Datentyp wimp_icon an:

   typedef struct
   {
      os_box extent;
      wimp_icon_flags flags;
      wimp_icon_data data;
   }
   wimp_icon;
						

Lage des Symbols innerhalb des Arbeitsbereichs

Symbolkoordinaten Die darin enthaltene Unterstruktur os_box extent gibt die Lage und damit auch Größe des Symbols innerhalb des Arbeitsbereichs eines Fensters an:

   typedef struct
   {
      int x0;
      int y0;
      int x1;
      int y1;
   }
   os_box;
						

Die y-Komponenten müssen hier - wie auch schon beim Fensterausschnitt des Arbeitsbereichs - negativ gezählt werden, da die y-Achse nach Festlegung eigentlich nach oben zeigt, der Arbeitsbereich aber vom Nullpunkt aus nach unten gezählt wird.

Ein Symbol, das einen einzeiligen Text enthält, ist üblicherweise 52 OS-Einheiten hoch (|y0| - |y1| = 52), zum Beispiel y0 = -150 und y1 = -98.

Symbole

Besagtes Ziel dieses Artikel ist es nicht, eine Übersicht über alle Steuerzeichen und Symbolinhalte zu bieten, sondern eine Einführung in die Thematik. Für eine Übersicht aller von Symbolen betroffenen Steuerzeichen und Speicherstrukturen bieten sich die PRMs an.

Steuerzeichen (Komponente wimp_icon_flags flags) und Symbolinhalt (Komponente wimp_icon_data data) sind dermaßen eng miteinander verknüpft, dass es mir nur Sinn zu machen scheint, beide miteinander gleichzeitig zu behandeln - und zwar in Abhängigkeit von der Art des Symbols, das man haben möchte. Diese werden daher im nachfolgenden einzeln erläutert.

Zuvor möchte ich aber noch gerne ganz kurz etwas näher auf die Strukturkomponente wimp_icon_data data eingehen. Symbole können Text oder Grafik oder beides gemischt enthalten. Nun muss dieser Text oder diese Grafik aber irgendwo im Speicher hinterlegt und mit dem Symbol verknüpft werden. Dazu dient die Komponente data von wimp_icon, welche in der Programmiersprache C eine Vereinigung / Union (engl. union) ist:

   typedef union
   {   char text [12];
       char sprite [12];
       char text_and_sprite [12];

       struct
       {   char *text;
           char *validation;
           int size;
       }
       indirected_text;

       struct
       {   osspriteop_id id;
           osspriteop_area *area;
           int size;
       }
       indirected_sprite;

       struct
       {   char *text;
           char *validation;
           int size;
       }
       indirected_text_and_sprite;
    }
    wimp_icon_data;
						

Eine Union in C bedeutet, dass die darin enthaltenen Komponenten nicht wie in einer Struktur gleichzeitig nebeneinander existieren können und damit entsprechend viel Speicher belegen, sondern dass jeweils nur eine einzige in ihr enthaltene Komponente existieren kann. Damit beschränkt sich der für eine Union erforderliche Speicherbedarf auf die größte in ihr enthaltene Komponente. Diese kann hier maximal 12 Bytes groß sein.

Mit einer Union verhält es sich genauso wie mit einem Stellplatz, der von verschieden großen Auto genutzt werden kann. Der Stellplatz muss mindestens so groß wie das größte Auto sein, damit alle verschieden große Autos darauf Platz haben. Indes kann er in der Regel aber nur von einem einzigen Fahrzeug gleichzeitig belegt werden. Der Rest des Platzes geht verloren, falls ein kleineres Auto darauf geparkt wird.

Unter Umständen können auch zwei oder mehr Autos abgestellt werden. Aber diese dürfen dann zusammengenommen niemals größer als das größte Fahrzeug sein.

In einer Union belegen also alle verschiedene Komponenten den gleichen physikalischen Speicherplatz. Genauer: ein bestimmter Teil davon kann unbelegt bleiben, falls eine Komponente kleiner ist als der insgesamt für die Union zugewiesene Speicher. Das funktioniert, weil zu einem ganz bestimmten Zeitpunkt immer nur eine einzige Komponente abgelegt wird. Die in der Union enthaltenen Datentypen dienen dem Compiler wieder zur Überprüfung bei der Übersetzung und haben sonst keine nähere Bedeutung.

Das macht man auch deshalb, weil man mit Hilfe einer Union Datentypen zerlegen oder zusammenfügen kann. Man kann zum Beispiel ein Zeichenfeld (char zeichenfeld[4]) aus 4 Bytes ablegen und daraus eine 32-Bit-Integerzahl vom Typ int bilden. Das darin enthaltene Bitmuster wird 1:1 übernommen und stimmt in beiden Datentypen exakt überein. Der Compiler interpretiert das Bitmuster je nach Datentyp aber verschieden.

Als Grundgerüst für die Beispiele verwenden wir das bereits in Kapitel sechs erläuterte Programmlisting für ein Fenster, allerdings den jeweiligen Anforderungen entsprechend in leicht abgewandelten und ergänzten Formen.

Einfaches Symbol mit kurzem Text

Wir wollen als erstes ein einfaches Symbol mit einem kurzen Text erzeugen.

Als erstes müssen wir beachten, dass wir den Speicherbereich für das Fenster so berechnen, dass mindestens ein Symbol Platz hat:

   window = malloc(sizeof(wimp_window) + 1*sizeof(wimp_icon));
						

Als nächstes ist zu bedenken, dass wir im Datenblock für das Fenster die Anzahl der im Fenster enthaltenen Symbole richtig eintragen:

   window->icon_count = 1;
						

Jetzt legen wir für ein diskretes Beispiel die Lage des Symbols innerhalb des Arbeitsbereichs fest:

   window->icons[0].extent.x0 =  100;
   window->icons[0].extent.y0 = -150;
   window->icons[0].extent.x1 =  300;
   window->icons[0].extent.y1 =  -60;
						

Die Minimum- und Maximumkoordinaten, also x0 und x1 sowie y0 und y1, sollten nicht vertauscht werden, da es sonst zu unschönen Effekten kommen kann. In der Praxis bedeutet das, dass x0 < x1 und y1 > y0 sein müssen, da letztere negativ. Man kann das gerne ausprobieren.

Die Steuerzeichen sind etwas umfangreicher. Wir müssen hier angeben, dass das Symbol einen Text enthält (wimp_ICON_TEXT). Alle weiteren Steuerzeichen sind optional. Allerdings beziehen sich einige der Steuerzeichen nicht auf Text-, sondern auf grafische Symbole oder führen zu Fehler, falls wir diese in Verbindung mit dem Beispiel in diesem Abschnitt setzen sollten.

In diesem Beispiel sollten wir uns daher erst einmal nur mit folgenden Steuerzeichen beschäftigen und alle anderen vorerst ungesetzt (= 0) beziehungsweise ausgeblendet lassen. Sie sind automatisch 0 gesetzt, wenn wir nichts weiter angeben.

Steuerzeichen Bedeutung
wimp_ICON_TEXT muss in diesem Fall gesetzt sein
wimp_ICON_BORDER Symbol hat Umrahmung
wimp_ICON_HCENTRED Text ist horizontal mittig ausgerichtet
wimp_ICON_VCENTRED Text ist vertikal mittig ausgerichtet
wimp_ICON_FILLED Symbol hat einen gefüllten Hintergrund (Farbe)
wimp_ICON_RJUSTIFIED Text ist rechts ausgerichtet
wimp_ICON_FG_COLOUR Schriftfarbe
wimp_ICON_BG_COLOUR Hintergrundfarbe (falls Bit wimp_ICON_FILLED gesetzt)

Im folgenden wird ein ausführlicheres Beispiel der Steuerzeichen für ein Textsymbol aufgeführt, das man einmal ausprobieren sollte:

   window->icons[0].flags = wimp_ICON_TEXT | wimp_ICON_HCENTRED |
                            wimp_ICON_VCENTRED |
                            wimp_COLOUR_BLACK <<
                               wimp_ICON_FG_COLOUR_SHIFT |
                            wimp_ICON_BORDER | wimp_ICON_FILLED;
						

Man sollte etwas mit den Bits herumspielen. Falls man ein Bit nicht setzen möchte, kann man es einfach aus der Liste entfernen. Es wird dann automatisch Null.

Es muss aber mindestens ein Bit gesetzt werden. Falls man überhaupt kein Bit setzen möchte, empfiehlt es sich, immer window->icons[0].flags = 0; zu verwenden, damit bereits früher gesetzte Bits und Bytes im Speicher überschrieben und damit an dieser Stelle für das Programm definiert werden. Das gilt für alle Zeichen, nicht nur für Symbolzeichen.

Denn wir reservieren mit window = malloc(sizeof(wimp_window) + 1*sizeof(wimp_icon)); zwar den benötigen Speicher für den Datenblock. Die Funktion malloc() initialisiert diesen jedoch nicht. Das heißt der zuvor in diesen Speicherbereich geschriebene Inhalt befindet sich auch nach der Zuweisung an unser Programm unverändert dort. Damit wären aber unter Umständen Zeichen gesetzt, die wir gar nicht haben wollen.

Das Setzen von Farben entspricht dem bereits im Kapitel sechs Fenster erläuterten Verfahren zum Setzen der Steuerzeichen für den Arbeitsbereich eines Fensters. Um eine bestimmte Farbe zu setzen muss man die Konstante für die entsprechende Farbe verwenden (zum Beispiel wimp_COLOUR_BLACK), diesen 4-Bit-breiten Wert dann aber noch um eine bestimmte Anzahl von Bits verschieben (wimp_COLOUR_BLACK << wimp_ICON_FG_COLOUR_SHIFT). So was steht aber grundsätzlich im Handbuch von OSLib bei jedem entsprechenden Eintrag mit dabei.

Kurzer Text Als letztes muss man natürlich noch den auszugebenden Text selbst hinterlegen. Dies geschieht in diesem Fall, indem der einfache kurze Text "Hallo Welt!" direkt in den Datenblock window an der Position window->icons[0].data.text kopiert wird. Der Compiler legt bei der Übersetzung des Programms selbst fest, wo die Zeichenfolge "Hallo Welt!" aus dem Programmlisting im Speicher hinterlegt wird; von dort muss dieser Text dann während des Programmablaufs an die entsprechende Position bei window->icons[0].data.text kopiert werden. Die Textlänge für das Symbol ist bei einem direkt adressierten Textsymbol auf 12 Zeichen festgesetzt. Werden weniger genutzt, wird der Rest unberührt gelassen. Das heißt je nachdem, was bereits vorher an den übrig gebliebenen Stellen im Speicher stand, können undefinierte Zeichen erscheinen, falls kein Endzeichen angegeben wird. Mehr als 12 Zeichen sind bei der direkten Adressierung nicht möglich.

   strncpy (window->icons[0].data.text, "Hallo Welt!", 12);
						

Zeichenketten können unterschiedlich lang sein. Das Programm sollte daher immer das Ende einer Zeichenkette erkennen können. Man behilft sich damit, dass man dem letzten Buchstaben, der letzten Zahl oder dem letzten Satzzeichen der Zeichenkette einen ganz besonderen Wert anfügt. Dieser Wert stellt dann nach ASCII (engl. American Standard Code for Information Interchange, zu deutsch etwa: Amerikanische Standard-Kodierung zum Informationsaustausch, festgesetzt in den Normen ANSI X3.4 sowie ISO 8859/1.2.) keinen darstellbaren Buchstaben, keine Ziffer und auch kein Satzzeichen mehr dar, sondern dient lediglich als Steuerzeichen, eine Anweisung, die dem System sagt, was es tun soll.

Im Editor Edit von RISC OS, zu finden in Apps auf der Symbolleiste, werden die vom Editor nicht zu verarbeitenden Steuerzeichen als hexadezimale Werte in Klammern angezeigt, also zum Beispiel [00] für die binäre Null und so weiter Man kann das einmal ausprobieren, indem man eine binär kodierte Datei, also zum Beispiel ein JPEG, ein ausführbares Programm oder ein PDF, auf das Editor-Symbol auf der Symbolleiste zieht. Edit muss dazu natürlich bereits per Doppelklick gestartet worden sein.

Dieses Verhalten beherbergt eines der grundlegenden Unterschiede zu anderen, weitaus bekannteren Systemen: Während auf anderen Systemen alles Mögliche vor dem Blick des Anwenders versteckt wird, macht RISC OS nahezu alles in irgend einer Form oder Art sichtbar.

In dem PRM 3 Seite 89 steht unter dem Abschnitt Icon data des SWIs Wimp_CreateIcon, dass Zeichenketten immer "control-terminated" sein sollen. Gemeint ist damit, dass sämtliche Dezimalwerte von 0 - 31 (Hexdezimal: 0 - 1F, binär: 0000 0000 bis 0001 1111) dem SWI signalisieren, dass die Zeichenkette mit dieser Stelle beendet ist. Die Stelle zählt nicht mehr zu den auszugebenden Zeichen dazu.

In C werden Zeichenketten immer mit dem hexadezimalen Wert 0x00 (binäre Null, Endnull) markiert. In C kann man innerhalt von Zeichenketten für 0x00 auch \0 schreiben, also etwa:

   "Textende.\0"
						

Die binäre Null \0 ist jener Wert, mit dem C innerhalb einer Zeichenkette - das ist alles zwischen zwei Anführungsstrichen - diese standardmäßig abschließt. Die \0 muss damit also nicht ausdrücklich geschrieben werden wie im vorhergegangenen Beispiel; sie wird automatisch angehängt. Allerdings muss diesem Zeichen \0 ein zusätzlicher Platz eingeräumt werden! Beispiel:

   char zeichenkette [11] = "Hallo Welt!";
						

Diese Zeichenkette wird nicht automatisch mit der Endnull markiert, weil hierfür kein Platz mehr vorhanden ist!

   char zeichenkette [12] = "Hallo Welt!";
						

Hier wird der Zeichenkette eine Endnull angefügt. Diese Endnull muss nicht angegeben werden. Sie wird vom Compiler automatisch angefügt. Allerdings eben nur dann, wenn auch ausreichend Platz, sprich ein zusätzliches Byte hierfür vorhanden ist. Auf solche Feinheiten kommt es in C leider an. Sonst funktioniert das Programm unter Umständen nicht richtig, je nachdem, was bereits zuvor im Speicher gestanden hat.

Unter BBC BASIC wird der Wagenrücklauf (englische Abkürzung CR für cariage return) mit dem Hexadezimalwert 0x0d angewendet, weil BBC BASIC Zeichenketten standardmäßig mit diesem Zeichen statt der binären Null im Vergleich zu C abschließt.

Ganz wichtig zu wissen ist jetzt, dass die in diesem Kurs verwendete C-Funktion strncpy() der zu kopierenden Zeichenkette binäre Nullen anfügt, wenn mehr Zeichen kopiert werden sollen als in der ursprünglichen Zeichenkette vorhanden sind.

In unserem vorangegangenen Beispiel strncpy(window->icons[0].data.text, "Hallo Welt!", 12); werden also 12 Zeichen von der Zeichenkette "Hallo Welt!" (ohne Anführungszeichen, die sind nur zur Programmeingabe da) nach window->icons[0].data.text kopiert. Da die Zeichenkette jedoch nur 11 Zeichen lang ist, wird als 12-te Zeichen eine binäre Null und damit das Endkennzeichen angefügt.

Würde man strncpy(window->icons[0].data.text, "Hallo!", 6); schreiben, würde die binäre Null als Endkennzeichen fehlen. Das Programm kann damit trotzdem richtig funktionieren, nämlich dann, wenn bereits zuvor rein zufällig eine binäre Null hier an 7-ter Stelle gestanden hätte. Das muss aber nicht der Fall sein. Falls das 7-te Byte des Speichers in Folge bereits die Bedeutung eines druckfähigen Zeichens hätte, würde man dieses im Textfeld im Anschluss an den Text "Hallo!" sehen können. Also zum Beispiel ein B, falls rein zufällig zuvor der Wert dezimal 65 an 7-ter Stelle ab Anfang der Zeichenkette gestanden hätte.

Diese Handhabung mit der binären Null \0 kann sich jedoch von Funktion zu Funktion unterscheiden. Gegebenenfalls muss man in der Dokumentation zu den Funktionen nachlesen, falls man mehr wissen muss / will.

Grundsätzlich ist es so, dass es auch Situationen gibt, wo kein Endkennzeichen angegeben werden müsste. Im vorangegangenen Beispiel ist klar, dass der Text nicht länger als 12 Zeichen sein kann, weil RISC OS bei der direkten Adressierung nicht mehr Platz dafür berücksichtigt. Wir könnten uns hier also das 12-te Zeichen als Endkennzeichen sparen und statt dessen den Platz noch für ein weiteres Zeichen nutzen.

Man soll sich diesen Unterschied vielleicht einmal näher ansehen, indem man Listing 7-01 mit folgenden Zeilen für das Textfeld ausprobiert:

   strncpy (window->icons[0].data.text, "ABCdefGHIjkl", 12);
   strncpy (window->icons[0].data.text, "Hallo!", 6);
						

und dabei den Wert 6 in 2-ter Zeile vor dem zweiten Übersetzen in ein lauffähiges Programm in 7 ändert. Diese beiden Zeilen sollten direkt hintereinander an jener Stelle eingefügt werden, wo in Listing 7-01 nur eine Zeile für den Symboltext steht.

Im Anschluss folgt zur Übersichtlichkeit noch einmal das komplette Programmlisting, welches ein Fenster mit einem einfachen Textsymbol erzeugt. Alle Quellcodes dieses Teils kann man sich herunterladen.

Listing 7-01 - Fenster mit einfachem direkten Textsymbol

Einfaches Symbol mit langem Text

Wollen wir ein Symbol mit einem Text haben, der länger als 12 Zeichen ist oder nachträglich nach der Erzeugung des Fensters geändert werden soll, müssen wir das anders machen.

In diesem Fall legen wir den Text einfach woanders ab und zeigen anschließend auf diese Stelle.

Als erstes müssen wir bei den Steuerzeichen für das Symbol unbedingt das Zeichen (Bit) wimp_ICON_INDIRECTED setzen.

Dann können wir einen längeren Symboltext im Speicher hinterlegen:

   char symboltext[26] = "Seht diese Erde leuchten!";
						

An dieser Stelle ein Hinweis: Hier können wir, müssen aber nicht die Länge der Zeichenkette in den Klammern angeben, weil der C-Compiler diese Länge selbst aus der nachfolgenden Zeichenkette bestimmen und anschließend den dafür notwendigen Speicher berechnen kann. Das funktioniert jedoch nur bei der Initialisierung dieses Feldes und nicht mehr nachträglich. Wir können also auch schreiben:

   char symboltext[] = "Seht diese Erde leuchten!";
						

und ersparen uns damit das Abzählen. Letzteres übernimmt bei dieser Variante der C-Compiler bei der Übersetzung des Quellcodes.

Falls wir erstere Variante wählen, müssen wir die Endnull \0 als Endkennzeichen hinzuzählen - also Anzahl der Zeichen in den Klammern + 1 - sonst fehlt diese, was zu unschönen Fehlern führen kann.

Jetzt müssen wir noch im Datenblock icons[0] des Symbols die Speicheradresse des ersten Buchstabens vom Text sowie die Textlänge angeben:

   window->icons[0].data.indirected_text.text = symboltext;
   window->icons[0].data.indirected_text.size = 26;
						

Auch hier können wir natürlich die Textlänge den C-Compiler mit Hilfe der C-Funktion strlen() selbst abzählen lassen:

   window->icons[0].data.indirected_text.text = symboltext;
   window->icons[0].data.indirected_text.size = strlen(symboltext);
						

Langer Text Die C-Funktion strlen() befindet sich in der Standard-C-Bibliothek. Diese muss im Kopf des Quellcodes angegeben werden, damit der C-Compiler diese Funktion auch findet beziehungsweise erkennt. Wir haben das in unserem Quellcode mit der Angabe #include <stdlib.h> aber schon gemacht.

Man bezeichnet dieses Vorgehen auch als indirekte Adressierung. Statt den Text selbst zu hinterlegen, wird eine Adresse hinterlegt, an deren Stelle dann der eigentliche Text zu finden ist der nun nicht mehr auf 12 Zeichen beschränkt sein muss. Ein Zeiger zeigt auf diese Adresse.

Den Validierungsstring, auf den der Zeiger window->icons[0].data.indirected_text.validation zeigt, können wir vorerst übergehen. Gegebenfalls kann man den Nullzeiger setzen, damit keine unerwünschten Nebeneffekte auftreten können:

   window->icons[0].data.indirected_text.validation = NULL;
						

Nullzeiger bedeutet, dass an dieser Stelle ein Zeiger eingetragen ist, der nicht gültig (null) ist. Das System weiß so, dass die Adresse sowie der Inhalt der Adresse nicht interpretiert werden dürfen. Damit kann nichts passieren.

Es macht noch Sinn, den Arbeitsbereich des Fensters aus dem Listing von Kapitel sechs nach rechts zu erweitern, damit das Symbol nicht abgeschnitten ist:

   window->extent.x1 = 1000;
						

Zur besseren Übersichtlichkeit hier nochmal das vollständige Programmlisting, welches ein Fenster mit einem Symbol erzeugt, das einen indirekt adressierten Text enthält:

Listing 7-02 - Fenster mit längerem indirekten Textsymbol

Symbol als Eingabefeld

Um aus einem Symbol ein schreibfähiges Eingabefeld zu machen, genügt es, in Listing 7-02 - Fenster mit längerem indirekten Textsymbol die Symbolsteuerzeichen mit dem Steuerzeichen wimp_BUTTON_WRITABLE << wimp_ICON_BUTTON_TYPE_SHIFT zu ergänzen (man beachte, dass bei WRITABLE in der Tat das 'e' fehlt), also:

   window->icons[0].flags = wimp_ICON_TEXT | wimp_ICON_HCENTRED |
                            wimp_ICON_VCENTRED | wimp_ICON_INDIRECTED |
                            wimp_BUTTON_WRITABLE <<
                               wimp_ICON_BUTTON_TYPE_SHIFT |
                            wimp_COLOUR_BLACK <<
                               wimp_ICON_FG_COLOUR_SHIFT |
                            wimp_ICON_BORDER | wimp_ICON_FILLED;
						

Feld zum Eingeben Bei den Steuerzeichen, welche mit wimp_BUTTON_... beginnen, handelt es sich um die Tastensymboltypen. Das sind Steuerzeichen, welche angeben, was mit dem Symbol geschehen soll, wenn der Mauszeiger über ihm steht und gegebenenfalls eine der Maustasten gedrückt wird. Diese Steuerzeichen bilden eine eigene Untergruppe innerhalb der allgemeinen Steuerzeichen für Symbole und belegen die Bits 12 bis 15. Deshalb müssen diese Steuerzeichen, wie schon einmal bei den Farben erklärt, mit dem Befehl << wimp_ICON_BUTTON_TYPE_SHIFT an die richtige Position innerhalb des Bitmusters geschoben werden.

Der Text in einem Eingabefeld lässt sich, anders als bei anderen Systemen, mittels der Tastenkombination Strg + U löschen.

Der eingegebene Text lässt sich über die dem Symbol zugewiesene Adresse für den Text auslesen, in unserem Fall symboltext. Die mögliche Eingabelänge muss zuvor festgelegt worden sein und steht in .indirected_text.size.

Bei den mit Zeichen behafteten Tasten kümmert sich die Wimp / RISC OS selbst um deren Verwaltung.

Bei Funktions- oder Aktionstasten, das sind die auf Tastaturen oft grau abgesetzten Tasten zum Beispiel Eingabetaste, Pfeiltasten, benachrichtigt die Wimp die Aufgabe, in unserem Falle "Hallo Welt!" genannt. Dabei handelt es sich um sogenannte Ereignisse. Dann kann die Aufgabe auf solche Ereignisse reagieren. Aber dafür muss man selbst entsprechende Programmteile schreiben.

Listing 7-03 - Fenster mit Symbol als Eingabefeld

Erlaubte Zeichenfolgen (engl. validation string)

Symbole können grundsätzlich verschiedene Verhalten aufweisen, die mittels einer Zeichenfolge (engl. validation string) angegeben werden können.

Der Zeiger char *validation muss auf diese Zeichenfolge zeigen. Bei diesen Zeichenfolgen handelt es sich um Befehle.

An dieser Stelle werden nur einige Befehle aufgezeigt, die in einem engeren Zusammenhang mit dem Eingabefeld stehen. Es gibt noch weitere Befehle, die jedoch erst später und immer im Zusammenhang mit den entsprechenden Symbolen erklärt werden sollen. Eine Übersicht über alle Befehle bieten die PRMs ab Seite 3-99. Dies hier soll schließlich kein Nachschlagewerk sein.

Befehl A

Mit diesem Befehl kann man angeben, welche Zeichen angenommen werden sollen und welche nicht. So lässt der Befehl A0-9 etwa nur die Eingabe der Ziffern 0 bis 9 zu. Mit der Tilde ~ können Tasten oder Gruppen ausgeschlossen werden. Der Befehl A0-9~3 zum Beispiel erlaubt die Eingabe der Ziffern 0 bis 9 mit Ausnahme der 3. Weitere Gruppen sind A-Z oder a-z. Den vier Zeichen -, ;, ~ und \ muss man immer einen rückwertigen Schrägstrich (engl. backslash) voranstellen, zum Beispiel: "A~\-\;\-\\"

Als Programmcode würde ein konkretes Beispiel folgendermaßen aussehen:

   char valid[] = "A0-9";
   ...icons[i].data.indirected_text.validation = valid;
						

Von diesem Befehl leitet sich der Name 'validation string' (erlaubte Zeichenfolge) ab. Diese Zeichenkette wird jedoch auch für anderes verwendet, wie wir noch sehen werden.

Befehl D

Mit diesem Befehl kann man statt der eingegebenen Zeichen andere ins Textfeld schreiben lassen. Das ist zum Beispiel sinnvoll als Passwortschutz einsetzbar. D* schreibt statt der eingegebenen Zeichen lauter * (Sternchen) ins Textfeld. Auch andere Zeichen sind möglich.

Bilder als Symbole

Werden aussagekräftige, einfach erkennbare Bilder als Symbole verwendet, können diese die Bedienung des Computers ganz erheblich erleichtern. Das erste Mal wurden grafische Symbole beim Xerox Alto (1972) eingesetzt. Unter RISC OS können auch Rasterbilder (Pixelgrafik) als Symbolinhalt verwendet werden.

Als Datenformat für grafische Symbole kann unter RISC OS nur das RISC-OS-eigene Bilddatenformat Sprite verwendet werden. Andere, heute weitaus bekanntere Bilddatenformate sind zum Beispiel JPEG, GIF oder PNG. Deshalb wird im weiteren Verlauf dieses Textes auch nur noch von Sprites an Stelle von Rasterbildern die Rede sein.

Sprites können mit der Anwendung Paint erzeugt, angezeigt und manipuliert werden. Paint liegt jeder Version von RISC OS bei.

Eine mit Hilfe von Paint erzeugte Datei kann mehrere Sprites enthalten, die alle einen eigenen Namen haben müssen.

Die Philosophie dahinter ist, dass man auf diese Weise einen zusammenhängenden Speicherbereich mit Sprites hat, den man nutzen kann. Egal ob in einer Datei oder im flüchtigen Hauptspeicher des Computers. Man muss so nicht jedes Sprite gesondert aus vielen einzelnen Dateien holen. Es reicht damit, eine einzige Datei zu laden.

ROM SpritesRISC OS verwendet bereits einen solchen zusammenhängenden und mit Sprites gefüllten Speicherbereich für vom System oft verwendete Symbole wie Dateitypen, Anwendungsverzeichnisse oder häufig verwendete Schaltflächen von Fenstern. Dieser besondere Speicherbereich wird im englischen wimp sprite area, zu deutsch in etwa Wimp- Sprite-Bereich genannt.

Der Wimp-Sprite-Bereich besteht aus zwei Teilen: Einmal enthält er Sprites aus dem ROM (engl. Read Only Memory für deutsch Festwertspeicher), welcher bei einer bestimmten Version von RISC OS immer gleich ist. Sie können und werden sich aber zwischen verschiedenen Versionen von RISC OS unterscheiden. Der zweite Teil enthält Sprites, die mittels dem Kommando *IconSprites <Dateiname> nachträglich in den Wimp-Sprite-Bereich geladen worden sind. Dieses Kommando findet sich zum Beispiel in den !Boot und !Run genannten Dateien von Anwendungen. Der zweite Teil ist also davon abhängig, welche Anwendungen vom System gesichtet worden sind. Es ist jederzeit möglich, mittels *IconSprites <Dateiname> nachträglich Sprites in den Wimp-Sprite-Bereich aufzunehmen, und man kann das freilich auch selbst mit diesem Befehl machen.

Mit Hilfe des folgenden Dreizeilers in der Programmiersprache BBC BASIC kann man die im Wimp-Sprite-Bereich enthaltenen Sprites in zwei, jeweils ROMSprites und RAMSprites genannte Dateien speichern:

   10 SYS "Wimp_BaseOfSprites" TO rom%, ram%
   20 SYS "OS_SpriteOp", 268, rom%, "ROMSprites"
   30 SYS "OS_SpriteOp", 268, ram%, "RAMsprites"
						

Den Dreizeiler kann man entweder mit Hilfe eines Texteditors wie Edit, StrongEd oder Zap in eine Textdatei eingeben, als BASIC-Typ speichern und anschließend diese Datei per Doppelklick mit dem Mauszeiger starten, oder man drückt die Funktionstaste F12, tippt BASIC, <RETURN> und anschließend den Dreizeiler samt voranstehenden Zeilennummern ab. Anschließend noch den Befehl RUN + <RETURN> eingeben. BBC-BASIC kann man anschließend mit dem Befehl QUIT + <RETURN> wieder verlassen. Mit <RETURN> ist der Druck auf die Eingabetaste, die große Pfeiltaste, gemeint.

Die beiden Dateien ROMSprites und RAMSprites lassen sich anschließend mit Paint anzeigen. Siehe hierzu auch die Abbildung oben.

Sprites müssen irgendwo hinterlegt werden. Die Vereinigung beziehungsweise Union vom Datentyp wimp_icon_data ist jedoch zu klein, um die Informationen aufzunehmen, welche ein Sprite abbilden. Die Sprites selbst finden sich daher immer woanders, egal ob bei direkter oder bei indirekter Adressierung.

Sprites werden letzten Endes immer über ihren bis zu elf Zeichen langen Namen angesprochen. Verschiedene Sprites in einer gemeinsamen Datei beziehungsweise im gleichen zusammenhängenden Speicherbereich dürfen und können folglich nicht den gleichen Namen haben. Die direkte beziehungsweise indirekte Adressierung bezieht sich hier nur auf den Namen des Sprites, nicht aber auf das Sprite selbst.

Der Name der Sprites kann zwar in beiden Fällen nur bis zu elf Zeichen lang sein. Aber es gibt auch hier trotzdem Unterschiede zwischen direkter und indirekter Adressierung, wie wir noch sehen werden.

Direkte Adressierung

Sprite im Fenster Bei direkter Adressierung wird der Name an der Stelle sprite angegeben. Dieser Name lässt sich nachträglich, das heißt nach der Erzeugung des Symbols, nicht mehr ändern. So was geht erst mit der indirekten Adressierung.

Die Angabe, wo die Sprites liegen, findet sich bei der direkten Adressierung ganz woanders - nämlich an der Stelle window->sprite_area. Das ist der Datenblock, der hier ein Fenster beschreibt.

Wir müssen also an der Stelle window->sprite_area die Anfangsadresse des zu nutzenden Speicherbereichs angeben, den wir für die Sprites vorgesehen haben.

Will man grafische Symbole aus dem Wimp-Sprite-Bereich nutzen, muss an dieser Stelle eine Eins eingetragen werden. Da der C-Compiler unter einer Eins aber den Datentyp Integer erkennt, sollten wir an dieser Stelle noch einen sogenannten Cast (von engl. to cast, zu deutsch werfen) durchführen, damit der Compiler bei der Übersetzung des Programms keine Warnung am Bildschirm ausgibt:

   window->sprite_area = (osspriteop_area *) 1;
						

Ohne diesen Cast gibt der Compiler bei der Übersetzung des Programms eine Warnung aus, weil der Datentyp der Angabe 1 (Datentyp: int für kurz Integer) nicht mit dem Datentyp der Struktur window->sprite_area (Datentyp: osspriteop_area, hier aber als Zeiger * ausgeführt) zusammenpasst, in welcher die 1 abgelegt beziehungsweise geschrieben werden soll. Den Datentyp osspriteop_area findet man im StrongHelp-Handbuch von OSLib.

Aber natürlich sieht OSLib, ganz im Sinne der C-Erfinder, auch für den Wimp-Sprite-Bereich eine Konstante vor, damit man sich keine Zahl merken muss: wimpspriteop_AREA. Diese Konstante ist allerdings nicht in der Datei wimp.h, sondern in der Datei wimpspriteop.h enthalten. Man muss also diese letzte Datei mit einbinden, damit OSLib die Konstante dann auch kennt:

   #include "oslib/wimpspriteop.h"
						

Der Unterschied zur vorhergegangenen Version window->sprite_area = (osspriteop_area *) 1; ist außerdem der, dass die Konstante wimpspriteop_AREA bereits den geeigneten Datentyp enthält. Wir müssen bei der Version mit der Konstante also keinen Cast mehr durchführen und können uns diesen somit ersparen.

Folgendes Programm erzeugt als Beispiel ein Fenster mit dem Sprite information aus dem Wimp-Sprite-Bereich. Das Sprite information findet man auch in der Sprite-Datei, welche unter dem Pfad Resources:$.Resources.Wimp.Sprites abgelegt ist - man klicke hierzu mit der mittleren Maustaste auf das Apps-Symbol auf der Symbolleiste.

Listing 7-04 - Fenster mit einem grafischen Symbol aus dem Wimp-Sprite-Bereich (direkte Adressierung)

Indirekte Adressierung

Bei der indirekten Adressierung kann entweder der Spritename oder das Sprite selbst indirekt, also dessen Position im Speicher mittels einem Zeiger, angegeben werden. Im folgenden Beispiel wird das zur Einfachheit an Hand eines Spritenamens demonstriert:

   char symbolname[12] = "information";
   window->icons[0].data.indirected_sprite.id =
      (osspriteop_id) symbolname;
						

Die direkte Angabe osspriteop_id symbolname[12] = "information"; ist hier nicht möglich, weil Zeichenketten nur beim Datentyp char funktionieren. Wir verwenden hier deshalb einen Zeiger symbolname vom Datentyp char und teilen dem Compiler im weiteren eine beabsichtigte Datentypkonvertierung (Cast) mit.

Der Bereich, wo das Sprite abgelegt ist, muss hier aber ebenfalls in der gleichen Strukturkomponente .data angegeben werden:

   window->icons[0].data.indirected_sprite.area = wimpspriteop_AREA;
						

Jetzt muss man noch die Länge des Symbolnamens eintragen:

   window->icons[0].data.indirected_sprite.size = 12;
						

Es folgt das vollständige Listing zu diesem Abschnitt:

Listing 7-05 - Fenster mit einem grafischen Symbol aus dem Wimp-Sprite-Bereich (indirekte Adressierung)

Auswählbare Symbole

Mit Symbolen kann man mehr anfangen, als nur etwas darzustellen, wie wir bereits am Beispiel Eingabefeld gesehen haben. Dies gilt auch für grafische Symbole (Sprites). Diese können sich zum Beispiel mit der Maus auswählen lassen, wenn man es möchte. Ein gutes Beispiel hierfür ist ein Fenster des Dateisystems das auch Filer genannt wird.

Ausgewählte Sprites im Filer Außerdem können Symbole auch mit der Maus angeklickt, eine Kopie davon auf dem Bildschirm herumgezogen und diese irgendwo anders abgelegt werden, auch außerhalb des ursprünglichen Fensters. Diese Technik ist im Englischen unter dem Begriff Drag & Drop, zu deutsch in etwa Ziehen und Fallen lassen, bekannt. [Anm. cms: Acorn nannte das einfach nur "dragging".] Das Ablegen des Symbols kann dann in einer völlig anderen Aufgabe, einem völlig anderen Programm, eine Funktion auslösen. Somit können Programme untereinander miteinander kommunizieren.

Hierfür ein gutes, weil freilich alltägliches Beispiel ist unter RISC OS ein Dokument, welches man speichern möchte: Man drückt die Taste F3 oder hangelt sich über das Anwendungsmenü, dazu in einer späteren Folge dieser Serie mehr, zur Speicherbox und zieht das darin enthaltene Dateisymbol mit Hilfe der Maus in das vom Ablageort zuvor geöffnete Fenster. Natürlich muss man hierfür mit Hilfe des Dateisystems (engl. Filer) das Fenster mit dem Ablageort schon geöffnet haben, bevor man das Dateisymbol dorthin ziehen möchte. Obwohl diese Technik doch völlig verschieden zu anderen Systemen ist, ist sie doch so intuitiv, denn sie stammt aus dem Alltag. Schließlich muss man eine Schublade auch öffnen, bevor man dort etwas hineinlegen kann. Und genauso funktioniert die Oberfläche von RISC OS.

Unter RISC OS sind beim Speichern also mindestens zwei verschiedene Aufgaben (Programme) an diesem Vorgang beteiligt: Einmal das Dateisystem, mit dessen Hilfe man das Fenster des Ablageorts öffnet, und einmal das Programm, dessen Dateisymbol man hinterher in das Fenster des Ablageorts zieht.

Der große Vorteil dieser Technik ist, dass man den Ablageort nur einmal öffnen muss, selbst, wenn man aus unzählig verschiedenen Programmen etwas dort hineinspeichern möchte. Die Schublade muss man ja auch nur einmal öffnen. Man muss sich also nicht ein jedes Mal wieder durch eine nervige Dateistruktur einer Speicherbox hangeln.

Unter RISC OS wird von Drag & Drop intensiv Gebrauch gemacht.

Um ein Symbol mittels Mauszeiger auswählbar zu machen, müssen wir uns wieder der bereits unter Abschnitt Symbol als Eingabefeld erwähnten Tastensymboltypen wimp_BUTTON_... bedienen. Das Betriebssystem kümmert sich dann bis zu einem gewissen Grad selbst um die Veränderung der Symbole. Bei Bedarf informiert es auch die Aufgabe (das Programm) über Aktionen mit dem Mauszeiger auf ein bestimmtes Symbol.

Um das Symbol mit dem Mauszeiger auswählbar zu machen, sollten wir uns erst einmal die beiden Tastensymboltypen wimp_BUTTON_RELEASE und wimp_BUTTON_DOUBLE_CLICK mit Hilfe des Listings 7-06 näher ansehen und ausprobieren.

wimp_BUTTON_RELEASE Klick wählt Symbol; Loslassen über Symbol benachrichtigt die Aufgabe; Fortbewegen des Mauszeigers hebt Auswahl auf.
wimp_BUTTON_DOUBLE_CLICK Klick wählt das Symbol aus; Doppelklick benachrichtigt die Aufgabe

Ausgewählte Symbole Benachrichtigungen sind als Ereignisse zu verstehen, welche der laufenden Aufgabe (dem laufenden Programm) mitgeteilt werden. Siehe hierzu auch Teil 5: Multitasking und Pollschleife dieser Serie. Diese Ereignisse sollten dann entsprechend in der Hauptschleife der Aufgabe (Pollschleife) ausgewertet werden.

Man beachte, dass alle Steuerzeichen für den Tastensymboltyp, wie bereits im Abschnitt Symbol als Eingabefeld erläutert, stets mittels << wimp_ICON_BUTTON_TYPE_SHIFT verschoben werden müssen um die richtigen Bits zu setzen.

Es gibt noch weitere Tastensymboltypen, welche jedoch umfangreichere Erläuterungen benötigen. Diese werden deshalb später jeweils im Zusammenhang mit einer geeigneten Anwendung näher erläutert.

An dieser Stelle sollen jetzt noch zwei weitere Steuerzeichen aufgeführt werden, die in direktem Zusammenhang mit der Auswahl von Symbolen stehen und die man einmal an Hand von Listing 7-06 ausprobieren sollte:

wimp_ICON_SELECTED Das entsprechende Symbol ist bereits ausgewählt
wimp_ICON_SHADED Symbol ist ausgegraut, das heißt es kann nicht ausgewählt werden

Also zum Beispiel:

   window->icons[0].flags = wimp_ICON_SPRITE | wimp_ICON_INDIRECTED |
                            wimp_ICON_HCENTRED | wimp_ICON_VCENTRED |
                            wimp_ICON_SELECTED;
						

Man beachte, dass es sich bei den beiden letzten Steuerzeichen um normale Steuerzeichen und nicht um Tastensymboltypen handelt. Deshalb müssen die letzten beiden aufgeführten Steuerzeichen auch nicht mittels << wimp_ICON_BUTTON_TYPE_SHIFT verschoben werden, um die richtigen Werte zu ermitteln.

Folgendes Programmlisting bietet drei auswählbare Symbole in einem Fenster an.

Listing 7-06 - Drei in einem Fenster auswählbare Symbole

In unserem Beispiel haben die Symbole keine Beschriftung (Text). Auswählbare Symbole werden aber erst in Verbindung mit Text-und-Sprite-Symbolen richtig interessant.

Text und Sprites als Symbole

Es gibt auch Symbole, die gleichzeitig Text und ein Sprite darstellen können. Der Text und das Sprite können dabei verschiedene Ausrichtungen zueinander haben.

Die Abbildung oben mit dem Fenster des Dateisystems zeigt ein solches Beispiel: Unterhalb des Ordnersymbols steht dessen Name. Um das zu verwirklichen, braucht man nicht zwei verschiedene Symbole zu verwenden. Für solche Fälle gibt es das Text-und-Sprite-Symbol.

Auch ein Text-und-Sprite-Symbol kann direkt oder indirekt adressiert sein. Hier gibt es aber einen gravierenden Unterschied. Bei direkt adressierten Text-Sprite-Symbolen müssen Spritename und Text gleich lauten beziehungsweise identisch sein. Das bedeutet, dass bei dieser Art von Symbol immer der Spritename irgendwo um das Sprite herum zu finden ist.

Bei indirekt adressierten Text-Sprite-Symbolen ist das anders. Hier können sich Text und Spritename unterscheiden.

Direkte Text- und Sprite-Symbole

Wollen wir ein Text-und-Sprite-Symbol erzeugen, müssen wir als erstes die Symbolzeichen wimp_ICON_TEXT | wimp_ICON_SPRITE gleichzeitig setzen.

Den Symbolnamen kopieren wir mittels der Zeile

   strncpy (window->icons[0].data.text_and_sprite, "information", 12);
						

Symbol und Text an die später vom Compiler zu bestimmende Adresse window->icons[0].data.text_and_sprite. Wir müssen den Symbolnamen mittels der Funktion strncpy() oder ähnlicher Funktion aus "information" kopieren, weil das Feld text_and_sprite[12] bereits innerhalb der Struktur beziehungsweise innerhalb des Datenblocks window existiert, aber noch nichts Bestimmtes enthält und ein nachträglicher, direkter Eintrag in C mittels window->icons[0].data.text_and_sprite[12] = "information"; nicht mehr möglich ist. Sowas geht in C nur bei der erstmaligen Festlegung (Definition) eines Feldes. Und dann auch nur bei Variablen vom Datentyp char.

Wichtig bei der Ausrichtung von Text und Sprite zu wissen ist, dass die entsprechenden Symbolzeichen wimp_ICON_HCENTRED (H), wimp_ICON_VCENTRED (V) und wimp_ICON_RJUSTIFIED (R) hier etwas andere Bedeutungen haben als bei einem reinen Text- oder Sprite-Symbol. Dies gilt auch für indirekt adressierte Tex-und-Sprite-Symbole. Die in den Klammern stehenden Buchstaben H, V und R gehören nicht zu den Namen der Symbolzeichen, sondern dienen nur als Abkürzung für die folgende Tabelle:

HVR waagrechte Ausrichtung senkrechte Ausrichtung
000 Text und Sprite links ausgerichtet Text unten, Sprite oben ausgerichtet
001 Text und Sprite rechts ausgerichtet Text unten, Sprite oben ausgerichtet
010 Sprite links, Text 12 Einheiten rechts davon ausgerichtet beide mittig zentriert ausgerichtet
011 Text links, Sprite rechts ausgerichtet beide mittig zentriert ausgerichtet
100 Text und Sprite mittig zentriert ausgerichtet Text unten, Sprite oben ausgerichtet
101 Text und Sprite mittig zentriert ausgerichtet Text oben, Sprite unten ausgerichtet
110 Text und Sprite mittig zentriert ausgerichtet; Text jedoch über Sprite beide mittig zentriert ausgerichtet
111 Text rechts, Sprite links ausgerichtet beide mittig zentriert ausgerichtet

0: Symbolzeichen nicht gesetzt, 1: Symbolzeichen gesetzt

Das ist der Grund, warum wir in Listing 7-07 noch zusätzlich das Symbolzeichen wimp_ICON_HCENTRED setzen. Und nur dieses. Bei einem Text-und-Sprite-Symbol hat dieses gesetzte Zeichen jedoch nur in Verbindung mit den zwei nicht gesetzten Zeichen wimp_ICON_VCENTRED und wimp_ICON_RJUSTIFIED die Bedeutung, dass Text und Sprite mittig ausgerichtet, der Text jedoch unter dem Sprite erscheinen soll. Andere Kombinationen dieser drei Symbolzeichen können und sollten einmal an Hand von Listing 7-07 ausprobiert werden.

Listing 7-07 - Erzeugung eines direkt adressierten Text-und-Sprite-Symbols

Indirekte Text- und Sprite-Symbole

Bei indirekt adressierten Text-und-Sprite-Symbolen können sich - wie bereits erwähnt - Spritename und Text unterscheiden.

Diese Art von Symbolen finden vielerlei Verwendung, zum Beispiel für Auswahlschalter oder Radioschalter, welche in den folgenden Abschnitten näher erklärt und realisiert werden.

Neben den Symbolzeichen wimp_ICON_TEXT und wimp_ICON_SPRITE muss zusätzlich auch noch das Symbolzeichen wimp_ICON_INDIRECTED gesetzt werden, um ein indirektes Text-und-Sprite-Symbol zu erzeugen.

Die Startadresse des Textes wird unter window->icons[0].data.indirected_text_and_sprite.text angegeben. Beispielsweise reservieren wir 12 Bytes für den abzubildenden Text und tragen bei der Einrichtung (Initialisierung) des Feldes diesen dort gleich mit ein: char schrift[12] = "mit Schnee";. Das geht in C aber nur bei der erstmaligen Einrichtung des Speichers für Zeichenketten. Wäre dieser Speicher bereits zugewiesen worden, müssten wir den Text mittels einer Funktion wie strncpy() dort nachträglich hineinkopieren.

schrift steht später bei der Übersetzung des Programms für die vom Compiler bestimmte Startadresse des Textfeldes, welche wir unter window->icons[0].data.indirected_text_and_sprite.text angeben:

   window->icons[0].data.indirected_text_and_sprite.text = schrift;
						

Jetzt müssen wir noch den Namen des abzubildenden Sprites angeben. Dies geschieht beim indirekten Text-und-Sprite-Symbol mit Hilfe des Zeigers window->icons[0].data.indirected_text_and_sprite.validation, welcher bereits früher unter dem Abschnitt erlaubte Zeichenfolgen erwähnt worden ist.

Der gerade erwähnte Zeiger window->icons[0].data.indirected_text_and_sprite.validation muss hier auf eine Zeichenkette zeigen, die mit dem Befehl S beginnt. Dem Befehl muss unmittelbar der Name des abzubildenden Sprites folgen und wird wieder mittels dem Steuerzeichen \0 abgeschlossen:

   char valid[15] = "Soptoff";
   window->icons[0].data.indirected_text_and_sprite.validation = valid;
						

Unter window->icons[0].data.indirected_text_and_sprite.size soll nach den PRMs noch die Länge des Textbuffers angegeben werden:

   window->icons[0].data.indirected_text_and_sprite.size = 12;
						

Es folgt zur Übersichtlichkeit das vollständige Beispiel zu diesem Abschnitt:

Listing 7-08 - Erzeugung eines indirekt adressierten Text-und-Sprite-Symbols

Auswahlschalter

Checkbox nicht auswählbar Das Listing 7-08 erzeugt ein Fenster, wie wir es links sehen können.

Es handelt sich dabei um ein indirekt adressiertes Text-und-Sprite-Symbol, welches uns eine Auswahlbox zeigt. Diese Auswahlbox kann nach Listing 7-08 allerdings nicht angewählt werden.

Eine Auswahlbox kann zwei Zustände widerspiegeln: gewählt oder abgewählt / nicht gewählt.

Wenn ein solches Text-und-Sprite-Symbol mit der Maus angewählt wird, sollte es allerdings nicht in den Farben umgedreht (invertiert) werden, wie wir es bereits an Hand Listing 7-06 bereits demonstriert haben. Statt dessen soll ein Häkchen gesetzt werden, wir wir es in der Abbildung unten rechts sehen können. In diesem Fall müssen wir den Zeiger auf den Spritenamen von optoff auf opton ändern, da es sich bei der Auswahlbox mit dem gesetzten Häkchen um ein anderes Sprite handelt. Wir müssen also das Sprite ändern.

Checkbox auswählt Hierzu reicht es, den Auswahltyp des Symbols mit dem Symbolzeichen wimp_BUTTON_RADIO anzugeben und in der Zeichenkette mit dem Spritenamen einen alternativen Spritenamen anzugeben: Soptoff,opton

RISC OS beziehungsweise die Wimp schaltet dann bei einer Anwahl des Symbols mit dem Mauszeiger von selbst zwischen den beiden Symbolen hin und her je nachdem, welcher Zustand vorher bereits enthalten war.

Es folgt zur besseren Übersichtlichkeit das vollständige Beispiel zu diesem Abschnitt:

Listing 7-09 - Erzeugung einer Auswahlbox

Auswahlgruppen (Exclusive Selection Groups - ESG)

RISC OS bietet die Möglichkeit, bis zu 31 (Wert 1 bis 32) verschiedene Gruppen von Symbolen innerhalb eines Fensters festzulegen. Da diese Eigenschaft von den Bits 16 bis 20 der Symbolzeichen festgelegt wird, muss der entsprechende Integer-Wert von 1 bis 32 mittels << wimp_ICON_ESG_SHIFT an die richtige Stelle geschoben werden. Zur Erinnerung: sämtliche Symbolzeichen werden durch den 32-stelligen Binärwert in wimp_icon_flags flags beschrieben. Falls der Wert 0 für die Auswahlgruppe gesetzt wird, wird diese Eigenschaft nicht beachtet. Das heißt die Symbole sind dann völlig unabhängig voneinander und beeinflussen sich nicht gegenseitig. Der Wert 0 ergibt sich üblicherweise automatisch, falls nichts weiter angegeben wird. Das ist bei den meisten Symbolen der Fall.

Symbole mit gleicher ESG-Nummer gehören immer zusammen. Aus einer Gruppe von Symbolen, welche alle die gleiche ESG-Nummer haben, kann mittels der Auswahltaste (üblicherweise linke Maustaste, engl. selection) immer nur ein Symbol ausgewählt werden. Wird mit der Auswahltaste ein anderes angewählt, wird das bisher ausgewählte Symbol wieder abgewählt.

Das Verhalten beim Auswählen mit der Spezialtaste (in der Regel die rechte Maustaste, engl. adjust) dagegen kann verschieden sein und hängt vom Symbolzeichen wimp_ICON_ALLOW_ADJUST ab. Wurde dieses Zeichen gesetzt, können durch Anklicken mit der Spezialtaste auch mehrere verschiedene Symbole mit der selben ESG-Nummer gleichzeitig ausgewählt sein. Ein gutes Beispiel für dieses Verhalten zeigt zum Beispiel ein geöffnetes Dateifenster vom Dateisystem wie es oben in der Abbildung des Dateimanagers zu sehen ist. Hier wurden mittels der Spezialtaste drei verschiedene Symbole ausgewählt. wimp_ICON_ALLOW_ADJUST muss für jedes Symbol gesetzt sein, das mittels der Spezialtaste zusätzlich auswählbar sein soll.

Auswahlgruppen werden auch für Radioschalter verwendet.

Radioschalter

Radioschalter Für Radioschalter verwendet man die Sprites radiooff und radioon aus dem ROM-Spritebereich, welche uns vom System zur Verfügung gestellt werden.

Bei Radioschaltern, wie in der nebenstehenden Abbildung, kann immer nur ein Schalter von vielen gleichzeitig ausgewählt sein, ähnlich wie man bei einem Radio immer nur einen Sender gleichzeitig empfangen kann. Deshalb heißt diese Art von Symbol auch Radiosymbol beziehungsweise -schalter (engl. radio buttons).

Wir müssen, um diese Eigenschaft erreichen zu können, einer Gruppe von Symbolen die gleiche Auswahlgruppennummer (ESG) zuweisen. OSLib stellt uns dafür gleich mehrere Variablen zur Verfügung.

Möchte man innerhalb eines Fensters nur eine einzige gemeinsame Auswahlgruppe (ESG) festlegen, genügt es, jedem dieser Auswahlgruppe zugehörigen Symbol das Symbolzeichen wimp_ICON_ESG mitzugeben. wimp_ICON_ESG setzt sämtliche Bits 16 - 20 der Symbolzeichen auf 1 und entspricht damit einer Auswahlgruppennummer von hexdezimal 0x1Fu = 31.

Möchte man mehrere verschiedene Auswahlgruppen innerhalb eines gemeinsamen Fensters festlegen, muss man die entsprechenden Bits mittels

   x << wimp_ICON_ESG_SHIFT
						

setzen, wobei x für eine Nummer zwischen 1 und 31 stehen kann. Sind sämtliche Bits der Stellen 16 bis 20 eines Symbolzeichens gelöscht, gehört es keiner Auswahlgruppe an und ist von allen anderen unabhängig. Falls beim Setzen der Symbolzeichen nichts weiteres angegeben wird, sind sämtliche Bits bereits gelöscht, das heißt der letztere Fall ist dann bereits gültig.

   31 << wimp_ICON_ESG_SHIFT
						

entspricht dem Setzen von wimp_ICON_ESG.

Die Angabe

   wimp_ICON_ESG << wimp_ICON_ESG_SHIFT
						

ist falsch und darf nicht verwendet werden, weil hier die bereits richtigen Symbolzeichen (Bits an richtiger Stelle) von wimp_ICON_ESG mittels wimp_ICON_ESG-SHIFT an falsche Positionen geschoben werden. Das heißt mittels dieser Angabe werden Symbolzeichen gesetzt, welche mit den eigentlichen Auswahlgruppen nichts mehr zu tun haben! Man kann sich dem auch klar werden, indem man sich den binären Wert von wimp_ICON_ESG ansieht (0000 0000 0011 1110 0000 0000 0000 0000) und diesen um 16 Stellen nach links verschiebt. Denn nichts anderes tut wimp_ICON_ESG << wimp_ICON_ESG_SHIFT.

Ein Radioschalter sollte bereits ausgewählt sein. Dieses haben wir mittels dem Setzen des Symbolzeichens wimp_ICON_SELECTED bereits getan.

Dreidimensionale Symbole

Radioschalter mit Rahmen Verschiedene Symbolgruppen innerhalb eines gemeinsamen Fensters sollten kenntlich gemacht werden. Dies kann man zum Beispiel mit einem Rahmen machen, wie in der nebenstehenden Abbildung zu sehen ist.

Dazu müssen wir das Symbolzeichen wimp_ICON_BORDER setzen. Wir verwenden hier ein indirektes Textsymbol, um mit Hilfe der zusätzlichen Validierungszeichenkette R4 aus dem Rand ein dreidimensionales Symbol zu machen. Text geben wir keinen aus. Das Symbol legen wir unter die drei bereits erzeugten Symbole. Das heißt es muss als erstes der vier in der Abbildung zu sehenden Symbole geschrieben werden (windows->icons[0]...), weil RISC OS sonst zwar die Radioschalter zeichnet, jedoch nicht mehr erkennt. Ein Auswählen mit der Maus ist dann nicht mehr möglich. Man kann dies einmal ausprobieren, in dem man die Reihenfolge der Symbole vertauscht und das 3-D-Symbol ans Ende stellt (window->icons[3]...)

Es gibt verschiedene Arten von 3-D-Symbolen, welche zum Teil noch zusätzliche Parameter verarbeiten können. Diese Parameter können Angaben über Farbe und so weiter enthalten:

R Bedeutung:
1 erhöhte Fläche
2 vertiefte Fläche
3 Wall
4 Rille
5 Aktionsknopf (Platte)
6 Aktionsknopf
7 editierbares Feld

Die PRMs geben hierüber nähere Auskunft. Man sollte diese Parameter einmal an Hand von Listing 7-10 ausprobieren.

Wichtig ist auch, dass man die Reihenfolge der Koordinaten einhält. Falls die Reihenfolge dieser Koordinaten vertauscht wird, kann es passieren, dass der 3-D-Rahmen nicht mehr richtig nachgezeichnet wird, falls man ein anderes Fenster darüberschiebt. Man sollte dies ebenfalls einmal ausprobieren, indem man in Listing 7-10 y0 und y1 vertauscht:

   window->icons[3].extent.y0 = -180;
   window->icons[3].extent.y1 = -230;
						

Es folgt das vollständige Programm-Beispiel zu diesem Abschnitt, welches ein Fenster mit Radioschaltern erzeugt.

Listing 7-10 - Erzeugung von Radiosymbolen

Wir haben in diesem Beispiel noch eine zusätzliche Variable namens anzahl_symbole eingeführt, welche nur zur Vereinfachung führt und mit dem Lehrinhalt nichts zu tun hat.

Will man mehrere Radiosymbole gleichzeitig mit Hilfe der Spezialtaste (rechte Maustaste - engl. adjust) auswählen können, so hat man zusätzlich zu jedem Radiosymbol das Symbolzeichen wimp_ICON_ALLOW_ADJUST zu setzen.

Mit Hilfe der Spezialtaste lässt sich auch das angewählte Radiosymbol abwählen, so dass überhaupt kein Radiosymbol mehr ausgewählt ist. Das ist unter RISC OS ein festgelegtes Verhalten. Will man dies verhindern, so muss man sich selbst einen eigenen Programmcode dafür schreiben.

Symbole auf der Symbolleiste

Wie bereits eingangs dieses Kursteils erwähnt, können Symbole auch nachträglich erzeugt werden - also wenn das Fenster bereits erzeugt worden ist. Der Datenblock hierzu ist ein etwas anderer als der für Symbole, die direkt dem Datenblock eines Fensters folgen, weil zusätzlich noch die Fensternummer (engl. window handle) angegeben werden muss:

   typedef struct
   {
      wimp_w w;
      wimp_icon icon;
   }
   wimp_icon_create;
						

An die Stelle wimp_w w; muss man die Nummer des Fensters schreiben, zu welchem das Symbol gehört. Diese Nummer wird in der Regel von RISC OS bei der Einrichtung eines Fensters vergeben. Handelt es sich bei dem Symbol um ein Sprite, muss es aus dem Spritebereich stammen, der im Datenblock des Fensters festgelegt worden ist. Wimp-Sprite-Bereich oder von der Aufgabe selbst eingerichteter Bereich, auch bekannt als Benutzerbereich.

Die Symbolleiste wird als selbständiges Fenster jedoch ohne Schaltflächen und Leisten behandelt. Sie hat bestimmte, vom System festgelegte und reservierte Nummern:

Fensternummer OSLib
-1 wimp_ICON_BAR_RIGHT
-2 wimp_ICON_BAR_LEFT

An dieser Stelle nur die wichtigsten. Es gibt noch weitere feste Nummern beziehungsweise Konstanten, welche den PRMs beziehungsweise der Dokumentation zu OSLib entnommen werden können.

Man beachte, dass der Datenblock wimp_w w für die Erzeugung eines Fensters genauso wie für die Erzeugung eines Symbols verwendet werden kann und deshalb einige der festen Nummern (Konstanten) in wimp_w w überladen sind. Bei Verwendung von wimp_w w in Verbindung mit einem Fenster hat -1 die Bedeutung von liege allen anderen Fenstern obenauf. Deshalb werden im Eintrag von wimp_w w im OSLib-Handbuch auch zwei verschiedene Konstanten aufgeführt, nämlich wimp_ICON_BAR_RIGHT und wimp_TOP, welche beide den gleichen Wert -1 vertreten.

wimp_icon icon; wurde bereits in den vorhergegangenen Abschnitten ausführlich behandelt. Allerdings bleibt noch zu erwähnen, dass im Falle der Symbolleiste die Koordinaten anders gezählt werden. .icon.extent.x0 = 0 sowie .icon.extent.y0 sollten beide 0 sein. Die maximale y-Ausdehnung des Sprites sollte 68 OS-Einheiten nicht überschreiten. Die Breite kann nahezu beliebig sein. Da aber fast immer Symbole von Anwendungsverzeichnissen auch für die Symbolleiste verwendet werden, macht es Sinn, sich auch hier auf 68 OS-Einheiten zu beschränken.

Bei Symbolen auf der Symbolleiste handelt es sich fast immer um ein direktes Spritesymbol, weshalb Bit 2 der Symbolzeichen gesetzt werden sollte (wimp_ICON_SPRITE). Das Symbol auf der Symbolleiste lässt sich üblicherweise mit einem Mausklick anklicken, denn dafür ist es hauptsächlich dar, weshalb man den Tastensymboltyp wimp_BUTTON_CLICK << wimp_BUTTON_TYPE_SHIFT zulassen und auswerten sollte.

Symbole auf Iconbar Ist der Datenblock des Symbols eingerichtet worden, so wird es dann mit der Funktion extern wimp_i wimp_create_icon (wimp_icon_create const *icon); erzeugt. Sie liefert die vom System vergebene Symbolnummer zurück (engl. icon handle), die erforderlich ist, um das Symbol anzusprechen beziehungsweise abzufragen.

Die Textmarke kann auf der Symbolleiste nicht gesetzt werden, weshalb auf der Symbolleiste keine schreibbaren Symbole verwendet werden sollen.

Es folgt das Programmbeispiel zu diesem Abschnitt:

Listing 7-11 - Erzeugung eines Symbols auf der Symbolleiste

Alle Listings stehen mit Makefile zum Herunterladen bereit.

Update 12. 6. 2016: Bild Lage des Symbols innerhalb des Arbeitsbereichs ausgetauscht, ein paar Korrkturen im Text.

 

Der achte Teil behandelt die Vorlagen von Fenstern

Fehler gefunden? Etwas unklar? Ergänzung oder ein Tipp? Oder einfach nur ein Kommentar? Nachricht schicken!

Name: *

EMail:

Text: *
Hardware   Software   Praxis   Sonstiges  
ArcSite   News   Magazin   Börse   Links   ArcArchie   Homepages