  GEM mit GFA: Die Hilfe   
                       
  - Verwendung von GEM-Dialogen       
  - Menleisten            
  - eigene Desktops      
  - Fenster             
  - Schreiben mit GDOS-Fonts, Textausgabe in GEM-Windows   

  (C) 1994 by David Reitter: PUBLIC DOMAIN    

                                                              15.5.94

0. Vorwort

Lieber User,
dieser Text gibt Dir einige Tips, wie Du unter GFA-Basic Dialoge, 
Mens und Fenster unter GEM einsetzen kannst. Vielleicht hast Du 
schon anhand diverser Literatur etwas rumprobiert - aber nach vielen 
Abstrzen aufgegeben. So ging es mir jedenfalls so, bevor ich von 
anderen Programmierern das lernte, was ich hier weiterzugeben 
versuche. Es geht auch ohne Abstrze - wenn auch nicht am Anfang. 
Ich mchte Dir hier zunchst ein bichen Software empfehlen. Zum 
Erstellen von Dialogboxen und von Mens bentigt man ein "Resource 
Construction Set". Ein sehr leistungsfhiges RCS ist "Interface", es 
kostet 128.- DM. Fr nur 50.- DM bekommt man das Shareware-Programm 
"ORCS", welches auch viele Funktionen bietet. Ein RCS bentigst Du 
auf jeden Fall, notfalls das, was mit GFA-Basic mitgeliefert wird.
Um GEM einzusetzen, ist etwas Literatur empfehlenswert: Das 
"ATARI ST/STE/TT-Profibuch" bietet sich da an. Im Software-Teil des 
Buches ist das Betriebssystem des ST komplett beschrieben. 
Alternativ wre fr den GFA-Programmierer "Das groe GFA-Basic-3.5-
Buch" interessant. Hier darf man sich aber nicht von den zahlreichen 
Unsauberkeiten, die der Autor als Beispielprogramme verwendet, vom 
"Pfad der Tugend" abbringen lassen.
Zuletzt noch der Hinweis auf zwei m.E. sehr gut einsetzbare 
Libraries. Die "FlyFials" von Gregor Duchalski sollte man auf jeden 
Fall in GEM-Programmen verwenden, zumal diese einem das Darstellen, 
Bearbeiten und Auswerten von Dialogen wesentlich erleichtern.
Die andere Library ist die "Winlib" von Stefan Mnch. Hiermit knnen 
Fenster verwaltet werden, wobei man sich die Programmierung eines 
Groteils der Oberflche spart.

Dem Programmierer, der nun mit der GEM-Programmierung beginnen will, 
empfehle ich folgendes: Kapitel 1 komplett lesen, FlyDials besorgen 
und nun mit den FlyDials die Dialoge programmieren. Sollen Fenster 
zum Einsatz kommen, kann man sich bei dem mitgelieferten 
Beispielprogramm (GFA_GEM.GFA) viel abgucken, Kapitel 3 und 5 sind 
Grundlage dafr.

Der Beispieldialog ist - das mu ich aus heutiger Sicht sagen (1.5 
Jahre nach dem Schreiben der ersten Version dieses Textes) nicht mehr 
ganz "State of the art", d.h. man kann ihn wunderschn zum Anschauen 
und zum Demonstrieren von AES-Funktionen benutzen, nicht aber sollte 
man sich im Design daran orientieren.

Ich bitte alle Programmierer, die lieber gesiezt werden mchten, den 
lockeren "Du"-Stil zu entschuldigen und wnsche auch ihnen bzw. Ihnen:

Viel Erfolg bei der GEM-Programmierung !



1. Allgemeines

Warum GEM ?

Die Verwendung von GEM in eigenen Programmen bietet viele Vorteile,
die sowohl den Anwender als auch den Programmierer betreffen. Wenn
ein Programm die Mglichkeiten benutzt, die GEM anbietet, kann der
Anwender das Programm schneller verstehen und benutzen, er mu sich
nicht mit der Schnittstelle beschftigen sondern kann direkt das
eigentliche Programm benutzen. Sonst sitzt der Anwender rtselnd vor
einer ihm unverstndlichen Oberflche und wei nicht, was er tun
kann und soll. Wird GEM verwendet, kann man davon ausgehen, da der
Anwender die Oberflche von anderen Programmen (und sei es das Atari-
Desktop) her kennt und wei, wie man Mens und Dialogboxen bedient.
Auch mhsame Anleitungen bleiben durch die "innere Konsistenz" 
gewahrt. Es ist nicht ntig, fr jede Funktion zu beschreiben, wie 
der Anwender sie erreichen kann. Eine simple Angabe wie 
"File/speichern" gengt, um dem Anwender klarzumachen, da das Men 
"File" zu ffnen ist und darin der Menpunkt "speichern" anzuklicken 
ist, um die beschriebene Funktion zu aktivieren.
Auerdem gehrt GEM zur sauberen Programmierung, denn nur durch
Zugriffe auf die oberste Systemebene (AES) kann verhindert werden,
da das Programm auf anderen Grafiksystemen nicht luft. Denn 
eine Grafikkarte sorgt automatisch dafr, da diese 
Funktionen korrekt ausgefhrt werden. Greift man dagegen 
direkt auf den Bildschirm zu, hat die Grafikkarte weniger 
Mglichkeiten, die Bildschirmnderungen entsprechend zurechtzu-
biegen. Desweiteren wrde man bei direkten Zugriffen auf den 
Bildschirm davon ausgehen, da der Bildschirm eine bestimmte 
Breite hat und der Bildschirmspeicher in einem bestimmten Format 
aufgebaut ist, was natrlich schnell (schon bei OverScan) nicht 
mehr gegeben ist. Auch sind Fenster fr den Betrieb eines 
Multitaskingsystems notendig, wenn der Anwender auf einem Gro-
bildschirm mehrere Anwendungen gleichzeitig sehen will.
Auch schon bei Accessories (das ist ja auch eine Art Multi-
tasking) mchte man Redraw-Meldungen empfangen, was ohne Fenster 
nicht mglich ist. Fr den Programmierer ergibt sich durch die 
Anwendung von GEM-Dialogboxen eine groe Vereinfachung, da diese 
nicht mhsam programmiert werden mssen. Auch mu der 
Programmierer keine eigene Oberflche entwickeln.
Es gibt also viele gute Grnde fr die Anwendung von GEM, erstrecht
dann, wenn ein Programm der ffentlichkeit zugnglich gemacht werden
soll. Die vielen Vorurteile erweisen sich schnell als nichtig, denn
GEM-Fenster sind gar nicht so langsam, wenn man nur ein paar
(saubere) Tricks beachtet (z.B. v_gtext()!).
Also ran an die Arbeit, denn der Weg zu perfektem GEM ist - in GFA-
Basic - nicht allzueinfach.

Beginnen wir mit dem einfachsten, einer Dialogbox.

Alle GEM-Elemente sind als Baumstruktur aufgebaut, d.h. ein Objekt
bildet die Grundlage fr beliebig viele andere Objekte. In einer
Datei mit der Endung RSC - die Resource-Datei - sind mehrere dieser
Grundobjekte abgespeichert, sie nennt man Dialogbume und kann sie 
mit Nummern angesprechen. In diesen Dialogbumen befinden sich nun 
weitere Objekte, und jedes dieser Objekte kann weitere 
Objekte beinhalten. Das oberste Objekt (das "Wurzelobjekt") ist ein 
"Mutterobjekt" - es hat mehrere "Kinder". All diese "Kind"-Objekte 
knnen nun weitere "Kind"-Objekte haben. Fr ihre Kinder sind sie 
logischerweise wieder Mutterobjekte. Auch diese Kinder (es sind 
sozusagen mittlerweile die "Enkel" des Wurzelobjektes) knnen wieder 
Kinder bekommen (dazu mu man einfach das betreffende Objekt im RCS 
auf ein anderes schieben - nein, kein Begattungsakt, denn das obere 
Objekt ist nun Kind). Wenn man das grafisch darstellt, sieht ein 
Objektbaum also so aus:


Wurzelobjekt                   DIALOG-RAHMEN
                                     |
                .------.-----.--------------.-----.------.
                |      |     |              |     |      |
               BOX    BOX   TEXT         E-TEXT BUTTON BUTTON
                |      |  "Titel"      "Edit:"  "OK"  "Abbruch"
            .------.  TEXT
            |      |  "Dies ist ein Text"
            |      |
         RBUTTON  RBUTTON
         "laut"   "leise"



Das oberste Objekt stellt das Mutterobjekt dar. "|" steht immer fr 
"Ist Mutter von".

In unserem Dialogbaum haben wir also insgesamt 9 Objekte (wenn man 
das Wurzelobjekt nicht mitzhlt). Davon zwei Buttons, mit denen man 
die Dialogbox verlassen kann namens "OK" und "Abbruch", ein 
Eingabefelde fr Text, eine berschrift, ein Text "Dies ist ein 
Text", um den herum eine Box gezeichnet ist und zwei Buttons, die man 
anklicken kann und die sich dann gegenseitig deaktivieren, d.h. wenn 
"laut" selektiert ist, kann nicht "leise" selektiert sein.
Alle Kind-Objekte befinden sich auch grafisch in ihrem Mutterobjekt. 
Die gespeicherten Koordinaten gehen dabei immer vom Mutterobjekt aus, 
wenn also der Text "Dies ist ein Text" die Koordinaten 2|3 hat, heit 
dies nicht, da er ganz links oben im Dialogbaum liegt, sondern da 
der Text von seinem Mutterobjekt "BOX" 2|3 Zeichen oder Pixel 
entfernt liegt.
Diese Baumstrukturmethode hat den groen Vorteil, da man sehr 
schnell ermitteln kann, welches Objekt unter dem Mauszeiger liegt. 

Zu jedem Objekt werden bestimmte Daten gespeichert:
(Strukturen werden hier hnlich wie in C notiert, lediglich Zeiger 
erscheinen zur besseren Lesbarkeit fr den GFA-Programmierer als 
LONG)
(CHARs, BYTES belegen 1 Byte
 WORDs, UWORDs und INTs belegen 2 Bytes
 LONGs belegen 4 Bytes)

