lazarus/components/synedit/syneditmiscclasses.pp
martin 585bbf6ef1 SynEdit, Auto-Indent: Implement indent types
git-svn-id: trunk@18241 -
2009-01-10 21:11:37 +00:00

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.