text function limitations?

Hi all,

Just wondering if anyone has seen what I’m currently seeing? I’m trying to draw a fairly hefty chunk of text using the text function (~ 3000 characters) but as soon as the length of the string I pass goes above 2010 characters nothing is drawn. The text I’m passing is just some lorum ipsum placeholder for the moment.

This is the code that works:

local txt = string.sub(text_to_draw, 1, 2010)
text(txt, 0, 0)

and this doesn’t:

local txt = string.sub(text_to_draw, 1, 2011)
text(txt, 0, 0)

Anyone have any ideas?

@Steppers - you need a routine to split the text you wish to present into widths that will fit the screen width at the text size you have specified and with the font you have chosen.

I think I found a routine which I used in the Final Frontier demo in that post if you want to look it up. Found it, and others, with an internet search.

@Steppers What other code do you have. A straight text line doesn’t go much past the width of the screen let alone 2010 characters. Are you wrapping the text or something like that.

@Bri_G @dave1707 Yep, it’s wrapping the text at the correct width and it renders just fine exactly where I expect it to at 2010 characters but it just seems like an odd limitation beyond that.

I can’t really split it easily and render the parts nicely as it’s currently failing in the middle of a word. I could but it’ll be a pain.

For context, it’s part of a project info panel I’m adding to WebRepo for longer descriptions so it’s unlikely we’ll actually hit this limit but it seems odd nonetheless.

This should be a little more of the actual code I’m using (which doesn’t render the text when over 2010 characters)

-- Draw long description
textWrapWidth(PANEL_W - PADDING*2)
if self.metadata.long_desc then
    textMode(CORNER)
    local txt = self.metadata.long_desc
    _, th = textSize(txt)
    text(txt, PADDING, button_y - 36 - PADDING - th)
end

@Steppers I can show a chunk of code that’s 4,105 characters. I’m using a textWrapWidth of 1026 in landscape. A textWrapWidth of 1027 or 4106 characters and nothing displays.

@dave1707 Oh that’s pretty strange then. That definitely sounds broken to me.

I can get it to render just fine if I set the wrap width to 1024 so something to do with that I guess.

@Steppers I don’t know if it’s broken or not. I’m sure there’s limitations to everything. They probably thought 4,000+ characters was more than enough.

@Steppers Anytime I want to show a lot of text, I do something like this. You can scroll the text up/down. Change the variable “wide” value to fill the screen.

viewer.mode=FULLSCREEN

function setup()
    font("Courier")
    textMode(CORNER)
    str=""
    for z=1,8000 do
        str=str..string.format("%04d",z)      
    end
    fill(255)
    wide=80
    dy=0
end

function draw()
    background(0)   
    line=0 
    for y=0,#str//wide do
        line=line+1
        text(string.sub(str,y*wide+1,y*wide+wide),1,HEIGHT-line*20+dy)
    end
end

function touched(t)
    if t.state==CHANGED then
        dy=dy+t.deltaY
        if dy<0 then
            dy=0
        end
    end
end

@dave1707 Perfect, thank you. I’m going to stick with unscrollable text for the time being but will come back and use something like that later :smile:

I think I’d like it to split between words too but I hadn’t thought about actually doing it manually.

@Steppers Splitting between words at the end of each line should be easy enough. The code I show above I just did off the top of my head. I probably have or had code that splits words on spaces at the end of each line.

@Steppers - here is the function I found on the net.

Pardon the android phone formatting. See amended post below.

Here’s a version that I have. The function split does all the work and creates a table of lines so the line splitting only needs to be done once. Then use the tabLine table to display the lines. Input is the string to split and the pixel width of the line. It uses pixel size and font size to determine the line size. I created a string of 27,456 characters so you can scroll the text up or down. Try changing the sizePixel and sizeFont parameters. It also works for different fonts types. All the other code is just to setup the demo so split() is all that’s needed.

viewer.mode=STANDARD

