Word wrapping a string to arbitrary position?

Just starting out? Need help? Post your questions and find answers here.
User avatar
Fangbeast
PureBasic Protozoa
PureBasic Protozoa
Posts: 4789
Joined: Fri Apr 25, 2003 3:08 pm
Location: Not Sydney!!! (Bad water, no goats)

Word wrapping a string to arbitrary position?

Post by Fangbeast »

I like the word wrapping of the editor gadget and I'd like to apply that logic to strings of arbitrary length.

Given a string such as:

Stringy.s = "Wrap me baby but don't hurt me, I'll
be good like a long stringy should and would!"

and an arbitrary 'wrap column' of 30, how would I go about something like this?

I'd feed a string somewhere that calculates the number of words and spaces to that position, adds the CRLF and then I could use that string where it needed that wrap space.
Amateur Radio/VK3HAF, (D-STAR/DMR and more), Arduino, ESP32, Coding, Crochet
Psych
Enthusiast
Enthusiast
Posts: 239
Joined: Thu Dec 18, 2008 3:35 pm
Location: Wales, UK

Re: Word wrapping a string to arbitrary position?

Post by Psych »

I'd imagine using the Textwidth function would do the job, assuming you could startdrawing to it.

Otherwise a google search returned this for the WINAPI.
Try using GetTextExtentPoint32. That uses the current font for the given device context to measure the width and height of the rendered string in logical units. For the default mapping mode, MM_TEXT, 1 logical unit is 1 pixel.

However, if you've changed the mapping mode for the current device context, a logical unit may not be the same as a pixel. You can read about the different mapping modes on MSDN. With the mapping mode, you can convert the dimensions returned to you by GetTextExtentPoint32 to pixels.
----------------------------------------------------------------------------
Commenting your own code is admitting you don't understand it.
----------------------------------------------------------------------------
RASHAD
PureBasic Expert
PureBasic Expert
Posts: 4946
Joined: Sun Apr 12, 2009 6:27 am

Re: Word wrapping a string to arbitrary position?

Post by RASHAD »

Not exact but it will do your request
190 = Right Margin to select (in pixel)
It depends on the width of your EditGadget & the font size used

Code: Select all

