          ====================================
               RUBY -- Yet Another Gem
          Copyright (c) 1992 by Markus M. Nick
          ====================================


1. Einleitung
-------------

Es ist soweit.  Ruby ist fertig.  Fr die, die noch nicht wissen, was Ruby 
ist, hier ein kurzer šberblick ber die Features:

- Ruby setzt Resource-Format der My/Fly/MagicDials fr Let 'em Fly! um, 
d.h. die Dialoge fliegen ber Let 'em Fly! und die Checkboxes etc. stammen 
direkt von Ruby.
  * Spezielle Object-Typen:
    + Checkboxes, runde Radiobuttons
    + tastaturbedienbare Buttons (ber Let 'em Fly!)
    + unterstrichener Text
    + Circle-Button fr Popups
    + Undo-Button, Help-Button
    + Eselsohr (Flugecke)
- Ruby beinhaltet Funktionen fr ein „užerst simples Popup-Handling.
- Ruby ist zus„tzlich noch erweiterbar, d.h. Sie k”nnen selbst zus„tzliche 
Objekttypen definieren u.„.

"Nicht schlecht sprach der Specht, aber WAS soll das?" werden Sie nun 
vielleicht fragen.  Nun --- wer in seinen Programmen Let 'em Fly! 
untersttzen bzw. nutzen m”chte, erh„lt mit Ruby eben noch runde 
Radiobuttons etc. Der Vorteil ist, daž der Overhead fr das Fliegen, die 
Keydials usw. nur einmal im System liegt --- n„mlich bei Let 'em Fly!. 
 Wenn nun Oliver Scheel sein Let 'em Fly! verbessert (z.B. den Extended 
Editor), dann ntzt das allen Programmen, die Let 'em Fly! nutzen ohne den 
Umweg ber ein zus„tzliches Update.

L„žt man ein Programm, das mittels Ruby Let 'em Fly! nutzt, ohne Let 'em 
Fly! laufen, dann k”nnen die Dialoge eben nicht fliegen und sind nicht 
tastaturbedienbar (Shortcuts fr Buttons fallen weg). Wer also auf den 
Komfort des Fliegens und der erweiterten Tastaturbedienung verzichten 
will, weil er vielleicht noch 25 KByte mehr Speicher ben”tigt, muž er 
trotzdem nicht auf das gewohnte Erscheinungsbild des Programms 
verzichten.

Manche halten mehr von Programmen, die diese Features fest eingebaut haben 
(GEMINI, Rufus, Interface).  Allerdings --- jedes Programm, das z.B. 
Tastaturbedienung und einen Extended Editor fest eingebaut hat, 
unterscheidet sich in der Bedienung der Edit-Felder und anderen Dingen 
sicherlich von Programmen, die eine andere Library verwenden.

Im Sinne einer Vereinheitlichung ist das Ausnutzen der Features von Let 'em 
Fly! auf jeden Fall die bessere L”sung.  Der Overhead durch Ruby betr„gt 
lediglich 5 KByte pro Programm. 

Ruby ist als Library fr Let 'em Fly! gedacht. Am besten sieht man Let 'em 
Fly! als Betriebssystemerweiterung und Ruby als komfortable Library dazu, 
wobei es auch ohne Let 'em Fly! l„uft --- nur eben mit weniger Komfort.

Da es sowohl Ruby als auch Let 'em Fly! als Freeware gibt und Ruby auch 
fr kommerzielle Software verwendet werden darf, sehen Oliver Scheel und 
ich keine Grnde, diese Kombination aufzugeben. Die Grnde dafr sind 
mehr philosophisch zu sehen (wie oben aufgefhrt).  Jeder ist herzlich 
dazu eingeladen, dieser Philosophie in seiner Software zu folgen.

Viel Spaž und wenig Probleme mit Ruby wnscht Ihnen
 
     Markus M. Nick



2. Lizenzbedingungen
--------------------

 Ruby ist Freeware. Sie drfen Ruby frei kopieren und weitergeben. Der 
 Verkauf von Ruby oder der Vertrieb ber PD-Versender ist ohne die 
schriftliche Genehmigung des Authors nicht gestattet. Die Verbreitung ber 
Mailboxen und BBSe ist gestattet, wenn fr den Download keine gesonderte 
Gebhr erhoben wird. Zuwiderhandlungen werde ich strafrechtlich verfolgen!

Fr von Ruby abgeleitete Derivate gilt das gleiche.

Ruby muž immer komplett weitergegeben werden.  In der Datei READ_ME finden 
Sie eine Liste aller Dateien, die zu Ruby geh”ren.

Unter den folgenden Bedingungen k”nnen Sie Ruby in Ihre Software einbinden:
- Im Programm und in der Dokumentation zum Programm muž darauf hingewiesen 
  werden, daž Ruby verwendet wurde.
- Es muž darauf hingewiesen werden, daž weder Ruby noch dessen Autor fr 
  das Layout der Dialoge des Programms verantwortlich ist (Entbindung von 
  dieser Pflicht auf Anfrage). 


2.1 Verwendung von Ruby in kostenpflichtiger Software
-----------------------------------------------------

Wenn Sie Ruby in Software verwenden m”chten, die Geld einspielen soll, d.h. 
kommerzielle Produkte, aber auch Shareware und Freeware, fr die Geld 
verlangt wird, ist die Verwendung von Ruby beim Autor anzuzeigen 
(Brief/Postkarte oder E-Mail mit Adresse und Telefonnummer und kurzem 
Produktinfo gengt).

Weitere Bedingungen sind daran nicht geknpft.  šber eine angemessene 
Spende und/oder die Zusendung der Software selbst wrde ich mich sehr 
freuen.  Ggf. kann ich Ihnen auch eine Rechnung ber den gespendeten Betrag 
ausstellen.

