Ataquarium - GEM & WinDom

Wer gedacht hatte, im Ataquarium schwimmen alle DEFINEs schon mit dem Bauch nach oben, beweist diese Ausgabe das Gegenteil.

Nachdem wir alle nach dem Lesen der letzten Ausgabe einen Top-Ten-Hit produziert haben, ist für den Lebensabend erst einmal ausgesorgt. Mit einem dicken Bankkonto im Rücken hat es sich schon immer leichter programmiert und so gibt's nach einem Monat Unterbrechung wieder ein Ataquarium.

Ob es die zeitliche Nähe zur Error-in-Line III oder einfach das Erwachen aus dem Winterschlaf war - es gibt wieder einige Neuigkeiten, wie immer frei von jeder Ordnung:

Eine Meldung nach dem Motto "Mal sehen, was dabei herauskommt" ist die Übernahme der XaAES-Sourcen durch Oliver Landemarre und Eric Reboux. Immerhin wandern die Sourcen von XaAES damit schon zum zweiten Mal in andere Hände. Interessant dürfte auch sein, ob das Programm weiter als Open Source vertrieben wird. Da schon die Original-Version unter der GPL stand, müssten auch die Weiterentwicklungen frei sein. Der zweite Punkt ist sicherlich, inwieweit sich ein "neues XaAES" an bestehende Standards hält. Hier wäre z.B. eine vollständige Integration von WDIALOG (egal wie unvollkommen es erscheinen mag) und erweiterter MagiC-Funktionen eine Notwendigkeit. Was wäre das für ein Traum: ein Programmierer schreibt ein GEM-Programm, ohne 70 KB an Bibliotheksroutinen hinzulinken zu müssen.

Endlich: GEM für den Atari

center

Wer erinnert sich noch an GEM/2.2? Damals hat eine kleine niederländische Firma damit für Verwirrung gesorgt, denn die grafische Benutzeroberfläche ist schließlich schon im Betriebssystem eingebaut. Tatsächlich trennten sich das PC-GEM und Atari-GEM schon kurz nach der Einführung des Atari ST. Verantwortlich dafür war in erster Linie Apple, die auch gerne als "Anwaltskanzlei mit angehängter Computerabteilung" verspottet wurden. Als Folge musste Digital Research das PC-GEM umändern. Statt frei bewegbarer Dateifenster gab es nur noch zwei starre Laufwerksfenster. Zu bewundern ist dies auch auf dem ST - Emutos benutzt den freien Desktop des PC-GEM. Natürlich kannte auch das PC-GEM weiterhin frei bewegbare Fenster, nur machte der Desktop davon keinen Gebrauch. 1986 erlebte GEM für den PC seinen viel zu kurzen Höhepunkt: der Amstrad (bei uns: Schneider) PC 1512 brachte GEM und EGA-Grafik für etwa 1500 Euro. Das PC-GEM hatte aber den Makel der "verkrüppelten" Oberfläche anhängen. Unter der Haube wies es aber einige Verbesserungen gegenüber dem Atari-GEM, daher machte die Rückportierung vom PC auf den Atari auch Sinn, zumal gleichzeitig einige PC-GEM-Programme (Paint, WordChart etc.) portiert wurden, die GEM 2.2 zwingend benötigten. Das Projekt war jedoch ein ziemlicher Reinfall, zumal es zu der Zeit schon genug leistungsfähige Programme für das "alte" Atari-GEM gab. PC-GEM und Atari-GEM gingen weiterhin getrennte Wege und zum Ende hin versuchte sich DR sogar an einem Multitasking-GEM, das jedoch nie fertig gestellt wurde. Schließlich übernahm Caldera DR, die Sourcen für GEM wurden freigegeben. Seitdem gibt es sporadische Weiterentwicklungen - so werden Funktionen des Atari-GEM nachgerüstet, die zwei starren Desktop-Fenster sind wieder flexibel und ein 3D-Effekt für Fensterelemente sowie ein Hintergrundbild lassen das alte GEM fast wieder zeitgemäß erscheinen.

Jetzt soll die letzte offizielle GEM-Version 3.x auf den Atari portiert werden. Klar erhoffen sich die Entwickler dadurch auch einen Schub für das PC-GEM. Nicht geklärt ist bislang, ob auch die ganzen inoffiziellen Änderungen mitportiert werden. Mutig ist das Unternehmen in jedem Fall - denn kaum ein Entwickler wird seine Programme an ein Atari-GEM 3.01 anpassen.

EmuTOS 0.6

