Page 1 of 1
Wrap Text in Rect
Posted: Wed Aug 15, 2018 9:32 pm
by pink
Finally got this working, the following code takes 4 inputs:
-the rectangle which will contain the text
-the text (duh)
-the font to use
-the foreground color to use for the text
Here's a few notes:
-if the text is ultimately too long to fit in the box, it just gets cut off
-if any word is too long to fit in the width of the box, it just sits on a line by itself and gets truncated
Here's what I can't figure out yet:
-how can I pass an alignment as a param? I tried putting "top left" as a 5th param, and then "fill text tLine at pAlign..." but I keep getting errors
-how to put line breaks into this... still working on it
Code: Select all
public handler mpWrapTextinRect(in pTextBox as Rectangle,in pText as String,in pFont as Font,in pForeC as Paint)
variable tRect as Rectangle
variable tTextW as Number
variable tTextH as Number
variable tMaxRows as Number
variable tWords as List
variable tWord as String
variable tLine as String
variable tTestLine as String
variable tRow as Number
split pText by " " into tWords
set the font of this canvas to pFont
set the paint of this canvas to pForeC
put the height of the layout bounds of text pText on this canvas into tTextH
put the width of pTextBox into tTextW
put the floor of ((the height of pTextBox)/tTextH) into tMaxRows
if tMaxRows = 0 then
return
end if
put 1 into tRow
repeat for each element tWord in tWords
put tLine & tWord into tTestLine
if the width of the layout bounds of text tTestLine on this canvas > tTextW then
fill text tLine at top left of pTextBox on this canvas
add tTextH to the top of pTextBox
put "" into tTestLine
if tRow=tMaxRows then
put "" into tLine
exit repeat
end if
add 1 to tRow
put tWord & " " into tLine
else
put tTestLine & " " into tLine
end if
end repeat
fill text tLine at top left of pTextBox on this canvas
end handler
Here's an example OnPaint handler using it:
Code: Select all
public handler OnPaint()
variable tFont as Font
variable tRect as Rectangle
variable tText as String
put "A common mistake that people make when trying to design something completely foolproof is to underestimate the ingenuity of complete fools." into tText
set the paint of this canvas to my background paint
put rectangle [0,0,my width,my height] into tRect
fill rectangle path of tRect on this canvas
put font "Arial" at size 18 into tFont
fill rectangle path of tRect on this canvas
mpWrapTextinRect(tRect,tText,tFont,my foreground paint)
end handler
Re: Wrap Text in Rect
Posted: Thu Aug 16, 2018 4:31 pm
by bn
Greg,
regarding alignment I only found this solution
Code: Select all
variable tAlign as String
put "center" into tAlign
and then
Code: Select all
if tAlign is "center" then
fill text tLine at center of pTextBox on this canvas
else if tAlign is "top left" then
fill text tLine at top left of pTextBox on this canvas
else if tAlign is "top right" then
fill text tLine at top right of pTextBox on this canvas
else
fill text tLine at top left of pTextBox on this canvas -- fall back/default
end if
of course you could set the alignment as a property and pass it etc.
Kind regards
Bernd
Re: Wrap Text in Rect
Posted: Thu Aug 16, 2018 7:10 pm
by bn
Greg,
as far as return is concerned I resorted to this solution
create some new variables and put a linefeed character into your list of words as a test.
I assume that if you pass the widget a string with a return from LCS it will be linefeed (ASCII 10).
Code: Select all
variable tReturnChar as String
get the char with code 10 -- linefeed used by LCS
put the result into tReturnChar
variable tContainsReturn as Boolean
split pText by " " into tWords
put tReturnChar after element 1 of tWords -- add a return after first word
when filling text add this
Code: Select all
put tLine contains tReturnChar into tContainsReturn -- true if it found a lineFeed
if the width of the layout bounds of text tTestLine on this canvas > tTextW or tContainsReturn then
your code for filling text follows
(boy, to find the right syntax in LCB is tedious...)
Kind regards
Bernd
Re: Wrap Text in Rect
Posted: Fri Aug 17, 2018 1:09 pm
by pink
This was my solution for adding a return/newline in the handler.
(I replaced the exiting carriage return with " qzqz " and then in the repeat sequence it ends the current line and begins the next line.
Also, in this iteration I removed the paint, I think it is easier to set in the OnPaint handler.
The one thing I cannot crack is centering text. Everything I've done so far causes the centering to begin both vertically and horizontally in the center instead of centered at the top. I've tried manually making rectangles for each line, but it seems like "center" ignores any other constraints I make.
Code: Select all
private handler mpWrapTextinRect(in pTextBox as Rectangle,in pText as String,in pFont as Font)
variable tRect as Rectangle
variable tTextW as Number
variable tTextH as Number
variable tMaxRows as Number
variable tWords as List
variable tWord as String
variable tLine as String
variable tTestLine as String
variable tRow as Number
variable tText as Rectangle
replace newline with " qzqz " in pText
split pText by " " into tWords
set the font of this canvas to pFont
put the height of the layout bounds of text pText on this canvas into tTextH
put the width of pTextBox into tTextW
put the floor of ((the height of pTextBox)/tTextH) into tMaxRows
if tMaxRows = 0 then
return
end if
put 1 into tRow
repeat for each element tWord in tWords
put tLine & tWord into tTestLine
if the width of the layout bounds of text tTestLine on this canvas > tTextW or tWord is "qzqz" then
fill text tLine at top left of pTextBox on this canvas
add tTextH to the top of pTextBox
put "" into tTestLine
if tRow=tMaxRows then
put "" into tLine
exit repeat
end if
add 1 to tRow
if tWord is "qzqz" then
put "" into tLine
else
put tWord & " " into tLine
end if
else
put tTestLine & " " into tLine
end if
end repeat
fill text tLine at top left of pTextBox on this canvas
end handler
Re: Wrap Text in Rect
Posted: Fri Aug 17, 2018 3:02 pm
by bn
Greg,
I did not know newLine, good to know, thank you.
here is your handler set up to display text centered. I made a variable tAlign which is hardcoded here.
It would probably be easier to make it a property so you can set it via script or from the properties Inspector.
Then the "fill" command is conditionally executed depending on the content of tAlign.
This is the same solution I suggested above. Now I put it into your script and it works for me.
Code: Select all
private handler mpWrapTextinRect(in pTextBox as Rectangle,in pText as String,in pFont as Font)
variable tRect as Rectangle
variable tTextW as Number
variable tTextH as Number
variable tMaxRows as Number
variable tWords as List
variable tWord as String
variable tLine as String
variable tTestLine as String
variable tRow as Number
variable tText as Rectangle
variable tAlign as String -- <-- make a variable
put "center" into tAlign -- <-- put "center", "top left" or "top right" into it
replace newline with " qzqz " in pText
split pText by " " into tWords
set the font of this canvas to pFont
put the height of the layout bounds of text pText on this canvas into tTextH
put the width of pTextBox into tTextW
put the floor of ((the height of pTextBox)/tTextH) into tMaxRows
if tMaxRows = 0 then
return
end if
put 1 into tRow
repeat for each element tWord in tWords
put tLine & tWord into tTestLine
if the width of the layout bounds of text tTestLine on this canvas > tTextW or tWord is "qzqz" then
if tAlign is "center" then
fill text tLine at center of pTextBox on this canvas
else if tAlign is "top left" then
fill text tLine at top left of pTextBox on this canvas
else if tAlign is "top right" then
fill text tLine at top right of pTextBox on this canvas
else
fill text tLine at top left of pTextBox on this canvas -- fall back/default
end if
add tTextH to the top of pTextBox
put "" into tTestLine
if tRow=tMaxRows then
put "" into tLine
exit repeat
end if
add 1 to tRow
if tWord is "qzqz" then
put "" into tLine
else
put tWord & " " into tLine
end if
else
put tTestLine & " " into tLine
end if
end repeat
if tAlign is "center" then
fill text tLine at center of pTextBox on this canvas
else if tAlign is "top left" then
fill text tLine at top left of pTextBox on this canvas
else if tAlign is "top right" then
fill text tLine at top right of pTextBox on this canvas
else
fill text tLine at top left of pTextBox on this canvas -- fall back/default
end if
end handler
Kind regards
Bernd
Re: Wrap Text in Rect
Posted: Fri Aug 17, 2018 3:23 pm
by pink
The problem with the centering is that it starts putting the text at what i would call "center center" instead of "top center" which is where I want it. What happens is that there is a large gap at the top of the box, and then all the text is at the bottom.
What I tried to do was to calculate the individual rectangle for each line of text, and then put it exactly where I thought it should be, but it always starts in the middle of the original box.
Re: Wrap Text in Rect
Posted: Fri Aug 17, 2018 3:29 pm
by bn
What happens is that there is a large gap at the top of the box, and then all the text is at the bottom
that it because your pTextBox is too tall, If you set its height to text height and not changing the topLeft or alteratively creating a new rect for filling that has the width of pTextBox and the height of the text and move that down then you have the text where you want it.
You can see this when logging the height of pTextBox.
Kind regards
Bernd
Re: Wrap Text in Rect
Posted: Fri Aug 17, 2018 4:07 pm
by pink
I figured out what I was doing wrong, and now this works... the problem I had in my non-working trials was that I was creating individual rectangles by adding tTextH to the top of pTextBox and then using the top and tTextH to set the bottom of pTextBox... however what I should have been doing was setting the height and not the bottom...
Code: Select all
private handler mpWrapTextinRect(in pTextBox as Rectangle,in pText as String,in pFont as Font,in pAlign as String)
variable tRect as Rectangle
variable tTextW as Number
variable tTextH as Number
variable tMaxRows as Number
variable tWords as List
variable tWord as String
variable tLine as String
variable tTestLine as String
variable tRow as Number
variable tText as Rectangle
variable tVal as Number
replace newline with " qzqz " in pText
split pText by " " into tWords
set the font of this canvas to pFont
put the height of the layout bounds of text pText on this canvas into tTextH
put the width of pTextBox into tTextW
put the floor of ((the height of pTextBox)/tTextH) into tMaxRows
if tMaxRows = 0 then
return
end if
put 1 into tRow
repeat for each element tWord in tWords
put pTextBox into tText
put tLine & tWord into tTestLine
if the width of the layout bounds of text tTestLine on this canvas > tTextW or tWord is "qzqz" then
add (tTextH*(tRow-1)) to the top of tText
set the height of tText to tTextH
if pAlign is "center" then
fill text tLine at center of tText on this canvas
else if pAlign is "top right" then
fill text tLine at top right of tText on this canvas
else
fill text tLine at top left of tText on this canvas
end if
put "" into tTestLine
if tRow=tMaxRows then
put "" into tLine
exit repeat
end if
add 1 to tRow
if tWord is "qzqz" then
put "" into tLine
else
put tWord & " " into tLine
end if
else
put tTestLine & " " into tLine
end if
end repeat
add (tTextH*(tRow-1)) to the top of tText
set the height of tText to tTextH
if pAlign is "center" then
fill text tLine at center of tText on this canvas
else if pAlign is "top right" then
fill text tLine at top right of tText on this canvas
else
fill text tLine at top left of tText on this canvas
end if
end handler
Re: Wrap Text in Rect
Posted: Fri Aug 17, 2018 5:12 pm
by pink
Okay, I swear this my last post for now because I am at work and I really should actually get to work...
I've removed the font as param, as it is easy to set via the system or in OnPaint
the pAlign param needs 2 words: [top,center,bottom] and [left,center,right]
so it can be aligned vertically and horizontally within the given rectangle
I also removed some extraneous variables that I stopped using
here is the full code of a widget using it:
https://github.com/madpink/labelbox-livecode-builder
here is the handler:
Code: Select all
private handler mpWrapTextinRect(in pTextBox as Rectangle,in pText as String,in pAlign as String)
variable tTextW as Number
variable tTextH as Number
variable tMaxRows as Number
variable tWords as List
variable tWord as String
variable tLine as String
variable tTestLine as String
variable tRow as Number
variable tAlign as List
variable tLinesofText as List
split pAlign by " " into tAlign
replace newline with " qzqz " in pText
split pText by " " into tWords
put the height of the layout bounds of text pText on this canvas into tTextH
put the width of pTextBox into tTextW
put the floor of ((the height of pTextBox)/tTextH) into tMaxRows
if tMaxRows = 0 then
return
end if
put 1 into tRow
repeat for each element tWord in tWords
put tLine & tWord into tTestLine
if the width of the layout bounds of text tTestLine on this canvas > tTextW or tWord is "qzqz" then
push tLine onto back of tLinesofText
put "" into tTestLine
if tRow=tMaxRows then
put "" into tLine
exit repeat
end if
add 1 to tRow
if tWord is "qzqz" then
put "" into tLine
else
put tWord & " " into tLine
end if
else
put tTestLine & " " into tLine
end if
end repeat
push tLine onto back of tLinesofText
if element 1 of tAlign is "center" then
add ((the height of pTextBox)-(tMaxRows*tTextH) + (tMaxRows-tRow)*tTextH)/2 to the top of pTextBox
else if element 1 of tAlign is "bottom" then
add ((the height of pTextBox)-(tMaxRows*tTextH) + (tMaxRows-tRow)*tTextH) to the top of pTextBox
end if
put 1 into tRow
repeat for each element tLine in tLinesofText
set the height of pTextBox to tTextH
if element 2 of tAlign is "center" then
fill text tLine at center of pTextBox on this canvas
else if element 2 of tAlign is "right" then
fill text tLine at top right of pTextBox on this canvas
else
fill text tLine at top left of pTextBox on this canvas
end if
add 1 to tRow
add tTextH to the top of pTextBox
end repeat
end handler