Wenn Ihnen durch Ruby Probleme entstehen, lassen Sie es mich wissen. 

    Postanschrift:                 Bankverbindung:
    Markus M. Nick                 Sparda-Bank Mainz e.G.
    Hinter der Kirche 20           BLZ 550 905 00
    W-6500 Mainz 41                Konto-Nr. 604 581
    55129 Mainz-Ebersheim   (neue PLZ ab 1.7.93)
    Germany                     

    Telefon:                       E-Mail:
    (Germany)--6136--45647         Markus_Nick @ MZ \quad  (im Mausnet) 
    (NIE vor 11 Uhr)               Markus_Nick@mz.maus.de  (im Internet)

Wenn Sie keinen Servicevertrag (siehe unten) abgeschlossen haben, legen Sie 
bei Anfragen aller Art bitte immer einen frankierten und adressierten 
Rckumschlag bei (ggf. auch eine Diskette).  Ich bitte um Verst„ndnis, daž 
ich nicht auch noch die Portokosten tragen kann, da Ruby ja Freeware ist -- 
in gewissem Sinne auch "Free Software".


2.2 Source, Service und Updates
-------------------------------

Sind Sie am Source, an automatischen Updates, Benachrichtigung bei Updates 
und/oder Serviceleistungen interessiert, dann wenden Sie sich bitte an mich. 
 Gegen eine Gebhr o.„. ist auch dies m”glich.

Um die Konsistenz der verfgbaren Versionen von Ruby zu gew„hrleisten, 
m”chte ich den Source nicht v”llig freigeben.  Sollte ich jedoch eines 
Tages das System wechseln, also alle meine STs verkaufen oder verschrotten 
[...], wird der Source zuvor freigegeben werden.

Sollten Sie einen Compiler besitzen, der keines der bereitgestellten 
Object-Files lesen kann, dann kontaktieren Sie mich bitte. Ich bin 
sicher, daž wir einen Weg finden werden.


2.3 Dementi
-----------

Da Ruby frei ist, gibt es keine Haftung jeglicher Art fr Ruby.  Ruby wird 
so geliefert, wie es ist, ohne jede Haftung, weder implizite oder 
explizite, einschliežlich, ohne Einsch„nkung, der Haftung fr die 
Zweckm„žigkeit und Verwendungstchtigkeit fr einen bestimmten Zweck.  Das 
gesamte Risko bzgl. Quali„t und Performance von Ruby liegt bei Ihnen, 
verehrter Anwender.  Sollte Ruby M„ngel irgendeiner Art aufweisen, so 
tragen Sie die alle n”tigen Kosten fr Service, Reparaturen und 
Korrekturen.

Sie k”nnen den Autor in keinem Fall fr irgendwelche Sch„den zur 
Verantwortung ziehen, weder im allgemeinen noch im speziellen oder 
zuf„lligen Fall, oder bei Folgesch„den oder solchen die aus der 
Untchtigkeit von Ruby fr einen bestimmten Zweck oder in 
Zusammenarbeit mit anderer Software entstehen -- selbst dann nicht, wenn 
Sie vom Autor oder anderen Personen darauf hingewiesen wurden.

Kurzum, jede Verantwortung fr die Verwendung und Anwendung von Ruby 
liegt bei Ihnen, lieber User.

Mit "Ruby" ist die komplette Distribution gemeint, die in der Datei 
READ_ME aufgelistet ist, d.h. alle Sourcen, Header, Objekt-Dateien, 
Libraries sowie die Dokumentation und die speziellen Hinweis-Texte.

Anmerkung: Bei Servicevertr„gen lauten die Bedingungen etwas anders.  Der 
Autor tr„gt in diesem Fall die Kosten fr den Updateservice von Ruby.



3. Verwendung von Ruby
----------------------

Um Ruby zu verwenden, sollten Sie den Header ruby.h includen.

Ich empfehle Ihnen, eine Kopie des Beispielprogramms anzulegen und mit 
dieser zun„chst ein wenig zu experimentieren.  Schauen Sie sich auch den 
Source an.  Er zeigt, wie man ganz einfach mit Popup-Mens umgehen kann.


3.1 Zus„tzliche Objekttypen
---------------------------

Alle zus„tzlichen Objekttypen werden ber das Highbyte des Elements ob_type 
der Struktur OBJECT eingestellt. In Resource-Construction-Sets kann man 
diese ber Felder mit Namen wie "erweiterer Objekttyp" einstellen.

