Recent

Author Topic: WrapText function question  (Read 7132 times)

typo

  • Hero Member
  • *****
  • Posts: 3051
WrapText function question
« on: September 04, 2014, 06:53:27 pm »
In the project attached I use SynEdit.CharsInWindow to set the MaxColum parameter for the function, but it seems not to result fine. Why?

MaxColum seems to be not observed.
« Last Edit: September 04, 2014, 06:57:38 pm by typo »

Edson

  • Hero Member
  • *****
  • Posts: 1302
Re: WrapText function question
« Reply #1 on: September 04, 2014, 07:36:47 pm »
It's because WrapText() don't do what it is supposed to do (I see it breaks the line where find the first space after Maxcol).

SynEdit.CharsInWindow is OK.

Maybe you need to write your own WrapText(). And it would consider to work with UTF-8.
Lazarus 2.2.6 - FPC 3.2.2 - x86_64-win64 on Windows 10

engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: WrapText function question
« Reply #2 on: September 04, 2014, 07:46:38 pm »
It does what it is supposed to do, but not what you want it to do.

In your sample: MyMemo.CharsInWindow is 30 chars
MyMemo.CharsInWindow - 8 is 22 chars
The line that shows the problem is:
Quote
a estas aventuras que arruinaram
The blue color is 22 chars
The green color is within 30 chars
The red color is more than 30 chars

The code does not break a word except at end of line or at one of [' ', '-', #9]

A line of code might explain it better. Try:
Code: [Select]
  MyMemo.Text := WrapText(MyMemo.Text, sLineBreak, ['A'..'Z','a'..'z',' ', '-', #9], MyMemo.CharsInWindow);

typo

  • Hero Member
  • *****
  • Posts: 3051
Re: WrapText function question
« Reply #3 on: September 04, 2014, 07:51:46 pm »
You mean that the function breaks the line after MaxColum value and not before as expected?

taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: WrapText function question
« Reply #4 on: September 04, 2014, 07:55:03 pm »
You mean that the function breaks the line after MaxColum value and not before as expected?
Yes. Max column is not an absolute value.
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: WrapText function question
« Reply #5 on: September 04, 2014, 07:56:41 pm »
It breaks words AFTER MaxCol at BreakStr or BreakChars only
Code: [Select]
    While ((P<=Len) and ((P<=MaxCol) or not IBC)) and ((LQ<>#0) or Not HB) do

engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: WrapText function question
« Reply #6 on: September 04, 2014, 08:02:03 pm »
One more thing, it does not break a quote.
Code: [Select]
      If (C=LQ) then
        LQ:=#0
      else If (C in Quotes) then
        LQ:=C;
      If (LQ<>#0) then
        Inc(P)

Mind you a quote starts with ' or ":
Code: [Select]
const
  Quotes = ['''', '"'];
« Last Edit: September 04, 2014, 08:04:35 pm by engkin »

typo

  • Hero Member
  • *****
  • Posts: 3051
Re: WrapText function question
« Reply #7 on: September 04, 2014, 08:14:31 pm »
Delphi seems to break the line before MaxColum value. See here:

http://www.delphibasics.co.uk/RTL.asp?Name=WrapText

Could it be a bug?
« Last Edit: September 04, 2014, 08:18:53 pm by typo »

engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: WrapText function question
« Reply #8 on: September 04, 2014, 08:31:04 pm »
If they are meant to be identical then yes it is a bug. they are not identical. Someone with Delphi could confirm it.

typo

  • Hero Member
  • *****
  • Posts: 3051
Re: WrapText function question
« Reply #9 on: September 05, 2014, 01:54:02 am »
I have gone to write my own WrapText function and here it is:

Code: [Select]
function MyWrapText(S :string; MaxCol:integer): string;
var
  P :PChar;
  CharLen, i :integer;
  C :string;
  RightSpace : Integer;
  LastLineEnding : Integer;
begin
  Result := '';
  P := PChar(S);
  LastLineEnding := 0;
  i := 1;
  while P^ <> #0 {i <= Length(S)} do
  begin
    CharLen := UTF8CharacterLength(P);
    C := UTF8Copy(P, 1, 1);
    Result := Result + C;
    if P^ = #10 then
      LastLineEnding := i;
    if (i - LastLineEnding >= MaxCol) then 
    begin
      RightSpace := Length((Result)) - RPos(' ', (Result));
      Dec(p, RightSpace);
      Dec(i, RightSpace);
      SetLength(Result, Length(Result) - RightSpace);
      Result := Result + LineEnding;
      LastLineEnding := i;
    end;
    Inc(P, CharLen);
    Inc(i, Charlen);
  end;
end;

I have noticed that sometimes it fails (for very narrow SynEdits, typically letting the last line unwrapped), but I don't know why.

My usage:

Code: [Select]
procedure TForm1.Button1Click(Sender : TObject);
begin
  MyMemo.Text := MyWrapText(MyMemo.Text, MyMemo.CharsInWindow);
end;
« Last Edit: September 05, 2014, 04:51:49 am by typo »

engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: WrapText function question
« Reply #10 on: September 05, 2014, 03:54:53 am »
shouldn't this line:
Code: [Select]
    if i - LastLineEnding = MaxCol then
be:
Code: [Select]
    if i - LastLineEnding >= MaxCol then
?

typo

  • Hero Member
  • *****
  • Posts: 3051
Re: WrapText function question
« Reply #11 on: September 05, 2014, 04:00:30 am »
You have reason. It seems to work fine now.

typo

  • Hero Member
  • *****
  • Posts: 3051
Re: WrapText function question
« Reply #12 on: September 05, 2014, 02:27:03 pm »
I have just edited a bit the code above.

For till 1000 lines of final text, for instance, this routine works fine for wordwrapping SynEdit, although it is not optimized. But making SynEdit itself wrap words is another issue.

WrapText function implementation does not work fine.
« Last Edit: September 05, 2014, 02:38:19 pm by typo »

 

TinyPortal © 2005-2018