If OpenWindow(1, 40, 40, 400, 400, "Editor Test", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_SizeGadget)
   EditorGadget(1, 10, 10, 380, 300)
   SendMessage_(GadgetID(1), #EM_SETTARGETDEVICE, #Null, 0)
   SendMessage_(GadgetID(1), #EM_SETMARGINS, #EC_RIGHTMARGIN, 0 | (190<<16))
   Repeat
     Event=WaitWindowEvent(10)
     Select Event
         Case #PB_Event_Gadget
            Select EventGadget()
              Case 1
              
            EndSelect
      EndSelect
   Until Event=#PB_Event_CloseWindow
   
EndIf

Egypt my love
User avatar
Fangbeast
PureBasic Protozoa
PureBasic Protozoa
Posts: 4789
Joined: Fri Apr 25, 2003 3:08 pm
Location: Not Sydney!!! (Bad water, no goats)

Re: Word wrapping a string to arbitrary position?

Post by Fangbeast »

I want the wrap calculated to be at a certain arbitrary column.

Not in the editorgadget, just like the way the editorgadget does it.

The new string would be calculated at the given border and CRLF pairs added at the right point and the string rejoined.

Old string. Wrap border at 30 chars.

String.s = "Stringy.s = "Wrap me baby but don't hurt me, I'll
be good like a long stringy should and would!"

New string?

NewString.s = "Wrap me baby but don't hurt me' + CRLF + , I'll be good like a long " + #CRLF$ + "stringy should and would!"
Amateur Radio/VK3HAF, (D-STAR/DMR and more), Arduino, ESP32, Coding, Crochet
MachineCode
Addict
Addict
Posts: 1482
Joined: Tue Feb 22, 2011 1:16 pm

Re: Word wrapping a string to arbitrary position?

Post by MachineCode »

I just knocked this up in 5 minutes but it may not be reliable.

[Edit] It wasn't. :oops:
Last edited by MachineCode on Mon Mar 04, 2013 12:21 pm, edited 1 time in total.
Microsoft Visual Basic only lasted 7 short years: 1991 to 1998.
PureBasic: Born in 1998 and still going strong to this very day!
Little John
Addict
Addict
Posts: 4779
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

Re: Word wrapping a string to arbitrary position?

Post by Little John »

Code: Select all

EnableExplicit

Procedure.s WordWrap (source$, width.i, delimList$="- "+Chr(9), nl$=#LF$)
   Protected.i posn, found, i
   Protected ret$=""
   
   If width <= 0
      ProcedureReturn source$
   EndIf
   
   posn = Len(source$)
   While posn > width
      For i = width To 1 Step -1
         found = FindString(delimList$, Mid(source$,i,1))
         If found > 0
            posn = i
            Break
         EndIf
      Next
      If found = 0
         For i = width+1 To posn
            found = FindString(delimList$, Mid(source$,i,1))
            If found > 0
               posn = i
               Break
            EndIf
         Next
      EndIf
      
      ret$ + RTrim(Left(source$, posn)) + nl$
      source$ = LTrim(Mid(source$, posn+1))
      posn = Len(source$)
   Wend
   
   ProcedureReturn ret$ + source$
EndProcedure


;-- Demo
Define source$, msg$

source$ = "Wrap me baby but don't hurt me, I'll be good like a long stringy should and would!"

msg$ = WordWrap(source$, 30)
MessageRequester("Word wrap demo", msg$)
msg$ = WordWrap(source$, 1)
MessageRequester("Word wrap demo", msg$)
This code can be accelerated by using a pointer to a character instead of Mid().
User avatar
Danilo
Addict
Addict
Posts: 3036
Joined: Sat Apr 26, 2003 8:26 am
Location: Planet Earth

Re: Word wrapping a string to arbitrary position?

Post by Danilo »

@Little John:
Problem is long texts don't get wrapped at all, see:
source$ = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmneopqrstuvwxyz"

I think if no word boundary (space or tab) is found, there should be a hard wrap, so it is still maximum requested line length.
Little John
Addict
Addict
Posts: 4779
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

Re: Word wrapping a string to arbitrary position?

Post by Little John »

Danilo wrote:@Little John:
Problem is long texts don't get wrapped at all, see:
source$ = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmneopqrstuvwxyz"
This is by design.
Danilo wrote:I think if no word boundary (space or tab) is found, there should be a hard wrap, so it is still maximum requested line length.
Yes, that would be an option, but not the way I personally normally would like such a routine to work.
For instance in e-mails normally a line shouldn't be longer than about 70 to 80 characters. But what about a very long URL? A good e-mail program doesn't wrap it, so that it will remain "clickable".

It depends on the context where Fangbeast needs it.
User avatar
Fangbeast
PureBasic Protozoa
PureBasic Protozoa
Posts: 4789
Joined: Fri Apr 25, 2003 3:08 pm
Location: Not Sydney!!! (Bad water, no goats)

Re: Word wrapping a string to arbitrary position?

Post by Fangbeast »

It depends on the context where Fangbeast needs it.

I'm going to use it on the text for the balloon tooltips that RASHAD wrote for us because some of the tip text might be very long.

Instead of manually figuring out where to throw in CRLF pairs which never look right, I want code to do it for me properly during the balloon creation.

It will make all the ballons look the same size and more professional (Dare I really use that word in context with me???)

This recipe program is getting better and better with all of your help. Now I just hope I get feedback from it:):)
Last edited by Fangbeast on Sun Mar 03, 2013 11:27 am, edited 1 time in total.
Amateur Radio/VK3HAF, (D-STAR/DMR and more), Arduino, ESP32, Coding, Crochet
Little John
Addict
Addict
Posts: 4779
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

Re: Word wrapping a string to arbitrary position?

Post by Little John »

This is almost the same function as above, but always forcing a wrap, even if there is no delimiter (like Danilo suggested):

Code: Select all

EnableExplicit

Procedure.s WordWrap (source$, width.i, delimList$="- "+Chr(9), nl$=#LF$)
   Protected.i posn, found, i
   Protected ret$=""
   
   If width <= 0
      ProcedureReturn source$
   EndIf
   
   posn = Len(source$)
   While posn > width
      For i = width To 1 Step -1
         found = FindString(delimList$, Mid(source$,i,1))
         If found > 0
            posn = i
            Break
         EndIf
      Next
      If found = 0
         posn = width
      EndIf
      
      ret$ + RTrim(Left(source$, posn)) + nl$
      source$ = LTrim(Mid(source$, posn+1))
      posn = Len(source$)
   Wend
   
   ProcedureReturn ret$ + source$
EndProcedure


;-- Demo
Define source$, msg$

source$ = "Wrap me baby but don't hurt me, I'll be good like a long stringy should and would!"
msg$ = WordWrap(source$, 10)
MessageRequester("Word wrap demo", msg$)

source$ = "Wrapmebabybutdon'thurtme, I'll be good like a long stringy should and would!"
msg$ = WordWrap(source$, 10)
MessageRequester("Word wrap demo", msg$)
I leave combining both functions, using an additional parameter as a flag, as an exercise for the reader. :-)
User avatar
Danilo
Addict
Addict
Posts: 3036
Joined: Sat Apr 26, 2003 8:26 am
Location: Planet Earth

Re: Word wrapping a string to arbitrary position?

Post by Danilo »

[offtopic]
Little John wrote:
Danilo wrote:I think if no word boundary (space or tab) is found, there should be a hard wrap, so it is still maximum requested line length.
Yes, that would be an option, but not the way I personally normally would like such a routine to work.
For instance in e-mails normally a line shouldn't be longer than about 70 to 80 characters. But what about a very long URL? A good e-mail program doesn't wrap it, so that it will remain "clickable".
The good e-mail program should hard wrap the line at the requested boundary in my opinion and it should still be clickable
on all wrapped lines. Didn't think about that because Outlook 2010 just does it as expected by me, so it is wrapped and clickable. ;)

[/offtopic]

Anyway, thanks for your codes! I tried 2 hours but always something did not work correctly. Didn't get it to work perfectly for all cases I tested,
especially long strings without any word boundaries had always some problems with hard wrap. :D
User avatar
Fangbeast
PureBasic Protozoa
PureBasic Protozoa
Posts: 4789
Joined: Fri Apr 25, 2003 3:08 pm
Location: Not Sydney!!! (Bad water, no goats)

Re: Word wrapping a string to arbitrary position?

Post by Fangbeast »

For me, getting help like this is fantastic. My life is full of doctors, surgeons and insurance claims so I don't think very well lately.

No comments from the peanuts gallery!

RASHAD, if you are still there: If balloon tooltips are on, sometimes ButtonImageGadget images don't appear.

You told me what could be safely disabled but I don't remember?
Amateur Radio/VK3HAF, (D-STAR/DMR and more), Arduino, ESP32, Coding, Crochet
Little John
Addict
Addict
Posts: 4779
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

Re: Word wrapping a string to arbitrary position?

Post by Little John »

Danilo wrote:[offtopic]
Little John wrote:
Danilo wrote:I think if no word boundary (space or tab) is found, there should be a hard wrap, so it is still maximum requested line length.
Yes, that would be an option, but not the way I personally normally would like such a routine to work.
For instance in e-mails normally a line shouldn't be longer than about 70 to 80 characters. But what about a very long URL? A good e-mail program doesn't wrap it, so that it will remain "clickable".
The good e-mail program should hard wrap the line at the requested boundary in my opinion and it should still be clickable
on all wrapped lines. Didn't think about that because Outlook 2010 just does it as expected by me, so it is wrapped and clickable. ;)

[/offtopic]
:-)

