mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-05-24 01:03:56 +02:00
570 lines
16 KiB
ObjectPascal
570 lines
16 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.
|
|
|
|
The Original Code is: SynEditMiscClasses.pas, released 2000-04-07.
|
|
The Original Code is based on the mwSupportClasses.pas file from the
|
|
mwEdit component suite by Martin Waldenburg and other developers, the Initial
|
|
Author of this file is Michael Hieke.
|
|
All Rights Reserved.
|
|
|
|
Contributors to the SynEdit and mwEdit projects are listed in the
|
|
Contributors.txt file.
|
|
|
|
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.
|
|
|
|
$Id$
|
|
|
|
You may retrieve the latest version of this file at the SynEdit home page,
|
|
located at http://SynEdit.SourceForge.net
|
|
|
|
Known Issues:
|
|
-------------------------------------------------------------------------------}
|
|
|
|
unit SynEditMiscClasses;
|
|
|
|
{$I synedit.inc}
|
|
|
|
interface
|
|
|
|
uses
|
|
{$IFDEF SYN_LAZARUS}
|
|
LCLIntf, LCLType, LCLProc,
|
|
{$ELSE}
|
|
Windows,
|
|
{$ENDIF}
|
|
Classes, Graphics, Controls, SysUtils, SynEditTypes;
|
|
|
|
type
|
|
|
|
// Empty - For type checking on function-arguments
|
|
// in places where TCustomSynEdit can not be used due to circular unit refs
|
|
TSynEditBase = class(TCustomControl)
|
|
protected
|
|
function GetTheLinesView: TStrings; virtual; abstract;
|
|
procedure SetRealLines(const AValue : TStrings); virtual; abstract;
|
|
function GetLines: TStrings; virtual; abstract;
|
|
procedure SetLines(Value: TStrings); virtual; abstract;
|
|
public
|
|
property RealLines: TStrings read GetTheLinesView write SetRealLines; // As viewed internally (with uncommited spaces / TODO: expanded tabs, folds). This may change, use with care
|
|
property Lines: TStrings read GetLines write SetLines; // No uncommited (trailing/trimmable) spaces
|
|
end;
|
|
|
|
{ TSynSelectedColor }
|
|
|
|
TSynSelectedColor = class(TPersistent)
|
|
private
|
|
FBG: TColor;
|
|
FFG: TColor;
|
|
FFrameColor: TColor;
|
|
FStyle: TFontStyles;
|
|
// StyleMask = 1 => Copy Style Bits
|
|
// StyleMask = 0 => Invert where Style Bit = 1
|
|
FStyleMask: TFontStyles;
|
|
FOnChange: TNotifyEvent;
|
|
// 0 or -1 start/end before/after line // 1 first char
|
|
FStartX, FEndX: Integer;
|
|
procedure SetBG(Value: TColor);
|
|
procedure SetFG(Value: TColor);
|
|
procedure SetFrameColor(const AValue: TColor);
|
|
procedure SetStyle(const AValue : TFontStyles);
|
|
procedure SetStyleMask(const AValue : TFontStyles);
|
|
procedure DoChange;
|
|
public
|
|
constructor Create;
|
|
procedure Assign(aSource: TPersistent); override;
|
|
procedure Clear;
|
|
function IsEnabled: boolean;
|
|
published
|
|
function GetModifiedStyle(aStyle : TFontStyles): TFontStyles;
|
|
procedure ModifyColors(var AForeground, ABackground, AFrameColor: TColor; var AStyle: TFontStyles);
|
|
property Background: TColor read FBG write SetBG default clHighLight;
|
|
property Foreground: TColor read FFG write SetFG default clHighLightText;
|
|
property FrameColor: TColor read FFrameColor write SetFrameColor default clNone;
|
|
property Style: TFontStyles read FStyle write SetStyle default [];
|
|
property StyleMask: TFontStyles read fStyleMask write SetStyleMask default [];
|
|
property StartX: Integer read FStartX write FStartX;
|
|
property EndX: Integer read FEndX write FEndX;
|
|
property OnChange: TNotifyEvent read fOnChange write fOnChange;
|
|
end;
|
|
|
|
{ TSynBookMarkOpt }
|
|
|
|
TSynBookMarkOpt = class(TPersistent)
|
|
private
|
|
fBookmarkImages: TImageList;
|
|
fDrawBookmarksFirst: boolean; //mh 2000-10-12
|
|
fEnableKeys: Boolean;
|
|
fGlyphsVisible: Boolean;
|
|
fLeftMargin: Integer;
|
|
fOwner: TComponent;
|
|
fXoffset: integer;
|
|
fOnChange: TNotifyEvent;
|
|
procedure SetBookmarkImages(const Value: TImageList);
|
|
procedure SetDrawBookmarksFirst(Value: boolean); //mh 2000-10-12
|
|
procedure SetGlyphsVisible(Value: Boolean);
|
|
procedure SetLeftMargin(Value: Integer);
|
|
procedure SetXOffset(Value: integer);
|
|
public
|
|
constructor Create(AOwner: TComponent);
|
|
published
|
|
property BookmarkImages: TImageList
|
|
read fBookmarkImages write SetBookmarkImages;
|
|
property DrawBookmarksFirst: boolean read fDrawBookmarksFirst //mh 2000-10-12
|
|
write SetDrawBookmarksFirst default True;
|
|
property EnableKeys: Boolean
|
|
read fEnableKeys write fEnableKeys default True;
|
|
property GlyphsVisible: Boolean
|
|
read fGlyphsVisible write SetGlyphsVisible default True;
|
|
property LeftMargin: Integer read fLeftMargin write SetLeftMargin default 2;
|
|
property Xoffset: integer read fXoffset write SetXOffset default 12;
|
|
property OnChange: TNotifyEvent read fOnChange write fOnChange;
|
|
end;
|
|
|
|
{ TSynMethodChain }
|
|
|
|
ESynMethodChain = class(Exception);
|
|
TSynExceptionEvent = procedure (Sender: TObject; E: Exception;
|
|
var DoContinue: Boolean) of object;
|
|
|
|
TSynMethodChain = class
|
|
private
|
|
FNotifyProcs: TList;
|
|
FExceptionHandler: TSynExceptionEvent;
|
|
protected
|
|
procedure DoFire(AEvent: TMethod); virtual; abstract;
|
|
function DoHandleException(E: Exception): Boolean; virtual;
|
|
property ExceptionHandler: TSynExceptionEvent read FExceptionHandler
|
|
write FExceptionHandler;
|
|
public
|
|
constructor Create;
|
|
destructor Destroy; override;
|
|
procedure Add(AEvent: TMethod);
|
|
procedure Remove(AEvent: TMethod);
|
|
procedure Fire;
|
|
end;
|
|
|
|
{ TSynNotifyEventChain }
|
|
|
|
TSynNotifyEventChain = class(TSynMethodChain)
|
|
private
|
|
FSender: TObject;
|
|
protected
|
|
procedure DoFire(AEvent: TMethod); override;
|
|
public
|
|
constructor CreateEx(ASender: TObject);
|
|
procedure Add(AEvent: TNotifyEvent);
|
|
procedure Remove(AEvent: TNotifyEvent);
|
|
property ExceptionHandler;
|
|
property Sender: TObject read FSender write FSender;
|
|
end;
|
|
|
|
{ TSynInternalImage }
|
|
|
|
TSynInternalImage = class(TObject)
|
|
public
|
|
constructor Create(const AName: string; Count: integer);
|
|
destructor Destroy; override;
|
|
procedure DrawMark(ACanvas: TCanvas; Number, X, Y, LineHeight: integer);
|
|
{$IFNDEF SYN_LAZARUS}
|
|
procedure DrawMarkTransparent(ACanvas: TCanvas; Number, X, Y,
|
|
LineHeight: integer; TransparentColor: TColor);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
|
|
{ TSynEditSearchCustom }
|
|
|
|
TSynEditSearchCustom = class(TComponent)
|
|
protected
|
|
function GetPattern: string; virtual; abstract;
|
|
procedure SetPattern(const Value: string); virtual; abstract;
|
|
function GetLength(aIndex: integer): integer; virtual; abstract;
|
|
function GetResult(aIndex: integer): integer; virtual; abstract;
|
|
function GetResultCount: integer; virtual; abstract;
|
|
procedure SetOptions(const Value: TSynSearchOptions); virtual; abstract;
|
|
public
|
|
function FindAll(const NewText: string): integer; virtual; abstract;
|
|
property Pattern: string read GetPattern write SetPattern;
|
|
property ResultCount: integer read GetResultCount;
|
|
property Results[aIndex: integer]: integer read GetResult;
|
|
property Lengths[aIndex: integer]: integer read GetLength;
|
|
property Options: TSynSearchOptions write SetOptions;
|
|
end;
|
|
|
|
implementation
|
|
|
|
uses
|
|
SynEditMiscProcs;
|
|
|
|
{ TSynSelectedColor }
|
|
|
|
constructor TSynSelectedColor.Create;
|
|
begin
|
|
inherited Create;
|
|
fBG := clHighLight;
|
|
fFG := clHighLightText;
|
|
FFrameColor:= clNone;
|
|
end;
|
|
|
|
function TSynSelectedColor.GetModifiedStyle(aStyle : TFontStyles) : TFontStyles;
|
|
begin
|
|
Result := fsXor(aStyle, FStyle * fsNot(FStyleMask)) // Invert Styles
|
|
+ (FStyle*FStyleMask) // Set Styles
|
|
- (fsNot(FStyle)*FStyleMask); // Remove Styles
|
|
end;
|
|
|
|
procedure TSynSelectedColor.ModifyColors(var AForeground, ABackground, AFrameColor: TColor; var AStyle: TFontStyles);
|
|
begin
|
|
if Foreground <> clNone then AForeground := Foreground;
|
|
if Background <> clNone then ABackground := Background;
|
|
if FrameColor <> clNone then AFrameColor := FrameColor;
|
|
AStyle := GetModifiedStyle(AStyle);
|
|
end;
|
|
|
|
procedure TSynSelectedColor.SetBG(Value: TColor);
|
|
begin
|
|
if (FBG <> Value) then
|
|
begin
|
|
FBG := Value;
|
|
DoChange;
|
|
end;
|
|
end;
|
|
|
|
procedure TSynSelectedColor.SetFG(Value: TColor);
|
|
begin
|
|
if (FFG <> Value) then
|
|
begin
|
|
FFG := Value;
|
|
DoChange;
|
|
end;
|
|
end;
|
|
|
|
procedure TSynSelectedColor.SetFrameColor(const AValue: TColor);
|
|
begin
|
|
if FFrameColor <> AValue then
|
|
begin
|
|
FFrameColor := AValue;
|
|
DoChange;
|
|
end;
|
|
end;
|
|
|
|
procedure TSynSelectedColor.SetStyle(const AValue : TFontStyles);
|
|
begin
|
|
if (FStyle <> AValue) then
|
|
begin
|
|
FStyle := AValue;
|
|
DoChange;
|
|
end;
|
|
end;
|
|
|
|
procedure TSynSelectedColor.SetStyleMask(const AValue : TFontStyles);
|
|
begin
|
|
if (FStyleMask <> AValue) then
|
|
begin
|
|
FStyleMask := AValue;
|
|
DoChange;
|
|
end;
|
|
end;
|
|
|
|
procedure TSynSelectedColor.DoChange;
|
|
begin
|
|
if Assigned(FOnChange) then
|
|
OnChange(Self);
|
|
end;
|
|
|
|
procedure TSynSelectedColor.Assign(aSource : TPersistent);
|
|
var
|
|
Source : TSynSelectedColor;
|
|
begin
|
|
if Assigned(aSource) and (aSource is TSynSelectedColor) then
|
|
begin
|
|
Source := TSynSelectedColor(aSource);
|
|
FBG := Source.FBG;
|
|
FFG := Source.FFG;
|
|
FFrameColor := Source.FFrameColor;
|
|
FStyle := Source.FStyle;
|
|
FStyleMask := Source.FStyleMask;
|
|
FStartX := Source.FStartX;
|
|
FEndX := Source.FEndX;
|
|
DoChange; {TODO: only if really changed}
|
|
end;
|
|
end;
|
|
|
|
procedure TSynSelectedColor.Clear;
|
|
begin
|
|
FBG := clNone;
|
|
FFG := clNone;
|
|
FFrameColor := clNone;
|
|
FStyle := [];
|
|
FStyleMask := [];
|
|
FStartX := -1;
|
|
FEndX := -1;
|
|
end;
|
|
|
|
function TSynSelectedColor.IsEnabled: boolean;
|
|
begin
|
|
Result := (FBG <> clNone) or (FFG <> clNone) or (FFrameColor <> clNone) or
|
|
(FStyle <> []) or (FStyleMask <> []);
|
|
end;
|
|
|
|
{ TSynBookMarkOpt }
|
|
|
|
constructor TSynBookMarkOpt.Create(AOwner: TComponent);
|
|
begin
|
|
inherited Create;
|
|
fDrawBookmarksFirst := TRUE; //mh 2000-10-12
|
|
fEnableKeys := True;
|
|
fGlyphsVisible := True;
|
|
fLeftMargin := 2;
|
|
fOwner := AOwner;
|
|
fXOffset := 12;
|
|
end;
|
|
|
|
procedure TSynBookMarkOpt.SetBookmarkImages(const Value: TImageList);
|
|
begin
|
|
if fBookmarkImages <> Value then begin
|
|
fBookmarkImages := Value;
|
|
if Assigned(fBookmarkImages) then fBookmarkImages.FreeNotification(fOwner);
|
|
if Assigned(fOnChange) then fOnChange(Self);
|
|
end;
|
|
end;
|
|
|
|
{begin} //mh 2000-10-12
|
|
procedure TSynBookMarkOpt.SetDrawBookmarksFirst(Value: boolean);
|
|
begin
|
|
if Value <> fDrawBookmarksFirst then begin
|
|
fDrawBookmarksFirst := Value;
|
|
if Assigned(fOnChange) then fOnChange(Self);
|
|
end;
|
|
end;
|
|
{end} //mh 2000-10-12
|
|
|
|
procedure TSynBookMarkOpt.SetGlyphsVisible(Value: Boolean);
|
|
begin
|
|
if fGlyphsVisible <> Value then begin
|
|
fGlyphsVisible := Value;
|
|
if Assigned(fOnChange) then fOnChange(Self);
|
|
end;
|
|
end;
|
|
|
|
procedure TSynBookMarkOpt.SetLeftMargin(Value: Integer);
|
|
begin
|
|
if fLeftMargin <> Value then begin
|
|
fLeftMargin := Value;
|
|
if Assigned(fOnChange) then fOnChange(Self);
|
|
end;
|
|
end;
|
|
|
|
procedure TSynBookMarkOpt.SetXOffset(Value: integer);
|
|
begin
|
|
if fXOffset <> Value then begin
|
|
fXOffset := Value;
|
|
if Assigned(fOnChange) then fOnChange(Self);
|
|
end;
|
|
end;
|
|
|
|
{ TSynMethodChain }
|
|
|
|
procedure TSynMethodChain.Add(AEvent: TMethod);
|
|
begin
|
|
if not Assigned(@AEvent) then
|
|
raise ESynMethodChain.CreateFmt(
|
|
'%s.Entry : the parameter `AEvent'' must be specified.', [ClassName]);
|
|
|
|
with FNotifyProcs, AEvent do
|
|
begin
|
|
Add(Code);
|
|
Add(Data);
|
|
end
|
|
end;
|
|
|
|
constructor TSynMethodChain.Create;
|
|
begin
|
|
inherited;
|
|
FNotifyProcs := TList.Create;
|
|
end;
|
|
|
|
destructor TSynMethodChain.Destroy;
|
|
begin
|
|
FNotifyProcs.Free;
|
|
inherited;
|
|
end;
|
|
|
|
function TSynMethodChain.DoHandleException(E: Exception): Boolean;
|
|
begin
|
|
if not Assigned(FExceptionHandler) then
|
|
raise E
|
|
else
|
|
try
|
|
Result := True;
|
|
FExceptionHandler(Self, E, Result);
|
|
except
|
|
raise ESynMethodChain.CreateFmt(
|
|
'%s.DoHandleException : MUST NOT occur any kind of exception in '+
|
|
'ExceptionHandler', [ClassName]);
|
|
end;
|
|
end;
|
|
|
|
procedure TSynMethodChain.Fire;
|
|
var
|
|
AMethod: TMethod;
|
|
i: Integer;
|
|
begin
|
|
i := 0;
|
|
with FNotifyProcs, AMethod do
|
|
while i < Count do
|
|
try
|
|
repeat
|
|
Code := Items[i];
|
|
Inc(i);
|
|
Data := Items[i];
|
|
Inc(i);
|
|
|
|
DoFire(AMethod)
|
|
until i >= Count;
|
|
except
|
|
on E: Exception do
|
|
if not DoHandleException(E) then
|
|
i := MaxInt;
|
|
end;
|
|
end;
|
|
|
|
procedure TSynMethodChain.Remove(AEvent: TMethod);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
if not Assigned(@AEvent) then
|
|
raise ESynMethodChain.CreateFmt(
|
|
'%s.Remove: the parameter `AEvent'' must be specified.', [ClassName]);
|
|
|
|
with FNotifyProcs, AEvent do
|
|
begin
|
|
i := Count - 1;
|
|
while i > 0 do
|
|
if Items[i] <> Data then
|
|
Dec(i, 2)
|
|
else
|
|
begin
|
|
Dec(i);
|
|
if Items[i] = Code then
|
|
begin
|
|
Delete(i);
|
|
Delete(i);
|
|
end;
|
|
Dec(i);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
{ TSynNotifyEventChain }
|
|
|
|
procedure TSynNotifyEventChain.Add(AEvent: TNotifyEvent);
|
|
begin
|
|
inherited Add(TMethod(AEvent));
|
|
end;
|
|
|
|
constructor TSynNotifyEventChain.CreateEx(ASender: TObject);
|
|
begin
|
|
inherited Create;
|
|
FSender := ASender;
|
|
end;
|
|
|
|
procedure TSynNotifyEventChain.DoFire(AEvent: TMethod);
|
|
begin
|
|
TNotifyEvent(AEvent)(FSender);
|
|
end;
|
|
|
|
procedure TSynNotifyEventChain.Remove(AEvent: TNotifyEvent);
|
|
begin
|
|
inherited Remove(TMethod(AEvent));
|
|
end;
|
|
|
|
var
|
|
InternalImages: TBitmap;
|
|
InternalImagesUsers: integer;
|
|
IIWidth, IIHeight: integer;
|
|
IICount: integer;
|
|
|
|
constructor TSynInternalImage.Create(const AName: string; Count: integer);
|
|
begin
|
|
inherited Create;
|
|
Inc(InternalImagesUsers);
|
|
if InternalImagesUsers = 1 then begin
|
|
InternalImages := TBitmap.Create;
|
|
InternalImages.LoadFromResourceName(HInstance, AName);
|
|
IIWidth := (InternalImages.Width + Count shr 1) div Count;
|
|
IIHeight := InternalImages.Height;
|
|
IICount := Count;
|
|
end;
|
|
end;
|
|
|
|
destructor TSynInternalImage.Destroy;
|
|
begin
|
|
Dec(InternalImagesUsers);
|
|
if InternalImagesUsers = 0 then begin
|
|
InternalImages.Free;
|
|
InternalImages := nil;
|
|
end;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TSynInternalImage.DrawMark(ACanvas: TCanvas;
|
|
Number, X, Y, LineHeight: integer);
|
|
var
|
|
rcSrc, rcDest: TRect;
|
|
begin
|
|
if (Number >= 0) and (Number < IICount) then
|
|
begin
|
|
if LineHeight >= IIHeight then begin
|
|
rcSrc := Rect(Number * IIWidth, 0, (Number + 1) * IIWidth, IIHeight);
|
|
Inc(Y, (LineHeight - IIHeight) div 2);
|
|
rcDest := Rect(X, Y, X + IIWidth, Y + IIHeight);
|
|
end else begin
|
|
rcDest := Rect(X, Y, X + IIWidth, Y + LineHeight);
|
|
Y := (IIHeight - LineHeight) div 2;
|
|
rcSrc := Rect(Number * IIWidth, Y, (Number + 1) * IIWidth, Y + LineHeight);
|
|
end;
|
|
ACanvas.CopyRect(rcDest, InternalImages.Canvas, rcSrc);
|
|
end;
|
|
end;
|
|
|
|
{$IFNDEF SYN_LAZARUS}
|
|
procedure TSynInternalImage.DrawMarkTransparent(ACanvas: TCanvas; Number, X, Y,
|
|
LineHeight: integer; TransparentColor: TColor);
|
|
var
|
|
rcSrc, rcDest: TRect;
|
|
begin
|
|
if (Number >= 0) and (Number < IICount) then
|
|
begin
|
|
if LineHeight >= IIHeight then begin
|
|
rcSrc := Rect(Number * IIWidth, 0, (Number + 1) * IIWidth, IIHeight);
|
|
Inc(Y, (LineHeight - IIHeight) div 2);
|
|
rcDest := Rect(X, Y, X + IIWidth, Y + IIHeight);
|
|
end else begin
|
|
rcDest := Rect(X, Y, X + IIWidth, Y + LineHeight);
|
|
Y := (IIHeight - LineHeight) div 2;
|
|
rcSrc := Rect(Number * IIWidth, Y, (Number + 1) * IIWidth, Y + LineHeight);
|
|
end;
|
|
ACanvas.BrushCopy(rcDest, InternalImages, rcSrc, TransparentColor);
|
|
end;
|
|
end;
|
|
{$ENDIF}
|
|
|
|
end.
|
|
|