mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-28 13:53:42 +02:00
864 lines
22 KiB
ObjectPascal
864 lines
22 KiB
ObjectPascal
{
|
|
/***************************************************************************
|
|
lclproc.pas
|
|
-----------
|
|
Component Library Code
|
|
|
|
|
|
***************************************************************************/
|
|
|
|
*****************************************************************************
|
|
* *
|
|
* This file is part of the Lazarus Component Library (LCL) *
|
|
* *
|
|
* See the file COPYING.LCL, included in this distribution, *
|
|
* for details about the copyright. *
|
|
* *
|
|
* This program is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
|
|
* *
|
|
*****************************************************************************
|
|
|
|
Useful lower level helper functions and classes.
|
|
}
|
|
unit LCLProc;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils, Math, LCLStrConsts, LCLType;
|
|
|
|
type
|
|
{ TMethodList - array of TMethod }
|
|
|
|
TMethodList = class
|
|
private
|
|
FItems: ^TMethod;
|
|
FCount: integer;
|
|
function GetItems(Index: integer): TMethod;
|
|
procedure SetItems(Index: integer; const AValue: TMethod);
|
|
public
|
|
destructor Destroy; override;
|
|
function Count: integer;
|
|
function NextDownIndex(var Index: integer): boolean;
|
|
function IndexOf(const AMethod: TMethod): integer;
|
|
procedure Delete(Index: integer);
|
|
procedure Remove(const AMethod: TMethod);
|
|
procedure Add(const AMethod: TMethod);
|
|
procedure Add(const AMethod: TMethod; AsLast: boolean);
|
|
procedure Insert(Index: integer; const AMethod: TMethod);
|
|
procedure Move(OldIndex, NewIndex: integer);
|
|
procedure RemoveAllMethodsOfObject(const AnObject: TObject);
|
|
public
|
|
property Items[Index: integer]: TMethod read GetItems write SetItems; default;
|
|
end;
|
|
|
|
|
|
function ShortCutToShortCutText(ShortCut: TShortCut): string;
|
|
function ShortCutTextToShortCut(const ShortCutText: string): TShortCut;
|
|
|
|
// Hooks used to prevent unit circles
|
|
type
|
|
TSendApplicationMessageFunction =
|
|
function(Msg: Cardinal; WParam: WParam; LParam: LParam):Longint;
|
|
TOwnerFormDesignerModifiedProc =
|
|
procedure(AComponent: TComponent);
|
|
TSendMessageToInterfaceFunction =
|
|
function(LM_Message: Integer; Sender: TObject; data: pointer): integer
|
|
of object;
|
|
|
|
|
|
var
|
|
SendApplicationMessageFunction: TSendApplicationMessageFunction;
|
|
OwnerFormDesignerModifiedProc: TOwnerFormDesignerModifiedProc;
|
|
// SendMsgToInterface is set in interfacebase.pp
|
|
SendMsgToInterface: TSendMessageToInterfaceFunction;
|
|
|
|
function SendApplicationMessage(Msg: Cardinal; WParam: WParam; LParam: LParam):Longint;
|
|
procedure OwnerFormDesignerModified(AComponent: TComponent);
|
|
procedure FreeThenNil(var AnObject: TObject);
|
|
|
|
procedure RegisterInterfaceFinalizationHandler(p: TProcedure);
|
|
procedure CallInterfaceFinalizationHandlers;
|
|
|
|
function OffsetRect(var ARect: TRect; dx, dy: Integer): Boolean;
|
|
procedure MoveRect(var ARect: TRect; x, y: Integer);
|
|
procedure MoveRectToFit(var ARect: TRect; const MaxRect: TRect);
|
|
procedure MakeMinMax(var i1, i2: integer);
|
|
procedure CalculateLeftTopWidthHeight(X1,Y1,X2,Y2: integer;
|
|
var Left,Top,Width,Height: integer);
|
|
|
|
function DeleteAmpersands(var Str : String) : Longint;
|
|
function BreakString(const s: string; MaxLineLength, Indent: integer): string;
|
|
|
|
function ComparePointers(p1, p2: Pointer): integer;
|
|
function CompareHandles(h1, h2: THandle): integer;
|
|
|
|
|
|
function RoundToInt(const e: Extended): integer;
|
|
function RoundToCardinal(const e: Extended): cardinal;
|
|
function TruncToInt(const e: Extended): integer;
|
|
function TruncToCardinal(const e: Extended): cardinal;
|
|
function StrToDouble(const s: string): double;
|
|
|
|
|
|
// debugging
|
|
procedure RaiseGDBException(const Msg: string);
|
|
|
|
procedure DebugLn(const S: String; Args: array of const);
|
|
procedure DebugLn;
|
|
procedure DebugLn(const s: string);
|
|
procedure DebugLn(const s1,s2: string);
|
|
procedure DebugLn(const s1,s2,s3: string);
|
|
procedure DebugLn(const s1,s2,s3,s4: string);
|
|
procedure DebugLn(const s1,s2,s3,s4,s5: string);
|
|
procedure DebugLn(const s1,s2,s3,s4,s5,s6: string);
|
|
procedure DebugLn(const s1,s2,s3,s4,s5,s6,s7: string);
|
|
procedure DebugLn(const s1,s2,s3,s4,s5,s6,s7,s8: string);
|
|
procedure DebugLn(const s1,s2,s3,s4,s5,s6,s7,s8,s9: string);
|
|
procedure DebugLn(const s1,s2,s3,s4,s5,s6,s7,s8,s9,s10: string);
|
|
procedure DebugLn(const s1,s2,s3,s4,s5,s6,s7,s8,s9,s10,s11: string);
|
|
procedure DebugLn(const s1,s2,s3,s4,s5,s6,s7,s8,s9,s10,s11,s12: string);
|
|
procedure DebugLn(const s1,s2,s3,s4,s5,s6,s7,s8,s9,s10,s11,s12,s13: string);
|
|
procedure DebugLn(const s1,s2,s3,s4,s5,s6,s7,s8,s9,s10,s11,s12,s13,s14: string);
|
|
procedure DebugLn(const s1,s2,s3,s4,s5,s6,s7,s8,s9,s10,s11,s12,s13,s14,s15: string);
|
|
procedure DebugLn(const s1,s2,s3,s4,s5,s6,s7,s8,s9,s10,s11,s12,s13,s14,s15,s16: string);
|
|
|
|
procedure DbgOut(const s: string);
|
|
procedure DbgOut(const s1,s2: string);
|
|
|
|
function DbgS(const c: cardinal): string;
|
|
function DbgS(const i: integer): string;
|
|
function DbgS(const r: TRect): string;
|
|
function DbgS(const p: TPoint): string;
|
|
function DbgS(const p: pointer): string;
|
|
function DbgS(const e: extended): string;
|
|
function DbgS(const b: boolean): string;
|
|
function DbgSName(const p: TPersistent): string;
|
|
|
|
function DbgS(const i1,i2,i3,i4: integer): string;
|
|
|
|
|
|
implementation
|
|
|
|
var
|
|
InterfaceFinalizationHandlers: TList;
|
|
|
|
|
|
Function DeleteAmpersands(var Str : String) : Longint;
|
|
// Replace all &x with x
|
|
// and return the position of the first ampersand letter in the resulting Str.
|
|
// double ampersands && are converted to a single & and are ignored.
|
|
var
|
|
SrcPos, DestPos, SrcLen: Integer;
|
|
begin
|
|
Result:=-1;
|
|
SrcLen:=length(Str);
|
|
SrcPos:=1;
|
|
DestPos:=1;
|
|
while SrcPos<=SrcLen do begin
|
|
if (Str[SrcPos]='&') and (SrcPos<SrcLen) then begin
|
|
// & found
|
|
inc(SrcPos); // skip &
|
|
if (Str[SrcPos]<>'&') and (Result<1) then
|
|
Result:=DestPos;
|
|
end;
|
|
if DestPos<SrcPos then
|
|
Str[DestPos]:=Str[SrcPos];
|
|
inc(SrcPos);
|
|
inc(DestPos);
|
|
end;
|
|
if DestPos<SrcPos then
|
|
SetLength(Str,DestPos-1);
|
|
end;
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Keys and shortcuts
|
|
|
|
type
|
|
TMenuKeyCap = (mkcBkSp, mkcTab, mkcEsc, mkcEnter, mkcSpace, mkcPgUp,
|
|
mkcPgDn, mkcEnd, mkcHome, mkcLeft, mkcUp, mkcRight, mkcDown, mkcIns,
|
|
mkcDel, mkcShift, mkcCtrl, mkcAlt);
|
|
|
|
const
|
|
SmkcBkSp = 'BkSp';
|
|
SmkcTab = 'Tab';
|
|
SmkcEsc = 'Esc';
|
|
SmkcEnter = 'Enter';
|
|
SmkcSpace = 'Space';
|
|
SmkcPgUp = 'PgUp';
|
|
SmkcPgDn = 'PgDn';
|
|
SmkcEnd = 'End';
|
|
SmkcHome = 'Home';
|
|
SmkcLeft = 'Left';
|
|
SmkcUp = 'Up';
|
|
SmkcRight = 'Right';
|
|
SmkcDown = 'Down';
|
|
SmkcIns = 'Ins';
|
|
SmkcDel = 'Del';
|
|
SmkcShift = 'Shift+';
|
|
SmkcCtrl = 'Ctrl+';
|
|
SmkcAlt = 'Alt+';
|
|
|
|
MenuKeyCaps: array[TMenuKeyCap] of string = (
|
|
SmkcBkSp, SmkcTab, SmkcEsc, SmkcEnter, SmkcSpace, SmkcPgUp,
|
|
SmkcPgDn, SmkcEnd, SmkcHome, SmkcLeft, SmkcUp, SmkcRight,
|
|
SmkcDown, SmkcIns, SmkcDel, SmkcShift, SmkcCtrl, SmkcAlt);
|
|
|
|
function GetSpecialShortCutName(ShortCut: TShortCut): string;
|
|
{var
|
|
ScanCode: Integer;
|
|
KeyName: array[0..255] of Char;}
|
|
begin
|
|
Result := '';
|
|
// ToDo:
|
|
{
|
|
ScanCode := MapVirtualKey(WordRec(ShortCut).Lo, 0) shl 16;
|
|
if ScanCode <> 0 then
|
|
begin
|
|
GetKeyNameText(ScanCode, KeyName, SizeOf(KeyName));
|
|
Result := KeyName;
|
|
end;
|
|
}
|
|
end;
|
|
|
|
function ShortCutToShortCutText(ShortCut: TShortCut): string;
|
|
var
|
|
Name: string;
|
|
begin
|
|
case WordRec(ShortCut).Lo of
|
|
$08, $09:
|
|
Name := MenuKeyCaps[TMenuKeyCap(Ord(mkcBkSp) + WordRec(ShortCut).Lo - $08)];
|
|
$0D: Name := MenuKeyCaps[mkcEnter];
|
|
$1B: Name := MenuKeyCaps[mkcEsc];
|
|
$20..$28:
|
|
Name := MenuKeyCaps[TMenuKeyCap(Ord(mkcSpace) + WordRec(ShortCut).Lo - $20)];
|
|
$2D..$2E:
|
|
Name := MenuKeyCaps[TMenuKeyCap(Ord(mkcIns) + WordRec(ShortCut).Lo - $2D)];
|
|
$30..$39: Name := Chr(WordRec(ShortCut).Lo - $30 + Ord('0'));
|
|
$41..$5A: Name := Chr(WordRec(ShortCut).Lo - $41 + Ord('A'));
|
|
$60..$69: Name := Chr(WordRec(ShortCut).Lo - $60 + Ord('0'));
|
|
$70..$87: Name := 'F' + IntToStr(WordRec(ShortCut).Lo - $6F);
|
|
else
|
|
Name := GetSpecialShortCutName(ShortCut);
|
|
end;
|
|
if Name <> '' then
|
|
begin
|
|
Result := '';
|
|
if ShortCut and scShift <> 0 then Result := Result + MenuKeyCaps[mkcShift];
|
|
if ShortCut and scCtrl <> 0 then Result := Result + MenuKeyCaps[mkcCtrl];
|
|
if ShortCut and scAlt <> 0 then Result := Result + MenuKeyCaps[mkcAlt];
|
|
Result := Result + Name;
|
|
end
|
|
else Result := '';
|
|
end;
|
|
|
|
function ShortCutTextToShortCut(const ShortCutText: string): TShortCut;
|
|
|
|
function CompareFront(var StartPos: integer; const Front: string): Boolean;
|
|
begin
|
|
if (Front<>'') and (StartPos+length(Front)-1<=length(ShortCutText))
|
|
and (AnsiStrLIComp(@ShortCutText[StartPos], PChar(Front), Length(Front))= 0)
|
|
then begin
|
|
Result:=true;
|
|
inc(StartPos,length(Front));
|
|
end else
|
|
Result:=false;
|
|
end;
|
|
|
|
var
|
|
Key: TShortCut;
|
|
Shift: TShortCut;
|
|
StartPos: integer;
|
|
Name: string;
|
|
begin
|
|
Result := 0;
|
|
Shift := 0;
|
|
StartPos:=1;
|
|
while True do
|
|
begin
|
|
if CompareFront(StartPos, MenuKeyCaps[mkcShift]) then
|
|
Shift := Shift or scShift
|
|
else if CompareFront(StartPos, '^') then
|
|
Shift := Shift or scCtrl
|
|
else if CompareFront(StartPos, MenuKeyCaps[mkcCtrl]) then
|
|
Shift := Shift or scCtrl
|
|
else if CompareFront(StartPos, MenuKeyCaps[mkcAlt]) then
|
|
Shift := Shift or scAlt
|
|
else
|
|
Break;
|
|
end;
|
|
if ShortCutText = '' then Exit;
|
|
for Key := $08 to $255 do begin { Copy range from table in ShortCutToText }
|
|
Name:=ShortCutToShortCutText(Key);
|
|
if (Name<>'') and (length(Name)=length(ShortCutText)-StartPos+1)
|
|
and (AnsiStrLIComp(@ShortCutText[StartPos], PChar(Name), length(Name)) = 0)
|
|
then begin
|
|
Result := Key or Shift;
|
|
Exit;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function SendApplicationMessage(Msg: Cardinal; WParam: WParam; LParam: LParam
|
|
): Longint;
|
|
begin
|
|
if SendApplicationMessageFunction<>nil then
|
|
Result:=SendApplicationMessageFunction(Msg, WParam, LParam)
|
|
else
|
|
Result:=0;
|
|
end;
|
|
|
|
procedure OwnerFormDesignerModified(AComponent: TComponent);
|
|
begin
|
|
if ([csDesigning,csLoading,csDestroying]*AComponent.ComponentState
|
|
=[csDesigning])
|
|
then begin
|
|
if OwnerFormDesignerModifiedProc<>nil then
|
|
OwnerFormDesignerModifiedProc(AComponent);
|
|
end;
|
|
end;
|
|
|
|
function OffSetRect(var ARect: TRect; dx,dy: Integer): Boolean;
|
|
Begin
|
|
with ARect do
|
|
begin
|
|
Left := Left + dx;
|
|
Right := Right + dx;
|
|
Top := Top + dy;
|
|
Bottom := Bottom + dy;
|
|
end;
|
|
if (ARect.Left >= 0) and (ARect.Top >= 0) then
|
|
Result := True
|
|
else
|
|
Result := False;
|
|
end;
|
|
|
|
procedure FreeThenNil(var AnObject: TObject);
|
|
begin
|
|
if AnObject<>nil then begin
|
|
AnObject.Free;
|
|
AnObject:=nil;
|
|
end;
|
|
end;
|
|
|
|
procedure RegisterInterfaceFinalizationHandler(p: TProcedure);
|
|
begin
|
|
InterfaceFinalizationHandlers.Add(p);
|
|
end;
|
|
|
|
procedure CallInterfaceFinalizationHandlers;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
for i:=0 to InterfaceFinalizationHandlers.Count-1 do
|
|
TProcedure(InterfaceFinalizationHandlers[i])();
|
|
end;
|
|
|
|
{ TMethodList }
|
|
|
|
function TMethodList.GetItems(Index: integer): TMethod;
|
|
begin
|
|
Result:=FItems[Index];
|
|
end;
|
|
|
|
procedure TMethodList.SetItems(Index: integer; const AValue: TMethod);
|
|
begin
|
|
FItems[Index]:=AValue;
|
|
end;
|
|
|
|
destructor TMethodList.Destroy;
|
|
begin
|
|
ReAllocMem(FItems,0);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TMethodList.Count: integer;
|
|
begin
|
|
if Self<>nil then
|
|
Result:=FCount
|
|
else
|
|
Result:=0;
|
|
end;
|
|
|
|
function TMethodList.NextDownIndex(var Index: integer): boolean;
|
|
begin
|
|
if Self<>nil then begin
|
|
dec(Index);
|
|
if (Index>=FCount) then
|
|
Index:=FCount-1;
|
|
end else
|
|
Index:=-1;
|
|
Result:=(Index>=0);
|
|
end;
|
|
|
|
function TMethodList.IndexOf(const AMethod: TMethod): integer;
|
|
begin
|
|
if Self<>nil then begin
|
|
Result:=FCount-1;
|
|
while Result>=0 do begin
|
|
if (FItems[Result].Code=AMethod.Code)
|
|
and (FItems[Result].Data=AMethod.Data) then exit;
|
|
dec(Result);
|
|
end;
|
|
end else
|
|
Result:=-1;
|
|
end;
|
|
|
|
procedure TMethodList.Delete(Index: integer);
|
|
begin
|
|
dec(FCount);
|
|
if FCount>Index then
|
|
System.Move(FItems[Index+1],FItems[Index],(FCount-Index)*SizeOf(TMethod));
|
|
ReAllocMem(FItems,FCount*SizeOf(TMethod));
|
|
end;
|
|
|
|
procedure TMethodList.Remove(const AMethod: TMethod);
|
|
var
|
|
i: integer;
|
|
begin
|
|
if Self<>nil then begin
|
|
i:=IndexOf(AMethod);
|
|
if i>=0 then Delete(i);
|
|
end;
|
|
end;
|
|
|
|
procedure TMethodList.Add(const AMethod: TMethod);
|
|
begin
|
|
inc(FCount);
|
|
ReAllocMem(FItems,FCount*SizeOf(TMethod));
|
|
FItems[FCount-1]:=AMethod;
|
|
end;
|
|
|
|
procedure TMethodList.Add(const AMethod: TMethod; AsLast: boolean);
|
|
begin
|
|
if AsLast then
|
|
Add(AMethod)
|
|
else
|
|
Insert(0,AMethod);
|
|
end;
|
|
|
|
procedure TMethodList.Insert(Index: integer; const AMethod: TMethod);
|
|
begin
|
|
if Index<FCount then
|
|
System.Move(FItems[Index],FItems[Index+1],(FCount-Index)*SizeOf(TMethod));
|
|
FItems[Index]:=AMethod;
|
|
end;
|
|
|
|
procedure TMethodList.Move(OldIndex, NewIndex: integer);
|
|
var
|
|
MovingMethod: TMethod;
|
|
begin
|
|
if OldIndex=NewIndex then exit;
|
|
MovingMethod:=FItems[OldIndex];
|
|
if OldIndex>NewIndex then
|
|
System.Move(FItems[NewIndex],FItems[NewIndex+1],
|
|
SizeOf(TMethod)*(OldIndex-NewIndex))
|
|
else
|
|
System.Move(FItems[NewIndex+1],FItems[NewIndex],
|
|
SizeOf(TMethod)*(NewIndex-OldIndex));
|
|
FItems[NewIndex]:=MovingMethod;
|
|
end;
|
|
|
|
procedure TMethodList.RemoveAllMethodsOfObject(const AnObject: TObject);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
if Self=nil then exit;
|
|
i:=FCount-1;
|
|
while i>=0 do begin
|
|
if TObject(FItems[i].Data)=AnObject then Delete(i);
|
|
dec(i);
|
|
end;
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
procedure RaiseGDBException(const Msg: string);
|
|
|
|
Raises an exception.
|
|
gdb does normally not catch fpc Exception objects, therefore this procedure
|
|
raises a standard AV which is catched by gdb.
|
|
------------------------------------------------------------------------------}
|
|
procedure RaiseGDBException(const Msg: string);
|
|
begin
|
|
debugln(rsERRORInLCL, Msg);
|
|
// creates an exception, that gdb catches:
|
|
debugln(rsCreatingGdbCatchableError);
|
|
if (length(Msg) div (length(Msg) div 10000))=0 then ;
|
|
end;
|
|
|
|
procedure MoveRect(var ARect: TRect; x, y: Integer);
|
|
begin
|
|
inc(ARect.Right,x-ARect.Left);
|
|
inc(ARect.Bottom,y-ARect.Top);
|
|
ARect.Left:=x;
|
|
ARect.Top:=y;
|
|
end;
|
|
|
|
procedure MoveRectToFit(var ARect: TRect; const MaxRect: TRect);
|
|
// move ARect, so it fits into MaxRect
|
|
// if MaxRect is too small, ARect is resized.
|
|
begin
|
|
if ARect.Left<MaxRect.Left then begin
|
|
// move rectangle right
|
|
ARect.Right:=Min(ARect.Right+MaxRect.Left-ARect.Left,MaxRect.Right);
|
|
ARect.Left:=MaxRect.Left;
|
|
end;
|
|
if ARect.Top<MaxRect.Top then begin
|
|
// move rectangle down
|
|
ARect.Bottom:=Min(ARect.Bottom+MaxRect.Top-ARect.Top,MaxRect.Bottom);
|
|
ARect.Top:=MaxRect.Top;
|
|
end;
|
|
if ARect.Right>MaxRect.Right then begin
|
|
// move rectangle left
|
|
ARect.Left:=Max(ARect.Left-ARect.Right+MaxRect.Right,MaxRect.Left);
|
|
ARect.Right:=MaxRect.Right;
|
|
end;
|
|
if ARect.Bottom>MaxRect.Bottom then begin
|
|
// move rectangle left
|
|
ARect.Top:=Max(ARect.Top-ARect.Bottom+MaxRect.Bottom,MaxRect.Top);
|
|
ARect.Bottom:=MaxRect.Bottom;
|
|
end;
|
|
end;
|
|
|
|
procedure MakeMinMax(var i1, i2: integer);
|
|
var
|
|
h: Integer;
|
|
begin
|
|
if i1>i2 then begin
|
|
h:=i1;
|
|
i1:=i2;
|
|
i2:=h;
|
|
end;
|
|
end;
|
|
|
|
procedure CalculateLeftTopWidthHeight(X1, Y1, X2, Y2: integer;
|
|
var Left, Top, Width, Height: integer);
|
|
begin
|
|
if X1<=X2 then begin
|
|
Left:=X1;
|
|
Width:=X2 - X1;
|
|
end else begin
|
|
Left:=X2;
|
|
Width:=X1 - X2;
|
|
end;
|
|
if Y1<=Y2 then begin
|
|
Top:=Y1;
|
|
Height:=Y2 - Y1;
|
|
end else begin
|
|
Top:=Y2;
|
|
Height:=Y1 - Y2;
|
|
end;
|
|
end;
|
|
|
|
function BreakString(const s: string; MaxLineLength, Indent: integer): string;
|
|
var
|
|
SrcLen: Integer;
|
|
APos: Integer;
|
|
Src: String;
|
|
SplitPos: Integer;
|
|
CurMaxLineLength: Integer;
|
|
begin
|
|
Result:='';
|
|
Src:=s;
|
|
CurMaxLineLength:=MaxLineLength;
|
|
if Indent>MaxLineLength-2 then Indent:=MaxLineLength-2;
|
|
if Indent<0 then MaxLineLength:=0;
|
|
repeat
|
|
SrcLen:=length(Src);
|
|
if SrcLen<=CurMaxLineLength then begin
|
|
Result:=Result+Src;
|
|
break;
|
|
end;
|
|
// split line
|
|
SplitPos:=0;
|
|
// search new line chars
|
|
APos:=1;
|
|
while (APos<=CurMaxLineLength) do begin
|
|
if Src[APos] in [#13,#10] then begin
|
|
SplitPos:=APos;
|
|
break;
|
|
end;
|
|
inc(APos);
|
|
end;
|
|
// search a space boundary
|
|
if SplitPos=0 then begin
|
|
APos:=CurMaxLineLength;
|
|
while APos>1 do begin
|
|
if (Src[APos-1] in [' ',#9])
|
|
and (not (Src[APos] in [' ',#9])) then begin
|
|
SplitPos:=APos;
|
|
break;
|
|
end;
|
|
dec(APos);
|
|
end;
|
|
end;
|
|
// search a word boundary
|
|
if SplitPos=0 then begin
|
|
APos:=CurMaxLineLength;
|
|
while APos>1 do begin
|
|
if (Src[APos] in ['A'..'Z','a'..'z'])
|
|
and (not (Src[APos-1] in ['A'..'Z','a'..'z'])) then begin
|
|
SplitPos:=APos;
|
|
break;
|
|
end;
|
|
dec(APos);
|
|
end;
|
|
end;
|
|
if SplitPos=0 then begin
|
|
// no word boundary found -> split chars
|
|
SplitPos:=CurMaxLineLength;
|
|
end;
|
|
// append part and newline
|
|
if (SplitPos<=SrcLen) and (Src[SplitPos] in [#10,#13]) then begin
|
|
// there is already a new line char at position
|
|
inc(SplitPos);
|
|
if (SplitPos<=SrcLen) and (Src[SplitPos] in [#10,#13])
|
|
and (Src[SplitPos]<>Src[SplitPos-1]) then
|
|
inc(SplitPos);
|
|
Result:=Result+copy(Src,1,SplitPos-1);
|
|
end else begin
|
|
Result:=Result+copy(Src,1,SplitPos-1)+LineEnding;
|
|
end;
|
|
// append indent
|
|
if Indent>0 then
|
|
Result:=Result+StringOfChar(' ',Indent);
|
|
// calculate new LineLength
|
|
CurMaxLineLength:=MaxLineLength-Indent;
|
|
// cut string
|
|
Src:=copy(Src,SplitPos,length(Src)-SplitPos+1);
|
|
until false;
|
|
end;
|
|
|
|
function ComparePointers(p1, p2: Pointer): integer;
|
|
begin
|
|
if p1>p2 then
|
|
Result:=1
|
|
else if p1<p2 then
|
|
Result:=-1
|
|
else
|
|
Result:=0;
|
|
end;
|
|
|
|
function CompareHandles(h1, h2: THandle): integer;
|
|
begin
|
|
if h1>h2 then
|
|
Result:=1
|
|
else if h1<h2 then
|
|
Result:=-1
|
|
else
|
|
Result:=0;
|
|
end;
|
|
|
|
function RoundToInt(const e: Extended): integer;
|
|
begin
|
|
Result:=integer(Round(e));
|
|
{$IFDEF VerboseRound}
|
|
DebugLn('RoundToInt ',e,' ',Result);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
function RoundToCardinal(const e: Extended): cardinal;
|
|
begin
|
|
Result:=cardinal(Round(e));
|
|
{$IFDEF VerboseRound}
|
|
DebugLn('RoundToCardinal ',e,' ',Result);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
function TruncToInt(const e: Extended): integer;
|
|
begin
|
|
Result:=integer(Trunc(e));
|
|
{$IFDEF VerboseRound}
|
|
DebugLn('TruncToInt ',e,' ',Result);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
function TruncToCardinal(const e: Extended): cardinal;
|
|
begin
|
|
Result:=cardinal(Trunc(e));
|
|
{$IFDEF VerboseRound}
|
|
DebugLn('TruncToCardinal ',e,' ',Result);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
function StrToDouble(const s: string): double;
|
|
begin
|
|
{$IFDEF VerboseRound}
|
|
DebugLn('StrToDouble "',s,'"');
|
|
{$ENDIF}
|
|
Result:=Double(StrToFloat(s));
|
|
end;
|
|
|
|
procedure DebugLn(const S: String; Args: array of const);
|
|
begin
|
|
DebugLn(Format(S, Args));
|
|
end;
|
|
|
|
procedure DebugLn;
|
|
begin
|
|
DebugLn('');
|
|
end;
|
|
|
|
procedure DebugLn(const s: string);
|
|
begin
|
|
if TextRec(Output).Mode<>fmClosed then
|
|
writeln(s);
|
|
end;
|
|
|
|
procedure DebugLn(const s1, s2: string);
|
|
begin
|
|
DebugLn(s1+s2);
|
|
end;
|
|
|
|
procedure DebugLn(const s1, s2, s3: string);
|
|
begin
|
|
DebugLn(s1+s2+s3);
|
|
end;
|
|
|
|
procedure DebugLn(const s1, s2, s3, s4: string);
|
|
begin
|
|
DebugLn(s1+s2+s3+s4);
|
|
end;
|
|
|
|
procedure DebugLn(const s1, s2, s3, s4, s5: string);
|
|
begin
|
|
DebugLn(s1+s2+s3+s4+s5);
|
|
end;
|
|
|
|
procedure DebugLn(const s1, s2, s3, s4, s5, s6: string);
|
|
begin
|
|
DebugLn(s1+s2+s3+s4+s5+s6);
|
|
end;
|
|
|
|
procedure DebugLn(const s1, s2, s3, s4, s5, s6, s7: string);
|
|
begin
|
|
DebugLn(s1+s2+s3+s4+s5+s6+s7);
|
|
end;
|
|
|
|
procedure DebugLn(const s1, s2, s3, s4, s5, s6, s7, s8: string);
|
|
begin
|
|
DebugLn(s1+s2+s3+s4+s5+s6+s7+s8);
|
|
end;
|
|
|
|
procedure DebugLn(const s1, s2, s3, s4, s5, s6, s7, s8, s9: string);
|
|
begin
|
|
DebugLn(s1+s2+s3+s4+s5+s6+s7+s8+s9);
|
|
end;
|
|
|
|
procedure DebugLn(const s1, s2, s3, s4, s5, s6, s7, s8, s9, s10: string);
|
|
begin
|
|
DebugLn(s1+s2+s3+s4+s5+s6+s7+s8+s9+s10);
|
|
end;
|
|
|
|
procedure DebugLn(const s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11: string);
|
|
begin
|
|
DebugLn(s1+s2+s3+s4+s5+s6+s7+s8+s9+s10+s11);
|
|
end;
|
|
|
|
procedure DebugLn(const s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11,
|
|
s12: string);
|
|
begin
|
|
DebugLn(s1+s2+s3+s4+s5+s6+s7+s8+s9+s10+s11+s12);
|
|
end;
|
|
|
|
procedure DebugLn(const s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12,
|
|
s13: string);
|
|
begin
|
|
DebugLn(s1+s2+s3+s4+s5+s6+s7+s8+s9+s10+s11+s12+s13);
|
|
end;
|
|
|
|
procedure DebugLn(const s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13,
|
|
s14: string);
|
|
begin
|
|
DebugLn(s1+s2+s3+s4+s5+s6+s7+s8+s9+s10+s11+s12+s13+s14);
|
|
end;
|
|
|
|
procedure DebugLn(const s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13,
|
|
s14, s15: string);
|
|
begin
|
|
DebugLn(s1+s2+s3+s4+s5+s6+s7+s8+s9+s10+s11+s12+s13+s14+s15);
|
|
end;
|
|
|
|
procedure DebugLn(const s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13,
|
|
s14, s15, s16: string);
|
|
begin
|
|
DebugLn(s1+s2+s3+s4+s5+s6+s7+s8+s9+s10+s11+s12+s13+s14+s15+s16);
|
|
end;
|
|
|
|
procedure DBGOut(const s: string);
|
|
begin
|
|
if TextRec(Output).Mode<>fmClosed then
|
|
write(s);
|
|
end;
|
|
|
|
procedure DBGOut(const s1, s2: string);
|
|
begin
|
|
DbgOut(s1+s2);
|
|
end;
|
|
|
|
function DbgS(const c: cardinal): string;
|
|
begin
|
|
Result:=IntToStr(c);
|
|
end;
|
|
|
|
function DbgS(const i: integer): string;
|
|
begin
|
|
Result:=IntToStr(i);
|
|
end;
|
|
|
|
function DbgS(const r: TRect): string;
|
|
begin
|
|
Result:=' x1='+IntToStr(r.Left)+',y1='+IntToStr(r.Top)
|
|
+',x2='+IntToStr(r.Right)+',y2='+IntToStr(r.Bottom);
|
|
end;
|
|
|
|
function DbgS(const p: TPoint): string;
|
|
begin
|
|
Result:=' x='+IntToStr(p.x)+',y='+IntToStr(p.y);
|
|
end;
|
|
|
|
function DbgS(const p: pointer): string;
|
|
begin
|
|
Result:=HexStr(Cardinal(p),8);
|
|
end;
|
|
|
|
function DbgS(const e: extended): string;
|
|
begin
|
|
Result:=FloatToStr(e);
|
|
end;
|
|
|
|
function DbgS(const b: boolean): string;
|
|
begin
|
|
if b then Result:='True' else Result:='False';
|
|
end;
|
|
|
|
function DbgSName(const p: TPersistent): string;
|
|
begin
|
|
if p=nil then
|
|
Result:='nil'
|
|
else if p is TComponent then
|
|
Result:=TComponent(p).Name+':'+p.ClassName
|
|
else
|
|
Result:=p.ClassName;
|
|
end;
|
|
|
|
function DbgS(const i1, i2, i3, i4: integer): string;
|
|
begin
|
|
Result:=dbgs(i1)+','+dbgs(i2)+','+dbgs(i3)+','+dbgs(i4);
|
|
end;
|
|
|
|
initialization
|
|
SendApplicationMessageFunction:=nil;
|
|
OwnerFormDesignerModifiedProc:=nil;
|
|
InterfaceFinalizationHandlers:=TList.Create;
|
|
finalization
|
|
InterfaceFinalizationHandlers.Free;
|
|
InterfaceFinalizationHandlers:=nil;
|
|
|
|
end.
|
|
|