Folgende erweiterte Objekttypen sind verfgbar:

  17 - XG_FLYBUTTON: 
           Kennzeichnet ein Objekt mit exklusiven "Flugrechten". Maximal 
           ein Objekt pro Formular kann ein XG_FLYBUTTON sein.

           Ist das Objekt vom Typ G_IBOX und als OUTLINED und SHADOWED 
           gekennzeichnet, wird es durch ein Eselsohr ersetzt.
  18 - XG_BUTTON:
           Der besondere Edelstein in Ruby. Hierunter verstecken sich 
           gleich drei Typen von Kn”pfen:
    Runder Radiobutton:
           Hierbei handelt es sich um die mittlerweile auch auf dem ST/TT 
           recht verbreiteten runden Radiobuttons, die man ja vom Macintosh 
           her kennt. Man kreiert dazu -- wie blich -- einen Radiobutton 
           (SELECTABLE und RBUTTON) kennzeichnet ihn dann mit dem 
           Xob_type 18.
    Ankreuzfeld:
           Das Ankreuzfeld ist ebenfalls schon recht verbreitet.  Man legt 
           einfach einen normalen Button an und kennzeichnet ihn als 
           SELECTABLE und mit dem Xob_type 18.
    Keybutton:
           Das ist ein Exit-Button mit oder ohne Shortcut.  Man legt 
           einfach den Button an und kennzeichnet ihn mit SELECTABLE, EXIT 
           und dem Xob_type 18.  Setzt man zus„tzlich ob_flags #11 
           (ob_flags |= 0x0800), so wird dadurch der Default-Abbruch-Button 
           gekennzeichnen, der auch mit der Taste [Undo] selektiert werden 
           kann.

           Diese Kn”pfe k”nnen mit den konventionellen Objekt-Typen 
           G_BUTTON, G_STRING, G_TEXT und G_BOXTEXT verknpft werden. 
           Beachten Sie bitte, daž die Kn”pfe alle zumindest entweder 
           SELECTABLE oder TOUCHEXIT sein mssen.

           Um einen Button mit einem Shortcut zu belegen, setzt man 
           einfach vor den gewnschten Buchstaben im Button-Text ein '['. 
           Zum Beispiel 
                          T[oll
           bewirkt, daž die Kombination [Alt][O] den Button selektiert 
           (und deselektiert).
  21 - XG_HELPBUT:
           entspricht XG_BUTTON, wobei der Knopf exklusiv mit der Taste 
           [Help] belegt wird.
  31 - XG_UNDOBUT:
           entspricht XG_BUTTON, wobei der Knopf exklusiv mit der Taste 
           [Undo] belegt wird.
  19 - _XG_TITLE:
           Unterstrichener Text. Der Text wird auf der Breite der 
           umrandenden Box unterstrichen.
  20 - XG_BOXTITLE:
           Box mit Titeltext, der auf dem Rahmen steht.
  22 - XG_POPUP:
           Circle-Button fr Popups.

Soweit keine Einschr„nkungen angegeben sind, k”nnen die neuen Objekttypen 
nach Belieben mit den konventionellen (G_BOX, G_BUTTON, G_TEXT usw.) 
verknpft werden.

Bedeutung             Xob_type             ob_flags      ob_state
Eselsohr              17 - XG_FLYBUTTON   TOUCHEXIT    CROSSED|OUTLINED
Exklusives Flugobjekt 17 - XG_FLYBUTTON   TOUCHEXIT
EXIT-Keybutton        18 - XG_BUTTON      EXIT|SELECTABLE
TOUCHEXIT-Keybutton   18 - XG_BUTTON      TOUCHEXIT
Runder Radiobutton    18 - XG_BUTTON      RBUTTON|SELECTABLE
Ankreuzfeld           18 - XG_BUTTON      SELECTABLE
Circlebutton          22 - XG_POPUP
Box mit Titel         20 - XG_BOXTITLE
Unterstrichener Text  19 - XG_TITLE


3.2 Initialisierung der Dialoge im Programm
-------------------------------------------

Da die zus„tzlichen Objekttypen sozusagen kodiert im Resource abgelegt 
werden, ist eine Initialisierung der Dialoge n”tig.  Diese Initialisierung 
sollte nur Dialog nur einmal erfolgen.  Es gibt dabei zwei M”glichkeiten:

 - Komplette Initialisierung einer geladenen Resource mit der Funktion 
   rsrc_ruby().  Das erledigt man am besten direkt nach dem Laden der 
   Resource.  Beispiel:

    /* Resource laden */
    if (!rsrc_load("STUFF.RSC")) {
        /* nicht gefunden => und Tschž... */
        ...;
    }

    /* und Dialoge initialisieren */
    if (!rsrc_ruby()) {
        /* irgendwas ist mit der Resource faul...
           derzeit bedeutet das, daž der Pointer 
           auf die Resource 0 ist */
        ...;
    }

   rsrc_ruby() entnimmt die Adresse der Resource aus global[7..8], die auf 
   den Resourceheader zeigt und holt sich von dort die Anzahl der B„ume in 
   der Resource.  Mit einer Iteration ber die Indices wird mittels 
   rsrc_gaddr(...) jeweils die Baumadresse festgestellt und ruby(...) fr 
   diesen Baum aufgerufen.

 - Einzelne Initialisierung jedes Baumes mit ruby(tree), wobei tree vom Typ 
   OBJECT* ist.  Das ist z.B. dann n”tig, wenn die Resource direkt ins 
   Programm eingebunden wird und diese keinen Header hat.

Statt einzelner Aufrufe, kann man auch analog zu rsrc_ruby() mit einer 
Iteration ber die Baumindices alle B„ume in einer for-Schleife 
initialisieren.

Beispiel:

    /* - NUM_TREE ist die Anzahl der B„ume
       - rs_trindex[] enth„lt die Adressen der B„ume
       Bei Verwendung einer `.RSH'-Datei des DRI/Atari-
       RCS 2.x kann man das folgende Programmstck 
       direkt verwenden 

       WICHTIG: Die Resource muž bereits initialisiert 
       -------- sein, d.h. die Pointer mssen bereits 
                gesetzt sein. */
    int tidx;
    for (tidx = 0; tidx < NUM_TREE; tidx++) {
        OBJECT *tree = (OBJECT*)rs_trindex[tidx];
        ruby(tree);
    }


3.3 Spezielle Optionen von Ruby
-------------------------------

Die Variable ruby_options enth„lt ein paar Informationen ber Ruby und 
gestattet einige Einstellungen.  Derzeit sieht die Defintion der Struktur 
wie folgt aus:

/* ==== ruby options ==== */

struct RUBY_OPTIONS {
    char *version;
    int btn_10pt_idx;    /* 0/2: 10pt or 11pt check box 
                                 or radio button */
    char (*m_alloc)(size_t);  /* Ruby alloziert ber diese 
                                 Funktion Speicher */
};

extern struct RUBY_OPTIONS ruby_options;

- Das Element version enth„lt eine Versionsinfo.  Das Format ist derzeit 
undefiniert.  Die Version zeigt auch lediglich das Vorhandensein von 
neueren Funktionen oder Objekttypen an.  Eigentlich ist die Info unwichtig, 
da Sie ja beim Linken bestimmen, was Sie genau linken...

- btn_10pt_idx erm”glicht die Auswahl aus zwei verschiedenen H”hen fr 
Checkboxes und Radio-Buttons.  Hierbei steht 0 fr 10pt und 2 fr 11pt.  Am 
besten probieren Sie es selbst aus.  Die 10pt-Icons sind auf jeden Fall 
dann geeigneter, wenn mehrere Checkboxes untereinander stehen, da diese 
sich bei 11pt berhren.  Diese Einstellung wird global vorgenommen, um 
zumindest bei den Buttons ein einheitliches Erscheinungsbild des Ruby 
nutzenden Programms zu gew„hrleisten.

- Ruby wandelt intern fast alle speziellen Objekttypen in G_USERDEF-Objekte 
um.  Dabei ist die Anforderung von Speicher mittels erforderlich, um die 
RUBY_USERDEF-Objekte anzulegen (siehe unten).  Zur Allokation von Speicher 
ruft Ruby daher immer (*ruby_options.m_alloc)(the_size) zur Allokation von 
Speicher auf.  Der Parameter the_size ist dabei vom Typ size_t. 
 ruby_options.m_alloc ist mit der Standardbibliotheksfunktion 
malloc vorbesetzt.  Sie k”nnen jedoch diesen Wert durch Zuweisung 
berschreiben, bevor irgendeine Funktion von Ruby aufgerufen wird.

Beispiel:
    /* Das eigene "malloc()" muž sich wie das Vorbild 
       aus der Standardbibliothek verhalten, d.h. ist 
       der Speicher voll, muž 0 geliefert werden, sofern 
       zum Aufruf zurckgesprungen wird (wird das 
       Programm beim Speicherberlauf direkt terminiert, 
       kann das entfallen...) */
    void *my_malloc(size_t);
    ...
    /* Ruby soll die programmeigene Speicherverwaltung 
       verwenden */
    ruby_options.m_alloc = my_malloc;

Derzeit wird nur bei der Initialisierung der Dialoge durch Ruby Speicher 
alloziert.  

Erh„lt Ruby von (*ruby_options.m_alloc)(...) einen Null-Pointer 
als Resultat, so wird die Funktion (*ruby_no_mem) mit der Adresse 
des Baumes und dem Index im Baum aufgerufen, bei dem der Speicherberlauf 
aufgetreten ist.  Per default ist ruby_no_mem 0.  Dabei wird dann 
lediglich die Initialisierung beendet, d.h. die Funktion ruby(...) 
terminiert.

/* ==== other globals ==== */

/* ruby_no_mem() wird aufgerufen, wenn kein Speicher 
    mehr fr die RUBY_USERBLKs zur Verfgung steht.
    Voraussetzung: ruby_no_mem ist != 0 */
extern void (*ruby_no_mem)(OBJECT *tree, int obj);


3.4 Popup-Mens
---------------

Ruby verfgt auch ber zwei Funktionen fr Popup-Mens.  Die eine 
(pop_it_up()) erleichtert die Arbeit mit dem Popup-Mens und die andere 
(ruby_popup()) beinhaltet das Popup selbst.  Das Popup kann brigens 
nicht nur in Dialogen verwendet werden, sondern auch an anderen Stellen.

Das Popup kann komplett mit der Tastatur bedient werden (Cursortasten und 
[Return] oder [Space]).  Dies teilen Sie pop_it_up() mit dem Parameter 
key_call mit.  Zum Aufruf per Tastatur sollte das zum Popup geh”rende 
Infofeld als XG_BUTTON mit TOUCHEXIT gekennzeichnet werden und diesem die 
Tastenkombination zugeordnet werden.  Im Beispielprogramm sehen Sie das. 
 So k”nnen durch Prfen des Rckgabewertes von form_do() feststellen, ob 
der Aufruf per Tastatur erfolgte (Rckgabe ist Infofeld) oder per Mausklick 
(Rckgabe ist Popup-Button).

Zurerst zur Funktion pop_it_up().  Wenn Ihnen deren Funktionalit„t 
ausreicht, mssen Sie sich im Normalfall gar nicht mit ruby_popup() 
"abgeben".  Die Parameterliste ist recht umfangreich und gestattet allerlei 
Einstellungen.  Im folgenden erst mal der Funktionskopf mit den 
Kurzbeschreibungen der Parameter:

enum POP_ACTION { pop_next,         // zum n„chsten Eintrag
                  pop_prev,         // zum vorhergehenden Eintrag
                  pop_choose };     // Auswahl im Popup selbst

int release_time = 10;  /* Zeit in ms, die auf das Loslassen der Maustaste 
                            vor dem eigentlichen Popup gewartet wird */

BOOLEAN pop_it_up(tree, btn, info, 
                  pop, popbox,
                  action, wrap_around, active_state, redraw_button,
                  ev_mbmask, ev_mbstate,
                  key_call,
                  mitem, lastkey, bgr_saved)
OBJECT *tree; // I: Dialog-OBJECT-Baum, der den Button `btn' enth„lt
int btn;      // I: Button, der den Text des ausgew„hlen Popupeintrags enth„lt
int info;     /* I: Baum-Index des Infotextes links vom Button `btn' (wird 
                      w„hrend des Popups invertiert dargestellt, wenn >= 0) */
OBJECT *pop;  // I: Baum, der das Popup enth„lt
int popbox;   // I: Index des Popups selbst (normalerweise 0)
enum POP_ACTION action; // I: was zu tun ist (siehe enum POP_ACTION)
BOOLEAN wrap_around;    // I: TRUE: automatischer Wrap-Around (ntzlich fr 
                               Circle-Buttons)
