Carbon intf: TSynEdit fixed textout, improved scrolling

- enhanced clipboard to use more text formats
- TComboBox.OnDropDown and OnCloseUp partial implementation

git-svn-id: trunk@12509 -
This commit is contained in:
tombo 2007-10-17 20:00:01 +00:00
parent 3badd0dfcc
commit 1a9ab26796
8 changed files with 317 additions and 126 deletions

View File

@ -609,6 +609,7 @@ var
W: WideString; W: WideString;
Tag: ATSUAttributeTag; Tag: ATSUAttributeTag;
DataSize: ByteCount; DataSize: ByteCount;
Options: ATSLineLayoutOptions;
PValue: ATSUAttributeValuePtr; PValue: ATSUAttributeValuePtr;
const const
SName = 'BeginTextRender'; SName = 'BeginTextRender';
@ -643,7 +644,19 @@ begin
PValue := @(CurrentFont.LineRotation); PValue := @(CurrentFont.LineRotation);
if OSError(ATSUSetLayoutControls(ALayout, 1, @Tag, @DataSize, @PValue), if OSError(ATSUSetLayoutControls(ALayout, 1, @Tag, @DataSize, @PValue),
Self, SName, 'ATSUSetLayoutControls', 'LineRotation') then Exit; Self, SName, 'ATSUSetLayoutControls', 'LineRotation') then Exit;
// disable fractional positions of glyphs in layout
// TODO: restrict to monspaced fonts only
Tag := kATSULineLayoutOptionsTag;
DataSize := SizeOf(ATSLineLayoutOptions);
Options := kATSLineFractDisable or kATSLineDisableAutoAdjustDisplayPos or
kATSLineDisableAllLayoutOperations or kATSLineUseDeviceMetrics;
PValue := @Options;
if OSError(ATSUSetLayoutControls(ALayout, 1, @Tag, @DataSize, @PValue),
Self, SName, 'ATSUSetLayoutControls', 'LineLayoutOptions') then Exit;
// set layout context // set layout context
Tag := kATSUCGContextTag; Tag := kATSUCGContextTag;
DataSize := SizeOf(CGContextRef); DataSize := SizeOf(CGContextRef);

View File

