Recent

Author Topic: RichMemo LineSpacing does not work in Linux?  (Read 2312 times)

paxnet_be

  • New Member
  • *
  • Posts: 25
RichMemo LineSpacing does not work in Linux?
« on: January 23, 2024, 02:23:52 pm »
Hi,

I tested in RichMemo both procedures SetParaMetric and SetRangeParaParams with LineSpacing.

Both procedures works well in Windows, but not in Linux. What did I miss?

See here the code:
Code: Pascal  [Select][+][-]
  1. unit uLineSpacing;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, Menus,
  9.   RichMemo;
  10.  
  11. type
  12.  
  13.   { TForm1 }
  14.  
  15.   TForm1 = class(TForm)
  16.     Button1: TButton;
  17.     RatioSingle: TMenuItem;
  18.     RatioOneHalf: TMenuItem;
  19.     RatioDouble: TMenuItem;
  20.     PMLineSpacing: TPopupMenu; // PM = PopMenu
  21.     RichMemo1: TRichMemo;
  22.     procedure Button1Click(Sender: TObject);
  23.     procedure RatioSingleClick(Sender: TObject);
  24.     procedure RatioOneHalfClick(Sender: TObject);
  25.     procedure RatioDoubleClick(Sender: TObject);
  26.   private
  27.     ParagraphMetric: TParaMetric;
  28.   public
  29.  
  30.   end;
  31.  
  32. var
  33.   Form1: TForm1;
  34.  
  35. implementation
  36.  
  37. {$R *.lfm}
  38.  
  39. { TForm1 }
  40.  
  41. procedure TForm1.Button1Click(Sender: TObject);
  42. begin
  43.   {
  44.     PopUp menu with 3 items:
  45.     1.0: OnClick --> RatioSingleClick
  46.     1.5: OnClick --> RatioOneHalfClick
  47.     2.0: OnClick --> RatioDoubleClick
  48.   }
  49.   PMLineSpacing.PopUp;
  50. end;
  51.  
  52. procedure TForm1.RatioSingleClick(Sender: TObject);
  53. begin
  54.   InitParaMetric(ParagraphMetric);
  55.   with RichMemo1 do begin
  56.     GetParaMetric(SelStart, ParagraphMetric);
  57.     ParagraphMetric.LineSpacing := DefLineSpacing;
  58.     ShowMessage('Line Space:' + #13 +
  59.                 'SelStart = ' + IntToStr(SelStart) + #13 +
  60.                 'SelLength = ' + IntToStr(SelLength) + #13 +
  61.                 'LineSpacing = ' + FloatToStr(ParagraphMetric.LineSpacing));
  62.     {
  63.       The use of SetParaMetric or SetRangeParaParams works both well
  64.       in Windows, but not in Linux.
  65.     }
  66.     SetParaMetric(SelStart, SelLength, ParagraphMetric);
  67.     //SetRangeParaParams(SelStart, SelLength, [pmm_LineSpacing], ParagraphMetric);
  68.   end;
  69. end;
  70.  
  71. procedure TForm1.RatioOneHalfClick(Sender: TObject);
  72. begin
  73.   InitParaMetric(ParagraphMetric);
  74.   with RichMemo1 do begin
  75.     GetParaMetric(SelStart, ParagraphMetric);
  76.     ParagraphMetric.LineSpacing := DefLineSpacing * 1.5;
  77.     ShowMessage('One Half Line Space:' + #13 +
  78.                 'SelStart = ' + IntToStr(SelStart) + #13 +
  79.                 'SelLength = ' + IntToStr(SelLength) + #13 +
  80.                 'LineSpacing = ' + FloatToStr(ParagraphMetric.LineSpacing));
  81.     {
  82.       The use of SetParaMetric or SetRangeParaParams works both well
  83.       in Windows, but not in Linux.
  84.     }
  85.     SetParaMetric(SelStart, SelLength, ParagraphMetric);
  86.     //SetRangeParaParams(SelStart, SelLength, [pmm_LineSpacing], ParagraphMetric);
  87.   end;
  88. end;
  89.  
  90. procedure TForm1.RatioDoubleClick(Sender: TObject);
  91. begin
  92.   InitParaMetric(ParagraphMetric);
  93.   with RichMemo1 do begin
  94.     GetParaMetric(SelStart, ParagraphMetric);
  95.     ParagraphMetric.LineSpacing := DefLineSpacing * 2;
  96.     ShowMessage('Double Line Space:' + #13 +
  97.                 'SelStart = ' + IntToStr(SelStart) + #13 +
  98.                 'SelLength = ' + IntToStr(SelLength) + #13 +
  99.                 'LineSpacing = ' + FloatToStr(ParagraphMetric.LineSpacing));
  100.     {
  101.       The use of SetParaMetric or SetRangeParaParams works both well
  102.       in Windows, but not in Linux.
  103.     }
  104.     SetParaMetric(SelStart, SelLength, ParagraphMetric);
  105.     //SetRangeParaParams(SelStart, SelLength, [pmm_LineSpacing], ParagraphMetric);
  106.   end;
  107. end;
  108.  
  109. end.
  110.  

