==================================== 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-