How to soft-wrap long text with no spaces? [SOLVED]
Moderators: FourthWorld, heatherlaine, Klaus, kevinmiller, robinmiller
How to soft-wrap long text with no spaces? [SOLVED]
Hi all,
My current project needs to use some lengthy file paths. If i put these into a field, this almost inevitably means the field length has be long enough to show the entire string as there are usually no spaces and therefore 'wrap' doesn't work and text appears truncated.
Ideally I'd like to be able to make the length shorter and height taller (for layout purposes).
To illustrate the problem: what I'd like to achieve is this:
Is there a way around this short of estimating formattedWidths and inserting carriage returns to hard wrap the text? I'd rather not do this, as it feels tedious to do and ensure it works with resizing fields and being able to actually use the field text for further processing (I know i could store the text in a custom prop of the field for programmatic use and just display a different text, but it all starts getting a bit complicated). I suppose i could include a horizontal scrollbar but that's always an eyesore to me.
Having searched online, i haven't found anything useful... Very grateful to hear if anyone has solved the soft-wrapping of text in fields? I guess 'character-wrapping'?
Many thanks,
Stam
My current project needs to use some lengthy file paths. If i put these into a field, this almost inevitably means the field length has be long enough to show the entire string as there are usually no spaces and therefore 'wrap' doesn't work and text appears truncated.
Ideally I'd like to be able to make the length shorter and height taller (for layout purposes).
To illustrate the problem: what I'd like to achieve is this:
Is there a way around this short of estimating formattedWidths and inserting carriage returns to hard wrap the text? I'd rather not do this, as it feels tedious to do and ensure it works with resizing fields and being able to actually use the field text for further processing (I know i could store the text in a custom prop of the field for programmatic use and just display a different text, but it all starts getting a bit complicated). I suppose i could include a horizontal scrollbar but that's always an eyesore to me.
Having searched online, i haven't found anything useful... Very grateful to hear if anyone has solved the soft-wrapping of text in fields? I guess 'character-wrapping'?
Many thanks,
Stam
Last edited by stam on Mon Aug 15, 2022 9:32 am, edited 2 times in total.
Re: How to soft-wrap long text with no spaces?
I remember an extensive thread in this forum, it got resurrected over the years from time to time. There was a lot of discussion, a few suggestions.
Ah yes.. here: https://forums.livecode.com/viewtopic.p ... 0&start=60
Ah yes.. here: https://forums.livecode.com/viewtopic.p ... 0&start=60
-
- Livecode Opensource Backer
- Posts: 9387
- Joined: Fri Feb 19, 2010 10:17 am
- Location: Bulgaria
Re: How to soft-wrap long text with no spaces?
An Old Chestnut: https://forums.livecode.com/viewtopic.php?t=3424
"The dontWrap on a field only handles word chunks"
https://forums.livecode.com/viewtopic.php?t=32179
Considering that this has been mentioned as some sort of a problem since 2009 it is odd
that nothing has been done about it.
However:
- -
Some people are NOT looking in the right place as I sorted this out last year:
"The dontWrap on a field only handles word chunks"
https://forums.livecode.com/viewtopic.php?t=32179
Considering that this has been mentioned as some sort of a problem since 2009 it is odd
that nothing has been done about it.
However:
- -
Some people are NOT looking in the right place as I sorted this out last year:
- Attachments
-
- Wrapper.livecode.zip
- Stack.
- (1.22 KiB) Downloaded 67 times
-
- Livecode Opensource Backer
- Posts: 9387
- Joined: Fri Feb 19, 2010 10:17 am
- Location: Bulgaria
Re: How to soft-wrap long text with no spaces?
However, be warned, that 'works' by shoving carriage returns into your string,
so if that's a problem, you still have a problem.
so if that's a problem, you still have a problem.
-
- VIP Livecode Opensource Backer
- Posts: 9837
- Joined: Sat Apr 08, 2006 7:05 am
- Location: Los Angeles
- Contact:
Re: How to soft-wrap long text with no spaces?
To save both space for the layout and my time for other development, I generally just keep path display fields single-line, making them right-aligned and scrollable when their contents are longer than their width.
Richard Gaskin
LiveCode development, training, and consulting services: Fourth World Systems
LiveCode Group on Facebook
LiveCode Group on LinkedIn
LiveCode development, training, and consulting services: Fourth World Systems
LiveCode Group on Facebook
LiveCode Group on LinkedIn
-
- Livecode Opensource Backer
- Posts: 9387
- Joined: Fri Feb 19, 2010 10:17 am
- Location: Bulgaria
Re: How to soft-wrap long text with no spaces?
You don't say.I generally just keep path display fields single-line, making them right-aligned and scrollable when their contents are longer than their width.
However the OP does not seem to want that.
What he asked was this:
And that is EXACTLY what is demonstrated in my stack attached in my first earlier posting.Is there a way around this short of estimating formattedWidths and inserting carriage returns to hard wrap the text?
Re: How to soft-wrap long text with no spaces?
Thanks Richmond and all,
i had anticipated there was probably no real soft-wrap option and much like Richmond i put together something that dynamically inserts a CR (apologies if the code is similar to yours Richmond - i haven't yet seen yours but since it does the same thing must be similar i guess).
I implemented this as a behaviour. The 'real' non-hard-wrapped text is stored in the custom property uText of the field and setting this will trigger the handlers:
The meat of it is here. I try to estimate the total length of text that can fit in a line and then add 1 char at a time to each line and compare it's formattedWidth the the max possible:
where the total margin width is estimated here (sadly needed as margin may be single number or a rect L,T,R,B)
On resizing the stack, all controls are set to resize with the Geometry Manager, but the re-wrapping is triggered in the resizeStack handler from the card script:
The attached stack as a long string in a 1-line field and the top left button sets the uText of the field to this, which then populates the multiline field with the hard-wrapped text while maintaining the original in a custom prop of the multiline field. Resizing the stack dynamically re-wraps the text...
As it's implemented as behaviour it can be applied to any field and when setting that field's custom property uText it should show the hard-wrapped version...
As they say, there are many ways to skin a cat!
i had anticipated there was probably no real soft-wrap option and much like Richmond i put together something that dynamically inserts a CR (apologies if the code is similar to yours Richmond - i haven't yet seen yours but since it does the same thing must be similar i guess).
I implemented this as a behaviour. The 'real' non-hard-wrapped text is stored in the custom property uText of the field and setting this will trigger the handlers:
Code: Select all
setProp uText pText
set the uText of me to pText
wrapField pText
end uText
The meat of it is here. I try to estimate the total length of text that can fit in a line and then add 1 char at a time to each line and compare it's formattedWidth the the max possible:
Code: Select all
command wrapField pText
local tLineNum, tLineWidth, tFieldTextWidth
set the text of me to empty
put the width of me - getMarginWidth(me) - (2 * the borderWidth me) into tFieldTextWidth
put 1 into tLineNum
lock screen
repeat for each char tChar in pText
put tChar after me
put the formattedWidth of char 1 to -1 of line tLineNum of me into tLineWidth
if tLineWidth >= tFieldTextWidth then
put return before char -1 of me
add 1 to tLineNum
end if
end repeat
end wrapField
Code: Select all
function getMarginWidth pField
local tMargins, tNum
put the margins of me into tMargins
if the length of tMargins = 1 then
put tMargins * 2 into tNum
else
put item 1 of tMargins + item 3 of tMargins into tNum
end if
return tNum
end getMarginWidth
Code: Select all
on resizeStack pNewWidth, pNewHeight, pOldWidth, pOldHeight
revUpdateGeometry -- update the geometry manager before proceeding
send "set the uText of me to the uText of me" to field "multiLine"
pass resizeStack
end resizeStack
As it's implemented as behaviour it can be applied to any field and when setting that field's custom property uText it should show the hard-wrapped version...
As they say, there are many ways to skin a cat!
- Attachments
-
- characterWrap.livecode.zip
- (2.15 KiB) Downloaded 78 times
-
- Livecode Opensource Backer
- Posts: 9387
- Joined: Fri Feb 19, 2010 10:17 am
- Location: Bulgaria
Re: How to soft-wrap long text with no spaces?
None needed, I'm sure: I probably 'stole' most of it from somewhere . . .apologies if the code is similar to yours Richmond
I am very glad you worked out a way to do things the way you wanted.
-
- VIP Livecode Opensource Backer
- Posts: 4002
- Joined: Sun Jan 07, 2007 9:12 pm
- Location: Bochum, Germany
Re: How to soft-wrap long text with no spaces? [SOLVED-ish]
Hi Stam,
should work.
Kind regards
Bernd
rightMargin and leftMargin work regardless of the format of the margins.where the total margin width is estimated here (sadly needed as margin may be single number or a rect L,T,R,B)
Code: Select all
function getMarginWidth pField
return the leftMargin of me + the rightMargin of me
end getMarginWidth
Kind regards
Bernd
Re: How to soft-wrap long text with no spaces?
I was really looking for a simpler way to soft-wrap text at character level without having to hard-wrap with carriage returns, but was obviously naive and the answer was obviously 'no', so hard wrapping it is...richmond62 wrote: ↑Sun Aug 14, 2022 7:43 pmNone needed, I'm sure: I probably 'stole' most of it from somewhere . . .apologies if the code is similar to yours Richmond
I am very glad you worked out a way to do things the way you wanted.
Having now had a look at your code, it is indeed similar although how the the CRs are inserted is different - but both work just fine and had i found your solution i may well have implemented that.
But this was probably for the better as it gave me an excuse for a new mini-project during some quiet time at work today (why do admin work between cases on call, when you can solve a juicy problem lol), and was able to implement as i wanted (preserving the original text, making this a field behaviour etc).
Gotta love how easy LiveCode makes it
Re: How to soft-wrap long text with no spaces? [SOLVED-ish]
Learn something everyday! That means i can just get rid of the function altogether, thanks Bernd!!bn wrote: ↑Sun Aug 14, 2022 10:56 pmrightMargin and leftMargin work regardless of the format of the margins.should work.Code: Select all
function getMarginWidth pField return the leftMargin of me + the rightMargin of me end getMarginWidth
Kind regards
Bernd
Re: How to soft-wrap long text with no spaces? [SOLVED-ish]
Thanks to Bernd, i was able to get rid of a handler and the behaviour script is now:
This works very well with texts of up to about 1000 characters, but performance drops of significantly with longer texts (judging by the wrapping with resizeStack). Not really relevant to my current need for file paths, but was just testing with longer texts.
I used https://loremipsum.io/generator/?n=5&t=p to generate 5 paragraphs (about 5000 chars) of lore ipsum text and pasted it into the oneLine field... on resizing it works but sloooowly (about 3 FPS).
Is there a way to to optimise this code further? Probably slower than it needs to be as wrapField is called continuously during resizing but at 2 am can't figure out how to call this *only after* resizing has finished as the mouse is up (mouseUp, mouseRelease, dragEnd and using an 'after resizeStack' handler all seem to do nothing...)
Many thanks
Stam
Code: Select all
setProp uText pText
set the uText of me to pText
wrapField pText
end uText
command wrapField pText
local tLineNum, tLineWidth, tFieldTextWidth
set the text of me to empty
put the width of me - (the leftMargin of me + the rightMargin of me) - (2 * the borderWidth of me) into tFieldTextWidth
put 1 into tLineNum
lock screen
repeat for each char tChar in pText
put tChar after me
put the formattedWidth of char 1 to -1 of line tLineNum of me into tLineWidth
if tLineWidth >= tFieldTextWidth then
put return before char -1 of me
add 1 to tLineNum
end if
end repeat
end wrapField
I used https://loremipsum.io/generator/?n=5&t=p to generate 5 paragraphs (about 5000 chars) of lore ipsum text and pasted it into the oneLine field... on resizing it works but sloooowly (about 3 FPS).
Is there a way to to optimise this code further? Probably slower than it needs to be as wrapField is called continuously during resizing but at 2 am can't figure out how to call this *only after* resizing has finished as the mouse is up (mouseUp, mouseRelease, dragEnd and using an 'after resizeStack' handler all seem to do nothing...)
Many thanks
Stam
-
- VIP Livecode Opensource Backer
- Posts: 9837
- Joined: Sat Apr 08, 2006 7:05 am
- Location: Los Angeles
- Contact:
Re: How to soft-wrap long text with no spaces? [SOLVED-ish]
I believe you should be fine in the neighborhood of 1k chars for the path. IIRC macOS has a max path length of 1024 chars, Windows much shorter 260?) Linux longer (4096).
Richard Gaskin
LiveCode development, training, and consulting services: Fourth World Systems
LiveCode Group on Facebook
LiveCode Group on LinkedIn
LiveCode development, training, and consulting services: Fourth World Systems
LiveCode Group on Facebook
LiveCode Group on LinkedIn
-
- VIP Livecode Opensource Backer
- Posts: 4002
- Joined: Sun Jan 07, 2007 9:12 pm
- Location: Bochum, Germany
Re: How to soft-wrap long text with no spaces? [SOLVED-ish]
Hi Stam,
This is an improved version that sends only 1 message after resizing. Paste this into your card script.
That works for me with your sample stack and the new code for your behavior button.
I will update the 'after resizeStack' stack in the other thread.
Kind regards
Bernd
Incidentally I had a look at the 'after resizeStack' yesterday and it turned out to have a flaw. It sent too many messages.using an 'after resizeStack' handler all seem to do nothing...)
This is an improved version that sends only 1 message after resizing. Paste this into your card script.
Code: Select all
on resizeStack pNewWidth, pNewHeight, pOldWidth, pOldHeight
send "doResize pNewWidth, pNewHeight" to me in 0 milliseconds
end resizeStack
on doResize pNewWidth, pNewHeight
local tPending, tRect, tFoundLast
if the mouse is down then
exit doResize
end if
put the pendingMessages into tPending
## apparently the messages in time get stacked up while resizeStack is active
## get the last pending message for "doResize" first
sort tPending descending numeric by item 2 of each -- the long seconds that trigger pending messages
repeat for each line aLine in tPending
if aLine contains "doResize" and tFoundLast is not true then
put true into tFoundLast
else
cancel item 1 of aLine -- delete all prior pending messages
end if
end repeat
if tFoundLast is true then
## there is one pending message for "doResize" left
## lets get out and wait for the last one
exit doResize
end if
## do your specific stuff here
send "set the uText of me to the uText of me" to field "multiLine"
end doResize
I will update the 'after resizeStack' stack in the other thread.
Kind regards
Bernd
Re: How to soft-wrap long text with no spaces? [SOLVED]
Bernd, you are the man! Genius! That's exactly what i was wanting to do - thank you!
I've modified your code further so it picks up all fields that need to be re-wrapped without explicitly being named and also automatically switches between immediate re-wrapping for fields with text of ≤ 1024 chars and deferred re-wrapping if > 1024 chars, as live re-wrapping looks nice as long as speed is acceptable. I guess for those on slower systems you can lower this number.
As there is no resizing in the doResize handler, i've renamed it to deferredWrap for semantic reasons and have removed the pNewWidth and pNewHeight params, passing instead a list of fields that need to be re-wrapped.
In my opinion it looks nicer if resizing done first, ie in resizeStack, and deferred re-wrapping is called after - for those that don't use the GM this should be done in resizeStack, in place of revUpdateGeometry.
Code: Select all
on resizeStack pNewWidth, pNewHeight, pOldWidth, pOldHeight
local tFieldList, tLongField
revUpdateGeometry
repeat with x = 1 to the number of fields
if the uText of field x is not empty then
put the short name of field x & return after tFieldList
if the length of the uText of field x > 1024 then put true into tLongField
end if
end repeat
delete the last char of tFieldList
if tLongField then
send "deferredWrap tFieldList" to me in 0 milliseconds
else
immediateWrap tFieldList
end if
end resizeStack
command immediateWrap pFieldList
repeat for each line aLine in pFieldList
send "set the uText of me to the uText of me" to field aLine
end repeat
end immediateWrap
on deferredWrap pFieldList #code by Bernd (modified)
local tPending, tRect, tFoundLast
if the mouse is down then exit deferredWrap
put the pendingMessages into tPending
sort tPending descending numeric by item 2 of each -- the long seconds that trigger pending messages
repeat for each line aLine in tPending
if aLine contains "deferredWrap" and tFoundLast is not true then
put true into tFoundLast
else
cancel item 1 of aLine -- delete all prior pending messages
end if
end repeat
if tFoundLast is true then
exit deferredWrap
end if
## do your specific stuff here
repeat for each line aLine in pFieldList
send "set the uText of me to the uText of me" to field aLine
end repeat
end deferredWrap
Thanks once again Bernd, very much appreciated,
Stam
------- EDIT : i've screwed something up and this code isn't working as expected, but don't have time to debug now (actual work etc!), i'll modify later...
Last edited by stam on Mon Aug 15, 2022 10:09 am, edited 2 times in total.