home *** CD-ROM | disk | FTP | other *** search
/ Turbo Toolbox / Turbo_Toolbox.iso / 1990 / 07 / praxis / fed.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1990-04-03  |  22.5 KB  |  826 lines

  1. (* ====================================================== *)
  2. (*                  Editor für Pixelfonts                 *)
  3. (*           (C) 1990 Matthias Uphoff & TOOLBOX           *)
  4. (*               Compiler: Turbo Pascal 5.5               *)
  5. (* ====================================================== *)
  6.  
  7. (*$V-*)
  8. (*$D-*)
  9. (*$S-*)
  10.  
  11. USES Dos, Crt, Bios3;        (* Unit Bios3 aus tx 6/90 *)
  12.  
  13. CONST MaxCSize = 32;              (* Maximale Zeichenhöhe *)
  14.       FSize = MaxCSize*256;       (* Maximale Fontgröße   *)
  15.  
  16. TYPE FileName = String[64];
  17.      FrameStr = String[8];     (* Grafikzeichen f. Rahmen *)
  18.      FArray = ARRAY[0..FSize-1] OF Byte;
  19.      CharSet = SET OF CHAR;
  20.  
  21. CONST SingleFrame = '┌─┐││└─┘';
  22.       Hex: String[16] = '0123456789ABCDEF';
  23.       (* --- Für Dateinamen erlaubte Zeichen --- *)
  24.       FileChar: CharSet =
  25.                   ['.','0'..'9','a'..'z','A'..'Z','\'];
  26.       (* --- Daten für Menue --- *)
  27.       MLength = 22;  (* Länge *)
  28.       MWidth = 39;   (* Breite *)
  29.       MLeft = 40;    (* Ecke links/oben *)
  30.       MTop = 2;
  31.       Menu: ARRAY[1..MLength] OF String[MWidth] =
  32.         ('┌───────────── Kommandos ─────────────┐',
  33.          '│   Cursor nach                       │',
  34.          '│ ['#27']    links      ['#26']    rechts     │',
  35.          '│ ['#24']    oben       ['#25']    unten      │',
  36.          '│ [Pos1] Spalte 1   [Ende] Spalte 8   │',
  37.          '│                                     │',
  38.          '│ [L]aden           [S]peichern       │',
  39.          '│ [Z]eichen wählen  [K]opieren        │',
  40.          '│ [B]lank           [I]nvertieren     │',
  41.          '│ [R]ückgängig      [F]ont zeigen     │',
  42.          '│ [Strg] [L]inks    [Strg] [R]echts   │',
  43.          '│ [Strg] [O]ben     [Strg] [U]nten    │',
  44.          '│                                     │',
  45.          '│ [<─┘]          Punkt setzen/löschen │',
  46.          '│ [Bild'#24']        1  Zeichen zurück    │',
  47.          '│ [Bild'#25']        1  Zeichen weiter    │',
  48.          '│ [Strg] [Bild'#24'] 10 Zeichen zurück    │',
  49.          '│ [Strg] [Bild'#25'] 10 Zeichen weiter    │',
  50.          '│ [Einfg]        Reihe hinzufügen     │',
  51.          '│ [Entf]         Reihe entfernen      │',
  52.          '│ [ESC]          Abbruch/Programmende │',
  53.          '└─────────────────────────────────────┘');
  54.       (* Daten für Editierfeld *)
  55.       ELength = 7;   (* Länge *)
  56.       EWidth = 20;   (* Breite *)
  57.       ELeft = 11;    (* Ecke links/oben *)
  58.       ETop = 2;
  59.       EFrame: ARRAY[1..ELength] OF String[EWidth] =
  60.         ('╔════╦════════╦════╗',
  61.          '║    ║12345678║    ║',
  62.          '╠════╬════════╬════╣',
  63.          '║    ║        ║    ║',
  64.          '╠════╩════════╩════╣',
  65.          '║   Zeichen        ║',
  66.          '╚══════════════════╝');
  67.  
  68. VAR R: Registers;            (* Prozessorregister *)
  69.     Font: FArray;            (* Aktueller Font *)
  70.     FontName: FileName;      (* Aktueller Font-Dateiname *)
  71.     VMode,                   (* Videomodus *)
  72.     CSize,                   (* Aktuelle Zeichenhöhe *)
  73.     MsLine,                  (* Ausgabezeile f. Meldungen *)
  74.     c,                       (* Aktuelle Zeichennummer *)
  75.     LastLine: Word;          (* Letzte Bildschirmzeile *)
  76.     EGA,                     (* TRUE wenn EGA vorhanden *)
  77.     VGA,                     (* TRUE wenn VGA vorhanden *)
  78.     changed: Boolean;        (* TRUE wenn Font geändert *)
  79.     UndoBuffer: Array[0..MaxCSize-1] OF Byte;
  80.  
  81. (* ----- Diverse Prozeduren für das Screen-Handling ----- *)
  82.  
  83. PROCEDURE Cursor(on: Boolean);
  84.    (* Schaltet Blockcursor ein/aus *)
  85. BEGIN
  86.   R.AX := $100;
  87.   IF on THEN R.CX := $1F ELSE R.CX := $2020;
  88.   Intr($10,R);
  89. END;
  90.  
  91.  
  92. PROCEDURE WriteBlanks(n: Word);
  93.    (* Gibt n Blanks aus *)
  94.    VAR i: Word;
  95. BEGIN
  96.   FOR i := 1 TO n DO Write(' ');
  97. END;
  98.  
  99.  
  100. PROCEDURE EraseMs;
  101.    (* Löscht Zeile mit Bildschirm-Meldung *)
  102. BEGIN
  103.   Cursor(FALSE);
  104.   GotoXY(2,MsLine);
  105.   WriteBlanks(78);
  106. END;
  107.  
  108.  
  109. PROCEDURE Message(x: Word; s: String);
  110.    (* Gibt Meldung s ab Spalte x in Zeile MsLine aus *)
  111. BEGIN
  112.   TextColor(White);
  113.   GotoXY(x,MsLine);
  114.   Write(s);
  115.   TextColor(LightGray);
  116.   Cursor(TRUE);
  117. END;
  118.  
  119.  
  120. PROCEDURE Error(s: String);
  121.    (* Gibt Fehlermeldung aus, wartet auf ESC *)
  122. BEGIN
  123.   Message(3,#7 + s + ': ESC drücken ');
  124.   REPEAT UNTIL ReadKey = #27;
  125.   EraseMs;
  126. END;
  127.  
  128.  
  129. PROCEDURE Frame(x1,y1,x2,y2,c: Word; fs: FrameStr);
  130.    (* Zeichnet Rahmen mit den Linienelementen in fs *)
  131.    (* x1,y1 liegt links oben, x2,y2 rechts unten    *)
  132.    VAR x,y: Word;
  133. BEGIN
  134.   TextColor(c);
  135.   GotoXY(x1,y1); Write(fs[1]);
  136.   FOR x := x1+1 TO x2-1 DO Write(fs[2]);
  137.   Write(fs[3]);
  138.   FOR y := y1+1 TO y2-1 DO BEGIN
  139.     GotoXY(x1,y); Write(fs[4]);
  140.     GotoXY(x2,y); Write(fs[5])
  141.   END;
  142.   GotoXY(x1,y2); Write(fs[6]);
  143.   FOR x := x1+1 TO x2-1 DO Write(fs[7]);
  144.   Write(fs[8]);
  145. END;
  146.  
  147.  
  148. PROCEDURE WriteMenu;
  149.    (* Gibt das Menue aus *)
  150.    VAR x,y: Word;
  151.        c: Char;
  152. BEGIN
  153.   FOR y := 1 TO MLength DO BEGIN
  154.     GotoXY(MLeft,MTop+y-1);
  155.     FOR x := 1 TO MWidth DO BEGIN
  156.       c := Menu[y,x];
  157.       IF c = '[' THEN TextColor(White);
  158.       Write(c);
  159.       IF c = ']' THEN TextColor(LightGray);
  160.     END;
  161.   END;
  162. END;
  163.  
  164.  
  165. PROCEDURE WriteEdit;
  166.    (* Baut das Editierfeld auf *)
  167.    VAR y,i: Word;
  168. BEGIN
  169.   TextColor(LightGray);
  170.   y := ETop;
  171.   FOR i := 1 TO 3 DO BEGIN
  172.     GotoXY(ELeft,y); Write(EFrame[i]);
  173.     Inc(y);
  174.   END;
  175.   FOR i := 1 TO CSize DO BEGIN
  176.     GotoXY(ELeft,y); Write(EFrame[4]);
  177.     GotoXY(ELeft+2,y); Write(i:2);
  178.     Inc(y);
  179.   END;
  180.   FOR i := 5 TO 7 DO BEGIN
  181.     GotoXY(ELeft,y); Write(EFrame[i]);
  182.     Inc(y);
  183.   END;
  184.   FOR i := y TO LastLine-1 DO BEGIN
  185.     GotoXY(ELeft,i);
  186.     WriteBlanks(EWidth);
  187.   END;
  188. END;
  189.  
  190.  
  191. PROCEDURE CharRow(c,r: Word);
  192.    (* Gibt die Pixelreihe r des Zeichens c aus *)
  193.    VAR x: Word;
  194.        b: Byte;
  195. BEGIN
  196.   b := Font[c*CSize+r-1];
  197.   GotoXY(ELeft+16,ETop+r+2);
  198.   Write(Hex[(b SHR 4) + 1],Hex[(b AND $F) + 1]);
  199.   TextColor(White);
  200.   GotoXY(ELeft+6,ETop+r+2);
  201.   FOR x := 1 TO 8 DO BEGIN
  202.     IF b AND $80 <> 0 THEN Write(#177) ELSE Write(#250);
  203.     b := b SHL 1;
  204.   END;
  205.   TextColor(LightGray);
  206. END;
  207.  
  208.  
  209. PROCEDURE ShowChar(c: Word);
  210.    (* Gibt Matrix von Zeichen c im Editierfeld aus *)
  211.    VAR y: Word;
  212. BEGIN
  213.   FOR y := 1 TO CSize DO CharRow(c,y);
  214.   GotoXY(ELeft+13,ETop+CSize+4);
  215.   Write(c:3);
  216.   GotoXY(ELeft+3,ETop+1);
  217.   IF c IN [7,8,10,13] THEN c := 0;    (* Steuerzeichen *)
  218.   Write(CHR(c));
  219. END;
  220.  
  221.  
  222. PROCEDURE SaveChar(c: Word);
  223.    (* Matrix von Zeichen c in den Undo-Puffer retten *)
  224.    (* und im Editierfeld ausgeben                    *)
  225. BEGIN
  226.   Move(Font[c*CSize],UndoBuffer,CSize);
  227.   ShowChar(c);
  228. END;
  229.  
  230.  
  231. PROCEDURE InitScreen(size: Word);
  232.    (* Baut den Bildschirm auf. Wenn Size > 16, wird in *)
  233.    (* den 43 bzw. 50-Zeilen-Modus geschaltet (EGA/VGA) *)
  234. BEGIN
  235.   IF EGA AND (size > 16) THEN BEGIN
  236.     TextMode(VMode + Font8x8);
  237.     IF VGA THEN LastLine := 50 ELSE LastLine := 43;
  238.   END
  239.   ELSE BEGIN
  240.     TextMode(VMode);
  241.     LastLine := 25;
  242.   END;
  243.   Cursor(FALSE);
  244.   MsLine := LastLine-1;;
  245.   WindMax := LastLine*256+79;
  246.   Frame(1,1,80,LastLine,7,SingleFrame);
  247.   WriteEdit;
  248.   WriteMenu;
  249.   GotoXY(13,1);
  250.   Write(' Font-Editor 2.0  ' +
  251.         ' (C) 1990 Matthias Uphoff & TOOLBOX ');
  252. END;
  253.  
  254.  
  255. FUNCTION CheckSize(size: Word): Boolean;
  256.    (* Überprüft die Zeichenhöhe, gibt FALSE zurück,    *)
  257.    (* wenn sie zu klein oder zu groß ist. Schaltet     *)
  258.    (* in den 43/50-Zeilen-Modus, falls nötig (EGA/VGA) *)
  259. BEGIN
  260.   IF (size >= 4) AND (size <= 16) THEN BEGIN
  261.     IF LastLine > 25 THEN InitScreen(size);
  262.     CheckSize := TRUE;
  263.   END
  264.   ELSE IF (size<4) OR (size>MaxCSize) OR NOT EGA THEN BEGIN
  265.     CheckSize := FALSE
  266.   END
  267.   ELSE BEGIN
  268.     IF LastLine = 25 THEN InitScreen(size);
  269.     CheckSize := TRUE;
  270.   END;
  271. END;
  272.  
  273.  
  274. PROCEDURE Input(max: Word; Allowed: CharSet; VAR s: String);
  275.    (* Eingabe an der akt. Cursorpos. mit Zeileneditor *)
  276.    (* max ist die max. Länge, Allowed enthält die er- *)
  277.    (* laubten Zeichen. s kann eine Vorgabe enthalten. *)
  278.    (* Bei Abbruch mit ESC wird s leer zurückgegeben   *)
  279.    VAR new, flag: Boolean;
  280.        x,y,xp: Word;
  281.        ch: Char;
  282. BEGIN
  283.   new := TRUE; flag := FALSE;
  284.   x := WhereX; y := WhereY;
  285.   TextColor(White);
  286.   Write(s);                      (* Vorgabe ausgeben *)
  287.   xp := Length(s) + 1;           (* Eingabeposition *)
  288.   REPEAT
  289.     GotoXY(x+xp-1,y);
  290.     ch := ReadKey;
  291.     CASE ch OF
  292.       #0:   CASE ReadKey OF         (* Extenden Code *)
  293.                #71: BEGIN           (* Pos1 *)
  294.                       new := false;
  295.                       xp := 1;
  296.                     END;
  297.                #75: BEGIN           (* Cursor links *)
  298.                       new := FALSE;
  299.                       IF xp > 1 THEN Dec(xp);
  300.                     END;
  301.                #77: BEGIN           (* Cursor rechts *)
  302.                       new := FALSE;
  303.                       IF xp < Length(s)+1 THEN Inc(xp);
  304.                     END;
  305.                #79: BEGIN           (* Ende *)
  306.                       new := FALSE;
  307.                       xp := Length(s) + 1; END;
  308.                #83: BEGIN           (* Entf *)
  309.                       new := FALSE;
  310.                       Delete(s,xp,1);
  311.                       GotoXY(x,y);
  312.                       Write(s,' ');
  313.                     END;
  314.             END;
  315.       #8:   BEGIN                   (* Backspace *)
  316.               new := FALSE;
  317.               IF xp > 1 THEN Dec(xp);
  318.               Delete(s,xp,1);
  319.               GotoXY(x,y);
  320.               Write(s,' ');
  321.             END;
  322.       #13:  BEGIN                (* Return *)
  323.               GotoXY(x,y);
  324.               WriteBlanks(Length(s));
  325.               flag := TRUE;
  326.             END;
  327.       #27:  BEGIN                (* ESC *)
  328.               GotoXY(x,y);
  329.               WriteBlanks(Length(s));
  330.               s := '';
  331.               flag := TRUE;
  332.             END
  333.       ELSE IF (ch IN Allowed) AND (Length(s)<max) THEN BEGIN
  334.         IF new THEN BEGIN        (* Vorgabe rauswerfen *)
  335.           GotoXY(x,y); WriteBlanks(Length(s));
  336.           new := FALSE; s := ''; xp := 1;
  337.         END;
  338.         Insert(ch,s,xp);         (* neues Zeichen *)
  339.         GotoXY(x,y); Write(s);
  340.         Inc(xp);
  341.       END;
  342.     END;
  343.   UNTIL flag;
  344.   TextColor(LightGray);
  345. END;
  346.  
  347. (* -------------- Diverse Editorfunktionen -------------- *)
  348.  
  349. PROCEDURE Pixel(c,x,y: Word);
  350.    (* Invertiert Pixel x,y im Zeichen c *)
  351.    VAR i: Word;
  352. BEGIN
  353.   i := c*CSize+y-1;
  354.   Font[i] := Font[i] XOR ($80 SHR (x-1));
  355.   CharRow(c,y);
  356.   changed := TRUE;
  357. END;
  358.  
  359.  
  360. FUNCTION GetChar(fs: String): Word;
  361.   (* Zeichen(nummer) von der Tastatur anfordern *)
  362.   VAR key: CHAR;
  363. BEGIN
  364.   Message(3,fs + ': Taste drücken oder ALT niederhalten' +
  365.                  ' und Ziffern eingeben ');
  366.   REPEAT
  367.     key := ReadKey;
  368.     IF key = #0 THEN BEGIN
  369.       key := ReadKey; key := #0;
  370.     END;
  371.   UNTIL key <> #0;
  372.   EraseMs;
  373.   GetChar := ORD(key);
  374. END;
  375.  
  376.  
  377. PROCEDURE CopyChar(c: Word);
  378.   (* Fordert Zeichen sc von der Tastatur an und   *)
  379.   (* kopiert die Matrix in das Feld von Zeichen c *)
  380.   VAR sc: Word;
  381. BEGIN
  382.   sc := GetChar('Matrix kopieren');
  383.   IF sc <> 27 THEN BEGIN
  384.     Move(Font[sc*CSize],Font[c*CSize],CSize);
  385.     ShowChar(c);
  386.     changed := TRUE;
  387.   END;
  388. END;
  389.  
  390.  
  391. PROCEDURE InvertChar(c: Word);
  392.    (* Invertiert die Matrix von Zeichen c *)
  393.    VAR i: Word;
  394. BEGIN
  395.   FOR i := c*CSize TO (c+1)*CSize-1 DO
  396.     Font[i] := NOT Font[i];
  397.   ShowChar(c);
  398.   changed := TRUE;
  399. END;
  400.  
  401.  
  402. PROCEDURE ClearChar(c: Word);
  403.    (* Löscht Matrix des Zeichen c (Blank) *)
  404. BEGIN
  405.   FillChar(Font[c*CSize],CSize,0);
  406.   ShowChar(c);
  407.   changed := TRUE;
  408. END;
  409.  
  410.  
  411. PROCEDURE Undo(c: Word);
  412.    (* Stellt den Originalzustand des Zeichens c her *)
  413. BEGIN
  414.   Move(UndoBuffer,Font[c*CSize],CSize);
  415.   ShowChar(c);
  416. END;
  417.  
  418.  
  419. PROCEDURE ShiftR(c: Word);
  420.    (* Schiebt die Punktreihen des Zeichens c nach rechts *)
  421.    VAR i: Word;
  422. BEGIN
  423.   FOR i := c*CSize TO (c+1)*CSize-1 DO
  424.     Font[i] := Font[i] SHR 1;
  425.   ShowChar(c);
  426.   changed := TRUE;
  427. END;
  428.  
  429.  
  430. PROCEDURE ShiftL(c: Word);
  431.    (* Schiebt die Punktreihen des Zeichens c nach links *)
  432.    VAR i: Word;
  433. BEGIN
  434.   FOR i := c*CSize TO (c+1)*CSize-1 DO
  435.     Font[i] := Font[i] SHL 1;
  436.   ShowChar(c);
  437.   changed := TRUE;
  438. END;
  439.  
  440.  
  441. PROCEDURE ShiftU(c: Word);
  442.    (* Schiebt die Punktreihen des Zeichens c nach oben *)
  443.    VAR i: Word;
  444. BEGIN
  445.   i := c*CSize;
  446.   Move(Font[i+1],Font[i],CSize-1);
  447.   Font[i+CSize-1] := 0;
  448.   ShowChar(c);
  449.   changed := TRUE;
  450. END;
  451.  
  452.  
  453. PROCEDURE ShiftD(c: Word);
  454.    (* Schiebt die Punktreihen des Zeichens c nach unten *)
  455.    VAR i: Word;
  456. BEGIN
  457.   i := c*CSize;
  458.   Move(Font[i],Font[i+1],CSize-1);
  459.   Font[i] := 0;
  460.   ShowChar(c);
  461.   changed := TRUE;
  462. END;
  463.  
  464.  
  465. PROCEDURE Leave;
  466.    (* Beendet das Programm nach Sicherheitsabfrage *)
  467.    VAR key: CHAR;
  468. BEGIN
  469.   TextColor(White);
  470.   IF changed THEN
  471.     Message(6,'Der Zeichensatz wurde nicht gespeichert' +
  472.               ' - das Programm beenden? (J/N) ')
  473.   ELSE
  474.     Message(25,'Das Programm beenden? (J/N) ');
  475.   REPEAT
  476.     key := UpCase(ReadKey);
  477.     IF key = #0 THEN BEGIN
  478.       key := ReadKey; key := #0;
  479.     END;
  480.   UNTIL (key = 'J') OR (key = 'N') OR (key = #27);
  481.   IF key = 'J' THEN BEGIN
  482.     TextMode(VMode);
  483.     Halt;
  484.   END;
  485.   EraseMs;
  486. END;
  487.  
  488.  
  489. PROCEDURE InsLine;
  490.    (* Vergrößert alle Zeichen um eine Punktreihe *)
  491.    VAR key: Char;
  492.        i: Word;
  493.        tmp: FArray;
  494. BEGIN
  495.   Message(20,'Reihe hinzufügen - [O]ben oder [U]nten? ');
  496.   REPEAT
  497.     key := UpCase(ReadKey);
  498.     IF key = #0 THEN BEGIN
  499.       key := ReadKey; key := #0;
  500.     END;
  501.   UNTIL (key = 'O') OR (key = 'U') OR (key = #27);
  502.   EraseMs;
  503.   IF key <> #27 THEN BEGIN
  504.     IF NOT CheckSize(CSize+1) THEN BEGIN
  505.       Error('Zu große Zeichenhöhe');
  506.       Exit;
  507.     END;
  508.     Tmp := Font;
  509.     FillChar(Font,SizeOf(Font),0);
  510.     FOR i := 0 TO 255 DO
  511.       IF key = 'O' THEN
  512.         Move(Tmp[i*CSize],Font[i*(CSize+1)+1],CSize)
  513.       ELSE
  514.         Move(Tmp[i*CSize],Font[i*(CSize+1)],CSize);
  515.     Inc(CSize);
  516.     WriteEdit;
  517.     SaveChar(c);
  518.     changed := TRUE;
  519.   END;
  520. END;
  521.  
  522.  
  523. PROCEDURE DelLine;
  524.    (* Verkleinert alle zeichen um eine Punktreihe *)
  525.    VAR key: Char;
  526.        i: Word;
  527.        tmp: FArray;
  528. BEGIN
  529.   Message(20,'Reihe entfernen - [O]ben oder [U]nten? ');
  530.   REPEAT
  531.     key := UpCase(ReadKey);
  532.     IF key = #0 THEN BEGIN
  533.       key := ReadKey; key := #0;
  534.     END;
  535.   UNTIL (key = 'O') OR (key = 'U') OR (key = #27);
  536.   EraseMs;
  537.   IF key <> #27 THEN BEGIN
  538.     IF NOT CheckSize(CSize-1) THEN BEGIN
  539.       Error('Zu kleine Zeichenhöhe');
  540.       Exit;
  541.     END;
  542.     Tmp := Font;
  543.     FOR i := 0 TO 255 DO BEGIN
  544.       IF key = 'O' THEN
  545.         Move(Tmp[i*CSize+1],Font[i*(CSize-1)],CSize-1)
  546.       ELSE
  547.         Move(Tmp[i*CSize],Font[i*(CSize-1)],CSize-1)
  548.     END;
  549.     Dec(CSize);
  550.     WriteEdit;
  551.     SaveChar(c);
  552.     changed := TRUE;
  553.   END;
  554. END;
  555.  
  556.  
  557. PROCEDURE ShowFont;
  558.    (* Zeigt den gesamten aktuellen Zeichensatz an *)
  559.    VAR x,y: Word;
  560.        ch: Char;
  561.    PROCEDURE CharOut;
  562.       (* Textausgabe ohne Steuerzeichen über das BIOS *)
  563.    BEGIN
  564.      R.AX := $200;                (* Funktionsnr. in AH *)
  565.      R.BH := 0;                   (* Bildseite 0 *)
  566.      R.DH := (y-1)*2;
  567.      R.DL := x*2 + 7;
  568.      Intr($10,R);       (* Cursorposition setzen *)
  569.      R.AH := 9;                   (* Funktionsnr. in AH *)
  570.      R.AL := ORD(ch);             (* Zeichen in AL *)
  571.      R.BH := 0;                   (* Bildseite 0 *)
  572.      R.BL := Red * 16 + White;    (* Weiß auf Rot *)
  573.      R.CX := 1;                   (* 1 mal wiederholen *)
  574.      Intr($10,R);       (* Zeichen ausgeben *)
  575.    END;
  576. BEGIN
  577.   IF NOT EGA THEN
  578.     Error('Für diese Funktion ist eine' +
  579.           ' EGA/VGA-Karte erforderlich')
  580.   ELSE BEGIN
  581.     TextMode(VMode);              (* Bildschirm löschen *)
  582.     (* aktuellen Font installieren: *)
  583.     UserTextFont(0,CSize,256,0,TRUE,Font);
  584.     ch := #0;
  585.     FOR y := 1 TO 8 DO
  586.       FOR x := 1 TO 32 DO BEGIN
  587.         CharOut; Inc(ch);
  588.       END;
  589.     REPEAT ch := ReadKey UNTIL ch <> #0;
  590.     InitScreen(CSize);
  591.     ShowChar(c);
  592.   END;
  593. END;
  594.  
  595. (* -- Prozeduren für das Laden und Speichern von Fonts -- *)
  596.  
  597. PROCEDURE InitFont;
  598.    (* Defaultfont aus ROM laden (EGA/VGA) *)
  599.    VAR p: Pointer;
  600. BEGIN
  601.   IF VGA THEN BEGIN
  602.     p := FontAddr(ROM8x16);
  603.     CSize := 16;
  604.     Move(p^,Font,256*CSize);
  605.     FontName := 'ROM8x16';
  606.   END
  607.   ELSE IF EGA THEN BEGIN
  608.     p := FontAddr(ROM8x14);
  609.     CSize := 14;
  610.     Move(p^,Font,256*CSize);
  611.     FontName := 'ROM8x14';
  612.   END
  613.   ELSE BEGIN
  614.     FillChar(Font,SizeOf(Font),0);
  615.     CSize := 8;
  616.     FontName := '';
  617.   END;
  618. END;
  619.  
  620.  
  621. FUNCTION SaveFont(fn: Filename;
  622.                   VAR MTable: FArray): Boolean;
  623.    (* Font in MTable abspeichern. Gibt FALSE zurück,  *)
  624.    (* wenn während des Speicherns ein Fehler auftritt *)
  625.    VAR f: File;
  626.        flag: BOOLEAN;
  627. BEGIN
  628.   (*$I-*)
  629.   Assign(f,fn);
  630.   ReWrite(f,1);
  631.   flag := IOResult = 0;
  632.   IF flag THEN BEGIN
  633.     BlockWrite(f,MTable,CSize*256);
  634.     flag := IOResult = 0;
  635.     IF flag THEN Close(f);
  636.   END;
  637.   (*$I+*)
  638.   SaveFont := flag;
  639. END;
  640.  
  641.  
  642. PROCEDURE Save;
  643.    (* Dateiname anfordern und aktuellen Font abspeichern *)
  644.    VAR fn: FileName;
  645.         c: CHAR;
  646. BEGIN
  647.   Message(3,'Zeichensatz speichern - Dateiname: ');
  648.   fn := FontName;
  649.   Input(40,FileChar,fn);
  650.   EraseMs;
  651.   IF fn <> '' THEN
  652.     IF SaveFont(fn,Font) THEN BEGIN
  653.       FontName := fn;
  654.       changed := FALSE;
  655.     END
  656.     ELSE Error('Fehler beim Speichern von ' + fn);
  657. END;
  658.  
  659.  
  660. PROCEDURE GetFont(fn: FileName);
  661.    (* Font mit Dateinamen fn holen. Die Namen '8', '14'  *)
  662.    (* und 16 laden die Fonts mit der entsprechenden      *)
  663.    (* Zeichenhöhe aus dem EGA/VGA-BIOS-ROM               *)
  664.    VAR FontSize: Integer;
  665.        p: Pointer;
  666. BEGIN
  667.   IF (fn = '8') AND EGA THEN BEGIN
  668.     p := FontAddr(ROM8x8);
  669.     CSize := 8;
  670.     Move(p^,Font,256*CSize);
  671.     FontName := 'ROM8x8';
  672.   END
  673.   ELSE IF (fn = '14') AND EGA THEN BEGIN
  674.     p := FontAddr(ROM8x14);
  675.     CSize := 14;
  676.     Move(p^,Font,256*CSize);
  677.     FontName := 'ROM8x14';
  678.   END
  679.   ELSE IF (fn = '16') AND VGA THEN BEGIN
  680.     p := FontAddr(ROM8x16);
  681.     CSize := 16;
  682.     Move(p^,Font,256*CSize);
  683.     FontName := 'ROM8x16';
  684.   END
  685.   ELSE BEGIN
  686.     FontSize := LoadFont(fn,Font);    (* siehe Unit Bios3 *)
  687.     IF FontSize = 0 THEN
  688.       Error('Datei '+ fn +' konnte nicht geladen werden')
  689.     ELSE IF FontSize = -1 THEN
  690.       Error(fn + ' ist keine Fontdatei')
  691.     ELSE BEGIN
  692.       FontName := fn;
  693.       CSize := FontSize DIV 256;
  694.       IF NOT CheckSize(CSize) THEN BEGIN
  695.         Error('Zu große Zeichenhöhe');
  696.         InitFont;
  697.       END;
  698.     END;
  699.   END;
  700.   InitScreen(CSize);
  701.   SaveChar(c);
  702.   changed := FALSE;
  703. END;
  704.  
  705.  
  706. PROCEDURE Load;
  707.    (* Dateinamen anfordern und Font laden *)
  708.    VAR fn: FileName;
  709.        key: Char;
  710. BEGIN
  711.   IF changed THEN BEGIN
  712.     Message(7,'Der Zeichensatz wurde nicht gespeichert' +
  713.               ' - trotzdem laden? (J/N) ');
  714.     REPEAT
  715.       key := UpCase(ReadKey);
  716.       IF key = #0 THEN BEGIN
  717.         key := ReadKey; key := #0;
  718.       END;
  719.     UNTIL (key = 'J') OR (key = 'N') OR (key = #27);
  720.     EraseMs;
  721.     IF key <> 'J' THEN Exit;
  722.   END;
  723.   Message(3,'Zeichensatz laden - Dateiname: ');
  724.   fn := '';
  725.   Input(40,FileChar,fn);
  726.   EraseMs;
  727.   IF fn <> '' THEN GetFont(fn);
  728. END;
  729.  
  730. (* --------- Editorschleife mit Tastaturabfrage ---.----- *)
  731.  
  732. PROCEDURE Edit;
  733.    VAR x,y: Word;
  734.    ch: Char;
  735. BEGIN
  736.   x := 1; y := 1;
  737.   REPEAT
  738.     IF y > CSize THEN y := CSize;
  739.     GotoXY(ELeft+5+x,ETop+2+y);
  740.     WHILE KeyPressed DO ch := ReadKey;
  741.     Cursor(TRUE);
  742.     ch := UpCase(ReadKey);
  743.     Cursor(FALSE);
  744.     CASE ch OF
  745.       #0:  CASE ReadKey OF          (* Extended Code *)
  746.              #71:  x := 1;
  747.              #72:  IF y = 1 THEN         (* Cursor oben *)
  748.                      y := CSize ELSE Dec(y);
  749.              #75:  IF x = 1 THEN         (* Cursor links *)
  750.                      x := 8 ELSE Dec(x);
  751.              #77:  IF x = 8 THEN         (* Cursor rechts *)
  752.                      x := 1 ELSE Inc(x);
  753.              #79:  x := 8;               (* Ende *)
  754.              #80:  IF y = CSize THEN     (* Cursor unten *)
  755.                      y := 1 ELSE Inc(y);
  756.              #82:  InsLine;              (* Einfg *)
  757.              #83:  DelLine;              (* Entf *)
  758.              #73:  BEGIN                 (* Bild oben *)
  759.                      IF c = 0 THEN c := 255 ELSE Dec(c);
  760.                      SaveChar(c);
  761.                    END;
  762.              #81:  BEGIN                 (* Bild unten *)
  763.                      IF c = 255 THEN c := 0 ELSE Inc(c);
  764.                      SaveChar(c);
  765.                    END;
  766.              #118: BEGIN               (* Strg Bild unten *)
  767.                      IF c > 245 THEN
  768.                        c := 255
  769.                      ELSE
  770.                        Inc(c,10);
  771.                      SaveChar(c);
  772.                    END;
  773.              #132: BEGIN               (* Strg Bild oben *)
  774.                      IF c < 10 THEN c := 0 ELSE Dec(c,10);
  775.                      SaveChar(c);
  776.                    END;
  777.            END;
  778.       #12: ShiftL(c);        (* ^L, links schieben *)
  779.       #13: Pixel(c,x,y);     (* Return, Punkt invertieren *)
  780.       #15: ShiftU(c);        (* ^O, nach oben schieben *)
  781.       #18: ShiftR(c);        (* ^R, rechts schieben *)
  782.       #21: ShiftD(c);        (* ^U, nach unten schieben *)
  783.       #27: Leave;            (* ESC, Programmende *)
  784.       #32: Pixel(c,x,y);     (* Space, Punkt invertieren *)
  785.       'B': ClearChar(c);     (* Zeichen löschen (Blank) *)
  786.       'F': ShowFont;         (* Font anzeigen *)
  787.       'L': Load;             (* Font laden *)
  788.       'I': InvertChar(c);    (* Zeichen invertieren *)
  789.       'K': CopyChar(c);      (* Zeichenmatrix kopieren *)
  790.       'R': Undo(c);          (* Rückgängig machen *)
  791.       'S': Save;             (* Font speichern *)
  792.       'Z': BEGIN             (* Zeichen wählen *)
  793.              c := GetChar('Zeichen wählen');
  794.              SaveChar(c);
  795.            END;
  796.     END;
  797.   UNTIL FALSE;
  798. END;
  799.  
  800. (* ------------------------- Main ----------------------- *)
  801.  
  802. BEGIN
  803.   SetCBreak(FALSE);          (* Ctrl Break unterbinden *)
  804.   (* --- Hardware ermitteln --- *)
  805.   IF (LastMode AND $7F) = 7 THEN
  806.     VMode := Mono            (* Monochrom-Bildschirm *)
  807.   ELSE
  808.     VMode := CO80;           (* Farbbildschirm *)
  809.   R.AX := $1A00;             (* Fkt. Read Display Code *)
  810.   Intr($10,R);
  811.   VGA := R.AL = $1A;
  812.   R.AX := $1200;             (* Fkt. Alternate Select *)
  813.   R.BL := $10;               (* UFkt. Return Video Info *)
  814.   Intr($10,R);
  815.   EGA := (R.BL = 3) OR VGA;  (* Rückgabe 3 für 256 K RAM *)
  816.   InitFont;
  817.   InitScreen(CSize);
  818.   IF ParamCount > 0 THEN GetFont(ParamStr(1));
  819.   changed := FALSE;
  820.   c := ORD('A');
  821.   SaveChar(c);
  822.   Edit;
  823. END.
  824.  
  825. (* ------------------------------------------------------ *)
  826.