int active_state;       // I: spezieller Status, mit dem der aktive 
                               Popupeintrag gekennzeichnet wird 
                               (meist CHECKED oder 0)
BOOLEAN redraw_button;  /* I: TRUE: automatischer Button-`btn'-Redraw
                               (nur bei gleichem Objekttyp im Popup und 
                                im Button `btn') */
int ev_mbmask;       /* I: die Maustasten, die beachtet werden sollen 
                            (fr evnt_multi()) */
int ev_mbstate;      /* I: der Status, der zum Beenden des Popups gefordert 
                            wird (given to evnt_multi()) */
BOOLEAN key_call;    // I: TRUE: Aufruf via Taste,  FALSE: via Mausklick
int *mitem;          // I/O: der aktive/selektierte Popupeintrag
int *lastkey;        // O: Code der Taste, die zum Verlassen fhrte
BOOLEAN *bgr_saved;  // O: TRUE: Hintergrund konnte gesichert werden
/*
    RETURN  TRUE        Auswahl vorgenommen
            FALSE       Auswahl abgebrochen
*/

Wenn action == pop_choose gilt, wird das Popup angezeigt.  Links vom 
Popup sollte sich auf gleicher H”he eine Beschreibung (Object info) 
befinden, die von pop_it_up() w„hrend der Auswahl aus dem Popupmen 
selektiert dargestellt wird (nach den Human Interface Guidelines).  Im 
Beispielprogramm ist das deutlich zu sehen.

