Blinken auf dem Bildschirm soll immer auf etwas Besonderes hinweisen. Etwas, das entweder "lang ersehnt und endlich erreicht" bedeutet oder aber "hier ist etwas ganz und gar anders verlaufen als gedacht". Unser Beispiel hier (Animation oben) ist aus der zweiten Kategorie.
Wir haben hier eine "Anwendung" namens "Any Application" mit drei Bildschirmfenstern, "Task 1", "Task 2" und "Eingabeaufforderung", man soll eine Taste drücken. Nachdem das geschehen ist, kommt der eigentliche Demo-Teil. Hier ist (scheinbar) ein schwerer Anwendungsfehler aufgetreten und das in der Mitte des Bildschirms erschienene Alert-Fenster weist uns darauf hin.
Damit es auf keinen Fall übersehen werden kann, verwendet es drei Hingucker-Tricks: 1. Es überdeckt (zum Teil) die anderen Fenster, 2. es ist andersfarbig, und 3. es blinkt. In diesem Fall gibt es im Alert-Fenster sogar zwei verschiedene Frequenzen (die Alert-Überschrift wechselt etwa halb so schnell wie die Blinkfrequenz), was zusätzlich Aufmerksamkeit erregen soll. - Wie geht das alles?
Ein Blinken unter TSB funktioniert so: Man wählt mit FLASH eine Farbe (oder auch mehrere, hier sind es zwei, weiß und rot), die blinken soll(en), und gibt in 60tel-Sekundenwerten an, wie hoch man die Blinkfrequenz haben möchte. Für einen Farbwechsel von zwei Mal pro Sekunde wäre daher ein Wert von 30 für die Blinkfrequenz richtig: Nach jeweils 30 Sechzigstelsekunden wechselt die Farbe. Welches ist die "ablösende" Farbe? Wir befinden uns auf dem Textbildschirm, da sind nur zwei Farben pro Zeichen möglich: Die Zeichenfarbe selbst und die Hintergrundfarbe (für alle Zeichen gleich).
Die gewählte Farbe blinkt also alternativ mit der Hintergrundfarbe. Es soll aber nicht der ganze Bildschirm blinken, sondern nur das Zeichen mit der gewählten Farbe. TSB macht das, indem es alle Zeichen dieser Farbe sucht und auf dem Bildschirm nach Ablauf der eingestellten Zeitspanne immer wieder invertiert. Das Zeichen hat dann immer noch die gleiche Schreibfarbe, aber die scheint nun je nach Blinkphase an anderen Stellen durch, so dass der Eindruck entsteht, die Schreibfarbe habe sich geändert.
Genau dies bereitet uns aber das Problem: Wenn wir während des Blinkens schreiben wollen, müssen wir genau die Blinkphase treffen, in der der Text ursprünglich geschrieben wurde, sonst blinkt diese Stelle entgegengesetzt! Das wollen wir natürlich nicht. Und: Wie wir oben im Eingangsbild sehen können, haben wir Einfluss auf den Schreibzeitpunkt. Hier erscheinen alle Zeichenwechsel nach der Invers-Phase (nach der grauen Phase). Denn glücklicherweise gibt es ein TSB-Flag für die jeweilige Phase (Speicherstelle $C5C7) und diese Code-Zeile macht die Magie:
wait $c5c7,$80,$80: print "ALERT"
Hier wartet TSB darauf, dass die Invers-Phase endet (in $C5C7 wechselt der Wert von $80 auf $00). Erst wenn das der Fall ist, wird das PRINT ausgeführt. Natürlich nur, wenn FLASH aktiv ist (sonst hängt sich TSB hier auf und man muss STOP/RESTORE drücken).
Es lohnt sich ein genauerer Blick auf das Programm, denn darin gibt es noch ein paar weitere nützliche Hinweise, z.B. zu CENTRE und INSERT. Zuerst die vorbereitenden Routinen, die die Oberfläche herstellen:
100 init 130 gui 150 do null 160 t$="": txtout 190 alert 210 t$="Thank you!": txtout 990 end 1400 proc txtout 1410 z=20: s=2: b=20: h=3: box: print at(s+1,z+1)"";: centre t$,b 1420 printat(s,z+2)""; 1430 end proc 1100 proc gui 1110 z=0: s=0: b=40: h=25: c=c0 1120 box: print at(s,z+1)"";: centre "Any Application" 1130 z=3: s=2: b=20: h=16: t$="Task 1": titled box 1140 z=3: s=23: b=15: h=20: t$="Task 2": titled box 1150 t$="Press a Key!": txtout 1160 end proc
1500 proc init 1510 div: cset1: c0=0: c1=1: c2=2 1520 r$="{C=a}{Sh-@}{C=s}{Sh--} {Sh--} {C=y}{Sh-@}{C=x}": b$="{Sh--} {Sh--} {C=q}{Sh-@}{C=w}" 1530 az=8: as=12: c=c0: colour,c 1540 a1$="ALERT": a2$="!!!!!" 1550 end proc 1000 proc box 1010 insert r$,z,s,b,h,c 1020 end proc 1050 proc titled box 1060 box: insert b$,z+1,s,b,2,c 1070 print at(s,z+1)"";: centre t$,b 1080 end proc
Da ist zunächst das obligatorische PROC init, wo die später verwendeten Variablen zur besseren Anpassbarkeit an neue "Anwendungen" vorbelegt werden, z.B. die Variablen AZ und AS, die festlegen, wo auf dem Bildschirm der Alert-Kasten erscheinen soll. Die Hauptroutine dieses Programm-Dummys ist PROC gui, das den übergeordneten Rahmen und die drei Fenster ausgibt. Dazu benutzt es PROC box, PROC titled box und PROC txtout.
Der Definitionsstring für den INSERT-Tabellenrahmem R$ ist der übliche, aus Standard-PETSCII-Zeichen aufgebaute String (Z. 1520, siehe Bild). Der String B$ dagegen ist eine von mehreren Möglichkeiten, eine Tabellentrennlinie zu definieren. Er nutzt die INSERT-Eigenschaft, bei Rahmen von zwei Zeichen Höhe die mittlere Zeile wegzulassen (die drei Spaces in der Mitte von B$, ebenfalls Z. 1520). Er löscht beim Zeichnen also die Überschriftzeile und schreibt direkt darunter die Querlinie (Z. 1060). Erst danach wird die Spaltenüberschrift eingetragen (Z. 1070).
Jede der drei oben aufgezählten Prozeduren wird vor dem Aufruf mit den erforderlichen Parametern gefüttert, das sind die Zeile und Spalte der linken oberen Ecke des Rahmens (Z und S), seine Breite und Höhe (B und H), seine Farbe (C) und ggf. ein Text (T$), siehe z.B. Z 1130.
Alle Texte sind hier relativ zu ihrem Ausgabeort zentriert. Dafür sorgt der beim CENTRE-Befehl angehängte zweite Parameter, hier in Form der Variablen B (für Breite, Zeilen 1070 und 1410):
centre t$,b
Nun zur Blinkroutine mit seinen zwei in 60teln einer Sekunde definierten Darstellungsfrequenzen. Zuerst wird in PROC alert der Text des Warnhinweises ausgegeben (Z. 1210 bis 1240). Dann wird in Zeile 1250 das Blinken der Farben rot und weiß aktiviert und mit dem Wert 20 (Sechzigstel Sekunden) beim zweiten FLASH-Befehl auf eine Blinkfrequenz von (eigentlich) drei Mal pro Sekunde eingestellt.
Schließlich wechselt das Programm zu PROC blink, in der die anders getaktete Ausgabe der Titelzeile erfolgt. Hier steht in Zeile 1330 der Wert 30 (Sechzigstel Sekunden), was eine Frequenz von zweimal pro Sekunde bedeutet. Die Ausgabe aber blinkt nicht, sondern wechselt nur den Ausgabeinhalt (von "ALERT" zu "!!!!!" und zurück). Sie benutzt dazu als erstes den Stringtausch-Befehl AT() (Z. 1320). Der Rest funktioniert folgendermaßen:
1200 proc alert 1210 z=az: s=as: b=15: h=8: c=c1: box: print at(s,z+2)"{rvs on}";: c=c2 1220 fill z+1,s+1,b-2,h-2,160,c: colour,c 1230 centre a1$,b: print at(s,lin+2)"";: centre "Leave the",b 1240 print at(s,lin+1)"";: centre "Building!",b 1250 flash c1: flash c2,20: blink 1260 flash off: colour 11,12,c0 1270 insert r$,z,s,b,h,c0: print at(s,z+h/2-1)"";: centre "ALL CLEAR",b 1280 print"{rvs off}":pause 10 1290 gui 1295 end proc
1300 proc blink 1310 bl=0: repeat: bl=bl+1 1320 getx$: at(a1$,a2$) 1330 poke $c516,0: repeat: until peek($c516)>30 1340 wait $c5c7,$80,$80: print at(s,z+2)""; 1350 centre a1$,b 1360 until bl>20 or x$>"" 1370 end proc
Die Prozedur blink wiederholt sich 20 Mal (Z. 1360), bei jedem Durchgang mit einer Verzögerung von einer halben Sekunde (Z. 1330, der Einfluss der anderen Befehle in der Prozedur ist nicht ausgemessen). Direkt nach der Verzögerung erfolgt die Synchronisation mit der FLASH-Ausgabe wie oben beschrieben (Z. 1340). Um möglichst ähnlich zu reagieren wie der PAUSE-Befehl (siehe Z. 1280), kann man die Prozedur mit Tastendruck abbrechen (Z. 1320).
Das Interessante an PROC blink ist also die Möglichkeit, auch kürzere Zeitverzögerungen als die auf volle Sekunden beschränkten PAUSE-Werte zu erhalten. Hier der Algorithmus dazu (für 30 Sechzigstel Sekunden):
poke $c516,0: repeat: until peek($c516)>30
Ist PROC blink abgearbeitet, wird zunächst Entwarnung gegeben (Z. 1260 bis 1280) und dann aufgeräumt und der ursprüngliche Zustand des Bildschirms wiederhergestellt (Z. 1260 bis 1290). Mit "Thank you!" endet daraufhin das Programm (in Z. 210/999). Es ist unter dem Namen "alert.dmo" auch auf der TSB-Disk zu finden.