WORD   ob_next      nchstes Objekt
WORD   ob_head      erstes Objekt auf gleicher Ebene
WORD   ob_tail      letztes Objekt "  "  "
UWORD  ob_flags     Eigenschaften
UWORD  ob_state     Zustand des Objekts
LONG   ob_spec      Objekt-spezifisches
WORD   ob_x         X-Position relativ zum Mutterobj.
WORD   ob_y         Y-Position "  "  "
WORD   ob_width     Objekt-Breite (OB_W...)
WORD   ob_height    Objekt-Hhe (OB_H(tree_adr%,obj&)

also ist ein Objekt 22 Bytes gro.

In GFA-Basic erreicht man die einzelnen Elemente einer Struktur 
durch den Namen des Elementes, z.B. erhlt man durch

OB_X(tree_adr%,obj_nmr&)

den Wert ob_x. Man bergibt die Adresse des Objektbaumes in 
tree_adr%, die Objektnummer (auch Objekt-Index genannt) in obj_nmr&.

Die Struktur OB_SPEC ist durch einen Zeiger auf sie vertreten. Hier 
werden Daten abgespeichert, die sich von Objekttyp zu Objekttyp 
verndern!

Die Anfangsadresse des ganzen Objektes (wird normalerweise nicht 
bentigt) erhlt man durch OB_ADR(tree_adr%,obj_nmr&).

All diese Elemente knnen ausgelesen oder durch Zuweisung gesetzt 
werden.

Nun zur Beschreibung der Elemente:

ob_next: Nummer des nchsten Objektes auf gleicher Ebene
ob_head: Nummer des ersten Objektes auf gleicher Ebene (von gleichem 
         Mutterobjekt)
ob_tail: Nummer des letzten Kindes auf gleicher Ebene

Diese drei Nummern enthalten -1 (nennt man "NIL" fr Not In List), 
wenn kein Objekt vorhanden ist.


ob_type: Art des Objekts:

Objekte knnen ganz verschieden sein, es gibt mehrere Objekttypen:

20 G_BOX
  Rechteck

21 G_TEXT
  Variabler Grafiktext

22 G_BOXTEXT
  Variabler Grafiktext in einem Rechteck

23 G_IMAGE
  Bitraster-Zeichnung ohne Maske

24 G_PROGDEF
  Fr eigene Routinen, in GFA leider noch unwichtig

25 G_IBOX
  Unsichtbares Rechteck, sollte als Wurzelobjekt verwendet werden

26 G_BUTTON
  Anklickbarer Text in einem Rechteck

27 G_BOXCHAR
  Einzelner Buchstabe, zentriert in einem Rechteck

28 G_STRING
  Grafiktext, auch in Mens

29 G_FTEXT
  Formatierter Grafiktext

30 G_FBOXTEXT
  Formatierter Grafiktext in einem Rechteck

31 G_ICON
  Bitraster-Zeichnung mit Maske und integriertem Text
  Zum Beispiel die Icons auf dem Atari-Desktop sehen so aus!

32 G_TITLE
  Nur fr Mens: Der Mentitel

ob_flags, ob_states:

Jedes Objekt hat

- Flags ( OB_FLAGS(tree_adr%,nmr&) )
- States ( OB_STATE(tree_adr%,nmr&) )

es handelt sich jeweils um Bitvektoren, deren Bits einzelne Bedeutung
haben:

FLAGS:

Bit  Name    Funktion
 0  SELECTABLE    dieses Objekt kann selektiert werden
 1  DEFAULT       dieses Obj wird auch mit RETURN selektiert
 2  EXIT          beim Anklicken dieses Objektes wird form_do
                  beendet!
 3  EDITABLE      Ein Textobj., das editiert werden kann
 4  RBUTTON       Radio-Button
 5  LASTOB        im Moment egal
 6  TOUCHEXIT     sofort beim Anklicken wird from_do beendet
 7  HIDETREE      dieses Objekt und seine Nachkommen sind unsichtbar
 8  INDIRECT      In ob_spec steht ein Zeiger auf ob_spec

STATES:

Bit  Name        Funktion
 0   SELECTED    Obj. ist selektiert und invertiert
 1   CROSSED     Obj. ist angekreuzt
 2   CHECKED     Obj. hat Haken
 3   DISABLED    Obj. ist grau gezeichnet
 4   OUTLINED    Obj. ist umrandet
 5   SHADOWED    Obj. hat Schatten

Die States sollten nur mit

~OBJC_CHANGE(tree_adr%,nmr&,0,x%,y%,w%,h%,neuer_status%,1)

gendert werden. Ist der letzte Parameter 0, wird das Obj
nicht neugezeichnet, ist er 1, wird es erneuert.
==> Bei der Verwendung von FlyDial-Routinen wird die Prozedur 
    "rsc_state" zum ndern der States und die Prozedur "rsc_flags" 
    zum ndern der Objektflags verwendet. Mit den gleichnamigen 
    Funktionen kann man die States und die Flags auslesen.


All diese Einstellungen knnen das Verhalten eines Objektes
verndern. Insbesondere die FLAGS sollte man im RCS schon setzen, die
States mssen im Programm verndert werden, denn nach form_do() sind
in der Regel die Objekte anders selektiert, auch ein OK-Button mu
deselektiert werden, am besten geht das mit:

~OBJC_CHANGE(tree_adr%,ex&,0,x%,y%,w%,h%,0,0)


ob_spec:
  
Abhngig von Objekttyp ist der Wert in OB_SPEC(tree_adr%,nmr&):

Bei Nummer 20 und 27 zeigt er auf eine Struktur namens BOXINFO
bei 21,22,29,30 auf TEDINFO
bei 23 auf BITBLK
bei 26 direkt auf einen CHAR{}-Text

Hiermit lassen sich also Objekte verndern.
Objekte mit Zeiger auf TEDINFO enthalten einen Text. Dieser
Text ist mit

CHAR{{OB_SPEC(tree_adr%,nmr&)}}="Hallo"

zu ndern. Man sollte so vor dem Zeichnen eines Objektbaumes
Edit-Felder vorbelegen. Zu beachten ist aber, da der zu setzende
String auf keinen Fall lnger als der ursprngliche String sein darf!
Deshalb mu man schon im RCS solche Edit-Felder vorbelegen!

hier noch die Strukturen:

BOXINFO:
(direkt in ob_spec enthalten, d.h. ob_spec ist kein Zeiger (auf eine 
Struktur), sondern ein Wert, bei dem die Bits folgende Bedeutungen 
haben:)


Bit 24..31: Darzustellendes Zeichen (fr G_BOXCHAR)
Bit 16..23: 0   Rahmendicke 0 (kein Rahmen)
    1 bis 128: 1 bis 128 Pixel nach innen
    -1 bis -127:1 bis 127 Pixel nach auen
Bit 12..15: Rahmenfarbe (0-15)
Bit 8..11: Textfarbe (0-15)
Bit 7:  Text transparent (0) oder deckend (1)
Bit 4..6: Fllmuster
Bit 0..3: Innenfarbe (0-15) 

---------------------------------------------------------------------

TEDINFO:

LONG *te_ptext      Zeiger auf te_ptext
LONG *te_ptmplt     Zeiger auf te_ptmplt
LONG *te_pvalid     Zeiger auf te_pvalid
WORD te_font        Zeichensatz (normal od. klein)
WORD te_resvd1      reserviert
WORD te_just        Ausrichtung
WORD te_color       Farbe des Rechtecks
WORD te_resvd2      reserviert
WORD te_thickness   Rahmendicke
WORD te_txtlen      Lnge d. Textes
WORD te_tmplen      Lnge d. Textmaske

te_ptext:
diese Zeichenkette ist wie alle Zeichenketten nullterminiert (mit 
ASCII 0 abgeschlossen) und enthlt den Text, der editiert wird. 
Whrend der Vorbereitung sollte te_ptext vernnftig gesetzt werden 
(z.B. auf ""), hinterher kann man die Zeichenkette auslesen. Sie 
enthlt NUR das, was man editieren kann.

te_ptmplt:
hier ist das zu finden, was immer gleichbleibt. An den Stellen, wo 
etwas editiert werden kann (also te_ptext eingesetzt wird), mu man 
den Unterstrich "_" einfgen.

te_pvalid:
Fr jeden Unterstrich in te_ptmplt (also fr jedes Zeichen in 
te_ptext) gibt man ein Zeichen in diesem String an. Damit kann man 
bestimmen, da an einer bestimmten Stelle im Text nur eine Zahl oder 
nur Grobuchstaben eingegeben werden knnen.

Folgende Zeichen sind mglich:

"X":  alle Zeichen erlaubt
"9":  nur Ziffern erlaubt
"A":  nur Grobuchstaben und Leerzeichen
"a":  nur Buchstaben und Leerzeichen
"N":  Grobuchstaben, Ziffern und Leerzeichen
"n":  Buchstaben, Ziffern und Leerzeichen
"F":  alle Zeichen, die ein Dateiname enthalten darf
"P":  alle Zeichen, die ein Pfadname enthalten darf
"p":  wie "P", ohne Wildcards "*" und "?"


te_pfont:
3 normaler Font (8*16-Zeichensatz)
5 kleiner Font (6*6-Zeichensatz) 

te_just:
0   linksbndig
1   rechtsbndig
2   zentriert

te_color:
Bitbeleguung:
12..15: Rahmenfarbe (0..15)
8..11: Textfarbe (0..15)
7:  0 - transparent, 1 - deckend
4..6:  Muster
0..3  Innenfarbe

te_thickness:
0   Rahmendicke 0 (kein Rahmen)
1..128: 1 bis 128 Pixel nach innen
-1..-127: 1 bis 127 Pixel nach auen


Hier ein Beispiel fr Texteditfelder:


te_ptext: "Donnerstag200892"
te_pvalid: "Aaaaaaaaaa999999"
te_ptmplt: "Heute ist __________, der __.__.19__"

ergibt:

"Heute ist Donnerstag, der 20.08.1992"

man kann den Wochentag editieren, wobei der erste Buchstabe 
grogeschrieben sein mu. Auerdem lt sich ein Datum eingeben. Die 
Punkte im Datum mu der Benutzer nicht eingeben, nach dem Tag springt 
der Cursor automatisch zum Monat, nach dem Monat automatisch hinter 
"19".

Wird schon bei der Vorbereitung der te_ptext-String so gesetzt, ist 
das Edit-Feld schon ausgefllt, man kann in der Vorbereitung fr 
te_ptext einen Leerstring einstellen (was sinnvoll ist).

Im RCS sollte man fr te_ptext aber UNBEDINGT soviele Platzhalter 
(zum Beispiel den Unterstrich) einsetzen, sonst berschreibt man bei 
der Vorbereitung wichtige Datenstrukturen!


Im eigenen Programm wird man meistens nur te_ptext setzen und 
auslesen, die anderen Elemente sind in der Regel uninteressant, weil 
man sie schon im RCS setzt.

So setzt man te_ptext:

CHAR{{OB_SPEC(tree_adr%,name&)}}="Donnerstag200892"

tree_adr% enthlt wie gewohnt die Baumadresse (dazu siehe spter 
mehr), name& die Objektnummer.
Durch OB_SPEC() erhlt man einen Zeiger auf die TEDINFO-Struktur. Die 
Klammern {} um den Zeiger bewirken, da man nun das erste Long der 
TEDINFO-Struktur hat. Dieses Long ist ein Zeiger auf te_ptext. Also 
noch ein CHAR{} drumherum (CHAR{} bergibt man einen Zeiger auf einen 
nullterminierten String) und jetzt kann man te_ptext setzten oder 
auslesen:

tag$=CHAR{{OB_SPEC(tree_adr%,name&)}}

---------------------------------------------------------------------

ICONBLK

LONG *ib_pmask      Zeiger auf ICON-Maske
LONG *ib_pdata      Zeiger auf ICON-Daten      
LONG *ib_ptext      Zeiger auf Text
WORD ib_char        Zeichen und Farben d. Icons
WORD ib_xchar       X-Position des Zeichens
WORD ib_ychar       Y-Position "  "
WORD ib_xicon
WORD ib_yicon       Position des Icons im Objekt
WORD ib_wicon       Breite des Icons
WORD ib_hicon       Hhe des Icons
WORD ib_xtext
WORD ib_ytext       Position des Textstrings
WORD ib_wtext       Textbreite in Pixel
WORD ib_htext       Texthhe in Pixel
WORD resvd          reserviert


ib_char:
Bits:
15..12: Vordergrundfarbe d. Icons
11..8: Hintergrundfarbe d. Icons
7..0:  Dieses Zeichen soll im Icon erscheinen

Am Besten, man stellt sich das Icon-Objekt als Mutterobjekt von 3 
weiteren Objekten vor: Einmal das Icon selber, einmal ein einzelnes 
Zeichen und ein beliebiger Textstring.
Nur: Die Objekte im Icon werden nicht als einzelne Objekte 
betrachtet, sondern sind im Objekt (in der ICONBLK-Struktur) 
enthalten! Deshalb sind alle Positionen in der ICONBLK-Struktur 
relativ zum ganzen icon zu verstehen!
Die Breite des "inneren" Icons mu durch 16 teilbar sein.
Die Iconmaske und die Daten werden im Speicher als WORDs dargestellt, 
die Zeilenweise hintereinander abgelegt sind. Man knnte auch einen 
PUT-String ab dem 7. Byte verwenden (die ersten 6 sind Header), der 
eine durch 16 teilbare Breite hat.

Icons erzeugt man am Besten im RCS und lt die Struktur dann ganz in 
Ruhe - ist am einfachsten!

---------------------------------------------------------------------

BITBLK

Nicht selektierbares Icon ohne Maske.

WORD *bi_pdata      Zeiger auf Image
WORD bi_wb;      Breite in Bytes
WORD bi_hl       Hhe in Pixeln
WORD bi_x       X-Position
WORD bi_y       Y-Position
WORD bi_color      Farbe


bi_pdata hat den gleichen Aufbau wie ib_pdata.
ib_wb mu durch 2 teilbar sein.

--------------------------------------------------------------------

USERBLK u. Unterstruktur PARMBLK

Hiermit kann man selbst Objekte erzeugen. In GFA haben diese 
Strukturen wenig Bedeutung, weil man dazu die Adresse einer Funktion 
seines eigenen Programmes bentigt, was im Interpreter gar nicht, im 
Compiler nur halbwegs (Adresse bekommt man durch Trick, Funktion lt 
sich aber nicht verwenden) mglich ist.

---------------------------------------------------------------------
Um einen solchen Objektbaum zu erstellen, bedient man sich eines
Resource-Construktion-Sets. Das von GFA mitgelieferte RCS bietet
diese Mglichkeit. Dazu legt man eine neue Datei an und zieht jetzt
das "Dialog"-Symbol ins Fenster. Dieses wird durch Doppelklick
geffnet. Hier hinein kann man weitere Objekte ziehen. Probiere es
aus, Du wirst schon damit zurechtkommen (mssen).
All diesen Objekten kann man Namen geben, was man tun sollte. Auch
Dialogbume bekommen Namen. Diese Namen werden dann in einer
LST-Datei abgespeichert, die man mit MERGE in das Programm 
einladen sollte. Diese Variablen sollten am Anfang des Programmes 
initialisiert werden. Konkret heit das, da man sich am Ende des 
Programms eine Prozedur anlegt und in diese die LST-Datei einldt. 
Am Anfang des eigenen Programms wird diese Prozedur dann einfah 
aufgerufen. In dieser Datei sind alle Namen als
Variablen-Konstanten definiert, das heit, da man die Objekte unter
deren Nummern bequem mit Namen ansprechen kann. (Jedes Objekt hat 
eine Nummer innerhalb des Dialogbaumes [also der Dialogbox], die man 
zum Ansprechen mit den AES-Funktionen bentigt.) Man sollte die 
Objekte NICHT direkt mit deren Nummern ansprechen, da sich ja 
im Zuge der Programmentwicklung diese Nummern ndern knnen: 
Sobald man ein neues Objekt in einen Objektbaum einfgt, 
verschieben sich alle Nummern.
Deshalb mu man bei nderungen des RSC-Files auch die neuen 
Variablendefinitionen in den Programmtext laden.

Soweit zum allgemeinen Vorgehen, am Besten, Du siehst Dir mal die 
RSC-Dateien von anderen Programmen (warum nicht GFA-GEM ?) an.

      ----------------------

2. Die Programmierung von Dialogen

Zuerst laden wir im Programm die Resource-Datei:

RESERVE -25000
IF RSRC_LOAD("TEST.RSC")=0
 ALERT 3,"Resource konnte nicht geladen werden!",1,"Abbruch",d&
 EDIT
ENDIF

Damit die Funktion gengend Speicherplatz zur Verfgung hat, sollte
man vorher etwas Speicher mit RESERVE freimachen. Ggfs. mu die Zahl
mit einer lngeren Datei erhht werden.
Der Funktion RSRC_LOAD ist ein Parameter zu bergeben, der den
Dateinamen (mit komplettem Pfad) enthlt. Tritt ein Fehler auf, wird
eine Zahl <> 0 zurckgeliefert, worauf entsprechend reagiert werden 
sollte.

Die Funktion RSRC_LOAD ldt ein RSC-File in den Arbeitsspeicher. 
Dabei mssen einige Daten angepat werden, die sich je nach 
verwendeter Bildschirmauflsung ndern, denn im RSC-File selber sind 
diese Daten (es handelt sich um die Positionen der Objekte) 
auflsungsunabhngig gespeichert. Eine geladene Resource lt sich 
mit RSRC_FREE() wieder freigeben, was man bei Programmende unbedingt 
tun sollte!

Man unterteilt die Darstellung einer Dialogbox und deren Bearbeitung 
in "Vorbereitung", "Durchfhrung" und "Nachbereitung".

VORBEREITUNG:

Um eine Dialogbox zu benutzen, mu man zuerst die Adresse des
Objektbaumes ermitteln:

~RSRC_GADDR(0,tree_00&,tree_adr%)

Der erste Parameter sollte 0 sein (es soll nmlich ein Baum ermittelt
werden), dann folgt die Baumnummer und zum Schlu eine Variable, die
nach Funktionsende einen Zeiger auf den Objektbaum enthlt.
Dieser Zeiger ist sehr wichtig, denn er mu bei allen Funktionen, die
mit Objekten zu tun haben, bergeben werden.

~WIND_UPDATE(1)
~WIND_UPDATE(3)

Diese Funktionen teilen dem AES mit, da man nun auf den Bildschirm
schreibt und sorgen dafr, da keine anderen Prozesse (wie
Accessories) auf den Bildschirm schreiben. Vielleicht siehst Du den
Sinn jetzt noch nicht ein: Trotzdem unbedingt verwenden, sonst kann
es groe Probleme bei der Verwendung von Multitaskingsystemen, bei
der sich mehrere Programme den Rechner teilen, geben.

Jetzt mu man die Korrdinaten des Objektbaumes zentrieren, damit
die Dialogbox in der Mitte erscheint:

~FORM_CENTER(tree_adr%,x%,y%,w%,h%)

Diese Routine bernimmt das und gibt dann auch gleich 4 Koordinaten
zurck, die die Position und Gre der Dialogbox enthalten.

Als nchstes reservieren wir einen Bildschirmbereich. Diese Funktion
fhrt im Moment (in den aktuellen GEM-Versionen) nichts aus, kann
aber von Bildschirmbeschleunigern zur Geschwindigkeitssteigerung
benutzt werden.

~FORM_DIAL(0,0,0,0,0,x%,y%,w%,h%)

Der Funktion sind die 4 Koordinaten, die wir vorher ermittelt haben,
zu bergeben. Auerdem kann sie auch noch einen Grafikeffekt
erzeugen, dazu bitte im GFA-Handbuch nachlesen.

Endlich ist es soweit: Wir knnen die Dialogbox auf den Bildschirm
bringen:

~OBJC_DRAW(tree_adr%,0,2,x%,y%,w%,h%)

Diese Funktion bentigt zuerst die Adresse des Objektbaumes, darauf
folgt die Nummer des Objekt-"Astes", man spricht von einem
"Mutterobjekt", das gezeichnet werden soll. Man kann nmlich mit
dieser Funktion auch Teile eines Obejktbaumes zeichnen. Als nchsten
Parameter bergibt man eine Anzahl an Ebenen, die angeben, wie tief
gezeichnet werden soll. Da die Dialogbox nur wenige Ebenen enthlt,
drften 2 ausreichen. Wird spter einmal nicht die ganze Dialogbox
gezeichnet, mu diese Zahl erhht werden!

DURCHFHRUNG:

Jetzt ist die Dialogbox auf dem Bildschirm zu sehen.
Nun mchte man natrlich dem Anwender die Mglichkeit geben, Eingaben
zu machen. Dafr gibt es folgende Funktion:

ex&=FORM_DO(tree_adr%,0)

Ab hier bernimmt das Betriebssystem die Kontrolle, und kehrt erst
wieder zu unserem Programm zurck, wenn der Anwender ein EXIT-Objekt
bettigt hat; dazu spter mehr. Als zweiten Parameter sollte man das
erste editierbare Objekt angeben!
Die Dialogbox kann nur durch (Touch-)Exit-Objekte verlassen werden!
Bei einem Doppelklick wird ein anderer Wert zurckgeliefert, siehe
Listing!

NACHBEREITUNG:

Wir mssen dafr sorgen, da der Bildschirmbereich wieder an der 
Stelle der Dialogbox erscheint:

~FORM_DIAL(3,0,0,0,0,x%,y%,w%,h%)


Wenn Du zum ersten Mal die Dialogbox auf weiem Hintergrund
darstellst, wirst Du feststellen, da diese Funktion eigentlich nur
grau zeichnet. Das ist korrekt, denn wir wollen ja irgendwann korrekt
Fenster anwenden, und das AES geht davon aus, da der Bildschirm grau
ist, denn es existiert ja noch kein Fenster auf dem Bildschirm.

Mchte man den Hintergrund retten, sollte man v_get() und v_put() 
benutzen, die in der VDILIB von Stefan Mnch (erhltlich in Mailboxen 
- nicht Stefan, die Library natrlich) enthalten sind und GET und PUT 
des GFA-Basics ersetzen, denn diese Befehle funktionieren nur begrenzt 
sauber! In der Regel wird man den Hintergrund "Redrawen" lassen, d.h. 
der Screen-Manager (Teil (Prozess) der AES) zeichnet die 
Fensterelemente und den Desktop neu, unser Programm bekommt dann 
automatisch Redrawmessages, welche Teile des Fensters neu gezeichnet 
werden mssen. Dazu einfach FORM_DIAL verwenden.

Jetzt gibt man den Bildschirm wieder fr andere Prozesse frei:

~WIND_UPDATE(0)
~WIND_UPDATE(2)

      ----------------------

Um das ganze mal in echt zu sehen, hier ein kleines Beispiel:

RESERVE -30000
IF RSRC_LOAD("D:\KREMPEL\GFAGEM.RSC")=0
  ALERT 3,"RSC-Datei konnte nicht geladen werden!",1,"Abbruch",d&
  ~INP(2)
  EDIT
ENDIF
'
' resource set indices for GFAGEM
'
LET testdial&=0 ! form/dialog
LET name&=2 ! FTEXT in tree testdial
LET datum&=3 ! STRING in tree testdial
LET riesig&=6 ! BUTTON in tree testdial
LET gross&=7 ! BUTTON in tree testdial
LET mittel&=8 ! BUTTON in tree testdial
LET klein&=9 ! BUTTON in tree testdial
LET mini&=10 ! BUTTON in tree testdial
LET ok&=12 ! BUTTON in tree testdial
LET abbruch&=13 ! BUTTON in tree testdial
LET touchex&=14 ! BUTTON in tree testdial
LET chgtext&=15 ! BOXTEXT in tree testdial
LET links&=16 ! BUTTON in tree testdial
LET rechts&=17 ! BUTTON in tree testdial
LET effekt&=18 ! ICON in tree testdial
'
LET testmenu&=1 ! menu
LET info&=7 ! STRING in tree testmenu
LET quit&=16 ! STRING in tree testmenu
'
wert%=50
'
~RSRC_GADDR(0,testdial&,tree_adr%)                      ! Adresse ermitteln
CHAR{OB_SPEC(tree_adr%,datum&)}=DATE$                   ! Datum setzen
CHAR{{OB_SPEC(tree_adr%,name&)}}="Hier steht mein Name" ! Edit-Feld setzen
CHAR{{OB_SPEC(tree_adr%,chgtext&)}}=STR$(wert%)         ! Wert-Feld setzen
~OBJC_CHANGE(tree_adr%,mittel&,0,x%,y%,w%,h%,1,0)       ! "Mittel" selektieren
~FORM_CENTER(tree_adr%,x%,y%,w%,h%)                     ! Zentrieren
~FORM_DIAL(0,0,0,0,0,x%,y%,w%,h%)                       ! Reservieren
~OBJC_DRAW(tree_adr%,0,2,x%,y%,w%,h%)                   ! Zeichnen
REPEAT
  ex&=FORM_DO(tree_adr%,0)                              ! Bearbeiten
  dklick%=SHR&(ex&,8)
  ex&=SHR&(ROL&(ex&,8),8)
  IF ex&=effekt&
    ~OBJC_OFFSET(tree_adr%,effekt&,xr%,yr%)             ! Koordianten ermitteln
    ~OBJC_OFFSET(tree_adr%,0,xr2%,yr2%)                 ! Fr effekt& und den Dialog

 ~GRAF_GROWBOX(xr%,yr%,OB_W(tree_adr%,effekt&),OB_H(tree_adr%,effekt&),xr2%,yr2%,OB_W(tree_adr%,0),OB_H(tree_adr%,0))

    ~OBJC_CHANGE(tree_adr%,effekt&,0,x%,y%,w%,h%,0,1)   ! Objekt deselektieren
  ENDIF
  IF ex&=touchex&
    IF dklick%
     ' kleine Kadenz spielen
    ELSE
     ' einmal Dur bitte
    ENDIF
    ~OBJC_CHANGE(tree_adr%,touchex&,0,x%,y%,w%,h%,0,1)  ! Objekt deselektieren
  ENDIF
  IF ex&=rechts&
    IF wert%<9999
      IF dklick%
        wert%=9999
      ELSE
        INC wert%
      ENDIF
      CHAR{{OB_SPEC(tree_adr%,chgtext&)}}=STR$(wert%)     ! Wert-Feld setzen
      ~OBJC_DRAW(tree_adr%,chgtext&,1,x%,y%,w%,h%)        ! Zeichnen
      ~OBJC_DRAW(tree_adr%,rechts&,1,x%,y%,w%,h%)         ! leider ntig !
    ELSE
      PRINT CHR$(7);
    ENDIF
    ~OBJC_CHANGE(tree_adr%,rechts&,0,x%,y%,w%,h%,0,1)     ! Objekt deselektieren
  ENDIF
  IF ex&=links&
    IF wert%>0
      IF dklick%
        wert%=0
      ELSE
        DEC wert%
      ENDIF
      CHAR{{OB_SPEC(tree_adr%,chgtext&)}}=STR$(wert%)     ! Wert-Feld setzen
      ~OBJC_DRAW(tree_adr%,chgtext&,1,x%,y%,w%,h%)        ! Zeichnen
      ~OBJC_DRAW(tree_adr%,links&,1,x%,y%,w%,h%)          ! leider
    ~OBJC_CHANGE(tree_adr%,rechts&,0,x%,y%,w%,h%,0,1)     ! Objekt deselektieren
  ENDIF
UNTIL ex&=ok& OR ex&=abbruch&
~FORM_DIAL(3,0,0,0,0,x%,y%,w%,h%)
~OBJC_CHANGE(tree_adr%,ex&,0,x%,y%,w%,h%,0,0)             ! Objekt deselektieren
~RSRC_FREE()

am Ende mu die Datei UNBEDINGT mit RSRC_FREE() freigegeben werden!


=====================================================================

3. D I E   E R E I G N I S V E R W A L T U N G   D E R   A E S 


Ein Programm verbringt die meiste Zeit bekannterweise mit Warten. 
Warten darauf, da etwas passiert - warten auf eine Eingabe des 
Benutzers. Nehmen wir also an, auf dem Bildschirm befinden sich 
einige Fenster, eine Menzeile. Preisfrage: Was wird nun als nchstes 
passieren ? Richtig, der Benutzer mchte einen Menpunkt anklicken. 
Dazu fhrt er die Maus zunchst auf den Mentitel, das Men ffnet 
sich, die Maus fhrt ins Men, und der Benutzer sucht sich einen 
Menpunkt aus. Whrenddessen wird immer der Menpunkt, ber dem sich 
der Mauszeiger befindet, invertiert. All das, was der Computer bis 
jetzt zu tun hatte, waren Darstellungsaufgaben. Diese Dinge 
bernehmen fr uns freundlicherweise die AES. Was liegt also nher, 
als den AES gleich die Kontrolle zu bergeben, die AES warten fr uns 
auf ein Ereignis. Ganz nebenbei geben die AES auch den Accessories 
eine Chance, etwas zu tun.
Unser Programm gibt also ab ans AES. Passiert nun irgendetwas, 
bekommen wir die Kontrolle ber den ST zurck. Auerdem "sagen" uns 
die AES, was passiert ist.
Dies nennen wir "Ereignis".
Zu jedem Ereignis schreiben die AES in einen Speicherbereich eine 
Message (engl. Mitteilung). In der Message steht dann genaueres ber
das stattgefundene Ereignis.

Prinzipiell haben wir schon einen Multitaskingcomputer vor 
uns. Fr das AES sind mehrere Prozesse "gleichzeitig" am Laufen:
- Der "Screen Manager"
- das eigene Programm
- andere Accessories
Diese Prozesse teilen sich ihren ST!

Sie senden sich gegenseitig ber das AES Messages. Wenn das
eigentliche Programm eine Message bekommt, mu es darauf reagieren.

Der Screen Manager ist fr die Darstellung der Fenster (nicht der 
Fensterinhalte!), der Mens und des Desktops zustndig. Klickt der 
Benutzer einen Menpunkt an, ist es der Screen Manager, der uns die 
Mitteilung ber das stattgefundene Ereignis schickt.

Um auf ein Ereignis zu warten, bedient man sich am Besten des 

back=EVNT_MULTI(&X010001,0,0,0,0,0,0,0,0,0,0,0,0,0,0,msg_adr%,0)

Eine Message wird in einem 16 Bytes groen Speicherbereich, der ab
msg_adr% beginnt, gespeichert.

Dieser Speicherbereich enthlt je ein Wort fr

- Nachrichtennummer (Kennung)
- Nummer (ap_id) des Absenders
- Anzahl der noch zu lesenden Bytes (unbenutzt).

Die restlichen Angaben hngen von der Nachrichtenkennung ab.

Um das schn abzufragen, benutzen wir den ABSOLUTE-Befehl, der ja
sowas hnliches wie eine Strukturdefinition erlaubt:

adr_mes%=MALLOC(16) ! 16 Bytes reservieren
'
ABSOLUTE word0&,adr_mes%
ABSOLUTE p&,adr_mes%+6
ABSOLUTE x&,adr_mes%+8
ABSOLUTE y&,adr_mes%+10
ABSOLUTE w&,adr_mes%+12
ABSOLUTE h&,adr_mes%+14

in word0& findet sich die Nachrichtennummer. Die Nummer des Absenders
ist nicht implementiert, da sie meistens ohne Belang ist. Auch die
Anzahl der noch zu lesenden Bytes wird nicht bercksichtigt.
Auf jeden Fall solltest Du nicht den Speicherplatz mit DIM 
"reservieren", denn auch bei DIM (angeblich sogar bei INLINE) kann 
sich der Speicherplatz verschieben, dann stimmt die Adresse nicht 
mehr und ein Absturz ist die Folge: Dieser ist schwierig zu 
diagnostizieren, da er nicht an Ort und Stelle im Programm auftritt 
sondern erst beim nchsten gemeldeten Event, aber auch hier mu der 
Absturz nicht sofort auftreten - vielleicht merkst Du ihn erst durch 
Hinweise anderer User.
Am Ende des Programmes mu der Speicher mit ~MFREE(adr_mes%) 
freigegeben werden. Beim MALLOCen an RESERVE denken!

Es gibt folgende Arten von Ereignissen:

Tastatur-Ereignis:  Der Benutzer hat eine Taste gedrckt
Mausknopf-Ereignis: Der Benutzer hat eine Maustaste gedrckt
                    (oder losgelassen)
Maus-Ereignis:      Der Mauszeiger betritt oder verlt einen recht-
                    eckigen Bereich
Message-Ereignis:   Ein anderer Prozess schickt eine Nachricht.
                    Es kann sich durchaus auch um das Anklicken eines 
                    Menpunktes handeln.
Timer-Ereignis:     Eine bestimmte Zeitspanne ist verstrichen


Man kann auf einzelne Ereignisse oder mehrere Ereignisse gleichzeitig 
warten.

Ein Ereignis sieht so aus:

MN_SELECTED (Kennung=word0&=10)
Ein Eintrag in einem Men ist angeklickt worden: p& enthlt die
Nummer der Mentitels (ganz gut zum Deselektieren) und und x& den
eigentlichen Menpunkt, welcher am wichtigsten ist.

WM_REDRAW (20)
Ein Teil des Fensterinhalts mu neugezeichnet werden.
In p& findet man das Handle des neuzuzeichnenden Fensters
In x,y,w,h die Koordinaten des neuzuzeichnenden Ausschnittes

WM_TOPPED (21)
Ein Fenster wird zum aktuellen Fenster
p& enthlt das Fenster-Handle

WM_CLOSED (22)
Das Schliefeld (CLOSER) eines Fensters wurde bettigt
p& - Fenster-Handle

WM_FULLED (23)
Full-Box rechts oben wurde angeklickt
p& - Fenster-handle

WM_ARROWED (24)
Ein Pfeil oder Bereich zum Scrollen ist angeklickt worden:

p& - Fenster Handle

x&: 0 Seite aufwrts
  1 Seite abwrts
  2 Zeile aufwrts
  3 Zeile abwrts
  4 Seite nach links
  5 Seite nach rechts
  6 Spalte nach links
  7 Spalte nach rechts

WM_HSLID (25)
Der horizontale Schieber (unten am Fenster) wurde bewegt.
p& - Fenster-Handle
x& enthlt einen Wert von 0 bis 1000, der die neue Position angibt.
(Der Schieber mu jetzt vom Programm mittels WIND_SET neu 
positioniert werden)

WM_VSLID (26)
Der vertikale Schieber (rechts am Fenster) wurde bewegt.
p& - Fenster-Handle
x& enthlt einen Wert von 0 bis 1000, der die neue Position angibt.
(Der Schieber mu jetzt vom Programm mittels WIND_SET neu 
positioniert werden)

WM_SIZED (27)
Die Gre eines Fensters wurde verndert
p& - Fenster-Handle
x&,y&,w&,h& - neue Auenmae
(das Fenster mu jetzt vom Programm mittels WIND_SET neu positioniert 
werden)

WM_MOVED (28)
Ein Fenster wurde verschoben
p& - Fenster-Handle
x&,y&,w&,h& - neue Auenmae

AC_OPEN  (40)
Eigenes ACC aktiviert - Menpunkt des eigenen ACCs angeklickt

AC_CLOSE (41)
Eigenes ACC-Fenster wurde geschlossen


Alle anderen Ereignisse sind zu ignorieren.

====================================================================

4.  M E N  s


Ein paar Worte mchte ich noch zu deren Gestaltung beitragen, denn 
viele Leute bauen ihre Mens derart SCHEUSSLICH zusammen, da das 
ganze Programm hlich wirkt. Dabei gibt es doch einen schnen 
Standard!
Alle Mentitel haben links und rechts EIN Leerzeichen. Ganz links
befindet sich ein Info-Men, welches als Titel den Programmnamen in
Grossschrift enthlt. Nicht DESK, denn so darf sich nur das
GEM-Desktop nennen! In diesem Men findet man als obersten Eintrag
etwas wie "Info...", bei Anklicken erhlt man eine Information ber
das laufende Programm. Die Zeilen darunter sind mit einer Trennlinie
und 6 Eintrgen fr ACCs zu fllen, die Verwaltung dieser Eintrge
bernimmt das AES. Im 2. Men - das " File " heien sollte, findet
man als untersten Eintrag auf jeden Fall einen Menpunkt zum
Verlassen des Programms. Dort und nirgendwoanders gehrt er hin!
Weiter oben sollten Eintrge wie "ffnen" oder "speichern" stehen. Da
wren wir bei den Menpunkten: Jeder Menpunkt hat links GENAU ZWEI
Leerezeichen, um Platz fr Checkmarks (Hckchen) zu lassen, aber auch
wenn keine Checkmarks dasind, gehren zwei Leerezeichen neben jeden
Menpunkt. Ein Tastaturkrzel steht immer rechts ausgerichtet im
Men, so da alle Tastaturkrzel in einer Spalte stehen. Links des
Tastaturkrzels ist ein Leerzeichen bis zum Mentitel, die Menbreite
richtet sich nach dem lngsten Eintrag, zwischen diesem und dem Rand
ist genau ein Zeichen frei.
Ein Mentitel, der einen Dialog zur Folge hat, hat drei Punkte "..."
am Ende. Als Trennzeichen werden "-" verwendet, und zwar soviele, da
der Menpunkt voll angefllt ist. Hier knnen auch durchgehende 
Linien verwendet werden, nur sind die nicht ganz so einfach zu 
realisieren. 

Soweit zur Gestaltung.

Eine Menzeile ist prinzipiell nichts anderes als ein Objektbaum, der
lediglich von den Objekten her ein festgelegteres Aussehen hat und
etwas anderes vom AES behandelt wird. Auch bei ihm mssen wir zuerst
mit RSRC_GADDR() die Adresse feststellen. Jetzt kann er ohne groe
Vorarbeit mit

~MENU_BAR(menu_adr%,1)

gezeichnet werden. Der zweite Parameter ist 0, wenn die Menzeile
gelscht werden soll - dies darf man am Ende des Programms NICHT
VERGESSEN!!

Bitte verwende NICHT die Befehle, die GFA-Basic schon fr Mens
anbietet. Sie sind unter Umstnden unsauber und lassen sich nicht so
gut beeinflussen.

Jetzt mchte man dem Benutzer natrlich Gelegenheit zur Benutzung
unserer schnen Menleiste geben. Und sptestens hier wird ein Wort
zum Thema "AES-Message-Handling" ntig.
Denn um die Menzeile "anzubieten", rufen wir

back=EVNT_MULTI(&X010001,0,0,0,0,0,0,0,0,0,0,0,0,0,0,msg_adr%,0)

auf.

Ich kann leider nicht alle Parameter aufzhlen, sieh bitte dazu in
der Dokumentation zu GFA-Basic, im Profibuch oder in der
Litzkendorf-Bibel nach.

 Fangen wir mal mit dem Bitvektor - dem ersten Parameter - an:

Bit Bedeutung
 0  Tastatur-Ereignis
 1  Mausknopf-Ereignis
 2  Maus-Ereignis Box 1
 3  Maus-Ereignis Box 2
 4  Event-Puffer-Ereignis
 5  Timer-Ereignis

EVNT_MULTI wartet darauf, da etwas passiert. Auf welche Art von
Ereignis kann man im ersten Bitvektor einstellen. Da wir im Moment
nur ein "Event-Puffer-Ereignis" bentigen, welches dann eintritt,
wenn ein Menpunkt angeklickt wird, sind auch nur die Bits 4 und 0
gesetzt.
Da EVNT_MULTI auf mehrere Ereignisse gleichzeitig warten kann, wird
in back das tatschlich stattgefundene Ereignis zurckgeliefert. Auch
dies ist ein Bitvektor, der genauso belegt ist, wie auch der erste
Parameter. Zu beachten ist, da auch mehrere Ereignisse gleichzeitig
eintreten knnen!
Nach dem EVNT_MULTI-Aufruf kann man nun das Ereignis auswerten. Und
jetzt wird's Zeit fr ein Beispielprogramm:


REM Resource Datei Indizes fr GFAGEM 
LET TESTDIAL&=0 ! Formular/Dialog
LET DATUM&=2 ! STRING in Baum TESTDIAL 
LET LINKS&=3 ! BUTTON in Baum TESTDIAL 
LET CHGTEXT&=4 ! BOXTEXT in Baum TESTDIAL 
LET RECHTS&=5 ! BUTTON in Baum TESTDIAL 
LET NAME&=6 ! FTEXT in Baum TESTDIAL 
LET RIESIG&=10 ! BUTTON in Baum TESTDIAL 
LET GROSS&=11 ! BUTTON in Baum TESTDIAL 
LET MITTEL&=12 ! BUTTON in Baum TESTDIAL 
LET KLEIN&=13 ! BUTTON in Baum TESTDIAL 
LET MINI&=14 ! BUTTON in Baum TESTDIAL 
LET BUTTON&=16 ! BUTTON in Baum TESTDIAL 
LET EFFEKT&=18 ! ICON in Baum TESTDIAL 
LET TOUCHEX&=19 ! BUTTON in Baum TESTDIAL 
LET ABBRUCH&=20 ! BUTTON in Baum TESTDIAL 
LET OK&=21 ! BUTTON in Baum TESTDIAL 
'
LET TESTMENU&=1 ! Menuebaum
LET INFO&=7 ! STRING in Baum TESTMENU 
LET OEFFNEN&=16 ! STRING in Baum TESTMENU 
LET SCHLIESS&=17 ! STRING in Baum TESTMENU 
LET QUIT&=19 ! STRING in Baum TESTMENU 
'
'
$m50000
RESERVE 50000				! Im Kompilat raus!!!
CHDRIVE "D"				! Im Kompilat raus!!!
CHDIR "D:\KREMPEL\"			! Im Kompilat raus!!!
IF RSRC_LOAD("GFAGEM.RSC")=0
  EDIT
ENDIF
'
~RSRC_GADDR(0,testmenu&,menu_adr%)
~MENU_BAR(menu_adr%,1)
'
DIM message_buffer%(3)  ! 16 Byte
adr_mes%=V:message_buffer%(0)
'
ABSOLUTE word0&,adr_mes%
ABSOLUTE p&,adr_mes%+6
ABSOLUTE x&,adr_mes%+8
ABSOLUTE y&,adr_mes%+10
ABSOLUTE w&,adr_mes%+12
ABSOLUTE h&,adr_mes%+14
'
PRINT AT(1,3);				 ! Nur zu Demozwecken,
'					   darf in GEM-Programmen 
'	    	                           nicht verwendet werden!
'
DO
  back=EVNT_MULTI(&X10001,0,0,0,0,0,0,0,0,0,0,0,0,0,adr_mes%,0)
  IF BTST(back,0)
    taste%=PEEK(GINTOUT+11)
    taste$=CHR$(taste%)
    scan%=PEEK(GINTOUT+12)
    '
    SELECT taste%
    CASE 0
      SELECT scan%
      ENDSELECT
    CASE 15
      sel_titel(menuf&)
      menu_sel(oeffnen&)
    CASE 19
      sel_titel(menuf&)
      menu_sel(schliess&)
    CASE 17
      sel_titel(menuf&)
      menu_sel(quit&)
    ENDSELECT
    '
  ENDIF
  IF BTST(back,4)         
    SELECT word0&
    CASE 10          ! MN_SELECTED
      menu_sel(x&)
    ENDSELECT
  ENDIF
LOOP
PROCEDURE sel_titel(z&)
  ~MENU_TNORMAL(menu_adr%,z&,0)       ! Mentitel invertieren
  p&=z&
RETURN
PROCEDURE menu_sel(z&)
  SELECT z&
  CASE info&
    PRINT "INFORMATION"               ! Dies sind blo Platzhalter!
  CASE oeffnen&
    PRINT "OEFFNEN"
  CASE Schliess&
    PRINT "SCHLIESSEN"
  CASE Quit&
    EDIT
  ENDSELECT
  '
  ~MENU_TNORMAL(Menu_adr%,P&,1)       ! Mentitel normal darstellen
RETURN

Dieses Programm benutzt brigens die gleiche Resource.

Mit etwas Nachdenken kann man erkennen, da menu_sel() entweder von 
einem Tastaturereignis oder von einem Menpunkt-anklick-
ereignis herrhrt. Vor der Ausfhrung eines Menpunktes 
sollte dieser invertiert werden, um dem Benutzer eine gewisse 
Rckmeldung ("Feedback") zu geben. AES tut dies dann, wenn 
ein Menpunkt angeklickt worden ist, wenn aber eine Taste 
gedrckt wird und damit die selbe Funktion wie nach dem 
Anklicken eines Menpunktes ausgefhrt wird, sollte der 
dazugehrige Mentitel invertiert werden. Das gibt dem Benutzer 
das Gefhl, die richtige Taste gedrckt zu haben.
Um das Setzen von Flags zu ermglichen, zeigt man gesetzte Flags
durch ein Hkchen an, was mit MENU_ICHECK() geht. Lt die aktuelle
Situation ein Anklicken eines Menpunktes nicht zu (z.B. "sichern"
wenn nichts zum sichern da ist), mu es vom Programm "disabled", also
grau dargestellt werden. Die geschieht mit MENU_IENABLE(). Ist die
Funktion wieder mglich, mu sie wieder normal dargestellt werden.
Das ndern von Mentexten ist mit MENU_TEXT() mglich, bei mir hat's
allerdings leider nicht funktioniert, weshalb ich die Texte (zum
Beispiel wird "ffnen" zu "hinzuladen", wenn schon ein Text editiert
wird) mit CHAR{OB_SPEC(menu_adr%,menupunkt&)}="..." ndere, was auch
gut funktioniert.
Sinnvoll ist brigens auch eine Auswertung des Tastendrucks nach dem 
Men-Text: In der Resource schreibt man ja sowieso die 
Tastenkombionation ans Ende jedes Menpunkts. Diese kann abgefragt 
und umgerechnet werden, so kann man die Kombinationen einfach ndern.

---------------------------------------------------------------------

5.  F E N S T E R

Fenster sind nicht absolut einfach, aber die einzige korrekte
Mglichkeit des Programms, Ausgaben zu machen. Darstellung in
Dialogboxen ist insofern schlecht, da dadurch der Multitasking-
betrieb unterbrochen wird.
Die Fensterverwaltung geschieht - in der Regel zusammen mit dem Men
- in einer Schleife, in der auf Events (Ereignisse) gewartet wird.

Zuallererst ermitteln wir die Gre des verfgbaren Bildschirmes:

~WIND_GET(0,5,max.x&,max.y&,max.w&,max.h&)

hiermit erhlt man die Koordinaten des verfgbaren Bereiches. Hierbei 
wird die Menzeile ausgelassen. Dies ist wichtig, da ja Fenster nicht 
in die Menzeile reinreichen drfen. Man sollte NICHT davon ausgehen, 
da die Menzeile immer 20 Pixel hoch ist! Dies kann sich in einer 
spteren AES-Version ndern!

Zuallererst mssen wir ein Fenster erzeugen:

handle&=WIND_CREATE(&X101111,max.x&,max.y&,max.w&,max.h&)

Dieser Funktion sind neben einem Bit-Vektor die Koordinaten der
maximal Mglichen Ausdehnung zu bergeben. Sie scheinen wohl keine
Auswirkung zu haben (???). Der Bit-Vektor sieht so aus:


Bit Bedeutung

 0 Name (Titelzeile)
 1 Close-Feld links oben (wenn Bit gesetzt: vorhanden)
 2 Full-Feld rechts oben
 3 Move-Balken oben (Balken mit hellem Muster und Titel)
 4 Info-Zeile unter dem Move-Balken
 5 Size-Feld rechts unten
 6 UPARROW (Aufwrtspfeil)
 7 DNARROW (Abwrtspfeil)
 8 VSLIDE-Balken rechts (Position z.B. im Text, Vertikalschieber)
 9 LFARROW (Linkspfeil)
10 RTARROW (Rechtspfeil)
11 HSLIDE-Balken unten (Horizontalschieber)

Jenachdem, ob die betreffenden Bits gesetzt sind, sind dann Elemente
im Fenster vorhanden und knnen angesprochen werden bzw. liefern
Events bei Benutzung.

Zurck bekommt man einen Wert handle&, mit dem das Fenster zuknftig
angesprochen werden kann. Ist er kleiner als 0, ist ein Fehler
aufgetreten, d.h. man sollte die Aktion abbrechen!!!
In der Regel ist dann kein weiteres Fenster frei. Normalerweise kann
man nmlich nur eine begrenzte Anzahl Fenster ffnen, mit
Erweiterungsprogrammen ("Winx") lassen sich aber sehr viel mehr
Fenster ffnen, weshalb die Fenster nicht gezhlt und dann ggfs.
abgebrochen werden sollte, sondern auf einen negativen handle&-Wert
reagiert werden sollte!

Jetzt sollte man erstmal Speicher zur Aufnahme der Titel u.
Info-Strings reservieren. Dies ist ntig, da sich GEM nicht die
Strings sondern die Adressen der Strings merkt. Leider bleiben aber
die Strings nicht immer an gleicher Stelle im Speicher (Garbage
Collection) und so knnen die Zeiger auf Speicher-Mll zeigen. Dies
hat oft zur Folge, da GEM brutal abstrzt, wenn die Strings lnger
als 80 Zeichen lang sind. Auch INLINEs bleiben von der
Speicherverschiebung nicht verschont, weshalb wir mit MALLOC Speicher
allozieren mssen. Man sollte - es sind ja nur ein paar Bytes - auf
jeden Fall den maximal mglichen Platz auf EINMAL freimachen. Damit
verhindert man eine Zerstckelung des Speichers in viele kleine
Teilbereiche, was keinem Betriebssystem guttut.
Also reservieren wir fr ein Fenster 162 Bytes Speicherplatz (2*81
Bytes, 80 Bytes maximale Breite, je ein 0-Byte am Ende), fr mehrere
Fenster sollte man am Anfang des Programms alles auf einmal
reservieren - entsprechend mehr:

stringbereich%=MALLOC(162)
titelbereich%=stringsbereich%
infobereich%=stringbereich%+81

nun bestimmen wir die Titelzeile:

CHAR{titelbereich%}="Window-Titelzeile"
~WIND_SET(handle&,2,CARD(SWAP(titelbereich%)),CARD(titelbereich%),0,0)

Diese etwas eigenartige bergabeweise liegt darin begrndet, da das
AES nur 16-Bit-Parameter annimmt, und Zeiger (Speicheradressen)
haben nunmal 32 (beim ST eigentlich 24) Bits.
Um die Infozeile zu bestimmen, verfhrt man entsprechend, man mu die
Variablen ndern und statt 2 3 bergeben.

Nun stellen wir das Fenster auf dem Bildschirm dar:

~WIND_OPEN(handle&,100,100,200,100)

bergeben werden die Koordinaten der Ausmae (X,Y,Breite,Hhe), die
das Fenster annehmen soll. Man liest sie am Besten aus der vom
Programm anzulegenden INF-Datei aus, die der Benutzer mit einer
Menfunktion wie "Arbeit sichern" oder besser "Einstellungen
speichern" in eine INF-Datei schreiben lassen kann.
Ansonsten schlage ich Maximalgre vor, sofern keine anderen Fenster
vorhanden sind.

~WIND_GET(handle&,4,wx&,wy&,ww&,wh&)

liefert uns nun die tatschlichen Koordinaten des Fensters, und zwar
jetzt nicht die Koordinaten des gesamten Fensters samt
Fensterelementen, sondern die des "Arbeitsbereiches", in den man auch
wirklich hineinschreiben/malen/ausgeben darf. Man sollte NIE von
einer festen Gre der Elemente ausgehen, sondern die Koordinaten mit
WIND_GET holen, weil sich ATARI vorbehlt, die Elemente zu ndern.

DEFFILL 1,0
GRAPHMODE 1
PBOX wx&,wy&,wx&+ww&,wy&+wh&

lscht den Arbeitsbereich.

nun kann's losgehen, und wir geben das Fenster zur Benutzung frei:

REPEAT

  ~EVNT_MULTI(&X110000,0,0,0,0,0,0,0,0,0,0,0,0,0,adr_mes%,100,d%,d%,d%,d%,d%,d%)
  SELECT word0&
  CASE 22        ! WM_CLOSED
    raus!=TRUE ! Fenster wurde geschlossen
  CASE 23        ! WM_FULLED
    ~WIND_SET(handle&,5,1,19,638,380) ! Maximalgre setzen
    ~WIND_GET(handle&,4,wx&,wy&,ww&,wh&) ! Arbeitsbereich erfragen
    PBOX wx&,wy&,wx&+ww&,wy&+wh&   ! " lschen
    word0&=0
  CASE 27,28       ! WM_SIZED, WM_MOVED
    IF w&<100
      w&=100
    ENDIF
    IF h&<80
      h&=80
    ENDIF
    ~WIND_SET(handle&,5,x&,y&,w&,h&)
    ~WIND_GET(handle&,4,wx&,wy&,ww&,wh&)
    PBOX wx&,wy&,wx&+ww&,wy&+wh&
    word0&=0
  ENDSELECT
UNTIL raus!
~WIND_CLOSE(handle&)  ! Fenster vom Bildschirm lschen
~WIND_DELETE(handle&)  ! Fenster aus dem Speicher lschen

hier wird prinzipiell nur auf Events gewartet (siehe
Menleistenbenutzung) und dann entsprechend verzweigt. Die Ereignisse
entnimmst Du bitte Deiner Dokumentation und dem Beispielprogramm.

Nochwas zum Thema RECHTECKLISTE (Redraws):

Die AES verwalten fr jedes Fenster eine "Rechteckliste". Hier sind 
mehrere Rechtecke mit Koordinaten definiert, die alle sichtbaren 
Ausschnitte eines Fensters definieren. Manchmal ist ja nur ein Teil 
des Fensters zu sehen, dann, wenn ein anderes Fenster darberliegt. 
Dies mu man beim Neuzeichnen eines Fensters unbedingt beachten !
Auch beim Redraw (dem teilweisen neuzeichnen eines Fensters) ist dies 
wichtig !

Hier eine REDRAW-Prozedur:

PROCEDURE redraw
  LOCAL wn&
  FOR wn&=0 TO max_window&
    IF p&=handle&(wn&)
      rechteckliste(p&,x&,y&,w&,h&)
      redraw!(wn&)=FALSE
    ENDIF
  NEXT wn&
RETURN
PROCEDURE rechteckliste(wind&,xprev&,yprev&,wprev&,hprev&)
  '
  '     Abarbeiten der Rechteckliste eines Fensters beim Redraw
  '
  '
  LOCAL xredr&,yredr&,wredr&,hredr&
  '
  ~WIND_UPDATE(1)
  '
  '
  ~WIND_GET(wind&,11,xredr&,yredr&,wredr&,hredr&)
  WHILE wredr& OR hredr&
    IF RC_INTERSECT(xprev&,yprev&,wprev&,hprev&,xredr&,yredr&,wredr&,hredr&)
      @vs_clip(1,xredr&,yredr&,xredr&+wredr&-1,yredr&+hredr&-1)
      upd
      @vs_clip(0,xredr&,yredr&,xredr&+wredr&-1,yredr&+hredr&-1)
    ENDIF
    ~WIND_GET(wind&,12,xredr&,yredr&,wredr&,hredr&)
  WEND
  '
  ~WIND_UPDATE(0)
  '
RETURN
Die Prozedur upd mu jeweils einen Fensterneuaufbau fr betreffende 
Fenster vornehmen, wobei immer das ganze Fenster neugezeichnet werden 
mu. Dabei drfen keine Line-A-Routinen verwendet werden, da diese 1. 
nur fr alte Auflsungen (ST-Low,Mid,High) und nicht fr die TT-
Auflsungen dokumentiert sind und 2. sie das VDI-Clipping, welches 
zum Redraw benutzt wird, nicht untersttzen. Auerdem darf man 
natrlich NICHT direkt auf den Bildschirmspeicher zugreifen, weil man 
nicht wei, in welcher Form dieser vorliegt (man kann nicht davon 
ausgehen, da wie in ST-High jedes Pixel einem Bit entspricht.

---------------------------------------------------------------------

6. D E R   E I G E N E   D E S K T O P 

Der Desktop ist grundstzlich der graue (grne bzw. farblich beim TT 
frei definierbare) Hintergrund, ber dem sich GEM-Fenster befinden. 
Auerdem kann man auf Desktops (wie dem GEM-Desktop) Icons und 
hnliches (Boxen wie in 1st Word Plus) finden. Dieser Desktop mu 
beim AES auch wie ein Fenster angemeldet werden. Wird unser Programm 
gestartet, befindet sich grundstzlich schon ein Desktop auf dem 
Bildschirm. Dies kann ein grauer Standard-Desktop sein, kann aber 
auch der GEM-Desktop in Multitaskingsystemen sein. Unser Programm 
darf also nicht davon ausgehen, da irgendetwas bestimmtes hier zu 
finden ist. [Im GFA-Interpreter ist er hlich wei, aber da kann man 
zum Beispiel in der Entwicklungszeit im Interpreter (und nur da!) 
ein FORM_DIAL(3) fr den gesamten Bildschirm aufrufen, was den 
Hintergrund grau macht). Mchte der Programmierer nun eigene Icons 
auf dem Desktop darstellen oder auch anderes ablegen lassen knnen, 
mu man sich einen eigenen Desktop installieren. Es gibt aber Grnde, 
die gegen einen solchen sprechen: 1. Man wei nicht, welche Farbe 
bzw. welches Muster der Standarddesktop hat und kann dies auch nicht 
auf legale Weise erfahren. In TOS-Versionen ab 2.x kann man nmlich 
die Farbe verndern. Dies hat eine Umstellung fr den Anwender zur 
Folge. 2. Verdeckt ein eigener Desktop den GEM-Desktop in 
Multitaskingsystemen, was ebenfalls sehr unschn ist. Ist der Desktop 
im eigenen Programm immer noch so wichtig, kann man so vorgehen:

- man kreiere sich eine Baumstruktur im RCS, die grau ist und am 
einfachsten alle Standard-Icons beinhaltet. Die Baumstruktur mu 
keine anderen Objekte haben (wie zum Beispiel einen Exit-Button).
- man ermittle im Programm die Adresse des Objektbaumes (RSRC_GADDR) 
und verndere die Gre des Mutterobjektes so, da sie der des alten 
entspricht. Die alte Gre ermittelt man mit WIND_GET.
- jetzt bergibt man sie (nein, nicht sich!) an WIND_SET.
- der neue Desktop ist jetzt installiert und mu nur noch gezeichnet 
werden, was das AES bernimmt (also FORM_DIAL fr die Desktopgre).

Der Desktop wird grundstzlich wie Fenster 0 verwaltet, weshalb man 
auch WIND_GET und WIND_SET verwalten kann. Auerdem werden alle 
Redraws vom Screen-Manager automatisch vorgenommen, d.h. es kommen 
keine WM_REDRAW-Nachrichten fr den Desktop. ABER: Der Desktop hat 
auch eine Rechteckliste! Diese mu man beachten, wenn man etwas 
daran (wie die Anzeige der Uhrzeit) verndern will. Dann mu man wie 
beim Redraw fr ein Fenster vorgehen, ober kein Clipping verwenden, 
sondern einfach die Schnittflche aus Redraw-Bereich (also 
errechneter Objekt-Bereich und sichtbarer Ausschnitt des Desktops, zu 
ermitteln mit RC_INTERSECT) an OBJC_DRAW bergeben. OBJC_DRAW 
zeichnet dann nur noch diesen Teil neu!

Vor Programmende mu

~WIND_SET(0,14,0,0,0,0)

aufgerufen werden, um den alten Desktop wiederherzustellen.

Und hier das Beispielprogramm:

PROCEDURE desktop_init
 IF INT{{GB+4}+2}=1     ! Single-Task-System ?
 ~RSRC_GADDR(0,desktop&,desk_adr%)
 '
 ~WIND_GET(0,5,max.x&,max.y&,max.w&,max.h&)
 OB_X(desk_adr%,0)=max.x&   ! Gren anpassen
 OB_Y(desk_adr%,0)=max.y&
 OB_W(desk_adr%,0)=max.w&
 OB_H(desk_adr%,0)=max.h&
 '
 ~WIND_SET(0,14,CARD(SWAP(desk_adr%)),CARD(desk_adr%),0,0)
 '
 ~WIND_GET(0,4,x%,y%,w%,h%)
 '
 ~FORM_DIAL(3,0,0,0,0,x%,y%,w%,h%)
 ELSE
 desk_adr%=0
 ENDIF
 ~WIND_GET(0,4,max.x&,max.y&,max.w&,max.h&)
RETURN

=====================================================================
7. Thema GDOS-Fonts

GDOS ist ein Aufsatz auf VDI, mit dem bestimmte aus Platzgrnden 
nicht mehr eingbaute Funktionen fr die Verwendung von verschiedenen 
Fonts nachgereicht werden. GDOS gibt es in verschiedenen Versionen 
und wird meist im Autoordner installiert.

Zuerst sollte man mit GDOS? testen, ob GDOS vorhanden ist. Wenn ja,
kann man mit

font_anz%=VST_LOAD_FONTS(0)

die Zeichenstze laden. Zurckgeliefert wird die Anzahl der geladenen
Zeichenstze. Diese mssen wir zu der Anzahl der bereits geladenen
Zeichenstze addieren:

ADD font_anz%,WORK_OUT(10)

Nun ist es interessant, die vorhandenen Zeichensatzgren zu
erfragen:

face%=VQT_NAME(fontnr%,font$)
DEFTEXT ,,,,face%
fontgr%=-1     ! ***
FOR h&=99 DOWNTO 1
 ogr%=fontgr%
 gr%=@vst_point(V~H,h&,w1&,h1&,w2&,h2&)
 IF ogr%<>gr%
 fontgr%=gr%
 ENDIF
NEXT h&
fontgr%=gr%

in fontnr% sollte die Fontnummer eingetragen sein. Diese Routine 
ermittelt die kleinste Fonthhe kleiner gleich 99 (auch wenn GDOS-
Fonts bis zu 999 Punkt gro werden knnen).
Mchte man die jeweils kleineren Fonts ermitteln, mu man die mit ***
markierte Zeile weglassen.
Die Routine beruht darauf, da vst_point die jeweils kleinere
Fontgre zurckliefert. Da eine Fontgre vorhanden ist, erkennt
man daran, da vst_point die gleiche Fonthhe zurckliefert, wie ihr
bergeben wurde.

brigens: Fonts werden prinzipiell auch skaliert, das heit, das die
Fonts zustzlich auch verdoppelt werden. Also ist ein 10-Pkt-Font
auch als 20-Pkt-Font in doppelter Hhe zu finden. ABER: Der jeweils
doppelt so groe Font ist als Rasterfont VERGROESSERT worden, was ein
hliches Schriftbild zur Folge hat!
Kommt der Benutzung der Fonts eine grere Bedeutung im Programm zu,
sollte man vorher mit obiger Routine testen, ob ein frei skalierbarer
Font vorliegt. Dies ist dann der Fall, wenn alle Fontgren von 1
bis 999 vorhanden sind. Dann sollte man dem Benutzer per
Edit-Feld die Mglichkeit geben, die Gre direkt einzugeben. Ist
der Font nur in festen Fontgren vorhanden, sollten die Fontgren
auswhlbar sein. [Empfehlung d. Profibuchs]

Hier also vst_point:
Die Routine kann auch Fonthhen setzen (Hauptzweck!).

FUNCTION vst_point(handle&,h&,VAR a&,b&,c&,d&)
 '
 INTIN(0)=h&     !gewnschte Pointhhe
 CONTRL(6)=handle&    !Gertehandle (meist V~H)
 '
 VDISYS 107,1,0    !VDI-Aufruf
 a&=PTSOUT(0)     !Zeichenbreite
 b&=PTSOUT(1)     !Zeichenhhe
 c&=PTSOUT(2)     !Zellenbreite
 d&=PTSOUT(3)     !Zellenhhe
 '
 RETURN INTOUT(0)    !gesetzte Hhe
ENDFUNC

=====================================================================

8. Vermischtes

Thema Textausgabe.

- Auf keinen Fall PRINT benutzen, denn PRINT benutzt das BIOS,
 dabei sollte man immer hhere Betriebssystemschichten benutzen (VDI
 wre eine solche). PRINT beachtet auerdem das CLIPPING nicht.
 PRINT benutzt auerdem keine GDOS-Fonts, weshalb es einem solchen
 Programm verwehrt bleiben wrde, diese anzubieten.
 PRINT ist zwar schnell, aber v_gtext() optimiert auch!!!

- v_gtext() benutzen. Texte immer an Byteposition ausgeben (also auf
 8 Pixel horizontal positionieren, was man auch schon bei der
 Fensterposition machen kann!). Auerdem ist die Ausgabe im
 Kompilat sehr viel schneller, da die Stringbergabe schneller
 erfolgt!
 Wenn das eigene Programm es erlaubt, sollte man an die v_gtext-Prozedur
 nur einen Zeiger auf den Text im Speicher bergeben bzw. eine globale
 Variable definieren, denn eine Stringbergabe als Parameter an eine 
 Prozedur/Funktion ist sehr langsam.

Hier die Routine zur Benutzung von v_gtext(), weil diese Funktion
leider nicht in GFA-Basic implementiert ist:

PROCEDURE v_gtext(x&,y&,string$)
  LOCAL i&,l&,adr%
  l&=MIN(LEN(string$),126)
  IF l&>0
    adr%=V:string$
    FOR i&=0 TO l&-1
      INTIN(i&)=BYTE{adr%+i&}
    NEXT i&
    PTSIN(0)=x&
    PTSIN(1)=y&
    CONTRL(0)=8
    CONTRL(1)=1
    CONTRL(3)=l&
    CONTRL(6)=V~H
    VDISYS
 ENDIF
RETURN

- Oftmals besteht das Problem von zuvielen unntigen Redraws. Hier 
sollte man sich nicht darauf verlassen, da die AES bestimmte Redraws 
bei bestimmten Aktionen senden. Probleme bereitet insbesondere das 
Auslsen von Redraws. Oftmals wird ja mit einem Menpunkt der 
Fensterinhalt verndert. Also: form_dial(3,...,wx&,wy&,ww&,wh...) ist 
unschn, weil damit auch andere, darberliegende Fenster ge-redrawt 
werden und auerdem Doppel-Redraws auftreten knnen. Mit APPL_WRITE 
kann man sich auch selber eine Redraw-Aufforderung schicken. Aber 
auch hier treten Doppel-Redraws bald auf.
Meine Lsung hilft:

PROCEDURE merke_redraw(window&)
  IF window&<>-1
    redraw!(window&)=TRUE
  ENDIF
RETURN

Am Anfang mu natrlich redraw!() initialisiert werden. In der Event-
Schleife fragt man jetzt nach dem Abfragen und Auswerten des Events 
(dies knnte ja schon ein Redraw sein) diese Variablen ab. Ist eine 
TRUE, wird ein Redraw fr das Fenster ausgelst, d.h. das Fenster neu 
gezeichnet, natrlich unter Beachtung der Rechteckliste.
Bei jedem Redraw mu die Variable redraw!() auf FALSE gesetzt werden.

- Der Befehl FILESELECT ist unschn, weil er den Hintergrund selber 
restauriert, aber gleichzeitig natrlich eine Redraw-Aufforderung an 
die Applikation (also unser Programm) geschickt wird. Auerdem wird 
Speicherplatz fr den Bildschirmspeicher bentigt.
Also verwendet man folgendes, stammt von Michael Heng (danke!) :

PROCEDURE fileselect(fs_title$,fs_path$,fs_default$,VAR fs_name$)
  '
  ~WIND_UPDATE(1)
  ~FRE(0)        ! Alles, nur keine Garbage-
  '          ! Collection ...
  '
  fs_title$=fs_title$+CHR$(0)   ! Plus String-Limiter
  fs_path$=fs_path$+STRING$(64,0)  ! Die sind ntig, weil dem AES
  fs_default$=fs_default$+STRING$(13,0) ! nur die Adressen der Strings
  '          ! bergeben werden und die nach
  '          ! FSEL_INPUT ja auch lnger sein
  '          ! knnen
  GCONTRL(1)=0       ! AES-Arrays initialisieren
  GCONTRL(2)=2       ! (kennst Du ein Wort mit mehr
  GCONTRL(4)=0       ! "i"s ?)
  ADDRIN(0)=V:fs_path$
  ADDRIN(1)=V:fs_default$
  '
  IF DPEEK(LPEEK(&H4F2)+2)>=&H104  ! TOS-Version ab 1.04 ?
    GCONTRL(3)=3       ! Ja, FSEL_EXINPUT nehmen
    ADDRIN(2)=V:fs_title$     ! und Titel bergeben
    GEMSYS 91
  ELSE
    GCONTRL(3)=2       ! Nein, FSEL_INPUT nehmen
    GEMSYS 90
  ENDIF
  '
  IF GINTOUT(1)=0      ! Abbruch ?
    fs_name$=""       ! Ja, wir wollen doch GFA-
    '          ! kompatibel bleiben ...
  ELSE
    fs_path$=CHAR{V:fs_path$}    ! klingt zwar unlogisch, aber
    fs_default$=CHAR{V:fs_default$}  ! man denke an die Lngen !!!
    '          ! und an die String-Limiter.
    '
    fs_name$=LEFT$(fs_path$,RINSTR(fs_path$,"\"))+fs_default$
    '          ! Rckgabe aus Pfad und Namen
    '          ! zusammensetzen.
  ENDIF
  ~WIND_UPDATE(0)
RETURN


- RESERVE
Problematisches Thema. RESERVE macht beim TT Probleme. Deshalb frage 
ich bei Programmbeginn ab, ob's ein TT ist (siehe VDILIB) und fhre 
dann nur ein einziges RESERVE aus, das den Speicher freigibt. Das 
Problem ist ja, da man den Basic-Speicherbereich begrenzen mu. 
Standardmig wird ja der ganze Speicher reserviert, was andere 
Programme unter Multitaskingsystemen (also auch ACCs) gar nicht mgen 
- ihnen bleibt ja dann kein Speicher mehr frei. Also mu man Speicher 
freigeben. Am einfachsten einen vom User zu definierenden Wert. Oder 
auch alles bis auf die Menge an Platz, die das Programm fr sich und 
seine Variablen (wenn sich das vorher bestimmen lt) bentigt. 
Sinnvoll ist dann, immer wenn ein Speicherbereich ge-MALLOC-t wird, 
entsprechend Speicher freizugeben und die Menge zu einer Variablen 
speicher% zu addieren. So kann jederzeit RESERVE -speicher% 
durchgefhrt werden, um Speicher freizumachen oder wiederzubekommen. 
Wenn man Speicher freigibt (Reihenfolge mu wie Reservieren sein!), 
ist der Wert natrlich von speicher% zu subtrahieren.
Liegt kein TT vor, kann man das machen, haben wir einen TT, mu man 
allen Speicher, den das Programm je MALLOC-t, am Anfang einmal 
freigeben. Danach alle RESERVE-Aufrufe in IF st!....ENDIF klammern.

- WIND_UPDATE sollte unbedingt sofort dann verwendet werden, wenn die 
Menleiste und die Fensterknpfe gesperrt werden sollen, erstrecht 
dann, wenn eine Dialogbox auf den Bildschirm gebracht werden soll.
Dazu bitte den Text W_UPDATE beachten!

--------------------------------------------------------------------
--------------------------------------------------------------------

(C) Copyright 1994 David Reitter
Alle Rechte vorbehalten. Keine kommerzielle Verwendung 
(Verffentlichung). Verwendung von PD-Vertrieben nur bei Preisen bis 
DM 10.- fr eine Diskette erlaubt. Kopieren des Textes im Original- 
zustand erlaubt - jede Vernderung verboten.
Eine Sondererlaubnis zur Distribution dieses Textes wird
Columbus Soft zum Vertrieb zusammen mit den FlyDials eingerumt.

Ich hafte nicht fr Richtigkeit und Schden. Warenzeichen werden 
ohne Kennzeichnung genannt.

Dem Text liegt ein Beispielprogramm GFAGEM.GFA, eine Beispielresource 
GFAGEM.RSC, die dazugehrigen HRD-Definitionen GFAGEM.HRD und
ein Text von Uwe Ohse (ber wind_update) bei. Ich danke den 
Autoren fr die freundliche Genehmigung.

Fr Hinweise, weitere Texte und Fehlermeldungen bin ich sehr dankbar.
Wenn Du Probleme mit der Programmierung von GEM hast, wende Dich 
ruhig an mich (oder schreib eine ffentliche Msg ins Mausnet - aber 
nur, wenns kein grundstzliches Problem ist).

Am einfachsten per E-Mail:

David_Reitter@WI2.maus.de (Internet ==> Mausnet)
KGB05.1375David R.   (STarNet)

Meine Adresse fr Anfragen und Sachspenden:

David Reitter
Albinistr. 10
55116 Mainz
Tel.: 06131-233255

Meine Kontonummer fr Geldspenden:

Konto 0229773
  BLZ 550 700 40
      Deutsche Bank Mainz


------------------
Referenzen

Interface
TEAM Computer
Klettenberggrtel 5
50939 Kln
Tel.: 0221-466774

ATARI-Profibuch  ST-STE-TT
ISBN 3-88745-888-5
DM 79.-

Das groe GFA-Basic 3.5 Buch
ISBN 3-89011-363-X
DM 59.-
