mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-06-20 11:28:38 +02:00
2820 lines
76 KiB
PHP
2820 lines
76 KiB
PHP
{%MainUnit cocoaint.pas}
|
|
{ $Id: cocoawinapi.inc 15525 2008-06-23 06:39:58Z paul $ }
|
|
{******************************************************************************
|
|
All Cocoa Winapi implementations.
|
|
This are the implementations of the overrides of the Cocoa Interface for the
|
|
methods defined in the
|
|
lcl/include/winapi.inc
|
|
|
|
******************************************************************************
|
|
Implementation
|
|
******************************************************************************
|
|
|
|
*****************************************************************************
|
|
This file is part of the Lazarus Component Library (LCL)
|
|
|
|
See the file COPYING.modifiedLGPL.txt, included in this distribution,
|
|
for details about the license.
|
|
*****************************************************************************
|
|
}
|
|
|
|
//##apiwiz##sps## // Do not remove, no wizard declaration before this line
|
|
|
|
function CocoaCombineMode(ACombineMode: Integer): TCocoaCombine;
|
|
begin
|
|
case ACombineMode of
|
|
RGN_AND: Result:=cc_And;
|
|
RGN_OR: Result:=cc_Or;
|
|
RGN_XOR: Result:=cc_Xor;
|
|
RGN_DIFF: Result:=cc_Diff;
|
|
else
|
|
Result:=cc_Copy;
|
|
end;
|
|
end;
|
|
|
|
const
|
|
CocoaRegionTypeToWin32Map: array[TCocoaRegionType] of Integer = (
|
|
{ crt_Error } ERROR,
|
|
{ crt_Empty } NULLREGION,
|
|
{ crt_Rectangle } SIMPLEREGION,
|
|
{ crt_Complex } COMPLEXREGION
|
|
);
|
|
|
|
function TCocoaWidgetSet.Arc(DC: HDC; Left, Top, Right, Bottom, angle1,
|
|
angle2: Integer): Boolean;
|
|
begin
|
|
Result:=inherited Arc(DC, Left, Top, Right, Bottom, angle1, angle2);
|
|
end;
|
|
|
|
function TCocoaWidgetSet.AngleChord(DC: HDC; x1, y1, x2, y2, angle1,
|
|
angle2: Integer): Boolean;
|
|
begin
|
|
Result:=inherited AngleChord(DC, x1, y1, x2, y2, angle1, angle2);
|
|
end;
|
|
|
|
function TCocoaWidgetSet.BeginPaint(Handle: hWnd; var PS: TPaintStruct): hdc;
|
|
begin
|
|
Result := inherited BeginPaint(Handle, PS);
|
|
PS.hdc := Result;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.BitBlt(DestDC: HDC; X, Y, Width, Height: Integer;
|
|
SrcDC: HDC; XSrc, YSrc: Integer; Rop: DWORD): Boolean;
|
|
var
|
|
SrcCtx, DestCtx: TCocoaContext;
|
|
Bmp: TCocoaBitmap;
|
|
begin
|
|
SrcCtx := CheckDC(SrcDC);
|
|
DestCtx := CheckDC(DestDC);
|
|
|
|
Result := Assigned(SrcCtx) and Assigned(DestCtx);
|
|
|
|
if not Result then
|
|
Exit;
|
|
|
|
if not (SrcCtx is TCocoaBitmapContext) then
|
|
begin
|
|
DebugLn('StretchMaskBlt Error - invalid source device context ', SrcCtx.ClassName,
|
|
', expected TCocoaBitmapContext!');
|
|
Exit(False);
|
|
end;
|
|
|
|
Bmp := TCocoaBitmapContext(SrcCtx).Bitmap;
|
|
|
|
if not Assigned(Bmp) then
|
|
Exit(False);
|
|
|
|
// Width and Height should not be greater than bitmap width
|
|
Width := Min(Width, Bmp.Width);
|
|
Height := Min(Height, Bmp.Height);
|
|
|
|
Result := DestCtx.StretchDraw(X, Y, Width, Height,
|
|
TCocoaBitmapContext(SrcCtx), XSrc, YSrc, Width, Height,
|
|
nil, 0, 0, Rop);
|
|
end;
|
|
|
|
function TCocoaWidgetSet.ClientToScreen(Handle: HWND; var P: TPoint): Boolean;
|
|
var
|
|
r : NSRect;
|
|
cl : NSView;
|
|
clr : TRect;
|
|
begin
|
|
Result := Handle <> 0;
|
|
|
|
if Result then
|
|
begin
|
|
// must use lclContentView! - it's client view
|
|
cl := NSObject(Handle).lclContentView;
|
|
if HWND(cl) = Handle then
|
|
begin
|
|
// if Handle is lclContentView, then we should check clientRect
|
|
// (i.e. TabControl doesn't have lclContentView, yet its clientRect is adjusted)
|
|
clr := NSObject(Handle).lclClientFrame;
|
|
P.X := P.X + clr.Left;
|
|
P.Y := P.Y + clr.Top;
|
|
end;
|
|
cl.lclLocalToScreen(P.X, P.Y);
|
|
end;
|
|
end;
|
|
|
|
procedure TCocoaWidgetSet.CallDefaultWndHandler(Sender: TObject; var Message);
|
|
var
|
|
hnd : NSObject;
|
|
vw : NSView;
|
|
tb : Boolean;
|
|
ar : Boolean;
|
|
ks : Boolean;
|
|
rt : Boolean;
|
|
const
|
|
WantTab : array [boolean] of integer = (0, DLGC_WANTTAB);
|
|
WantArrow : array [boolean] of integer = (0, DLGC_WANTARROWS);
|
|
WantKeys : array [boolean] of integer = (0, DLGC_WANTALLKEYS);
|
|
begin
|
|
case TLMessage(Message).Msg of
|
|
LM_GETDLGCODE: begin
|
|
hnd := nil;
|
|
if (Sender is TWinControl) then hnd := NSObject(TWinControl(Sender).Handle);
|
|
if not Assigned(hnd) then Exit;
|
|
vw := hnd.lclContentView();
|
|
if Assigned(vw) then
|
|
begin
|
|
tb := false;
|
|
ar := false;
|
|
ks := false;
|
|
rt := false;
|
|
vw.lclExpectedKeys(tb, ar, rt, ks);
|
|
ks := ks or rt; // Return is handled by LCL as part of ALLKey
|
|
TLMessage(Message).Result := TLMessage(Message).Result or WantTab[tb] or WantArrow[ar] or WantKeys[ks];
|
|
end;
|
|
|
|
end;
|
|
else
|
|
TLMessage(Message).Result := 0;
|
|
end;
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: ClipboardFormatToMimeType
|
|
Params: FormatID - A registered format identifier (0 is invalid)
|
|
Returns: The corresponding mime type as string
|
|
------------------------------------------------------------------------------}
|
|
function TCocoaWidgetSet.ClipboardFormatToMimeType(FormatID: TClipboardFormat): string;
|
|
begin
|
|
{$IFDEF VerboseClipboard}
|
|
DebugLn('TCocoaWidgetSet.ClipboardFormatToMimeType FormatID: ' + DbgS(FormatID));
|
|
{$ENDIF}
|
|
Result := fClipboard.FormatToMimeType(FormatID);
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: ClipboardGetData
|
|
Params: ClipboardType - Clipboard type
|
|
FormatID - A registered format identifier (0 is invalid)
|
|
Stream - If format is available, it will be appended to this
|
|
stream
|
|
Returns: If the function succeeds
|
|
------------------------------------------------------------------------------}
|
|
function TCocoaWidgetSet.ClipboardGetData(ClipboardType: TClipboardType;
|
|
FormatID: TClipboardFormat; Stream: TStream): boolean;
|
|
begin
|
|
{$IFDEF VerboseClipboard}
|
|
DebugLn('TCocoaWidgetSet.ClipboardGetData ClipboardType=' +
|
|
ClipboardTypeName[ClipboardType] + ' FormatID: ' + DbgS(FormatID));
|
|
{$ENDIF}
|
|
Result := fClipboard.GetData(ClipboardType, FormatID, Stream);
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: ClipboardGetFormats
|
|
Params: ClipboardType - The type of clipboard operation
|
|
Count - The number of clipboard formats
|
|
List - Pointer to an array of supported formats
|
|
(you must free it yourself)
|
|
Returns: If the function succeeds
|
|
------------------------------------------------------------------------------}
|
|
|
|
function TCocoaWidgetSet.ClipboardGetFormats(ClipboardType: TClipboardType;
|
|
var Count: integer; var List: PClipboardFormat): boolean;
|
|
var
|
|
fmt: TDynClipboardFormatArray;
|
|
begin
|
|
{$IFDEF VerboseClipboard}
|
|
DebugLn('TCocoaWidgetSet.ClipboardGetFormats ClipboardType' +
|
|
ClipboardTypeName[ClipboardType]);
|
|
{$ENDIF}
|
|
fmt := nil;
|
|
Result := fClipboard.GetFormats(ClipboardType, Count, fmt);
|
|
if Count > 0 then begin
|
|
GetMem(List, Count * sizeof(TClipboardFormat));
|
|
System.Move(fmt[0], List^, Count * sizeof(TClipboardFormat));
|
|
end else
|
|
List := nil;
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: ClipboardGetOwnerShip
|
|
Params: ClipboardType - Type of clipboard
|
|
OnRequestProc - TClipboardRequestEvent is defined in LCLType.pp
|
|
If OnRequestProc is nil the onwership will end.
|
|
FormatCount - Number of formats
|
|
Formats - Array of TClipboardFormat. The supported formats the
|
|
owner provides.
|
|
|
|
Returns: If the function succeeds
|
|
|
|
Sets the supported formats and requests ownership for the clipboard.
|
|
The OnRequestProc is used to get the data from the LCL and to put it on the
|
|
clipboard.
|
|
If someone else requests the ownership, the OnRequestProc will be executed
|
|
with the invalid FormatID 0 to notify the old owner of the lost of ownership.
|
|
------------------------------------------------------------------------------}
|
|
function TCocoaWidgetSet.ClipboardGetOwnerShip(ClipboardType: TClipboardType;
|
|
OnRequestProc: TClipboardRequestEvent; FormatCount: integer;
|
|
Formats: PClipboardFormat): boolean;
|
|
begin
|
|
{$IFDEF VerboseClipboard}
|
|
DebugLn('TCocoaWidgetSet.ClipboardGetOwnerShip ClipboardType=' +
|
|
ClipboardTypeName[ClipboardType] + ' FormatCount: ' + DbgS(FormatCount));
|
|
{$ENDIF}
|
|
Result := fClipboard.GetOwnership(ClipboardType, OnRequestProc, FormatCount, Formats);
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: ClipboardRegisterFormat
|
|
Params: AMimeType - A string (usually a MIME type) identifying a new format
|
|
type to register
|
|
Returns: The registered Format identifier (TClipboardFormat)
|
|
------------------------------------------------------------------------------}
|
|
function TCocoaWidgetSet.ClipboardRegisterFormat(const AMimeType: string): TClipboardFormat;
|
|
begin
|
|
Result := fClipboard.RegisterFormat(AMimeType);
|
|
{$IFDEF VerboseClipboard}
|
|
DebugLn('TCocoaWidgetSet.ClipboardRegisterFormat AMimeType=' + AMimeType
|
|
+ ' Result='+DbgS(Result));
|
|
{$ENDIF}
|
|
end;
|
|
|
|
function TCocoaWidgetSet.ClipboardFormatNeedsNullByte(
|
|
const AFormat: TPredefinedClipboardFormat): Boolean;
|
|
begin
|
|
Result := False
|
|
end;
|
|
|
|
function TCocoaWidgetSet.CombineRgn(Dest, Src1, Src2: HRGN; fnCombineMode: Longint): Longint;
|
|
begin
|
|
Result := LCLType.Error;
|
|
if (Dest = 0) or (Src1 = 0) or (fnCombineMode<RGN_AND) or (fnCombineMode>RGN_COPY) then Exit;
|
|
if (fnCombineMode <> RGN_COPY) and (Src2 = 0) then Exit;
|
|
|
|
Result := CocoaRegionTypeToWin32Map[TCocoaRegion(Dest).CombineWith(TCocoaRegion(Src1), cc_Copy)];
|
|
|
|
if fnCombineMode <> RGN_COPY then
|
|
Result := CocoaRegionTypeToWin32Map[TCocoaRegion(Dest).CombineWith(TCocoaRegion(Src2), CocoaCombineMode(fnCombineMode))];
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: CreateBitmap
|
|
Params: Width - Bitmap width, in pixels
|
|
Height - Bitmap height, in pixels
|
|
Planes - Number of color planes
|
|
BitCount - Number of bits required to identify a color (TODO)
|
|
BitmapBits - Pointer to array containing color data (TODO)
|
|
Returns: A handle to a bitmap
|
|
|
|
Creates a bitmap with the specified width, height and color format
|
|
------------------------------------------------------------------------------}
|
|
function TCocoaWidgetSet.CreateBitmap(Width, Height: Integer;
|
|
Planes, BitCount: Longint; BitmapBits: Pointer): HBITMAP;
|
|
var
|
|
bmpType: TCocoaBitmapType;
|
|
begin
|
|
// WORKAROUND: force context supported depths
|
|
if BitmapBits = nil then
|
|
begin
|
|
if BitCount = 24 then BitCount := 32;
|
|
// if BitCount = 1 then BitCount := 8;
|
|
end;
|
|
|
|
case BitCount of
|
|
1: bmpType := cbtMono;
|
|
8: bmpType := cbtGray;
|
|
32: bmpType := cbtARGB;
|
|
else
|
|
bmpType := cbtRGB;
|
|
end;
|
|
|
|
// winapi Bitmaps are on a word boundary
|
|
Result := HBITMAP(TCocoaBitmap.Create(Width, Height, BitCount, BitCount, cbaWord, bmpType, BitmapBits));
|
|
end;
|
|
|
|
function TCocoaWidgetSet.CreateBrushIndirect(const LogBrush: TLogBrush): HBRUSH;
|
|
begin
|
|
Result := HBrush(TCocoaBrush.Create(LogBrush));
|
|
end;
|
|
|
|
function TCocoaWidgetSet.CreateCaret(Handle: HWND; Bitmap: hBitmap; Width,
|
|
Height: Integer): Boolean;
|
|
begin
|
|
Result := (Handle <> 0);
|
|
if Result then
|
|
Result := CocoaCaret.CreateCaret(NSView(Handle).lclContentView, Bitmap, Width, Height)
|
|
end;
|
|
|
|
function TCocoaWidgetSet.CreateCompatibleBitmap(DC: HDC; Width, Height: Integer): HBITMAP;
|
|
begin
|
|
Result := HBITMAP(TCocoaBitmap.Create(Width, Height, 32, 32, cbaDQWord, cbtARGB, nil));
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: CreateCompatibleDC
|
|
Params: DC - Handle to memory device context
|
|
Returns: Handle to a memory device context
|
|
|
|
Creates a memory device context (DC) compatible with the specified device
|
|
------------------------------------------------------------------------------}
|
|
function TCocoaWidgetSet.CreateCompatibleDC(DC: HDC): HDC;
|
|
begin
|
|
Result := HDC(TCocoaBitmapContext.Create);
|
|
end;
|
|
|
|
//todo:
|
|
//function TCocoaWidgetSet.CreateEllipticRgn(p1, p2, p3, p4: Integer): HRGN;
|
|
//begin
|
|
//end;
|
|
|
|
function TCocoaWidgetSet.CreateFontIndirect(const LogFont: TLogFont): HFONT;
|
|
begin
|
|
Result := HFont(TCocoaFont.Create(LogFont, LogFont.lfFaceName));
|
|
end;
|
|
|
|
function TCocoaWidgetSet.CreateFontIndirectEx(const LogFont: TLogFont;
|
|
const LongFontName: string): HFONT;
|
|
begin
|
|
Result := HFont(TCocoaFont.Create(LogFont, LongFontName));
|
|
end;
|
|
|
|
class function TCocoaWidgetSet.Create32BitAlphaBitmap(ABitmap, AMask: TCocoaBitmap): TCocoaBitmap;
|
|
var
|
|
ARawImage: TRawImage;
|
|
Desc: TRawImageDescription absolute ARawimage.Description;
|
|
|
|
ImgHandle, ImgMaskHandle: HBitmap;
|
|
ImagePtr: PRawImage;
|
|
DevImage: TRawImage;
|
|
DevDesc: TRawImageDescription;
|
|
SrcImage, DstImage: TLazIntfImage;
|
|
W, H: Integer;
|
|
begin
|
|
Result := nil;
|
|
|
|
if not LCLIntf.RawImage_FromBitmap(ARawImage, HBITMAP(ABitmap), HBITMAP(AMask)) then
|
|
Exit;
|
|
|
|
ImgMaskHandle := 0;
|
|
|
|
W := Desc.Width;
|
|
if W < 1 then W := 1;
|
|
H := Desc.Height;
|
|
if H < 1 then H := 1;
|
|
|
|
QueryDescription(DevDesc, [riqfRGB, riqfAlpha], W, H);
|
|
|
|
if DevDesc.IsEqual(Desc)
|
|
then begin
|
|
// image is compatible, so use it
|
|
DstImage := nil;
|
|
ImagePtr := @ARawImage;
|
|
end
|
|
else begin
|
|
// create compatible copy
|
|
SrcImage := TLazIntfImage.Create(ARawImage, False);
|
|
DstImage := TLazIntfImage.Create(0,0,[]);
|
|
DstImage.DataDescription := DevDesc;
|
|
DstImage.CopyPixels(SrcImage);
|
|
SrcImage.Free;
|
|
DstImage.GetRawImage(DevImage);
|
|
ImagePtr := @DevImage;
|
|
end;
|
|
|
|
try
|
|
if not LCLIntf.RawImage_CreateBitmaps(ImagePtr^, ImgHandle, ImgMaskHandle, True) then Exit;
|
|
|
|
Result := TCocoaBitmap(ImgHandle);
|
|
finally
|
|
ARawImage.FreeData;
|
|
DstImage.Free;
|
|
end;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.CreateIconIndirect(IconInfo: PIconInfo): HICON;
|
|
var
|
|
ABitmap: TCocoaBitmap;
|
|
begin
|
|
Result := 0;
|
|
if IconInfo^.hbmColor = 0 then Exit;
|
|
|
|
ABitmap := Create32BitAlphaBitmap(TCocoaBitmap(IconInfo^.hbmColor), TCocoaBitmap(IconInfo^.hbmMask));
|
|
|
|
if IconInfo^.fIcon then
|
|
Result := HICON(ABitmap)
|
|
else
|
|
Result := HICON(TCocoaCursor.CreateFromBitmap(ABitmap, GetNSPoint(IconInfo^.xHotSpot, IconInfo^.yHotSpot)));
|
|
end;
|
|
|
|
function TCocoaWidgetSet.CreatePenIndirect(const LogPen: TLogPen): HPEN;
|
|
begin
|
|
Result := HPen(TCocoaPen.Create(LogPen));
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: CreatePolygonRgn
|
|
Params: Points - Pointer to array of polygon points
|
|
NumPts - Number of points passed
|
|
FillMode - Filling mode
|
|
Returns: The new polygonal region
|
|
|
|
Creates a new polygonal region from the specified points
|
|
------------------------------------------------------------------------------}
|
|
function TCocoaWidgetSet.CreatePolygonRgn(Points: PPoint; NumPts: Integer;
|
|
FillMode: integer): HRGN;
|
|
begin
|
|
{$IFDEF VerboseWinAPI}
|
|
DebugLn('TCocoaWidgetSet.CreatePolygonRgn NumPts: ' + DbgS(NumPts) +
|
|
' FillMode: ' + DbgS(FillMode));
|
|
{$ENDIF}
|
|
|
|
Result := HRGN(TCocoaRegion.Create(Points, NumPts, FillMode=ALTERNATE));
|
|
end;
|
|
|
|
function TCocoaWidgetSet.CreateRectRgn(X1, Y1, X2, Y2: Integer): HRGN;
|
|
begin
|
|
{$IFDEF VerboseWinAPI}
|
|
DebugLn('TCocoaWidgetSet.CreateRectRgn R: ' + DbgS(Classes.Rect(X1, Y1, X2, Y2)));
|
|
{$ENDIF}
|
|
|
|
Result := HRGN(TCocoaRegion.Create(X1, Y1, X2, Y2));
|
|
end;
|
|
|
|
function TCocoaWidgetSet.DeleteObject(GDIObject: HGDIOBJ): Boolean;
|
|
const
|
|
SName = 'TCocoaWidgetSet.DeleteObject';
|
|
var
|
|
gdi: TCocoaGDIObject;
|
|
begin
|
|
Result := False;
|
|
if GDIObject = 0 then
|
|
Exit(True);
|
|
|
|
gdi := CheckGDIOBJ(GdiObject);
|
|
|
|
if not Assigned(gdi) then
|
|
begin
|
|
DebugLn(SName, ' Error - GDIObject: ' + DbgSName(gdi) + ' is unknown!');
|
|
Exit;
|
|
end;
|
|
|
|
if gdi.Global then
|
|
begin
|
|
// global brushes can be cached, so just exit here since we will free the resource later on
|
|
//DebugLn(SName, ' Error - GDIObject: ' + DbgSName(gdi) + ' is global!');
|
|
Exit;
|
|
end;
|
|
|
|
if gdi.RefCount <> 1 then
|
|
begin
|
|
DebugLn(SName, 'Error - GDIObject: ' + DbgSName(gdi) + ' is still selected!');
|
|
Exit;
|
|
end;
|
|
|
|
gdi.Destroy;
|
|
Result := True;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.DestroyCaret(Handle: HWND): Boolean;
|
|
begin
|
|
Result := CocoaCaret.DestroyCaret( NSView(Handle).lclContentView );
|
|
end;
|
|
|
|
function TCocoaWidgetSet.DestroyIcon(Handle: HICON): Boolean;
|
|
var
|
|
Ico: TObject;
|
|
begin
|
|
Result := Handle <> 0;
|
|
if not Result then
|
|
Exit;
|
|
Ico := TObject(Handle);
|
|
Result := (Ico is TCocoaBitmap) or (Ico is TCocoaCursor);
|
|
if Result then
|
|
Ico.Destroy;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.DPtoLP(DC: HDC; var Points; Count: Integer): BOOL;
|
|
var
|
|
ctx: TCocoaContext;
|
|
P: PPoint;
|
|
begin
|
|
Result := False;
|
|
ctx := CheckDC(DC);
|
|
if not Assigned(ctx) then Exit;
|
|
P := @Points;
|
|
with ctx.GetLogicalOffset do
|
|
while Count > 0 do
|
|
begin
|
|
Dec(Count);
|
|
dec(P^.X, X);
|
|
dec(P^.Y, Y);
|
|
inc(P);
|
|
end;
|
|
Result := True;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.DrawFocusRect(DC: HDC; const Rect: TRect): boolean;
|
|
var
|
|
ctx: TCocoaContext;
|
|
p: Integer;
|
|
pn: TCocoaPen;
|
|
opn: TCocoaPen;
|
|
r: TRect;
|
|
begin
|
|
|
|
ctx := CheckDC(DC);
|
|
Result := Assigned(ctx);
|
|
if Result then
|
|
begin
|
|
//ctx.DrawFocusRect(Rect);
|
|
|
|
// drawing in Windows compatible XOR style
|
|
|
|
p:=ctx.ROP2;
|
|
opn:=ctx.Pen;
|
|
pn:=TCocoaPen.Create(clDkGray, psSolid, true, 2, pmCopy, pecFlat, pjsRound, false );
|
|
try
|
|
ctx.Pen:=pn;
|
|
ctx.ROP2:=R2_NOTXORPEN;
|
|
ctx.Pen.Apply(ctx, true);
|
|
r:=Rect;
|
|
dec(r.Right);
|
|
dec(r.Bottom);
|
|
ctx.Frame(r);
|
|
finally
|
|
ctx.ROP2:=p;
|
|
ctx.Pen:=opn;
|
|
pn.Free;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure DrawEdgeRect(dst: TCocoaContext; const r: TRect; flags: Cardinal;
|
|
LTColor, BRColor: TColor);
|
|
begin
|
|
dst.Pen.SetColor(LTColor, true);
|
|
dst.Pen.Apply(dst);
|
|
if flags and BF_LEFT > 0 then
|
|
begin
|
|
dst.MoveTo(r.Left, r.Bottom);
|
|
dst.LineTo(r.Left, r.Top);
|
|
end;
|
|
if flags and BF_TOP > 0 then
|
|
begin
|
|
dst.MoveTo(r.Left, r.Top);
|
|
dst.LineTo(r.Right, r.Top);
|
|
end;
|
|
|
|
dst.Pen.SetColor(BRColor, true);
|
|
dst.Pen.Apply(dst);
|
|
if flags and BF_RIGHT > 0 then
|
|
begin
|
|
dst.MoveTo(r.Right, r.Top);
|
|
dst.LineTo(r.Right, r.Bottom);
|
|
end;
|
|
if flags and BF_BOTTOM > 0 then
|
|
begin
|
|
dst.MoveTo(r.Right, r.Bottom);
|
|
// there's a missing pixel. Seems like it's accumulating an offset
|
|
dst.LineTo(r.Left-1, r.Bottom);
|
|
end;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.DrawEdge(DC: HDC; var Rect: TRect; edge: Cardinal;
|
|
grfFlags: Cardinal): Boolean;
|
|
var
|
|
ctx: TCocoaContext;
|
|
r: TRect;
|
|
keepPen : TCocoaPen;
|
|
edgePen : TCocoaPen;
|
|
keepBrush : TCocoaBrush;
|
|
edgeBrush : TCocoaBrush;
|
|
const
|
|
OutLT = cl3DLight; // the next to hilight
|
|
OutBR = cl3DDkShadow; // the darkest (almost black)
|
|
InnLT = cl3DHiLight; // the lightest (almost white)
|
|
InnBR = cl3DShadow; // darker than light, lighter than dark shadow
|
|
begin
|
|
ctx := CheckDC(DC);
|
|
Result := Assigned(ctx);
|
|
if not Result then Exit;
|
|
|
|
keepPen := ctx.Pen;
|
|
keepBrush := ctx.Brush;
|
|
try
|
|
edgePen := TCocoaPen.Create($FFFFFF, psSolid, false, 1, pmCopy, pecRound, pjsRound);
|
|
edgeBrush := TCocoaBrush.Create(NSColor.whiteColor, false);
|
|
edgeBrush.Solid := false;
|
|
ctx.Pen := edgePen;
|
|
ctx.Brush := edgeBrush;
|
|
|
|
r := Rect;
|
|
if (edge and BDR_OUTER > 0) then
|
|
begin
|
|
if edge and BDR_RAISEDOUTER > 0 then
|
|
DrawEdgeRect(ctx, r, grfFlags, OutLT, OutBR)
|
|
else
|
|
DrawEdgeRect(ctx, r, grfFlags, InnBR, InnLT);
|
|
InflateRect(r, -1, -1);
|
|
end;
|
|
|
|
if (edge and BDR_INNER > 0) then
|
|
begin
|
|
if edge and BDR_RAISEDINNER > 0 then
|
|
DrawEdgeRect(ctx, r, grfFlags, InnLT, InnBR)
|
|
else
|
|
DrawEdgeRect(ctx, r, grfFlags, OutBR, OutLT);
|
|
end;
|
|
|
|
finally
|
|
ctx.Pen := keepPen;
|
|
ctx.Brush := keepBrush;
|
|
edgeBrush.Free;
|
|
edgePen.Free;
|
|
end;
|
|
|
|
Result := true;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.Ellipse(DC: HDC; x1, y1, x2, y2: Integer): Boolean;
|
|
var
|
|
ctx: TCocoaContext;
|
|
begin
|
|
ctx := CheckDC(DC);
|
|
Result := Assigned(ctx);
|
|
if Result then
|
|
ctx.Ellipse(x1, y1, x2, y2);
|
|
end;
|
|
|
|
function TCocoaWidgetSet.EnableWindow(hWnd: HWND; bEnable: Boolean): Boolean;
|
|
var
|
|
obj : NSObject;
|
|
begin
|
|
Result := hWnd <> 0;
|
|
if Result then
|
|
begin
|
|
obj := NSObject(hWnd);
|
|
|
|
// The following check is actually a hack. LCL enables all windows disabled
|
|
// during ShowModal form. No matter if the windows are on the stack of the modality or not.
|
|
// Since Cocoa doesn't do much of the "modal" control over the windows
|
|
// (runWindowModal isn't used... maybe it should be?)
|
|
// It's possible that windows "disabled" by a another model window would be
|
|
// re-enabled. This check verifies that only a window on the top of the modal stack
|
|
// will be brought back active... what about other windows?
|
|
if bEnable and isModalSession and (obj.isKindOfClass(TCocoaWindowContent)) then begin
|
|
if not (TCocoaWindowContent(obj).isembedded)
|
|
and not isTopModalWin(TCocoaWindowContent(obj).window) then Exit;
|
|
end;
|
|
obj.lclSetEnabled(bEnable);
|
|
|
|
if (CaptureControl <> 0)
|
|
and (not bEnable)
|
|
and (obj.isKindOfClass(NSView))
|
|
and NSViewIsLCLEnabled(NSView(obj)) then
|
|
ReleaseCapture
|
|
end;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.EndPaint(Handle: hwnd; var PS: TPaintStruct): Integer;
|
|
begin
|
|
Result:=inherited EndPaint(Handle, PS);
|
|
end;
|
|
|
|
function TCocoaWidgetSet.EnumFontFamiliesEx(DC: HDC; lpLogFont: PLogFont;
|
|
Callback: FontEnumExProc; Lparam: LParam; Flags: dword): longint;
|
|
var
|
|
fname: NSString;
|
|
ELogFont: TEnumLogFontEx;
|
|
Metric: TNewTextMetricEx;
|
|
FontName: AnsiString;
|
|
begin
|
|
Result := 0;
|
|
if not Assigned(Callback) then Exit;
|
|
for fname in NSFontManager.sharedFontManager.availableFontFamilies do
|
|
begin
|
|
try
|
|
FontName := NSStringToString(fname);
|
|
FillChar(ELogFont, SizeOf(ELogFont), #0);
|
|
FillChar(Metric, SizeOf(Metric), #0);
|
|
ELogFont.elfLogFont.lfFaceName := FontName;
|
|
ELogFont.elfFullName := FontName;
|
|
//todo: read the data from all fonts of the fontfamily
|
|
Result := CallBack(ELogFont, Metric, TRUETYPE_FONTTYPE, lparam);
|
|
if Result = 0 then Break;
|
|
except
|
|
Break;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
// According to the documentation of NSScreen.screen It's recommended
|
|
// not to cache NSScreen objects stored in the array. As those might change.
|
|
// However, according to the same documentation, the objects can change
|
|
// only with a notificatio sent out. BUT while using a macincloud (remote desktop)
|
|
// services, it was identified that NSScreen object CAN change without any notification.
|
|
// So, instead of passing NSScreen as HMonitor, only INDEX+1 in NSScreen.screen
|
|
// is used.
|
|
function IndexToHMonitor(i: NSUInteger): HMonitor;
|
|
begin
|
|
if i = NSIntegerMax then Result := 0
|
|
else Result := i + 1;
|
|
end;
|
|
|
|
function HMonitorToIndex(h: HMonitor): NSUInteger;
|
|
begin
|
|
if h = 0 then Result := NSIntegerMax
|
|
else Result := NSUInteger(h)-1;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.EnumDisplayMonitors(hdc: HDC; lprcClip: PRect;
|
|
lpfnEnum: MonitorEnumProc; dwData: LPARAM): LongBool;
|
|
var
|
|
i: NSUInteger;
|
|
cnt: NSUInteger;
|
|
begin
|
|
Result := True;
|
|
cnt := NSScreen.screens.count;
|
|
if cnt = 0 then
|
|
begin
|
|
Result := false;
|
|
Exit;
|
|
end;
|
|
for i := 0 to NSScreen.screens.count - 1 do
|
|
begin
|
|
Result := Result and lpfnEnum(IndexToHMonitor(i), 0, nil, dwData);
|
|
if not Result then break;
|
|
end;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.ExcludeClipRect(dc: hdc;
|
|
Left, Top, Right, Bottom : Integer) : Integer;
|
|
var
|
|
RRGN : HRGN;
|
|
R : TRect;
|
|
begin
|
|
// there seems to be a bug in TWidgetset ExcludeClipRect.
|
|
// as it doesn't use LPtoDP() (as IntersectClipRect does).
|
|
// Fixing the problem here.
|
|
R := Types.Rect(Left, Top, Right, Bottom);
|
|
LPtoDP(DC, R, 2);
|
|
|
|
If DCClipRegionValid(DC) then begin
|
|
//DebugLn('TWidgetSet.ExcludeClipRect A DC=',DbgS(DC),' Rect=',Left,',',Top,',',Right,',',Bottom);
|
|
// create the rectangle region, that should be excluded
|
|
RRGN := CreateRectRgn(R.Left,R.Top,R.Right,R.Bottom);
|
|
Result := ExtSelectClipRGN(DC, RRGN, RGN_DIFF);
|
|
//DebugLn('TWidgetSet.ExcludeClipRect B Result=',Result);
|
|
DeleteObject(RRGN);
|
|
end else
|
|
Result:=ERROR;
|
|
end;
|
|
|
|
|
|
function TCocoaWidgetSet.ExtSelectClipRGN(dc: hdc; rgn: hrgn; Mode: Longint): Integer;
|
|
var
|
|
ctx: TCocoaContext;
|
|
begin
|
|
ctx := CheckDC(DC);
|
|
if Assigned(ctx) then
|
|
Result := CocoaRegionTypeToWin32Map[ctx.SetClipRegion(TCocoaRegion(rgn), CocoaCombineMode(Mode))]
|
|
else
|
|
Result := ERROR;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.ExtCreatePen(dwPenStyle, dwWidth: DWord;
|
|
const lplb: TLogBrush; dwStyleCount: DWord; lpStyle: PDWord): HPEN;
|
|
begin
|
|
Result := HPEN(TCocoaPen.Create(dwPenStyle, dwWidth, lplb, dwStyleCount, lpStyle));
|
|
end;
|
|
|
|
function TCocoaWidgetSet.ExtTextOut(DC: HDC; X, Y: Integer; Options: Longint;
|
|
Rect: PRect; Str: PChar; Count: Longint; Dx: PInteger): Boolean;
|
|
var
|
|
ctx: TCocoaContext;
|
|
begin
|
|
ctx := CheckDC(DC);
|
|
Result := Assigned(ctx);
|
|
if Assigned(ctx) then
|
|
ctx.TextOut(X, Y, Options, Rect, Str, Count, Dx);
|
|
end;
|
|
|
|
function TCocoaWidgetSet.FillRect(DC: HDC; const Rect: TRect; Brush: HBRUSH): Boolean;
|
|
var
|
|
ctx: TCocoaContext;
|
|
br: TCocoaGDIObject;
|
|
begin
|
|
ctx := CheckDC(DC);
|
|
br := CheckGDIOBJ(Brush);
|
|
Result := Assigned(ctx) and (not Assigned(br) or (br is TCocoaBrush));
|
|
if not Result then Exit;
|
|
|
|
ctx.Rectangle(Rect.Left, Rect.Top, Rect.Right, Rect.Bottom, True, TCocoaBrush(br));
|
|
end;
|
|
|
|
function TCocoaWidgetSet.FillRgn(DC: HDC; RegionHnd: HRGN; hbr: HBRUSH): Bool;
|
|
var
|
|
OldRgn: TCocoaRegion;
|
|
R: TRect;
|
|
Clipped: Boolean;
|
|
ctx: TCocoaContext;
|
|
br: TCocoaGDIObject;
|
|
I: Integer;
|
|
begin
|
|
ctx := CheckDC(DC);
|
|
br := CheckGDIOBJ(hbr);
|
|
Result := Assigned(ctx) and (not Assigned(br) or (br is TCocoaBrush));
|
|
if not Result then Exit;
|
|
|
|
Clipped := ctx.Clipped;
|
|
I := ctx.SaveDC;
|
|
if Clipped then
|
|
OldRgn := TCocoaRegion.CreateDefault;
|
|
try
|
|
if Clipped then
|
|
ctx.CopyClipRegion(OldRgn);
|
|
if SelectClipRgn(DC, RegionHnd) <> ERROR then
|
|
begin
|
|
R := TCocoaRegion(RegionHnd).GetBounds;
|
|
with R do
|
|
ctx.Rectangle(Left, Top, Right, Bottom, True, TCocoaBrush(br));
|
|
if Clipped then
|
|
SelectClipRgn(DC, HRGN(OldRgn));
|
|
Result := True;
|
|
end;
|
|
finally
|
|
if Clipped then
|
|
OldRgn.Free;
|
|
ctx.RestoreDC(I);
|
|
end;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.Frame3d(DC: HDC; var ARect: TRect;
|
|
const FrameWidth: integer; const Style: TBevelCut): Boolean;
|
|
var
|
|
ctx: TCocoaContext;
|
|
begin
|
|
ctx := CheckDC(DC);
|
|
Result := Assigned(ctx) and (FrameWidth > 0);
|
|
if Result then
|
|
ctx.Frame3d(ARect, FrameWidth, Style);
|
|
end;
|
|
|
|
function TCocoaWidgetSet.FrameRect(DC: HDC; const ARect: TRect; hBr: HBRUSH): Integer;
|
|
var
|
|
ctx: TCocoaContext;
|
|
begin
|
|
ctx := CheckDC(DC);
|
|
if Assigned(ctx) then
|
|
begin
|
|
ctx.FrameRect(ARect, TCocoaBrush(hBr));
|
|
Result := -1;
|
|
end
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.GetActiveWindow: HWND;
|
|
var
|
|
wn : NSWindow;
|
|
begin
|
|
// return the currect application active window
|
|
wn := NSApp.keyWindow;
|
|
if not Assigned(wn) then Result := 0
|
|
else Result := HWND(wn.contentView);
|
|
end;
|
|
|
|
function TCocoaWidgetSet.GetBkColor(DC: HDC): TColorRef;
|
|
var
|
|
ctx: TCocoaContext;
|
|
begin
|
|
ctx := CheckDC(DC);
|
|
if Assigned(ctx) then
|
|
Result := ctx.BkColor
|
|
else
|
|
Result := CLR_INVALID;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.GetCapture: HWND;
|
|
begin
|
|
Result:=FCaptureControl;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.GetCaretPos(var lpPoint: TPoint): Boolean;
|
|
begin
|
|
Result := CocoaCaret.GetCaretPos(lpPoint);
|
|
end;
|
|
|
|
function TCocoaWidgetSet.GetCaretRespondToFocus(handle: HWND;
|
|
var ShowHideOnFocus: boolean): Boolean;
|
|
begin
|
|
Result := inherited GetCaretRespondToFocus(handle, ShowHideOnFocus);
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
function ShowWindow(hWnd: HWND; nCmdShow: Integer): Boolean;
|
|
|
|
nCmdShow:
|
|
SW_SHOWNORMAL, SW_MINIMIZE, SW_SHOWMAXIMIZED
|
|
------------------------------------------------------------------------------}
|
|
function TCocoaWidgetSet.ShowWindow(hWnd: HWND; nCmdShow: Integer): Boolean;
|
|
var
|
|
win: NSWindow;
|
|
lCocoaWin: TCocoaWindow = nil;
|
|
lWinContent: TCocoaWindowContent = nil;
|
|
disableFS : Boolean;
|
|
const
|
|
NSFullScreenWindowMask = 1 shl 14;
|
|
|
|
begin
|
|
Result:=true;
|
|
{$ifdef VerboseCocoaWinAPI}
|
|
DebugLn('TCocoaWidgetSet.ShowWindow');
|
|
{$endif}
|
|
|
|
// for regular controls (non-window or embedded window, acting as a control)
|
|
if (not NSObject(hWnd).isKindOfClass(TCocoaWindowContent)) or (TCocoaWindowContent(hWnd).isembedded) then
|
|
begin
|
|
NSObject(hWnd).lclSetVisible(nCmdSHow <> SW_HIDE);
|
|
Exit;
|
|
end;
|
|
|
|
// for windows
|
|
lWinContent := TCocoaWindowContent(hWnd);
|
|
|
|
//todo: should it be lclOwnWindow?
|
|
if Assigned(lWinContent.fswin) then
|
|
win := lWinContent.fswin
|
|
else
|
|
win := NSWindow(lWinContent.window);
|
|
|
|
disableFS := false;
|
|
if win.isKindOfClass(TCocoaWindow) then
|
|
begin
|
|
lCocoaWin := TCocoaWindow(win);
|
|
disableFS := Assigned(lCocoaWin) and (lCocoaWin.lclIsFullScreen) and (nCmdShow <> SW_SHOWFULLSCREEN);
|
|
end;
|
|
|
|
if disableFS and Assigned(lCocoaWin) then
|
|
lCocoaWin.lclSwitchFullScreen(false);
|
|
|
|
case nCmdShow of
|
|
SW_SHOW, SW_SHOWNORMAL:
|
|
win.orderFront(nil);
|
|
SW_HIDE:
|
|
win.orderOut(nil);
|
|
SW_MINIMIZE:
|
|
win.miniaturize(nil);
|
|
SW_MAXIMIZE:
|
|
win.zoom(nil);
|
|
SW_SHOWFULLSCREEN:
|
|
if Assigned(lCocoaWin) then
|
|
lCocoaWin.lclSwitchFullScreen(true);
|
|
end;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.StretchBlt(DestDC: HDC; X, Y, Width, Height: Integer;
|
|
SrcDC: HDC; XSrc, YSrc, SrcWidth, SrcHeight: Integer; ROp: Cardinal
|
|
): Boolean;
|
|
begin
|
|
Result := StretchMaskBlt(DestDC, X, Y, Width, Height, SrcDC, XSrc, YSrc,
|
|
SrcWidth, SrcHeight, 0, 0, 0, Rop);
|
|
end;
|
|
|
|
function TCocoaWidgetSet.StretchMaskBlt(DestDC: HDC; X, Y, Width,
|
|
Height: Integer; SrcDC: HDC; XSrc, YSrc, SrcWidth, SrcHeight: Integer;
|
|
Mask: HBITMAP; XMask, YMask: Integer; Rop: DWORD): Boolean;
|
|
var
|
|
SrcCtx, DestCtx: TCocoaContext;
|
|
begin
|
|
DestCtx := CheckDC(DestDC);
|
|
SrcCtx := CheckDC(SrcDC);
|
|
|
|
Result := Assigned(DestCtx) and Assigned(SrcCtx);
|
|
|
|
if not Result then
|
|
Exit;
|
|
|
|
if not (SrcCtx is TCocoaBitmapContext) then
|
|
begin
|
|
DebugLn('StretchMaskBlt Error - invalid source device context ', SrcCtx.ClassName,
|
|
', expected TCocoaBitmapContext!');
|
|
Exit;
|
|
end;
|
|
|
|
Result := DestCtx.StretchDraw(X, Y, Width, Height,
|
|
TCocoaBitmapContext(SrcCtx), XSrc, YSrc, SrcWidth, SrcHeight,
|
|
TCocoaBitmap(Mask), XMask, YMask, Rop);
|
|
end;
|
|
|
|
function TCocoaWidgetSet.SystemParametersInfo(uiAction: DWord; uiParam: DWord;
|
|
pvParam: Pointer; fWinIni: DWord): LongBool;
|
|
begin
|
|
Result := True;
|
|
case uiAction of
|
|
SPI_GETWHEELSCROLLLINES: PDword(pvPAram)^ := 3;
|
|
SPI_GETWORKAREA:
|
|
begin
|
|
NSToLCLRect(NSScreen(NSScreen.screens.objectAtIndex(0)).visibleFrame
|
|
, NSScreenZeroHeight
|
|
, TRect(pvParam^));
|
|
end;
|
|
else
|
|
Result := False;
|
|
end
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: GetWindowRect
|
|
Params: Handle - Handle of window
|
|
Rect - Record for window coordinates
|
|
Returns: if the function succeeds, the return value is nonzero; if the
|
|
function fails, the return value is zero
|
|
|
|
Retrieves the screen bounding rectangle of the specified window
|
|
------------------------------------------------------------------------------}
|
|
function TCocoaWidgetSet.GetWindowRect(Handle: hwnd; var ARect: TRect): Integer;
|
|
var
|
|
dx, dy: Integer;
|
|
begin
|
|
if Handle <> 0 then
|
|
begin
|
|
ARect := NSObject(Handle).lclFrame;
|
|
if not NSObject(Handle).isKindOfClass_(NSWindow) then
|
|
begin
|
|
dx := 0;
|
|
dy := 0;
|
|
NSObject(Handle).lclLocalToScreen(dx, dy);
|
|
MoveRect(ARect, dx, dy);
|
|
end;
|
|
Result := 1;
|
|
end else
|
|
Result := 0;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.IsWindowEnabled(Handle: HWND): boolean;
|
|
begin
|
|
if Handle<>0
|
|
then Result:=NSObject(Handle).lclIsEnabled
|
|
else Result:=False;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.IsWindowVisible(Handle: HWND): boolean;
|
|
begin
|
|
if Handle<>0
|
|
then Result:=NSObject(Handle).lclIsVisible
|
|
else Result:=False;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.GetClientBounds(handle : HWND; var ARect : TRect) : Boolean;
|
|
begin
|
|
Result := Handle <> 0;
|
|
if Result then
|
|
ARect := NSObject(handle).lclClientFrame;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.GetClientRect(handle : HWND; var ARect : TRect) : Boolean;
|
|
begin
|
|
Result := Handle <> 0;
|
|
if Result then
|
|
begin
|
|
ARect := NSObject(handle).lclClientFrame;
|
|
OffsetRect(ARect, -ARect.Left, -ARect.Top);
|
|
end;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.GetClipBox(DC: hDC; lpRect: PRect): Longint;
|
|
var
|
|
ctx: TCocoaContext;
|
|
begin
|
|
ctx := CheckDC(DC);
|
|
if Assigned(ctx) and Assigned(lpRect) then
|
|
begin
|
|
lpRect^ := ctx.GetClipRect;
|
|
Result := COMPLEXREGION;
|
|
end
|
|
else
|
|
Result := ERROR;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.GetClipRGN(DC: hDC; RGN: hRGN): Longint;
|
|
var
|
|
ctx: TCocoaContext;
|
|
begin
|
|
ctx := CheckDC(DC);
|
|
if Assigned(ctx) and (RGN <> 0) then
|
|
Result := CocoaRegionTypeToWin32Map[ctx.CopyClipRegion(TCocoaRegion(RGN))]
|
|
else
|
|
Result := ERROR;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.GetCursorPos(var lpPoint: TPoint ): Boolean;
|
|
begin
|
|
with NSEvent.mouseLocation do
|
|
begin
|
|
lpPoint.x := Round(x);
|
|
// cocoa returns cursor with inverted y coordinate
|
|
lpPoint.y := Round(NSScreenZeroHeight-y);
|
|
end;
|
|
//debugln('GetCursorPos='+DbgS(lpPoint));
|
|
Result := True;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.GetMonitorInfo(hMonitor: HMONITOR; lpmi: PMonitorInfo): Boolean;
|
|
var
|
|
Scr0Height: CGFloat;
|
|
ScreenID: NSScreen;
|
|
idx : NSUInteger;
|
|
begin
|
|
Result := (lpmi <> nil) and (lpmi^.cbSize >= SizeOf(TMonitorInfo));
|
|
if not Result then Exit;
|
|
idx := HMonitorToIndex(hMonitor);
|
|
Result := (idx < NSScreen.screens.count);
|
|
if not Result then Exit;
|
|
|
|
Scr0Height := NSScreenZeroHeight;
|
|
ScreenID := NSScreen(NSScreen.screens.objectAtIndex(idx));
|
|
NSToLCLRect(ScreenID.frame, Scr0Height, lpmi^.rcMonitor);
|
|
NSToLCLRect(ScreenID.visibleFrame, Scr0Height, lpmi^.rcWork);
|
|
// according to the documentation the primary (0,0 coord screen)
|
|
// is always and index 0
|
|
if idx = 0 then
|
|
lpmi^.dwFlags := MONITORINFOF_PRIMARY
|
|
else
|
|
lpmi^.dwFlags := 0;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.GetObject(GDIObj: HGDIOBJ; BufSize: Integer; Buf: Pointer): Integer;
|
|
var
|
|
AObject: TCocoaGDIObject;
|
|
DIB: TDIBSection;
|
|
Width, Height, RequiredSize, i: Integer;
|
|
Traits: NSFontTraitMask;
|
|
|
|
APen: TCocoaPen absolute AObject;
|
|
ALogPen: PLogPen absolute Buf;
|
|
AExtLogPen: PExtLogPen absolute Buf;
|
|
AFont: TCocoaFont absolute AObject;
|
|
ALogFont: PLogFont absolute Buf;
|
|
begin
|
|
Result := 0;
|
|
|
|
AObject := CheckGDIObj(GDIObj);
|
|
|
|
if AObject is TCocoaBitmap then
|
|
begin
|
|
if Buf = nil then
|
|
begin
|
|
Result := SizeOf(TDIBSection);
|
|
Exit;
|
|
end;
|
|
|
|
Width := TCocoaBitmap(AObject).Width;
|
|
Height := TCocoaBitmap(AObject).Height;
|
|
|
|
FillChar(DIB, SizeOf(TDIBSection), 0);
|
|
|
|
{dsBM - BITMAP}
|
|
DIB.dsBm.bmType := $4D42;
|
|
DIB.dsBm.bmWidth := Width;
|
|
DIB.dsBm.bmHeight := Height;
|
|
DIB.dsBm.bmWidthBytes := 0;
|
|
DIB.dsBm.bmPlanes := 1;
|
|
DIB.dsBm.bmBitsPixel := 32;
|
|
DIB.dsBm.bmBits := nil;
|
|
|
|
{dsBmih - BITMAPINFOHEADER}
|
|
DIB.dsBmih.biSize := 40;
|
|
DIB.dsBmih.biWidth := Width;
|
|
DIB.dsBmih.biHeight := Height;
|
|
DIB.dsBmih.biPlanes := DIB.dsBm.bmPlanes;
|
|
DIB.dsBmih.biCompression := 0;
|
|
DIB.dsBmih.biSizeImage := 0;
|
|
DIB.dsBmih.biXPelsPerMeter := 0;
|
|
DIB.dsBmih.biYPelsPerMeter := 0;
|
|
DIB.dsBmih.biClrUsed := 0;
|
|
DIB.dsBmih.biClrImportant := 0;
|
|
DIB.dsBmih.biBitCount := 32;
|
|
|
|
if BufSize >= SizeOf(TDIBSection) then
|
|
begin
|
|
PDIBSection(Buf)^ := DIB;
|
|
Result := SizeOf(TDIBSection);
|
|
end
|
|
else
|
|
if BufSize > 0 then
|
|
begin
|
|
System.Move(DIB, Buf^, BufSize);
|
|
Result := BufSize;
|
|
end;
|
|
end
|
|
else
|
|
if AObject is TCocoaPen then
|
|
begin
|
|
if APen.IsExtPen then
|
|
begin
|
|
RequiredSize := SizeOf(TExtLogPen);
|
|
if Length(APen.Dashes) > 1 then
|
|
inc(RequiredSize, (Length(APen.Dashes) - 1) * SizeOf(DWord));
|
|
if Buf = nil then
|
|
Result := RequiredSize
|
|
else
|
|
if BufSize >= RequiredSize then
|
|
begin
|
|
Result := RequiredSize;
|
|
AExtLogPen^.elpPenStyle := APen.Style;
|
|
if APen.IsGeometric then
|
|
begin
|
|
case APen.JoinStyle of
|
|
kCGLineJoinRound:
|
|
AExtLogPen^.elpPenStyle := AExtLogPen^.elpPenStyle or PS_JOIN_ROUND;
|
|
kCGLineJoinBevel:
|
|
AExtLogPen^.elpPenStyle := AExtLogPen^.elpPenStyle or PS_JOIN_BEVEL;
|
|
kCGLineJoinMiter:
|
|
AExtLogPen^.elpPenStyle := AExtLogPen^.elpPenStyle or PS_JOIN_MITER;
|
|
end;
|
|
|
|
case APen.CapStyle of
|
|
kCGLineCapRound:
|
|
AExtLogPen^.elpPenStyle := AExtLogPen^.elpPenStyle or PS_ENDCAP_ROUND;
|
|
kCGLineCapSquare:
|
|
AExtLogPen^.elpPenStyle := AExtLogPen^.elpPenStyle or PS_ENDCAP_SQUARE;
|
|
kCGLineCapButt:
|
|
AExtLogPen^.elpPenStyle := AExtLogPen^.elpPenStyle or PS_ENDCAP_FLAT;
|
|
end;
|
|
AExtLogPen^.elpWidth := APen.Width;
|
|
end
|
|
else
|
|
AExtLogPen^.elpWidth := 1;
|
|
|
|
AExtLogPen^.elpBrushStyle := BS_SOLID;
|
|
AExtLogPen^.elpColor := APen.ColorRef;
|
|
AExtLogPen^.elpHatch := 0;
|
|
|
|
AExtLogPen^.elpNumEntries := Length(APen.Dashes);
|
|
if AExtLogPen^.elpNumEntries > 0 then
|
|
begin
|
|
for i := 0 to AExtLogPen^.elpNumEntries - 1 do
|
|
PDword(@AExtLogPen^.elpStyleEntry)[i] := Trunc(APen.Dashes[i]);
|
|
end
|
|
else
|
|
AExtLogPen^.elpStyleEntry[0] := 0;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
if Buf = nil then
|
|
Result := SizeOf(TLogPen)
|
|
else
|
|
if BufSize >= SizeOf(TLogPen) then
|
|
begin
|
|
Result := SizeOf(TLogPen);
|
|
ALogPen^.lopnStyle := APen.Style;
|
|
ALogPen^.lopnWidth := Types.Point(APen.Width, 0);
|
|
ALogPen^.lopnColor := APen.ColorRef;
|
|
end;
|
|
end;
|
|
end;
|
|
if AObject is TCocoaFont then
|
|
begin
|
|
if Buf = nil then
|
|
Result := SizeOf(TLogFont)
|
|
else
|
|
if BufSize >= SizeOf(TLogFont) then
|
|
begin
|
|
Result := SizeOf(TLogFont);
|
|
FillChar(ALogFont^, SizeOf(ALogFont^), 0);
|
|
ALogFont^.lfFaceName := AFont.Name;
|
|
ALogFont^.lfHeight := -AFont.Size; // Cocoa supports only full height (with leading) that corresponds with a negative value in WinAPI
|
|
Traits := NSFontManager.sharedFontManager.traitsOfFont(AFont.Font);
|
|
if (Traits and NSFontBoldTrait) <> 0 then
|
|
ALogFont^.lfWeight := FW_BOLD
|
|
else
|
|
ALogFont^.lfWeight := FW_NORMAL;
|
|
if (Traits and NSFontItalicTrait) <> 0 then
|
|
ALogFont^.lfItalic := 1
|
|
else
|
|
ALogFont^.lfItalic := 0;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.GetParent(Handle : HWND): HWND;
|
|
begin
|
|
if Handle<>0 then
|
|
Result:=HWND(NSObject(Handle).lclParent)
|
|
else
|
|
Result:=0;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.GetWindowRelativePosition(Handle: hwnd; var Left, Top: Integer): boolean;
|
|
begin
|
|
Result := Handle <> 0;
|
|
if Result then
|
|
NSObject(handle).lclRelativePos(Left, Top);
|
|
end;
|
|
|
|
function TCocoaWidgetSet.GetWindowSize(Handle: hwnd; var Width, Height: Integer): boolean;
|
|
var
|
|
r: TRect;
|
|
lView: NSView;
|
|
begin
|
|
Result := Handle <> 0;
|
|
if not Result then Exit;
|
|
|
|
r := NSObject(Handle).lclFrame;
|
|
Width := R.Right - R.Left;
|
|
Height := R.Bottom - R.Top;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.InitStockFont(AFont: TObject; AStockFont: TStockFont): Boolean;
|
|
var
|
|
Font: TFont absolute AFont;
|
|
CTFont: CTFontRef;
|
|
CTFontName: CFStringRef;
|
|
CTFontSize: CGFloat;
|
|
CTFontType: CTFontUIFontType;
|
|
begin
|
|
Result := False;
|
|
|
|
case AStockFont of
|
|
sfSystem: // stock system font
|
|
CTFontType := kCTFontSystemFontType;
|
|
sfHint: // stock hint font
|
|
CTFontType := kCTFontToolTipFontType;
|
|
sfIcon: // stock icon font
|
|
CTFontType := kCTFontViewsFontType;
|
|
sfMenu: // stock menu font
|
|
CTFontType := kCTFontMenuItemFontType;
|
|
end;
|
|
|
|
CTFont := CTFontCreateUIFontForLanguage(CTFontType, 0, nil);
|
|
try
|
|
CTFontName := CTFontCopyFamilyName(CTFont);
|
|
try
|
|
Font.Name := CFStringToStr(CTFontName);
|
|
finally
|
|
CFRelease(CTFontName);
|
|
end;
|
|
CTFontSize := CTFontGetSize(CTFont);
|
|
Font.Height := -Round(CTFontSize);
|
|
finally
|
|
CFRelease(CTFont);
|
|
end;
|
|
Result := True;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.HideCaret(Handle: HWND): Boolean;
|
|
var
|
|
lView: NSView;
|
|
begin
|
|
if (Handle = 0)
|
|
then lView := nil
|
|
else lView := NSView(Handle).lclContentView;
|
|
|
|
Result := CocoaCaret.HideCaret(lView);
|
|
end;
|
|
|
|
function TCocoaWidgetSet.InvalidateRect(aHandle: HWND; Rect: pRect; bErase: Boolean): Boolean;
|
|
begin
|
|
Result := aHandle <> 0;
|
|
if Result then
|
|
begin
|
|
if Assigned(Rect) then
|
|
NSObject(aHandle).lclInvalidateRect(Rect^)
|
|
else
|
|
NSObject(aHandle).lclInvalidate;
|
|
end;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.UpdateWindow(Handle: HWND): Boolean;
|
|
begin
|
|
Result := Handle <> 0;
|
|
if Result then
|
|
NSObject(Handle).lclUpdate;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.GetProp(Handle: hwnd; Str: PChar): Pointer;
|
|
var
|
|
PropStorage: TStringList;
|
|
I: Integer;
|
|
begin
|
|
if Handle <> 0 then
|
|
begin
|
|
PropStorage := NSObject(Handle).lclGetPropStorage;
|
|
if Assigned(PropStorage) then
|
|
begin
|
|
I := PropStorage.IndexOf(Str);
|
|
if I <> -1 then
|
|
Result := PropStorage.Objects[I]
|
|
else
|
|
Result := nil;
|
|
end
|
|
else
|
|
Result := nil;
|
|
end else
|
|
Result := nil;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.IsWindow(handle: HWND): boolean;
|
|
var
|
|
cbi : ICommonCallback;
|
|
obj : TObject;
|
|
begin
|
|
if handle <> 0 then
|
|
begin
|
|
cbi := NSObject(handle).lclGetCallback;
|
|
Result := Assigned(cbi);
|
|
if not Result then Exit;
|
|
|
|
obj := cbi.GetCallbackObject;
|
|
Result := (obj is TLCLCommonCallback)
|
|
and (HWND(TLCLCommonCallback(obj).HandleFrame)=handle);
|
|
end
|
|
else
|
|
Result := False;
|
|
end;
|
|
|
|
function ViewFromPoint(view: NSView;Point: TPoint): HWND;
|
|
var rect: TRect;
|
|
p:TPoint;
|
|
cb: ICommonCallback;
|
|
cbo: TObject;
|
|
hv : NSView;
|
|
begin
|
|
Result:=0;
|
|
if not assigned(view) then
|
|
exit;
|
|
cb := view.lclGetCallback;
|
|
if Assigned(cb) then
|
|
begin
|
|
cbo := cb.GetCallbackObject;
|
|
if not (cbo is TLCLCommonCallback) then Exit;
|
|
p:=Point;
|
|
// The hit test is done by the out-side frame (Handle)
|
|
hv := TLCLCommonCallback(cbo).HandleFrame;
|
|
hv.lclScreenToLocal(p.X,p.Y);
|
|
rect:=hv.lclClientFrame;
|
|
if PtInRect(rect, p) then
|
|
//if hv.lclClassName;
|
|
Result := HWND(hv)
|
|
end
|
|
end;
|
|
|
|
function RecurseSubviews(view: NSView;Point: TPoint):HWND;
|
|
var sv:integer;
|
|
begin
|
|
// first check views subview if there is a embedded view
|
|
Result:=0;
|
|
if not Assigned(view) or (view.isHidden) or (not view.lclIsEnabled) then Exit;
|
|
sv:=0;
|
|
while (Result=0) and (sv<view.subviews.count) do
|
|
begin
|
|
Result:=RecurseSubviews(view.subviews.objectAtIndex(sv),Point);
|
|
inc(sv)
|
|
end;
|
|
if Result=0 then
|
|
Result:=ViewFromPoint(view,Point);
|
|
end;
|
|
|
|
function TCocoaWidgetSet.WindowFromPoint(Point: TPoint): HWND;
|
|
var
|
|
winrect: TRect;
|
|
windows: NSArray;
|
|
win: integer;
|
|
window, windowbelowpoint: NSWindow;
|
|
p:NSPoint;
|
|
winnr:NSInteger;
|
|
begin
|
|
Result := 0;
|
|
if not assigned(NSApp) then
|
|
Exit;
|
|
|
|
windows := NSApp.windows;
|
|
for win := 0 to windows.count - 1 do
|
|
begin
|
|
window:=windows.objectAtIndex(win);
|
|
p.x:=Point.X;
|
|
p.y:=NSScreenZeroHeight-Point.Y;
|
|
winnr:=NSWindow.windowNumberAtPoint_belowWindowWithWindowNumber(p,0);
|
|
windowbelowpoint:=NSWindow(NSApp.windowWithWindowNumber(winnr));
|
|
if windowbelowpoint=window then
|
|
begin
|
|
Result:=RecurseSubviews(window.contentView, Point);
|
|
if Result<>0 then
|
|
begin
|
|
exit;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
function TCocoaWidgetSet.GetRgnBox(RGN: HRGN; lpRect: PRect): Longint;
|
|
begin
|
|
Result := ERROR;
|
|
if Assigned(lpRect) then
|
|
lpRect^ := Types.Rect(0, 0, 0, 0);
|
|
|
|
if not (TObject(RGN) is TCocoaRegion) then
|
|
Exit;
|
|
|
|
if Assigned(lpRect) then
|
|
begin
|
|
lpRect^ := TCocoaRegion(RGN).GetBounds;
|
|
Result := CocoaRegionTypeToWin32Map[TCocoaRegion(RGN).GetType];
|
|
end;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.GetROP2(DC: HDC): Integer;
|
|
var
|
|
ctx: TCocoaContext;
|
|
begin
|
|
ctx := CheckDC(DC);
|
|
if Assigned(ctx) then
|
|
Result := ctx.ROP2
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.SetProp(Handle: hwnd; Str: PChar; Data: Pointer): Boolean;
|
|
var
|
|
PropStorage: TStringList;
|
|
begin
|
|
Result := Handle <> 0;
|
|
if Result then
|
|
begin
|
|
PropStorage := NSObject(Handle).lclGetPropStorage;
|
|
Result := Assigned(PropStorage);
|
|
if Result then
|
|
PropStorage.AddObject(Str, TObject(Data));
|
|
end;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.SetROP2(DC: HDC; Mode: Integer): Integer;
|
|
var
|
|
ctx: TCocoaContext;
|
|
begin
|
|
ctx := CheckDC(DC);
|
|
if Assigned(ctx) then
|
|
begin
|
|
Result := ctx.ROP2;
|
|
ctx.ROP2 := Mode;
|
|
end
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
{----------------------------- WINDOWS SCROLLING ------------------------------}
|
|
|
|
function TCocoaWidgetSet.GetScrollBarSize(Handle: HWND; BarKind: Integer): integer;
|
|
var
|
|
sc : NSScrollView;
|
|
obj : NSObject;
|
|
begin
|
|
obj := NSObject(Handle);
|
|
Result := 0;
|
|
if not Assigned(obj) then Exit;
|
|
|
|
if obj.isKindOfClass(NSScrollView) then
|
|
begin
|
|
if (BarKind = SB_Vert) and Assigned(NSScrollView(obj).verticalScroller) then
|
|
Result:=round(NSScrollView(obj).verticalScroller.frame.size.width)
|
|
else if (BarKind = SB_Horz) and Assigned(NSScrollView(obj).horizontalScroller) then
|
|
Result:=round(NSScrollView(obj).verticalScroller.frame.size.height)
|
|
else
|
|
Result := Round(NSScroller.scrollerWidth);
|
|
end
|
|
else
|
|
Result := Round(NSScroller.scrollerWidth);
|
|
end;
|
|
|
|
function TCocoaWidgetSet.GetScrollbarVisible(Handle: HWND; SBStyle: Integer): boolean;
|
|
var
|
|
obj : NSObject;
|
|
sc : NSScrollView;
|
|
mn : TCocoaManualScrollView;
|
|
begin
|
|
obj := NSObject(Handle);
|
|
Result := Assigned(obj);
|
|
if not Result then Exit;
|
|
|
|
if obj.isKindOfClass(TCocoaManualScrollHost) then
|
|
obj := TCocoaManualScrollHost(obj).documentView;
|
|
|
|
if obj.isKindOfClass(NSScrollView) then
|
|
begin
|
|
sc := NSScrollView(obj);
|
|
case SBStyle of
|
|
SB_Vert: Result := sc.hasVerticalScroller;
|
|
SB_Horz: Result := sc.hasHorizontalScroller;
|
|
else
|
|
Result := sc.hasHorizontalScroller and sc.hasVerticalScroller;
|
|
end;
|
|
end
|
|
else if obj.isKindOfClass(TCocoaManualScrollView) then
|
|
begin
|
|
mn := TCocoaManualScrollView(obj);
|
|
case SBStyle of
|
|
SB_Vert: Result := mn.hasVerticalScroller;
|
|
SB_Horz: Result := mn.hasHorizontalScroller;
|
|
else
|
|
Result := mn.hasHorizontalScroller and mn.hasVerticalScroller;
|
|
end;
|
|
end
|
|
else
|
|
Result := False;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.GetScrollInfo(Handle: HWND; BarFlag: Integer;
|
|
var ScrollInfo: TScrollInfo): Boolean;
|
|
var
|
|
sc : NSScrollView;
|
|
obj : NSObject;
|
|
begin
|
|
obj := NSObject(Handle);
|
|
Result := Assigned(obj);
|
|
if not Result then Exit;
|
|
|
|
if obj.isKindOfClass(TCocoaManualScrollHost) then
|
|
obj := TCocoaManualScrollHost(obj).documentView;
|
|
|
|
if obj.isKindOfClass(TCocoaScrollBar) then
|
|
Result := CocoaScrollBarGetScrollInfo(TCocoaScrollBar(obj), ScrollInfo)
|
|
else
|
|
if obj.isKindOfClass(TCocoaManualScrollView) then
|
|
begin
|
|
if BarFlag = SB_Vert then
|
|
Result := CocoaScrollBarGetScrollInfo( TCocoaScrollBar(TCocoaManualScrollView(obj).verticalScroller), ScrollInfo)
|
|
else
|
|
Result := CocoaScrollBarGetScrollInfo( TCocoaScrollBar(TCocoaManualScrollView(obj).horizontalScroller), ScrollInfo);
|
|
end else if obj.isKindOfClass(NSScrollView) then
|
|
NSScrollViewGetScrollInfo(NSScrollView(obj), BarFlag, ScrollInfo)
|
|
else
|
|
Result := False;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.GetStockObject(Value: Integer): THandle;
|
|
begin
|
|
Result := 0;
|
|
|
|
case Value of
|
|
BLACK_BRUSH: // Black brush.
|
|
Result := FStockBlackBrush;
|
|
DKGRAY_BRUSH: // Dark gray brush.
|
|
Result := FStockDKGrayBrush;
|
|
GRAY_BRUSH: // Gray brush.
|
|
Result := FStockGrayBrush;
|
|
LTGRAY_BRUSH: // Light gray brush.
|
|
Result := FStockLtGrayBrush;
|
|
NULL_BRUSH: // Null brush (equivalent to HOLLOW_BRUSH).
|
|
Result := FStockNullBrush;
|
|
WHITE_BRUSH: // White brush.
|
|
Result := FStockWhiteBrush;
|
|
|
|
BLACK_PEN: // Black pen.
|
|
Result := FStockBlackPen;
|
|
NULL_PEN: // Null pen.
|
|
Result := FStockNullPen;
|
|
WHITE_PEN: // White pen.
|
|
Result := FStockWhitePen;
|
|
|
|
DEFAULT_GUI_FONT, SYSTEM_FONT:
|
|
Result := FStockSystemFont;
|
|
SYSTEM_FIXED_FONT:
|
|
Result := FStockFixedFont;
|
|
end;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.GetSysColor(nIndex: Integer): DWORD;
|
|
var
|
|
Color: NSColor;
|
|
SysBrush: HBrush;
|
|
begin
|
|
// 1. get the system brush - it has a NSColor reference
|
|
SysBrush := GetSysColorBrush(nIndex);
|
|
if SysBrush = 0 then
|
|
begin
|
|
Result := 0;
|
|
Exit;
|
|
end;
|
|
|
|
Color := TCocoaBrush(SysBrush).Color;
|
|
|
|
if Assigned(Color) then
|
|
Result := NSColorToColorRef(Color)
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.GetSysColorBrush(nIndex: Integer): HBRUSH;
|
|
var
|
|
sys : NSColor;
|
|
begin
|
|
if (nIndex < 0) or (nIndex > MAX_SYS_COLORS) then
|
|
begin
|
|
Result := 0;
|
|
Exit;
|
|
end;
|
|
if (FSysColorBrushes[nIndex] = 0) then
|
|
FSysColorBrushes[nIndex] := HBrush(TCocoaBrush.Create(SysColorToNSColor(nIndex), True))
|
|
else
|
|
begin
|
|
// system wide can change the color on the fly
|
|
TCocoaBrush(FSysColorBrushes[nIndex]).Color := SysColorToNSColor(nIndex)
|
|
end;
|
|
|
|
Result := FSysColorBrushes[nIndex];
|
|
end;
|
|
|
|
function TCocoaWidgetSet.SetScrollInfo(Handle : HWND; SBStyle : Integer; ScrollInfo: TScrollInfo; bRedraw : Boolean): Integer;
|
|
var
|
|
si : TScrollInfo;
|
|
obj : NSObject;
|
|
sc : TCocoaScrollView;
|
|
bar : TCocoaScrollBar;
|
|
f : NSSize;
|
|
sz : NSSize;
|
|
flg : NSUInteger;
|
|
hosted: Boolean;
|
|
begin
|
|
obj := NSObject(Handle);
|
|
Result := 0;
|
|
if not Assigned(obj) then Exit;
|
|
|
|
if obj.isKindOfClass(TCocoaManualScrollHost) then
|
|
begin
|
|
hosted := true;
|
|
obj := TCocoaManualScrollHost(obj).documentView;
|
|
end else
|
|
hosted := false;
|
|
|
|
if obj.isKindOfClass(TCocoaScrollView) then
|
|
begin
|
|
sc:=TCocoaScrollView(obj);
|
|
if sc.isCustomRange and (ScrollInfo.fMask and SIF_RANGE>0) then begin
|
|
f:=sc.frame.size;
|
|
sz:=NSView(sc.documentView).frame.size; // type casting is here for the compiler. for i386 it messes up types
|
|
flg:=sc.documentView.autoresizingMask;
|
|
|
|
if SBStyle=SB_Horz then begin
|
|
if ScrollInfo.nMax>f.width then begin
|
|
sz.width := ScrollInfo.nMax;
|
|
flg:=flg and not NSViewWidthSizable;
|
|
end else begin
|
|
sz.width := f.width;
|
|
flg:=flg or NSViewWidthSizable;
|
|
end;
|
|
end else if SBStyle=SB_Vert then begin
|
|
if ScrollInfo.nMax>f.height then begin
|
|
sz.height := ScrollInfo.nMax;
|
|
flg:=flg and not NSViewHeightSizable;
|
|
end else begin
|
|
sz.height := f.height;
|
|
flg:=flg or NSViewHeightSizable;
|
|
end;
|
|
end;
|
|
sc.documentView.setAutoresizingMask(flg);
|
|
sc.documentView.setFrameSize( sz );
|
|
end;
|
|
|
|
if ScrollInfo.fMask and SIF_ALL > 0 then
|
|
NSScrollViewSetScrollPos(NSScrollView(obj), SBStyle, ScrollInfo);
|
|
FillChar(si, sizeof(si), 0);
|
|
si.cbSize:=sizeof(si);
|
|
NSScrollViewGetScrollInfo(NSScrollView(obj), SBStyle, si);
|
|
Result:=si.nPos;
|
|
end else if obj.isKindOfClass(TCocoaManualScrollView) then
|
|
begin
|
|
bar:=nil;
|
|
if SBStyle=SB_Vert then
|
|
bar:= TCocoaScrollBar(TCocoaManualScrollView(obj).allocVerticalScroller(false))
|
|
else if SBStyle=SB_Horz then
|
|
bar:= TCocoaScrollBar(TCocoaManualScrollView(obj).allocHorizontalScroller(false));
|
|
|
|
if Assigned(bar) then
|
|
begin
|
|
Result := CocoaScrollBarSetScrollInfo(bar, ScrollInfo);
|
|
//debugln('TCocoaWidgetSet.SetScrollInfo page=',bar.pageInt,' min=',bar.minInt,' max=',bar.maxInt,' ',bar.lclPos);
|
|
ShowScrollBar(Handle, SBStyle, bar.pageInt < bar.maxInt-bar.minInt);
|
|
end
|
|
else
|
|
Result := 0;
|
|
|
|
if hosted then
|
|
NSView(obj).lclInvalidate;
|
|
|
|
end else if obj.isKindOfClass(TCocoaScrollBar) then
|
|
begin
|
|
Result := CocoaScrollBarSetScrollInfo(TCocoaScrollBar(obj), ScrollInfo);
|
|
end
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.ShowScrollBar(Handle: HWND; wBar: Integer; bShow: Boolean): Boolean;
|
|
var
|
|
obj : NSObject;
|
|
sc : TCocoaScrollView;
|
|
mn : TCocoaManualScrollView;
|
|
begin
|
|
obj := NSObject(Handle);
|
|
Result := Assigned(obj);
|
|
if not Result then Exit;
|
|
|
|
if obj.isKindOfClass(TCocoaManualScrollHost) then
|
|
obj := TCocoaManualScrollHost(obj).documentView;
|
|
|
|
if obj.isKindOfClass(TCocoaScrollView)
|
|
then begin
|
|
Result := true;
|
|
sc := TCocoaScrollView(obj);
|
|
if wBar in [SB_Vert, SB_Both] then
|
|
sc.setHasVerticalScroller(bShow);
|
|
|
|
if wBar in [SB_Horz, SB_Both] then
|
|
sc.setHasHorizontalScroller(bShow);
|
|
end
|
|
else if obj.isKindOfClass(TCocoaManualScrollView)
|
|
then begin
|
|
mn := TCocoaManualScrollView(obj);
|
|
|
|
if wBar in [SB_Vert, SB_Both] then
|
|
mn.setHasVerticalScroller(bShow);
|
|
|
|
if wBar in [SB_Horz, SB_Both] then
|
|
mn.setHasHorizontalScroller(bShow);
|
|
|
|
Result := true;
|
|
end else
|
|
Result := false;
|
|
end;
|
|
|
|
{----------------------------------- DRAWING ----------------------------------}
|
|
|
|
|
|
type
|
|
TPointArray = array [word] of TPoint;
|
|
PPointArray = ^TPointArray;
|
|
|
|
function TCocoaWidgetSet.LineTo(DC: HDC; X, Y: Integer): Boolean;
|
|
var
|
|
ctx: TCocoaContext;
|
|
begin
|
|
ctx := CheckDC(DC);
|
|
Result := Assigned(ctx);
|
|
if Result then
|
|
ctx.LineTo(X, Y);
|
|
end;
|
|
|
|
function TCocoaWidgetSet.LPtoDP(DC: HDC; var Points; Count: Integer): BOOL;
|
|
var
|
|
ctx: TCocoaContext;
|
|
P: PPoint;
|
|
begin
|
|
Result := False;
|
|
ctx := CheckDC(DC);
|
|
if not Assigned(ctx) then Exit;
|
|
P := @Points;
|
|
with ctx.GetLogicalOffset do
|
|
while Count > 0 do
|
|
begin
|
|
Dec(Count);
|
|
inc(P^.X, X);
|
|
inc(P^.Y, Y);
|
|
inc(P);
|
|
end;
|
|
Result := True;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.OffsetRgn(RGN: HRGN; nXOffset, nYOffset: Integer): Integer;
|
|
begin
|
|
if not (TObject(RGN) is TCocoaRegion) then
|
|
Exit(ERROR);
|
|
TCocoaRegion(RGN).Offset(nXOffset, nYOffset);
|
|
Result := CocoaRegionTypeToWin32Map[TCocoaRegion(RGN).GetType];
|
|
end;
|
|
|
|
function TCocoaWidgetSet.MoveToEx(DC: HDC; X, Y: Integer; OldPoint: PPoint): Boolean;
|
|
var
|
|
ctx: TCocoaContext;
|
|
begin
|
|
ctx := CheckDC(DC);
|
|
Result := Assigned(ctx);
|
|
if Result then
|
|
begin
|
|
if Assigned(OldPoint) then
|
|
OldPoint^ := ctx.PenPos;
|
|
ctx.MoveTo(X, Y);
|
|
end;
|
|
end;
|
|
|
|
{$push}
|
|
{$rangechecks off}
|
|
function TCocoaWidgetSet.Polygon(DC: HDC; Points: PPoint; NumPts: Integer; Winding: boolean): boolean;
|
|
var
|
|
ctx: TCocoaContext;
|
|
begin
|
|
ctx := CheckDC(DC);
|
|
Result := Assigned(ctx) and Assigned(Points) and (NumPts >= 2);
|
|
if Result then
|
|
ctx.Polygon(PPointArray(Points)^, NumPts, Winding);
|
|
end;
|
|
|
|
function TCocoaWidgetSet.Polyline(DC: HDC; Points: PPoint; NumPts: Integer): boolean;
|
|
var
|
|
ctx: TCocoaContext;
|
|
begin
|
|
ctx := CheckDC(DC);
|
|
Result := Assigned(ctx) and Assigned(Points) and (NumPts > 0);
|
|
if Result then
|
|
ctx.Polyline(PPointArray(Points)^, NumPts);
|
|
end;
|
|
{$pop}
|
|
|
|
type
|
|
TLCLEventMessage = objcclass(NSObject)
|
|
handle: HWND;
|
|
msg: Cardinal;
|
|
wp: WParam;
|
|
lp: LParam;
|
|
res: LResult;
|
|
releaseAfterRun: Boolean;
|
|
procedure lclRunEvent(sender: id); message 'lclRunEvent:';
|
|
end;
|
|
|
|
procedure TLCLEventMessage.lclRunEvent(sender: id);
|
|
begin
|
|
res := NSObject(handle).lclDeliverMessage(msg, wp, lp);
|
|
if releaseAfterRun then self.release;
|
|
end;
|
|
|
|
function AllocLCLEventMessage(ahandle: HWND; amsg: Cardinal; awp: WParam; alp: LParam; forSend: Boolean): TLCLEventMessage;
|
|
begin
|
|
Result := TLCLEventMessage.alloc.init;
|
|
Result.handle := ahandle;
|
|
Result.msg := amsg;
|
|
Result.wp := awp;
|
|
Result.lp := alp;
|
|
Result.releaseAfterRun := not forSend;
|
|
end;
|
|
|
|
|
|
function TCocoaWidgetSet.PostMessage(Handle: HWND; Msg: Cardinal;
|
|
wParam: WParam; lParam: LParam): Boolean;
|
|
var
|
|
m: TLCLEventMessage;
|
|
begin
|
|
Result := Handle <> 0;
|
|
if Result then
|
|
begin
|
|
m:=AllocLCLEventMessage(Handle, Msg, wParam, lParam, false);
|
|
m.performSelectorOnMainThread_withObject_waitUntilDone(
|
|
ObjCSelector('lclRunEvent:'), nil, false
|
|
);
|
|
end;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.Rectangle(DC: HDC; X1, Y1, X2, Y2: Integer): Boolean;
|
|
var
|
|
ctx: TCocoaContext;
|
|
begin
|
|
ctx := CheckDC(DC);
|
|
Result := Assigned(ctx);
|
|
if Result then
|
|
begin
|
|
// rectangle must be filled using current brush
|
|
ctx.Rectangle(X1, Y1, X2, Y2, True, ctx.Brush);
|
|
// and outlined by current pen
|
|
ctx.Rectangle(X1, Y1, X2, Y2, False, nil);
|
|
end;
|
|
end;
|
|
|
|
{------------------------------- SYNC OBJECTS ---------------------------------}
|
|
|
|
procedure TCocoaWidgetSet.InitializeCriticalSection(var CritSection: TCriticalSection);
|
|
begin
|
|
CritSection:=TCriticalSection(NSRecursiveLock.alloc);
|
|
end;
|
|
|
|
procedure TCocoaWidgetSet.DeleteCriticalSection(var CritSection: TCriticalSection);
|
|
begin
|
|
if CritSection=0 then Exit;
|
|
NSRecursiveLock(CritSection).release;
|
|
CritSection:=0;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.DeleteDC(hDC: HDC): Boolean;
|
|
begin
|
|
Result := hDC <> 0;
|
|
if Result then
|
|
TCocoaContext(hDC).Free;
|
|
end;
|
|
|
|
procedure TCocoaWidgetSet.EnterCriticalSection(var CritSection: TCriticalSection);
|
|
begin
|
|
if CritSection=0 then Exit;
|
|
NSRecursiveLock(CritSection).lock;
|
|
end;
|
|
|
|
procedure TCocoaWidgetSet.LeaveCriticalSection(var CritSection: TCriticalSection);
|
|
begin
|
|
if CritSection=0 then Exit;
|
|
NSRecursiveLock(CritSection).unlock;
|
|
end;
|
|
|
|
{------------------------------- DEVICE CONTEXT -------------------------------}
|
|
|
|
function TCocoaWidgetSet.GetDC(hWnd: HWND): HDC;
|
|
var
|
|
ctx: TCocoaContext = nil;
|
|
lCallback: ICommonCallback;
|
|
begin
|
|
if hWnd = 0 then
|
|
Result := HDC(ScreenContext)
|
|
else
|
|
begin
|
|
lCallback := NSObject(hWnd).lclGetCallback;
|
|
if lCallback <> nil then
|
|
ctx := lCallback.GetContext;
|
|
|
|
if ctx = nil then
|
|
begin
|
|
ctx := TCocoaContext.Create(DefaultContext.ctx);
|
|
ctx.InitDraw(DefaultContext.size.cx, DefaultContext.size.cy);
|
|
end;
|
|
Result := HDC(ctx);
|
|
end;
|
|
|
|
{$IFDEF VerboseWinAPI}
|
|
DebugLn('[TCocoaWidgetSet.GetDC] hWnd: %x Result: %x', [hWnd, Result]);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
function TCocoaWidgetSet.GetDCOriginRelativeToWindow(PaintDC: HDC;
|
|
WindowHandle: HWND; var OriginDiff: TPoint): boolean;
|
|
begin
|
|
Result:=PaintDC<>0;
|
|
if Result then
|
|
OriginDiff:=TCocoaContext(PaintDC).WindowOfs;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.GetDeviceCaps(DC: HDC; Index: Integer): Integer;
|
|
var
|
|
ctx: TCocoaContext;
|
|
begin
|
|
ctx := CheckDC(DC);
|
|
if not Assigned(ctx) then
|
|
Exit(0);
|
|
|
|
// todo: change implementation for printers
|
|
case Index of
|
|
HORZSIZE:
|
|
Result := Round(NSScreen.mainScreen.frame.size.width / 72 * 25.4);
|
|
VERTSIZE:
|
|
Result := Round(NSScreen.mainScreen.frame.size.height / 72 * 25.4);
|
|
HORZRES:
|
|
Result := Round(NSScreen.mainScreen.frame.size.width);
|
|
BITSPIXEL:
|
|
// this is based on the main screen only. Should verify what actual DC is passed.
|
|
// for VIEWS the typical BPP would be 32.
|
|
case NSScreen.mainScreen.depth of
|
|
NSWindowDepthTwentyfourBitRGB: //24-bit would be reported as 32
|
|
Result := 32;
|
|
NSWindowDepthSixtyfourBitRGB:
|
|
Result := 64;
|
|
NSWindowDepthOnehundredtwentyeightBitRGB:
|
|
Result := 128;
|
|
else
|
|
Result := 32;
|
|
end;
|
|
|
|
PLANES:
|
|
Result := 1;
|
|
SIZEPALETTE:
|
|
Result := 0;
|
|
LOGPIXELSX:
|
|
Result := 72;
|
|
LOGPIXELSY:
|
|
Result := 72;
|
|
VERTRES:
|
|
Result := Round(NSScreen.mainScreen.frame.size.height);
|
|
NUMRESERVED:
|
|
Result := 0;
|
|
else
|
|
DebugLn('TCocoaWidgetSet.GetDeviceCaps TODO Index: ' + DbgS(Index));
|
|
Result := 0;
|
|
end;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.GetDeviceSize(DC: HDC; var P: TPoint): Boolean;
|
|
var
|
|
ctx: TCocoaContext;
|
|
begin
|
|
ctx := CheckDC(DC);
|
|
Result := Assigned(ctx);
|
|
if Result then
|
|
with ctx.Size do
|
|
begin
|
|
P.X := cx;
|
|
P.Y := cy;
|
|
end;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.GetFocus: HWND;
|
|
var
|
|
Obj : NSObject;
|
|
win : NSWindow;
|
|
rsp : NSResponder;
|
|
view : NSView;
|
|
dl : NSObject;
|
|
cb : ICommonCallback;
|
|
cbobj : TObject;
|
|
begin
|
|
Result := 0;
|
|
win := NSApp.keyWindow;
|
|
if not Assigned(win) then Exit;
|
|
// assuming that that the content view of Window
|
|
// is the focused handle and return it, by default
|
|
Result := HWND(win.contentView);
|
|
|
|
rsp := win.firstResponder;
|
|
if not Assigned(rsp) then Exit;
|
|
|
|
// todo: The HANDLE is allocated in "WS" side, thus we should be using
|
|
// "callback" object to determine, what actual NSView is the handle
|
|
|
|
if rsp.isKindOfClass(TCocoaFieldEditor) then
|
|
begin
|
|
// field editor is a "popup" editor over many controls
|
|
// the editor itself is never returned as any kind of HANDLE.
|
|
// The handle is the box, that's editing
|
|
dl := NSObject(TCocoaFieldEditor(rsp).delegate);
|
|
if Assigned(dl) and (dl.isKindOfClass(NSView)) and Assigned(dl.lclGetCallback) then
|
|
Result := HWND(dl);
|
|
end
|
|
else
|
|
begin
|
|
cb := rsp.lclGetCallback;
|
|
if Assigned(cb) then
|
|
cbobj := cb.GetCallbackObject
|
|
else
|
|
cbobj := nil;
|
|
|
|
if (cbobj is TLCLCommonCallback) then
|
|
Result := HWND(TLCLCommonCallback(cbobj).HandleFrame)
|
|
else
|
|
Result := 0;
|
|
end;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.GetForegroundWindow: HWND;
|
|
//var
|
|
// App: NSRunningApplication;
|
|
begin
|
|
// return the currect active window in the system
|
|
{ this is not possible because we can't access another application NSApplication
|
|
for App in NSWorkSpace.sharedWorkspace.runningApplications do
|
|
if App.isActive then
|
|
begin
|
|
Result := HWND(App.keyWindow);
|
|
Exit;
|
|
end;
|
|
}
|
|
if NSApp.isActive then
|
|
Result := HWND(NSApp.keyWindow)
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.GetKeyState(nVirtKey: Integer): Smallint;
|
|
const
|
|
StateDown = SmallInt($FF80);
|
|
StateToggled = SmallInt($0001);
|
|
DownMap: array[Boolean] of SmallInt = (0, StateDown);
|
|
ToggleMap: array[Boolean] of SmallInt = (0, StateToggled);
|
|
var
|
|
Modifiers: NSUInteger;
|
|
begin
|
|
// NSApp.currentEvent.modifierFlags doesn't work before events start coming,
|
|
// see bug 29272 and http://lists.apple.com/archives/cocoa-dev/2010/Feb/msg00105.html
|
|
Modifiers := NSEvent.modifierFlags_();
|
|
case nVirtKey of
|
|
VK_MENU,
|
|
VK_LMENU:
|
|
// the ssAlt/VK_MENU is mapped to optionKey under MacOS
|
|
Result := DownMap[(Modifiers and NSAlternateKeyMask) <> 0];
|
|
VK_SHIFT,
|
|
VK_LSHIFT:
|
|
Result := DownMap[(Modifiers and NSShiftKeyMask) <> 0];
|
|
VK_CONTROL,
|
|
VK_LCONTROL:
|
|
Result := DownMap[(Modifiers and NSControlKeyMask) <> 0];
|
|
VK_LWIN, VK_RWIN:
|
|
Result := DownMap[(Modifiers and NSCommandKeyMask) <> 0];
|
|
VK_CAPITAL:
|
|
Result := ToggleMap[(Modifiers and NSAlphaShiftKeyMask) <> 0];
|
|
VK_LBUTTON:
|
|
Result := DownMap[(NSEvent.pressedMouseButtons() and $1) <> 0];
|
|
VK_RBUTTON:
|
|
Result := DownMap[(NSEvent.pressedMouseButtons() and $2) <> 0];
|
|
VK_MBUTTON:
|
|
Result := DownMap[(NSEvent.pressedMouseButtons() and $3) <> 0];
|
|
VK_XBUTTON1:
|
|
Result := DownMap[(NSEvent.pressedMouseButtons() and $4) <> 0];
|
|
VK_XBUTTON2:
|
|
Result := DownMap[(NSEvent.pressedMouseButtons() and $5) <> 0];
|
|
else
|
|
Result := 0;
|
|
end;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.SelectObject(ADC: HDC; GDIObj: HGDIOBJ): HGDIOBJ;
|
|
var
|
|
dc: TCocoaContext;
|
|
gdi: TCocoaGDIObject;
|
|
const
|
|
SName = 'TCocoaWidgetSet.SelectObject';
|
|
begin
|
|
{$IFDEF VerboseWinAPI}
|
|
DebugLn(Format('TCocoaWidgetSet.SelectObject DC: %x GDIObj: %x', [ADC, GDIObj]));
|
|
{$ENDIF}
|
|
Result := 0;
|
|
|
|
dc:=CheckDC(ADC);
|
|
gdi:=CheckGDIOBJ(GDIObj);
|
|
if not Assigned(dc) then Exit;
|
|
if not Assigned(gdi) then Exit;
|
|
|
|
if gdi is TCocoaBrush then
|
|
begin // select brush
|
|
Result := HBRUSH(dc.Brush);
|
|
dc.Brush := TCocoaBrush(gdi);
|
|
end else if gdi is TCocoaPen then
|
|
begin // select pen
|
|
Result := HPEN(dc.Pen);
|
|
dc.Pen := TCocoaPen(gdi);
|
|
end else if gdi is TCocoaFont then
|
|
begin // select font
|
|
Result := HFONT(dc.Font);
|
|
dc.Font := TCocoaFont(gdi);
|
|
end else if gdi is TCocoaRegion then
|
|
begin // select region
|
|
Result := HRGN(dc.Region);
|
|
dc.Region := TCocoaRegion(gdi);
|
|
end else if gdi is TCocoaBitmap then
|
|
begin // select bitmap
|
|
if not (dc is TCocoaBitmapContext) then
|
|
begin
|
|
DebugLn(SName + ' Error - The specified device context is not bitmap context!');
|
|
Exit;
|
|
end;
|
|
Result := HBITMAP(TCocoaBitmapContext(dc).Bitmap);
|
|
TCocoaBitmapContext(dc).Bitmap := TCocoaBitmap(gdi);
|
|
end
|
|
else
|
|
begin
|
|
DebugLn(SName + ' Error - Unknown Object Type ' + DbgSName(gdi));
|
|
Exit;
|
|
end;
|
|
|
|
{$IFDEF VerboseWinAPI}
|
|
DebugLn(Format('TCocoaWidgetSet.SelectObject Result: %x', [Result]));
|
|
{$ENDIF}
|
|
end;
|
|
|
|
function TCocoaWidgetSet.SendMessage(Handle: HWND; Msg: Cardinal;
|
|
WParam: WParam; LParam: LParam): LResult;
|
|
var
|
|
m: TLCLEventMessage;
|
|
begin
|
|
if Handle <> 0 then
|
|
begin
|
|
m:=AllocLCLEventMessage(Handle, Msg, wParam, lParam, true);
|
|
m.performSelectorOnMainThread_withObject_waitUntilDone(
|
|
ObjCSelector('lclRunEvent:'), nil, true
|
|
);
|
|
Result := m.res;
|
|
m.release;
|
|
end else
|
|
Result := 0;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.SetActiveWindow(Handle: HWND): HWND;
|
|
var
|
|
Obj: NSObject;
|
|
begin
|
|
Obj := NSObject(Handle);
|
|
Result := 0; // should return 0, if function fails
|
|
if Assigned(Obj) and NSApp.isActive then
|
|
begin
|
|
Result := HWND(NSApp.keyWindow.contentView);
|
|
if (Handle <> 0) then
|
|
NSView(Handle).window.makeKeyWindow;
|
|
end;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.SetBKColor(DC: HDC; Color: TColorRef): TColorRef;
|
|
var
|
|
ctx: TCocoaContext;
|
|
begin
|
|
ctx := CheckDC(DC);
|
|
if Assigned(ctx) then
|
|
begin
|
|
Result := ctx.BkColor;
|
|
ctx.BkColor := TColor(Color);
|
|
end
|
|
else
|
|
Result := CLR_INVALID;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.SetBkMode(DC: HDC; bkMode: Integer): Integer;
|
|
var
|
|
ctx: TCocoaContext;
|
|
begin
|
|
ctx := CheckDC(DC);
|
|
if Assigned(ctx) then
|
|
begin
|
|
Result := ctx.BkMode;
|
|
ctx.BkMode := bkMode;
|
|
end
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.SetCapture(AHandle: HWND): HWND;
|
|
begin
|
|
Result := FCaptureControl;
|
|
FCaptureControl := AHandle;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.SetCaretPos(X, Y: Integer): Boolean;
|
|
begin
|
|
Result := CocoaCaret.SetCaretPos(X, Y);
|
|
end;
|
|
|
|
function TCocoaWidgetSet.SetCaretPosEx(Handle: HWnd; X, Y: Integer): Boolean;
|
|
begin
|
|
Result := CocoaCaret.SetCaretPos(X, Y);
|
|
end;
|
|
|
|
function TCocoaWidgetSet.SetCaretRespondToFocus(handle: HWND;
|
|
ShowHideOnFocus: boolean): Boolean;
|
|
begin
|
|
Result:=inherited SetCaretRespondToFocus(handle, ShowHideOnFocus);
|
|
end;
|
|
|
|
function TCocoaWidgetSet.RectVisible(dc: hdc; const ARect: TRect): Boolean;
|
|
var
|
|
ClipBox: CGRect;
|
|
ctx : TCocoaContext;
|
|
R: TRect;
|
|
begin
|
|
ctx := CheckDC(DC);
|
|
Result := Assigned(ctx) and (ARect.Right > ARect.Left) and (ARect.Bottom > ARect.Top);
|
|
|
|
if not Result then Exit;
|
|
|
|
// In Quartz 2D there is no direct access to clipping path of CGContext,
|
|
// therefore we can only test bounding box of the clipping path.
|
|
|
|
ClipBox := CGContextGetClipBoundingBox(ctx.CGContext);
|
|
Result := IntersectRect(R, ARect, CGRectToRect(ClipBox));
|
|
end;
|
|
|
|
function TCocoaWidgetSet.ReleaseCapture : Boolean;
|
|
begin
|
|
FCaptureControl:=0;
|
|
Result := True;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.ReleaseDC(hWnd: HWND; DC: HDC): Integer;
|
|
var
|
|
ctx: TCocoaContext;
|
|
begin
|
|
Result := 0;
|
|
ctx := CheckDC(DC);
|
|
if not Assigned(ctx) then
|
|
Exit;
|
|
if (ctx <> DefaultContext) and (ctx<>ScreenContext) and (not ctx.isControlDC) then
|
|
ctx.Free;
|
|
Result := 1;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.GetWindowOrgEx(dc: hdc; P: PPoint): Integer;
|
|
var
|
|
ctx: TCocoaContext;
|
|
begin
|
|
ctx := CheckDC(dc);
|
|
if not Assigned(ctx) then
|
|
Exit(0);
|
|
if Assigned(P) then
|
|
P^ := ctx.WindowOfs;
|
|
Result:=1;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.SetCursor(ACursor: HCURSOR): HCURSOR;
|
|
begin
|
|
if ACursor = 0 then Result := 0 else
|
|
Result := HCURSOR(TCocoaCursor(ACursor).Install);
|
|
end;
|
|
|
|
function TCocoaWidgetSet.SetCursorPos(X, Y: Integer): Boolean;
|
|
var
|
|
CursorPos: CGPoint;
|
|
begin
|
|
Result := False;
|
|
|
|
CursorPos.X := X;
|
|
CursorPos.Y := Y;
|
|
if CGWarpMouseCursorPosition(CursorPos) <> noErr then Exit;
|
|
Result := True;
|
|
end;
|
|
|
|
function NeedsFocusNotifcation(event: NSEvent; win: NSWindow): Boolean;
|
|
begin
|
|
Result := (Assigned(win))
|
|
and (not Assigned(event) or (event.window <> win));
|
|
end;
|
|
|
|
function TCocoaWidgetSet.SetFocus(Handle: HWND): HWND;
|
|
var
|
|
Obj: NSObject;
|
|
lView: NSView;
|
|
cb: ICommonCallback;
|
|
begin
|
|
if Handle <> 0 then
|
|
begin
|
|
Result := GetFocus;
|
|
if Result = Handle then
|
|
Exit;
|
|
Obj := NSObject(Handle);
|
|
if Obj.isKindOfClass(NSWindow) then
|
|
begin
|
|
NSWindow(Obj).makeKeyWindow;
|
|
NSWindow(Obj).makeFirstResponder(nil);
|
|
end
|
|
else
|
|
begin
|
|
lView := obj.lclContentView;
|
|
if lView <> nil then
|
|
begin
|
|
if lView.window <> nil then
|
|
begin
|
|
lView.window.makeKeyWindow;
|
|
if lView.window.makeFirstResponder(lView.lclContentView) then
|
|
begin
|
|
// initial focus set (right before the event loop starts)
|
|
if NeedsFocusNotifcation(NSApp.currentEvent, lView.window) then
|
|
begin
|
|
cb := lView.lclGetCallback;
|
|
if Assigned(cb) then cb.BecomeFirstResponder;
|
|
end;
|
|
end;
|
|
end else
|
|
Result := 0; // the view is on window, cannot set focus. Fail
|
|
end else
|
|
Result := 0;
|
|
end;
|
|
end
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.SetForegroundWindow(HWnd: HWND): boolean;
|
|
var
|
|
Obj: NSObject;
|
|
lWin: NSWindow;
|
|
begin
|
|
Result := HWnd <> 0;
|
|
if Result then
|
|
begin
|
|
{$ifdef BOOLFIX}
|
|
NSApp.activateIgnoringOtherApps_(Ord(True));
|
|
{$else}
|
|
NSApp.activateIgnoringOtherApps(True);
|
|
{$endif}
|
|
Obj := NSObject(HWnd);
|
|
lWin := NSWindow(GetNSObjectWindow(Obj));
|
|
if lWin <> nil then
|
|
lWin.makeKeyAndOrderFront(NSApp)
|
|
else
|
|
Result := False;
|
|
end;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.SetMenu(AWindowHandle: HWND; AMenuHandle: HMENU): Boolean;
|
|
var
|
|
lWin: NSWindow;
|
|
frm : TCustomForm;
|
|
begin
|
|
Result := False;
|
|
|
|
lWin := NSWindow(GetNSObjectWindow(NSObject(AWindowHandle)));
|
|
|
|
frm := HWNDToForm(AWindowHandle);
|
|
if Assigned(frm) and (csDesigning in frm.ComponentState) then begin
|
|
Result := true;
|
|
Exit;
|
|
end;
|
|
if not Assigned(frm) then Exit;
|
|
|
|
if (lWin <> nil) and lWin.isKindOfClass(TCocoaWindow) and
|
|
//todo: why is Menu handle checked here?
|
|
(frm.Menu.Handle = AMenuHandle)
|
|
then
|
|
begin
|
|
if lWin.isKeyWindow or lWin.isMainWindow then
|
|
SetMainMenu(AMenuHandle, frm.Menu);
|
|
Result := True;
|
|
end;
|
|
end;
|
|
|
|
{------------------------------- FONT AND TEXT --------------------------------}
|
|
|
|
function TCocoaWidgetSet.SetTextColor(DC: HDC; Color: TColorRef): TColorRef;
|
|
var
|
|
ctx: TCocoaContext;
|
|
begin
|
|
ctx := CheckDC(DC);
|
|
if Assigned(ctx) then
|
|
begin
|
|
Result := ctx.TextColor;
|
|
ctx.TextColor := TColor(Color);
|
|
end
|
|
else
|
|
Result := CLR_INVALID;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.SetViewPortOrgEx(DC: HDC; NewX, NewY: Integer;
|
|
OldPoint: PPoint): Boolean;
|
|
var
|
|
ctx: TCocoaContext;
|
|
begin
|
|
Result := False;
|
|
ctx := CheckDC(DC);
|
|
if not Assigned(ctx) then Exit;
|
|
|
|
if Assigned(OldPoint) then
|
|
OldPoint^ := ctx.ViewportOfs;
|
|
ctx.ViewportOfs := Types.Point(NewX, NewY);
|
|
Result := True;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.SetWindowOrgEx(DC: HDC; NewX, NewY: Integer;
|
|
OldPoint: PPoint): Boolean;
|
|
var
|
|
ctx: TCocoaContext;
|
|
begin
|
|
Result := False;
|
|
ctx := CheckDC(DC);
|
|
if not Assigned(ctx) then Exit;
|
|
|
|
if Assigned(OldPoint) then
|
|
OldPoint^ := ctx.WindowOfs;
|
|
ctx.WindowOfs := Types.Point(NewX, NewY);
|
|
Result := True;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.ShowCaret(Handle: HWND): Boolean;
|
|
var
|
|
lView: NSView;
|
|
begin
|
|
//writeln('WinAPI. show caret ',PtrUInt(Handle));
|
|
if (Handle = 0) then lView := nil
|
|
else lView := NSView(Handle).lclContentView;
|
|
|
|
Result := CocoaCaret.ShowCaret(lView)
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: GetSystemMetrics
|
|
Params: NIndex - System metric to retrieve
|
|
Returns: The requested system metric value
|
|
|
|
Retrieves various system metrics.
|
|
------------------------------------------------------------------------------}
|
|
function TCocoaWidgetSet.GetSystemMetrics(nIndex: Integer): Integer;
|
|
begin
|
|
Result := 0;
|
|
|
|
{$IFDEF VerboseWinAPI}
|
|
DebugLn('TCocoaWidgetSet.GetSystemMetrics NIndex: ' + DbgS(NIndex));
|
|
{$ENDIF}
|
|
|
|
case NIndex of
|
|
SM_CXHSCROLL,
|
|
SM_CYHSCROLL,
|
|
SM_CXVSCROLL,
|
|
SM_CYVSCROLL:
|
|
Result := Round(NSScroller.scrollerWidthForControlSize(NSRegularControlSize));
|
|
SM_CXSCREEN,
|
|
SM_CXVIRTUALSCREEN,
|
|
SM_CXFULLSCREEN: Result := Round(NSScreen.mainScreen.frame.size.width);
|
|
SM_CYSCREEN,
|
|
SM_CYVIRTUALSCREEN,
|
|
SM_CYFULLSCREEN: Result := Round(NSScreen.mainScreen.frame.size.height);
|
|
SM_XVIRTUALSCREEN: Result := Round(NSScreen.mainScreen.frame.origin.x);
|
|
SM_YVIRTUALSCREEN: Result := Round(NSScreen.mainScreen.frame.origin.y);
|
|
SM_CXSMICON,
|
|
SM_CYSMICON:
|
|
Result := 16;
|
|
SM_CXICON,
|
|
SM_CYICON:
|
|
Result := 128;
|
|
SM_CXCURSOR,
|
|
SM_CYCURSOR:
|
|
begin
|
|
{ if TCarbonCursor.HardwareCursorsSupported then
|
|
Result := 64 else}
|
|
Result := 16;
|
|
end;
|
|
SM_CXDRAG,SM_CYDRAG: Result := 5;
|
|
SM_CXHTHUMB, SM_CYVTHUMB:
|
|
Result := Round(NSScroller.scrollerWidthForControlSize(NSRegularControlSize));
|
|
SM_SWSCROLLBARSPACING:
|
|
Result := 0;
|
|
SM_LCLHasFormAlphaBlend:
|
|
Result := 1;
|
|
else
|
|
DebugLn('TCocoaWidgetSet.GetSystemMetrics TODO ', DbgS(NIndex));;
|
|
end;
|
|
|
|
{$IFDEF VerboseWinAPI}
|
|
DebugLn('TCocoaWidgetSet.GetSystemMetrics Result: ' + DbgS(Result));
|
|
{$ENDIF}
|
|
end;
|
|
|
|
function TCocoaWidgetSet.GetTextColor(DC: HDC) : TColorRef;
|
|
var
|
|
ctx: TCocoaContext;
|
|
begin
|
|
ctx := CheckDC(DC);
|
|
if Assigned(ctx) then
|
|
Result := ColorToRGB(ctx.TextColor)
|
|
else
|
|
Result := CLR_INVALID;
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: GetTextExtentPoint
|
|
Params: DC - Handle of device context
|
|
Str - Text string
|
|
Count - Number of characters in string
|
|
Size - The record for the dimensions of the string
|
|
Returns: If the function succeeds
|
|
|
|
Computes the width and height of the specified string of text
|
|
------------------------------------------------------------------------------}
|
|
function TCocoaWidgetSet.GetTextExtentPoint(DC: HDC; Str: PChar; Count: Integer; var Size: TSize): Boolean;
|
|
var
|
|
ctx : TCocoaContext;
|
|
begin
|
|
{$IFDEF VerboseWinAPI}
|
|
DebugLn('[TCocoaWidgetSet.GetTextExtentPoint] DC: %x Str: %s Count: %d', [DC, Str, Count]);
|
|
{$ENDIF}
|
|
ctx:=CheckDC(DC);
|
|
Result:=Assigned(ctx);
|
|
if not Assigned(ctx) then Exit(False);
|
|
Result := ctx.GetTextExtentPoint(Str, Count, Size);
|
|
{$IFDEF VerboseWinAPI}
|
|
DebugLn('[TCocoaWidgetSet.GetTextExtentPoint] Size: %d,%d', [Size.cx, Size.cy]);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: GetTextMetrics
|
|
Params: DC - Handle of device context
|
|
TM - The Record for the text metrics
|
|
Returns: If the function succeeds
|
|
|
|
Fills the specified buffer with the metrics for the currently selected font
|
|
TODO: get exact max. and av. char width, pitch and charset
|
|
------------------------------------------------------------------------------}
|
|
function TCocoaWidgetSet.GetTextMetrics(DC: HDC; var TM: TTextMetric): Boolean;
|
|
var
|
|
ctx: TCocoaContext;
|
|
begin
|
|
ctx := CheckDC(DC);
|
|
Result := Assigned(ctx) and ctx.GetTextMetrics(TM);
|
|
end;
|
|
|
|
function TCocoaWidgetSet.GetViewPortOrgEx(DC: HDC; P: PPoint): Integer;
|
|
var
|
|
ctx: TCocoaContext;
|
|
begin
|
|
ctx := CheckDC(dc);
|
|
if not Assigned(ctx) then
|
|
Exit(0);
|
|
if Assigned(P) then
|
|
P^ := ctx.ViewportOfs;
|
|
Result:=1;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.TextOut(DC: HDC; X,Y: Integer; Str: Pchar; Count: Integer) : Boolean;
|
|
begin
|
|
Result := ExtTextOut(DC, X, Y, 0, nil, Str, Count, nil);
|
|
end;
|
|
|
|
function TCocoaWidgetSet.SaveDC(DC: HDC): Integer;
|
|
var
|
|
ctx: TCocoaContext;
|
|
begin
|
|
ctx := CheckDC(DC);
|
|
if Assigned(ctx) then
|
|
Result := ctx.SaveDC
|
|
else
|
|
Result:=0;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.ScreenToClient(Handle: HWND; var P: TPoint): Integer;
|
|
begin
|
|
Result := Ord(Handle <> 0);
|
|
|
|
if Result = 1 then
|
|
NSObject(Handle).lclScreenToLocal(P.X, P.Y);
|
|
end;
|
|
|
|
function TCocoaWidgetSet.ScrollWindowEx(hWnd: HWND; dx, dy: Integer; prcScroll, prcClip: PRect; hrgnUpdate: HRGN; prcUpdate: PRect; flags: UINT): Boolean;
|
|
var
|
|
obj: NSOBject;
|
|
v : NSView;
|
|
begin
|
|
obj:=NSObject(hWnd);
|
|
Result:=Assigned(obj) and (obj.isKindOfClass(NSView));
|
|
if not Result then Exit;
|
|
|
|
v:=NSView(obj).lclContentView;
|
|
// todo: parse the passed parameters.
|
|
// the content of the window could be already prepared
|
|
// thus not entire control should be invalided
|
|
{$ifdef BOOLFIX}
|
|
v.setNeedsDisplay__(Ord(true));
|
|
{$else}
|
|
v.setNeedsDisplay_(true);
|
|
{$endif}
|
|
end;
|
|
|
|
function TCocoaWidgetSet.SelectClipRGN(DC: hDC; RGN: HRGN): Longint;
|
|
begin
|
|
Result := ExtSelectClipRgn(DC, RGN, RGN_COPY);
|
|
end;
|
|
|
|
function TCocoaWidgetSet.SetSysColors(cElements: Integer; const lpaElements; const lpaRgbValues): Boolean;
|
|
var
|
|
n: Integer;
|
|
Element: LongInt;
|
|
Color: NSColor;
|
|
begin
|
|
Result := False;
|
|
if cElements > MAX_SYS_COLORS then Exit;
|
|
|
|
for n := 0 to cElements - 1 do
|
|
begin
|
|
Element := PInteger(@lpaElements)[n];
|
|
if (Element > MAX_SYS_COLORS) or (Element < 0) then
|
|
Exit;
|
|
Color := ColorToNSColor(PDWord(@lpaRgbValues)[n]);
|
|
if (FSysColorBrushes[Element] <> 0) then
|
|
TCocoaBrush(FSysColorBrushes[Element]).Color := Color
|
|
else
|
|
FSysColorBrushes[Element] := HBrush(TCocoaBrush.Create(Color, True));
|
|
end;
|
|
|
|
Result := True;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.RestoreDC(DC: HDC; SavedDC: Integer): Boolean;
|
|
var
|
|
ctx: TCocoaContext;
|
|
begin
|
|
ctx := CheckDC(DC);
|
|
if Assigned(ctx) then
|
|
Result := ctx.RestoreDC(SavedDC)
|
|
else
|
|
Result := False;
|
|
end;
|
|
|
|
function TCocoaWidgetSet.RoundRect(DC: HDC; X1, Y1, X2, Y2: Integer; RX,
|
|
RY: Integer): Boolean;
|
|
begin
|
|
Result:=inherited RoundRect(DC, X1, Y1, X2, Y2, RX, RY);
|
|
end;
|
|
|
|
//##apiwiz##eps## // Do not remove, no wizard declaration after this line
|