UNIT bildschirm; {$project vt } { Bildschirmausgaben zum Programm VideoText } INTERFACE; FROM vt USES pagelist,decode,cct,sys; CONST colht=15; VAR jobcursor: Boolean; { >Markierung in der Job- oder in der Seitenliste? } incomplete: Boolean; { Seitenaufbau unterbrochen? } concealed: Boolean; { verdeckte Zeichen wirklich verdeckt? } PROCEDURE cursoroff; PROCEDURE cursoron; PROCEDURE mainline; FUNCTION ja_nein: Boolean; PROCEDURE mark_queue(really: Boolean); PROCEDURE redraw_queue(job: Integer); PROCEDURE space_in_queue; FUNCTION pos_from_queue(x,y: Integer): Integer; PROCEDURE mark_list(really: Boolean); PROCEDURE redraw_list; PROCEDURE update_list(start: p_onepage; delta: Integer); FUNCTION page_from_list(x,y: Integer): p_onepage; PROCEDURE fileinfo; PROCEDURE test(active: Boolean); PROCEDURE writepage(seite: p_onepage, verdeckt: Boolean); FUNCTION number_from_page(x,y: Integer): Integer; PROCEDURE redraw_all; FUNCTION click_action(x,y: Integer): Char; { ---------------------------------------------------------------------- } IMPLEMENTATION; {$opt q,s+,i+ } { keine Laufzeitprüfungen außer Stack und Feldindizes } CONST head=7; tail=6; { Aufteilung der Warteschlange } sp_maxdisp=15; VAR listoffset: Integer; fix1,fix2,fix3: Integer; { fileinfo-x-Positionen } PROCEDURE cursoroff; BEGIN Write(#155'0 p'); { Cursor unsichtbar } END; PROCEDURE cursoron; BEGIN Write(#155' p'); { Cursor wieder sichtbar } END; PROCEDURE mainline; BEGIN GotoXY(1,24); Write(#155'0m',Copy(blank40,1,39)); GotoXY(1,24); END; FUNCTION ja_nein{: Boolean}; VAR ch: Char; BEGIN cursoron; Write(' (J/N)? '); REPEAT Delay(2); Write(#8' '#8); ch := waitkey; IF (Ord(ch) MOD 128)>31 THEN Write(ch) ELSE Write(' '); UNTIL ch IN ['j', 'J', 'n', 'N'] ja_nein := ch IN ['j', 'J']; cursoroff; END; PROCEDURE mark_queue{(really: Boolean)}; { Gibt die Position des Job-Markers als '>' am Bildschirm aus, } { kann Werte von -1 bis - annehmen. } { Für =FALSE wird stattdessen ' ' ausgegeben. } CONST x0=1; y0=1; VAR y,j: Integer; special: Boolean; BEGIN special := False; y := y0 + maxactive - thisjob; IF thisjob<0 THEN BEGIN y := y + 2; IF NOT fifo THEN y := y + 1; IF (queued>=colht) AND (-thisjob>head) THEN BEGIN { unvollständige Anzeige der Schlange } IF -thisjob>queued-tail THEN y := y + colht-1 - queued { zeigt auf hinteres Ende } ELSE BEGIN special := True; y := y + thisjob + head + 1; { zeigt auf die '...' } j := (firstinq - thisjob - 2) MOD qlen + 1; END; END; END; GotoXY(x0,y); Write(#155'0m'); IF really THEN Write('>') ELSE Write(' '); IF special THEN BEGIN Write('(',hexstr(queue[j].pg,0),')'); END; END; PROCEDURE redraw_queue{(job: Integer)}; { Gibt für job<0 die aktuelle Belegung der Warteschlange und der aktiven Jobs } { am Bildschirm aus, sonst wird nur der Job mit der angegebenen Nummer neu } { ausgegeben: interessant ist dabei vor allem der Status der eingelesenen } { Unterseiten. } CONST x0=1; y0=1; VAR i,j,y,max: Integer; BEGIN GotoXY(x0,y0); Write(#155'0m Seitensuche:'); FOR j := 0 TO maxactive-1 DO IF (job<0) OR (j=job) THEN WITH activejobs[j] DO BEGIN GotoXY(x0,maxactive+y0-j); Write(Copy(blank40,1,25)); { nicht das Testfeld überschreiben! } GotoXY(x0+1,maxactive+y0-j); IF pg=0 THEN Write('---') ELSE BEGIN Write(hexstr(pg,0)); CASE sp OF -3: Write('/!'); -2: Write('/.'); -1: Write('/*'); 0: ; OTHERWISE Write('/',hexstr(sp,0)); END; Write(' '); IF sp_check[0] THEN Write('+'); IF sp_max>0 THEN { echte Unterseiten eingetroffen } IF sp<>0 THEN { zu einer Einzelanforderung? } Write('+') ELSE BEGIN max := bcd(sp_max); IF max>sp_maxdisp THEN max := sp_maxdisp-2; Write('('); FOR i := 1 TO max DO IF sp_check[i] THEN Write('+') ELSE Write('-'); IF bcd(sp_max)>max THEN Write('...') ELSE Write(')'); END; END; END; GotoXY(x0,y0+2+maxactive); Write(' Jobs:'); IF job<0 THEN BEGIN y := y0 + 3 + maxactive; IF fifo THEN y := y + colht - 1; GotoXY(x0,y); Write(' '); FOR j := 1 TO colht-1 DO BEGIN y := j+y0+2+maxactive; IF NOT fifo THEN y := y + 1; GotoXY(x0,y); Write(' '); IF j<=queued THEN BEGIN GotoXY(x0+1,y); i := (firstinq + j - 2) MOD qlen + 1; IF (queued>=colht) AND (j>head) THEN i := (firstinq + queued + j - colht - 1) MOD qlen + 1; IF (queued>=colht) AND (j=head+1) THEN Write('...') ELSE WITH queue[i] DO BEGIN Write(hexstr(pg,0)); CASE sp OF -3: Write('/!'); -2: Write('/.'); -1: Write('/*'); 0: ; OTHERWISE Write('/',hexstr(sp,0)); END; END; END; END; { Ende FOR-Schleife } END; IF jobcursor THEN mark_queue(True); END; PROCEDURE space_in_queue; { den für Eingaben reservierten Platz in der Warteschlange ansteuern } CONST x0=1; y0=1; BEGIN IF NOT fifo THEN GotoXY(x0+1,y0+3+maxactive) ELSE IF queuedx0+8) THEN Exit; IF (y>y0) AND (y<=y0+maxactive) THEN pos_from_queue := maxactive + y0 - y { Position in der Seitensuche } ELSE BEGIN y := y - y0 - maxactive - 2; IF NOT fifo THEN Dec(y); IF (y>0) AND (y wird hier neu } { berechnet. Der Rückgabewert sagt, um wieviele Spalten die Liste (falls } { bereits angezeigt) verschoben werden muß. (>0: rechts kommen Spalten dazu) } VAR nr,delta: Integer; hilf: p_onepage; BEGIN { Herausfinden, die wievielte Seite in der Liste ist: } hilf := root; nr := 0; WHILE (hilf<>Nil) AND (hilf<>thispage) DO BEGIN hilf := hilf^.next; Inc(nr); END; delta := 0; WHILE nr=cols*colht DO BEGIN listoffset := listoffset+colht; Inc(delta); END; adjust_offset := delta; END; PROCEDURE listentry(ch: Char; seite: p_onepage; nr: Integer); { Einen Listeneintrag erzeugen, von dem seine Nummer im sichtbaren Bereich } { der Liste bekannt ist. ist normalerweise '?', oder ' ', '>' um eins } { der beiden Zeichen zu erzwingen. } VAR x,y: Integer; BEGIN x := x0+colw*(nr DIV colht); y := y0+1+nr MOD colht; GotoXY(x,y); IF ch='?' THEN BEGIN Write(#155'0m',lspc); GotoXY(x,y); IF NOT jobcursor AND (seite=thispage) THEN ch :='>' ELSE ch := ' '; END; IF seite<>Nil THEN Write(ch,hexstr(seite^.pg,0),'/',hexstr(seite^.sp,0)); END; PROCEDURE redraw_column(col: Integer); { gibt eine Spalte der Seitenliste aus } VAR i: Integer; hilf: p_onepage; BEGIN hilf := root; FOR i := 1 TO listoffset+(col-1)*colht DO IF hilf<>Nil THEN hilf := hilf^.next; FOR i := 1 TO colht DO BEGIN listentry('?',hilf,(i-1)+(col-1)*colht); IF hilf<>Nil THEN hilf := hilf^.next; END; END; PROCEDURE mark_list{(really: Boolean)}; { Gibt die Position des Seiten-Markers am Bildschirm aus, für } { =FALSE wird die Markierung dagegen aufgehoben. } { Scrollt die Liste auch weiter, falls nötig. } VAR nr,i: Integer; dx: Integer; hilf: p_onepage; BEGIN { scrollen? } dx := adjust_offset; FOR i := cols DOWNTO 1 DO BEGIN IF dx>=i THEN scroll_text(y0+1,y0+colht,x0,x0+cols*colw-1,0,colw); IF dx<=-i THEN scroll_text(y0+1,y0+colht,x0,x0+cols*colw-1,0,-colw); END; FOR i := 1 TO cols DO IF (i+dx>cols) OR (i+dx<1) THEN redraw_column(i); { Herausfinden, die wievielte Seite in der Liste ist: } hilf := root; nr := 0; WHILE (hilf<>Nil) AND (hilf<>thispage) DO BEGIN hilf := hilf^.next; Inc(nr); END; nr := nr-listoffset; IF really THEN listentry('>',thispage,nr) ELSE listentry(' ',thispage,nr); END; PROCEDURE redraw_list; { aktualisiert die gesamte Seitenliste } VAR i: Integer; hilf: p_onepage; BEGIN IF adjust_offset<>0 THEN; { Wert ist egal } GotoXY(x0,y0); Write(#155,'0m Im Speicher:'); hilf := root; FOR i := 1 TO listoffset DO IF hilf<>Nil THEN hilf := hilf^.next; FOR i := 0 TO cols*colht-1 DO BEGIN listentry('?',hilf,i); IF hilf<>Nil THEN hilf := hilf^.next; END; END; PROCEDURE redraw_rows(rows: Integer); { gibt die ersten bzw. die letzten <-rows> Zeilen der Seitenliste } { aus, nicht ganz trivial } VAR i,j: Integer; hilf: p_onepage; BEGIN hilf := root; FOR i := 1 TO listoffset DO IF hilf<>Nil THEN hilf := hilf^.next; FOR i := 1 TO cols DO FOR j := 1 TO colht DO BEGIN IF (j<=rows) OR (j>colht+rows) THEN listentry('?',hilf,(j-1)+(i-1)*colht); IF hilf<>Nil THEN hilf := hilf^.next; END; END; PROCEDURE update_list{(start: p_onepage; delta: Integer)}; { Es wurden Seiten in die Liste eingefügt (delta>0) bzw. entfernt (delta<0). } { ist die erste Seite, die sich dadurch geändert hat. } VAR i,nr: Integer; hilf: p_onepage; BEGIN { Herausfinden, wo auf dem Bildschirm die bezeichnete Seite ist } hilf := root; nr := 0; WHILE (hilf<>Nil) AND (hilf<>start) DO BEGIN hilf := hilf^.next; Inc(nr); END; nr := nr-listoffset; { ein paar Spalten komplett scrollen, eine nur zum Teil } FOR i := 1 TO cols DO BEGIN IF (i-1)*colht>=nr THEN scroll_text(y0+1,y0+colht,x0+(i-1)*colw,x0+i*colw-1,-delta,0) ELSE IF i*colht>=nr+Abs(delta) THEN scroll_text(y0+1+nr MOD colht,y0+colht,x0+(i-1)*colw,x0+i*colw-1,-delta,0) END; hilf := start; FOR i := 0 TO delta-1 DO BEGIN IF (nr+i=0) THEN listentry('?',hilf,nr+i); IF hilf<>Nil THEN hilf := hilf^.next; END; redraw_rows(delta); { '>' neu setzten, hat evtl. sogar den Bildschirm verlassen: } mark_list(NOT jobcursor); END; FUNCTION page_from_list{(x,y: Integer): p_onepage}; { zu einer angeklickten Zeichenposition die Seite herausfinden } VAR nr: Integer; hilf: p_onepage; BEGIN page_from_list := Nil; IF (y IN [y0+1..y0+colht]) AND (x IN [x0-2..x0+cols*colw+2]) THEN BEGIN nr := listoffset + y - (y0+1) + colht*(Round((x-x0)/colw+0.5)-1); hilf := root; IF hilf<>Nil THEN WHILE (hilf^.next<>Nil) AND (nr>0) DO BEGIN hilf := hilf^.next; Dec(nr); END; IF nr=0 THEN page_from_list := hilf; END ELSE IF (y=y0) AND (x IN [x0..x0+12]) THEN { Überschrift angeklickt } page_from_list := root; END; PROCEDURE fileinfo; CONST x0=1; y0=26; BEGIN GotoXY(x0,y0); Write(#155'0mDatei ('); fix1 := x0 + 7; fix2 := fix1 + 4; IF asciifile THEN BEGIN Write('ASCII, '); fix2 := fix2 + 3; END ELSE Write('VT, '); fix3 := fix2 + 11; IF overwrite THEN BEGIN Write('}berschr.): '); fix3 := fix3 + 1; END ELSE Write('anf}gend): '); Write(#155'2m',outputname); IF withicon THEN Write(#155'0m, mit Icon'); ClrEoL; END; PROCEDURE test{(active: Boolean)}; { Decodertest, sollte aus einer Schleife heraus aufgerufen werden. } { für active=false wird ein leeres Testfeld erzeugt. } CONST x0=26; y0=1; VAR stat: Byte; i: Integer; zeit: str80; ch: char; tag,min,tic: Long; PROCEDURE zweistellig(x: Integer); BEGIN Write(x DIV 10, x MOD 10); END; BEGIN GotoXY(x0,y0); Write(#155'0mStatus:'); IF NOT active THEN BEGIN FOR stat := 1 TO 5 DO BEGIN GotoXY(x0,y0+stat); Write(' '); { 13 Spaces } END; Write(#155,'2m'); END; GotoXY(x0,y0+1); Write('Bus:'); GotoXY(x0+5,y0+1); Write('AV:'); GotoXY(x0+5,y0+2); Write('VT:'); GotoXY(x0,y0+3); Write(' VT:'); GotoXY(x0,y0+4); Write('Sys:'); IF active THEN BEGIN Write(#155,'2m'); stat := VTstat; GotoXY(x0,y0+2); IF i2c_status=0 THEN Write('OK ') ELSE Write('Err',i2c_status); FOR i := 1 TO 2 DO BEGIN GotoXY(x0+9,y0+i); IF i2c_status=0 THEN IF (stat AND i)<>0 THEN Write('ja ') ELSE Write('nein') ELSE Write(' ') END; { Zeit aus dem VT-Seitenspeicher abfragen: } gettime(aktspeicher,zeit); GotoXY(x0+5,y0+3); Write(zeit); { zum Vergleich: Amiga-Zeit } telltime(tag,min,tic); GotoXY(x0+5,y0+4); zweistellig(min DIV 60); Write(':'); zweistellig(min MOD 60); Write(':'); zweistellig(tic DIV 50); END; Write(#155'0m'); END; PROCEDURE writepage{(seite: p_onepage, verdeckt: Boolean)}; { Seite am Bildschirm ausgeben } CONST xoff = 40; VAR zeile,i,j,j0: Integer; farbe,farbe0: Word; out: bigstring; x: Byte; s,attrib: str80; dblheight,rastergfx,special: Boolean; normal: String[10]; BEGIN visblpage := seite; concealed := verdeckt; normal := #155'0;3'+colperms[7]+';4'+colperms[0]+'m'; { weiß auf schwarz } incomplete := True; dblheight := False; rastergfx := False; IF seite<>Nil THEN seite^.chars[0] := 2; { Seitennummer zunächst grün } for i := 0 to 24 do begin zeile := i MOD 24; IF i=24 THEN BEGIN { 1. Zeile nochmal, mit weißer Seitennummer: } IF seite<>Nil THEN seite^.chars[0] := 7; dblheight := False; incomplete := False; { Seite komplett } END; IF dblheight THEN { auf eine doppelthohe Zeile folgt nur eine leere Zeile } dblheight := False ELSE BEGIN { normale Zeile ausgeben } IF seite<>Nil THEN decode_line(seite, zeile, verdeckt, out, attrib, dblheight, rastergfx) ELSE out := blank40; GotoXY(xoff,zeile+1); Write(normal,out,normal,' '); IF rastergfx THEN BEGIN { Zeile, die gerasterte Grafikzeichen enthält } special := False; farbe := 0; FOR j := 0 TO 39 DO BEGIN { zu rasternde Abschnitte suchen } farbe0 := farbe; farbe := Ord(attrib[j+1]); IF (farbe<>farbe0) AND special THEN BEGIN raster_line(zeile+1,xoff+j0,xoff+j-1,farbe0 AND 7); j0 := j; special := (farbe AND 16<>0); END; IF (farbe AND 16<>0) AND NOT special THEN BEGIN j0 := j; special := True; END; END; IF special THEN raster_line(zeile+1,xoff+j0,xoff+39,farbe0 AND 7); END; IF zeile=23 THEN dblheight := False; { unterste Zeile nie doppelthoch! } IF dblheight THEN BEGIN { Handhabung doppelthoher Zeilen } special := False; FOR j := 1 TO Length(out) DO BEGIN { alles außer den ANSI-Codes } { entfernen -> erzeugt Kopie der Hintergrundfarben der Zeile } IF out[j] = #155 THEN special := True; IF NOT special THEN out[j] := ' '; IF out[j] = 'm' THEN special := False; END; GotoXY(xoff,zeile+2); Write(normal,out,normal,' '); special := False; FOR j := 0 TO 39 DO { doppelthohe Abschnitte suchen } CASE seite^.chars[40*zeile+j] OF 13: BEGIN j0 := j; special := True; END; 12: IF special THEN BEGIN stretch_line(zeile+1,xoff+j0,xoff+j); special := False; END; OTHERWISE; END; IF special THEN stretch_line(zeile+1,xoff+j0,79); END; END; lastkey := readkey; { Taste: Abbruch und Rückmeldung ans HP } intui_events; IF (lastkey<>chr(0)) OR stop THEN Exit; END; END; FUNCTION number_from_page{(x,y: Integer): Integer}; { versucht zu einer angeklickten Bildschirmposition herauszufinden, auf } { was für eine Nummer geklickt wurde } VAR i,j,j0,n,m: Integer; ok: Boolean; CONST xoff = 40; BEGIN n := -1; IF (x IN [xoff..xoff+39]) AND (y IN [1..24]) AND (visblpage<>Nil) THEN BEGIN i := 40*(y-1); ok := True; j0 := x-xoff; FOR j := x-xoff DOWNTO 0 DO BEGIN IF NOT (visblpage^.chars[i+j] IN [48..57]) THEN ok := False; IF ok THEN j0 := j; END; ok := True; n := 0; m := 0; FOR j := j0 TO 39 DO BEGIN IF NOT (visblpage^.chars[i+j] IN [48..57]) THEN ok := False; IF ok THEN BEGIN n := (n SHL 4) + visblpage^.chars[i+j]-48; Inc(m); END; END; IF m=0 THEN n := -1; { keine Ziffern gefunden } END; number_from_page := n; END; PROCEDURE redraw_all; { kompletter Neuaufbau des Bildschirms, inklusive clrscr } BEGIN ClrScr; writepage(thispage,True); test(False); redraw_queue(-1); redraw_list; fileinfo; END; FUNCTION click_action{(x,y: Integer): Char}; { Ein paar bestimmte Sachen, die man anklicken kann } BEGIN click_action := ' '; IF (y=1) AND (x IN [26..32]) THEN click_action := 'T'; { "Status" } IF (y=1) AND (x IN [2..13]) THEN click_action := 'S'; { "Seitensuche" } IF (y=7) AND (x IN [2..6]) THEN click_action := 'J'; { "Jobs" } IF (y=26) THEN BEGIN IF x IN [1..fix1-3] THEN click_action := 'D'; { Dateiname } IF x IN [fix1..fix2-3] THEN click_action := 'F'; { Format } IF x IN [fix2..fix3-4] THEN click_action := 'M'; { Modus } IF x IN [fix3..80] THEN click_action := 'I'; { Icon? } END; IF (x>=40) THEN CASE y OF 1..8: click_action := '-'; { oberes Seitendrittel } 17..24: click_action := '+'; { unteres Seitendrittel } OTHERWISE; END; END; BEGIN { Initialisierungsteil } listoffset := 0; jobcursor := False; incomplete := False; concealed := True; END.