Canvas: Formatted text

Is there a way to draw formatted text on a canvas?

I have used the code below tons of times.

g.drawstring "Hello World", 10, 10

But I am wondering why I couldn’t just sent formatted text to a canvas.

[quote=226524:@Edwin van den Akker]Is there a way to draw formatted text on a canvas?

I have used the code below tons of times.

g.drawstring "Hello World", 10, 10

But I am wondering why I couldn’t just sent formatted text to a canvas.[/quote]

What do you mean by " sent formatted text to a canvas" ? You mean styled ?

Yep

Graphicshas several properties for setting various styling attributes like color etc
http://documentation.xojo.com/index.php/Graphics

[quote=226529:@Norman Palardy]Graphicshas several properties for setting various styling attributes like color etc
http://documentation.xojo.com/index.php/Graphics[/quote]

Thanks Norman. I do make great use of those styling attributes in the graphics object. But what if I have a chunk of data that contains Styled Text… I would love to have that be drawn on a canvas. I have been dealing with parsing the styled text, and drawing it in chucks. But with wrapping it all goes wrong. Words are cut in pieces… there must be an easier way, not?

would be nice but no
graphics has no way to draw styled text
I know this all too well since thats the way the IDE does the code editor
Its basically a canvas

TextArea.DrawInto could be a way.

or just interate thru the styleruns in the styled text and alter the graphics attributes and use DRAWSTRING

I offer this code AS-IS… but I think it contains everything you need to do what you are asking… I dug it uup from an old project
it is directly from a XOJO_CODE file so there are extra tags and such

#tag Module
Protected Module StyledTextDrawing
	#tag Method, Flags = &h21
		Private Sub DrawLIne(theLine as DrawnLine, g as Graphics, x As Integer, y As Integer, theWidth As Integer)
		  #If Not DebugBuild
		    #pragma DisableBackgroundTasks
		    #pragma DisableBoundsChecking
		    #pragma DisableAutoWaitCursor
		  #EndIf
		  Dim currLineAscent As Integer = theLine.LineTextAscent
		  Dim s As DrawnSection
		  Dim currX As Integer
		  
		  Select Case theLine.LineAlignment
		  Case 0, 1  // normal (left aligned)
		    currX = x
		  Case 2 // centered
		    currX = x + (theWidth-theLine.LineWidth)/2
		  Case 3 // right aligned
		    currX = x + (theWidth-theLine.LineWidth)
		  End Select
		  
		  For Each s In theLine.Sections
		    s.SetTo g
		    If g.ForeColor=color_white And Dragging_Text_Mode=1 Then g.ForeColor=Color_OffWhite
		    g.DrawString s.SectionText, currX, y + currLineAscent
		    currX = currX + g.StringWidth(s.SectionText)
		  Next
		End Sub
	#tag EndMethod

	#tag Method, Flags = &h0
		Sub DrawStyledText(g as Graphics, theStyledText as StyledText, x As Integer = 0, y As Integer = 0, wrapWidth As Integer = 9999)
		  #If Not DebugBuild
		    #pragma DisableBackgroundTasks
		    #pragma DisableBoundsChecking
		    #pragma DisableAutoWaitCursor
		  #EndIf
		  Dim line As DrawnLine
		  Dim lastY As Integer = y
		  Dim st As New FormattedText(theStyledText)
		  
		  SaveGraphicsSettings g
		  
		  While UBound(st.StyleRuns) >= 0
		    line = PrepareLine(st, wrapWidth)
		    DrawLIne line, g, x, lastY, wrapWidth
		    
		    lastY = lastY + line.LineTextHeight
		  Wend
		  
		  RestoreGraphicsSettings g
		End Sub
	#tag EndMethod

	#tag Method, Flags = &h21
		Private Function PrepareLine(theStyledText as FormattedText, theWidth As Integer = 9999) As DrawnLine
		  #If Not DebugBuild
		    #pragma DisableBackgroundTasks
		    #pragma DisableBoundsChecking
		    #pragma DisableAutoWaitCursor
		  #EndIf
		  Dim lastWidth As Integer
		  Dim wordIdx As Integer
		  Dim numWords As Integer
		  Dim sec(), d As DrawnSection
		  Dim currRun As FormattedTextRun
		  Dim l As New DrawnLine
		  While (UBound(theStyledText.StyleRuns) >= 0) And Not UserCancelled
		    currRun = theStyledText.StyleRuns(0)
		    l.LineAlignment = currRun.Alignment // We store alignment on a per-line basis, since it's easier that way.
		    d = New DrawnSection
		    d.SetFrom currRun // Sets formatting aspects of the section we are trying to append
		    // First see if we can fit the whole run on the current line...
		    d.SectionText = currRun.Text
		    sec.Append d
		    If lastWidth + d.SectionWidth < theWidth Then
		      // we can fit the whole run on, so delete it from theStyledText...
		      theStyledText.StyleRuns.Remove 0
		      If InStr(d.SectionText, EndOfLine) > 0 Then Exit
		      lastWidth = lastWidth + d.SectionWidth
		    Else
		      // nope, doesn't fit the whole run on. Let's try it word-by-word...
		      d.SectionText = ""
		      wordIdx = 1
		      numWords = CountFields(currRun.Text, " ")
		      While (lastWidth + d.SectionWidth < theWidth) And (wordIdx <= numWords)
		        d.SectionText = d.SectionText + NthField(currRun.Text, " ", wordIdx) + " "
		        wordIdx = wordIdx + 1
		      Wend
		      // Now that we've found the shortest string that is too long,
		      // shave off the last word to make it fit...
		      d.SectionText = Mid(d.SectionText, 1, Len(d.SectionText)-Len(NthField(currRun.Text, " ", wordIdx-1))-1)
		      currRun.Text = Mid(currRun.Text, Len(d.SectionText)+1) // +1 to get rid of trailing space
		      Exit
		    End If
		  Wend
		  l.Sections = sec
		  Return l
		End Function
	#tag EndMethod

	#tag Method, Flags = &h21
		Private Sub RestoreGraphicsSettings(g as Graphics)
		  g.TextFont = gTextFont
		  g.TextSize = gTextSize
		  g.ForeColor = gTextColor
		  g.Bold = gBold
		  g.Italic = gItalic
		  g.Underline = gUnderline
		End Sub
	#tag EndMethod

	#tag Method, Flags = &h21
		Private Sub SaveGraphicsSettings(g as Graphics)
		  gTextFont = g.TextFont
		  gTextSize = g.TextSize
		  gTextColor = g.ForeColor
		  gBold = g.Bold
		  gItalic = g.Italic
		  gUnderline = g.Underline
		End Sub
	#tag EndMethod


	#tag Property, Flags = &h21
		Private gBold As Boolean
	#tag EndProperty

	#tag Property, Flags = &h21
		Private gItalic As Boolean
	#tag EndProperty

	#tag Property, Flags = &h21
		Private gTextColor As Color = &c000000
	#tag EndProperty

	#tag Property, Flags = &h21
		Private gTextFont As String
	#tag EndProperty

	#tag Property, Flags = &h21
		Private gTextSize As Integer
	#tag EndProperty

	#tag Property, Flags = &h21
		Private gUnderline As Boolean
	#tag EndProperty


	#tag ViewBehavior
		#tag ViewProperty
			Name="Index"
			Visible=true
			Group="ID"
			InitialValue="-2147483648"
			Type="Integer"
		#tag EndViewProperty
		#tag ViewProperty
			Name="Left"
			Visible=true
			Group="Position"
			InitialValue="0"
			Type="Integer"
		#tag EndViewProperty
		#tag ViewProperty
			Name="Name"
			Visible=true
			Group="ID"
			Type="String"
		#tag EndViewProperty
		#tag ViewProperty
			Name="Super"
			Visible=true
			Group="ID"
			Type="String"
		#tag EndViewProperty
		#tag ViewProperty
			Name="Top"
			Visible=true
			Group="Position"
			InitialValue="0"
			Type="Integer"
		#tag EndViewProperty
	#tag EndViewBehavior
