home *** CD-ROM | disk | FTP | other *** search
Modula Implementation | 1989-09-29 | 12.8 KB | 557 lines |
- (**********************************************************)
- (* SCREEN.MOD *)
- (* Bildschirmsteuerung per Bios *)
- (* (c) 1989 by Ulrich Mök & toolbox *)
- (**********************************************************)
-
- IMPLEMENTATION MODULE Screen;
-
- (* ---------- Import der Bibliotheksroutinen ------------ *)
-
- FROM SYSTEM IMPORT
- ADDRESS, SEG, OFS, WORD;
-
- FROM System IMPORT
- AX, BX, CX, DX, Trap, Move;
-
- FROM Storage IMPORT
- ALLOCATE, DEALLOCATE, Available;
-
- FROM Strings IMPORT Length;
-
- (* ----------- Typen - Deklaration ---------------------- *)
-
- TYPE
- Register = RECORD
- CASE b : BOOLEAN OF
- TRUE : w : CARDINAL;
- | FALSE : l, h : CHAR;
- END;
- END;
-
- ScreenTyp = RECORD
- CASE b : BOOLEAN OF
- TRUE : p : WORD;
- | FALSE : ch, a : CHAR;
- END;
- END;
-
- BsArray = ARRAY [0..1999] OF WORD;
- GlobTyp = RECORD
- WinX1, WinY1, WinX2, WinY2,
- WinCurX, WinCurY,
- WinAttr : CARDINAL;
- END;
-
- ScrStack = POINTER TO Kopf;
- Kopf = RECORD
- Bs : BsArray;
- prev : ScrStack;
- END;
-
-
- RahmenTyp = ARRAY [einfach..doppelt] OF
- ARRAY [0..5] OF CHAR;
-
- (* ----------- Variablen - Deklaration ------------------ *)
-
- VAR
- RegAX, RegBX,
- RegCX, RegDX : Register;
- BsStack : ScrStack;
- ScrAdr : ADDRESS;
- Punkt : ScreenTyp;
- BsRahmen : RahmenTyp;
- Glob : GlobTyp;
- c : CHAR;
-
-
- (* ----------- Bios - Routinen -------------------------- *)
-
-
- PROCEDURE VideoKarte;
- BEGIN
- RegAX.h := CHR( 15 ); (* Funktionsnummer in AH *)
- AX := RegAX.w;
- Trap( 10H );
- RegAX.w := AX;
- IF ORD( RegAX.l ) = 7 THEN
- ScrAdr.SEG := 0B000H;
- Mono := TRUE;
- ELSE
- ScrAdr.SEG := 0B800H;
- Mono := FALSE;
- END;
- ScrAdr.OFS := 0H;
- END VideoKarte;
-
-
- PROCEDURE CursorGroesse( Start, Ende : CARDINAL );
- (* mögliche Werte : für Start ab 0, für *)
- (* Ende bei CGA 7 und bei Hercules 13 *)
-
- BEGIN
- RegAX.h := CHR( 1 ); (* Funktionsnummer in AH *)
- RegCX.h := CHR( Start );
- RegCX.l := CHR( Ende );
- AX := RegAX.w;
- CX := RegCX.w;
- Trap( 10H );
- END CursorGroesse;
-
-
- PROCEDURE CursorNorm;
- BEGIN
- IF Mono
- THEN CursorGroesse( 11, 12 )
- ELSE CursorGroesse( 6, 7 )
- END;
- END CursorNorm;
-
-
- PROCEDURE CursorBlock;
- BEGIN
- IF Mono
- THEN CursorGroesse( 0, 13 )
- ELSE CursorGroesse( 0, 7 )
- END;
- END CursorBlock;
-
-
- PROCEDURE CursorOff;
- BEGIN
- IF Mono
- THEN CursorGroesse( 13, 0 )
- ELSE CursorGroesse( 7, 0 )
- END;
- END CursorOff;
-
-
- PROCEDURE Goto( x, y : CARDINAL );
- BEGIN
- RegAX.h := CHR( 2 ); (* Funktionsnummer in AH *)
- RegBX.h := CHR( 0 ); (* Bs-Seite in BH *)
- RegDX.h := CHR( y );
- RegDX.l := CHR( x );
- AX := RegAX.w;
- BX := RegBX.w;
- DX := RegDX.w;
- Trap( 10H );
- END Goto;
-
-
- PROCEDURE GotoXY( x, y : CARDINAL );
- BEGIN
- (* Werte auf Fenster umrechnen und Window-Grenzen *)
- (* prüfen; dann ggf. CursorPos setzen *)
-
- IF ( x > 0 ) AND ( y > 0 ) THEN
- x := x + Glob.WinX1 - 2;
- y := y + Glob.WinY1 - 2;
- IF ( x <= Glob.WinX2 ) AND ( y <= Glob.WinY2 ) THEN
- Goto( x, y );
- END;
- END;
- END GotoXY;
-
-
- PROCEDURE WhereX() : CARDINAL;
- BEGIN
- RegAX.h := CHR( 3 ); (* Funktionsnummer in AH *)
- RegBX.h := CHR( 0 ); (* Bs-Seite in BH *)
- AX := RegAX.w;
- BX := RegBX.w;
- Trap( 10H );
- RETURN ORD( RegDX.l ) + 2 - Glob.WinX1;
- END WhereX;
-
-
- PROCEDURE WhereY() : CARDINAL;
- BEGIN
- RegAX.h := CHR( 3 ); (* Funktionsnummer in AH *)
- RegBX.h := CHR( 0 ); (* Bs-Seite in BH *)
- AX := RegAX.w;
- BX := RegBX.w;
- Trap( 10H );
- RETURN ORD( RegDX.h ) + 2 - Glob.WinY1;
- END WhereY;
-
-
- PROCEDURE Scroll( x1,y1,x2,y2, Richtung,
- ZeilenZahl, Attribut : CARDINAL );
- (* Richtung / Up = 6, Dn = 7 *)
- BEGIN
-
- (* Assemblernotation des Fensters = 0,0,79,24 ! *)
- (* also alle Groessen dekrementieren *)
-
- DEC( x1 ); DEC( y1 ); DEC( x2 ); DEC( y2 );
-
- RegAX.h := CHR( Richtung );
- RegAX.l := CHR( ZeilenZahl );
- RegBX.h := CHR( Attribut );
- RegCX.h := CHR( y1 );
- RegCX.l := CHR( x1 );
- RegDX.h := CHR( y2 );
- RegDX.l := CHR( x2 );
- AX := RegAX.w;
- BX := RegBX.w;
- CX := RegCX.w;
- DX := RegDX.w;
- Trap( 10H );
- END Scroll;
-
-
- PROCEDURE InsLine;
- BEGIN
- Scroll( WhereX(), WhereY(), Glob.WinX2, Glob.WinY2,
- 7, 1, Glob.WinAttr );
- END InsLine;
-
-
- PROCEDURE DelLine;
- BEGIN
- Scroll( WhereX(), WhereY(), Glob.WinX2, Glob.WinY2,
- 6, 1, Glob.WinAttr );
- END DelLine;
-
-
- PROCEDURE ClrScr;
- (* Bildschirm löschen unter *)
- (* Beachtung des aktuellen Fensters *)
- BEGIN
- WITH Glob DO
- Scroll( WinX1, WinY1, WinX2, WinY2,
- 6, WinY2 - WinY1 + 1, CARDINAL( WinAttr ));
- END;
- CursorGroesse( 6, 7 );
- GotoXY( 1, 1 );
- END ClrScr;
-
-
- PROCEDURE ClrEol;
- (* Bildschirm löschen unter *)
- (* Beachtung des aktuellen Fensters *)
-
- VAR
- x, y : CARDINAL;
-
- BEGIN
- x := WhereX() + Glob.WinX1 - 1;
- y := WhereY() + Glob.WinY1 - 1;
- Scroll( x, y, Glob.WinX2, y,
- 6, 0, CARDINAL( Glob.WinAttr ));
- END ClrEol;
-
-
- PROCEDURE RepChar( Ch : CHAR; Anzahl, Attr : CARDINAL );
- BEGIN
- (* Fensterbreite berücksichtigen; dazu aktuelle *)
- (* XPosition feststellen und ggf.Ausgabebreite kappen *)
-
- IF ( WhereX() + Anzahl ) > Glob.WinX2 THEN
- Anzahl := Glob.WinX2 - WhereX();
- END;
-
- RegAX.h := CHR( 9 );
- RegAX.l := Ch;
- RegBX.h := CHR( 0 );
- RegBX.l := CHR( Attr );
- RegCX.w := Anzahl;
- AX := RegAX.w;
- BX := RegBX.w;
- CX := RegCX.w;
- Trap( 10H );
- END RepChar;
-
- (* ----------- Schreiben in BS-Speicher ----------------- *)
-
- (* Die Routinen Disp... schreiben ohne Berücksichtigung *)
- (* des aktuellen Fensters in den Bildschirmspeicher *)
-
- PROCEDURE DispChr( x, y : CARDINAL; Ch : CHAR );
- BEGIN
- DEC( x ); DEC( y );
- ScrAdr.OFS := ( y * 160 ) + ( x * 2 );
- Punkt.ch := Ch;
- Punkt.a := CHR( Glob.WinAttr );
- ScrAdr^ := Punkt.p;
- Goto( x + 1, y );
- ScrAdr.OFS := 0H;
- END DispChr;
-
- PROCEDURE DispStr( x, y : CARDINAL; S : String );
- VAR
- Zaehler : CARDINAL;
-
- BEGIN
- DEC( x ); DEC( y );
- Punkt.a := CHR( Glob.WinAttr );
- ScrAdr.OFS := ( y * 160 ) + ( x * 2 );
- FOR Zaehler:= 0 TO Length( S ) DO
- Punkt.ch := S [Zaehler];
- ScrAdr^ := Punkt.p;
- INC( ScrAdr.OFS, 2 );
- END;
- Goto( x + Length( S ), y );
- ScrAdr.OFS := 0H;
- END DispStr;
-
- (* ------------------------------------------------------ *)
-
- (* Die Routinen Wr... schreiben mit Berücksichtigung *)
- (* des aktuellen Fensters in den Bildschirmspeicher. *)
- (* Durch den Prüfaufwand etwas langsamer als Disp...!! *)
-
- PROCEDURE WrChr( x, y : CARDINAL; Ch : CHAR );
- BEGIN
- (* Werte auf Fenster umrechnen und Window-Grenzen *)
- (* prüfen; dann Charakter schreiben *)
-
- IF ( x > 0 ) AND ( y > 0 ) THEN
- x := x + Glob.WinX1 - 1;
- y := y + Glob.WinY1 - 1;
- IF ( x <= Glob.WinX2 ) AND ( y <= Glob.WinY2 ) THEN
- DispChr( x, y, Ch );
- IF x + 1 >= Glob.WinX2 THEN
- GotoXY( 1, y - Glob.WinY1 + 2 );
- END;
- END;
- END;
-
- END WrChr;
-
-
- PROCEDURE WrStr( x, y : CARDINAL; S : String );
- VAR
- P : CARDINAL;
-
- BEGIN
- (* Werte auf Fenster umrechnen und Window-Grenzen *)
- (* prüfen; dann Charakterweise schreiben *)
-
- IF ( x > 0 ) AND ( y > 0 ) THEN
- x := x + Glob.WinX1 - 1;
- y := y + Glob.WinY1 - 1;
- P := 0;
-
- WHILE P < Length( S ) DO
-
- IF x <= Glob.WinX2 THEN
- DispChr( x, y, S [P] );
- INC( x ); INC( P );
- ELSE
- x := Glob.WinX1; INC( y );
-
- IF y > Glob.WinY2 THEN
- Scroll( Glob.WinX1, Glob.WinY1,
- Glob.WinX2, Glob.WinY2,
- 6, 1, Glob.WinAttr );
- DEC( y );
- END;
-
- END;
-
- END;
-
- IF x + 1 >= Glob.WinX2 THEN
- GotoXY( 1, y - Glob.WinY1 + 2 );
- END;
-
- END;
-
- END WrStr;
-
-
- (* ------------ Farb - Routinen ------------------------- *)
-
-
- PROCEDURE HighVideo;
- BEGIN
- Glob.WinAttr := 0FH;
- END HighVideo;
-
-
- PROCEDURE LowVideo;
- VAR
- c : CARDINAL;
- BEGIN
- Glob.WinAttr := 07H;
- END LowVideo;
-
-
- PROCEDURE TextAttr( fg, bg : CARDINAL );
- BEGIN
- IF ( bg < 8 ) AND ( fg < 16 ) THEN
- Glob.WinAttr := ( bg MOD 10H ) * 10H + fg MOD 10H;
- END;
- END TextAttr;
-
-
- PROCEDURE TextColor( fg: CARDINAL );
- VAR
- bg : CARDINAL;
-
- BEGIN
- bg := Glob.WinAttr DIV 10H;
- TextAttr( fg, bg );
- END TextColor;
-
-
- PROCEDURE TextBackground( bg: CARDINAL );
- VAR
- fg : CARDINAL;
-
- BEGIN
- fg := Glob.WinAttr MOD 10H;
- TextAttr( fg, bg );
- END TextBackground;
-
-
- (* ------------ Window - Routinen ----------------------- *)
-
-
- PROCEDURE OpenWindow( x1,y1,x2,y2 : CARDINAL;
- Header : String;
- Frame : FrameTyp );
- VAR
- S : ScrStack;
- i : CARDINAL;
-
-
- PROCEDURE WerteAktualisieren;
- BEGIN
- (* Neue global-Werte setzen *)
- WITH Glob DO
- WinX1 := x1; WinY1 := y1;
- WinX2 := x2; WinY2 := y2;
- END;
-
- END WerteAktualisieren;
-
-
- PROCEDURE RahmenZeichnen;
- BEGIN
-
- IF (( Frame = einfach ) OR ( Frame = doppelt )) AND
- (( x1 > 1 ) AND ( y1 > 1 ) AND
- ( x2 < 80 ) AND ( y2 < 25 ))
- THEN
- DispChr( x1 - 1, y1 - 1, BsRahmen [Frame, 0]);
- DispChr( x2 + 1, y1 - 1, BsRahmen [Frame, 1]);
- DispChr( x1 - 1, y2 + 1, BsRahmen [Frame, 2]);
- DispChr( x2 + 1, y2 + 1, BsRahmen [Frame, 3]);
- FOR i:=x1 TO x2 DO
- DispChr( i, y1 - 1, BsRahmen [Frame, 4]);
- DispChr( i, y2 + 1, BsRahmen [Frame, 4]);
- END;
- FOR i:=y1 TO y2 DO
- DispChr( x1 - 1, i, BsRahmen [Frame, 5]);
- DispChr( x2 + 1, i, BsRahmen [Frame, 5]);
- END;
- END;
-
- END RahmenZeichnen;
-
-
- PROCEDURE Ueberschriftschreiben;
- BEGIN
-
- IF (( x2 - x1 ) >= ( Length( Header ) + 2 )) AND
- ( Length( Header ) # 0 )
- THEN
- i := ( x2 - x1 - Length( Header )) DIV 2;
- DispStr( x1 + i, y1 - 1, Header );
- END;
-
- END Ueberschriftschreiben;
-
-
- BEGIN (* OpenWindow *)
- (* !!! Heap-Prüfung & Speicher allokieren !!! *)
-
- IF Available( SIZE( Kopf )) THEN
- ALLOCATE( S, SIZE( Kopf ));
- (* Screen & global-Werte in Liste schreiben *)
-
- WerteAktualisieren;
- Move( ScrAdr, S, SIZE( Kopf ));
- S^.prev := BsStack;
- BsStack := S;
- RahmenZeichnen;
- Ueberschriftschreiben;
- ClrScr; (* Screenbereich löschen *)
-
- END; (* !!! FehlerMeldung einbauen !!! *)
-
- END OpenWindow;
-
-
- PROCEDURE LastWindow() : BOOLEAN;
- BEGIN
- RETURN BsStack = NIL;
- END LastWindow;
-
-
- PROCEDURE CloseWindow;
- VAR
- S : ScrStack;
-
- BEGIN
- IF BsStack # NIL THEN
- (* Screen restaurieren *)
- Move( BsStack, ScrAdr, SIZE( Kopf ));
-
- (* StackElement auskoppeln & Speicher freigeben *)
- S := BsStack;
- BsStack := BsStack^.prev;
- DEALLOCATE( S, SIZE( Kopf ));
-
- END;
- END CloseWindow;
-
-
- PROCEDURE RemoveAllWindows;
- VAR
- S : ScrStack;
-
- BEGIN
- (* StackElemente auskoppeln & Speicher freigeben *)
- (* !!! Letztes Window bleibt erhalten !!! *)
-
- WHILE BsStack^.prev # NIL DO
- S := BsStack;
- BsStack := BsStack^.prev;
- DEALLOCATE( S, SIZE( Kopf ));
- END;
-
- END RemoveAllWindows;
-
- (* ------------ Initialisieren der Werte ---------------- *)
-
- BEGIN (* Modul-Körper & Initialisierungen *)
- VideoKarte; (* Screen-Adresse ermitteln *)
- BsStack := NIL; (* Liste initialisieren *)
-
- (* initialisieren der Rahmen-Werte *)
- BsRahmen [einfach, 0] := '┌';
- BsRahmen [einfach, 1] := '┐';
- BsRahmen [einfach, 2] := '└';
- BsRahmen [einfach, 3] := '┘';
- BsRahmen [einfach, 4] := '─';
- BsRahmen [einfach, 5] := '│';
- BsRahmen [doppelt, 0] := '╔';
- BsRahmen [doppelt, 1] := '╗';
- BsRahmen [doppelt, 2] := '╚';
- BsRahmen [doppelt, 3] := '╝';
- BsRahmen [doppelt, 4] := '═';
- BsRahmen [doppelt, 5] := '║';
-
- (* erstes Window setzen *)
- OpenWindow( 1,1,80,25, "", ohne );
-
- Glob.WinAttr := 7; (* Screen-Attribut HellGrau *)
- END Screen.
-
- (* ------------- Ende von SCREEN.MOD -------------------- *)