ð#Syntax10.Scn.FntôRôRMODULE FontEdit; (* gri 22.10.92 / mh 24.9.1994 *) IMPORT Input, Display, Files, Texts, TextFrames, Viewers, MenuViewers, Oberon, FEFonts, Fonts; CONST default = ORD("A"); black = Display.black; white = Display.white; left = 2; middle = 1; right = 0; cancel = {left, middle, right}; width = 50; height = 40; side = 9; LeftMarg = 20; TopMarg = 50; MetrMarg = 30; (* Color version: *) MetricLineCol = 13; (* grey *) SelectCol = 1; (* red *) (* BW Version: MetricLineCol = white; SelectCol = white; *) UpdateProbeStr = 100; TYPE Frame = POINTER TO FrameDesc; FrameDesc = RECORD (Display.FrameDesc) font: FEFonts.Font; this: INTEGER; undo: FEFonts.Character; focus: BOOLEAN; iMin, jMin: INTEGER; (* minimum i and j values in this frame *) (* iMin <= 0; jMin <= 0 *) probe: ARRAY 128 OF CHAR; END ; FrameMsg = RECORD (Display.FrameMsg) font: FEFonts.Font; op, ch, i, j: INTEGER END ; VAR W: Texts.Writer; DIGIT: ARRAY 16+1 OF CHAR; PROCEDURE AppendInt (n: INTEGER; base: INTEGER; VAR str: ARRAY OF CHAR); VAR i: INTEGER; PROCEDURE Digit(k: INTEGER); BEGIN IF k > base-1 THEN Digit(k DIV base) END ; str[i] := DIGIT[k MOD base]; INC(i) END Digit; BEGIN i := 0; ASSERT(base <= 16); WHILE str[i] # 0X DO INC(i) END ; IF n < 0 THEN str[i] := "-"; INC(i); n := -n END ; Digit(n); str[i] := 0X; END AppendInt; PROCEDURE AppendStr (s: ARRAY OF CHAR; VAR str: ARRAY OF CHAR); VAR n, k: INTEGER; BEGIN n := 0; k := 0; WHILE str[n] # 0X DO INC(n) END ; WHILE s[k] # 0X DO str[n] := s[k]; INC(n); INC(k) END ; str[n] := 0X; END AppendStr; PROCEDURE MarkMenu (F: Frame); VAR R: Texts.Reader; V: Viewers.Viewer; T: Texts.Text; ch: CHAR; BEGIN V := Viewers.This(F.X, F.Y); IF (V IS MenuViewers.Viewer) & (V.dsc IS TextFrames.Frame) THEN T := V.dsc(TextFrames.Frame).text; IF T.len > 0 THEN Texts.OpenReader(R, T, T.len - 1); Texts.Read(R, ch) ELSE ch := 0X END ; IF ch # "!" THEN Texts.Write(W, "!"); Texts.Append(T, W.buf) END END END MarkMenu; PROCEDURE DispString (F: Frame; s: ARRAY OF CHAR; X, Y: INTEGER; col: INTEGER); VAR i, x, y, w, h, dx: INTEGER; pat: LONGINT; BEGIN i := 0; WHILE s[i] # 0X DO Display.GetChar(Fonts.Default.raster, s[i], dx, x, y, w, h, pat); Display.CopyPatternC(F, col, pat, X+x, Y+y, Display.paint); INC(X, dx); INC(i); END END DispString; PROCEDURE Block (F: Display.Frame; X, Y, W, H, col: INTEGER); VAR x, y: INTEGER; keys: SET; BEGIN Display.ReplConstC(F, col, X, Y, W, H, Display.replace); END Block; PROCEDURE Notify (F: FEFonts.Font; op, ch, i, j: INTEGER); VAR msg: FrameMsg; BEGIN msg.font := F; msg.op := op; msg.ch := ch; msg.i := i; msg.j := j; Viewers.Broadcast(msg) END Notify; PROCEDURE ToGlobal (F: Frame; i, j: INTEGER; VAR X, Y: INTEGER); BEGIN X := F.X + LeftMarg + (i - F.iMin)*side; Y := F.Y + F.H - (TopMarg + height*side) + (j - F.jMin)*side END ToGlobal; PROCEDURE ToLocal (F: Frame; X, Y: INTEGER; VAR i, j: INTEGER); BEGIN i := F.iMin + (X - F.X - LeftMarg) DIV side; j := F.jMin + (Y - F.Y - F.H + (TopMarg + height*side)) DIV side END ToLocal; PROCEDURE HLine (F: Frame; j, col: INTEGER); VAR X, X1, Y: INTEGER; BEGIN IF (F.jMin <= j) & (j <= F.jMin + height) THEN ToGlobal(F, F.iMin, j, X, Y); IF j # 0 THEN INC(X, 2); X1 := X + width*side; WHILE X < X1 DO Block(F, X, Y, side-3, 1, col); INC(X, side) END END END END HLine; PROCEDURE VLine (F: Frame; i, col: INTEGER); VAR X, Y, Y1: INTEGER; BEGIN IF (F.iMin <= i) & (i <= F.iMin + width) THEN ToGlobal(F, i, F.jMin, X, Y); Y1 := Y + height*side; IF i # 0 THEN INC(Y, 2); WHILE Y < Y1 DO Block(F, X, Y, 1, side-3, col); INC(Y, side) END END END END VLine; PROCEDURE DrawSmallChar (F: Frame; ascii: INTEGER; X, Y, col: INTEGER); VAR dx, x, y, w, h, i, j: INTEGER; val: BOOLEAN; BEGIN FEFonts.GetMetric(F.font, ascii, dx, x, y, w, h); j := y; WHILE j < y+h DO i := x; WHILE i < x+w DO FEFonts.GetDot(F.font, ascii, i, j, val); IF val THEN Display.DotC(F, col, X + i, Y + j, Display.replace); END ; INC(i) END ; INC(j) END END DrawSmallChar; PROCEDURE DrawProbeString (F: Frame; col: INTEGER); VAR i, dx, x, y, w, h, X, Y: INTEGER; BEGIN i := 0; X := F.X + LeftMarg; Y := F.Y+F.H-TopMarg-height*side-40; WHILE F.probe[i] # 0X DO FEFonts.GetMetric(F.font, ORD(F.probe[i]), dx, x, y, w, h); DrawSmallChar(F, ORD(F.probe[i]), X, Y, col); INC(X, dx); INC(i); END END DrawProbeString; PROCEDURE DrawChar (F: Frame; col: INTEGER); VAR dx, x, y, w, h, i, j, X0, X, Y, col0: INTEGER; val: BOOLEAN; ascii: ARRAY 16 OF CHAR; BEGIN IF col = black THEN col0 := black ELSE col0 := white END ; Oberon.RemoveMarks(F.X, F.Y, F.W, F.H); FEFonts.GetMetric(F.font, F.this, dx, x, y, w, h); ToGlobal(F, x, y, X0, Y); j := y; WHILE j < y+h DO X := X0; i := x; WHILE i < x+w DO FEFonts.GetDot(F.font, F.this, i, j, val); IF val THEN IF (F.iMin <= i) & (i < F.iMin+width) & (F.jMin <= j) & (j < F.jMin + height) THEN Block(F, X+1, Y+1, side-1, side-1, col) END END ; INC(X, side); INC(i) END ; INC(Y, side); INC(j) END ; IF col = black THEN VLine(F, dx, black) ELSE VLine(F, dx, MetricLineCol) END ; ascii := "ASCII "; AppendInt(F.this, 10, ascii); AppendStr(" (", ascii); AppendInt(F.this, 16, ascii); AppendStr("X)", ascii); DispString(F, ascii, F.X + LeftMarg, F.Y + F.H - MetrMarg, col0); END DrawChar; PROCEDURE DrawMetrics(F: Frame; col: INTEGER); VAR s: ARRAY 64 OF CHAR; BEGIN s := ""; AppendStr("height = ", s); AppendInt(F.font.height, 10, s); AppendStr(" minX = ", s); AppendInt(F.font.minX, 10, s); AppendStr(" maxX = ", s); AppendInt(F.font.maxX, 10, s); AppendStr(" minY = ", s); AppendInt(F.font.minY, 10, s); AppendStr(" maxY = ", s); AppendInt(F.font.maxY, 10, s); DispString(F, s, F.X + LeftMarg + 130, F.Y + F.H - MetrMarg, col); END DrawMetrics; PROCEDURE DrawGrid (F: Frame; col: INTEGER); VAR i, j, X0, X, Y: INTEGER; BEGIN Oberon.RemoveMarks(F.X, F.Y, F.W, F.H); ToGlobal(F, F.iMin, F.jMin, X0, Y); j := F.jMin; WHILE j <= F.jMin + height DO IF j # 0 THEN X := X0; i := F.iMin; WHILE i <= F.iMin + width DO IF i # 0 THEN Display.DotC(F, col, X, Y, Display.replace) END ; INC(X, side); INC(i) END END ; INC(Y, side); INC(j) END END DrawGrid; PROCEDURE DrawAxis (F: Frame; col: INTEGER); VAR X, Y: INTEGER; BEGIN Oberon.RemoveMarks(F.X, F.Y, F.W, F.H); ToGlobal(F, 0, F.jMin, X, Y); IF F.focus THEN Block(F, X, Y, 1, height*side + 1, col) ELSE Display.ReplPatternC(F, col, Display.grey1, X, Y, 1, height*side + 1, X, Y, Display.replace) END ; ToGlobal(F, F.iMin, 0, X, Y); IF F.focus THEN Block(F, X, Y, width*side + 1, 1, col) ELSE Display.ReplPatternC(F, col, Display.grey1, X, Y, width*side + 1, 1, X, Y, Display.replace) END END DrawAxis; PROCEDURE UpdateProbeString (F: Frame); BEGIN Display.ReplConstC(F, black, F.X + LeftMarg, F.Y+F.H-TopMarg-height*side-80, F.W, 80, Display.replace); DrawProbeString(F, white); END UpdateProbeString; PROCEDURE UpdateDot (F: Frame; i, j: INTEGER); VAR X, Y, X1, Y1, col: INTEGER; val: BOOLEAN; BEGIN Oberon.RemoveMarks(F.X, F.Y, F.W, F.H); ToGlobal(F, i, j, X, Y); FEFonts.GetDot(F.font, F.this, i, j, val); IF val THEN col := white ELSE col := black END ; Block(F, X+1, Y+1, side-1, side-1, col); END UpdateDot; PROCEDURE UpdateChar (F: Frame; H: INTEGER); BEGIN Oberon.RemoveMarks(F.X, F.Y, F.W, F.H); Block(F, F.X, F.Y, F.W, H, black); DrawAxis(F, white); DrawChar(F, white); HLine(F, F.font.minY, MetricLineCol); HLine(F, F.font.maxY, MetricLineCol); DrawMetrics(F, white); DrawProbeString(F, white); END UpdateChar; PROCEDURE UpdateGrid (F: Frame; GridCol: INTEGER); BEGIN Oberon.RemoveMarks(F.X, F.Y, F.W, F.H); Block(F, F.X + LeftMarg, F.Y+F.H-TopMarg-height*side, width*side+1, height*side+1, black); DrawAxis(F, GridCol); DrawChar(F, white); HLine(F, F.font.minY, MetricLineCol); HLine(F, F.font.maxY, MetricLineCol); END UpdateGrid; PROCEDURE MoveXY (F: Frame; di, dj: INTEGER); VAR dx, x, y, w, h, i, j, X0, X, Y, X1, Y1, col: INTEGER; val0, val: BOOLEAN; BEGIN Oberon.RemoveMarks(F.X, F.Y, F.W, F.H); FEFonts.GetMetric(F.font, F.this, dx, x, y, w, h); ToGlobal(F, F.iMin + width, 28, X1, Y1); INC(X1, 2*LeftMarg); ToGlobal(F, x-di, y-dj, X0, Y); j := y; WHILE j < y+h DO X := X0; i := x; WHILE i < x+w DO FEFonts.GetDot(F.font, F.this, i, j, val0); FEFonts.GetDot(F.font, F.this, i-di, j-dj, val); IF val0 # val THEN IF val THEN col := white ELSE col := black END ; Block(F, X+1, Y+1, side-1, side-1, col) END ; INC(X, side); INC(i) END ; INC(Y, side); INC(j) END ; ToGlobal(F, x, y, X0, Y); j := y; WHILE j < y+h DO X := X0; i := x; WHILE i < x+w DO FEFonts.GetDot(F.font, F.this, i+di, j+dj, val0); FEFonts.GetDot(F.font, F.this, i, j, val); IF val0 # val THEN IF val THEN col := white ELSE col := black END ; Block(F, X+1, Y+1, side-1, side-1, col) END ; INC(X, side); INC(i) END ; INC(Y, side); INC(j) END ; END MoveXY; PROCEDURE MoveDx (F: Frame; di: INTEGER); VAR dx, x, y, w, h: INTEGER; BEGIN Oberon.RemoveMarks(F.X, F.Y, F.W, F.H); FEFonts.GetMetric(F.font, F.this, dx, x, y, w, h); VLine(F, dx-di, black); VLine(F, dx, MetricLineCol); END MoveDx; PROCEDURE TrackMouse (F: Frame; keys: SET; X, Y: INTEGER); VAR dx0, x0, y0, dx, x, y, w, h, i0, j0, i, j: INTEGER; keySum: SET; val0, val: BOOLEAN; undo: FEFonts.Character; BEGIN keySum := keys; ToLocal(F, X, Y, i0, j0); FEFonts.GetMetric(F.font, F.this, dx0, x0, y0, w, h); IF (keys = {middle}) & (dx0 = i0) THEN (* move dx line *) VLine(F, dx0, SelectCol); LOOP Input.Mouse(keys, X, Y); keySum := keySum + keys; ToLocal(F, X, Y, i, j); Oberon.DrawCursor(Oberon.Mouse, Oberon.Arrow, X, Y); IF keys = {} THEN EXIT END ; IF i # i0 THEN FEFonts.GetMetric(F.font, F.this, dx, x, y, w, h); INC(dx, i-i0); IF (F.iMin <= dx) & (dx <= F.iMin+width) THEN FEFonts.MoveDx(F.font, F.this, i-i0) END ; i0 := i; VLine(F, dx, SelectCol); END END ; VLine(F, dx, MetricLineCol); IF keySum = cancel THEN FEFonts.GetMetric(F.font, F.this, dx, x, y, w, h); FEFonts.MoveDx(F.font, F.this, dx0-dx) ELSE FEFonts.UpdateMetrics(F.font); Notify(F.font, UpdateProbeStr, 0, 0, 0); MarkMenu(F) END ELSIF left IN keys THEN IF ~F.focus THEN Oberon.PassFocus(MenuViewers.Ancestor); F.focus := TRUE; DrawAxis(F, white); REPEAT Input.Mouse(keys, X, Y) UNTIL keys = {}; ELSE FEFonts.GetChar(F.font, F.this, undo); FEFonts.GetDot(F.font, F.this, i0, j0, val0); DEC(i0); LOOP Input.Mouse(keys, X, Y); keySum := keySum + keys; ToLocal(F, X, Y, i, j); Oberon.DrawCursor(Oberon.Mouse, Oberon.Arrow, X, Y); IF keys = {} THEN EXIT END ; IF ((i # i0) OR (j # j0)) & (F.iMin <= i) & (i < F.iMin + width) & (F.jMin <= j) & (j < F.jMin + height) THEN FEFonts.GetDot(F.font, F.this, i, j, val); IF val = val0 THEN FEFonts.SetDot(F.font, F.this, i, j, ~val0) END ; i0 := i; j0 := j END END ; IF keySum = cancel THEN FEFonts.SetChar(F.font, F.this, undo) ELSE FEFonts.UpdateMetrics(F.font); Notify(F.font, UpdateProbeStr, 0, 0, 0); MarkMenu(F) END END ELSIF middle IN keys THEN FEFonts.GetMetric(F.font, F.this, dx0, x0, y0, w, h); FEFonts.GetDot(F.font, F.this, i0, j0, val); IF val THEN (* move character *) DrawChar(F, SelectCol); LOOP Input.Mouse(keys, X, Y); keySum := keySum + keys; ToLocal(F, X, Y, i, j); Oberon.DrawCursor(Oberon.Mouse, Oberon.Arrow, X, Y); IF keys = {} THEN EXIT END ; IF (i # i0) OR (j # j0) THEN FEFonts.GetMetric(F.font, F.this, dx, x, y, w, h); INC(x, i-i0); INC(y, j-j0); IF (F.iMin <= x) & (x + w <= F.iMin + width) & (F.jMin <= y) & (y + h <= F.jMin + height) THEN FEFonts.MoveXY(F.font, F.this, i-i0, j-j0); DrawChar(F, SelectCol); END ; i0 := i; j0 := j END END ; DrawChar(F, white); IF keySum = cancel THEN FEFonts.GetMetric(F.font, F.this, dx, x, y, w, h); FEFonts.MoveXY(F.font, F.this, x0-x, y0-y) ELSE FEFonts.UpdateMetrics(F.font); Notify(F.font, UpdateProbeStr, 0, 0, 0); MarkMenu(F); END ELSE (* move origin *) ToLocal(F, X, Y, i0, j0); FEFonts.GetMetric(F.font, F.this, dx, x, y, w, h); DrawAxis(F, SelectCol); LOOP Input.Mouse(keys, X, Y); keySum := keySum + keys; ToLocal(F, X, Y, i, j); Oberon.DrawCursor(Oberon.Mouse, Oberon.Arrow, X, Y); IF keys = {} THEN EXIT END ; IF (i # i0) OR (j # j0) THEN INC(F.iMin, i0-i); IF F.iMin > -1 THEN F.iMin := -1 ELSIF F.iMin < -(width-1) THEN F.iMin := -(width-1) END ; INC(F.jMin, j0-j); IF F.jMin > -1 THEN F.jMin := -1 ELSIF F.jMin < -(height-1) THEN F.jMin := -(height-1) END ; ToLocal(F, X, Y, i0, j0); UpdateGrid(F, SelectCol); END END ; DrawAxis(F, white); END ELSE Oberon.DrawCursor(Oberon.Mouse, Oberon.Arrow, X, Y) END END TrackMouse; PROCEDURE ConsumeChar (F: Frame; ch: INTEGER); BEGIN IF ch = 0C4H THEN ch := (F.this - 1) MOD 100H ELSIF ch = 0C3H THEN ch := (F.this + 1) MOD 100H END ; IF ch # F.this THEN DrawChar(F, black); F.this := ch; FEFonts.GetChar(F.font, F.this, F.undo); DrawChar(F, white) END END ConsumeChar; PROCEDURE Modify (F: Frame; Y, H: INTEGER); VAR dH: INTEGER; BEGIN dH := H-F.H; IF dH > 0 THEN (* extend *) IF F.Y+F.H # Y+H THEN Display.CopyBlock(F.X, F.Y, F.W, F.H, F.X, Y+dH, Display.replace) END ; F.Y := Y; F.H := H; UpdateChar(F, dH) ELSIF dH < 0 THEN (* reduce *) IF F.Y+F.H # Y+H THEN Display.CopyBlock(F.X, F.Y-dH, F.W, H, F.X, Y, Display.replace) END ; F.Y := Y; F.H := H END END Modify; PROCEDURE Handle (f: Display.Frame; VAR msg: Display.FrameMsg); VAR F: Frame; CopyOfF: Frame; BEGIN F := f(Frame); IF msg IS FrameMsg THEN WITH msg: FrameMsg DO IF msg.font = F.font THEN IF msg.op = FEFonts.updateFontMetrics THEN UpdateChar(F, F.H); MarkMenu(F) ELSIF msg.op = UpdateProbeStr THEN UpdateProbeString(F) ELSIF msg.ch = F.this THEN IF msg.op = FEFonts.updateDot THEN UpdateDot(F, msg.i, msg.j) ELSIF msg.op = FEFonts.updateChar THEN UpdateChar(F, F.H) ELSIF msg.op = FEFonts.moveXY THEN MoveXY(F, msg.i, msg.j) ELSIF msg.op = FEFonts.moveDx THEN MoveDx(F, msg.i) END END END END ELSIF msg IS Oberon.InputMsg THEN WITH msg: Oberon.InputMsg DO IF (msg.id = Oberon.consume) & F.focus THEN ConsumeChar(F, ORD(msg.ch)) ELSIF msg.id = Oberon.track THEN TrackMouse (F, msg.keys, msg.X, msg.Y) END END ELSIF msg IS Oberon.ControlMsg THEN WITH msg: Oberon.ControlMsg DO IF ((msg.id = Oberon.defocus) OR (msg.id = Oberon.neutralize)) & F.focus THEN F.focus := FALSE; DrawAxis(F, white) END END ELSIF msg IS Oberon.CopyMsg THEN WITH msg: Oberon.CopyMsg DO NEW(CopyOfF); CopyOfF^ := F^; CopyOfF.focus := FALSE; msg.F := CopyOfF END ELSIF msg IS MenuViewers.ModifyMsg THEN WITH msg: MenuViewers.ModifyMsg DO Modify(F, msg.Y, msg.H) END END END Handle; PROCEDURE OpenScanner (VAR S: Texts.Scanner); VAR Sel: Texts.Text; beg, end, time: LONGINT; BEGIN Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos); Texts.Scan(S); IF (S.class = Texts.Char) & (S.line = 0) & (S.c = "^") THEN Oberon.GetSelection(Sel, beg, end, time); IF time >= 0 THEN Texts.OpenScanner(S, Sel, beg) ELSE S.class := Texts.Inval END ELSE Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos); END END OpenScanner; PROCEDURE Open*; VAR S: Texts.Scanner; F: Frame; X, Y: INTEGER; V: MenuViewers.Viewer; font: FEFonts.Font; menu: TextFrames.Frame; buf: Texts.Buffer; T: Texts.Text; BEGIN OpenScanner(S); Texts.Scan(S); IF (S.class = Texts.Name) & (S.line = 0) THEN font := FEFonts.This(S.s); IF font # NIL THEN font.notify := Notify; NEW(F); F.handle := Handle; F.font := font; F.this := default; FEFonts.GetChar(font, default, F.undo); F.focus := FALSE; F.iMin := -16; F.jMin := -16; F.probe := "Hamburgefon"; IF Files.Old("FontEdit.Menu.Text") = NIL THEN menu := TextFrames.NewMenu(font.name, "System.Close System.Copy System.Grow FontEdit.Undo FontEdit.Store "); ELSE menu := TextFrames.NewMenu(font.name, ""); NEW(T); Texts.Open(T, "FontEdit.Menu.Text"); NEW(buf); Texts.OpenBuf(buf); Texts.Save(T, 0, T.len, buf); Texts.Append(menu.text, buf) END ; Oberon.AllocateUserViewer(Oberon.Mouse.X, X, Y); V := MenuViewers.New(menu, F, TextFrames.menuH, X, Y) ELSE Texts.WriteString(W, S.s); Texts.WriteString(W, " not found"); Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf); END END END Open; PROCEDURE GetFrame(): Frame; VAR F: Frame; V: Viewers.Viewer; BEGIN F := NIL; IF Oberon.Par.frame = Oberon.Par.vwr.dsc THEN IF Oberon.Par.frame.next IS Frame THEN F := Oberon.Par.frame.next(Frame) END ELSE V := Oberon.MarkedViewer(); IF (V # NIL) & (V.dsc # NIL) & (V.dsc.next # NIL) THEN IF V.dsc.next IS Frame THEN F := V.dsc.next(Frame) END END END ; RETURN F END GetFrame; PROCEDURE Store*; VAR F: Frame; S: Texts.Scanner; t: Texts.Text; BEGIN F := GetFrame(); IF F # NIL THEN t := Oberon.Par.vwr.dsc(TextFrames.Frame).text; Texts.OpenScanner(S, t, 0); Texts.Scan(S); IF (S.class = Texts.Name) & (S.line = 0) THEN Texts.WriteString(W, "FontEdit.Store "); Texts.Append(Oberon.Log, W.buf); FEFonts.Store(S.s, F.font); Texts.WriteString(W, S.s); Texts.WriteLn(W); IF F.font.height < F.font.maxY - F.font.minY THEN Texts.WriteString(W, " WARNING: font height < maxY - minY !"); Texts.WriteLn(W); END ; Texts.Append(Oberon.Log, W.buf); Texts.OpenReader(S, t, t.len-1); Texts.Read(S, S.c); IF S.c = "!" THEN Texts.Delete(t, t.len-1, t.len) END ; END END END Store; PROCEDURE Show*; VAR S: Texts.Scanner; F: Frame; char: FEFonts.Character; n, ascii: INTEGER; s: ARRAY 16 OF CHAR; ch: CHAR; PROCEDURE HexVal(ch: CHAR): INTEGER; BEGIN IF ("0" <= ch) & (ch <= "9") THEN RETURN ORD(ch) - ORD("0") ELSIF ("A" <= ch) & (ch <= "F") OR ("a" <= ch) & (ch <= "f") THEN RETURN ORD(CAP(ch)) - ORD("A") + 10; END ; RETURN -1; END HexVal; BEGIN F := GetFrame(); IF F # NIL THEN OpenScanner(S); n := 0; ascii := -1; WHILE (S.nextCh <= " ") & ~S.eot DO Texts.Read(S, S.nextCh) END ; IF ~S.eot THEN ch := S.nextCh; REPEAT s[n] := S.nextCh; INC(n); Texts.Read(S, S.nextCh) UNTIL (S.nextCh <= " ") OR (n = 16); IF n > 1 THEN IF s[n-1] = "X" THEN ascii := HexVal(s[n-2]); IF (ascii >= 0) & (n > 2) THEN INC(ascii, 16*HexVal(s[n-3])) END END END ; IF (ascii < 0) & (n > 0) THEN ascii := ORD(s[0]) END ; IF (ascii > 0) & (ascii # F.this) THEN DrawChar(F, black); F.this := ascii; FEFonts.GetChar(F.font, F.this, F.undo); DrawChar(F, white) END END END END Show; PROCEDURE CopyFrom*; VAR src, targ: Frame; V: Viewers.Viewer; BEGIN src := GetFrame(); IF src # NIL THEN V := Oberon.FocusViewer; IF (V # NIL) & (V IS MenuViewers.Viewer) & (V.dsc.next IS Frame) THEN targ := V.dsc.next(Frame); IF src # targ THEN DrawChar(targ, black); FEFonts.GetChar(src.font, src.this, targ.undo); (*targ.this := src.this;*) FEFonts.SetChar(targ.font, targ.this, targ.undo); DrawChar(targ, white) END END END END CopyFrom; PROCEDURE Commit*; VAR F: Frame; BEGIN F := GetFrame(); IF F # NIL THEN FEFonts.Commit(F.font, F.this) END END Commit; PROCEDURE Undo*; VAR F: Frame; BEGIN F := GetFrame(); IF F # NIL THEN FEFonts.Undo(F.font, F.this); FEFonts.UpdateMetrics(F.font); Notify(F.font, UpdateProbeStr, 0, 0, 0); END END Undo; PROCEDURE Next*; VAR F: Frame; BEGIN F := GetFrame(); IF F # NIL THEN DrawChar(F, black); F.this := (F.this + 1) MOD 100H; FEFonts.GetChar(F.font, F.this, F.undo); DrawChar(F, white) END END Next; PROCEDURE Prev*; VAR F: Frame; BEGIN F := GetFrame(); IF F # NIL THEN DrawChar(F, black); F.this := (F.this - 1) MOD 100H; FEFonts.GetChar(F.font, F.this, F.undo); DrawChar(F, white) END END Prev; PROCEDURE SetProbe*; VAR F: Frame; S: Texts.Scanner; BEGIN F := GetFrame(); IF F # NIL THEN OpenScanner(S); Texts.Scan(S); IF S.class IN {Texts.Name, Texts.String} THEN DrawProbeString(F, black); COPY(S.s, F.probe); DrawProbeString(F, white) END END END SetProbe; PROCEDURE SetHeight*; VAR F: Frame; S: Texts.Scanner; BEGIN F := GetFrame(); IF F # NIL THEN OpenScanner(S); Texts.Scan(S); IF S.class = Texts.Int THEN FEFonts.SetHeight(F.font, SHORT(S.i)) ELSIF (S.class = Texts.Name) & (S.s = "default") THEN FEFonts.SetHeight(F.font, F.font.maxY - F.font.minY) END ; END END SetHeight; BEGIN Texts.OpenWriter(W); DIGIT := "0123456789ABCDEF"; END FontEdit. FontEdit.Open Syntax16.Scn.Fnt