Recent

Author Topic: Customize lines coloration with TSynEdit  (Read 7475 times)

StreamerTeam

  • New member
  • *
  • Posts: 7
Customize lines coloration with TSynEdit
« on: November 25, 2016, 04:43:47 pm »
Hello dear every developers!

I am new in this forum, so this is my first question.

I use TSynEdit component to replace my very old TRichEdit component.
I want to apply specific colorations for each line of the edited file in the component but I can not find solution. I try the event OnSpecialLineColors but the entire line is colorized...
example:
a line without color
CQUAD4   3271227 335196  3271020 3271151 3270225 3271152 325001  0.
and I want to color the line like in the attached file

How can I make it possible?

StreamerTeam

Best regards

Sorry for my bad English.

Edson

  • Hero Member
  • *****
  • Posts: 1044
Re: Customize lines coloration with TSynEdit
« Reply #1 on: November 25, 2016, 05:45:58 pm »
Wellcome to the forum.

TSynEdit manages the text-highlighting (coloration) in a different way from TRichEdit.

There are, basically, 2 ways you can get the coloration:

1. Using Markups.
2. Using Highlighters.

Using Markups, you can use some code like this:

Code: Pascal  [Select]
  1. unit Unit1;
  2. {$mode objfpc}{$H+}
  3. interface
  4. uses
  5.   Classes, SysUtils, Forms, Controls, Graphics,
  6.   SynEdit, SynEditMarkupSelection,
  7.   SynEditTypes, SynEditPointClasses, SynEditMarkup;
  8.  
  9. type
  10.   { TMiEditor }
  11.   TMiEditor = class(TSynEdit)
  12.   private
  13.     Bloque1: TSynEditSelection;      
  14.     Markup1: TSynEditMarkupSelection;
  15.  
  16.     Bloque2: TSynEditSelection;      
  17.     Markup2: TSynEditMarkupSelection;
  18.   public
  19.     constructor Create(AOwner: TComponent); override;
  20.     destructor Destroy; override;
  21.   end;
  22.  
  23.   { TForm1 }
  24.   TForm1 = class(TForm)
  25.     procedure FormCreate(Sender: TObject);
  26.     procedure FormDestroy(Sender: TObject);
  27.   private
  28.     MiEditor: TMiEditor;
  29.   end;
  30.  
  31. var
  32.   Form1: TForm1;
  33.  
  34. implementation
  35. { TMiEditor }
  36. constructor TMiEditor.Create(AOwner: TComponent);
  37. var
  38.   MarkupManager: TSynEditMarkupManager;
  39. begin
  40.   inherited Create(AOwner);
  41.   MarkupManager := TSynEditMarkupManager(MarkupMgr);  
  42.   //create block to mark
  43.   Bloque1 := TSynEditSelection.Create(ViewedTextBuffer, false);
  44.   Bloque1.InvalidateLinesMethod := @InvalidateLines;
  45.   Markup1 := TSynEditMarkupSelection.Create(self, Bloque1);
  46.   MarkupManager.AddMarkUp(Markup1);
  47.   //create block to mark
  48.   Bloque2 := TSynEditSelection.Create(ViewedTextBuffer, false);
  49.   Bloque2.InvalidateLinesMethod := @InvalidateLines;
  50.   Markup2 := TSynEditMarkupSelection.Create(self, Bloque2);
  51.   MarkupManager.AddMarkUp(Markup2);
  52. end;
  53.  
  54. destructor TMiEditor.Destroy;
  55. begin
  56.   Bloque1.Free;    
  57.   Bloque2.Free;    
  58.   inherited Destroy;
  59. end;
  60.  
  61. {$R *.lfm}
  62. { TForm1 }
  63. procedure TForm1.FormCreate(Sender: TObject);
  64. begin
  65.   MiEditor := TMiEditor.Create(self);
  66.   MiEditor.Parent:= self;          
  67.   MiEditor.Align := alClient;      
  68.   //write a text
  69.   MiEditor.Lines.Add('En un lugar de la mancha');
  70.   MiEditor.Lines.Add('de cuyo nombre');
  71.   MiEditor.Lines.Add('No quiero acordarme');
  72.   //define section 1 to mark
  73.   MiEditor.Bloque1.StartLineBytePos := Point(5,1);
  74.   MiEditor.Bloque1.EndLineBytePos := Point(8,1);
  75.   MiEditor.Markup1.Enabled := True;
  76.   MiEditor.Markup1.MarkupInfo.FrameColor := clRed;
  77.  
  78.   //define section 2 to mark
  79.   MiEditor.Bloque2.StartLineBytePos := Point(8,3);
  80.   MiEditor.Bloque2.EndLineBytePos := Point(13,3);
  81.   MiEditor.Markup2.Enabled := True;
  82.   MiEditor.Markup2.MarkupInfo.FrameColor := clRed;
  83. end;
  84.  
  85. procedure TForm1.FormDestroy(Sender: TObject);
  86. begin
  87.   MiEditor.Destroy;
  88. end;
  89. end.
  90.  