Greifbarer ist da schon die neue Version von EmuTOS, dem Open Source-TOS. Das Betriebssystem unterstützt jetzt vr_tranfm, das Native-Feat-Interface von Emulatoren, Dead Keys, XHDI und NVRAM. Hinzu kommen etliche Bugfixes und Detailverbesserungen. Trotzdem lässt die Kompatibilität noch zu wünschen übrig - aber schließlich hat EmuTOS noch nicht den Leistungsstand von TOS 1.0 erreicht.

HighWire

Auch von HighWire gibt es neues zu berichten: GIF-Bilder werden jetzt auch bei einer Farbtiefe größer als 8 Bit richtig dargestellt.

WinDom - DFRM

Viele haben schon von der GEM-Library WinDom gehört. Diese ist durch verschiedene Zusätze erweiterbar, was der ohnehin schon umfangreichen Library noch ein paar Zusatzfunktionen beschert. Mit dem Windom-Kurs wird es zwar in dieser Ausgabe nichts, aber zumindest soll hier ein Windom-Modul vorgestellt werden: DFRM.

Neulich habe ich in einer alten st-computer (Jahrgang 1986) geblättert. Abgedruckt war dort ein kleines Accessory, dass die aktuelle Uhrzeit in der rechten oberen Bildschirmecke anzeigte. Solche Programme sind heute nichts besonders und auch vor 17 Jahren waren sie nicht unbedingt der letzte Schrei, aber das Programm war besonders kompakt. Dies wurde erreicht, in dem die Resource-Datei im Programm integriert wurde.

Ein anderes Beispiel für einen etwas anderen Weg, eine Dialogbox aufzubauen, zeigt der HTML-Editor HomeSite für Windows. Dort bringt das Hauptprogramm nur eine gewisse Grundfunktionalität mit, viele der Dialoge für die verschiedenen HTML-Tags liegen in Modul-Verzeichnissen. Jeder kann also Tag-Editoren nachrüsten, in die Werkzeugleisten integrieren, oder bestehende Editoren abändern. Alles geschieht mit einer Sprache namens VTML, die dem Benutzer gerade so viel Freiheit lässt, wie er braucht.

Auf dem Atari gibt es Resource-Dateien, aber wer es Anwendern erlauben will, Funktionalitäten nachzurüsten, muss entweder mit mehreren RSCs arbeiten oder strikte Vorgaben machen, damit das Programm nicht durch die vom Anwender durchgeführten Änderungen nicht mehr auf die eigenen Daten zugreifen kann (der DAU lauert überall).

DFRM ist in diesem Fall die Lösung. Es funktioniert ähnlich wie die Lösung der stc aus dem Jahr 1986, ist aber ungleich moderner. Angenommen die Daten für die Dialoge werden extern geladen, erhält man nicht nur die Grundlage für ein Plug-in-System, sondern kann auch - anders als bei RSC-Dateien - genau steuern, was der User ändern darf und was nicht.

Die Include-Dateien

Die Installation von DFRM ist sehr einfach. Die Ordner im Archiv heißen Include und Lib und sind noch einmal unterteilt in gcc281, gcc295, purec und sozobon. Da DFRM auf Windom aufsetzt, muss dieses bereits installiert sein.

Start

In eine neue C-Datei kommt zunächst die Einbindung der Includes:

#include <stdlib.h>
#include <windom.h>
#include <dfrm.h>

Anschließend legen wir die Prototypen für die eigenen Funktionen fest. Ohne die Prototypen wird sich der Compiler beschweren und das Programm wird evtl. nicht funktionieren:

void Infos( WINDOW *win, int index);
void Schliessen( WINDOW *win, int index);
void Shutdown(void);
void WinTerm( WINDOW *win, void *data);

In der Hauptprozedur wird die Dialogbox zusammengebaut. Bei komplexeren Projekten ist es sicherlich sinnvoll, diese in eine eigene Funktion auszulagern.

