Page 1 of 2

Word wrapping a string to arbitrary position?

Posted: Sun Mar 03, 2013 6:46 am
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.

Re: Word wrapping a string to arbitrary position?

Posted: Sun Mar 03, 2013 7:17 am
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.

Re: Word wrapping a string to arbitrary position?

Posted: Sun Mar 03, 2013 7:56 am
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


Re: Word wrapping a string to arbitrary position?

Posted: Sun Mar 03, 2013 8:39 am
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!"

Re: Word wrapping a string to arbitrary position?

Posted: Sun Mar 03, 2013 10:19 am
by MachineCode
I just knocked this up in 5 minutes but it may not be reliable.

[Edit] It wasn't. :oops:

Re: Word wrapping a string to arbitrary position?

Posted: Sun Mar 03, 2013 10:54 am
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().

Re: Word wrapping a string to arbitrary position?

Posted: Sun Mar 03, 2013 11:02 am
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.

Re: Word wrapping a string to arbitrary position?

Posted: Sun Mar 03, 2013 11:09 am
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.

Re: Word wrapping a string to arbitrary position?

Posted: Sun Mar 03, 2013 11:16 am
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:):)

Re: Word wrapping a string to arbitrary position?

Posted: Sun Mar 03, 2013 11:21 am
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. :-)

Re: Word wrapping a string to arbitrary position?

Posted: Sun Mar 03, 2013 12:42 pm
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

Re: Word wrapping a string to arbitrary position?

Posted: Sun Mar 03, 2013 1:37 pm
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?

Re: Word wrapping a string to arbitrary position?

Posted: Sun Mar 03, 2013 7:02 pm
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

Re: Word wrapping a string to arbitrary position?

Posted: Mon Mar 04, 2013 12:23 am
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$ <> "")

Re: Word wrapping a string to arbitrary position?

Posted: Mon Mar 04, 2013 1:19 am
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.