End Module
#tag EndModule

You could also consider an invisible TextArea, using it’s StyledTextPrinter to Draw the text. I haven’t used it real world applications, but it does seem to work very well.

Here’s an example in the paint event of a canvas. Textarea1 is an invisible textarea with styled turned on.

[code] dim t as TextArea=TextArea1
t.text=“a,b,c,d,e,f”
t.SelStart=0
t.SelLength=1
t.SelBold=true
t.SelStart=2
t.SelTextColor=&cff0000
t.selstart=4
t.SelBold=false
t.SelStart=6
t.SelTextColor=&cff00ff
t.SelStart=8
t.SelTextColor=&c00ff00

dim p as StyledTextPrinter=t.styledTextPrinter(g,20)
p.DrawBlock(0,0,300)

[/code]

You could also just set the styledText property directly, or feed it RTF data and render that to screen…

Not any more, necessarily: “StyledTextPrinter no longer works on Windows starting with 2016r4.”

You guys can always use DynaPDF to make a temporary in memory PDF with text, render it to picture and draw to window.
Or use native functions like NSAttributeStringMBS and NSGraphicsMBS classes in MBS Xojo Plugins.

[quote=226532:@Norman P]would be nice but no
graphics has no way to draw styled text
I know this all too well since thats the way the IDE does the code editor
Its basically a canvas[/quote]
Is that why when pressing the space bar on repeat, the cursor might basically disappear until you let go of the space bar? This happens if the blinking cursor happened to be “off” when the repeat started.

Rendering to PDF seems overkill to me, and probably is also not performing too well when you’re trying to render 100s of little Excel cells into a Canvas, like I do :slight_smile:

On macOS very likely
Windows draws the cursor differently