function setup()
    parameter.integer("sizePixel",50,800,400,split1)
    parameter.integer("sizeFont",5,60,17,split1)
    fontSize(12)
    textMode(CORNER)
    fill(255)
    tabLine={}
    str="Five little monkeys jumping on the bed. One fell off and bumped his head. Mama called the doctor and the doctor said: No more monkeys jumping on the bed! Four little monkeys jumping on the bed. One fell off and bumped his head. Mama called the doctor and the doctor said: No more monkeys jumping on the bed! Three little monkeys jumping on the bed. One fell off and bumped his head. Mama called the doctor and the doctor said: No more monkeys jumping on the bed! Two little monkeys jumping on the bed. One fell off and bumped his head. Mama called the doctor and the doctor said: No more monkeys jumping on the bed! One little monkey jumping on the bed. He fell off and bumped his head. Mama called the doctor and the doctor said: No more monkeys jumping on the bed! Now there's no little monkeys jumping on the bed. They`re all jumping on the sofa instead! "
    
    for z=1,5 do        -- create a large string
        str=str..str
    end
    print("string size  ",#str)
    
    stroke(255)
    strokeWidth(2)
    dy=0   
    w,h=textSize("A")
    split(str,400)
end

function split1()
    fontSize(sizeFont)
    w,h=textSize("A")
    dy=0
    tabLine={}
    split(str,sizePixel)
end

function split(str,pixelSize)
    local temp,line={},"" 
    for word in str:gmatch("%S+") do 
        table.insert(temp,word) 
    end    
    for a,b in pairs(temp) do
        if textSize(line)+textSize(b)<pixelSize then
            line=line..b.." "
        else
            table.insert(tabLine,line)
            line=b.." "
        end            
    end
    if #line>0 then
        table.insert(tabLine,line)
    end
end
    
function draw()
    background()
    for a,b in pairs(tabLine) do
        text(b,20,HEIGHT-a*h+dy)
    end
    line(19,0,19,HEIGHT)
    line(sizePixel+20,0,sizePixel+20,HEIGHT)
end

function touched(t)
    if t.state==CHANGED then
        dy=dy+t.deltaY
    end
end

@Steppers @Simeon @dave1707 imho there’s definitely something wrong with the text function bc even with just three words it won’t print to screen at seemingly-random sizes. IIRC you could sometimes get the text in my text-resizing box to disappear and reappear at least twice before it reached any of the screen borders.

@Stepper - here is the function I found on the net.

function split(str, max_line_length)
    local lines = {}
    local line
    str:gsub('(%s*)(%S+)',
    function(spc, word)
        if not line or #line + #spc + #word > max_line_length then
            table.insert(lines, line)
            line = word
        else
            line = line..spc..word
        end
    end
    )
    table.insert(lines, line)
    return lines
end

Grrrrh - I hate posting from Android phones into this forum but when you’re away from your iPad and Mac what can you do? Pasting here much better.

@Bri_G Amazing. Thank you! I’ll check it out when I come to adding scrolling text on the project panels.

Here’s an updated version of the above code. It splits a string on space boundaries to fit within scrolling box area. Pass the class the string and the x,y,w,h of the scroll area. Also, the font size, font color, and font name can be different for each scroll area. I could have added a lot more options, but this is good enough for now.

viewer.mode=FULLSCREEN

function setup()
    textMode(CORNER)
    str="Five little monkeys jumping on the bed. One fell off and bumped his head. Mama called the doctor and the doctor said: No more monkeys jumping on the bed! Four little monkeys jumping on the bed. One fell off and bumped his head. Mama called the doctor and the doctor said: No more monkeys jumping on the bed! Three little monkeys jumping on the bed. One fell off and bumped his head. Mama called the doctor and the doctor said: No more monkeys jumping on the bed! Two little monkeys jumping on the bed. One fell off and bumped his head. Mama called the doctor and the doctor said: No more monkeys jumping on the bed! One little monkey jumping on the bed. He fell off and bumped his head. Mama called the doctor and the doctor said: No more monkeys jumping on the bed! Now there's no little monkeys jumping on the bed. They`re all jumping on the sofa instead! "    
    for z=1,5 do        -- create a larger string
        str=str..str
    end
    
    -- string,  x,  y,  w,  h,  font size, font color, font name
    s1=splitString(str,  20,300,300,400, 10,color(0,255,255),"MarkerFelt-Thin")
    s2=splitString(str, 350,400,450,400, 30,color(0,255,0),"SnellRoundhand")
    s3=splitString(str, 450,100,300,200, 15,color(255,255,0),"CourierNewPS-ItalicMT")
end

function draw()
    background(32, 72, 104)
    s1:draw()
    s2:draw()
    s3:draw()
end

function touched(t)
    s1:touched(t)
    s2:touched(t)
    s3:touched(t)
end

splitString=class()

function splitString:init(str,x,y,width,height,sizeFont,colr,fontName)
    self.x=math.max(5,x)
    self.y=math.max(5,y)  
    self.width=math.min(width,WIDTH-self.x-5)
    self.height=math.min(height,HEIGHT-self.y-5) 
    self.sizeFont=sizeFont
    self.colr=colr
    self.fontName=fontName
    self.lineHeight=0
    self.line="" 
    self.dy=0 
    self.tab={}
    self:split(self)
end

function splitString:split()
    font(self.fontName)
    fontSize(self.sizeFont)
    _,self.lineHeight=textSize("A")
    local temp={}
    for word in str:gmatch("%S+") do 
        table.insert(temp,word) 
    end    
    for a,b in pairs(temp) do
        if textSize(self.line)+textSize(b)<self.width then
            self.line=self.line..b.." "
        else
            table.insert(self.tab,self.line)
            self.line=b.." "
        end            
    end
    if #self.line>0 then
        table.insert(self.tab,self.line)
    end
end
    
function splitString:draw()
    clip(self.x-5,self.y-5,self.width+10,self.height+10)
    stroke(255)
    strokeWidth(2)
    fill(40)
    rect(self.x-5,self.y-5,self.width+10,self.height+10)
    fill(self.colr)
    font(self.fontName)
    fontSize(self.sizeFont)
    for a,b in pairs(self.tab) do
        text(b,self.x,self.y-a*self.lineHeight+self.dy+self.height)
    end
end

function splitString:touched(t)
    if t.x>self.x and t.x<self.x+self.width and 
                t.y>self.y and t.y<self.y+self.height then
        if t.state==CHANGED then
            self.dy=self.dy+t.deltaY
            if self.dy<0 then
                self.dy=0
            end
        end
    end
end

If I draw a rectangle at the side of the screen, I get half a rectangle. I suggest that text should clip at the screen edge, not just vanish altogether.

This comment in no way relates to the apparent bug I had in my class/method printer due to extremely long method names. Not at all.

But really, shouldn’t it display what it can, like other display stuff?

@RonJeffries i believe it used to.

that, i do not know