Announcement

Collapse
No announcement yet.

gbWordWrap

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • gbWordWrap

    This thread is for discussion of gbWordWrap, which I've released into the Source Code forum.

    I wrote gbWordWrap as a test bed to test out, and improve the speed, of code that addresses four aspects of wordwrapping that interest me.
    1. Prepare text for paragraph wrapping (pointer approach to editing the number of $CRLF delimiters)
    2. WordWrap (that Pierre and I worked on – takes a string with $CRLF and returns a string with only $CR)
    3. Locate delimiter positions for quickly locating text of lines (something based on recent comments by Eros)
    4. Maintaining the top position in the text while changing font properties and ListView size.
    The code I released covers #1-#3 but doesn't address #4.



    Features include:
    • Use +/- to change font size
    • Dropdown combobox to select font
    • Toggle bold
    • Toggle between line and paragraph wrapping
    • Select a text file whose content will be displayed in the ListView
    • Toggle between 10MB of test data or the user-selected file
    • Timing for each of the 1-2-3 items above, plus total time, plus line count of the wrapped text (statusbar)
    • Restore text to the top line from the last session
    • Re-wrap after resizing the dialog (not during a resize)
    • Save settings between sessions, including dialog size/location
    As always, comments and suggestions are welcome.
    Last edited by Gary Beene; 9 Oct 2017, 10:42 PM.

  • #2
    Some definition - line wrap vs paragraph wrap

    Consider this text:

    Now is the time for Pierre to establish a new kingdom.
    Now is the time for Pierre to establish a new kingdom.

    "Line Wrap" could give this - wraps each line individually:

    Now is the time for Pierre to establish
    a new kingdom.
    Now is the time for Pierre to establish
    a new kingdom.

    "Paragraph Wrap" could give this - combines lines that a not separated by $crlf + $crlf

    Now is the time for Pierre to establish
    new kingdom. Now is the time for
    Pierre to establish a new kingdom.

    Generally, the paragraph wrapping gives the best visual result. But line wrapping is must faster.

    Comment


    • #3
      I may have mentioned this in another of the several threads I've started of late, but in apps where a user can press a button to change the font size, the response of the word wrapping code needs to accommodate a fast user. I use 5 clicks per second - 0.2s per click - as my guideline for host fast sequence of the 4 items in #1 above need to operate. A tad faster would be even better, but by 0.15s my need for speed runs out.

      Also, the speed does depend on how much text is involved. For my discussions, I've been running speed tests against ~10MB of text. That size pretty much seems to cover 99% of all book sizes.

      Comment


      • #4
        My thanks to Pierre for his work on the #2 item in the OP, and to Eros for his code from which I derived the code for the #3 item in the OP.

        Comment


        • #5
          If you look at the gbWordWrap source code, you'll find that items 1-3 of the OP are handled in one function, PierreWrap. That function monitors the speed of the items 1-3 from the OP and puts the result in the StatusBar.
          Last edited by Gary Beene; 9 Oct 2017, 11:03 PM.

          Comment


          • #6
            On the OP item 4 ...

            Maintaining the top position in the text while changing font properties and ListView size.
            Keeping the top line works between sessions because in that case, all text is on the same line at session end and when the session restarts.

            But when you change the font name/size/bold or the ListView control size, applying word wrap changes the number of lines and which words are then present on which line. That's the fundamental problem that has to be solved to get an answer to item 4 in the OP.

            Since text can be repeated in a document, you can't just use the text on the top line as the place at which to begin the ListView listing after a font change. The text in a line may not even be on the same line.

            You also can't use the byte position of the first character in the top line, because the number of line delimiters changes after a font change.

            One option might be to insert a special character in the original text, removed after word wrapping but used as the marker to help define which text needs to go in the first line.

            Whatever the approach, the content of the new top line after a font change can definitely not be the same text as the current top line, which is what the solution to item 4 in the OP has to take into account.

            Also, if the user presses a button several times, increasing the size each time, does the baseline position remain constant through all clicks, or after each click does the baseline position change?

            I should mention that Kindle seems to ignore the issue. When you change the font size in Kindle, the top line becomes totally different text - causing the user to potentially miss some lines of text, or at least not knowing how much to scroll up/down to get back to their position in the book. I'm working to get a better solution than that - not perfect perhaps, but as least some way to keep the user from completely losing their place in the book.

            Comment


            • #7
              A word on the word wrapping algorithm that Pierre and I worked on.

              With an incoming text of ...

              Code:
              "abc def" + $crlf + "ghi jkl"
              We found that we could speed up word wrapping quite a bit by having the end result be text that uses a single character delimiter. For example, if a wrap occurred between two words, we changed the $SPC between the words to $CR. That means we also replaced $CRLF with $SPC+$CR. Then, when we parse for lines of text, we parse on just the $CR.

              Comment


              • #8
                Originally posted by Gary Beene View Post
                As always, comments and suggestions are welcome.
                Nifty code! Just a tiny observation: As soon as the text box gets so narrow (or the font is so large) that a full word doesn't have enough space, the display changes to a Chinese (or Korean?) character set:



                Cheers,
                Albert
                „Let the machine do the dirty work.“
                The Elements of Programming Style, Brian W. Kernighan, P. J. Plauger 1978

                Comment


                • #9
                  Gary, maybe place an upper limit to the size of fonts so that it won't display chinese?

                  Comment


                  • #10
                    Font size is irrelevant. The word wrapping routine is just plain faulty.
                    Which is rather odd, because it only handles ANSI text.

                    It does a bad job with this

                    Code:
                    1) Click the cell where "Subtotal:" is to be entered.
                    2) Type "Subtotal:".
                    
                    Or,
                    
                    1) Click the cell where "Subtotal:" is to be entered.
                    2) Set "Text" to "Subtotal:" in the "Data" category.
                    Dominic Mitchell
                    Phoenix Visual Designer
                    http://www.phnxthunder.com

                    Comment


                    • #11
                      Hey Guys!

                      Sorry - I was out of pocket today, but thanks for the observations.

                      Yep, I can confirm what Dominic says - the algorithm doesn't appear to handle some combinations of word count/word sizes on the small end. It's not a word combination that I've run into using the code to read dozens of books, but I can certainly replicate the result here for the test case we're discussing.

                      I'll go experiment with it to find out what's causing the problem.
                      .

                      Dominic,
                      On my test here, the text is displayed fine, except the line containing the "Or,".

                      Albert,
                      The large font size would seem to come into play because it affects how many words/characters can fit on a line.


                      Chris,
                      Thanks for the thought, but I definitely want there to be no font size limit. I think when I figure out what is wrong, the font size limit will not have to be change.


                      I'll be back!

                      Comment


                      • #12
                        By the way, the file filter for the Open File dialog does not work.
                        On my system, it displays files with the extensions *.exe, *.c, *.png, *.txt etc.
                        Dominic Mitchell
                        Phoenix Visual Designer
                        http://www.phnxthunder.com

                        Comment


                        • #13
                          Thanks Dominic,
                          I'd noticed it a while ago, but totally forgot about it! Will fix once I figure out the issue we've discussed!
                          Gary

                          Comment


                          • #14
                            This line ...
                            Code:
                               filter$ = Chr$("Data",*.txt",0)
                            Should be this ...
                            Code:
                               filter$ = Chr$("Data",0,"*.txt",0)
                            I left out the first "0" argument.

                            Comment


                            • #15
                              I think I found the issue on the weird characters but have to leave on an errand ... will post when I get back.

                              Comment


                              • #16
                                Well, if I change the code to set BookText = "1234" or any string < 5 characters, then the text is not displayed correctly.

                                In WM_Notify the text appears correctly when displayed in the Dialog caption, but does not appear correctly when displayed in the ListView. Not sure why that is just yet. The code looks like any other virtual ListView I've used previously but apparently I'm missing something.

                                Looking ...

                                From the Callback function ...

                                Code:
                                CallBack Function DlgProc() As Long
                                   Local w,h,iRow As Long, pLVDI As LV_DispInfoW Ptr, temp$$, tmp$
                                   Select Case CbMsg
                                      Case %WM_Notify
                                         Select Case Cb.NmId
                                            Case %IDC_ListView
                                               Select Case Cb.NmCode
                                                  Case %LVN_GetDispInfoW                                            'notification to ask for data
                                                        pLVDI = Cb.LParam                                           'pointer to LVDISPINFO structure for requested subitem
                                                        iRow = @pLVDI.item.iItem                                    'row being asked for
                                                        temp$$ = Trim$(Mid$(BookText, CRArray(iRow) To CRArray(iRow+1)), Any $Spc + $CrLf)
                                                        Dialog Set Text hDlg, temp$$                ‘works
                                                        @pLVDI.item.pszText = StrPtr(temp$$)        ‘fails when the line to display is 4 or less characters
                                               End Select
                                         End Select

                                Comment


                                • #17
                                  Hi Gary,

                                  Give this a try.
                                  Code:
                                  temp$$ = Trim$(Mid$(BookText, CRArray(iRow) To CRArray(iRow+1)), Any $$Spc + $$CrLf)
                                  (Unicode versions of $Spc and $CrLf)
                                  Rgds, Dave

                                  Comment


                                  • #18
                                    Howdy, Dave!

                                    Thanks! I tried your suggestion and it seems to give the desired result. But, since the BookText variable is a normal STRING variable, I'm not sure why using $$SPC or $$CRLF would affect the value that it to be stored in temp$$. Your thought on that?

                                    You'll recall that after wordwrapping in gbWordWrap, the BookText variable contains only $CR characters, not $CRLF. So when I use $$SPC + $$CR, that seems to work too.

                                    I was talking with Pierre yesterday and he had me explicitly end the string in Nul$(2). That worked some of the time, but not in every case.

                                    I tried this other approach, similar to your suggestion, but it did not work ...

                                    Code:
                                                            tmp$ = Trim$(Mid$(BookText, CRArray(iRow) To CRArray(iRow+1)), Any $Spc + $CrLf)
                                                            temp$$ = tmp$
                                    ... but this does work ...

                                    Code:
                                                            tmp$ = Mid$(BookText, CRArray(iRow) To CRArray(iRow+1))
                                                            temp$$ = Trim$(tmp$, Any $$Spc + $$CrLf)
                                    There's some interaction going on here that I don't understand just yet.

                                    I've been looking at other virtual ListView code that I've used in other apps, and none of those demonstrate the problem. This following code, for example, looks pretty much like what I've done with gbWordWrap and does not show the odd characters.

                                    Code:
                                    'Compilable Example:
                                    #Compile Exe
                                    #Dim All
                                    %Unicode=1
                                    #Include "win32api.inc"
                                    
                                    %IDC_ListView = 500
                                    Global hDlg, hListView As Dword, D() As String
                                    
                                    Function PBMain() As Long
                                       Dialog Default Font "Tahoma", 12, 1
                                       Dialog New Pixels, 0, "Virtual ListView", , , 150,125, %WS_SysMenu,, To hDlg
                                       Control Add ListView, hDlg, %IDC_ListView,"", 0,0,150,125, %WS_Child Or %WS_TabStop Or %WS_Visible Or %LVS_ShowSelAlways Or %LVS_Report Or %LVS_OwnerData Or %LVS_ShowSelAlways Or %LVS_SingleSel
                                       Control Handle hDlg, %IDC_ListView To hListView                  'handle to ListView
                                       ListView Insert Column hDlg, %IDC_Listview, 1, "Data", 150,0     'set headers
                                       SendMessage (hListView, %WM_NOTIFYFORMAT, hDlg, %NF_REQUERY)
                                       ReDim D(2) : Array Assign D() = "Zero","One","Two"
                                       ListView_SetItemCountEx(hListView, UBound(D)+1, %LVSICF_noInvalidateAll)   'max rows
                                       Dialog Show Modal hDlg, Call CBProc
                                    End Function
                                    
                                    CallBack Function CBProc
                                       Local iRow As Long, temp$$, pLVDI As LV_DISPINFOW Ptr
                                       Select Case Cb.Msg
                                          Case %WM_Notify
                                             Select Case Cb.NmId
                                                Case %IDC_ListView
                                                   Select Case Cb.NmCode
                                                      Case %LVN_GetDispInfoW             'notification to ask for data
                                                         pLVDI = Cb.LParam              'pointer to LVDISPINFO structure for requested subitem
                                                         iRow = @pLVDI.item.iItem       'row being asked for
                                                         temp$$ = D(iRow)
                                                         @pLVDI.item.pszText = StrPtr(temp$$)
                                                   End Select
                                             End Select
                                       End Select
                                    End Function

                                    Comment


                                    • #19
                                      Gary,

                                      Make temp$$ as STATIC

                                      Regard,
                                      Pierre

                                      Comment


                                      • #20
                                        Howdy, Pierre!
                                        or Global ... seems to work ..

                                        ... but why (other than it seems to work) ?

                                        What is the underlying issue that STATIC or GLOBAL resolves?
                                        Last edited by Gary Beene; 15 Oct 2017, 12:08 PM.

                                        Comment

                                        Working...
                                        X