SynEdit OnPaintTransientDemo

1.2k views Asked by At

I'm working with Delphi 2007 and SynEdit component.

I'm the main developer of an open source editor (Tinn-R) and I'm trying to switch from the SynEdit ANSI to UNICODE.

After some months of work everything is working fine except OnPaintTransient procedure.

To try to discover the source of the problem I have tried the original demo OnPaintTransientDemo. This works perfectly in the latest ANSI version of SynEdit. However, I'm not getting the same result with the latest UNICODE version.

if the instruction occupies only one line, only one symbol "[] {} or ()" near at the cursor is mistakenly highlighted, which closes not.

In other words, when you click on the first bracket "(" the last bracket ")" doesn't change color. It should color the start and end tag. For example, considering "|" as the cursor position:

(|aaaa) -> only ( is highlighted
(aaaa|) -> only ) is highlighted

However, if the symbols are in different lines both are correctly highlighted:

(|a
a
a
a) -> both () are highlighted

(a
a
a
a|) -> both () are highlighted

This is looking like a bug in the sources of the component!
(Doing debug I could not find the source of the bug.)

Anyone can help please?

2

There are 2 answers

0
jcfaria On BEST ANSWER

The code below (IceMan is the original author) works fine for me:

procedure TForm1.EditorPaintTransient(Sender: TObject; Canvas: TCanvas; TransientType: TTransientType);
var
  Editor: TSynEdit;
  OpenChars: array of WideChar;//[0..2] of WideChar=();
  CloseChars: array of WideChar;//[0..2] of WideChar=();
  Attri: TSynHighlighterAttributes;

function IsCharBracket(AChar: WideChar): Boolean;
begin
  case AChar of
    '{',
    '[',
    '(',
    '<',
    '}',
    ']',
    ')',
    '>':
    Result:= True;
  else
    Result:= False;
  end;
end;

function CharToPixels(P: TBufferCoord): TPoint;
begin
  Result:=Editor.RowColumnToPixels(Editor.BufferToDisplayPos(P));
end;

procedure SetCanvasStyle;
begin
  Editor.Canvas.Brush.Style:= bsSolid; //Clear;
  Editor.Canvas.Font.Assign(Editor.Font);
  Editor.Canvas.Font.Style:= Attri.Style;
  if (TransientType = ttAfter) then begin
    Editor.Canvas.Font.Color:= FBracketFG;
    Editor.Canvas.Brush.Color:= FBracketBG;
  end
  else begin
    Editor.Canvas.Font.Color:= Attri.Foreground;
    Editor.Canvas.Brush.Color:= Attri.Background;
  end;

  if (Editor.Canvas.Font.Color = clNone) then
    Editor.Canvas.Font.Color:= Editor.Font.Color;
  if (Editor.Canvas.Brush.Color = clNone) then
    Editor.Canvas.Brush.Color:= Editor.Color;
end;

var
P  : TBufferCoord;
Pix: TPoint;
D  : TDisplayCoord;
S  : WideString;
I,
 ArrayLength,
 start: Integer;
TmpCharA,
 TmpCharB: WideChar;

begin
  try
    // if Memo1.InReplaceStatus = False then
    // begin
    (*
    if fMain.SyntaxHEnabled = False then exit;
    if Memo1.Highlighter = nil then exit;
    if fMain.BracketMatching = False then exit;
    if TSynEdit(Sender).SelAvail then exit;
    *)
    Editor:= TSynEdit(Sender);
    ArrayLength:= 3;
    (*
    if (Editor.Highlighter = SynHTMLSyn1) or (Editor.Highlighter = SynXMLSyn1) then
    inc(ArrayLength);
    *)
    SetLength(OpenChars,
              ArrayLength);
    SetLength(CloseChars,
              ArrayLength);

    for i:= 0 to ArrayLength - 1 do
      Case i of
        0: begin
             OpenChars[i]:= '(';
             CloseChars[i]:= ')';
           end;
        1: begin
             OpenChars[i]:= '{';
             CloseChars[i]:= '}';
           end;
        2: begin
             OpenChars[i]:= '[';
             CloseChars[i]:= ']';
           end;
        3: begin
             OpenChars[i]:= '<';
             CloseChars[i]:= '>';
           end;
      end;

    P:= Editor.CaretXY;
    D:= Editor.DisplayXY;
    Start:= Editor.SelStart;

    if (Start > 0) and
       (Start <= length(Editor.Text)) then
      TmpCharA:= Editor.Text[Start]
    else
      TmpCharA:= #0;

    if (Start < length(Editor.Text)) then
      TmpCharB:= Editor.Text[Start + 1]
    else
      TmpCharB:= #0;

    if not IsCharBracket(TmpCharA) and
       not IsCharBracket(TmpCharB) then
      Exit;

    S:= TmpCharB;
    if not IsCharBracket(TmpCharB) then begin
      P.Char:= P.Char - 1;
      S:= TmpCharA;
    end;

    Editor.GetHighlighterAttriAtRowCol(P,
                                       S,
                                       Attri);

    if (Editor.Highlighter.SymbolAttribute = Attri) then begin
      for i:= low(OpenChars) to High(OpenChars) do begin
        if (S = OpenChars[i]) or
           (S = CloseChars[i]) then begin
          Pix:= CharToPixels(P);
          SetCanvasStyle;
          Editor.Canvas.TextOut(Pix.X,
                                Pix.Y,
                                S);
          P := Editor.GetMatchingBracketEx(P);

          if (P.Char > 0) and
             (P.Line > 0) then begin
            Pix:= CharToPixels(P);
            if Pix.X > Editor.Gutter.Width then begin
              SetCanvasStyle;
              if S = OpenChars[i] then
                Editor.Canvas.TextOut(Pix.X,
                                      Pix.Y,
                                      CloseChars[i])
              else
                Editor.Canvas.TextOut(Pix.X,
                                      Pix.Y,
                                      OpenChars[i]);
            end; //if Pix.X >
          end; //if (P.Char > 0)
        end; //if (S = OpenChars[i])
      end; //for i:= low(OpenChars)
      Editor.Canvas.Brush.Style := bsSolid;
    end; //if (Editor.Highlighter.SymbolAttribute = Attri)
  except
  // TODO
  end; //try
end;
0
Robbie Matthews On

CharToPixels messes with the font color, I found. Setting font.color back to FBrackBG just before drawing seems to work.