Das Popup wird mit dem vorselektierte Popupeintrag (*mitem, wenn $\ge 
0$) automatisch auf den Popup-Button btn ausgerichtet, soweit es die 
Ausmaže des Popup und die Position des Popup-Buttons zulassen.

Wird der Circle-Button angeklickt, so sollte mit action == pop_next und 
wrap_around == TRUE gearbeitet werden.  Dies bewirkt, daž vom letzten 
Eintrag automatisch zu ersten gesprungen wird.

button_redraw == TRUE veranlažt, daž der Popup-Button btn, der 
den ausgew„hlten Popupeintrag enth„lt automatisch aktualisiert und neu 
gezeichnet wird.  Dies ist nur m”glich, wenn alle Popupeintr„ge und der 
Popup-Button vom gleichen oder „hnlichen Objekttyp sind, d.h. ob_spec 
auf die gleiche Struktur zeigt.  Die Ursache dafr liegt darin, daž hierbei 
einfach das ob_spec vom Popupeintrag in den Popup-Button btn 
kopiert wird.

Mit ev_mbmask kann man z.B. eine Auswahl mit der rechten Maustaste 
bewirken.  In diesem Fall muž ev_mbmask == 2 sein (Bit 1 gesetzt).  Fr 
die linke Maustaste muž ev_mbmask == 1 gelten (Bit 0 gesetzt -- wie 
beim AES).  Der Wert wird direkt ber ruby_popup() an 
evnt_multi() weitergegeben.

ev_mbstate enth„lt den Maustastenstatus, der zum Beenden der Auswahl im 
Popup anliegen muž.  Es gilt die gleiche Belegung wie bei ev_mbmask, 
d.h. Bit 0 fr die linke und Bit 1 fr die rechte Maustaste.

Eine Besonderheit:  pop_it_up() wartet release_time 
Millisekunden auf das Loslassen der in ev_mbmask angegebenen 
Maustasten.  Sind diese Tasten dann noch gedrckt, so erfolgt die Selektion im 
Popupmen durch das Loslassen der Maustaste, andernfalls durch das Drcken der 
Taste (testen Sie es einmal mal im Beispielprogramm).  release_time ist 
auf 10 ms voreingestellt.

*mitem enth„lt immer den Object-Index des zuletzt ausgew„hlen 
Popupeintrags.  D.h. wird die Auswahl abgebrochen, so ist *mitem 
unver„ndert.  Ist *mitem nach der Rckkehr -1, so konnte kein Eintrag 
ausgew„hlt werden (pop_next und alle Eintr„ge sind disabled).

Wenn der Speicher nicht ausreicht, kann der Hintergrund nicht gesichert 
werden.  Das wird mit *bgr_saved == FALSE angezeigt.  In diesem Fall 
muž die Applikation den vom Popup berdeckten Teil des Dialogs neu zeichnen. 
 Da die Funktion ruby_popup() in einem solchen Fall automatisch 
form_dial(FMD_FINISH,...) aufruft, erh„lt man eine entsprechende 
WM_REDRAW-Message vom AES.

Bemerkung:  ruby_popup() verwendet Malloc() und Mfree() 
fr die Speicherallokation und -freigabe.

Damit auch unter MultiGEM und in Accessories das Popup richtig funktioniert, 
ruft pop_it_up() wind_update(BEG_MCTRL) und 
wind_update(END_MCTRL) auf.  Wenn Sie stattdessen ruby_popup() 
verwenden, mssen Sie sich selbst darum kmmern.

typedef BOOLEAN (*MITEM_SEL)(OBJECT *pop, 
                    BOOLEAN *mo_choose, 
                    int sel_mitem,  /* aktueller Eintrag im aufrufenden 
                                        Popup `pop' */
                    int *mitem, int *lastkey);

BOOLEAN ruby_popup(pop, pop_box, 
                    px, py, ev_mbmask, ev_mbstate,
                    presel_1st, item_sel, tit_rect, 
                    mo_choose,
                    mitem, lastkey, bgr_saved)
OBJECT *pop;        // I: Baum, der das Popup enth„lt
int pop_box;        // I: Index des Popups selbst (normalerweise 0)
int px, py;
int ev_mbmask;      /* I: die Maustasten, die beachtet werden sollen 
                           (fr evnt_multi()) */
int ev_mbstate;     /* I: der Status, der zum Beenden des Popups gefordert 
                           wird (given to evnt_multi()) */
BOOLEAN presel_1st; // I: TRUE: 1. Eintrag vorselektieren
MITEM_SEL item_sel; // I: Funktion, die aufgerufen wird, wenn ein Eintrag 
                            selektiert wird