void main(void) 
{
WINDOW *win;
void *dial:
int child, parent;
ApplInit(); /* Initialisierung der Anwendung */

Der Befehl zum Erstellen einer neuen Dialogbox oder eines neuen Menübaums lautet dfrm_create. Mit create wird ein Objektbaum noch nicht dargestellt - er wird lediglich vorbereitet.

dial = dfrm_create (10, TYPE_NORMAL);

Der erste Parameter ("10") definiert, wie viele Objekte maximal in dem Dialog/Menü enthalten sein dürfen.

Der zweite Parameter legt den Typ des Objektbaums fest. "TYPE_NORMAL" steht für einen normalen Dialog. Mit "TYPE_MENU" kann auch ein Menübaum erstellt werden, wobei die Menüeinträge vom Aussehen nicht ganz dem Standard entsprechen. Neben diesen beiden häufig verwendeten Typen existiert weiterhin "TYPE_OUTLINED" (Dialog mit einem zusätzlichen Außenrand) und TYPE_EMPTY (leerer Objektbaum). Bei letzterem wird das Objekt, das als erstes definiert wurde, zum Root-Objekt.

Jetzt kann schon das erste Text-Objekt in der Dialogbox definiert werden. Um einen einfachen Text/String zu definieren, dient die Funktion dfrm_new_label:

child = dfrm_new_label(dial, TYPE_LABEL, "Die st-computer");

Damit bekommt unser Dialog sein erstes Kind. Aber bevor die Sektkorken knallen, komme ich noch zu den Parametern. Der erste Parameter (dial) ist, wie unschwer zu erraten ist, ein Zeiger auf den Dialog, der mit dfrm_create erstellt wurde. "TYPE_LABEL" lässt darauf schließen, das es mehr als einen Text-Typ gibt. Zwei weitere Typen werden für Menüs benutzt: TYPE_MITEM (Menüeintrag) und TYPE_MTITLE (Menütitel). Hinzu kommt mit TYPE_ULABEL ein Typ für unterstrichenen Text. Tatsächlich unterstützt DFRM alle erweiterten Windom-Objekte - so etwa auch mehrzeiligen Text oder scrollbare Texteingabefelder. Der letzte Parameter ist natürlich der Text selber. Die Größe im Dialog entspricht immer der Textlänge.

dfrm_add(dial, ROOT, child, -4, -1, DIR_VERT);

Mit dfrm_add wird das Objekt dem Dialog hinzugefügt. Der erste Parameter ist natürlich ein Zeiger auf den Dialog. Als nächstes wird der Objektindex des Eltern-Objekts angegeben, danach kommt der Objektindex des Kind-Objektes (child), den wir als Rückgabewert von dfrm_new_label erhalten haben. Anschließend kann eingestellt werden, wie viel Platz um das Objekt geschaffen werden soll - damit wird das Objekt letztendlich positioniert. Als erstes gibt es hier horizontalen Freiraum, dann folgt der vertikale Freiraum. In diesem Fall wird die relative Positionierung gewählt. Der letzte Parameter legt fest, ob nur Freiraum gegenüber dem übergeordneten Eltern-Objekt geschaffen oder eine Objektposition eingestellt wird. Die "-4" bedeutet, dass der Text vier Zeicheneinheiten Platz nach links hat. Das Minus-Zeichen mag etwas seltsam aussehen, aber es dient als Schalter zwischen Pixel-Werten und Zeichenwerten. Letztere sind eigentlich immer vorzuziehen, da sonst eine andere Schriftgröße zu einem hässlichen Dialog führen würde. Das Eltern-Objekt wird im übrigen immer den Kind-Objekten angepasst - die Gefahr, mit Texten über die Fenstergrenzen "hinauszuschießen", ist also sehr gering.

Die Ausrichtung des Objektes wurde damit aber noch nicht festgelegt. Dazu dient dfrm_align:

dfrm_align(dial, child, DIR_HORI, ALIGN_CENTER);

Diese Funktion ist schon fast selbsterklärend. Ein Text kann entweder horizontal oder vertikal ausgerichtet werden. Dementsprechend variieren auch die erlaubten Werte für den vierten Parameter.

Bei horizontaler Ausrichtung gibt es ALIGN_LEFT (linksbündig), ALIGN_CENTER (zentriert), ALIGN_RIGHT (rechtsbündig) und ALIGN_JUSTIFY (Blocksatz).

Die vertikale Ausrichtung kennt ALIGN_TOP (oberhalb ausrichten), ALIGN_CENTER (zentrieren), ALIGN_BOT (nach unten ausrichten) und ALIGN_JUSTIFY.

Zeit für ein zweites Kind:

child = dfrm_new_label(dial, TYPE_LABEL, "ist ein spitzen Magazin!");

Zugegeben, Eigenlob stinkt, aber Computerprogramme haben nun einmal den unschätzbaren Vorteil, das sie (noch) nicht Geruch ausströmen. Die nächsten zwei Zeilen benötigen wohl auch keiner größeren Erläuterung:

dfrm_add(dial, ROOT, child, -4, 0, DIR_VERT);
dfrm_align(dial, child, DIR_HORI, ALIGN_CENTER);

In GEM-Programmen werden unsichtbare (transparente) Boxen dazu benutzt, Objekte zusammenzufassen. Damit wird ein neues Eltern-Objekt (also quasi ein "Elternabend") definiert:

parent = dfrm_new_box(dial, 0,0,0,0);

Parameter 1 dürfte klar sein. Parameter zwei und drei definieren die Breite und die Höhe. Wie gehabt bedeutet ein negativer Wert eine Größe in Zeichen und ein positiver eine Pixel-Angabe. Bei einer Box, die andere Objekte gruppieren soll, ist keine Größenangabe erforderlich, schließlich passt Windom die Größe automatisch an.

Der vierte Parameter gibt die Größe des Randes an. Ist dieser Wert größer 0, zeichnet Windom die Box sichtbar. Mit dem fünften Parameter wird schließlich die Farbe des Randes definiert.

Was wäre ein Eltern-Objekt ohne Kind? Richtig, einsam. Das Programm wird nichts besonderes machen, aber zumindest einen Button soll der Dialog bekommen:

child = dfrm_new_button(dial, TYPE_XDBUT, "Stimmt!");

Am Button-Text wird schon deutlich: Programmieren ist keine Demokratie und ein Zweitbutton ist erstmal nicht vorgesehen. Eine Angabe ist noch unbekannt: TYPE_XDBUT. Hierbei handelt es sich um einen erweiterten Defaultbutton von Windom, die Standard-Ausführung nennt sich TYPE_DBUT. Neben diesen beiden gibt es noch Exit-Buttons (TYPE_EBUT/TYPE_XEBUT), Undo-Buttons (TYPE_UBUT/TYPE_XUBUT) und den selektierbaren Button (TYPE_XSBUT).

Jetzt wird der Button mit einer Callback-Funktion verbunden:

dfrm_attach(dial, child, BIND_FUNC, Schliesssen);

Der Button wird mit der Funktion "Schliessen" verbunden, die das Programm beendet.

Nun wird das Objekt ausgerichtet:

dfrm_add(dial, parent, child, 0, -1, DIR_HORI);

Ein zweiter Button dient lediglich dazu, eine kleine Info-Box aufzurufen:

child = dfrm_new_button(dial, TYPE_XDBUT, "[Hilfe");
dfrm_add(dial, parent, child, -4, -1, DIR_HORI);
dfrm_attach(dial, child, BIND_FUNC, Infos);

Damit ist der Aufbau des Inhaltes der unsichtbaren Box abgeschlossen. Sie muss jetzt nur noch mit dem übergeordneten Objekt verbunden werden:

dfrm_add(dial, ROOT, parent, -4, 0, DIR_VERT);
dfrm_align(dial, parent, DIR_HORI, ALIGN_CENTER);

Abgeschlossen wird die Dialogdefinition mit dfrm_repack. Windom kalkuliert dann die nötigen Objektbreiten:

dfrm_repack (dial);

Jetzt kann die Dialogbox endlich geöffnet werden:

win = dfrm_open(dial, WAT_FORM, "Ataquarium", TRUE);
Evnt_Attach(NULL, AP_TERM, Shutdown);
for(;;) EvntWindom(MU_MESAG);
}