Thanks in advance for your comments.
--------------------------
Lazarus 3.0 (rev lazarus_3_0) FPC 3.2.2 x86_64-linux-gtk2
Now I know you never know, but at least I know this. - Jean Gabin

Thaddy

  • Hero Member
  • *****
  • Posts: 19129
  • Glad to be alive.
Re: RichMemo LineSpacing does not work in Linux?
« Reply #1 on: January 23, 2024, 03:39:28 pm »
 :'(Change #13 to LineSpacing,  or sLinebreak which is a default constant per platform.  Under windows it is #13#10, under linux it is just #10.
« Last Edit: January 23, 2024, 03:48:35 pm by Thaddy »
objects are fine constructs. You can even initialize them with constructors.

paxnet_be

  • New Member
  • *
  • Posts: 25
Re: RichMemo LineSpacing does not work in Linux?
« Reply #2 on: January 23, 2024, 03:56:48 pm »
Sorry Thaddy, I was meaning the vertical line spacing, not the horizontal. #13 is just for ShowMessage, but you are write about it.
Now I know you never know, but at least I know this. - Jean Gabin

rvk

  • Hero Member
  • *****
  • Posts: 7014
Re: RichMemo LineSpacing does not work in Linux?
« Reply #3 on: January 23, 2024, 06:14:57 pm »
:'(Change #13 to LineSpacing,  or sLinebreak which is a default constant per platform.  Under windows it is #13#10, under linux it is just #10.
You are correct for the #13, but you might have missed that this is only used for the ShowMessage, NOT for the RichMemo itself.

@paxnet_be
The linespacing is done correctly WITHIN the paragraph on Linux/TRichMemo. But when using linebreak (enter) you begin a new paragraph. If you, for example, type a very long line and let it wrap a few times, then select that text/paragraph and press your button, you'll see the linespacing change. So the TRichMemo interprets the linespacing different for Windows vs Linux (because there it's for every linebreak including inside a paragraph).

(You could try to play with ParagraphMetric.SpaceBefore but you'll need to set that per paragraph, you can't do that for a selection and have it be for every line.)

paxnet_be

  • New Member
  • *
  • Posts: 25
Re: RichMemo LineSpacing does not work in Linux?
« Reply #4 on: January 24, 2024, 06:52:42 am »
Thank you, RVK, I tried with word wrapping, and indeed it works that way.
So the different interpretation in Windows and Linux is what I missed. Case resolved.  :)
Now I have to figure out, how I could apply it with several paragraphs.  ::)
Now I know you never know, but at least I know this. - Jean Gabin

rvk

  • Hero Member
  • *****
  • Posts: 7014