GRECT *tit_rect;    // I: wird dieser Bereich "betreten", so wird die Funktion 
                            terminiert (wenn != 0)
BOOLEAN *mo_choose; // I: TRUE: Mausauswahl, FALSE: Auswahl mit Tastatur
                            (Umschaltung erfolgt automatisch)
int *mitem;         // I/O: ausgew„hlter Meneintrag 
                            (in: der, nach dem das Popup ausgerichtet wird)
int *lastkey;       // O: key-code, der das Verlassen verursacht hat
BOOLEAN *bgr_saved; // O: TRUE: Hintergrund konnte gesichert werden
/*
        RETURN  TRUE        Auswahl vorgenommen
                FALSE       Auswahl abgebrochen
*/

Mit ruby_popup() direkt zu arbeiten lohnt sich nur, wenn Sie Popups mit 
Submens programmieren m”chten.  Das ist m”glich und wurde auch schon mit 
dieser Funktion im Entmauser realisiert.  Dazu ist eine Funktion vom Typ 
MITEM_SEL bereitzustellen, die immer dann aufgerufen, wenn ein Eintrag 
selektiert wurde.  Diese Funktion wird dann wieder ruby_popup() fr's 
Popup aufrufen, wobei ab dem ersten rekursiven Aufruf noch tit_rect 
mitgeliefert wird.  tit_rect enth„lt dann Koordinaten des Eintrags im 
bergeordneten Popupmen.  Denn genau dann, wenn die Maus auf diesen zeigt, 
muž das Submen ja wieder weggeklappt werden.

Mit den Cursortasten (rechts, links) kann nach auch per Tastatur in die 
Submens hinein bzw. diese verlassen.

Achten Sie bitte darauf, wind_update(BEG_MCTRL) vor ruby_popup() 
und danach wind_update(END_MCTRL) aufzurufen, damit Ihre Applikation 
bzw. Ihr Accessory auch die volle Kontrolle ber Maus und Tastatur erh„lt (bei 
Submens reicht ein BEG_MCTRL).  Unterlassen Sie dies, so kehrt das AES 
u.U. nie mehr zum evnt_multi()-Aufruf von ruby_popup() zurck 
und ihre Applikation wird zur Speicher- und Bildschirmleiche. 
 pop_it_up() t„tigt die wind_update-Aufrufe selbst.



4. Interna von Ruby
-------------------

Einige Interna von Ruby sollen hier dokumentiert werden.


4.1 Die RUBY_USERBLK-Struktur
-----------------------------

Einige der zus„tzlichen Objekttypen werden durch G_USERDEF-Objekte 
implementiert, d.h. der ursprngliche Objekttyp (z.B. G_BUTTON) wird durch 
G_USERDEF ersetzt.  In diesem Zuge wird das ursprngliche ob_spec durch 
einen Zeiger auf eine erweiterte USERBLK-Struktur ersetzt, die sogenannte 
die RUBY_USERBLK-Struktur.  Die ursprnglichen Werte von ob_type und 
ob_spec werden in der ub_type und in ub_spec in der RUBY_USERBLK-Struktur 
ablegt, um weiterhin darauf zugreifen zu k”nnen.  Das Element text_offset 
bestimmt einen Offset, um den der Text bei der Ausgabe verschoben wird. 
 Dieser sollte z.B. von Let 'em Fly! verwendet werden, um die korrekte 
Position des Shortcut-"Strichleins" von auch bei Radio-Buttons und 
Checkboxen zu garantieren.

Die RUBY_USERBLK-Struktur ist noch durch eine Magic abgesichert, die 
den Wert 0x09800665L haben muž.  Nur dann sind die beschriebenen Daten 
auch wirklich vorhanden.

/* ==== Ruby's special extended USERBLK ==== */
typedef struct {
    int cdecl (*ub_code) _((PARMBLK*));
    OBSPEC ub_spec;     /* original ob_spec */
    int ub_type;        /* original ob_type */
    long ruby_magic;    /* the RUBY_MAGIC */
    int text_offset;    /* offset for drawing the text (pixel) */
} RUBY_USERBLK;

#define RUBY_MAGIC  0x09800665L     /* g [m/s^2] */

N„here Informationen ber die Funktion und Anwendung von 
USERBLK-Struktur und G_USERDEF-Objekten k”nnen Sie in 
einschl„giger Literatur finden.


4.2 Globale Variablen, die von Ruby ben”tigt werden
------------------------------------------------------

Ruby ben”tigt einige wenige allgemeine Variablen.  Diese werden von den 
beigelegten Modulen meiner GEM-Library bereitgestellt.  Wenn Sie diese 
Module nicht verwenden m”chten, mssen Sie folgende Variablen 
bereitstellen:

 Variable/Funktion   Bedeutung 
 lib_handle          ein Virtual-VDI-Screen-Workstation-Handle, 
                     mit dem Ruby machen darf, was es will...
 std_fdb             MFDB fr den Bildschirm, der auch die Anzahl 
                     der Planes des Bildschirms und die Maže des 
                     Bildschirm enth„lt.
 xdesk .. hdesk      Maže des Desktops, die man mit
                     wind_get(0, WF_WORKXYWH ...) erh„lt. 
 get_cookie(...)     Funktion aus der Let 'em Fly!-Bibliothek 
 fix_image(...)      diese Funkion ist in rfiximag.c enthalten 
 clip_start(...)
 clip_end(...)       diese beiden Funktionen sind in clip_it.c enthalten

Der Source rubyinit.c enth„lt Code, der die in der Liste aufgefhrten 
Variablen deklariert und initialisiert.  Beachten Sie bitte die Hinweise im 
Source selbst.

