(****************************************************************************) (* Bibliotheks-Modul WINDOW.BIB *) (* Allgemeine Fenstertechnik ohne direkten Bildschirm-Zugriff *) (* Vorausgesetzt wird das INCLUDE-File WINDOW.PAR mit den entsprechen- *) (* den Parametern fuer Grafikzeichen, Bildschirmgroesse und ConOut. *) (* Falls ConOut unbekannt, gibt 'writeln(ConOutPtr)' Auskunft *) (* *) (* Folgende Bezeichner sind privat und sollten nicht benuetzt werden: *) (* (t Screen Bildschirm) *) (* (t Attribut Flag fuer High- und LowVideo) *) (* (t WindowPtr, t WindowInh gefaehrlich dynamisch!) *) (* (v OrgConOut, v TmpConOut) *) (* (v Window die maximal 255 Fenster) *) (* (v ActScreen, v ActAttr der momentane Bildschirm) *) (* (p wrtchar, p CLS, p InvVideo, p NorVideo, p EraEol) *) (* (p wwrite, p RewriteScreen, p MoveScreen, p RemoveScreen) *) (* *) (* Das Modul liefert folgende Bezeichner und High-Level-Routinen: *) (* p InitWindows schaltet die Fenstertechnik ein *) (* p ExitWindows schaltet sie wieder aus *) (* p OpenWindow(x1,y1,x2,y2) Oeffnet ein Fenster von *) (* (x1,y1)=LinksOben bis (x2,y2)=RechtsUnten *) (* p CloseWindow schliesst das letzte Fenster *) (* p SelWindow(Nr) Holt bei ueberlappenden Fenstern das Nr-te *) (* nach vorn und macht es aktiv *) (* p ChangeWindow(Nr) wie Selwindow, wenn sich die Fenster nicht *) (* ueberlappen. *) (* v inverse : boolean gibt an, ob gerade LowVideo gilt *) (* v ScreenPtr : byte gibt die Nummer des gerade aktiven Fensters *) (* v initialisiert : boolean gibt an, ob InitWindows aufgerufen wurde*) (* v MaxScreen : byte ist die Anzahl der geoeffneten Fenster *) (* f WhereX : integer Cursor-Spalte *) (* f WhereY : integer Cursor-Zeile *) (* *) (* Neu definiert wurden folgende Prozeduren, die sich nun allesamt auf *) (* das aktive Fenster beziehen: *) (* ClrScr, gotoxy, ClrEol, LowVideo, NormVideo, HighVideo, InsLine, *) (* DelLine , letztere funktionieren nur in Fenstern! *) (****************************************************************************) CONST ScreenPtr : byte = 0; (* gibt die Anzahl der eroeffneten Fenster an *) inverse : boolean = false; OrgConOut : integer = ConOut; (* Zeigt auf Standard-Ausgabe *) TmpConOut : integer = ConOut; (* Zeigt spaeter auf Spezialausgabe *) initialisiert : boolean = false; TYPE Screen = ARRAY[1..BildschirmZeilen,1..BildschirmSpalten] OF char; attribut = ARRAY[1..BildschirmZeilen,1..BildschirmSpalten] OF byte; windowPtr = ^windowinh; windowinh = RECORD x1,y1,x2,y2 : byte; (* Fenster-Koordinaten *) cx, cy : byte; (* letzte Cursor-Position *) ScrPtr : ^Screen; (* Zeiger auf Zwischenspeicher *) AttPtr : ^Attribut; (* Zeiger auf ZwischenSpeicher *) END; VAR Window : ARRAY[byte] OF windowPtr; ActScreen : screen; ActAttr : Attribut; MaxScreen : byte; PROCEDURE wrtchr(c:char); BEGIN BDOS(2,ord(c)) (* CP/M-80 *) (* INLINE($FF/$B6/C/$2E/$FF/$16/ORGCONOUT) andere Versionen *) END; PROCEDURE CLS; BEGIN ClrScr; IF initialisiert THEN WITH Window[0]^ DO BEGIN fillchar(ActAttr,SizeOf(Attribut),0); fillchar(ActScreen,SizeOf(Screen),' '); cx:=1; cy:=1 END END; PROCEDURE locate(x,y : byte); BEGIN ConOutPtr:=OrgConOut; gotoxy(x,y); ConOutPtr:=TmpConOut END; PROCEDURE InvVideo; BEGIN ConOutPtr:=OrgConOut; LowVideo; ConOutPtr:=TmpConOut; END; PROCEDURE NorVideo; BEGIN ConOutPtr:=OrgConOut; NormVideo; ConOutPtr:=TmpConOut; END; PROCEDURE EraEol; BEGIN ConOutPtr:=OrgConOut; ClrEol; ConOutPtr:=TmpConOut; END; PROCEDURE RewriteScreen(x1,y1,x2,y2:integer); VAR i,j : integer; v,w : boolean; BEGIN v:=false; NorVideo; FOR i:=y1 TO y2 DO BEGIN locate(x1,i); FOR j:=x1 TO x2-ord((y2=BildSchirmZeilen) AND (x2=BildSchirmSpalten)) DO BEGIN w:=(ActAttr[i,j] AND 128)>0; IF v XOR w THEN IF v AND NOT w THEN NorVideo ELSE InvVideo; v:=w; wrtchr(ActScreen[i,j]) END END; IF inverse THEN InvVideo END; PROCEDURE DelLine; LABEL exit; VAR i,s : integer; BEGIN IF NOT initialisiert THEN GOTO EXIT; WITH Window[ScreenPtr]^ DO BEGIN s:=pred(x2-x1); FOR i:=succ(cy) TO pred(y2) DO BEGIN move(ActAttr[i,succ(x1)],ActAttr[pred(i),succ(x1)],s); move(ActScreen[i,succ(x1)],ActScreen[pred(i),succ(x1)],s); END; fillchar(ActAttr[pred(y2),succ(x1)],s,0); fillchar(ActScreen[pred(y2),succ(x1)],s,32); RewriteScreen(succ(x1),cy,pred(x2),pred(y2)); locate(cx,cy) END; EXIT: END; PROCEDURE InsLine; LABEL EXIT; VAR i,s,r : integer; BEGIN IF NOT initialisiert THEN GOTO EXIT; WITH Window[ScreenPtr]^ DO BEGIN s:=pred(x2-x1); r:=x2-cx; FOR i:=pred(y2) DOWNTO cy+2 DO BEGIN move(ActAttr[pred(i),succ(x1)],ActAttr[i,succ(x1)],s); move(ActScreen[pred(i),succ(x1)],ActScreen[i,succ(x1)],s); END; fillchar(ActAttr[succ(cy),succ(x1)],s,0); fillchar(ActScreen[succ(cy),succ(x1)],s,32); move(ActAttr[cy,cx],ActAttr[succ(cy),succ(x1)],r); move(ActScreen[cy,cx],ActScreen[succ(cy),succ(x1)],r); fillchar(ActAttr[cy,cx],r,0); fillchar(ActScreen[cy,cx],r,32); RewriteScreen(succ(x1),cy,pred(x2),pred(y2)); locate(cx,cy) END; EXIT: END; PROCEDURE wwrite(c : char); (*$R-*) PROCEDURE scroll; (* Scrollt das aktuelle Fenster! *) VAR i : 1..BildschirmZeilen; BEGIN WITH Window[ScreenPtr]^ DO BEGIN cy:=succ(y1); DelLine; cy:=pred(y2); locate(cx,cy) END END; BEGIN (* wwrite *) WITH Window[ScreenPtr]^ DO BEGIN IF ord(c)<32 THEN CASE c OF ^H : cx:=pred(cx); ^J : cy:=succ(cy); ^M : cx:=succ(x1); ^G : wrtchr(c); END ELSE BEGIN ActScreen[cy,cx]:=c; wrtchr(c); IF inverse THEN ActAttr[cy,cx]:=ActAttr[cy,cx] OR 128 ELSE ActAttr[cy,cx]:=ActAttr[cy,cx] AND 127; cx:=succ(cx); END; IF cx=x1 THEN IF cy=succ(y1) THEN BEGIN cx:=succ(x1); cy:=succ(y1) END ELSE BEGIN cy:=pred(cy); cx:=pred(x2); locate(cx,cy) END; IF cx=x2 THEN BEGIN cy:=succ(cy); cx:=succ(x1) END; IF cy=y2 THEN scroll; IF (cx=succ(x1)) OR (c=^H) THEN locate(cx,cy); END; (* with *) END; (* wwrite *) (****************************************************************************) (* Bildschirm-Handling *) (****************************************************************************) PROCEDURE gotoxy(x,y : byte); LABEL EXIT; VAR xNeu, yNeu : byte; BEGIN IF NOT initialisiert THEN BEGIN locate(x,y); GOTO exit END; WITH Window[ScreenPtr]^ DO BEGIN xNeu:=x+x1; yNeu:=y+y1; IF xNeu<=BildschirmSpalten THEN IF yNeu<=BildschirmZeilen THEN BEGIN locate(xNeu,yNeu); cx:=xNeu; cy:=yNeu; END END; EXIT: END; PROCEDURE LowVideo; BEGIN inverse:=true; InvVideo; END; PROCEDURE NormVideo; BEGIN inverse:=false; NorVideo; END; PROCEDURE Highvideo; BEGIN NormVideo END; PROCEDURE ClrEol; VAR i : byte; BEGIN IF ScreenPtr=0 THEN EraEol ELSE IF initialisiert THEN WITH Window[ScreenPtr]^ DO BEGIN FOR i:=cx TO pred(x2) DO BEGIN ActAttr[cy,i]:=0; ActScreen[cy,i]:=' '; wrtchr(' '); END; locate(cx,cy) END; END; PROCEDURE ClrScr; VAR i,s : integer; BEGIN IF (ScreenPtr=0) OR NOT initialisiert THEN CLS ELSE WITH Window[ScreenPtr]^ DO BEGIN s:=pred(x2-x1); FOR i:=succ(y1) TO pred(y2) DO BEGIN fillchar(ActAttr[i,succ(x1)],s,0); fillchar(ActScreen[i,succ(x1)],s,32) END; RewriteScreen(succ(x1),succ(y1),pred(x2),pred(y2)); END; gotoxy(1,1) END; FUNCTION WhereX : integer; BEGIN WITH Window[ScreenPtr]^ DO WhereX:=cx-x1 END; FUNCTION WhereY : integer; BEGIN WITH Window[ScreenPtr]^ DO WhereY:=cy-y1 END; (****************************************************************************) (* Fenster-Hilfs-Prozeduren *) (****************************************************************************) PROCEDURE MoveScreen(a1,b1,a2,b2 : Byte; VAR P,T); { Privat } VAR TempScr : ARRAY[1..2000] OF char ABSOLUTE P; TempAtt : ARRAY[1..2000] OF byte ABSOLUTE T; dx, j : byte; BEGIN dx:=succ(a2-a1); FOR j:=b1 TO b2 DO BEGIN move(ActScreen[j,a1],TempScr[(j-b1)*dx+1],dx); move(ActAttr[j,a1],TempAtt[(j-b1)*dx+1],dx); END END; PROCEDURE RemoveScreen(a1,b1,a2,b2 : byte; VAR P,T); { Privat } VAR TempScr : ARRAY[1..2000] OF char ABSOLUTE P; TempAtt : ARRAY[1..2000] OF byte ABSOLUTE T; dx, j : byte; BEGIN dx:=succ(a2-a1); FOR j:=b1 TO b2 DO BEGIN move(TempAtt[(j-b1)*dx+1],ActAttr[j,a1],dx); move(TempScr[(j-b1)*dx+1],ActScreen[j,a1],dx); END END; (****************************************************************************) (* Fensterwahl fuer ueberlappende Fenster *) (****************************************************************************) PROCEDURE SelWindow(x:byte); LABEL EXIT; VAR i:byte; PROCEDURE Swap(i:byte); VAR Size : integer; tScr : ^Screen; tAttr : ^Attribut; BEGIN WITH window[i]^ DO BEGIN Size:=succ(abs(x2-x1))*succ(abs(y2-y1)); getmem(tScr,Size); getmem(tAttr,Size); MoveScreen(x1,y1,x2,y2,tScr^,tAttr^); RemoveScreen(x1,y1,x2,y2,ScrPtr^,AttPtr^); freemem(ScrPtr,Size); freemem(AttPtr,Size); ScrPtr:=tScr; AttPtr:=tAttr END END; BEGIN IF NOT initialisiert OR (x > MaxScreen) THEN GOTO EXIT; IF ScreenPtr <> MaxScreen THEN IF ScreenPtr=0 THEN FOR i:=1 TO MaxScreen DO Swap(i) ELSE BEGIN Swap(ScreenPtr); FOR i:=MaxScreen DOWNTO ScreenPtr+1 DO Swap(i); FOR i:=ScreenPtr TO MaxScreen DO Swap(i) END; IF x <> MaxScreen THEN IF x=0 THEN FOR i:=MaxScreen DOWNTO 1 DO Swap(i) ELSE BEGIN FOR i:=MaxScreen DOWNTO x DO swap(i); FOR i:=x+1 TO MaxScreen DO Swap(i); Swap(x) END; IF (ScreenPtr=0) OR (x=0) THEN RewriteScreen(1,1,BildSchirmSpalten,BildSchirmzeilen) ELSE BEGIN WITH window[ScreenPtr]^ DO RewriteScreen(x1,y1,x2,y2); WITH window[x]^ DO RewriteScreen(x1,y1,x2,y2) END; ScreenPtr:=x; WITH window[ScreenPtr]^ DO locate(cx,cy); EXIT: END; (****************************************************************************) (* Fensterwahl bei nebeneinanderliegenden Fenstern *) (****************************************************************************) PROCEDURE ChangeWindow(x : byte); BEGIN IF initialisiert THEN IF x<=MaxScreen THEN BEGIN ScreenPtr:=x; WITH Window[ScreenPtr]^ DO locate(cx,cy) END END; (****************************************************************************) (* Oeffnen eines Fensters *) (****************************************************************************) PROCEDURE OpenWindow(a1,b1,a2,b2:byte); LABEL exit; VAR Size : integer; i, j : byte; PROCEDURE NewWindow; (* Malt den Rahmen und loescht den Bereich *) VAR i : integer; BEGIN FOR i:=b1 TO b2 DO fillchar(ActAttr[i,a1],succ(a2-a1),0); ActScreen[b1,a1]:=LinksOben; ActScreen[b1,a2]:=RechtsOben; ActScreen[b2,a1]:=LinksUnten; ActScreen[b2,a2]:=RechtsUnten; FOR i:=succ(a1) TO pred(a2) DO BEGIN ActScreen[b1,i]:=WaagrechtO; ActScreen[b2,i]:=WaagrechtU END; FOR i:=succ(b1) TO pred(b2) DO BEGIN ActScreen[i,a1]:=SenkrechtL; ActScreen[i,a2]:=SenkrechtR; fillchar(ActScreen[i,succ(a1)],pred(a2-a1),32); END; RewriteScreen(a1,b1,a2,b2) END; BEGIN IF NOT initialisiert THEN GOTO exit; IF (a1<1) OR (a2>BildschirmSpalten) OR (a1>a2) OR (b1<1) OR (b2>BildschirmZeilen ) OR (b1>b2) THEN GOTO exit; IF ScreenPtr <> MaxScreen THEN SelWindow(MaxScreen); inverse:=false; NormVideo; ScreenPtr:=succ(ScreenPtr); new(Window[ScreenPtr]); WITH Window[ScreenPtr]^ DO BEGIN x1:=a1; y1:=b1; x2:=a2; y2:=b2; cx:=succ(a1); cy:=succ(b1); Size:=succ(abs(x2-x1))*succ(abs(y2-y1)); getmem(ScrPtr,Size); getmem(AttPtr,Size); MoveScreen(a1,b1,a2,b2,ScrPtr^,AttPtr^); NewWindow END; MaxScreen:=ScreenPtr; gotoxy(1,1); exit: END; (****************************************************************************) (* CloseWindow - schliesst das letzte Fenster *) (****************************************************************************) PROCEDURE CloseWindow; LABEL EXIT; VAR Size : integer; i, j : byte; BEGIN IF (ScreenPtr=0) OR NOT initialisiert THEN GOTO exit; IF ScreenPtr <> MaxScreen THEN SelWindow(MaxScreen); WITH Window[ScreenPtr]^ DO BEGIN NormVideo; RemoveScreen(x1,y1,x2,y2,ScrPtr^,AttPtr^); RewriteScreen(x1,y1,x2,y2); Size:=succ(abs(x2-x1))*succ(abs(y2-y1)); freemem(ScrPtr,Size); freemem(AttPtr,Size); END; dispose(Window[ScreenPtr]); ScreenPtr:=pred(ScreenPtr); MaxScreen:=ScreenPtr; locate(Window[ScreenPtr]^.cx,Window[ScreenPtr]^.cy); EXIT: END; (****************************************************************************) (* Init/ExitWindows - Initialisierung der Fenstertechnik *) (****************************************************************************) PROCEDURE InitWindows; (* Erste Anweisung im Programm *) BEGIN initialisiert:=true; ScreenPtr:=0; MaxScreen:=0; new(Window[0]); WITH Window[0]^ DO BEGIN CLS; ScreenPtr:=0; x1:=0; y1:=0; x2:=succ(BildschirmSpalten); y2:=succ(BildschirmZeilen) END; OrgConOut:=ConOutPtr; TmpConOut:=addr(wwrite); (* ofs(wwrite) bei MS-DOS oder CP/M-86 *) ConOutPtr:=TmpConOut END; PROCEDURE ExitWindows; (* Letzte Anweisung im Programm *) BEGIN ConOutPtr:=OrgConOut; initialisiert:=false END;