{ /*************************************************************************** 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, LCLType; type 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 IndexOf(AMethod: TMethod): integer; procedure Delete(Index: integer); procedure Remove(AMethod: TMethod); procedure Add(AMethod: TMethod); procedure Insert(Index: integer; AMethod: TMethod); procedure Move(OldIndex, NewIndex: integer); property Items[Index: integer]: TMethod read GetItems write SetItems; default; end; Function DeleteAmpersands(var Str : String) : Longint; function ShortCutToShortCutText(ShortCut: TShortCut): string; function ShortCutTextToShortCut(const ShortCutText: string): TShortCut; // Hooks used to prevent unit circles type TSendApplicationMessageFunction = function(Msg: Cardinal; WParam, LParam: Longint):Longint; TOwnerFormDesignerModifiedProc = procedure(AComponent: TComponent); TSendMessageToInterfaceFunction = function(LM_Message: Integer; Sender: TObject; data: pointer): integer of object; var SendApplicationMessageFunction: TSendApplicationMessageFunction; OwnerFormDesignerModifiedProc: TOwnerFormDesignerModifiedProc; SendMsgToInterface: TSendMessageToInterfaceFunction; function SendApplicationMessage(Msg: Cardinal; WParam, LParam: Longint):Longint; procedure OwnerFormDesignerModified(AComponent: TComponent); function OffsetRect(var ARect: TRect; dx,dy: Integer): Boolean; procedure FreeThenNil(var AnObject: TObject); procedure RaiseGDBException(const Msg: string); procedure MakeMinMax(var i1, i2: integer); procedure CalculateLeftTopWidthHeight(X1,Y1,X2,Y2: integer; var Left,Top,Width,Height: integer); implementation 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'&') and (Result<1) then Result:=DestPos; end; if DestPos 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, LParam: Longint ): Longint; begin if SendApplicationMessageFunction<>nil then Result:=SendApplicationMessageFunction(Msg,WParam,LParam) else Result:=0; end; procedure OwnerFormDesignerModified(AComponent: TComponent); begin if OwnerFormDesignerModifiedProc<>nil then OwnerFormDesignerModifiedProc(AComponent); 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; { 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 Result:=FCount; end; function TMethodList.IndexOf(AMethod: TMethod): integer; 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; 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(AMethod: TMethod); var i: integer; begin i:=IndexOf(AMethod); if i>=0 then Delete(i); end; procedure TMethodList.Add(AMethod: TMethod); begin inc(FCount); ReAllocMem(FItems,FCount*SizeOf(TMethod)); FItems[FCount-1]:=AMethod; end; procedure TMethodList.Insert(Index: integer; AMethod: TMethod); begin if IndexNewIndex 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 RaiseGDBException(const Msg: string); Raises an exception. gdb does not catch fpc Exception objects, therefore this procedure raises a standard AV which is catched by gdb. ------------------------------------------------------------------------------} procedure RaiseGDBException(const Msg: string); begin writeln('ERROR in gtk-interface: ',Msg); // creates an exception, that gdb catches: writeln('Creating gdb catchable error:'); if (length(Msg) div (length(Msg) div 10000))=0 then ; 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; initialization SendApplicationMessageFunction:=nil; OwnerFormDesignerModifiedProc:=nil; end.