How to soft-wrap long text with no spaces? [SOLVED]

LiveCode is the premier environment for creating multi-platform solutions for all major operating systems - Windows, Mac OS X, Linux, the Web, Server environments and Mobile platforms. Brand new to LiveCode? Welcome!

Moderators: FourthWorld, heatherlaine, Klaus, kevinmiller, robinmiller

stam
Posts: 2679
Joined: Sun Jun 04, 2006 9:39 pm
Location: London, UK

How to soft-wrap long text with no spaces? [SOLVED]

Post by stam » Sun Aug 14, 2022 3:31 pm

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:
Screenshot 2022-08-14 at 15.25.38.png
what I'd like to achieve is this:
Screenshot 2022-08-14 at 15.29.22.png

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.

SparkOut
Posts: 2852
Joined: Sun Sep 23, 2007 4:58 pm

Re: How to soft-wrap long text with no spaces?

Post by SparkOut » Sun Aug 14, 2022 4:29 pm

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

richmond62
Livecode Opensource Backer
Livecode Opensource Backer
Posts: 9359
Joined: Fri Feb 19, 2010 10:17 am
Location: Bulgaria

Re: How to soft-wrap long text with no spaces?

Post by richmond62 » Sun Aug 14, 2022 4:32 pm

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:
-
SShot 2022-08-14 at 18.45.58.png
-
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

richmond62
Livecode Opensource Backer
Livecode Opensource Backer
Posts: 9359
Joined: Fri Feb 19, 2010 10:17 am
Location: Bulgaria

Re: How to soft-wrap long text with no spaces?

Post by richmond62 » Sun Aug 14, 2022 4:59 pm

However, be warned, that 'works' by shoving carriage returns into your string,
so if that's a problem, you still have a problem. 8)

FourthWorld
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 9823
Joined: Sat Apr 08, 2006 7:05 am
Location: Los Angeles
Contact:

Re: How to soft-wrap long text with no spaces?

Post by FourthWorld » Sun Aug 14, 2022 5:39 pm

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

richmond62
Livecode Opensource Backer
Livecode Opensource Backer
Posts: 9359
Joined: Fri Feb 19, 2010 10:17 am
Location: Bulgaria

Re: How to soft-wrap long text with no spaces?

Post by richmond62 » Sun Aug 14, 2022 6:56 pm

I generally just keep path display fields single-line, making them right-aligned and scrollable when their contents are longer than their width.
You don't say.

However the OP does not seem to want that.

What he asked was this:
Is there a way around this short of estimating formattedWidths and inserting carriage returns to hard wrap the text?
And that is EXACTLY what is demonstrated in my stack attached in my first earlier posting.

stam
Posts: 2679
Joined: Sun Jun 04, 2006 9:39 pm
Location: London, UK

Re: How to soft-wrap long text with no spaces?

Post by stam » Sun Aug 14, 2022 7:40 pm

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:

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
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
     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
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:

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
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!
Attachments
characterWrap.livecode.zip
(2.15 KiB) Downloaded 78 times

richmond62
Livecode Opensource Backer
Livecode Opensource Backer
Posts: 9359
Joined: Fri Feb 19, 2010 10:17 am
Location: Bulgaria

Re: How to soft-wrap long text with no spaces?

Post by richmond62 » Sun Aug 14, 2022 7:43 pm

apologies if the code is similar to yours Richmond
None needed, I'm sure: I probably 'stole' most of it from somewhere . . . 8)

I am very glad you worked out a way to do things the way you wanted.

bn
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 3999
Joined: Sun Jan 07, 2007 9:12 pm
Location: Bochum, Germany

Re: How to soft-wrap long text with no spaces? [SOLVED-ish]

Post by bn » Sun Aug 14, 2022 10:56 pm

Hi Stam,
where the total margin width is estimated here (sadly needed as margin may be single number or a rect L,T,R,B)
rightMargin and leftMargin work regardless of the format of the margins.

Code: Select all

function getMarginWidth pField
    return the leftMargin of me + the rightMargin of me
end getMarginWidth
should work.

Kind regards
Bernd

stam
Posts: 2679
Joined: Sun Jun 04, 2006 9:39 pm
Location: London, UK

Re: How to soft-wrap long text with no spaces?

Post by stam » Sun Aug 14, 2022 11:17 pm

richmond62 wrote:
Sun Aug 14, 2022 7:43 pm
apologies if the code is similar to yours Richmond
None needed, I'm sure: I probably 'stole' most of it from somewhere . . . 8)

I am very glad you worked out a way to do things the way you wanted.
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... ;-)

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 8)

stam
Posts: 2679
Joined: Sun Jun 04, 2006 9:39 pm
Location: London, UK

Re: How to soft-wrap long text with no spaces? [SOLVED-ish]

Post by stam » Sun Aug 14, 2022 11:19 pm

bn wrote:
Sun Aug 14, 2022 10:56 pm
rightMargin and leftMargin work regardless of the format of the margins.

Code: Select all

function getMarginWidth pField
    return the leftMargin of me + the rightMargin of me
end getMarginWidth
should work.

Kind regards
Bernd
Learn something everyday! That means i can just get rid of the function altogether, thanks Bernd!!

stam
Posts: 2679
Joined: Sun Jun 04, 2006 9:39 pm
Location: London, UK

Re: How to soft-wrap long text with no spaces? [SOLVED-ish]

Post by stam » Mon Aug 15, 2022 2:40 am

Thanks to Bernd, i was able to get rid of a handler and the behaviour script is now:

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
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

FourthWorld
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 9823
Joined: Sat Apr 08, 2006 7:05 am
Location: Los Angeles
Contact:

Re: How to soft-wrap long text with no spaces? [SOLVED-ish]

Post by FourthWorld » Mon Aug 15, 2022 5:45 am

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

bn
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 3999
Joined: Sun Jan 07, 2007 9:12 pm
Location: Bochum, Germany

Re: How to soft-wrap long text with no spaces? [SOLVED-ish]

Post by bn » Mon Aug 15, 2022 7:55 am

Hi Stam,
using an 'after resizeStack' handler all seem to do nothing...)
Incidentally I had a look at the 'after resizeStack' yesterday and it turned out to have a flaw. It sent too many messages.

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
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

stam
Posts: 2679
Joined: Sun Jun 04, 2006 9:39 pm
Location: London, UK

Re: How to soft-wrap long text with no spaces? [SOLVED]

Post by stam » Mon Aug 15, 2022 9:31 am

bn wrote:
Mon Aug 15, 2022 7:55 am
This is an improved version that sends only 1 message after resizing. Paste this into your card script.
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
This seems to work extremely well for both shorter and longer texts!
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.

Post Reply

Return to “Getting Started with LiveCode - Experienced Developers”