Noch eine Anmerkung zur Variable lib_handle.  Dieses Handle verwendet Ruby, 
um seine VDI-Ausgaben und -Operationen zu t„tigen.  Ruby setzt die 
VDI-Attribute vor allen Ausgaben und Operationen auf die ben”tigten Werte. 
Daher kann lib_handle ohne weiteres auch fr andere Libraries verwendet 
werden.  Ich selbst verwende lib_handle in meinen Libraries und handle in 
meinen Programmen, um in Programm und Libraries unabh„ngig mit dem VDI 
arbeiten zu k”nnen.

Ruby ben”tigt schachtelbares Clipping.  Ohne schachtelbares Clipping wrde 
das Popup nicht korrekt arbeiten, weil im Popup selbst ein "Ruby-OBJECT" 
enthalten ist.  Daher habe ich die Funktionen clip_start() und clip_end() 
implementiert.  Erstere stellt einen neuen Clipping-Bereich ein und merkt 
sich den alten.  Letztere schaltet zum alten Clipping-Bereich zurck.  Die 
Schachtelungstiefe betr„gt derzeit 20, ist aber im Modul clip_it.c 
einstellbar (CLIP_STK_DEPTH).  Das Modul clip_it.c ist bereits in die 
Libraries integriert (nicht DRI/Alcyon und Megamax LaserC Objectfiles).

Die PureC/TurboC-Version ben”tigt aužerdem noch die beiden Funktionen 
save_regs() und restore_regs(), die vom Assembler-Source tc\sr_regs.s 
bereitgestellt werden.


4.3 Die Gr”že des SMALL-Systemfonts und das Cookie SMAL
-------------------------------------------------------

Die Gr”že des sogenannten SMALL-Systemfonts wird weder vom VDI noch vom AES 
direkt geliefert.  Daher bedient sich Ruby eines "Tricks", der auch von 
Atari selbst verwendet wird.  Nach dem ™ffnen einer virtuellen 
Screen-Workstation steht die minimale Zeichenh”he in work_out[46].  Da 
Atari selbst im AES so die Gr”že des SMALL-Systemfonts ermittelt, ist mit 
einer Žnderung nicht so schnell zu rechnen.

int work_out[57], attrib[10];
long *the_smal_cookie;

/* LTMF-cookie */
ltmf_cookie = (LTMFLY*)_get_cookie(cookie_LTMF);

/* characters extents of the system fonts */
vq_extnd(lib_handle, 0, work_out);
vqt_attributes(lib_handle, attrib);
ibm_height = attrib[7];     /* aktuelle Zeichenh”he */
sml_height = work_out[46];  /* minimale Zeichenh”he */
vst_font(lib_handle, 1);
vst_effects(lib_handle, 0);
vst_height(lib_handle, sml_height, &dummy, &dummy, 
                            &sml_pix_width, &sml_pix_height);
vst_height(lib_handle, ibm_height, &dummy, &dummy, 
                            &ibm_pix_width, &ibm_pix_height);

if (the_smal_cookie = _get_cookie(cookie_SMAL)) {
    register int foo;
    if (foo = (int)(*(long*)the_smal_cookie & 0x0000FFFFL))
        sml_height = foo;
        if (foo = (int)((*(long*)the_smal_cookie & 0xFFFF0000L) >> 16))
            ibm_height = foo;
}

Sollte die Gr”že des SMALL-Systemfonts irgendwann einmal nicht mehr in 
work_out[46] stehen, dann k”nnen alle Programm, die Ruby verwenden durch 
ein TSR (Terminate\&Stay-Resident-Auto-Ordner-Programm) umkonfiguriert 
werden.  Dieses TSR muž lediglich ein Cookie anlegen, das im Low-Word die 
Gr”že des SMALL-Systemfonts passend als Parameter fr vst_height(...) 
enth„lt.  Ggf. kann das High-Word zus„tzlich noch die Gr”že des sogenannten 
IBM-Systemfonts enthalten.

Das obenstehende Programmstck darf ohne spezielle Bedingungen in andere 
Software eingebunden werden.


4.4 Erweiterungen fr Ruby -- der Ruby-Hook
-------------------------------------------

Auf recht einfache Art und Weise k”nnen Sie Ruby um eigene spezielle 
Objekt-Typen erweitern oder Objekte irgendwie modifizieren.  Als Beispiel 
liegt das Modul repldlin.c bei, das die Trennzeilen in Mens und 
Popup-Mens durch eine richtige Linie ersetzt (a la Gemini).

Das Prinzip ist ganz einfach.  Bevor Ruby ein OBJECT eines Baumes irgendwie 
bearbeitet, wird ber den Pointer ruby_hook eine Funktion aufgerufen, die 
das OBJECT prft und ggf. modifiziert und eine USERDEF-Routine installiert. 
 Dazu empfiehlt sich die Verwendung von install_ruby_userblk(), das das 
einen RUBY_USERBLK vollst„ndig installiert.  Sie mssen dann nur noch die 
Zeichenroutine in ub_code eintragen (siehe Beispiel).

Die "Hook-Funktion" gibt TRUE zurck, wenn Ruby sich nicht mehr um dieses 
OBJECT kmmern soll.  Damit werden Doppelinterpretationen ausgeschlossen. 
 FALSE signalisiert Ruby, daž es ganz normal verfahren soll, d.h. seine 
ob_type-Prfungen auf XG_BUTTON usw. durchfhrt.

Damit mehrere Hooks eingeh„ngt werden k”nnen, muž beim Installieren eines 
Hooks der als Pointer-Wert von ruby_hook gespeichert werden und im eigenen 
Hook ber den alten Pointer-Wert in den n„chste Hook sprungen werden.  Ein 
n„chster Hook existiert nur dann, der alte Pointer-Wert != 0 ist.  Im 
Beispiel ist der Mechanismus deutlich zu erkennen.