Re: RichMemo LineSpacing does not work in Linux?
« Reply #5 on: January 24, 2024, 09:29:45 am »
Now I have to figure out, how I could apply it with several paragraphs.  ::)
Actually, setting ParagraphMetric.SpaceBefore := 15 * DefLineSpacing did apply to all paragraphs for me (selecting multiple lines/paragraphs).

(I used 15 as an example for fontpixelsize which is used in setting ParagraphMetric.LineSpacing)

But when setting it back to 0 it somehow switched the SpaceBefore to SpaceAfter.
Not sure why, could be due to the GetParaMetric at SelStart.
(Doing it multiple times it did get back to 0  %) )

The relevant code for setting the paragraph in Linux is:
Code: Pascal  [Select][+][-]
  1.   tag := gtk_text_buffer_create_tag (buffer, nil,
  2.       'pixels-above-lines',   [ gint(round(AMetric.SpaceBefore*DPIFactor)),
  3.       'pixels-above-lines-set', gboolean(gTRUE),
  4.       'pixels-below-lines',     gint(round(AMetric.SpaceAfter*DPIFactor)),
  5.       'pixels-below-lines-set', gboolean(gTRUE),
  6.       'left-margin',            gint(round(h*DPIFactor)),
  7.       'left-margin-set',        gboolean(gTRUE),
  8.       'right-margin',           gint(round(AMetric.TailIndent*DPIFactor)),
  9.       'right-margin-set',       gboolean(gTRUE),
  10.       'indent',                 gint(round(fl*DPIFactor)),
  11.       'indent-set',             gboolean(gTRUE),
  12.       'pixels-inside-wrap',     gint((round(fp.Size*(AMetric.LineSpacing-DefLineSpacing)*DPIFactor))),
  13.       'pixels-inside_wrap-set', gboolean(gTRUE),
  14.       nil]);
You can find documentation for gtktexttag everywhere. http://irtfweb.ifa.hawaii.edu/SoftwareDocs/gtk20/gtk/gtktexttag.html

See the fp.Size* in pixels-inside-wrap but not in pixels-above-lines. So SpaceBefore and SpaceAfter are in pixels. You need to multiply them with the DefLineSpacing * FontPixelHeight.

Further... for Linux you need to apply both the SpaceBefore (for the paragraph) AND LineSpacing (for inside the paragraph) to get what you want, where on Windows just LineSpacing would suffice (so you need to work with {$IFDEF LINUX} for that).

Happy coding  :D

paxnet_be

  • New Member
  • *
  • Posts: 25
Re: RichMemo LineSpacing does not work in Linux?
« Reply #6 on: February 14, 2024, 05:10:41 pm »
Thanks to you RVK, for the GTK-tips.

Before I was able to apply them, I had to teach myself a little bit about GTK. After searching for information, I found a GTK manual for Free Pascal at:

  https://www.mimuw.edu.pl/~zbyszek/pgtk/html/contents.html

All examples works with the FP-IDE (some with minor changes), except for the calendar, wich gives GTK-crtical errors, that I was not able to fix with my knowledge as a novice.

Then I applied your tips in my Lazarus program, without success, until ... I copied the values of SelStart and SelLength into a local variable and then passed these to the function SetParaMetric...

Finally, it turned out, that GTK calls are not required in Linux, only (local) variables with the values of SelStart and SelLength are needed. Why I don't know.  %)

Here the working code:  :D