@ -38,9 +38,10 @@ type
{ TCarbonClipboard } { TCarbonClipboard }
TCarbonClipboard = class TCarbonClipboard = class
FOwnerShips: Integer;
private private
FPasteboards: Array [TClipboardType] of PasteboardRef; FPasteboards: Array [TClipboardType] of PasteboardRef;
FFormats: TList; // list of CFStringRef UTIs, 1 is reserved for text/plain FFormats: TList; // list of CFStringRef UTIs
FOnClipboardRequest: Array [TClipboardType] of TClipboardRequestEvent; FOnClipboardRequest: Array [TClipboardType] of TClipboardRequestEvent;
function FindFormat(const UTI: CFStringRef): TClipboardFormat; function FindFormat(const UTI: CFStringRef): TClipboardFormat;
@ -59,14 +60,16 @@ type
OnRequestProc: TClipboardRequestEvent; FormatCount: Integer; OnRequestProc: TClipboardRequestEvent; FormatCount: Integer;
Formats: PClipboardFormat): Boolean; Formats: PClipboardFormat): Boolean;
function RegisterFormat(const AMimeType: String): TClipboardFormat; function RegisterFormat(const AMimeType: String): TClipboardFormat;
public
property OwnerShips: Integer read FOwnerShips;
end; end;
var var
ClipboardTypeToPasteboard: Array [TClipboardType] of CFStringRef = ClipboardTypeToPasteboard: Array [TClipboardType] of CFStringRef =
( (
{ctPrimarySelection } kPasteboardUniqueName, // local application pasteboard {ctPrimarySelection } kPasteboardUniqueName, // local application pasteboard
{ctSecondarySelection} nil, // Find pasteboard {ctSecondarySelection} nil, // Find pasteboard
{ctClipboard } nil // standard global pasteboard {ctClipboard } nil // standard global pasteboard
); );
Clipboard: TCarbonClipboard; Clipboard: TCarbonClipboard;
@ -88,7 +91,7 @@ var
begin begin
for I := 1 to FFormats.Count - 1 do for I := 1 to FFormats.Count - 1 do
begin begin
if UTTypeConformsTo(UTI, CFStringRef(FFormats[I])) then if UTTypeEqual(UTI, CFStringRef(FFormats[I])) then
begin begin
Result := I; Result := I;
Exit; Exit;
@ -113,8 +116,14 @@ begin
FOnClipboardRequest[T] := nil; FOnClipboardRequest[T] := nil;
end; end;
FOwnerShips := 0;
FFormats := TList.Create; FFormats := TList.Create;
FFormats.Add(nil);
FFormats.Add(nil); // add default supported text formats
FFormats.Add(kUTTypePlainText);
FFormats.Add(kUTTypeUTF8PlainText);
FFormats.Add(kUTTypeUTF16PlainText);
RegisterFormat(PredefinedClipboardMimeTypes[pcfText]); RegisterFormat(PredefinedClipboardMimeTypes[pcfText]);
end; end;
@ -128,7 +137,7 @@ var
I: Integer; I: Integer;
S: CFStringRef; S: CFStringRef;
begin begin
for I := 0 to FFormats.Count - 1 do for I := 4 to FFormats.Count - 1 do // 0..3 are predefined
begin begin
S := FFormats[I]; S := FFormats[I];
FreeCFString(S); FreeCFString(S);
@ -157,6 +166,7 @@ begin
if (PasteboardSynchronize(FPasteboards[T]) and if (PasteboardSynchronize(FPasteboards[T]) and
kPasteboardClientIsOwner) = 0 then kPasteboardClientIsOwner) = 0 then
begin // inform LCL about ownership lost begin // inform LCL about ownership lost
Dec(FOwnerShips);
FOnClipboardRequest[T](0, nil); FOnClipboardRequest[T](0, nil);
end; end;
end; end;
@ -192,12 +202,6 @@ var
begin begin
if (FormatID > 0) and (FormatID < FFormats.Count) then if (FormatID > 0) and (FormatID < FFormats.Count) then
begin begin
if FormatID = 1 then
begin
Result := PredefinedClipboardMimeTypes[pcfText];
Exit;
end;
S := UTTypeCopyPreferredTagWithClass(CFStringRef(FFormats[FormatID]), kUTTagClassMIMEType); S := UTTypeCopyPreferredTagWithClass(CFStringRef(FFormats[FormatID]), kUTTagClassMIMEType);
try try
Result := CFStringToStr(S); Result := CFStringToStr(S);
@ -221,17 +225,34 @@ function TCarbonClipboard.GetData(ClipboardType: TClipboardType;
FormatID: TClipboardFormat; Stream: TStream): Boolean; FormatID: TClipboardFormat; Stream: TStream): Boolean;
var var
Pasteboard: PasteboardRef; Pasteboard: PasteboardRef;
I, J: Integer; I: Integer;
L: SizeUInt; UTI, CFString: CFStringRef;
Encoding: CFStringEncoding;
Flavors: CFArrayRef; Flavors: CFArrayRef;
UTI: CFStringRef;
FlavorCount: CFIndex;
FlavorData: CFDataRef; FlavorData: CFDataRef;
Count: ItemCount; Count: ItemCount;
ID: PasteboardItemID; ID: PasteboardItemID;
S: String; S: String;
const const
SName = 'GetData'; SName = 'GetData';
function HasFormat(Format: CFStringRef): Boolean;
var
FlavorCount: CFIndex;
J: Integer;
begin
Result := False;
FlavorCount := CFArrayGetCount(Flavors);
for J := 0 to FlavorCount - 1 do
if UTTypeEqual(Format, CFArrayGetValueAtIndex(Flavors, J)) then
begin
//DebugLn('Has UTI ' + CFStringToStr(Format));
Result := True;
Break;
end;
end;
begin begin
Result := False; Result := False;
@ -255,46 +276,55 @@ begin
if OSError(PasteboardCopyItemFlavors(Pasteboard, ID, Flavors), Self, SName, if OSError(PasteboardCopyItemFlavors(Pasteboard, ID, Flavors), Self, SName,
'PasteboardCopyItemFlavors') then Continue; 'PasteboardCopyItemFlavors') then Continue;
FlavorCount := CFArrayGetCount(Flavors); UTI := FFormats[FormatID];
for J := 0 to FlavorCount - 1 do if FormatID = 1 then
begin begin
UTI := CFArrayGetValueAtIndex(Flavors, J); if HasFormat(FFormats[2]) then UTI := FFormats[2] // check UTF-8 text
//DebugLn('TCarbonClipboard.GetData FlavorType: ' + CFStringToStr(UTI) + else
// ' ' + CFStringToStr(FFormats[FormatID])); if HasFormat(FFormats[3]) then UTI := FFormats[3] // check UTF-16 text
if UTTypeConformsTo(FFormats[FormatID], UTI) then else
if not HasFormat(UTI) then Exit; // check plain text
end
else
if not HasFormat(UTI) then Exit;
//DebugLn('TCarbonClipboard.GetData Paste FlavorType: ' + CFStringToStr(UTI));
if OSError(PasteboardCopyItemFlavorData(Pasteboard, ID, UTI, FlavorData),
Self, SGetData, 'PasteboardCopyItemFlavorData') then Continue;
try
if CFDataGetLength(FlavorData) = 0 then
begin begin
//DebugLn('TCarbonClipboard.GetData Paste FlavorType: ' + CFStringToStr(UTI));
if OSError(PasteboardCopyItemFlavorData(Pasteboard, ID, UTI, FlavorData),
Self, SGetData, 'PasteboardCopyItemFlavorData') then Continue;
try
if CFDataGetLength(FlavorData) = 0 then
begin
Result := True;
Exit;
end;
//DebugLn('TCarbonClipboard.GetData Paste FlavordataLength: ' + DbgS(CFDataGetLength(FlavorData)));
if FormatID = 1 then // convert text/plain UTF-16 to UTF-8
begin
SetLength(S, (CFDataGetLength(FlavorData) div 2) * 3);
if ConvertUTF16ToUTF8(PChar(S), Length(S) + 1,
PWideChar(CFDataGetBytePtr(FlavorData)), CFDataGetLength(FlavorData) div 2,
[toInvalidCharToSymbol], L) <> trNoError then Exit;
SetLength(S, L - 1);
Stream.Write(S[1], L - 1);
end
else
Stream.Write(CFDataGetBytePtr(FlavorData)^, CFDataGetLength(FlavorData));
finally
CFRelease(FlavorData);
end;
Result := True; Result := True;
Exit; Exit;
end; end;
//DebugLn('TCarbonClipboard.GetData Paste FlavordataLength: ' + DbgS(CFDataGetLength(FlavorData)));
if FormatID = 1 then
begin
if UTI = FFormats[2] then // UTF-8 text
Encoding := kCFStringEncodingUTF8;
if UTI = FFormats[3] then // UTF-16 text
Encoding := kCFStringEncodingUTF16;
if UTI = FFormats[1] then // plain text
Encoding := CFStringGetSystemEncoding;
CreateCFString(FlavorData, Encoding, CFString);
try
S := CFStringtoStr(CFString);
Stream.Write(S[1], Length(S));
finally
FreeCFString(CFString);
end;
end
else
Stream.Write(CFDataGetBytePtr(FlavorData)^, CFDataGetLength(FlavorData));
finally
CFRelease(FlavorData);
end; end;
Result := True;
Exit;
end; end;
end; end;
@ -343,10 +373,14 @@ begin
for J := 0 to FlavorCount - 1 do for J := 0 to FlavorCount - 1 do
begin begin
UTI := CFArrayGetValueAtIndex(Flavors, J); UTI := CFArrayGetValueAtIndex(Flavors, J);
//DebugLn('TCarbonClipboard.GetFormats ' + CFStringToStr(UTI));
FormatID := FindFormat(UTI); FormatID := FindFormat(UTI);
if FormatID = 0 then if FormatID = 0 then
FormatID := FFormats.Add(UTI); FormatID := FFormats.Add(UTI);
if FormatID < 4 then // if it is text format, add plain text format
if Formats.IndexOf(Pointer(1)) = -1 then Formats.Add(Pointer(1));
if Formats.IndexOf(Pointer(FormatID)) = -1 then if Formats.IndexOf(Pointer(FormatID)) = -1 then
begin begin
@ -388,46 +422,53 @@ function TCarbonClipboard.GetOwnerShip(ClipboardType: TClipboardType;
OnRequestProc: TClipboardRequestEvent; FormatCount: Integer; OnRequestProc: TClipboardRequestEvent; FormatCount: Integer;
Formats: PClipboardFormat): Boolean; Formats: PClipboardFormat): Boolean;
procedure AddData(Format: CFStringRef; CFData: CFDataRef);
begin
if CFData = nil then Exit;
//DebugLn('Add Data ' + CFStringToStr(Format));
OSError(PasteboardPutItemFlavor(FPasteboards[ClipboardType],
PasteboardItemID(1), Format, CFData, 0),
Self, 'GetOwnerShip', 'PasteboardPutItemFlavor');
end;
procedure PutOnClipboard; procedure PutOnClipboard;
var var
Data: CFDataRef; DataStream: TStringStream;
UTI: CFStringRef;
DataStream: TMemoryStream;
I: Integer; I: Integer;
L: SizeUInt; CFString: CFStringRef;
W: WideString;
begin begin
DataStream := TMemoryStream.Create; DataStream := TStringStream.Create('');
for I := 0 to FormatCount - 1 do for I := 0 to FormatCount - 1 do
begin begin
DataStream.Size := 0;
DataStream.Position := 0;
if not ((Formats[I] > 0) and (Formats[I] < FFormats.Count)) then if not ((Formats[I] > 0) and (Formats[I] < FFormats.Count)) then
begin begin
DebugLn('TCarbonClipboard.GetOwnerShip Error: Invalid Format ' + DbgS(Formats[I]) + ' specified!'); DebugLn('TCarbonClipboard.GetOwnerShip Error: Invalid Format ' + DbgS(Formats[I]) + ' specified!');
Continue; Continue;
end; end;
UTI := CFStringRef(FFormats[Formats[I]]); DataStream.Size := 0;
DataStream.Position := 0;
FOnClipBoardRequest[ClipboardType](Formats[I], DataStream); FOnClipBoardRequest[ClipboardType](Formats[I], DataStream);
if Formats[I] = 1 then // convert plain/text UTF-8 to UTF-16 if Formats[I] = 1 then // add more unicode and mac text formats
begin begin
SetLength(W, DataStream.Size); CreateCFString(DataStream.DataString, CFString);
if ConvertUTF8ToUTF16(PWideChar(W), Length(W) + 1, PChar(DataStream.Memory), try
DataStream.Size, [toInvalidCharToSymbol], L) <> trNoError then Exit; // UTF-8 text
AddData(FFormats[2], CFStringToData(CFString, kCFStringEncodingUTF8));
SetLength(W, L - 1); // UTF-16 text
Data := CFDataCreate(nil, PChar(W), (L - 1) * 2); AddData(FFormats[3], CFStringToData(CFString, kCFStringEncodingUTF16));
// plain text
AddData(FFormats[1], CFStringToData(CFString, CFStringGetSystemEncoding));
finally
FreeCFString(CFString);
end;
end end
else else
Data := CFDataCreate(nil, DataStream.Memory, DataStream.Size); AddData(FFormats[Formats[I]], CFDataCreate(nil, @DataStream.DataString[1],
DataStream.Size));
OSError(PasteboardPutItemFlavor(FPasteboards[ClipboardType],
PasteboardItemID(1), UTI, Data, 0),
Self, 'GetOwnerShip', 'PasteboardPutItemFlavor');
end; end;
DataStream.Free; DataStream.Free;
@ -435,13 +476,14 @@ function TCarbonClipboard.GetOwnerShip(ClipboardType: TClipboardType;
begin begin
Result := False; Result := False;
DebugLn('TCarbonClipboard.GetOwnerShip'); //DebugLn('TCarbonClipboard.GetOwnerShip');
if (FormatCount = 0) or (OnRequestProc = nil) then if (FormatCount = 0) or (OnRequestProc = nil) then
begin begin
// The LCL indicates it doesn't have the clipboard data anymore // The LCL indicates it doesn't have the clipboard data anymore
// and the interface can't use the OnRequestProc anymore. // and the interface can't use the OnRequestProc anymore.
FOnClipboardRequest[ClipboardType] := nil; FOnClipboardRequest[ClipboardType] := nil;
Dec(FOwnerShips);
end end
else else
begin begin
@ -450,6 +492,7 @@ begin
FOnClipboardRequest[ClipboardType] := nil; FOnClipboardRequest[ClipboardType] := nil;
if not Clear(ClipboardType) then Exit; if not Clear(ClipboardType) then Exit;
Inc(FOwnerShips);
FOnClipboardRequest[ClipboardType] := OnRequestProc; FOnClipboardRequest[ClipboardType] := OnRequestProc;
PutOnClipboard; PutOnClipboard;
end; end;
@ -467,16 +510,11 @@ function TCarbonClipboard.RegisterFormat(const AMimeType: String): TClipboardFor
var var
UTI, M: CFStringRef; UTI, M: CFStringRef;
begin begin
if AMimeType = PredefinedClipboardMimeTypes[pcfText] then CreateCFString(AMimeType, M);
CreateCFString('public.utf16-plain-text', UTI) try
else UTI := UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, M, nil);
begin finally
CreateCFString(AMimeType, M); FreeCFString(M);
try
UTI := UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, M, nil);
finally
FreeCFString(M);
end;
end; end;
Result := FindFormat(UTI); Result := FindFormat(UTI);
@ -497,7 +535,7 @@ initialization
finalization finalization
Clipboard.Free; FreeAndNil(Clipboard);
FreeCFString(ClipboardTypeToPasteboard[ctSecondarySelection]); FreeCFString(ClipboardTypeToPasteboard[ctSecondarySelection]);
FreeCFString(ClipboardTypeToPasteboard[ctClipboard]); FreeCFString(ClipboardTypeToPasteboard[ctClipboard]);

