Recent

Author Topic: [solved]Paragraph Indents only work correctly in TRichMemo when font size is 10  (Read 2041 times)

indydev

  • Full Member
  • ***
  • Posts: 114
Seeing strange results with RichMemo and paragraph indentation, I decided to examine the RTF output. Long story short, RichMemo only makes the correct indents (HeadIndent -- \li , FirstLine indent -- \fi) when the font size of the TRichMemo control is set to 10.  At least that is the case in Linux.  I made a button toggle to switch between font size 10 and 12 to watch the correct and incorrect display.  The RTF code for font size is `\fs20` for 10 and `\fs24` for 12. Setting up a TMemo and directing the RTF output from TRichMemo on a form you can see the RTF code display the `\fsxx` values correctly.

Here's some code I used to test this:

Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. var
  3.   pm: TParaMetric;
  4. begin
  5.   RichMemo1.Clear;
  6.   RichMemo1.Lines.Add('1.' + #9 + 'To create a hanging indent for list items in RTF, you need to set the `\li` (left indent) to the desired indentation level for the list item, and the `\fi` (first line indent) to a negative value that pulls the first line back to the left, creating the hanging effect for the list sym');
  7.   RichMemo1.Lines.Add('2.' + #9 + 'If you want to set a specific line spacing, you would include `\sl` followed by the value and `\slmult1` in your RTF control words. If you want to use the default line spacing, you can simply omit these control words.');
  8.   RichMemo1.Lines.Add('3.' + #9 + 'In RTF, the `\fi` value is the indentation for the first line of a paragraph relative to the left margin, and the `\li` value is negative.');
  9.  
  10.   pm.HeadIndent:=18;
  11.   pm.FirstLine:=-18;
  12.  
  13.   RichMemo1.SetParaMetric(0, Length(RichMemo1.Text), pm);
  14. end;

Here's the RTF output with font set to size 10:

Code: Text  [Select][+][-]
  1. {\rtf1\ansi\ansicp1252\deff0\deflan1033{\fonttbl{\f0\fcharset0 Ubuntu;}}{\colortbl;\red211\green211\blue211;}\f0\fs20\cf1 \pard\li360\fi-360\sl200\slmult1 1.   To create a hanging indent for list items in RTF, you need to set the `\\li` (left indent) to the desired indentation level for the list item, and the `\\fi` (first line indent) to a negative value that pulls the first line back to the left, creating the hanging effect for the list sym\par \pard\li360\fi-360\sl200\slmult1 2.  If you want to set a specific line spacing, you would include `\\sl` followed by the value and `\\slmult1` in your RTF control words. If you want to use the default line spacing, you can simply omit these control words.\par \pard\li360\fi-360\sl200\slmult1 3.     In RTF, the `\\fi` value is the indentation for the first line of a paragraph relative to the left margin, and the `\\li` value is negative.\par }

And the RTF output with font set to size 12:

Code: Text  [Select][+][-]
  1. {\rtf1\ansi\ansicp1252\deff0\deflan1033{\fonttbl{\f0\fcharset0 Ubuntu;}}{\colortbl;\red211\green211\blue211;}\f0\fs24\cf1 \pard\li360\fi-360\sl200\slmult1 1.   To create a hanging indent for list items in RTF, you need to set the `\\li` (left indent) to the desired indentation level for the list item, and the `\\fi` (first line indent) to a negative value that pulls the first line back to the left, creating the hanging effect for the list sym\par \pard\li360\fi-360\sl200\slmult1 2.  If you want to set a specific line spacing, you would include `\\sl` followed by the value and `\\slmult1` in your RTF control words. If you want to use the default line spacing, you can simply omit these control words.\par \pard\li360\fi-360\sl200\slmult1 3.     In RTF, the `\\fi` value is the indentation for the first line of a paragraph relative to the left margin, and the `\\li` value is negative.\par }

I decided to try and fool the TRichMemo control by changing the `\li360\fi-360`values to `\li432\fi-432` to see if that would fix the issue when the font size was set to 12 (12*2*18=432). It looked close but was slightly off. When I checked the RTF output from the TRichMemo control it had changed `\li432\fi-432` to `\li435\fi-435` which seems totally bizarre.

I only use Linux so I don't know if this happens in Windows or not.
« Last Edit: December 15, 2023, 06:06:05 pm by indydev »

indydev

  • Full Member
  • ***
  • Posts: 114
Found a way around for font size 12 if you are willing to have a little more space, and set the `lixxx\fi-xxx` numbers manually.  Since 480 is a multiple of both 24 and 20 (20*24) AND a multiple of 5, just change `\li360\fi-360` to `\li480\fi-480`. This at least lines up the indents correctly. The RTF Encoder in Linux seems to only allow for `\li ` and `\fi ` values in multiples of 5 (although `\li0` is ok).

rvk

  • Hero Member
  • *****
  • Posts: 6327
  pm.HeadIndent:=18;
  pm.FirstLine:=-18;
I'm not sure what the problem is (I'm not on Linux but I see nothing strange in Windows).
(Or if the display is "off" you should have included screenshots instead of rtf-code)

The HeadIndent and Firstline are in points. In the RTF it's 1/20th point (twip) so that's why you get 360 (18*20).

Changing the font wouldn't effect this.

(Or are your seeing that it does have effect the indent size when you switch fontsize?)


indydev

  • Full Member
  • ***
  • Posts: 114
That is how it should work, but in Linux it doesn't. I have tried to track down why this happens but cannot find it.

indydev

  • Full Member
  • ***
  • Posts: 114
Here you can see the two results. The first is with the font at size 10. The second is with the font at size 12.

If you are examining the forms, ignore the checked bullet radio button, it's disconnected for the moment.
« Last Edit: December 15, 2023, 04:06:24 pm by indydev »

rvk

  • Hero Member
  • *****
  • Posts: 6327
Actually... this seems to be absolutely correct.
But it seems that the TAB is reached and a second tab is used.

If you look at the indent itself, it's the same for 10 or 12 points. No problems there.

It's only that for 12 points the first TAB position is reached with 1. so the editor takes the second tab position.

What happens if you set a bigger first tab position before adding the text (so it can hold the 2. etc for 10 and 12 points)?

rvk

  • Hero Member
  • *****
  • Posts: 6327
YES, I just checked.
It seems the default tab positions are effected by the font size.

So there is no problem if you set hard tab positions and don't count on the automatic created ones.

So this is no indent problem (but an automatic tab-set problem).

indydev

  • Full Member
  • ***
  • Posts: 114
Hmmm. How do I get rid of automatic tabs? I have TabOrder = 0, TabStop = unchecked, WantTabs = unchecked. I am missing something.

indydev

  • Full Member
  • ***
  • Posts: 114
Ugh. Ignore the last message. I realize that all those tab items have to do with form tabbing.  However, I still don't understand how to get rid of automatic tabs.

rvk

  • Hero Member
  • *****
  • Posts: 6327
However, I still don't understand how to get rid of automatic tabs.
You can get rid of automatic tabs by setting hard tabs.
When you set a first hard tab at position for example at 4cm, all automatic tabs before 4cm are removed.
After (beyond) all hard tabs the automatic tabs kick back in.

BTW TabOrder, TabStop are for the component and have nothing to do with tab settings in your text.
Ah, you already saw that... :)
WantTabs is the ability to set a tab character with keyboard input (otherwise you tab our of the richmemo to the next component).

So you need to set the tab positions with RichMemo1.SetParaTabs.
https://wiki.freepascal.org/RichMemo#SetParaTabs
« Last Edit: December 15, 2023, 04:54:49 pm by rvk »

indydev

  • Full Member
  • ***
  • Posts: 114
Got it. Thanks.

indydev

  • Full Member
  • ***
  • Posts: 114
Hmmm. I get no change by setting tabs to 0 (empty) using the following to the code.

Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. var
  3.   pm: TParaMetric;
  4.   tb: TTabStoplist;  // new tab variable
  5. begin
  6.   tb.Count:=0;      // tab count
  7.   tb.Tabs:=[];      // tab offset array
  8.   InitTabStopList(tb);                // No difference with or without this line.
  9.   RichMemo1.SetParaTabs(0, -1, tb);   // No difference from before.
  10.  
  11.   RichMemo1.Clear;
  12.   RichMemo1.Lines.Add('1.' + #9 + 'To create a hanging indent for list items in RTF, you need to set the `\li` (left indent) to the desired indentation level for the list item, and the `\fi` (first line indent) to a negative value that pulls the first line back to the left, creating the hanging effect for the list sym');
  13.   RichMemo1.Lines.Add('2.' + #9 + 'If you want to set a specific line spacing, you would include `\sl` followed by the value and `\slmult1` in your RTF control words. If you want to use the default line spacing, you can simply omit these control words.');
  14.   RichMemo1.Lines.Add('3.' + #9 + 'In RTF, the `\fi` value is the indentation for the first line of a paragraph relative to the left margin, and the `\li` value is negative.');
  15.  
  16.   pm.HeadIndent:=18;
  17.   pm.FirstLine:=-18;
  18.  
  19.  
  20.   RichMemo1.SetParaMetric(0, -1, pm);
  21. end;              

I am not attaching any pictures because there is no difference.  I wonder if the GTKWidget set is the issue.

rvk

  • Hero Member
  • *****
  • Posts: 6327
What did you imagine with a tab stop at 0 points?
A tab stop is a stop for a #9 character. That can't be at 0 points.

This works under Windows... but when I add the TParaMetrics, then the tab seems to stick to the old setting.
Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. var
  3.   pm: TParaMetric;
  4.   tb: TTabStoplist;
  5. begin
  6.   RichMemo1.Clear;
  7.   RichMemo1.Lines.Add('1.' + #9 + 'To create a hanging indent for list items in RTF, you need to set the `\li` (left indent) to the desired indentation level for the list item, and the `\fi` (first line indent) to a negative value that pulls the first line back to the left, creating the hanging effect for the list sym');
  8.   RichMemo1.Lines.Add('2.' + #9 + 'If you want to set a specific line spacing, you would include `\sl` followed by the value and `\slmult1` in your RTF control words. If you want to use the default line spacing, you can simply omit these control words.');
  9.   RichMemo1.Lines.Add('3.' + #9 + 'In RTF, the `\fi` value is the indentation for the first line of a paragraph relative to the left margin, and the `\li` value is negative.');
  10.   {
  11.   pm.HeadIndent := 18;
  12.   pm.FirstLine := -18;
  13.   RichMemo1.SetParaMetric(0, -1, pm);
  14.   }
  15.   InitTabStopList(tb, [40, 50, 60]);
  16.   RichMemo1.SetParaTabs(0, RichMemo1.GetTextLen, tb);
  17. end;

Does this work under Linux? (just powered down my hyper-v mint)
Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. var
  3.   pm: TParaMetric;
  4.   tb: TTabStoplist;
  5. begin
  6.   RichMemo1.Clear;
  7.   RichMemo1.Lines.Add('1.' + #9 + 'To create a hanging indent for list items in RTF, you need to set the `\li` (left indent) to the desired indentation level for the list item, and the `\fi` (first line indent) to a negative value that pulls the first line back to the left, creating the hanging effect for the list sym');
  8.   RichMemo1.Lines.Add('2.' + #9 + 'If you want to set a specific line spacing, you would include `\sl` followed by the value and `\slmult1` in your RTF control words. If you want to use the default line spacing, you can simply omit these control words.');
  9.   RichMemo1.Lines.Add('3.' + #9 + 'In RTF, the `\fi` value is the indentation for the first line of a paragraph relative to the left margin, and the `\li` value is negative.');
  10.   pm.HeadIndent := 18;
  11.   pm.FirstLine := -18;
  12.   RichMemo1.SetParaMetric(0, -1, pm);
  13.   InitTabStopList(tb, [40, 50, 60]);
  14.   RichMemo1.SetParaTabs(0, RichMemo1.GetTextLen, tb);
  15. end;

rvk

  • Hero Member
  • *****
  • Posts: 6327
Just tried it, and yes. Under Linux it works (but not under Windows).

And setting the first tab at 18 will get the result you want (because you also set the indent at 18.

Code: Pascal  [Select][+][-]
  1. InitTabStopList(tb, [18, 99]);
  2. RichMemo1.SetParaTabs(0, RichMemo1.GetTextLen, tb);

BTW. It seems under Windows that the first automatic tab already set to the indent position. This is not the case in Linux.
So doing SetParaTabs with the first tab at 18 will work on Linux (and on Windows it can't hurt because the indent is used anyway).
« Last Edit: December 15, 2023, 05:47:31 pm by rvk »

indydev

  • Full Member
  • ***
  • Posts: 114
My apologies. I thought `count` referred to the number of TabStops not an offset. But the good news is that your solution works. I will just set the tabs at intervals of 18 (and thanks for letting me know that it works under windows as well).

 

TinyPortal © 2005-2018