★ CODING ★ BENUTZEROBERFLAECHE CEUS V1.0 - TEIL 2: DER WINDOW-MANAGER (I) (CPC AMSTRAD INTERNATIONAL) ★ |
Menu - RSX | Benutzeroberflaeche CEUS v1.0 - Teil 2: Der Window-Manager (I) (CPC Amstrad International) |
Haben Sie die letzte Folge gut Überstunden? Ja? Gut, denn jetzt geht es erst richtig los. In diesem Teil kommt das Grundgerüst des komfortablen Window-Managers auf Sie zu. Komfortabel ist immer nur relativ . Natürlich kann man auf dem CPC keinen Window-Manager wie X-Windows oder MS-Windows realisieren. Dazu hat er ganz einfach zu wenig Speicherplatz, und die Berechnungen dafür würden vermutlich wesentlich mehr Zeit verschlingen, als man opfern kann. Also, ein bißchen Selbstbeschränkung muß sein, aber in diesem Rahmen läßt sich schon einiges machen. Aber was macht dieser Window-Manager denn nun konkret? Nun, im Prinzip übernimmt er die gesamte Fensterverwaltung auf dem CPC. Nicht mehr -aber auch nicht weniger. Und wie funktioniert diese Fensterverwaltung überhaupt? Ein Fenster ist ja bekanntlich (vergleiche 1. Folge) ein unabhängiger Bildausschnitt. der andere Bildausschnitte und den Hintergrund nicht beeinflußt. Und damit wäre auch schon das größte Problem der Fensterverwaltung angesprochen: Ein Fenster muß so gestaltet werden, daß man cs über andere Fenster legen und wieder entfernen kann, ohne diese anderen Fenster oder ihren Inhalt zu zerstören. Man merkt sich also den Hintergrund, über dem ein Fenster eröffnet wird. Und das kann man? Ja, natürlich kann man das, aber... All you need is memory Machen wir einmal eine kleine Überschlagsrechnung: Angenommen, wir wollen im Mode 2 ein Fenster ab den Koordinaten 5/5 mit der Länge 50/15 Zeichen eröffnen (wer eine Fensterverwaltung im Mode 0 machen will, dem ist eh' nicht mehr zu helfen). Ein Zeichen im Mode 2 belegt 8 Bytes im Bildschirmspeicher. Das Window ist 50 mal 15 Zeichen groß, macht nach Eva Zwerg 15*50*8 = 6000 Bytes nur für dieses eine Window. Dazu kommen noch die Daten für den Rahmen und den Schatten, in unserem Beispiel weitere 1072 Byte. Das sind fast 7 kByte, wenn man jetzt noch fünf weitere Fenster eröffnen will, kann's schon mal ziemlich eng im Speicher werden. Diese ganzen Probleme gäbe cs natürlich nicht, wenn der CPC wie seine großen Brüder mit den drei Buchstaben einen ordentlichen Textmodus hätte. Da bräuchte man nur noch 1768 Byte, ja wenn... Er hat aber nicht, und so müssen wir uns damit abfinden, daß ein Programm, wird es länger, auch weniger Windows auf einmal offenhalten darf. Und wenn cs noch so unlogisch klingt - wer gerade Lust dazu hat, kann nachher ja einmal die Window-Routinen so umschreiben, daß sie den Hintergrund in die zweiten 64 kByte eines CPC 6128 auslagern - es geht, immerhin vier ganzbildschirmgroße Fenster unterzubringen. Nicht ganz so sinnvoll, aber durchaus denkbar wäre es, die Daten auf Diskette auszulagern. Da haben dann schon elf Windows Platz, aber auch nur, wenn die Diskette sonst nicht gebraucht wird — und cs ist ziemlich langsam. Ach, hätte man doch nur eine Festplatte, da würden dann bei 20 MByte... Alles steht im BASIC-Handbuch... Das Prinzip ist also klar. Wir brauchen eine Routine, die einen bestimmten Bereich des Bildschirms in einen bestimmten anderen Bereich des Speichers auslagert. Aber in welchen? Dieses Problem haben wir zum Glück nicht mehr, denn darum haben sich die Entwickler des BASIC im CPC schon gekümmert. Solange noch genügend freier Speicher da ist. braucht man nur zum Betriebssystem zu gehen und es lieb zu bitten, doch mal eben ein bißchen davon herauszurücken: denn wozu soll man alles selber machen, was andere schon (und besser?) geschaffen haben. Merke: Betriebssysteme sind dazu da, um sie zu benutzen, und nicht, um sie zu umgehen! Mit dem Memory-Befehl wird die Obergrenze des BASIC zur Verfügung stehenden Speichers festgelegt. Man braucht nur auszurechnen, wieviel Platz man denn eigentlich benötigt (Achtung: der Platzbedarf pro Zeichen ist modusabhängig, die Betriebssystem-Routine SCR CHAR POSITION (#BC1A) liefert im B-Register die Zeichenbreite in Byte zurück), sich die derzeitige Memory-Ad resse zu holen (steht an Adresse #AE5E beim CPC 6128, die Werte für CPC 464/664 stehen - sofern abweichend - im Listing)), den benötigten Platz davon abzuziehen und die Memory-Routinc aufzurufen (#F808 — ist eigentlich nicht der ganze MEMORY-Befehl, reicht aber für unsere Zwecke aus). Wenn der benötigte Platz nicht mehr da ist, meldet sich die Memory-Routine schon von ganz alleine mit einem freundlichen 'Memory full'. Für das alles ist der Befehl |WINDOW.IN,x,y,xd,yd,@adr%,@)len% zuständig, er speichert den Bereich von x,y (Zeichcnkoordinaten) bis x + xd,y +yd ab und gibt in den Variablen adr% und len% die Adresse und die Länge des Bereichs zurück, in dem der Ausschnitt gespeichert wurde.
...fast alles Nicht ganz so einfach ist das Wieder-einblenden. Zuerst muß man auch hier einfach die Bildschirmadresse holen. Dann den gespeicherten Ausschnitt einfach wieder zurückschreiben und den Speicher, der für den Ausschnitt belegt wurde, wieder freigeben; denn der liegt sonst ziemlich brach als Speicherleiche herum, und so etwas können wir nun wirklich nicht dulden. Wenn man nun einfach einen Ausschnitt speichert und wieder einblendet, dann ist das noch kein großes Problem. Man braucht nur die Speicherobergrenze wieder heraufzusetzen. Aber was macht man, wenn das Betriebssystem seine Symboltabellen ' unter unserem Ausschnitt abgelegt hat oder wenn wieder ein Kassettenbuffer .im Weg ist? Zuerst: Wenn der Kassettenbuffer im Weg ist und man ihn nicht loswerden kann, macht man gar nichts; dann ist der Speicher, der darüber belegt war, weg! Pech gehabt; also: Wichtig! Nie ein Window öffnen, dann eine Datei eröffnen und versuchen das Window wieder zu schließen, solange die Datei noch offen ist (gilt auch umgekehrt). Immer FIFO-Prinzip beachten (first in. first out: hier: immer alle Operationen erst dann zu Ende bringen, wenn alle später begonnenen schon fertig sind)! In allen anderen Fällen stehen wirzwar nicht ohne Probleme dar, aber immerhin sind diese lösbar. Ein Buffer, der nicht mehr gebraucht wird, kann einfach mit einer BASIC-Routine (#F761) unschädlich gemacht werden; die Symboltabellen sind da schon etwas schwieriger. Um sie loszuwerden, muß man ihre Adresse holen und sic eventuell 'von Hand* an das Ende des freizugebenden Bereichs kopieren, ihre Adresse korrigieren und dann einen entsprechend weiter unten liegenden Bereich freigeben. Diese Aufgaben übernimmt die Routine MEMFR. die von dem Befehl |WINDOW.OUT,x,y,xd,yd,adr,len aufgerufen wird. Er blendet den gesicherten Ausschnitt wieder in den Bildschirmspeicher ein. Jetzt bekommt die Handlung einen Rahmen Ein gesicherter Ausschnitt macht noch kein Fenster. Schließlich hat eine Benutzeroberfläche etwas mit Benutzerfreundlichkeit zu tun und letzteres etwas mit Ergonomie und dieses wieder mit Design. Zu Deutsch: Unsere Windows sollen schöner werden. Dieses Aussehen erledigt der Befehl |WINDOW.DRAW,x,y,xd,yd. Er löscht den angegebenen Bereich des Bildschirms und zeichnet einen Rahmen und einen Schatten drumherum. Ach ja, der Schatten. Der ist sowieso ein Thema für sich. Der CEUS-Schatten verhält sich in unterschiedlichen Modi natürlich auch unterschiedlich. In Mode 2 wird er einfach durch eine Zeile und eine Spalte invertierter Zeichen links unterhalb des Fensters dargestellt. Im Mode l hingegen verändert er die Farben der Bildpunkte, die in seinem Bereich liegen, nach dem Schema PEN 0 wird zu PEN 2, PEN 1 bleibt und PEN 2 und 3 werden zu PEN 1. Bei einer Farbverteilung wie 0 weiß, 1 schwarz und 2 grau oder 0 gelb, 1 rot und 2 orange (3 jeweils beliebig) ergibt sich so ein durchaus realistischer Schatteneffekt. Was im Mode 0 geschieht, wissen wir auch nicht so genau (vergleiche Bemerkung über Windows im Mode 0); es ergibt sich ein Schatteneffekt ähnlich dem im Mode 1, aber nach welchen Regeln...? Licht und Schatten Die Realisierung dieses Effektes ist eine ziemliche Bit-Schieberei über mehrere Masken, deren Erklärung im einzelnen zu viel Platz brauchen würde, wir können daher nur auf das Assemblerlisting verweisen. Falls jemandem dieser wundervolle Schatten nicht gefallen sollte, kann er ihn natürlich auch abschalten mit |SHADOW.OFF, bzw. wieder einschalten mit |SHADOW.ON, dies muß aber selbstverständlich vor der Darstellung geschehen. Die Parameter für |WINDOW.DRAW müssen übrigens so gewählt werden, daß der gesamte Fensterinhalt zwischen den Koordinaten 2/2 und 79(39,19)/24 liegt, da immer (auch ohne Schatten) auf jeder Seite des Windows ein Zeichen für den Rahmen benötigt wird. Viele Kleine ergeben ein Großes Nachdem jetzt sämtliche Befehle zur Verfügung stehen, mit denen man EIN Fenster auf dem Bildschirm eröffnen und verwalten kann, fehlt jetzt nur noch ein Befehl, der dies umfassend, allgemein und für MEHRERE Windows erledigt. Für diesen Zweck gibt es die Befehle |WINDOW.OPEN,num,x1,y1 ,x2,y2 und |WINDOW.CLOSE. |WINDOW.OPEN eröffnet ein Window. weist ihm die Betriebssystemnummer num (von 0-7) zu, rettet den Hintergrund, trägt es in eine Tabelle ein und stellt es auf dem Bildschirm dar; |WINDOW.CLOSE entfernt es vom Bildschirm und aus der Tabelle und gibt seinen Speicher wieder frei. Die Windownummer entspricht dabei den jeweiligen BASIC-Nummern, das heißt, das Fenster kann mit 'PRINT #num' beschrieben werden. Damit diese Funktionen ausgeführt werden können, müssen einige Parameter zwischengespeichert werden. Da wären zum einen natürlich die Koordinaten - woher soll der Befehl sonst wissen, welchen Bereich er freigeben soll? - dann der belegte Speicher, die Nummer des Windows und die Position des Windows in der Tabelle - denn es kann ja immernur das oberste Fenster geschlossen werden, sonst werden eventuell dar-überliegende Fenster zerstört. |WINDOW.OPEN speichert nun alle diese Werte in entsprechenden Tabellen ab, und |WINDOW.CLOSE braucht sie danach nur auszulesen und die Tabelle zu korrigieren (die Tabellen sind jeweils neun Einträge lang, obwohl nur acht Fenster eröffnet werden können; das erleichtert die Verwaltung und hält einen Platz als Koordinatenzwischenspeicher frei - er wird später noch gebraucht). Übrigens: Sämtliche RSX-Befehle sind mit einer Parameterkontrolle ausgerüstet, die im Fehlerfall die richtige Systemmeldung ('lmproper argument' oder 'Operand missing') auslöst (vergleiche 1. Folge). Beim nächsten Mal... Das wär's dann erst einmal für diese Folge. Im nächsten Heft kommen dann einige nette Zusätze für den Window-Manager auf Sie zu, mit denen man Windows einen Namen geben, sie verstecken oder unter anderen Fenstern hervorholen kann. Wer es bis dahin nicht aushält, der kann sich ja des Speicherplatzproblems annehmen. Neben den oben genannten Lösungsansätzen gibt es ja auch noch einen Kompressor für die Daten. Der müßte dann allerdings irgendwie schon vorher wissen, wie lang das Komprimat wird; denn wieviel Speicher soll sonst abgezwackt werden? Man könnte ihn dazu einfach zweimal ablaufen lassen, wenn das nur nicht s viel Zeit kosten würde... Also, dies Aufgabe ist mit Sicherheit anspruchs voller als die Verlegung der Ausschnitte in die zweiten 64 kByte des 6128 aber unlösbar? Bestimmt nicht!
|