Im Gadget #29 hatte ich beschrieben, wie man mit Hilfe von DataTypes Bilder auf eigenem Screen anzeigen kann. Der beigefügte Assembler-Source zeigte nur die wichtigsten Routinen.
Inzwischen habe ich etwas Zeit gefunden, um diese Routinen zu einem lauffähigen Programm auszubauen. Es heißt MView und kann nicht nur Bilder, sondern auch Texte, Guides usw. anzeigen. MView, der dazugehörige Sourcecode und ein kurzes .dok befinden sich in dieser Ausgabe des AmigaGadget. Um MView auszuprobieren, kann man sich das Bild pic002 anzeigen lassen. OS V39+ ist allerdings Vorraussetzung.
Der Sourcecode ist ausreichend kommentiert, so daß ich nur auf einige Besonderheiten hinweisen möchte. Assembliert werden kann nur mit dem A68k, weil das Format für lokale Label - sie beginnen mit "\" - von anderen Assemblern nicht verstanden wird.
MView ist "pure", kann also resident gemacht werden. Wie erreicht man das?
MView akzeptiert ein Muster als Argument, d.h. im angegebenen Dateinamen könen wildcards enthalten sein. Möglich wurde das durch Verwendung der Dos-Funktionen MatchFirst(), MatchNext() und MatchEnd(). Ich hatte diese Funktionen vorher nie benutzt und war deshalb überrascht, wie komfortabel man damit arbeiten kann. Sie ersparen einem die Anwendung einer ganzen Reihe von Dos-Funktionen, z.B. Lock(), Examine(), ExNext, MatchPattern(), NameFromLock() und noch verschiedenes mehr. Alle 3 Funktionen erwarten als ein Argument einen Zeiger auf den sog. AnchorPath. Der Aufbau dieser Struktur ist wie folgt:
STRUCTURE AnchorPath,0 APTR ap_Base APTR ap_Last LONG ap_BreakBits ;Bits für Ctrl-C bis Ctrl-F LONG ap_FoundBreak BYTE ap_Flags BYTE ap_Reserved WORD ap_Strlen ;Länge von ap_Buf STRUCT ap_Info,260 ;FileInfoBlock ------------------------ STRUCT ap_Buf
Der Speicher für AnchorPath (longword aligned) muß vom Programm zur Verfügung gestellt werden, initialisiert wird er größtenteils von MatchFirst(). Wenn man den vollen Pfad einer Datei haben will, ist ein Puffer dafür direkt hinter ap_Info anzuhängen und seine Länge in ap_Strlen einzutragen. Initialisiert werden können auch ap_Flags und ap_BreakBits. Letztere entscheiden darüber, ob der User mit einer Ctrl-Tastenkombination abbrechen kann. Für Ctrl-C ist z.B. $1000, für alle möglichen Kombinationen (C,D,E,F) $F000 einzutragen. Das sollte man allerdings erst vor dem Aufruf von MatchNext() tun, da eine Initialisierung vor MatchFirst() nach meiner Erfahrung keine Wirkung hat.
Nach MatchFirst() wird MatchNext() so lange aufgerufen, bis ein Wert ungleich Null zurückgegeben wird. d0 enthält dann einen der DosErrorCodes, wie sie auch von IoErr() geliefert werden. Dieser Code kann mittels PrintFault() in eine lokalisierte Fehlermeldung an der Shell umgewandelt werden. Anschließend wird MatchEnd() aufrufen. Bei normalem Verlauf tritt am Ende ERROR_NO_MORE_ENTRIES auf oder ERROR_BREAK, falls der User eine von den BreakBits zugelassene Ctrl-Kombination gedrückt hat.
Noch einige Infomationen zu ap_Flags: Sie sind im Handbuch (dosasl.h) dokumentiert, allerdings ohne den Hinweise, daß APB_DOWILD und APB_DODOT nicht implementiert sind. Durch Setzen von APB_DODIR kann man in ein Unter- verzeichnis eintreten, wenn MatchNext() auf eines stößt. Im Normalfall werden Unterverzeichnisse übergangen. Beim Wechsel zurück ins übergeordnete Verzeichnis setzt MatchNext() APB_DIDDIR.
Der Abbruch mittels Ctrl-C ist für den User ein wenig mühselig, wenn das Programm wie im Falle von MView ein eigenes Fenster öffnet und damit die Shell inaktiviert. Hier sollte man andere Abbruchmöglichkeiten vorsehen. Normalerweise empfängt ein Programm Eingaben über den IDCMP-Port des von ihm geöffneten Fensters und kann bestimmte Tasten für den Abbruch vorsehen. MView benutzt dafür bei der Bildanzeige ESC und Q. Bei Verwendung der amigaguide.library ist das Programm hingegen von der Außenwelt abgeschnitten. Die IntuiMessages, die an das von der library geöffnete Fenster gehen, werden auch von ihr ausgewertet. Um dem User eine komfortable Möglichkeit zum Abbruch zu geben, öffnet MView nach jeder Anzeige einen EasyRequester - vorausgesetzt, ein Muster wurde angegeben - der über die jeweils nächste Datei informiert und die Gadgets ZEIGEN, WEITER und ABBRUCH aufweist. Da der Punkt WEITER auch nach der Anzeige eines Bildes Sinn macht, wird er auch hier verwendet.
Von den beiden Möglichkeiten, einen EasyRequester aufzurufen, habe ich BuildEasyRequestArgs() verwendet, weil nur mit dieser Funktion Messages über die vom User gedrückten Tasten empfangen werden können. EasyRequestArgs() erlaubt zwar auch durch Angabe des IDCMP-Flags VANILLAKEY per Tastendruck abzubrechen, informiert aber nur darüber, daß eine Taste gedrückt wurde, nicht welche.
Noch ein Wort zur Gestaltung des EasyRequesters: Höhe und Breite des Requesters werden von EasyRequestArgs() selbst bestimmt. Man kann ihn aber etwas großzügiger gestalten, indem man vor den Bodytext ein Linefeed setzt. Dies führt zur Einfügung einer Leerzeile ober- und(!) unterhalb des Textes. Wenn man noch mehr Kontrolle über das Aussehen des Requesters haben will, sollte man BuildSysRequest() verwenden. Durch entsprechende Werte in den hier erforderlichen IntuiText-Strukturen lassen sich auch Zeilenabstände und Font festlegen. EasyRequester verwenden immer den ScreenFont, nicht den SystemDefaultFont. Da der ScreenFont auch proportional sein kann, eignet er sich schlecht zur Ausgabe von Texten, in denen eine bestimmte Anordnung eingehalten werden soll, z.B. Tabellen. BuildSysRequest() läßt allerdings maximal nur 2 Gadgets zu.
Die Routinen zur Anzeige von Bildern sind von mir bereits ausführlich erläutert worden, erklärungsbedürftig sind zwei nachträgliche Änderungen:
GetDisplayInfoData = -$2f4 (handle,buf,size,tagID,displayID) (a0,a1,d0-d2) buf = Zeiger auf Zielpuffer size = Puffergröße in Bytes (=56) tagID = DTAG_NAME ID = optional, wenn handle NULL
Ein Problem taucht noch auf, wenn die erhaltenen Daten mittels RawDoFmt() formatiert werden sollen. Der hier verwendete FormatString ist:
picinfo.fmt dc.b '%s: %s (%dx%dx%d) %s',LF,'%s',0
Im DataStream ist für jedes "%s" die Adresse eines strings, für jedes "%d" ein Wert (Word) vorzusehen. Nun kann es sein, daß für das letzte "%s" keine Adresse angegeben werden kann, weil FindDisplayInfo() bzw. GetDisplayInfo- Data() versagten. In diesem Fall muß man einen Zeiger auf einen Leerstring im DataStream eintragen, d.h. die Adresse muß auf eine Speicherstelle zeigen, die mit einem Nullbyte beginnt. Dann substituiert RawDoFmt() das "%s" mit nichts. Auf das LF(=Linefeed) würde also im formatierten string sofort das abschließende Nullbyte folgen. Keinesfalls ist NULL in den DataStream einzutragen, weil dies einen illegalen Zugriff auf Adresse 0 zur Folge hätte.
Zum Abschluß möchte ich auf die Verwendung der amigaguide.library hinweisen. Die Anzeige von Texten (ASCII, Guides), ab OS 3+ auch von anderen Dateitypen, für die DataTypes vorliegen, ist denkbar einfach. Man muß lediglich OpenAmigaGuide() eine leere NewAmigaGuide-Struktur übergeben, in die nur der Pfad der Datei einzutragen ist.
So, ich hoffe, das war jetzt nicht völlig umsonst. Bei dieser Gelegenheit möchte ich Sven Drieling grüßen. Ich war hoch erfreut darüber, daß Du meinen BOOPSI-Programmiertip aufgegriffen und erweitert hast. Die Idee, die Textzeilen über Execlisten zu verwalten, fand ich sehr interessant.
Jürgen