mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-11-24 07:59:52 +01:00
* Cursor patch from Paul Ishenin
* Disabled setting cursors for gtk2, since it is broken git-svn-id: trunk@10544 -
This commit is contained in:
parent
d0214c39e6
commit
92e3d63d75
@ -242,9 +242,10 @@ begin
|
|||||||
{$IFDEF DebugGDK}EndGDKErrorTrap;{$ENDIF}
|
{$IFDEF DebugGDK}EndGDKErrorTrap;{$ENDIF}
|
||||||
end;
|
end;
|
||||||
|
|
||||||
if TheWinControl<>nil then begin
|
if TheWinControl<>nil then
|
||||||
|
begin
|
||||||
TheWinControl.CNPreferredSizeChanged;
|
TheWinControl.CNPreferredSizeChanged;
|
||||||
SetCursor(TheWinControl, crDefault);
|
SetCursor(TheWinControl, Screen.Cursors[TheWinControl.Cursor]);
|
||||||
ConnectInternalWidgetsSignals(MainWidget,TheWinControl);
|
ConnectInternalWidgetsSignals(MainWidget,TheWinControl);
|
||||||
|
|
||||||
if TheWinControl is TCustomPage then
|
if TheWinControl is TCustomPage then
|
||||||
|
|||||||
@ -365,7 +365,6 @@ begin
|
|||||||
FExtUTF8OutCacheSize:=0;
|
FExtUTF8OutCacheSize:=0;
|
||||||
|
|
||||||
FreeAllStyles;
|
FreeAllStyles;
|
||||||
FreeGDKCursors;
|
|
||||||
FreeStockItems;
|
FreeStockItems;
|
||||||
|
|
||||||
if FGTKToolTips<>nil then begin
|
if FGTKToolTips<>nil then begin
|
||||||
@ -3530,7 +3529,7 @@ procedure TGtkWidgetSet.SetDesigning(AComponent: TComponent);
|
|||||||
begin
|
begin
|
||||||
// change cursor
|
// change cursor
|
||||||
if AComponent is TWinControl then
|
if AComponent is TWinControl then
|
||||||
gtkproc.SetCursor(TWinControl(AComponent), TCursor(PtrUInt(nil)));
|
gtkproc.SetCursor(TWinControl(AComponent), Screen.Cursors[TWinControl(AComponent).Cursor]);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{------------------------------------------------------------------------------
|
{------------------------------------------------------------------------------
|
||||||
@ -5238,8 +5237,46 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
function TGTKWidgetSet.CreateStandardCursor(ACursor: SmallInt): hCursor;
|
function TGTKWidgetSet.CreateStandardCursor(ACursor: SmallInt): hCursor;
|
||||||
|
var
|
||||||
|
CursorValue: Integer;
|
||||||
begin
|
begin
|
||||||
Result := GetPredefinedCursor(ACursor);
|
Result := 0;
|
||||||
|
if ACursor < crLow then Exit;
|
||||||
|
if ACursor > crHigh then Exit;
|
||||||
|
|
||||||
|
case TCursor(ACursor) of
|
||||||
|
crDefault: CursorValue := GDK_LEFT_PTR;
|
||||||
|
crNone: CursorValue := GDK_LEFT_PTR;
|
||||||
|
crArrow: CursorValue := GDK_Arrow;
|
||||||
|
crCross: CursorValue := GDK_Cross;
|
||||||
|
crIBeam: CursorValue := GDK_XTerm;
|
||||||
|
// crSize: CursorValue := GDK_FLEUR;
|
||||||
|
crSizeNESW: CursorValue := GDK_BOTTOM_LEFT_CORNER;
|
||||||
|
crSizeNS: CursorValue := GDK_SB_V_DOUBLE_ARROW;
|
||||||
|
crSizeNWSE: CursorValue := GDK_TOP_LEFT_CORNER;
|
||||||
|
crSizeWE: CursorValue := GDK_SB_H_DOUBLE_ARROW;
|
||||||
|
crSizeNW: CursorValue := GDK_TOP_LEFT_CORNER;
|
||||||
|
crSizeN: CursorValue := GDK_TOP_SIDE;
|
||||||
|
crSizeNE: CursorValue := GDK_TOP_RIGHT_CORNER;
|
||||||
|
crSizeW: CursorValue := GDK_LEFT_SIDE;
|
||||||
|
crSizeE: CursorValue := GDK_RIGHT_SIDE;
|
||||||
|
crSizeSW: CursorValue := GDK_BOTTOM_LEFT_CORNER;
|
||||||
|
crSizeS: CursorValue := GDK_BOTTOM_SIDE;
|
||||||
|
crSizeSE: CursorValue := GDK_BOTTOM_RIGHT_CORNER;
|
||||||
|
crUpArrow: CursorValue := GDK_LEFT_PTR;
|
||||||
|
crHourGlass:CursorValue := GDK_CLOCK;
|
||||||
|
crHSplit: CursorValue := GDK_SB_H_DOUBLE_ARROW;
|
||||||
|
crVSplit: CursorValue := GDK_SB_V_DOUBLE_ARROW;
|
||||||
|
crNo: CursorValue := GDK_LEFT_PTR;
|
||||||
|
crAppStart: CursorValue := GDK_LEFT_PTR;
|
||||||
|
crHelp: CursorValue := GDK_QUESTION_ARROW;
|
||||||
|
crHandPoint:CursorValue := GDK_Hand1;
|
||||||
|
crSizeAll: CursorValue := GDK_FLEUR;
|
||||||
|
else
|
||||||
|
CursorValue := -1;
|
||||||
|
end;
|
||||||
|
if CursorValue <> -1 then
|
||||||
|
Result := hCursor(gdk_cursor_new(CursorValue));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{------------------------------------------------------------------------------
|
{------------------------------------------------------------------------------
|
||||||
|
|||||||
@ -4630,109 +4630,39 @@ var
|
|||||||
AWindow: PGdkWindow;
|
AWindow: PGdkWindow;
|
||||||
NewCursor: PGdkCursor;
|
NewCursor: PGdkCursor;
|
||||||
begin
|
begin
|
||||||
|
{$ifdef gtk2}
|
||||||
|
// MWE:
|
||||||
|
// We seriously need to rethink the way of setting cursors.
|
||||||
|
// for instance a button doesn't have an own xwindow.
|
||||||
|
// so setting the cursor results in a cursor set for the parent (=most times form)
|
||||||
|
// buttons have for instance a event_window, we might be able to set a cursor
|
||||||
|
// for that (if an input only window allows that).
|
||||||
|
// using an overridden Tgtk2WSButtonPrivate.SetCursor might solve it.
|
||||||
|
{$note Rethink gtk2 setcursor}
|
||||||
|
Exit;
|
||||||
|
{$endif}
|
||||||
|
|
||||||
if not ((AWinControl is TWinControl) and AWinControl.HandleAllocated)
|
if not ((AWinControl is TWinControl) and AWinControl.HandleAllocated)
|
||||||
then exit;
|
then exit;
|
||||||
|
|
||||||
AWidget:= PGtkWidget(AWinControl.Handle);
|
AWidget:= PGtkWidget(AWinControl.Handle);
|
||||||
|
|
||||||
|
{$note Move designcursor to LCL}
|
||||||
if csDesigning in AWinControl.ComponentState
|
if csDesigning in AWinControl.ComponentState
|
||||||
then begin
|
then begin
|
||||||
AWindow:=GetControlWindow(AWidget);
|
AWindow:=GetControlWindow(AWidget);
|
||||||
if AWindow = nil then exit;
|
ACursor := Screen.Cursors[crDefault];
|
||||||
if ACursor = crDefault then
|
end else
|
||||||
SetCursorRecursive(AWindow, GetGDKMouseCursor(GetPredefinedCursor(crDefault)))
|
begin
|
||||||
else begin
|
|
||||||
NewCursor:= GetGDKMouseCursor(ACursor);
|
|
||||||
if NewCursor <> nil then SetCursorRecursive(AWindow, NewCursor);
|
|
||||||
end;
|
|
||||||
end
|
|
||||||
else begin
|
|
||||||
|
|
||||||
FixWidget:= GetFixedWidget(AWidget);
|
FixWidget:= GetFixedWidget(AWidget);
|
||||||
AWindow:= GetControlWindow(FixWidget);
|
AWindow:= GetControlWindow(FixWidget);
|
||||||
if AWindow = nil then exit;
|
|
||||||
|
|
||||||
NewCursor:= GetGDKMouseCursor(AWinControl.Cursor);
|
|
||||||
if NewCursor <> nil then DoSetCursor(AWindow, NewCursor);
|
|
||||||
end;
|
end;
|
||||||
end;
|
if AWindow = nil then exit;
|
||||||
|
|
||||||
function GetPredefinedCursor(ACursor: TCursor): HCursor;
|
NewCursor := PGdkCursor(ACursor);
|
||||||
begin
|
if NewCursor = nil then Exit;
|
||||||
Result := 0;
|
|
||||||
if ACursor > crHigh then Exit;
|
|
||||||
if ACursor < crLow then Exit;
|
|
||||||
|
|
||||||
Result := ACursor - PREDEFINED_CURSOR_OFFSET;
|
SetCursorRecursive(AWindow, NewCursor);
|
||||||
end;
|
|
||||||
|
|
||||||
function GetGDKMouseCursor(ACursor: HCursor): PGdkCursor;
|
|
||||||
var
|
|
||||||
CursorValue: Integer;
|
|
||||||
begin
|
|
||||||
Result := nil;
|
|
||||||
if ACursor < Low(SmallInt) then Exit;
|
|
||||||
if ACursor > High(SmallInt) then Exit;
|
|
||||||
|
|
||||||
if MMouseCursorMap.GetData(ACursor, Result) then Exit;
|
|
||||||
// not yet created or illegal value
|
|
||||||
|
|
||||||
if TCursor(ACursor + PREDEFINED_CURSOR_OFFSET) > crHigh then Exit;
|
|
||||||
if TCursor(ACursor + PREDEFINED_CURSOR_OFFSET) < crLow then Exit;
|
|
||||||
|
|
||||||
// add it now
|
|
||||||
case TCursor(ACursor + PREDEFINED_CURSOR_OFFSET) of
|
|
||||||
crDefault: CursorValue := GDK_LEFT_PTR;
|
|
||||||
crNone: CursorValue := GDK_LEFT_PTR;
|
|
||||||
crArrow: CursorValue := GDK_Arrow;
|
|
||||||
crCross: CursorValue := GDK_Cross;
|
|
||||||
crIBeam: CursorValue := GDK_XTerm;
|
|
||||||
// crSize: CursorValue := GDK_FLEUR;
|
|
||||||
crSizeNESW: CursorValue := GDK_BOTTOM_LEFT_CORNER;
|
|
||||||
crSizeNS: CursorValue := GDK_SB_V_DOUBLE_ARROW;
|
|
||||||
crSizeNWSE: CursorValue := GDK_TOP_LEFT_CORNER;
|
|
||||||
crSizeWE: CursorValue := GDK_SB_H_DOUBLE_ARROW;
|
|
||||||
crSizeNW: CursorValue := GDK_TOP_LEFT_CORNER;
|
|
||||||
crSizeN: CursorValue := GDK_TOP_SIDE;
|
|
||||||
crSizeNE: CursorValue := GDK_TOP_RIGHT_CORNER;
|
|
||||||
crSizeW: CursorValue := GDK_LEFT_SIDE;
|
|
||||||
crSizeE: CursorValue := GDK_RIGHT_SIDE;
|
|
||||||
crSizeSW: CursorValue := GDK_BOTTOM_LEFT_CORNER;
|
|
||||||
crSizeS: CursorValue := GDK_BOTTOM_SIDE;
|
|
||||||
crSizeSE: CursorValue := GDK_BOTTOM_RIGHT_CORNER;
|
|
||||||
crUpArrow: CursorValue := GDK_LEFT_PTR;
|
|
||||||
crHourGlass:CursorValue := GDK_CLOCK;
|
|
||||||
crDrag: CursorValue := GDK_SAILBOAT;
|
|
||||||
crNoDrop: CursorValue := GDK_IRON_CROSS;
|
|
||||||
crHSplit: CursorValue := GDK_SB_H_DOUBLE_ARROW;
|
|
||||||
crVSplit: CursorValue := GDK_SB_V_DOUBLE_ARROW;
|
|
||||||
crMultiDrag:CursorValue := GDK_SAILBOAT;
|
|
||||||
crSQLWait: CursorValue := GDK_LEFT_PTR;
|
|
||||||
crNo: CursorValue := GDK_LEFT_PTR;
|
|
||||||
crAppStart: CursorValue := GDK_LEFT_PTR;
|
|
||||||
crHelp: CursorValue := GDK_QUESTION_ARROW;
|
|
||||||
crHandPoint:CursorValue := GDK_Hand1;
|
|
||||||
crSizeAll: CursorValue := GDK_FLEUR;
|
|
||||||
else
|
|
||||||
CursorValue := GDK_LEFT_PTR;
|
|
||||||
end;
|
|
||||||
|
|
||||||
Result := gdk_cursor_new(CursorValue);
|
|
||||||
MMouseCursorMap.Add(ACursor, Result);
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure FreeGDKCursors;
|
|
||||||
var
|
|
||||||
Iterator: TMapIterator;
|
|
||||||
begin
|
|
||||||
Iterator := TMapIterator.Create(MMouseCursorMap);
|
|
||||||
while not Iterator.EOM do
|
|
||||||
begin
|
|
||||||
gdk_Cursor_destroy(PGdkCursor(Iterator.DataPtr^));
|
|
||||||
Iterator.Next;
|
|
||||||
end;
|
|
||||||
Iterator.Free;
|
|
||||||
MMouseCursorMap.Clear;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{-------------------------------------------------------------------------------
|
{-------------------------------------------------------------------------------
|
||||||
|
|||||||
@ -492,9 +492,6 @@ procedure UpdateMouseCaptureControl;
|
|||||||
|
|
||||||
// mouse cursor
|
// mouse cursor
|
||||||
procedure SetCursor(AWinControl: TWinControl; ACursor: HCursor);
|
procedure SetCursor(AWinControl: TWinControl; ACursor: HCursor);
|
||||||
function GetPredefinedCursor(ACursor: TCursor): HCursor;
|
|
||||||
function GetGDKMouseCursor(ACursor: hCursor): PGdkCursor;
|
|
||||||
procedure FreeGDKCursors;
|
|
||||||
|
|
||||||
const
|
const
|
||||||
// for now return the same value, in the future we may want to return an
|
// for now return the same value, in the future we may want to return an
|
||||||
|
|||||||
@ -1256,6 +1256,127 @@ begin
|
|||||||
Assert(False,Format('trace: [TGtkWidgetSet.CreateCompatibleDC] DC: 0x%x --> 0x%x', [Integer(DC), Integer(Result)]));
|
Assert(False,Format('trace: [TGtkWidgetSet.CreateCompatibleDC] DC: 0x%x --> 0x%x', [Integer(DC), Integer(Result)]));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function TGtkWidgetSet.CreateCursor(ACursorInfo: PIconInfo): hCursor;
|
||||||
|
|
||||||
|
procedure GetColorMask(AImage, AMask: PGDKPixmap; AImgBits, AMskBits: PByte; AWidth, AHeight: integer);
|
||||||
|
var
|
||||||
|
i, j: integer;
|
||||||
|
colormap: PGDKColormap;
|
||||||
|
Image, MaskImage: PGDKImage;
|
||||||
|
GDKColor: TGDKColor;
|
||||||
|
Pixel, MaskPixel: LongWord;
|
||||||
|
offset: byte;
|
||||||
|
|
||||||
|
procedure SetColorAndMask(c: TGDKColor; MaskPixel: LongWord);
|
||||||
|
var
|
||||||
|
c_bit, m_bit: byte;
|
||||||
|
begin
|
||||||
|
c_bit := ord(c.pixel = $FFFFFF);
|
||||||
|
m_bit := ord(MaskPixel = 0);
|
||||||
|
|
||||||
|
AImgBits^ := AImgBits^ or (c_bit shl offset);
|
||||||
|
AMskBits^ := AMskBits^ or (m_bit shl offset);
|
||||||
|
|
||||||
|
inc(offset);
|
||||||
|
if offset > 7 then
|
||||||
|
begin
|
||||||
|
inc(AImgBits);
|
||||||
|
inc(AMskBits);
|
||||||
|
offset := 0;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
begin
|
||||||
|
// most of this code was taken from TGtkWidgetSet.DCGetPixel
|
||||||
|
|
||||||
|
Image := gdk_drawable_get_image(AImage, 0, 0, AWidth, AHeight);
|
||||||
|
MaskImage := gdk_drawable_get_image(AMask, 0, 0, AWidth, AHeight);
|
||||||
|
|
||||||
|
{$ifdef Gtk1}
|
||||||
|
// previously gdk_image_get_colormap(image) was used, implementation
|
||||||
|
// was casting GdkImage to GdkWindow which is not valid and cause AVs
|
||||||
|
if gdk_window_get_type(PGdkWindow(AImage))= GDK_WINDOW_PIXMAP then
|
||||||
|
colormap := nil // pixmaps are created with null colormap, get system one instead
|
||||||
|
else
|
||||||
|
colormap := gdk_window_get_colormap(PGdkWindow(AImage));
|
||||||
|
{$else}
|
||||||
|
colormap := gdk_image_get_colormap(image);
|
||||||
|
{$endif}
|
||||||
|
|
||||||
|
if colormap = nil then
|
||||||
|
colormap := gdk_colormap_get_system;
|
||||||
|
|
||||||
|
offset := 0;
|
||||||
|
|
||||||
|
for j := 0 to AHeight - 1 do
|
||||||
|
for i := 0 to AWidth - 1 do
|
||||||
|
begin
|
||||||
|
Pixel := gdk_image_get_pixel(Image, i, j);
|
||||||
|
MaskPixel := gdk_image_get_pixel(MaskImage, i, j);
|
||||||
|
FillChar(GDKColor,SizeOf(GDKColor), 0);
|
||||||
|
// does not work with TBitmap.Canvas
|
||||||
|
gdk_colormap_query_color(colormap, Pixel, @GDKColor);
|
||||||
|
SetColorAndMask(GDKColor, MaskPixel);
|
||||||
|
end;
|
||||||
|
gdk_image_unref(Image);
|
||||||
|
gdk_image_unref(MaskImage);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var
|
||||||
|
FG, BG: TGDKColor;
|
||||||
|
Img, Msk: PGdkPixmap;
|
||||||
|
srcbitmap, mskbitmap: PGdkPixmap;
|
||||||
|
W, H, bitlen: integer;
|
||||||
|
ImgBits, MskBits: array of byte;
|
||||||
|
begin
|
||||||
|
Result := 0;
|
||||||
|
if not IsValidGDIObject(ACursorInfo^.hbmColor) then Exit;
|
||||||
|
|
||||||
|
Img := PGDIObject(ACursorInfo^.hbmColor)^.GDIBitmapObject;
|
||||||
|
Msk := PGDIObject(ACursorInfo^.hbmColor)^.GDIBitmapMaskObject;
|
||||||
|
|
||||||
|
gdk_drawable_get_size(Img, @W, @H);
|
||||||
|
bitlen := (W * H) shr 3;
|
||||||
|
SetLength(ImgBits, bitlen);
|
||||||
|
SetLength(MskBits, bitlen);
|
||||||
|
FillChar(ImgBits[0], bitlen, 0);
|
||||||
|
FillChar(MskBits[0], bitlen, 0);
|
||||||
|
|
||||||
|
GetColorMask(Img, Msk, @ImgBits[0], @MskBits[0], W, H);
|
||||||
|
|
||||||
|
srcbitmap := gdk_bitmap_create_from_data (nil, @ImgBits[0], W, H);
|
||||||
|
mskbitmap := gdk_bitmap_create_from_data (nil, @MskBits[0], W, H);
|
||||||
|
|
||||||
|
|
||||||
|
// white
|
||||||
|
fg.red := $FFFF;
|
||||||
|
fg.green := $FFFF;
|
||||||
|
fg.blue := $FFFF;
|
||||||
|
fg.pixel := 0;
|
||||||
|
|
||||||
|
// black
|
||||||
|
bg.red := 0;
|
||||||
|
bg.green := 0;
|
||||||
|
bg.blue := 0;
|
||||||
|
bg.pixel := 0;
|
||||||
|
|
||||||
|
// TODO: for gtk2, use gdk_cursor_new_from_pixbuf for colored cursors
|
||||||
|
Result := hCursor(gdk_cursor_new_from_pixmap (srcbitmap, mskbitmap, @fg, @bg,
|
||||||
|
ACursorInfo^.xHotspot, ACursorInfo^.yHotspot));
|
||||||
|
|
||||||
|
gdk_pixmap_unref(srcbitmap);
|
||||||
|
gdk_pixmap_unref(mskbitmap);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TGtkWidgetSet.DestroyCursor(Handle: hCursor): Boolean;
|
||||||
|
begin
|
||||||
|
if Handle <> 0 then
|
||||||
|
gdk_cursor_destroy(PGdkCursor(Handle));
|
||||||
|
end;
|
||||||
|
|
||||||
{------------------------------------------------------------------------------
|
{------------------------------------------------------------------------------
|
||||||
Function: CreateFontIndirect
|
Function: CreateFontIndirect
|
||||||
Params: const LogFont: TLogFont
|
Params: const LogFont: TLogFont
|
||||||
|
|||||||
@ -53,6 +53,7 @@ function CreateBrushIndirect(const LogBrush: TLogBrush): HBRUSH; override;
|
|||||||
function CreateCaret(Handle : HWND; Bitmap : hBitmap; width, Height : Integer) : Boolean; override;
|
function CreateCaret(Handle : HWND; Bitmap : hBitmap; width, Height : Integer) : Boolean; override;
|
||||||
function CreateCompatibleBitmap(DC: HDC; Width, Height: Integer): HBITMAP; override;
|
function CreateCompatibleBitmap(DC: HDC; Width, Height: Integer): HBITMAP; override;
|
||||||
function CreateCompatibleDC(DC: HDC): HDC; override;
|
function CreateCompatibleDC(DC: HDC): HDC; override;
|
||||||
|
function CreateCursor(ACursorInfo: PIconInfo): hCursor; override;
|
||||||
function CreateFontIndirect(const LogFont: TLogFont): HFONT; override;
|
function CreateFontIndirect(const LogFont: TLogFont): HFONT; override;
|
||||||
function CreateFontIndirectEx(const LogFont: TLogFont; const LongFontName: string): HFONT; override;
|
function CreateFontIndirectEx(const LogFont: TLogFont; const LongFontName: string): HFONT; override;
|
||||||
function CreatePalette(const LogPalette: TLogPalette): HPALETTE; override;
|
function CreatePalette(const LogPalette: TLogPalette): HPALETTE; override;
|
||||||
@ -65,6 +66,7 @@ procedure DeleteCriticalSection(var CritSection: TCriticalSection); override;
|
|||||||
function DeleteDC(hDC: HDC): Boolean; override;
|
function DeleteDC(hDC: HDC): Boolean; override;
|
||||||
function DeleteObject(GDIObject: HGDIOBJ): Boolean; override;
|
function DeleteObject(GDIObject: HGDIOBJ): Boolean; override;
|
||||||
function DestroyCaret(Handle : HWND): Boolean; override;
|
function DestroyCaret(Handle : HWND): Boolean; override;
|
||||||
|
function DestroyCursor(Handle: hCursor): Boolean; override;
|
||||||
Function DrawFrameControl(DC: HDC; var Rect : TRect; uType, uState : Cardinal) : Boolean; override;
|
Function DrawFrameControl(DC: HDC; var Rect : TRect; uType, uState : Cardinal) : Boolean; override;
|
||||||
function DrawFocusRect(DC: HDC; const Rect: TRect): boolean; override;
|
function DrawFocusRect(DC: HDC; const Rect: TRect): boolean; override;
|
||||||
function DrawEdge(DC: HDC; var ARect: TRect; Edge: Cardinal; grfFlags: Cardinal): Boolean; override;
|
function DrawEdge(DC: HDC; var ARect: TRect; Edge: Cardinal; grfFlags: Cardinal): Boolean; override;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user