Evnt_Attach verdeutlicht eine der Stärken von Windom: Systemnachrichten können sehr einfach mit User-Funktionen verbunden werden.

Die Funktion, die das Programm beendet, darf nicht fehlen:

void Shutdown(void) {
  while( wglb.first) {
    ApplWrite( app.id, WM_DESTROY, 
               wglb.first->handle, 0, 0, 0, 0);
    EvntWindom( MU_MESAG);
  }
  ApplExit();
  exit( 0);
}

Die Funktion "Schliessen" ist mehr oder weniger eine Umleitung auf die Shutdown-Funktion, allerdings wird der Button-Status zurückgesetzt:

void Schliessen(WINDOW *win, int index)
{
	ObjcChange(OC_FORM, win, index, NORMAL, TRUE);
	ApplWrite(app.id, AP_TERM, 0, 0, 0, 0, 0);
}

Zu guter Letzt soll noch eine kleine Programminformation in einem schnöden Alert ausgespuckt werden:

void Infos(WINDOW *win, int index)
{
	FormAlert(1,"[1][Ataquarium-Beispiel!][OK]");
	ObjcChange(OC_FORM, win, index, NORMAL, TRUE);
}

Auch hier wird der Objektstatus des Exit-Buttons zurückgesetzt.

Auf diesem Programmierbeispiel kann man sehr gut aufbauen. In einem späteren Ataquarium wird das Programm eventuell so erweitert, das es etwas sinnvolles tut. In diesem Sinne, bis nächsten Monat!

Quellen:


Mia Jaap
Aus: ST-Computer 06 / 2003, Seite

Links

Copyright-Bestimmungen: siehe Über diese Seite