UFTextTest:
CEDAR MONITOR
IMPORTS UnifiedFonts, ViewerOps, Graphics, RopeIO, RopeReader, Process, ShowTime, Scaled
= BEGIN
leading: NAT ← 2;
indent: NAT ← 6;
text: Rope.ROPE ← "Quick brown fox, jump over the lazy dogs.";
deviceType: ATOM ← $Ideal;
fontName: Rope.ROPE ← "Tioga";
size: REAL ← 10.0;
rotation: REAL ← 0;
viewer: ViewerClasses.Viewer;
positioning: UnifiedFonts.Positioning ← rounded;
spaceChar: CHAR ← ' ;
Load: PROC [fileName: Rope.ROPE] = TRUSTED {text ← RopeIO.FromFile[fileName]; Paint[]};
Paint: PROC = TRUSTED {ViewerOps.PaintViewer[viewer, client]};
CharSeq: TYPE = REF CharSeqRec;
CharSeqRec:
TYPE =
RECORD [
length: NAT ← 0,
charWidthPairs: SEQUENCE maxLength: NAT OF CharWidthPair
];
CharWidthPair:
TYPE =
RECORD [
char: CHAR,
width: Scaled.Value
];
buf1: CharSeq ← NEW[CharSeqRec[1030]];
bufAvail: CONDITION;
GetBuf: ENTRY PROC RETURNS [b: CharSeq] = {IF buf1 = NIL THEN WAIT bufAvail; b ← buf1; buf1 ← NIL; IF b = NIL THEN b ← NEW[CharSeqRec[1030]]};
FreeBuf: ENTRY PROC [b: CharSeq] = {buf1 ← b; NOTIFY bufAvail};
t, timeForPaint: ShowTime.Microseconds ← 0;
painting: BOOLEAN ← TRUE; -- make false to determine formatting time.
clippedBottomLine: BOOLEAN ← TRUE; -- make false to eliminate clipped line at bottom
TextTestPaint: ViewerClasses.PaintProc =
TRUSTED {
font: UnifiedFonts.FONT ← UnifiedFonts.Create[fontName, [size, rotation], deviceType];
ropeReader: RopeReader.Ref ← RopeReader.GetRopeReader[];
done: BOOLEAN ← FALSE;
charWidths: UnifiedFonts.WidthArray ← font.GetWidthArray[UnifiedFonts.FixedPoint, UnifiedFonts.FixedPoint];
lineWidth: Scaled.Value ← Scaled.FromInt[MAX[self.cw - 2*indent, 5]];
buf: CharSeq ← GetBuf[];
startTime: ShowTime.Microseconds ← ShowTime.GetMark[];
ylimit: REAL ← IF clippedBottomLine THEN (-font.fontBoundingBox.ymax) ELSE (1-font.fontBoundingBox.ymin);
ropeReader.SetPosition[text];
ropeReader.SetCharForEndOfRope['\377];
IF
NOT clear
THEN {
Graphics.SetColor[context, Graphics.white];
Graphics.DrawBox[context, [-100000, -100000, 100000, 100000]];
};
Graphics.SetColor[context, Graphics.black];
Graphics.Translate[context, indent, 0];
FOR y:
REAL ← self.ch - size, y - size - leading
UNTIL y<ylimit
OR done
DO
zero: Scaled.Value ← Scaled.zero;
Graphics.SetCP[context, 0, y];
done ← FormatLine[ropeReader, buf, lineWidth, charWidths];
IF painting
THEN
TRUSTED{font.DrawCharSeq[
context: context,
count: buf.length,
charPtr: @(buf[0].char),
charIncrement: SIZE[CharWidthPair],
deltaXptr: @(buf[0].width),
deltaXincrement: SIZE[CharWidthPair],
deltaYptr: @zero,
deltaYincrement: 0,
positioning: positioning
]};
ENDLOOP;
t ← timeForPaint ← ShowTime.SinceMark[startTime];
FreeBuf[buf];
};
FormatLine:
PROC [ropeReader: RopeReader.Ref, buf: CharSeq, lineLength: Scaled.Value, charWidths: UnifiedFonts.WidthArray]
RETURNS [lastLine:
BOOLEAN ←
FALSE] =
TRUSTED {
spaceLoc: ARRAY [0..200) OF NAT;
numberOfSpaces: NAT ← 0;
startIndex: INT;
totWidth: Scaled.Value ← Scaled.zero;
i: NAT ← 0;
char: CHAR;
WHILE (char ← ropeReader.Peek[])=' OR char='\t OR char='\n DO char ← ropeReader.Get[] ENDLOOP;
startIndex ← ropeReader.GetIndex[];
WHILE
NOT totWidth.
GREATER[lineLength]
DO
w: Scaled.Value;
SELECT char ← ropeReader.Get[]
FROM
'\377 => {spaceLoc[numberOfSpaces] ← i; numberOfSpaces ← numberOfSpaces + 1; buf[i] ← [spaceChar, Scaled.zero]; i ← i+1; lastLine ← TRUE; EXIT};
'\n => {spaceLoc[numberOfSpaces] ← i; numberOfSpaces ← numberOfSpaces + 1; buf[i] ← [spaceChar, Scaled.zero]; i ← i+1; EXIT};
' , '\t => {spaceLoc[numberOfSpaces] ← i; numberOfSpaces ← numberOfSpaces + 1; w ← charWidths[char]; char ← spaceChar};
ENDCASE => w ← charWidths[char];
buf[i] ← [char, w];
totWidth ← totWidth.PLUS[w];
i ← i+1;
ENDLOOP;
WHILE i>1
AND totWidth.
GREATER[lineLength]
DO
i ← i-1;
totWidth ← totWidth.MINUS[buf[i].width];
ENDLOOP;
WHILE numberOfSpaces>0 AND spaceLoc[numberOfSpaces-1] > i DO numberOfSpaces ← numberOfSpaces-1 ENDLOOP;
IF numberOfSpaces>0 THEN i ← spaceLoc[numberOfSpaces-1];
ropeReader.SetIndex[startIndex + i];
buf.length ← i;
};
Create:
PROCEDURE
RETURNS [viewer: ViewerClasses.Viewer] =
TRUSTED {
viewer ← ViewerOps.CreateViewer[flavor: $UFTextTest, info: [name: "Text Tester"], paint: TRUE];
};
textTestClass: ViewerClasses.ViewerClass ←
NEW[ViewerClasses.ViewerClassRec ← [
paint: TextTestPaint,
tipTable: NIL
]];
TRUSTED {ViewerOps.RegisterViewerClass[$UFTextTest, textTestClass]};
TRUSTED {Process.InitializeCondition[@bufAvail, Process.MsecToTicks[500]]};
viewer ← Create[];
END.