lazarus/lcl/interfaces/carbon/carbonproc.pp
tombo c44f23e18d Carbon intf:
- patch #0008537 by Philip J. Hess - Adds basic TOpenDialog, TSaveDialog and TSelectDirectoryDialog
- debug and tracing info, OSError for checking Carbon calls as Philip J. Hess proposed
- started TMainMenu, TPopupMenu, Hints
- TabOrder, TabStop, focusing
- TGraphicControl and TCustomControl descendants improved 

git-svn-id: trunk@10828 -
2007-03-29 13:50:41 +00:00

999 lines
34 KiB
ObjectPascal

{ $Id$
----------------------------------------
carbonproc.pp - Carbon interface procs
----------------------------------------
@created(Wed Aug 26st WET 2005)
@lastmod($Date$)
@author(Marc Weustink <marc@@lazarus.dommelstein.net>)
This unit contains procedures/functions needed for the Carbon <-> LCL interface
Common carbon untilities (usable by other projects) go to CarbonUtils
*****************************************************************************
* *
* This file is part of the Lazarus Component Library (LCL) *
* *
* See the file COPYING.modifiedLGPL, included in this distribution, *
* for details about the copyright. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* *
*****************************************************************************
}
unit CarbonProc;
{$mode objfpc}{$H+}
interface
uses
FPCMacOSAll, Classes, Types, LCLType, LCLProc, LCLClasses, LMessages,
Controls, Forms, Avl_Tree, SysUtils, Graphics, Math, GraphType,
CarbonDef, CarbonPrivate, CarbonMenus;
function AsControlRef(Handle: HWND): ControlRef; inline;
function AsWindowRef(Handle: HWND): WindowRef; inline;
function AsMenuRef(Handle: HMENU): MenuRef; inline;
function CheckHandle(const AWinControl: TWinControl; const AClass: TClass; const DbgText: String): Boolean;
function CheckWidget(const Handle: HWND; const AMethodName: String; AParamName: String = ''): Boolean;
function CheckMenu(const Menu: HMENU; const AMethodName: String; AParamName: String = ''): Boolean;
function CheckDC(const DC: HDC; const AMethodName: String; AParamName: String = ''): Boolean;
function CheckGDIObject(const GDIObject: HGDIOBJ; const AMethodName: String; AParamName: String = ''): Boolean;
function CheckBitmap(const Bitmap: HBITMAP; const AMethodName: String; AParamName: String = ''): Boolean;
function CheckCursor(const Cursor: HCURSOR; const AMethodName: String; AParamName: String = ''): Boolean;
function OSError(AResult: OSStatus; const AMethodName, ACallName: String;
const AText: String = ''): Boolean;// inline;
function OSError(AResult: OSStatus; const AObject: TObject; const AMethodName, ACallName: String;
const AText: String = ''): Boolean;// inline;
function OSError(AResult: OSStatus; const AClass: TClass; const AMethodName, ACallName: String;
const AText: String = ''): Boolean;// inline;
function OSError(AResult: OSStatus; const AObject: TObject; const AMethodName, ACallName: String;
const AText: String; AValidResult: OSStatus): Boolean;// inline;
function GetCarbonWidget(AWidget: Pointer): TCarbonWidget;
function GetCarbonWindow(AWidget: WindowRef): TCarbonWindow;
function GetCarbonControl(AWidget: ControlRef): TCarbonControl;
function GetCarbonMsgKeyState: PtrInt;
function GetCarbonShiftState: TShiftState;
function FindCarbonFontID(const FontName: String): ATSUFontID;
function FontStyleToQDStyle(const AStyle: TFontStyles): FPCMacOSAll.Style;
procedure FillStandardDescription(var Desc: TRawImageDescription);
function RegisterEventHandler(AHandler: TCarbonWSEventHandlerProc): EventHandlerUPP;
procedure UnRegisterEventHandler(AHandler: TCarbonWSEventHandlerProc);
procedure CreateCFString(const S: String; out AString: CFStringRef); inline;
procedure FreeCFString(var AString: CFStringRef); inline;
function CFStringToStr(AString: CFStringRef): String;
function GetCarbonRect(Left, Top, Width, Height: Integer): FPCMacOSAll.Rect;
function GetCarbonRect(const ARect: TRect): FPCMacOSAll.Rect;
function ParamsToCarbonRect(const AParams: TCreateParams): FPCMacOSAll.Rect;
type
CGRectArray = Array of CGRect;
function ExcludeRect(const A, B: TRect): CGRectArray;
function GetCGRect(X1, Y1, X2, Y2: Integer): CGRect;
function GetCGRectSorted(X1, Y1, X2, Y2: Integer): CGRect;
function RectToCGRect(const ARect: TRect): CGRect;
function CGRectToRect(const ARect: CGRect): TRect;
function ParamsToHIRect(const AParams: TCreateParams): HIRect;
function CarbonRectToRect(const ARect: FPCMacOSAll.Rect): TRect;
function ColorToRGBColor(const AColor: TColor): RGBColor;
function RGBColorToColor(const AColor: RGBColor): TColor; inline;
function CreateCGColor(const AColor: TColor): CGColorRef;
function Dbgs(const ASize: TSize): string; overload;
function Dbgs(const ARect: FPCMacOSAll.Rect): string; overload;
function Dbgs(const AColor: FPCMacOSAll.RGBColor): string; overload;
implementation
uses CarbonInt, CarbonCanvas, CarbonGDIObjects;
{------------------------------------------------------------------------------
Name: AsControlRef
Params: Handle - Handle of window control
Returns: Carbon control
------------------------------------------------------------------------------}
function AsControlRef(Handle: HWND): ControlRef;
begin
Result := ControlRef(TCarbonControl(Handle).Widget);
end;
{------------------------------------------------------------------------------
Name: AsWindowRef
Params: Handle - Handle of window
Returns: Carbon window
------------------------------------------------------------------------------}
function AsWindowRef(Handle: HWND): WindowRef;
begin
Result := WindowRef(TCarbonWindow(Handle).Widget);
end;
{------------------------------------------------------------------------------
Name: AsMenuRef
Params: Handle - Handle of menu
Returns: Carbon menu
------------------------------------------------------------------------------}
function AsMenuRef(Handle: HMENU): MenuRef; inline;
begin
Result := TCarbonMenu(Handle).Menu;
end;
const
CarbonWSPrefix = 'TCarbonWidgetSet.';
{------------------------------------------------------------------------------
Name: CheckHandle
Params: AWinControl - Handle of window
AClass - Class
DbgText - Text to output on invalid DC
Returns: If the wincontrol handle is allocated and valid
------------------------------------------------------------------------------}
function CheckHandle(const AWinControl: TWinControl; const AClass: TClass;
const DbgText: String): Boolean;
begin
if AWinControl <> nil then
begin
if TObject(AWinControl.Handle) is TCarbonWidget then
begin
{$IFDEF VerboseWSClass}
DebugLn(AClass.ClassName + '.' + DbgText + ' for ' + AWinControl.Name);
{$ENDIF}
Result := True;
end
else
begin
Result := False;
DebugLn(AClass.ClassName + '.' + DbgText + ' for ' + AWinControl.Name +
' failed: Handle ' + DbgS(Integer(AWinControl.Handle)) + ' is invalid!');
end;
end
else
begin
Result := False;
DebugLn(AClass.ClassName + '.' + DbgText + ' for ' + AWinControl.Name +
' failed: WinControl is nil!');
end;
end;
{------------------------------------------------------------------------------
Name: CheckWidget
Params: Handle - Handle of window
AMethodName - Method name
AParamName - Param name
Returns: If the window is valid
------------------------------------------------------------------------------}
function CheckWidget(const Handle: HWND; const AMethodName: String;
AParamName: String): Boolean;
begin
if TObject(Handle) is TCarbonWidget then Result := True
else
begin
if Pos('.', AMethodName) = 0 then
DebugLn(CarbonWSPrefix + AMethodName + ' Error - invalid widget ' +
AParamName + ' = ' + IntToStr(Integer(Handle)) + '!')
else
DebugLn(AMethodName + ' Error - invalid widget ' + AParamName + ' = ' +
IntToStr(Integer(Handle)) + '!');
Result := False;
end;
end;
{------------------------------------------------------------------------------
Name: CheckMenu
Params: Menu - Handle of menu
AMethodName - Method name
AParamName - Param name
Returns: If the menu is valid
------------------------------------------------------------------------------}
function CheckMenu(const Menu: HMENU; const AMethodName: String;
AParamName: String): Boolean;
begin
if TObject(Menu) is TCarbonMenu then Result := True
else
begin
if Pos('.', AMethodName) = 0 then
DebugLn(CarbonWSPrefix + AMethodName + ' Error - invalid menu ' +
AParamName + ' = ' + IntToStr(Integer(Menu)) + '!')
else
DebugLn(AMethodName + ' Error - invalid menu ' + AParamName + ' = ' +
IntToStr(Integer(Menu)) + '!');
Result := False;
end;
end;
{------------------------------------------------------------------------------
Name: CheckDC
Params: DC - Handle to a device context (TCarbonDeviceContext)
AMethodName - Method name
AParamName - Param name
Returns: If the DC is valid
------------------------------------------------------------------------------}
function CheckDC(const DC: HDC; const AMethodName: String;
AParamName: String): Boolean;
begin
if TObject(DC) is TCarbonDeviceContext then Result := True
else
begin
if Pos('.', AMethodName) = 0 then
DebugLn(CarbonWSPrefix + AMethodName + ' Error - invalid DC ' +
AParamName + ' = ' + IntToStr(Integer(DC)) + '!')
else
DebugLn(AMethodName + ' Error - invalid DC ' + AParamName + ' = ' +
IntToStr(Integer(DC)) + '!');
Result := False;
end;
end;
{------------------------------------------------------------------------------
Name: CheckGDIObject
Params: GDIObject - Handle to a GDI Object (TCarbonFont, ...)
AMethodName - Method name
AParamName - Param name
Returns: If the GDIObject is valid
Remark: All handles for GDI objects must be pascal objects so we can
distinguish between them
------------------------------------------------------------------------------}
function CheckGDIObject(const GDIObject: HGDIOBJ; const AMethodName: String;
AParamName: String): Boolean;
begin
if TObject(GDIObject) is TCarbonGDIObject then Result := True
else
begin
if Pos('.', AMethodName) = 0 then
DebugLn(CarbonWSPrefix + AMethodName + ' Error - invalid GDIObject ' +
AParamName + ' = ' + IntToStr(Integer(GDIObject)) + '!')
else
DebugLn(AMethodName + ' Error - invalid GDIObject ' + AParamName + ' = ' +
IntToStr(Integer(GDIObject)) + '!');
Result := False;
end;
end;
{------------------------------------------------------------------------------
Name: CheckBitmap
Params: Bitmap - Handle to a bitmap (TCarbonBitmap)
AMethodName - Method name
AParamName - Param name
Returns: If the bitmap is valid
------------------------------------------------------------------------------}
function CheckBitmap(const Bitmap: HBITMAP; const AMethodName: String;
AParamName: String): Boolean;
begin
if TObject(Bitmap) is TCarbonBitmap then Result := True
else
begin
if Pos('.', AMethodName) = 0 then
DebugLn(CarbonWSPrefix + AMethodName + ' Error - invalid bitmap ' +
AParamName + ' = ' + IntToStr(Integer(Bitmap)) + '!')
else
DebugLn(AMethodName + ' Error - invalid bitmap ' + AParamName + ' = ' +
IntToStr(Integer(Bitmap)) + '!');
Result := False;
end;
end;
{------------------------------------------------------------------------------
Name: CheckCursor
Params: Cursor - Handle to a cursor (TCarbonCursor)
AMethodName - Method name
AParamName - Param name
Returns: If the cursor is valid
------------------------------------------------------------------------------}
function CheckCursor(const Cursor: HCURSOR; const AMethodName: String;
AParamName: String): Boolean;
begin
if TObject(Cursor) is TCarbonCursor then Result := True
else
begin
if Pos('.', AMethodName) = 0 then
DebugLn(CarbonWSPrefix + AMethodName + ' Error - invalid cursor ' +
AParamName + ' = ' + IntToStr(Integer(Cursor)) + '!')
else
DebugLn(AMethodName + ' Error - invalid cursor ' + AParamName + ' = ' +
IntToStr(Integer(Cursor)) + '!');
Result := False;
end;
end;
{------------------------------------------------------------------------------
Name: OSError
Params: AResult - Result of Carbon function call
AMethodName - Parent method name
ACallName - The Carbon function name
AText - Another text useful for debugging (param value, ...)
Returns: If an error was the result of calling the specified Carbon function
------------------------------------------------------------------------------}
function OSError(AResult: OSStatus; const AMethodName, ACallName: String;
const AText: String): Boolean;
begin
if AResult = noErr then Result := False
else
begin
Result := True;
DebugLn(AMethodName + ' Error: ' + ACallName + ' ' + AText +
' failed with result ' + DbgS(AResult));
end;
end;
{------------------------------------------------------------------------------
Name: OSError
Params: AResult - Result of Carbon function call
AObject - Method object
AMethodName - Parent method name
ACallName - The Carbon function name
AText - Another text useful for debugging (param value, ...)
Returns: If an error was the result of calling the specified Carbon function
------------------------------------------------------------------------------}
function OSError(AResult: OSStatus; const AObject: TObject;
const AMethodName, ACallName: String;
const AText: String = ''): Boolean;
begin
if AResult = noErr then Result := False
else
begin
Result := True;
DebugLn(AObject.ClassName + '.' + AMethodName + ' Error: ' + ACallName +
' ' + AText + ' failed with result ' + DbgS(AResult));
end;
end;
{------------------------------------------------------------------------------
Name: OSError
Params: AResult - Result of Carbon function call
AClass - Method object
AMethodName - Parent method name
ACallName - The Carbon function name
AText - Another text useful for debugging (param value, ...)
Returns: If an error was the result of calling the specified Carbon function
------------------------------------------------------------------------------}
function OSError(AResult: OSStatus; const AClass: TClass;
const AMethodName, ACallName: String;
const AText: String = ''): Boolean;
begin
if AResult = noErr then Result := False
else
begin
Result := True;
DebugLn(AClass.ClassName + '.' + AMethodName + ' Error: ' + ACallName +
' ' + AText + ' failed with result ' + DbgS(AResult));
end;
end;
{------------------------------------------------------------------------------
Name: OSError
Params: AResult - Result of Carbon function call
AObject - Method object
AMethodName - Parent method name
ACallName - The Carbon function name
AText - Another text useful for debugging (param value, ...)
AValidResult - Another result code that is valid like noErr
Returns: If an error was the result of calling the specified Carbon function
------------------------------------------------------------------------------}
function OSError(AResult: OSStatus; const AObject: TObject;
const AMethodName, ACallName: String;
const AText: String; AValidResult: OSStatus): Boolean;
begin
if (AResult = noErr) or (AResult = AValidResult) then Result := False
else
begin
Result := True;
DebugLn(AObject.ClassName + '.' + AMethodName + ' Error: ' + ACallName +
' ' + AText + ' failed with result ' + DbgS(AResult));
end;
end;
//=====================================================
// UPP mamanger
//=====================================================
type
TUPPAVLTreeNode = class(TAVLTreeNode)
public
UPP: EventHandlerUPP;
RefCount: Integer;
procedure Clear; reintroduce; // not overridable, so reintroduce since we only will call this clear
destructor Destroy; override;
end;
var
UPPTree: TAVLTree = nil;
procedure TUPPAVLTreeNode.Clear;
begin
if UPP <> nil
then begin
DisposeEventHandlerUPP(UPP);
UPP := nil;
end;
inherited Clear;
end;
destructor TUPPAVLTreeNode.Destroy;
begin
if UPP <> nil
then begin
DisposeEventHandlerUPP(UPP);
UPP := nil;
end;
inherited Destroy;
end;
{------------------------------------------------------------------------------
Name: GetCarbonWidget
Params: AWidget - Pointer to control or window widget
Returns: The Carbon widget
Retrieves widget for specified Carbon control or window
------------------------------------------------------------------------------}
function GetCarbonWidget(AWidget: Pointer): TCarbonWidget;
begin
if AWidget = nil then
begin
Result := nil;
Exit;
end;
if IsValidControlHandle(AWidget) then
Result := GetCarbonControl(ControlRef(AWidget))
else
// there is no (cheap) check for windows so assume a window
// when it is not a control.
Result := GetCarbonWindow(WindowRef(AWidget));
end;
{------------------------------------------------------------------------------
Name: GetCarbonWindow
Params: AWidget - Pointer to window widget
Returns: The Carbon window
Retrieves the Carbon window for specified window widget
------------------------------------------------------------------------------}
function GetCarbonWindow(AWidget: WindowRef): TCarbonWindow;
begin
if GetWindowProperty(AWidget, LAZARUS_FOURCC, WIDGETINFO_FOURCC,
SizeOf(TCarbonWidget), nil, @Result) <> noErr then Result := nil;
end;
{------------------------------------------------------------------------------
Name: GetCarbonControl
Params: AWidget - Pointer to control widget
Returns: The Carbon control
Retrieves the Carbon control for specified control widget
------------------------------------------------------------------------------}
function GetCarbonControl(AWidget: ControlRef): TCarbonControl;
begin
if GetControlProperty(AWidget, LAZARUS_FOURCC, WIDGETINFO_FOURCC,
SizeOf(TCarbonWidget), nil, @Result) <> noErr then Result := nil;
end;
{------------------------------------------------------------------------------
Name: GetCarbonMsgKeyState
Returns: The current state of mouse and function keys
------------------------------------------------------------------------------}
function GetCarbonMsgKeyState: PtrInt;
var
Modifiers, ButtonState: UInt32;
begin
Result := 0;
Modifiers := GetCurrentEventKeyModifiers; // shift, control, option, command
ButtonState := GetCurrentEventButtonState; // Bit 0 first button (left),
// bit 1 second (right), bit2 third (middle) ...
if (ButtonState and 1) > 0 then Inc(Result, MK_LButton);
if (ButtonState and 2) > 0 then Inc(Result, MK_RButton);
if (ButtonState and 4) > 0 then Inc(Result, MK_MButton);
if (shiftKey and Modifiers) > 0 then Inc(Result, MK_Shift);
if (cmdKey and Modifiers) > 0 then Inc(Result, MK_Control);
//DebugLn('GetCarbonMsgKeyState Result=',dbgs(KeysToShiftState(Result)),' Modifiers=',hexstr(Modifiers,8),' ButtonState=',hexstr(ButtonState,8));
end;
{------------------------------------------------------------------------------
Name: GetCarbonShiftState
Returns: The current shift state of mouse and function keys
------------------------------------------------------------------------------}
function GetCarbonShiftState: TShiftState;
var
Modifiers, ButtonState: UInt32;
begin
Result := [];
Modifiers := GetCurrentEventKeyModifiers; // shift, control, option, command
ButtonState := GetCurrentEventButtonState; // Bit 0 first button (left),
// bit 1 second (right), bit2 third (middle) ...
if (ButtonState and 1) > 0 then Include(Result, ssLeft);
if (ButtonState and 2) > 0 then Include(Result, ssRight);
if (ButtonState and 4) > 0 then Include(Result, ssMiddle);
if (shiftKey and Modifiers) > 0 then Include(Result, ssShift);
if (cmdKey and Modifiers) > 0 then Include(Result, ssCtrl);
if (controlKey and Modifiers) > 0 then Include(Result, ssMeta);
if (optionKey and Modifiers) > 0 then Include(Result, ssAlt);
if (alphaLock and Modifiers) > 0 then Include(Result, ssCaps);
//DebugLn('GetCarbonShiftState Result=',dbgs(Result),' Modifiers=',hexstr(Modifiers,8),' ButtonState=',hexstr(ButtonState,8));
end;
{------------------------------------------------------------------------------
Name: FindCarbonFontID
Params: FontName - The font name, UTF-8 encoded
Returns: Carbon font ID of font with the specified name
------------------------------------------------------------------------------}
function FindCarbonFontID(const FontName: String): ATSUFontID;
begin
Result := 0;
if (FontName <> '') and not SameText(FontName, 'default') then
begin
ATSUFindFontFromName(@FontName[1], Length(FontName),
kFontFamilyName, kFontMacintoshPlatform, kFontRomanScript,
kFontEnglishLanguage, Result);
end;
end;
{------------------------------------------------------------------------------
Name: FontStyleToQDStyle
Params: AStyle - Font style
Returns: QuickDraw Style
------------------------------------------------------------------------------}
function FontStyleToQDStyle(const AStyle: TFontStyles): FPCMacOSAll.Style;
begin
Result := FPCMacOSAll.normal;
if fsBold in AStyle then Result := Result or FPCMacOSAll.bold;
if fsItalic in AStyle then Result := Result or FPCMacOSAll.italic;
if fsUnderline in AStyle then Result := Result or FPCMacOSAll.underline;
// fsStrikeOut has no counterpart?
end;
{------------------------------------------------------------------------------
Name: FillStandardDescription
Params: Desc - Raw image description
Returns: Nothing
Fills the raw image description with standard Carbon internal image storing
description
------------------------------------------------------------------------------}
procedure FillStandardDescription(var Desc: TRawImageDescription);
begin
FillChar(Desc, SizeOf(Desc), 0);
Desc.Format := ricfRGBA;
Desc.HasPalette := False;
// Width and Height skipped
Desc.PaletteColorCount := 0;
Desc.ColorCount := Desc.PaletteColorCount;
Desc.BitOrder := riboReversedBits;
Desc.ByteOrder := riboMSBFirst;
Desc.LineEnd := rileDQWordBoundary; // 128bit aligned
Desc.AlphaSeparate := False;
Desc.LineOrder := riloTopToBottom;
Desc.BitsPerPixel := 32;
Desc.Depth := 32;
// 8-8-8-8 mode, $RRGGBBAA
Desc.RedPrec := 8;
Desc.GreenPrec := 8;
Desc.BluePrec := 8;
Desc.AlphaPrec := 8;
Desc.RedShift := 24;
Desc.GreenShift := 16;
Desc.BlueShift := 08;
Desc.AlphaShift := 00;
end;
{------------------------------------------------------------------------------
Name: RegisterEventHandler
Params: AHandler - Carbon event handler procedure
Returns: Event handler UPP
Registers new carbon event handler procedure
------------------------------------------------------------------------------}
function RegisterEventHandler(AHandler: TCarbonWSEventHandlerProc): EventHandlerUPP;
var
Node: TUPPAVLTreeNode;
begin
if UPPTree = nil then UPPTree := TAVLTree.Create;
Node := TUPPAVLTreeNode(UPPTree.Find(AHandler));
if Node = nil then
begin
Node := TUPPAVLTreeNode.Create;
Node.Data := AHandler;
Node.UPP := NewEventHandlerUPP(EventHandlerProcPtr(AHandler));
UPPTree.Add(Node);
end;
Inc(Node.Refcount);
Result := Node.UPP;
end;
{------------------------------------------------------------------------------
Name: UnRegisterEventHandler
Params: AHandler - Carbon event handler procedure
Returns: Nothing
Unregisters event handler procedure
------------------------------------------------------------------------------}
procedure UnRegisterEventHandler(AHandler: TCarbonWSEventHandlerProc);
var
Node: TUPPAVLTreeNode;
begin
if UPPTree = nil then Exit; //???
Node := TUPPAVLTreeNode(UPPTree.Find(AHandler));
if Node = nil then Exit; //???
if Node.Refcount <= 0 then
begin
DebugLn('[UnRegisterEventHandler] UPPInconsistency, Node.RefCount <= 0');
Exit;
end;
Dec(Node.Refcount);
if Node.Refcount > 0 then Exit;
// Sigh !
// there doesn't exist a light version of the avltree without buildin memmanager
// So, just free it and "pollute" the memmanager with our classes;
// Freeing our node is also not an option, since that would
// corrupt the tree (no handling for that).
// Tweaking the memmanager is also not possible since only the class is public
// and not the manager itself.
Node.Clear;
UPPTree.Delete(Node);
end;
{------------------------------------------------------------------------------
Name: CreateCFString
Params: S - UTF-8 string
AString - Core Foundation string ref
Returns: Nothing
Creates new Core Foundation string form specified string
------------------------------------------------------------------------------}
procedure CreateCFString(const S: String; out AString: CFStringRef);
begin
AString := CFStringCreateWithCString(nil, Pointer(PChar(S)), DEFAULT_CFSTRING_ENCODING);
end;
{------------------------------------------------------------------------------
Name: FreeCFString
Params: AString - Core Foundation string ref to free
Returns: Nothing
Frees specified Core Foundation string
------------------------------------------------------------------------------}
procedure FreeCFString(var AString: CFStringRef);
begin
if AString <> nil then
CFRelease(Pointer(AString));
end;
{------------------------------------------------------------------------------
Name: CFStringToStr
Params: AString - Core Foundation string ref
Returns: UTF-8 string
Converts Core Foundation string to string
------------------------------------------------------------------------------}
function CFStringToStr(AString: CFStringRef): String;
var
Str: Pointer;
StrSize: CFIndex;
begin
if AString = nil then
begin
Result := '';
Exit;
end;
// Try the quick way first
Str := CFStringGetCStringPtr(AString, DEFAULT_CFSTRING_ENCODING);
if Str <> nil then
Result := PChar(Str)
else
begin
// if that doesn't work this will
StrSize := CFStringGetLength(AString) + 1; // + 1 for null terminator
GetMem(Str, StrSize);
try
CFStringGetCString(AString, Str, StrSize, DEFAULT_CFSTRING_ENCODING);
Result := PChar(Str);
finally
System.FreeMem(Str);
end;
end;
end;
{------------------------------------------------------------------------------
Name: GetCarbonRect
Params: Left, Top, Width, Height - coordinates
Returns: Carbon Rect
------------------------------------------------------------------------------}
function GetCarbonRect(Left, Top, Width, Height: Integer): FPCMacOSAll.Rect;
begin
Result.Left := Left;
Result.Top := Top;
Result.Right := Left + Width;
Result.Bottom := Top + Height;
end;
{------------------------------------------------------------------------------
Name: GetCarbonRect
Params: ARect - Rectangle
Returns: Carbon Rect
------------------------------------------------------------------------------}
function GetCarbonRect(const ARect: TRect): FPCMacOSAll.Rect;
begin
Result.Left := ARect.Left;
Result.Top := ARect.Top;
Result.Right := ARect.Right;
Result.Bottom := ARect.Bottom;
end;
{------------------------------------------------------------------------------
Name: ParamsToCarbonRect
Params: AParams - Creation parameters
Returns: Carbon Rect from creation parameters
------------------------------------------------------------------------------}
function ParamsToCarbonRect(const AParams: TCreateParams): FPCMacOSAll.Rect;
begin
Result.Left := AParams.X;
Result.Top := AParams.Y;
Result.Right := AParams.X + AParams.Width;
Result.Bottom := AParams.Y + AParams.Height;
end;
{------------------------------------------------------------------------------
Name: ExcludeRect
Params: A - Source rectangle
B - Rectangle to be excluded
Returns: Array of CGRect, which are product of exclusion rectangle B from
rectangle A.
Note: The returned rectangles may overlay.
------------------------------------------------------------------------------}
function ExcludeRect(const A, B: TRect): CGRectArray;
begin
SetLength(Result, 0);
if (A.Left >= A.Right) or (A.Top >= A.Bottom) then Exit;
SetLength(Result, 1);
Result[0] := RectToCGRect(A);
if (B.Left >= B.Right) or (B.Top >= B.Bottom) then Exit;
if (B.Left < A.Right) and (B.Right > A.Left)
and (B.Top < A.Bottom) and (B.Bottom > A.Top) then
begin // rectangles have intersection
SetLength(Result, 0);
if B.Top > A.Top then
begin
SetLength(Result, Succ(Length(Result)));
Result[High(Result)] := GetCGRect(A.Left, A.Top, A.Right, B.Top);
end;
if B.Bottom < A.Bottom then
begin
SetLength(Result, Succ(Length(Result)));
Result[High(Result)] := GetCGRect(A.Left, B.Bottom, A.Right, A.Bottom);
end;
if B.Left > A.Left then
begin
SetLength(Result, Succ(Length(Result)));
Result[High(Result)] := GetCGRect(A.Left, A.Top, B.Left, A.Bottom);
end;
if B.Right < A.Right then
begin
SetLength(Result, Succ(Length(Result)));
Result[High(Result)] := GetCGRect(B.Right, A.Top, A.Right, A.Bottom);
end;
end;
end;
{------------------------------------------------------------------------------
Name: GetCGRect
Params: X1, Y1, X2, Y2 - Rectangle coordinates
Returns: CGRect
------------------------------------------------------------------------------}
function GetCGRect(X1, Y1, X2, Y2: Integer): CGRect;
begin
Result.origin.x := X1;
Result.size.width := X2 - X1;
Result.origin.y := Y1;
Result.size.height := Y2 - Y1;
end;
{------------------------------------------------------------------------------
Name: GetCGRectSorted
Params: X1, Y1, X2, Y2 - Rectangle coordinates
Returns: CGRect, coordinates are sorted
------------------------------------------------------------------------------}
function GetCGRectSorted(X1, Y1, X2, Y2: Integer): CGRect;
begin
if X1 <= X2 then
begin
Result.origin.x := X1;
Result.size.width := X2 - X1;
end
else
begin
Result.origin.x := X2;
Result.size.width := X1 - X2;
end;
if Y1 <= Y2 then
begin
Result.origin.y := Y1;
Result.size.height := Y2 - Y1;
end
else
begin
Result.origin.y := Y2;
Result.size.height := Y1 - Y2;
end;
end;
{------------------------------------------------------------------------------
Name: RectToCGRect
Params: ARect - Rectangle
Returns: CGRect
------------------------------------------------------------------------------}
function RectToCGRect(const ARect: TRect): CGRect;
begin
Result.origin.x := ARect.Left;
Result.origin.y := ARect.Top;
Result.size.width := ARect.Right - ARect.Left;
Result.size.height := ARect.Bottom - ARect.Top;
end;
{------------------------------------------------------------------------------
Name: CGRectToRect
Params: ARect - CGRect
Returns: TRect
------------------------------------------------------------------------------}
function CGRectToRect(const ARect: CGRect): TRect;
begin
Result.Left := Floor(ARect.origin.x);
Result.Top := Floor(ARect.origin.y);
Result.Right := Ceil(ARect.origin.x + ARect.size.width);
Result.Bottom := Ceil(ARect.origin.y + ARect.size.height);
end;
{------------------------------------------------------------------------------
Name: ParamsToHIRect
Params: AParams - Creation parameters
Returns: HIView Rect from creation parameters
------------------------------------------------------------------------------}
function ParamsToHIRect(const AParams: TCreateParams): HIRect;
begin
Result.origin.x := AParams.X;
Result.origin.y := AParams.Y;
Result.size.width := AParams.Width;
Result.size.height := AParams.Height;
end;
{------------------------------------------------------------------------------
Name: CarbonRectToRect
Params: ARect - Carbon Rect
Returns: Rectangle
------------------------------------------------------------------------------}
function CarbonRectToRect(const ARect: FPCMacOSAll.Rect): TRect;
begin
Result.Left := ARect.Left;
Result.Top := ARect.Top;
Result.Right := ARect.Right;
Result.Bottom := ARect.Bottom;
end;
{------------------------------------------------------------------------------
Name: ColorToRGBColor
Params: AColor - Color
Returns: Carbon RGBColor
------------------------------------------------------------------------------}
function ColorToRGBColor(const AColor: TColor): RGBColor;
var
V: TColor;
begin
V := ColorToRGB(AColor);
Result.Red := Red(V);
Result.Red := (Result.Red shl 8) or Result.Red;
Result.Green := Green(V);
Result.Green := (Result.Green shl 8) or Result.Green;
Result.Blue := Blue(V);
Result.Blue := (Result.Blue shl 8) or Result.Blue;
end;
{------------------------------------------------------------------------------
Name: RGBColorToColor
Params: AColor - Carbon RGBColor
Returns: Color
------------------------------------------------------------------------------}
function RGBColorToColor(const AColor: RGBColor): TColor;
begin
Result := RGBToColor(AColor.Red shr 8, AColor.Green shr 8, AColor.Blue shr 8);
end;
{------------------------------------------------------------------------------
Name: CreateCGColor
Params: AColor - Color
Returns: CGColorRef
Creates CGColorRef from the specified color. You are responsible for
releasing it by CGColorRelease.
------------------------------------------------------------------------------}
function CreateCGColor(const AColor: TColor): CGColorRef;
var
V: TColor;
F: Array [0..3] of Single;
begin
V := ColorToRGB(AColor);
F[0] := Red(V) / 255;
F[1] := Green(V) / 255;
F[2] := Blue(V) / 255;
F[3] := 1; // Alpha
Result := CGColorCreate(RGBColorSpace, @F[0]);
end;
function Dbgs(const ASize: TSize): string;
begin
Result := 'cx: ' + IntToStr(ASize.cx) + ' cy: ' + IntToStr(ASize.cy);
end;
function Dbgs(const ARect: FPCMacOSAll.Rect): String;
begin
Result := IntToStr(ARect.left) + ', ' + IntToStr(ARect.top)
+ ', ' + IntToStr(ARect.right) + ', ' + IntToStr(ARect.bottom);
end;
function Dbgs(const AColor: FPCMacOSAll.RGBColor): String;
begin
Result :=
'R: ' + IntToHex(AColor.Red, 4) +
' G: ' + IntToHex(AColor.Green, 4) +
' B: ' + IntToHex(AColor.Blue, 4);
end;
finalization
if UPPTree <> nil then FreeAndNil(UPPTree);
end.