View File

@ -75,11 +75,14 @@ type
LCLObject: TWinControl; // LCL control which created this widget LCLObject: TWinControl; // LCL control which created this widget
Context: TCarbonContext; // Carbon content area context Context: TCarbonContext; // Carbon content area context
Widget: Pointer; // Reference to the Carbon window or control Widget: Pointer; // Reference to the Carbon window or control
public
procedure FocusSet; dynamic;
procedure FocusKilled; dynamic;
procedure BoundsChanged; virtual;
public public
constructor Create(const AObject: TWinControl; const AParams: TCreateParams); constructor Create(const AObject: TWinControl; const AParams: TCreateParams);
destructor Destroy; override; destructor Destroy; override;
procedure AddToWidget(AParent: TCarbonWidget); virtual; abstract; procedure AddToWidget(AParent: TCarbonWidget); virtual; abstract;
procedure BoundsChanged; virtual;
function GetClientRect(var ARect: TRect): Boolean; virtual; abstract; function GetClientRect(var ARect: TRect): Boolean; virtual; abstract;
function GetPreferredSize: TPoint; virtual; function GetPreferredSize: TPoint; virtual;
function GetMousePos: TPoint; virtual; abstract; function GetMousePos: TPoint; virtual; abstract;
@ -373,6 +376,26 @@ begin
end; end;
end; end;
{------------------------------------------------------------------------------
Method: TCarbonWidget.FocusSet
Handles set focus
------------------------------------------------------------------------------}
procedure TCarbonWidget.FocusSet;
begin
LCLSendSetFocusMsg(LCLObject);
end;
{------------------------------------------------------------------------------
Method: TCarbonWidget.FocusKilled
Handles kill focus
------------------------------------------------------------------------------}
procedure TCarbonWidget.FocusKilled;
begin
LCLSendKillFocusMsg(LCLObject);
end;
{------------------------------------------------------------------------------ {------------------------------------------------------------------------------
Method: TCarbonWidget.BoundsChanged Method: TCarbonWidget.BoundsChanged

View File

@ -82,6 +82,8 @@ type
class function GetValidEvents: TCarbonControlEvents; override; class function GetValidEvents: TCarbonControlEvents; override;
procedure ListItemSelected(AIndex: Integer); virtual; procedure ListItemSelected(AIndex: Integer); virtual;
procedure ValueChanged; override; procedure ValueChanged; override;
procedure FocusSet; override;
procedure FocusKilled; override;
public public
function GetText(var S: String): Boolean; override; function GetText(var S: String): Boolean; override;
procedure SetReadOnly(AReadOnly: Boolean); override; procedure SetReadOnly(AReadOnly: Boolean); override;
@ -630,6 +632,30 @@ begin
if FReadOnly then ListItemSelected(GetValue - 1); if FReadOnly then ListItemSelected(GetValue - 1);
end; end;
{------------------------------------------------------------------------------
Method: TCarbonComboBox.FocusSet
Handles set focus
------------------------------------------------------------------------------}
procedure TCarbonComboBox.FocusSet;
begin
inherited;
// emulate DropDown event here
LCLSendDropDownMsg(LCLObject);
end;
{------------------------------------------------------------------------------
Method: TCarbonComboBox.FocusKilled
Handles kill focus
------------------------------------------------------------------------------}
procedure TCarbonComboBox.FocusKilled;
begin
inherited;
// emulate CloseUp event here
LCLSendCloseUpMsg(LCLObject);
end;
{------------------------------------------------------------------------------ {------------------------------------------------------------------------------
Method: TCarbonComboBox.GetText Method: TCarbonComboBox.GetText
Params: S - Text Params: S - Text

View File

@ -471,7 +471,8 @@ begin
SendEventToEventTarget(Event, Target); SendEventToEventTarget(Event, Target);
ReleaseEvent(Event); ReleaseEvent(Event);
Clipboard.CheckOwnerShip; if Clipboard <> nil then
if Clipboard.OwnerShips > 0 then Clipboard.CheckOwnerShip;
until Application.Terminated; until Application.Terminated;

View File

@ -171,17 +171,19 @@ type
TCarbonCustomControl = class(TCarbonControl) TCarbonCustomControl = class(TCarbonControl)
private private
FScrollView: HIViewRef; FScrollView: HIViewRef;
FScrollOrigin: TPoint; FScrollOrigin: HIPoint;
FScrollSize: TPoint; FScrollSize: TPoint;
FScrollPageSize: TPoint; FScrollPageSize: TPoint;
FMulX: Single; // multiply x coords to fit real page size
FMulY: Single; // multiply y coords to fit real page size
protected protected
procedure RegisterEvents; override; procedure RegisterEvents; override;
procedure CreateWidget(const AParams: TCreateParams); override; procedure CreateWidget(const AParams: TCreateParams); override;
procedure DestroyWidget; override; procedure DestroyWidget; override;
function GetFrame(Index: Integer): ControlRef; override; function GetFrame(Index: Integer): ControlRef; override;
public public
procedure GetInfo(out AImageSize, AViewSize, ALineSize, AOrigin: TPoint); dynamic; procedure GetInfo(out AImageSize, AViewSize, ALineSize: HISize; out AOrigin: HIPoint); virtual;
procedure ScrollTo(const ANewOrigin: TPoint); dynamic; procedure ScrollTo(const ANewOrigin: HIPoint); virtual;
public public
procedure SetColor(const AColor: TColor); override; procedure SetColor(const AColor: TColor); override;
procedure SetFont(const AFont: TFont); override; procedure SetFont(const AFont: TFont); override;
@ -363,7 +365,6 @@ function CarbonScrollable_GetInfo(ANextHandler: EventHandlerCallRef;
AEvent: EventRef; AEvent: EventRef;
AWidget: TCarbonWidget): OSStatus; {$IFDEF darwin}mwpascal;{$ENDIF} AWidget: TCarbonWidget): OSStatus; {$IFDEF darwin}mwpascal;{$ENDIF}
var var
ImageSize, ViewSize, LineSize, Origin: TPoint;
ImageHISize, ViewHISize, LineHISize: HISize; ImageHISize, ViewHISize, LineHISize: HISize;
HIOrigin: HIPoint; HIOrigin: HIPoint;
const const
@ -373,12 +374,7 @@ begin
DebugLn('CarbonScrollable_GetInfo ', DbgSName(AWidget.LCLObject)); DebugLn('CarbonScrollable_GetInfo ', DbgSName(AWidget.LCLObject));
{$ENDIF} {$ENDIF}
(AWidget as TCarbonCustomControl).GetInfo(ImageSize, ViewSize, LineSize, Origin); (AWidget as TCarbonCustomControl).GetInfo(ImageHISize, ViewHISize, LineHISize, HIOrigin);
ImageHISize := PointToHISize(ImageSize);
ViewHISize := PointToHISize(ViewSize);
LineHISize := PointToHISize(LineSize);
HIOrigin := PointToHIPoint(Origin);
OSError(SetEventParameter(AEvent, kEventParamImageSize, typeHISize, OSError(SetEventParameter(AEvent, kEventParamImageSize, typeHISize,
SizeOf(HISize), @ImageHISize), SName, SSetEvent, 'kEventParamImageSize'); SizeOf(HISize), @ImageHISize), SName, SSetEvent, 'kEventParamImageSize');
@ -411,7 +407,7 @@ begin
SizeOf(HIPoint), nil, @Origin), 'CarbonScrollable_ScrollTo', SGetEvent, SizeOf(HIPoint), nil, @Origin), 'CarbonScrollable_ScrollTo', SGetEvent,
'kEventParamOrigin') then Exit; 'kEventParamOrigin') then Exit;
(AWidget as TCarbonCustomControl).ScrollTo(HIPointToPoint(Origin)); (AWidget as TCarbonCustomControl).ScrollTo(Origin);
Result := noErr; Result := noErr;
end; end;
@ -455,7 +451,9 @@ begin
FScrollView := EmbedInScrollView(AParams); FScrollView := EmbedInScrollView(AParams);
FScrollSize := Classes.Point(0, 0); FScrollSize := Classes.Point(0, 0);
FScrollPageSize := Classes.Point(0, 0); FScrollPageSize := Classes.Point(0, 0);
FScrollOrigin := Classes.Point(0, 0); FScrollOrigin := GetHIPoint(0, 0);
FMulX := 1;
FMulY := 1;
inherited; inherited;
end; end;
@ -489,15 +487,27 @@ end;
ALineSize - Size of scrollable line ALineSize - Size of scrollable line
AOrigin - Scroll position AOrigin - Scroll position
Handles scrollableget info event Handles scrollable get info event
------------------------------------------------------------------------------} ------------------------------------------------------------------------------}
procedure TCarbonCustomControl.GetInfo(out AImageSize, AViewSize, procedure TCarbonCustomControl.GetInfo(out AImageSize, AViewSize, ALineSize: HISize;
ALineSize, AOrigin: TPoint); out AOrigin: HIPoint);
var
C: TRect;
begin begin
AOrigin := FScrollOrigin; // modify coordinates to fit real page size
AImageSize := FScrollSize; GetClientRect(C);
AViewSize := FScrollPageSize;
ALineSize := Classes.Point(10, 10); if FScrollPageSize.X = 0 then FMulX := 1
else
FMulX := (C.Right - C.Left) / FScrollPageSize.X;
if FScrollPageSize.Y = 0 then FMulY := 1
else
FMulY := (C.Bottom - C.Top) / FScrollPageSize.Y;
AOrigin := GetHIPoint(FScrollOrigin.X * FMulX, FScrollOrigin.Y * FMulY);
AImageSize := GetHISize(FScrollSize.X * FMulX, FScrollSize.Y * FMulY);
AViewSize := GetHISize(C.Right - C.Left, C.Bottom - C.Top);
ALineSize := GetHISize(FScrollPageSize.X * FMulX / 40, FScrollPageSize.Y * FMulY / 40);
{$IFDEF VerboseScroll} {$IFDEF VerboseScroll}
DebugLn('TCarbonCustomControl.GetInfo ' + LCLObject.Name + ' Origin: ' + DebugLn('TCarbonCustomControl.GetInfo ' + LCLObject.Name + ' Origin: ' +
@ -512,7 +522,7 @@ end;
Handles scrollable scroll to event Handles scrollable scroll to event
------------------------------------------------------------------------------} ------------------------------------------------------------------------------}
procedure TCarbonCustomControl.ScrollTo(const ANewOrigin: TPoint); procedure TCarbonCustomControl.ScrollTo(const ANewOrigin: HIPoint);
var var
ScrollMsg: TLMScroll; ScrollMsg: TLMScroll;
begin begin
@ -521,14 +531,19 @@ begin
DbgS(ANewOrigin)); DbgS(ANewOrigin));
{$ENDIF} {$ENDIF}
FScrollOrigin := ANewOrigin; if FMulX = 0 then FScrollOrigin.X := 0
else
FScrollOrigin.X := ANewOrigin.X / FMulX;
if FMulY = 0 then FScrollOrigin.Y := 0
else
FScrollOrigin.Y := ANewOrigin.Y / FMulY;
// send vertical scroll // send vertical scroll
FillChar(ScrollMsg, SizeOf(TLMScroll), 0); FillChar(ScrollMsg, SizeOf(TLMScroll), 0);
with ScrollMsg do with ScrollMsg do
begin begin
Msg := LM_VSCROLL; Msg := LM_VSCROLL;
Pos := ANewOrigin.Y; Pos := Round(FScrollOrigin.Y);
ScrollCode := SB_THUMBPOSITION; ScrollCode := SB_THUMBPOSITION;
end; end;
DeliverMessage(LCLObject, ScrollMsg); DeliverMessage(LCLObject, ScrollMsg);
@ -538,7 +553,7 @@ begin
with ScrollMsg do with ScrollMsg do
begin begin
Msg := LM_HSCROLL; Msg := LM_HSCROLL;
Pos := ANewOrigin.X; Pos := Round(FScrollOrigin.X);
ScrollCode := SB_THUMBPOSITION; ScrollCode := SB_THUMBPOSITION;
end; end;
DeliverMessage(LCLObject, ScrollMsg); DeliverMessage(LCLObject, ScrollMsg);
@ -590,9 +605,9 @@ begin
{$ENDIF} {$ENDIF}
if SBStyle = SB_HORZ then if SBStyle = SB_HORZ then
Result := FScrollOrigin.X; Result := Round(FScrollOrigin.X);
if SBStyle = SB_VERT then if SBStyle = SB_VERT then
Result := FScrollOrigin.Y; Result := Round(FScrollOrigin.Y);
if (SIF_RANGE and ScrollInfo.fMask) > 0 then if (SIF_RANGE and ScrollInfo.fMask) > 0 then
begin begin
@ -665,9 +680,9 @@ begin
if (SIF_POS and ScrollInfo.fMask) > 0 then if (SIF_POS and ScrollInfo.fMask) > 0 then
begin begin
if SBStyle = SB_HORZ then if SBStyle = SB_HORZ then
ScrollInfo.nPos := FScrollOrigin.X; ScrollInfo.nPos := Round(FScrollOrigin.X);
if SBStyle = SB_VERT then if SBStyle = SB_VERT then
ScrollInfo.nPos := FScrollOrigin.Y; ScrollInfo.nPos := Round(FScrollOrigin.Y);
end; end;
if (SIF_PAGE and ScrollInfo.fMask) > 0 then if (SIF_PAGE and ScrollInfo.fMask) > 0 then