I didn't know that e.g. Outlook 2010 can handle URLs this way. Yes, that's fine for the users of Outlook.
But when you are writing (or forwarding) a mail with a long URL using Outlook 2010, and Outlook will insert hard line breaks into the URL, then the risk is high that in the mail client of the recipient that URL will not be clickable any more! (Not only) IMHO a good mail program should be conservative and rather strict when creating mails, and flexible and tolerant when receiving and displaying mails.
Anyway, I almost forgot that in mails there really is a line length limit that HAS TO be considered:
RFC 2822 wrote:There are two limits that this standard places on the number of
characters in a line. Each line of characters MUST be no more than
998 characters, and SHOULD be no more than 78 characters, excluding
the CRLF.
So when I previously thought of never inserting a hard line break in an e-mail, that was wrong.
Little John wrote:I leave combining both functions, using an additional parameter as a flag, as an exercise for the reader. :-)
When I wrote that, my idea was to use a flag that just tells whether or not to use hard wraps.
But after recalling the above section of RFC 2822, I thought that it is more flexible to allow different positions for soft and for hard wraps!
So for creating an e-mail, e.g. you could use softWrapPosn=70, hardWrapPosn=70, and I can use say softWrapPosn=70, hardWrapPosn=998.
Because of this additional idea, I've now written a new WordWrap function.
Danilo wrote:Anyway, thanks for your codes! I tried 2 hours but always something did not work correctly. Didn't get it to work perfectly for all cases I tested,
especially long strings without any word boundaries had always some problems with hard wrap. :D
My first attempt also did not work. Then I recalled the KISS principle. :-)
Danilo, I have to thank you, because discussing with you is always interesting, and often gives me a deeper understanding of a problem, or like in this case gave me some inspiration.

@Fangbeast:
People who throw hamsters at srod or some such thing are more than welcome! :P
User avatar
RichAlgeni
Addict
Addict
Posts: 935
Joined: Wed Sep 22, 2010 1:50 am
Location: Bradenton, FL

Re: Word wrapping a string to arbitrary position?

Post by RichAlgeni »

Just wanted to offer a quick tip from my experience. This is will only work with the new Bool function.

This method will count the number of fields in a string using a delimiter, but won't give a false count greater than 0 when the string is null.

Code: Select all

CountString(test$, " ") + Bool(test$ <> "")
Little John
Addict
Addict
Posts: 4779
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

Re: Word wrapping a string to arbitrary position?

Post by Little John »

Fangbeast wrote:I'm going to use it on the text for the balloon tooltips that RASHAD wrote for us because some of the tip text might be very long.

Instead of manually figuring out where to throw in CRLF pairs which never look right, I want code to do it for me properly during the balloon creation.
I am sorry: I almost forgot (but jassing reminded me) that the code which I had written mainly was intended for text files or windows/gadgets with fixed-width fonts. With a variable-width font (which is probably used by the tooltips) the result might not be satisfying.
Therefore now I wrote new code that can be used with variable-width fonts. Unfortunately, I wasn't able to give an example with a tooltip, because I don't know how to use PB's built-in function TextWidth() with tooltips.
Post Reply