mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-05 10:57:55 +02:00
195 lines
5.8 KiB
ObjectPascal
195 lines
5.8 KiB
ObjectPascal
{-------------------------------------------------------------------------------
|
|
The contents of this file are subject to the Mozilla Public License
|
|
Version 1.1 (the "License"); you may not use this file except in compliance
|
|
with the License. You may obtain a copy of the License at
|
|
http://www.mozilla.org/MPL/
|
|
|
|
Software distributed under the License is distributed on an "AS IS" basis,
|
|
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
|
|
the specific language governing rights and limitations under the License.
|
|
|
|
Alternatively, the contents of this file may be used under the terms of the
|
|
GNU General Public License Version 2 or later (the "GPL"), in which case
|
|
the provisions of the GPL are applicable instead of those above.
|
|
If you wish to allow use of your version of this file only under the terms
|
|
of the GPL and not to allow others to use your version of this file
|
|
under the MPL, indicate your decision by deleting the provisions above and
|
|
replace them with the notice and other provisions required by the GPL.
|
|
If you do not delete the provisions above, a recipient may use your version
|
|
of this file under either the MPL or the GPL.
|
|
|
|
-------------------------------------------------------------------------------}
|
|
unit SynEditMarkupGutterMark;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils, Graphics, Controls,
|
|
SynEditMarkup, SynEditMiscClasses, SynEditMarks;
|
|
|
|
type
|
|
|
|
TMarkSection = record
|
|
StartX, EndX: Integer; // Physical
|
|
Priority: Integer;
|
|
Markup: TSynSelectedColor;
|
|
end;
|
|
PMarkSection = ^TMarkSection;
|
|
|
|
{ TSynEditMarkupMark }
|
|
|
|
TSynEditMarkupMark = class(TSynEditMark)
|
|
private
|
|
FSourceMarkup: TSynSelectedColor;
|
|
public
|
|
property SourceMarkup: TSynSelectedColor read FSourceMarkup write FSourceMarkup;
|
|
end;
|
|
|
|
|
|
{ TSynEditMarkupGutterMark }
|
|
|
|
TSynEditMarkupGutterMark = class(TSynEditMarkup)
|
|
// TODO: subscribe to mark changes for line invalidation => currently done by synedit itself
|
|
private
|
|
FRowData: Array of TMarkSection;
|
|
FWordBreaker: TSynWordBreaker;
|
|
protected
|
|
procedure DoMarkupChanged(AMarkup: TSynSelectedColor); override;
|
|
public
|
|
constructor Create(ASynEdit: TSynEditBase; AWordBreaker: TSynWordBreaker);
|
|
|
|
procedure PrepareMarkupForRow(ARow: Integer); override;
|
|
function GetMarkupAttributeAtRowCol(const aRow: Integer;
|
|
const aStartCol: TLazSynDisplayTokenBound;
|
|
const AnRtlInfo: TLazSynDisplayRtlInfo): TSynSelectedColor; override;
|
|
procedure GetNextMarkupColAfterRowCol(const aRow: Integer;
|
|
const aStartCol: TLazSynDisplayTokenBound;
|
|
const AnRtlInfo: TLazSynDisplayRtlInfo;
|
|
out ANextPhys, ANextLog: Integer); override;
|
|
end;
|
|
|
|
implementation
|
|
|
|
{ TSynEditMarkupGutterMark }
|
|
|
|
procedure TSynEditMarkupGutterMark.DoMarkupChanged(AMarkup: TSynSelectedColor);
|
|
begin
|
|
inherited DoMarkupChanged(AMarkup);
|
|
SynEdit.Invalidate;
|
|
end;
|
|
|
|
constructor TSynEditMarkupGutterMark.Create(ASynEdit: TSynEditBase;
|
|
AWordBreaker: TSynWordBreaker);
|
|
begin
|
|
FWordBreaker := AWordBreaker;
|
|
inherited Create(ASynEdit);
|
|
end;
|
|
|
|
procedure TSynEditMarkupGutterMark.PrepareMarkupForRow(ARow: Integer);
|
|
var
|
|
MLine: TSynEditMarkLine;
|
|
i, j: Integer;
|
|
s: string;
|
|
Markup: TSynEditMarkupMark;
|
|
Section: PMarkSection;
|
|
x: Integer;
|
|
begin
|
|
MLine := (SynEdit.Marks as TSynEditMarkList).Line[ARow];
|
|
if MLine = nil then begin
|
|
SetLength(FRowData, 0);
|
|
exit;
|
|
end;
|
|
SetLength(FRowData, MLine.Count);
|
|
|
|
j := 0;
|
|
s := '';
|
|
for i := 0 to MLine.Count - 1 do begin
|
|
if not (MLine[i] is TSynEditMarkupMark) then
|
|
continue;
|
|
Markup:=TSynEditMarkupMark(MLine[i]);
|
|
if Markup.SourceMarkup = nil then
|
|
continue;
|
|
|
|
Section := @FRowData[j];
|
|
Section^.Markup := Markup.SourceMarkup;
|
|
Section^.Priority := Markup.Priority;
|
|
|
|
if s='' then
|
|
s := Lines[ARow-1];
|
|
if s='' then break;
|
|
|
|
x := FWordBreaker.PrevBoundary(s, Markup.Column, True);
|
|
if x < 1 then
|
|
x := 1;
|
|
Section^.StartX := Point(x, ARow).x;
|
|
|
|
x := FWordBreaker.NextBoundary(s, Markup.Column);
|
|
if x < 1 then
|
|
x := length(s) + 1;
|
|
Section^.EndX := Point(x, ARow).x;
|
|
|
|
if (Section^.StartX > 0) and (Section^.EndX > 0) and (Section^.StartX<Section^.EndX)
|
|
then
|
|
inc(j);
|
|
end;
|
|
|
|
SetLength(FRowData, j);
|
|
end;
|
|
|
|
function TSynEditMarkupGutterMark.GetMarkupAttributeAtRowCol(const aRow: Integer;
|
|
const aStartCol: TLazSynDisplayTokenBound; const AnRtlInfo: TLazSynDisplayRtlInfo): TSynSelectedColor;
|
|
var
|
|
i, FoundPri: Integer;
|
|
Section: PMarkSection;
|
|
begin
|
|
FoundPri := 0;
|
|
Result := nil;
|
|
for i := 0 to length(FRowData) - 1 do begin
|
|
Section := @FRowData[i];
|
|
if (Section^.StartX <= aStartCol.Logical) and (Section^.EndX > aStartCol.Logical) and
|
|
( (Section^.Priority < FoundPri) or (Result=nil) )
|
|
then begin
|
|
Result := Section^.Markup;
|
|
MarkupInfo.SetFrameBoundsLog(Section^.StartX, Section^.EndX);
|
|
FoundPri := Section^.Priority;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TSynEditMarkupGutterMark.GetNextMarkupColAfterRowCol(const aRow: Integer;
|
|
const aStartCol: TLazSynDisplayTokenBound; const AnRtlInfo: TLazSynDisplayRtlInfo; out ANextPhys,
|
|
ANextLog: Integer);
|
|
// return the next StartX or EndX after aStartCol
|
|
|
|
procedure Improve(Col: integer); inline;
|
|
begin
|
|
if Col <= aStartCol.Logical then exit;
|
|
if Col > ANextLog then exit;
|
|
ANextLog:=Col;
|
|
end;
|
|
|
|
var
|
|
i: Integer;
|
|
Section: PMarkSection;
|
|
begin
|
|
ANextPhys := -1;
|
|
if length(FRowData) = 0 then
|
|
begin
|
|
ANextLog := -1;
|
|
exit;
|
|
end;
|
|
ANextLog := High(ANextLog);
|
|
for i := 0 to length(FRowData) - 1 do begin
|
|
Section := @FRowData[i];
|
|
Improve(Section^.StartX);
|
|
Improve(Section^.EndX);
|
|
end;
|
|
if ANextLog = High(ANextLog) then
|
|
ANextLog := -1;
|
|
end;
|
|
|
|
end.
|
|
|