View File

@ -350,9 +350,9 @@ begin
end; end;
if FocusPart <> kControlFocusNoPart then if FocusPart <> kControlFocusNoPart then
LCLSendSetFocusMsg(AWidget.LCLObject) AWidget.FocusSet
else else
LCLSendKillFocusMsg(AWidget.LCLObject); AWidget.FocusKilled;
end; end;
{------------------------------------------------------------------------------ {------------------------------------------------------------------------------

View File

@ -78,8 +78,10 @@ const
DEFAULT_CFSTRING_ENCODING = kCFStringEncodingUTF8; DEFAULT_CFSTRING_ENCODING = kCFStringEncodingUTF8;
procedure CreateCFString(const S: String; out AString: CFStringRef); procedure CreateCFString(const S: String; out AString: CFStringRef);
procedure CreateCFString(const Data: CFDataRef; Encoding: CFStringEncoding; out AString: CFStringRef);
procedure FreeCFString(var AString: CFStringRef); procedure FreeCFString(var AString: CFStringRef);
function CFStringToStr(AString: CFStringRef): String; function CFStringToStr(AString: CFStringRef; Encoding: CFStringEncoding = DEFAULT_CFSTRING_ENCODING): String;
function CFStringToData(AString: CFStringRef; Encoding: CFStringEncoding = DEFAULT_CFSTRING_ENCODING): CFDataRef;
function RoundFixed(const F: Fixed): Integer; function RoundFixed(const F: Fixed): Integer;
@ -104,6 +106,8 @@ function HIRectToCarbonRect(const ARect: HIRect): FPCMacOSAll.Rect;
function PointToHIPoint(const APoint: TPoint): HIPoint; function PointToHIPoint(const APoint: TPoint): HIPoint;
function PointToHISize(const APoint: TPoint): HISize; function PointToHISize(const APoint: TPoint): HISize;
function HIPointToPoint(const APoint: HIPoint): TPoint; function HIPointToPoint(const APoint: HIPoint): TPoint;
function GetHIPoint(X, Y: Single): HIPoint;
function GetHISize(X, Y: Single): HISize;
function ColorToRGBColor(const AColor: TColor): RGBColor; function ColorToRGBColor(const AColor: TColor): RGBColor;
function RGBColorToColor(const AColor: RGBColor): TColor; function RGBColorToColor(const AColor: RGBColor): TColor;
@ -111,6 +115,8 @@ function CreateCGColor(const AColor: TColor): CGColorRef;
function DbgS(const ARect: FPCMacOSAll.Rect): string; overload; function DbgS(const ARect: FPCMacOSAll.Rect): string; overload;
function DbgS(const AColor: FPCMacOSAll.RGBColor): string; overload; function DbgS(const AColor: FPCMacOSAll.RGBColor): string; overload;
function DbgS(const APoint: HIPoint): string; overload;
function DbgS(const ASize: HISize): string; overload;
implementation implementation
@ -493,13 +499,30 @@ end;
Params: S - UTF-8 string Params: S - UTF-8 string
AString - Core Foundation string ref AString - Core Foundation string ref
Creates new Core Foundation string form specified string Creates new Core Foundation string from the specified string
------------------------------------------------------------------------------} ------------------------------------------------------------------------------}
procedure CreateCFString(const S: String; out AString: CFStringRef); procedure CreateCFString(const S: String; out AString: CFStringRef);
begin begin
AString := CFStringCreateWithCString(nil, Pointer(PChar(S)), DEFAULT_CFSTRING_ENCODING); AString := CFStringCreateWithCString(nil, Pointer(PChar(S)), DEFAULT_CFSTRING_ENCODING);
end; end;
{------------------------------------------------------------------------------
Name: CreateCFString
Params: Data - CFDataRef
Encoding - Data encoding format
AString - Core Foundation string ref
Creates new Core Foundation string from the specified data and format
------------------------------------------------------------------------------}
procedure CreateCFString(const Data: CFDataRef; Encoding: CFStringEncoding; out
AString: CFStringRef);
begin
AString := nil;
if Data = nil then Exit;
AString := CFStringCreateWithBytes(nil, CFDataGetBytePtr(Data),
CFDataGetLength(Data), Encoding, False);
end;
{------------------------------------------------------------------------------ {------------------------------------------------------------------------------
Name: FreeCFString Name: FreeCFString
Params: AString - Core Foundation string ref to free Params: AString - Core Foundation string ref to free
@ -514,12 +537,13 @@ end;
{------------------------------------------------------------------------------ {------------------------------------------------------------------------------
Name: CFStringToStr Name: CFStringToStr
Params: AString - Core Foundation string ref Params: AString - Core Foundation string ref
Encoding - Result data encoding format
Returns: UTF-8 string Returns: UTF-8 string
Converts Core Foundation string to string Converts Core Foundation string to string
------------------------------------------------------------------------------} ------------------------------------------------------------------------------}
function CFStringToStr(AString: CFStringRef): String; function CFStringToStr(AString: CFStringRef; Encoding: CFStringEncoding): String;
var var
Str: Pointer; Str: Pointer;
StrSize: CFIndex; StrSize: CFIndex;
@ -532,7 +556,7 @@ begin
end; end;
// Try the quick way first // Try the quick way first
Str := CFStringGetCStringPtr(AString, DEFAULT_CFSTRING_ENCODING); Str := CFStringGetCStringPtr(AString, Encoding);
if Str <> nil then if Str <> nil then
Result := PChar(Str) Result := PChar(Str)
else else
@ -541,16 +565,35 @@ begin
StrRange.location := 0; StrRange.location := 0;
StrRange.length := CFStringGetLength(AString); StrRange.length := CFStringGetLength(AString);
CFStringGetBytes(AString, StrRange, DEFAULT_CFSTRING_ENCODING, CFStringGetBytes(AString, StrRange, Encoding,
0, False, nil, 0, StrSize); Ord('?'), False, nil, 0, StrSize);
SetLength(Result, StrSize); SetLength(Result, StrSize);
if StrSize > 0 then if StrSize > 0 then
CFStringGetBytes(AString, StrRange, DEFAULT_CFSTRING_ENCODING, CFStringGetBytes(AString, StrRange, Encoding,
0, False, @Result[1], StrSize, StrSize); Ord('?'), False, @Result[1], StrSize, StrSize);
end; end;
end; end;
{------------------------------------------------------------------------------
Name: CFStringToData
Params: AString - Core Foundation string ref
Encoding - Result data encoding format
Returns: CFDataRef
Converts Core Foundation string to data
------------------------------------------------------------------------------}
function CFStringToData(AString: CFStringRef; Encoding: CFStringEncoding): CFDataRef;
var
S: String;
begin
Result := nil;
if AString = nil then Exit;
S := CFStringToStr(AString, Encoding);
Result := CFDataCreate(nil, @S[1], Length(S));
end;
{------------------------------------------------------------------------------ {------------------------------------------------------------------------------
Name: RoundFixed Name: RoundFixed
Params: F - Fixed value Params: F - Fixed value
@ -810,6 +853,28 @@ begin
Result.Y := Trunc(APoint.Y); Result.Y := Trunc(APoint.Y);
end; end;
{------------------------------------------------------------------------------
Name: GetHIPoint
Params: X, Y
Returns: HIPoint
------------------------------------------------------------------------------}
function GetHIPoint(X, Y: Single): HIPoint;
begin
Result.X := X;
Result.Y := Y;
end;
{------------------------------------------------------------------------------
Name: GetHISize
Params: X, Y
Returns: HISize
------------------------------------------------------------------------------}
function GetHISize(X, Y: Single): HISize;
begin
Result.width := X;
Result.height := Y;
end;
{------------------------------------------------------------------------------ {------------------------------------------------------------------------------
Name: ColorToRGBColor Name: ColorToRGBColor
Params: AColor - Color Params: AColor - Color
@ -875,6 +940,16 @@ begin
' B: ' + IntToHex(AColor.Blue, 4); ' B: ' + IntToHex(AColor.Blue, 4);
end; end;
function DbgS(const APoint: HIPoint): string;
begin
Result := 'X: ' + DbgS(APoint.X) + ' Y: ' + DbgS(APoint.Y);
end;
function DbgS(const ASize: HISize): string;
begin
Result := 'W: ' + DbgS(ASize.width) + ' H: ' + DbgS(ASize.height);
end;
{------------------------------------------------------------------------------ {------------------------------------------------------------------------------
Name: CustomControlHandler Name: CustomControlHandler
Handles custom control class methods Handles custom control class methods