Forum Discussion

ttown253's avatar
ttown253
Visitor
10 years ago

Text Wrapping in roImageCanvas

Hi all,

I'm using an roImageCanvas to build a grid of rectangles that will make a grid for TV listings.

Basically how I understand it is, you position your text on the screen via a TargetRect with an X, Y position and a length and width.

The width of the TargetRect handles the wrapping great. If the text is too wide for the TargetRect, it wraps to the next line.

What I'm trying to figure out is how to get it to stop displaying text if there are too many lines. It's not doing anything about the height of the TargetRect. It will just keep printing the text, albeit the correct width, on several lines well beneath the TargetRect.

Is there any way to solve this issue without complex coding, text width analysis, etc?

Here's my code which put's a red rectangle on the screen the same size as the Text's TargetRect. The text printed goes outside of the bottom of the TargetRect because it's too long.


function Main()

canvas = CreateObject("roImageCanvas")

canvas.SetLayer(0, [
{
Color: "#FF0000",
TargetRect: {x: 400, y: 300, h: 100, w: 400}
},
{
Text: "Hello this is a long sentence about something I will see on TV someday and this is a continuation of that sentence which will wrap beneath the target rectangle",
TextAttrs: {color: "#FFFFFF", valign: "Top", halign: "Left"},
TargetRect: {x: 400, y: 300, h: 100, w: 400}
}
])

port = CreateObject("roMessagePort")
canvas.SetMessagePort(port)
canvas.Show()
while true
event = Wait(0, port)
if (event.IsRemoteKeyPressed())
index = event.GetIndex()
if (index = 6) ' Press OK to exit
exit while
end if
end if
end while

end function

6 Replies

  • Here's a bit of code I use to cut off something that's too long:
    IF Len(adjusters) > 30 THEN adjusters = Left(adjusters, 28) +"..." ' If there are many stat adjusters, cut this off short
  • I had thought about doing something like that, but it doesn't take into account the width of the font. Like 30 capital W's versus 30 lower case i's.

    I think I'm going to explore the EPGGrid of the scene graph API to implement my project instead of ImageCanvas.
  • That is a very useful function that I currently use and have used quite a bit. Thanks for sharing that. It saved me a great deal of time not having to write it myself. Just be aware, and I believe it was mentioned somewhere, perhaps by yourself, that it does not address strings without whitespace that happen to be longer than "width". Such as a long URL that you wanted to display in a dialog. If it is longer than the width and the function cannot find whitespace to break it up then it will go into an endless loop. I have made adjustments to it myself to accommodate those types of strings pretty much the same way as the Scene Graph components handle it, at least according to the Scene Graph documentation. But for normal strings it is a great piece of code.
  • If you just want to prevent the text from overlapping other UI elements, you could redraw the background in that section at a higher layer (using SourceRect to slice out the area you need to repeat). The text would still overrun your TargetRect, but it'd be hidden behind the background slice.
  • "ttown253" wrote:
    What I'm trying to figure out is how to get it to stop displaying text if there are too many lines. It's not doing anything about the height of the TargetRect. It will just keep printing the text, albeit the correct width, on several lines well beneath the TargetRect.

    Is there any way to solve this issue without complex coding, text width analysis, etc

    If you do decide to use an roImageCanvas, compute the height for your text rectangle by taking the number of lines of text you want in each rectangle multiplied by GetOneLineHeight(). By drawing another text rectangle immediately adjacent to the one with overflowing text, as long as its background is completely filled, you will over-write any overflow text from the previous text rectangle, as demonstrated in the following code (which does require you to use a custom font):

    function Main()

    fontFile = "pkg:/fonts/Font.ttf" ' From: http://www.dafont.com/liberation-sans.font
    fontName = "Liberation Sans"
    fontSize = 24

    fr = CreateObject ("roFontRegistry")
    fr.Register (fontFile)

    fontObject = fr.GetFont (fontName, fontSize, false, false)
    fontString = fr.Get (fontName, fontSize, false, false)

    lineH = fontObject.GetOneLineHeight ()
    nLines = 3
    rectH = nLines * lineH

    canvas = CreateObject("roImageCanvas")

    canvas.SetLayer(0, [
    {
    Color: "#FF0000",
    TargetRect: {x: 200, y: 200, h: rectH, w: 400}
    },
    {
    Text: "Hello this is a long sentence about something I will see on TV someday and this is a continuation of that sentence which will wrap beneath the target rectangle",
    TextAttrs: {font: fontString, color: "#FFFFFF", valign: "Top", halign: "Left"},
    TargetRect: {x: 200, y: 200, h: rectH, w: 400}
    },
    {
    ' The next grid element over-writes any overflow from the previous element
    Color: "#00FF00",
    TargetRect: {x: 200, y: 200 + rectH, h: rectH, w: 400}
    },
    {
    Text: "This is the next sentence",
    TextAttrs: {font: fontString, color: "#FFFFFF", valign: "Top", halign: "Left"},
    TargetRect: {x: 200, y: 200 + rectH, h: rectH, w: 400}
    }
    ])

    port = CreateObject("roMessagePort")
    canvas.SetMessagePort(port)
    canvas.Show()
    while true
    event = Wait(0, port)
    if (event.IsRemoteKeyPressed())
    index = event.GetIndex()
    if (index = 6) ' Press OK to exit
    exit while
    end if
    end if
    end while

    end function