Achten Sie in der Zeichen-Funktion (draw_dash_line() im Beispiel) bitte auf 
Clipping.  Verwenden Sie bitte dafr die Funktionen clip_start() und 
clip_end() aus dem Modul clip_it.c.  Diese Funktionen erm”glichen die 
Schachtelung von Clipping-Areas.  Wenn Sie dies nicht machen, kann es 
passieren, daž z.B. das Popup nicht mehr verschwindet o.„.  Sie k”nnen sich 
den Effekt anschauen, indem Sie im Beispiel einfach mal clip_start() durch 
den entsprechenden vs_clip()-Aufruf ersetzen und clip_end() weglassen. 
Schleužlich, was?  Also:  Immer clip_start() und clip_end() verwenden.

Wenn Sie das Clipping ganz unterlassen, wird Ihre Erweiterung in 
Fensterdialogen nicht korrekt funktionieren, da dort der Redraw anhand von 
Rechtecklisten vorgenommen wird und Clipping somit unerl„žlich ist.

Wenn Sie eine Ruby-Erweiterung programmieren m”chten, verwenden Sie am 
besten das Beispiel-Modul und modifizieren dies auf geeignete Art und 
Weise.  In draw_dash_line() mssen Sie beispielsweise nur die Aufrufe der 
VDI-Funktionen zum Zeichnen ersetzen und die Erkennung im Hook anpassen.

Sie m”chten Ihre Ruby-Erweiterungen auch anderen Leuten zur Verfgung 
stellen?  Am besten stellen Sie eine kurze Info und ein Beispielprogramm 
zusammen und schicken mir dies.  Ich werde dann zumindest im Mausnet und 
Starnet fr eine gewisse Verbreitung sorgen k”nnen.



5. Bemerkungen zum Design von Dialogen
--------------------------------------

Halten Sie das Design der Dialoge einheitlich.  Schauen Sie sich ab besten 
Software an, die ebenso die Features von Ruby bzw. entsprechende Features 
anderer Libraries verwendet (Beispiele:  Gemini, CAT, Rufus).  Orientieren 
Sie sich daran.

Ein paar Richtlinien m”chte ich Ihnen noch mit auf den Weg geben:

- Halten Sie den Hintergrund Ihrer Dialoge m”glichst einfach.  Am 
unaufdringlichsten ist ein einfacher weižer Hintergrund {\em ohne} Muster. 
 Damit heben sich Dialoge auf bestens vom grauen Desktophintergrund ab.

- Sorgen Sie fr eine einheitliche Strukturierung Ihrerer Formulare.  Oben 
kommt die šberschrift hin, dann die ganzen Einstellungen und unten die 
Buttons zum Verlassen des Dialogs.

- Die Button zum Verlassen des Dialogs sollten in allen Dialogen an der 
gleichen Position in der gleichen Reihenfolge stehen.  Ich pers”nlich ziehe 
die Reihenfolge OK--Abbruch vor.  Bei der Schreibweise hat es 
sich eingebrgert, immer OK grož zu schreiben und Abbruch in 
normaler Grož-Klein-Schreibung zu verwenden.  Da sich die Bezeichnungen OK 
und Abbruch eingebrgert haben, m”chte ich Ihnen nahelegen, diese ebenso zu 
verwenden.


5.1 Implementierung
-------------------

Zur Implementierung habe ich derzeit nur einen einzigen, aber sehr 
wichtigen Hinweis.

- Packen Sie die Aufrufe der Dialoge immer in wind_update(BEG_UPDATE) -- 
wind_update(END_UPDATE), da sonst Fehlfunktionen bei Accessories oder unter 
MultiGEM auftreten.  Wenn Sie das n„mlich vergessen, werden Klicks und 
Tastendrcke u.U. an das oberste Fenster und nicht an den Dialog 
weitergeleitet.  Die Folgen k”nnen Sie sich selbst ausmalen...


Haben Sie weitere Vorschl„ge, um die dieses Kapitel erweitert werden 
sollte, dann lassen Sie es mich bitte wissen.



6. Bugreports
-------------

Wenn Sie irgendwelche Fehler in Ruby entdecken, so benachrichtigen Sie 
mich bitte.  Als Programmierer sollten Sie wissen, was ich dazu wohl 
ben”tigen werde und ber das Problem wissen soll und muž.

Schicken Sie Bugreports bitte m”glichst per E-Mail, um mir Rckfragen zu 
erm”glichen.

  E-Mail:
  Markus_Nick @ MZ         (im Mausnet)
  Markus_Nick@mz.maus.de   (im Internet)



7. Abspann
----------


7.1 Acknowledgements
--------------------

Ich m”chte mich bei folgenden Leuten fr die Mitarbeit und Untersttzung 
bei der Entwicklung von Ruby bedanken:

 - Oliver Scheel -- insbesondere fr Let 'em Fly! -- ohne Let 'em Fly! g„be 
   es n„mlich kein Ruby -- und fr seine grožartige Untersttzung bei der 
   Entwicklung von Ruby und beim Beta-Testen.
 - Dieter Linde fr's sorgf„ltige Beta-Testen, die konstruktiven 
   Fehlermeldungen und Anregungen.


7.2 Warenzeichen
----------------

- Atari und Atari ST und TT sind geschtzte Warenzeichen der Atari Corp.
- GEM ist ein geschtztes Warenzeichen von Digital Research Corp.
- LaserC ist ein geschtztes Warenzeichen von Megamax Inc.

Diverse in diesem Text verwendete Namen sind m”glicherweise urheberrechtlich 
geschtzt.  Daraus, daž diese nicht kenntlich gemacht sind, kann nicht 
geschlossen werden, daž sie frei von Rechten Dritter sind.

Weiterhin:
- GNU-CC ist ein Produkt der Free Software Foundation
- Let 'em Fly! ist Freeware von Oliver Scheel (Oliver Scheel @ K)
- "Three Flights Up" ist die Library zu Let 'em Fly! von Oliver Scheel

%-eof-
