TextInVoiceImpl.mesa:
it's all getting so recursive !!!! - routines which draw the artwork around voice viewers; that artwork is actually a textual display
 Ades, April 30, 1986 10:09:49 am PDT
Swinehart, March 23, 1987 2:46:43 pm PST
although the extents and positions of text in artworks are given in terms of constants from VoiceMarkers, note that the line spacing is set up independently by VoiceProfile.Style
DIRECTORY
Rope USING [ROPE],
Imager USING [Context, Move, ShowChar, SetStrokeWidth, SetStrokeJoint, MaskStroke, SetXY, ShowRope, SetFont, black, SetColor],
ImagerFont USING [Extents, Escapement, Font],
ImagerPath USING [PathProc],
TextNode USING [Location],
NodeStyle USING [Ref],
NodeStyleOps USING [OfStyle],
TEditFormat USING [CharacterArtwork, CharacterArtworkRep, CharacterArtworkClass, CharacterArtworkClassRep, RegisterCharacterArtwork, GetFont],
TextEdit USING [FetchChar, CharSet, GetCharProp],
Vector2 USING [VEC],
VoiceMarkers USING [voiceMarkerFont, voiceCharSet, voiceCharHeight, voiceCharDescent];
TextInVoiceImpl: CEDAR PROGRAM IMPORTS Imager, ImagerFont, TEditFormat, TextEdit, VoiceMarkers = BEGIN
VoiceMarkerDataRep: TYPE ~ RECORD [
letter: CHAR,
label: Rope.ROPE,
charHeight: REAL,
charWidth: REAL
];
VoiceMarkerPaint: PROC [self: TEditFormat.CharacterArtwork, context: Imager.Context] ~ {
data: REF VoiceMarkerDataRep ~ NARROW[self.data];
DrawArrow: ImagerPath.PathProc = {
moveTo[[0.0, 2.0*data.charHeight]];
lineTo[[0.0, data.charHeight]];
lineTo[[3.0, 4.0*data.charHeight/3.0]];
lineTo[[-2.0, 4.0*data.charHeight/3.0]];
lineTo[[0.0, data.charHeight]]
};
Imager.Move[context];
Imager.ShowChar[context, data.letter];
Imager.SetColor[context, Imager.black];
Imager.SetStrokeWidth[context, 1.0];
Imager.SetStrokeJoint[context, round];
Imager.MaskStroke[context, DrawArrow, TRUE];
Imager.SetXY[context, [2.0, 3.0*data.charHeight/2.0]];
Imager.SetFont[context, VoiceMarkers.voiceMarkerFont];
Imager.ShowRope[context, data.label];
};
VoiceMarkerFormat: PROC [class: TEditFormat.CharacterArtworkClass, loc: TextNode.Location, style: NodeStyle.Ref, kind: NodeStyleOps.OfStyle] RETURNS [TEditFormat.CharacterArtwork] ~ {
voiceCharSet: TextEdit.CharSet ← TextEdit.FetchChar[loc.node, loc.where].charSet;
letter: CHAR ← TextEdit.FetchChar[loc.node, loc.where].char;
label: Rope.ROPENARROW[TextEdit.GetCharProp[loc.node, loc.where, $VoiceMark], Rope.ROPE];
escapement: Vector2.VEC ← ImagerFont.Escapement[TEditFormat.GetFont[style], [set: VoiceMarkers.voiceCharSet, code: letter-'\000]];
charWidth: REAL ← escapement.x;
data: REF VoiceMarkerDataRep ~ NEW[VoiceMarkerDataRep ← [
letter: letter,
label: label,
charHeight: VoiceMarkers.voiceCharHeight,
charWidth: charWidth
]];
extents: ImagerFont.Extents ← [leftExtent: 0.0, rightExtent: 20.0, ascent: 5.0*data.charHeight/2.0, descent: VoiceMarkers.voiceCharDescent];
RETURN [NEW[TEditFormat.CharacterArtworkRep ← [paint: VoiceMarkerPaint, extents: extents, escapement: escapement, data: data]]]
};
talksBubbleClass: TEditFormat.CharacterArtworkClass ~ NEW[TEditFormat.CharacterArtworkClassRep ← [
name: $VoiceMarker,
format: VoiceMarkerFormat,
data: NIL
]];
TEditFormat.RegisterCharacterArtwork[talksBubbleClass];
END.