For Highlighters, I recommend to check the Lazarus Example Project: SynPositionHighlighter

« Last Edit: November 25, 2016, 05:55:53 pm by Edson »
Lazarus 1.6 - FPC 3.0.0 - x86_64-win64 on  Windows 7

howardpc

  • Hero Member
  • *****
  • Posts: 3158
Re: Customize lines coloration with TSynEdit
« Reply #2 on: November 25, 2016, 08:44:18 pm »
Edson, if you have time it would be good to add a section to the wiki synedit page about markup (as opposed to highlighters), and your example would be good code to attach.

Edson

  • Hero Member
  • *****
  • Posts: 1044
Re: Customize lines coloration with TSynEdit
« Reply #3 on: November 26, 2016, 04:02:55 am »
Yes, I will find some time to update the SynEdit wiki. I have made many additions to the Spanish version of the SynEdit wiki :), but not the English version.

This example is from my book: "La Biblia del SynEdit" - Section 1.8 (http://forum.lazarus.freepascal.org/index.php/topic,22320.msg197128.html#msg197128) only in spanish by now  :(.
Lazarus 1.6 - FPC 3.0.0 - x86_64-win64 on  Windows 7

StreamerTeam

  • New member
  • *
  • Posts: 7
Re: Customize lines coloration with TSynEdit
« Reply #4 on: November 26, 2016, 10:23:32 am »
Hi,

Thanks you very much for the answer.

But I am confused. I am an Embarcadero RAD Studio XE 10.1 user and the version of SynEdit (1.1) provided by my compiler do not contain these options.

Where can I find a complete version of SynEdit components?

Best regards.


Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 5638
    • wiki
Re: Customize lines coloration with TSynEdit
« Reply #5 on: November 27, 2016, 12:11:10 am »
The SynEdit that comes with Lazarus was forked a decade ago, and has many differences.

You might have (or be able to find on the net) a version of SynPosSyn. (SynPosition Highlighter).





StreamerTeam

  • New member
  • *
  • Posts: 7
Re: Customize lines coloration with TSynEdit
« Reply #6 on: November 27, 2016, 02:08:31 pm »
Thanks you dear Martin

I will investigate for these components.

Before writing this topic, I have tried to implement a custom syntax which could realize the desired highlighting.
Do you think that is possible to create an attri that highlight each line of my text file according to the rule that I show in the picture sent before?

It is simple.
Each line contains 80 caracters, I want to alternate color background each 8 caracters.
The comments lines are correctly detected, each special words are correctly highlighted, but I can not find the way to alternate color.

Best regards.

Edson

  • Hero Member
  • *****
  • Posts: 1044
Re: Customize lines coloration with TSynEdit
« Reply #7 on: November 27, 2016, 04:52:00 pm »
The next highlighter alternate the colors of every lines:

Code: Pascal  [Select]
  1. unit uSintax; {$mode objfpc}{$H+}
  2. interface
  3. uses
  4.   Classes, SysUtils, Graphics, SynEditHighlighter;
  5. type
  6.   {Clase para la creación de un resaltador}
  7.  
  8.   //ID para categorizar a los tokens
  9.   TtkTokenKind = (tkComment, tkKey, tkNull, tkNumber, tkSpace, tkString, tkUnknown);
  10.  
  11.   TProcTableProc = procedure of object; //Tipo procedimiento para procesar el
  12.                                         //token por el carácter inicial.
  13.   { TSynMiColor }
  14.   TSynMiColor = class(TSynCustomHighlighter)
  15.   protected
  16.     posIni, posFin: Integer;
  17.     linAct   : PChar;
  18.     fProcTable: array[#0..#255] of TProcTableProc;   //tabla de procedimientos
  19.     fTokenID : TtkTokenKind;  //Id del token actual
  20.     //define las categorías de los "tokens"
  21.     fAtriComent  : TSynHighlighterAttributes;
  22.     fAtriClave   : TSynHighlighterAttributes;
  23.     fAtriNumero  : TSynHighlighterAttributes;
  24.     fAtriEspac   : TSynHighlighterAttributes;
  25.     fAtriCadena  : TSynHighlighterAttributes;
  26.   public
  27.     procedure SetLine(const NewValue: String; LineNumber: Integer); override;
  28.     procedure Next; override;
  29.     function  GetEol: Boolean; override;
  30.     procedure GetTokenEx(out TokenStart: PChar; out TokenLength: integer);
  31.               override;
  32.     function  GetTokenAttribute: TSynHighlighterAttributes; override;
  33.   public
  34.     function GetToken: String; override;
  35.     function GetTokenPos: Integer; override;
  36.     function GetTokenKind: integer; override;
  37.     constructor Create(AOwner: TComponent); override;
  38.   end;
  39.  
  40. implementation
  41.  
  42. constructor TSynMiColor.Create(AOwner: TComponent);
  43. //Constructor de la clase. Aquí se deben crear los atributos a usar.
  44. begin
  45.   inherited Create(AOwner);
  46.   //atributo de comentarios
  47.   fAtriComent  := TSynHighlighterAttributes.Create('Comment');
  48.   fAtriComent.Style := [fsItalic];     //en cursiva
  49.   fAtriComent.Foreground := clGray;    //color de letra gris
  50.   AddAttribute(fAtriComent);
  51.   //atribuuto de palabras claves
  52.   fAtriClave   := TSynHighlighterAttributes.Create('Key');
  53.   fAtriClave.Style := [fsBold];       //en negrita
  54.   fAtriClave.Foreground:=clGreen;     //color de letra verde
  55.   AddAttribute(fAtriClave);
  56.   //atributo de números
  57.   fAtriNumero  := TSynHighlighterAttributes.Create('Number');
  58.   fAtriNumero.Foreground := clFuchsia;
  59.   AddAttribute(fAtriNumero);
  60.   //atributo de espacios. Sin atributos
  61.   fAtriEspac   := TSynHighlighterAttributes.Create('space');
  62.   AddAttribute(fAtriEspac);
  63.   //atributo de cadenas
  64.   fAtriCadena  := TSynHighlighterAttributes.Create('String');
  65.   fAtriCadena.Foreground := clBlue;   //color de letra azul
  66.   AddAttribute(fAtriCadena);
  67.  
  68. end;
  69.  
  70. procedure TSynMiColor.SetLine(const NewValue: String; LineNumber: Integer);
  71. {Es llamado por el editor, cada vez que necesita actualizar la información de
  72.  coloreado sobre una línea. Despues de llamar a esta función, se espera que
  73.  GetTokenEx, devuelva el token actual. Y también después de cada llamada a
  74.  "Next".}
  75. begin
  76.   inherited;
  77.   linAct := PChar(NewValue);  //copia la línea actual
  78.   posFin := 0;                //apunta al primer caracter
  79.   Next;
  80. end;
  81.  
  82. procedure TSynMiColor.Next;
  83. //Es llamado por SynEdit, para acceder al siguiente Token.
  84. begin
  85.   posIni := posFin;           //apunta al siguiente token
  86.   ///////////////////////////////////////
  87.   if linAct[posFin] = #0 then begin
  88.     fTokenID := tkNull;
  89.     exit;
  90.   end;
  91.   posFin := posIni + 8;
  92.   if posFin > length(linAct) then begin
  93.     posFin := length(linAct);
  94.   end;
  95.   if fTokenID = tkKey then fTokenID := tkUnknown else fTokenID := tkKey;
  96.   ////////////////////////////////////////
  97. //  fProcTable[linAct[posFin]]; //Se ejecuta la función que corresponda.
  98. end;
  99.  
  100. function TSynMiColor.GetEol: Boolean;
  101. {Indica cuando se ha llegado al final de la línea}
  102. begin
  103.   Result := fTokenId = tkNull;
  104. end;
  105.  
  106. procedure TSynMiColor.GetTokenEx(out TokenStart: PChar; out TokenLength: integer);
  107. {Devuelve información sobre el token actual}
  108. begin
  109.   TokenLength := posFin - posIni;
  110.   TokenStart := linAct + posIni;
  111. end;
  112.  
  113. function TSynMiColor.GetTokenAttribute: TSynHighlighterAttributes;
  114. //Devuelve información sobre el token actual
  115. begin
  116.   case fTokenID of
  117.     tkComment: Result := fAtriComent;
  118.     tkKey    : Result := fAtriClave;
  119.     tkNumber : Result := fAtriNumero;
  120.     tkSpace  : Result := fAtriEspac;
  121.     tkString : Result := fAtriCadena;
  122.     else Result := nil;  //tkUnknown, tkNull
  123.   end;
  124. end;
  125.  
  126. {Las siguientes funciones, son usadas por SynEdit para el manejo de las
  127.  llaves, corchetes, parentesis y comillas. No son cruciales para el coloreado
  128.  de tokens, pero deben responder bien.}
  129. function TSynMiColor.GetToken: String;
  130. begin
  131.   Result := '';
  132. end;
  133.  
  134. function TSynMiColor.GetTokenPos: Integer;
  135. begin
  136.   Result := posIni - 1;
  137. end;
  138.  
  139. function TSynMiColor.GetTokenKind: integer;
  140. begin
  141.   Result := 0;
  142. end;
  143.  
  144. end.
  145.  

This code was taken from "La Biblia del SynEdit" and adapted.
Lazarus 1.6 - FPC 3.0.0 - x86_64-win64 on  Windows 7

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 5638
    • wiki
Re: Customize lines coloration with TSynEdit
« Reply #8 on: November 27, 2016, 04:52:54 pm »
If you do not need any "language highlight" (such as sql, js, pas.... / like the IDE does highligh keywords)....

So if you do not need that, then you can write your own Highlighter.

For what you describe it should be fairly simple.

-----------------------
There is a tutorial for the highlighter in Lazarus.

Have a look, http://wiki.lazarus.freepascal.org/SynEdit_Highlighter#The_Basics:_Returning_Tokens_and_Attributes

ONLY look at the chapter "The Basics: Returning Tokens and Attributes"
With a bit of luck, this is the same (or very nearly the same) as in your version.

The example source is in the lazarus installation, in the example folder.

Instead of searching for specific tokens (words), you just take the word/text at the position that you want (next column pos).

-----------------------
EDIT
the inheritance of the Lazarus example is probabliy different / and maybe one or to method names.

Open a highlighter (find a simple one TSynAnySyn, if you have) from your SynEdit and compare the class declaration.

« Last Edit: November 27, 2016, 04:55:19 pm by Martin_fr »

StreamerTeam

  • New member
  • *
  • Posts: 7
Re: Customize lines coloration with TSynEdit
« Reply #9 on: November 27, 2016, 05:40:49 pm »
Thanks you for the reply Martin_fr and Edson.

Indeed, the behaviour that I want is very simple and Synedit seems to be the most effective solution compared to our old source used with the TRichEdit.
I suspected that the function Next was the solution.
This afternoon, I compared the two versions of SynEdit (Lazarus SynEdit vs SynEdit 1.1 for Embarcadero).
Indeed, the sources code are very similar except some advanced function from Lazarus like GetTokenEx...

I will apply this solution tomorrow and keep you informed.

For the future, can I create my own SynEdit package for embarcadero with sources from Lazarus?

Best regards

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 5638
    • wiki
Re: Customize lines coloration with TSynEdit
« Reply #10 on: November 27, 2016, 07:56:17 pm »
Lazarus Synedit has the same license as the original (MPL, or at the users choice GPL)

So yes you can use it.
You may have to do some changes though, as delphi may not compile it (there are some differences in the compiler).

Afaik, if you modify it AND publish your app (that contains the modified version), then you must also make the modified source available.  (not sure if the MPL requires this, you may wish to check)

StreamerTeam

  • New member
  • *
  • Posts: 7
Re: Customize lines coloration with TSynEdit
« Reply #11 on: December 02, 2016, 12:00:29 pm »
Hi dear developers,

I come back to you to describe my progress. I realize the custom syntax as I want... not without difficulty.
Some strange characters appeared  :o but I managed to remove them  %) and I am not comfortable in Delphi.

I have a new question now. I have defined new tokens attributes but I can not access it in my main program (a program developed in C++)  although I have defined properties in the definition of my class

  published
    property PairFieldAttri: TSynHighlighterAttributes read fPairFieldAttri write fPairFieldAttri;
    property ImpairFieldAttri: TSynHighlighterAttributes read fImpairFieldAttri write fImpairFieldAttri;

Did I miss something?

Best regards.

EDIT: I found the problem. I tried to get the attribute by the wrong way.
SynEdit1->Highligther->PairFieldAttri
The good way is SynNastranSyn1->PairFieldAttri
 :P

« Last Edit: December 02, 2016, 12:11:51 pm by StreamerTeam »

StreamerTeam

  • New member
  • *
  • Posts: 7
Re: Customize lines coloration with TSynEdit
« Reply #12 on: January 17, 2017, 10:59:48 am »
Hello dear developers,

I am so impressed by the performance of the component SynEdit so I want to add a new option in my text editor.

It is possible to realize a fade effect on the text?
The selected line must be white or no color and previous and following lines begin more and more dark until dark grey.

I first try to use SpecialLinesColor but color gradient is not easy to code.

Do you know a way to do that please?

Best regards and happy new year

StreamerTeam

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 5638
    • wiki
Re: Customize lines coloration with TSynEdit
« Reply #13 on: January 17, 2017, 01:25:31 pm »
OnSpecialLine is the easiest/fastest way do to this.

If you want your code to be more re-usable then write your own TSynEditMarkup
But that is all the same steps, plus added work.

In either case your code is called, inside the paint event.
That means it can be called often, and your code should be fast.

So in either case pre-calculate the colors, (if they need to change on caret move, then hook OnStatusChanged / RegisterStatusChangedHandler).
In the paint event just return the already known color.

StreamerTeam

  • New member
  • *
  • Posts: 7
Re: Customize lines coloration with TSynEdit
« Reply #14 on: January 17, 2017, 02:06:28 pm »
Thanks Martin,

Indeed, the speciallinescolor event is very faster (my text file contains more than 1 million of line). I was a little scared about the performance.
I will use a function to convert RGB color to hexa to calculate grey nuances. It will make illusion of a fade effect.

I will show my code after develop it.