<> <> << Ades, September 22, 1986 6:18:07 pm PDT>> <<>> DIRECTORY Rope USING [ROPE, Fetch, Length], Basics USING [BYTE], Imager USING [Color, Context, Move, SetColor, ShowChar, ShowRope, SetStrokeWidth, SetStrokeJoint, MaskStroke], ImagerPath USING [PathProc], ImagerColorDefs USING [ConstantColor], ImagerColorPrivate USING [ColorFromStipple], ImagerFont USING [Extents, FontBoundingBox, Width], TextNode USING [Location], NodeStyle USING [Ref, GetReal], NodeStyleOps USING [OfStyle], TEditFormatExtras USING [CharacterArtwork, CharacterArtworkRep, CharacterArtworkClass, CharacterArtworkClassRep, RegisterCharacterArtwork, GetFont], TextEdit USING [FetchChar, CharSet, GetCharProp], Vector2 USING [VEC], VoiceInText USING [VoiceWindowRef]; TalksBubbleImpl: CEDAR PROGRAM IMPORTS Rope, Imager, ImagerColorPrivate, ImagerFont, NodeStyle, TEditFormatExtras, TextEdit = BEGIN TalksBubbleDataRep: TYPE ~ RECORD [ letter: CHAR, label: Rope.ROPE, ascent: REAL, descent: REAL, width: REAL, bearoff: REAL, firstCharWidth: REAL ]; TalksBubblePaint: PROC [self: TEditFormatExtras.CharacterArtwork, context: Imager.Context] ~ { data: REF TalksBubbleDataRep ~ NARROW[self.data]; DrawBubble: ImagerPath.PathProc = { height: REAL _ data.ascent + data.descent; moveTo[[data.bearoff, -data.descent+(height/4)]]; lineTo[[data.bearoff, -data.descent+(3*height/4)]]; arcTo[[data.bearoff+(data.width/2), -data.descent+height], [data.bearoff + data.width, -data.descent+(3*height/4)]]; lineTo[[data.bearoff+data.width, -data.descent+(height/4)]]; arcTo[[data.bearoff+(15*data.width/16), -data.descent+(height/16)], [data.bearoff + (3*data.width/4), -data.descent]]; lineTo[[data.bearoff+(data.width/4), -data.descent-(height/2)]]; lineTo[[data.bearoff+(data.width/2), -data.descent]]; lineTo[[data.bearoff+(data.width/4), -data.descent]]; arcTo[[data.bearoff+(data.width/16), -data.descent+(height/16)], [data.bearoff, -data.descent+(height/4)]]; }; DrawBox: ImagerPath.PathProc = { moveTo[[data.bearoff+data.firstCharWidth, -data.descent]]; lineTo[[data.bearoff+data.firstCharWidth, data.ascent]]; lineTo[[data.bearoff+data.width, data.ascent]]; lineTo[[data.bearoff+data.width, -data.descent]]; lineTo[[data.bearoff+data.firstCharWidth, -data.descent]] }; Imager.Move[context]; Imager.ShowChar[context, data.letter]; IF data.label = NIL THEN { Imager.SetStrokeWidth[context, 1.0]; Imager.SetStrokeJoint[context, round]; Imager.MaskStroke[context, DrawBubble, TRUE] } ELSE { Imager.SetColor[context, textColor]; Imager.ShowRope[context, data.label]; Imager.SetStrokeWidth[context, 1.0]; Imager.SetStrokeJoint[context, round]; Imager.MaskStroke[context, DrawBox, TRUE] } }; TalksBubbleFormat: PROC [class: TEditFormatExtras.CharacterArtworkClass, loc: TextNode.Location, style: NodeStyle.Ref, kind: NodeStyleOps.OfStyle] RETURNS [TEditFormatExtras.CharacterArtwork] ~ { charSet: TextEdit.CharSet _ TextEdit.FetchChar[loc.node, loc.where].charSet; letter: CHAR _ TextEdit.FetchChar[loc.node, loc.where].char; ascent: REAL _ NodeStyle.GetReal[style, backgroundAscent]; descent: REAL _ NodeStyle.GetReal[style, backgroundDescent]; width: REAL; bearoff: REAL _ NodeStyle.GetReal[style, outlineboxBearoff]; windowRef: VoiceInText.VoiceWindowRef _ NARROW[TextEdit.GetCharProp[loc.node, loc.where, $voiceWindow], VoiceInText.VoiceWindowRef]; label: Rope.ROPE _ IF windowRef = NIL THEN NIL ELSE windowRef.label; escapement: Vector2.VEC _ ImagerFont.Width[TEditFormatExtras.GetFont[style], [set: charSet, code: letter-'\000]]; firstCharWidth: REAL _ escapement.x; IF label # NIL THEN FOR i: INT IN [0..label.Length) DO escapement.x _ escapement.x + ImagerFont.Width[TEditFormatExtras.GetFont[style], [set: charSet, code: label.Fetch[i]-'\000]].x ENDLOOP; width _ escapement.x; IF ascent+descent <= 0.0 THEN { fontBoundingBox: ImagerFont.Extents ~ ImagerFont.FontBoundingBox[TEditFormatExtras.GetFont[style]]; ascent _ fontBoundingBox.ascent + bearoff; descent _ fontBoundingBox.descent - bearoff; }; { data: REF TalksBubbleDataRep ~ NEW[TalksBubbleDataRep _ [ letter: letter, label: label, ascent: ascent, descent: descent, width: width, bearoff: bearoff, firstCharWidth: firstCharWidth ]]; extents: ImagerFont.Extents _ [leftExtent: -data.bearoff+2.0, rightExtent: data.bearoff+data.width+2.0, ascent: data.ascent+2.0, descent: (data.descent+data.ascent)/2]; RETURN [NEW[TEditFormatExtras.CharacterArtworkRep _ [paint: TalksBubblePaint, extents: extents, escapement: escapement, data: data]]] } }; talksBubbleClass: TEditFormatExtras.CharacterArtworkClass ~ NEW[TEditFormatExtras.CharacterArtworkClassRep _ [ name: $TalksBubble, format: TalksBubbleFormat, data: NIL ]]; textColor: ImagerColorDefs.ConstantColor _ ImagerColorPrivate.ColorFromStipple[7BDEH, paint]; TEditFormatExtras.RegisterCharacterArtwork[talksBubbleClass]; END.