Code: Pascal  [Select][+][-]
  1. unit uLineSpacing;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, Menus,
  9.   RichMemo;
  10.  
  11. type
  12.  
  13.   { TForm1 }
  14.  
  15.   TForm1 = class(TForm)
  16.     Button1: TButton;
  17.     RatioSingle: TMenuItem;
  18.     RatioOneHalf: TMenuItem;
  19.     RatioDouble: TMenuItem;
  20.     PMLineSpacing: TPopupMenu; // PM = PopupMenu
  21.     RichMemo1: TRichMemo;
  22.     procedure Button1Click(Sender: TObject);
  23.     procedure RatioSingleClick(Sender: TObject);
  24.     procedure RatioOneHalfClick(Sender: TObject);
  25.     procedure RatioDoubleClick(Sender: TObject);
  26.   private
  27.     ParagraphMetric: TParaMetric;
  28.   public
  29.  
  30.   end;
  31.  
  32. const
  33.   DPIFactor = 1.3333; // = 96 / 72 (Unit = Pixel / Point)
  34. var
  35.   Form1: TForm1;
  36.   //Tag: PGtkTextTag;
  37.   //Buffer: PGtkTextBuffer;
  38.  
  39. implementation
  40.  
  41. {$R *.lfm}
  42.  
  43. { TForm1 }
  44.  
  45. procedure TForm1.Button1Click(Sender: TObject);
  46. begin
  47.   {
  48.     PopUp menu with 3 items:
  49.     1.0: OnClick --> RatioSingleClick
  50.     1.5: OnClick --> RatioOneHalfClick
  51.     2.0: OnClick --> RatioDoubleClick
  52.   }
  53.   PMLineSpacing.PopUp;
  54. end;
  55.  
  56. procedure TForm1.RatioSingleClick(Sender: TObject);
  57. var
  58.   RMTextStart, RMTextLen: Integer;
  59. begin
  60.   InitParaMetric(ParagraphMetric);
  61.   with RichMemo1 do begin
  62.     GetParaMetric(SelStart, ParagraphMetric);
  63.     {
  64.       The function SetParaMetric does not use the variables
  65.       SelStart and SelLength properly in Linux (why?),
  66.       so we save their values in local variables:
  67.     }
  68.     RMTextStart := SelStart;
  69.     RMTextLen := SelLength;
  70.     ParagraphMetric.LineSpacing := DefLineSpacing; // Single ratio
  71.     ParagraphMetric.SpaceBefore := ParagraphMetric.LineSpacing;
  72.     SetParaMetric(RMTextStart, RMTextLen, ParagraphMetric);
  73.   end;
  74. end;
  75.  
  76. procedure TForm1.RatioOneHalfClick(Sender: TObject);
  77. var
  78.   RMTextStart, RMTextLen: Integer;
  79. begin
  80.   InitParaMetric(ParagraphMetric);
  81.   with RichMemo1 do begin
  82.     GetParaMetric(SelStart, ParagraphMetric);
  83.     {
  84.       The function SetParaMetric does not use the variables
  85.       SelStart and SelLength properly in Linux (why?),
  86.       so we save their values in local variables:
  87.     }
  88.     RMTextStart := SelStart;
  89.     RMTextLen := SelLength;
  90.     ParagraphMetric.LineSpacing := DefLineSpacing * 1.5; // One half ratio
  91.     ParagraphMetric.SpaceBefore := ParagraphMetric.LineSpacing * 2;
  92.     SetParaMetric(RMTextStart, RMTextLen, ParagraphMetric);
  93.   end;
  94. end;
  95.  
  96. procedure TForm1.RatioDoubleClick(Sender: TObject);
  97. var
  98.   RMTextStart, RMTextLen: Integer;
  99. begin
  100.   InitParaMetric(ParagraphMetric);
  101.   with RichMemo1 do begin
  102.     GetParaMetric(SelStart, ParagraphMetric);
  103.     {
  104.       The function SetParaMetric does not use the variables
  105.       SelStart and SelLength properly in Linux (why?),
  106.       so we save their values in local variables:
  107.     }
  108.     RMTextStart := SelStart;
  109.     RMTextLen := SelLength;
  110.     ParagraphMetric.LineSpacing := DefLineSpacing * 2; // Double ratio
  111.     ParagraphMetric.SpaceBefore := ParagraphMetric.LineSpacing * 4;
  112.     SetParaMetric(RMTextStart, RMTextLen, ParagraphMetric);
  113.   end;
  114. end;
  115.  
  116. end.
  117.  

Cheers!
Pax_Be
Now I know you never know, but at least I know this. - Jean Gabin

 

TinyPortal © 2005-2018