mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-22 10:59:29 +02:00
Cocoa: split BaseInputClient responsibility from TCocoaCustomControl into TCocoaCustomControlWithBaseInputClient
This commit is contained in:
parent
a0aa06e92c
commit
224719b67b
@ -15,17 +15,12 @@ uses
|
||||
type
|
||||
{ TCocoaCustomControl }
|
||||
|
||||
TCocoaCustomControl = objcclass(NSControl, NSTextInputClientProtocol)
|
||||
TCocoaCustomControl = objcclass(NSControl)
|
||||
private
|
||||
fstr : NSString;
|
||||
|
||||
isdrawing : integer;
|
||||
faileddraw : Boolean;
|
||||
|
||||
_inIME: Boolean;
|
||||
private
|
||||
function getWindowEditor(): NSTextView; message 'getWindowEditor';
|
||||
procedure DoCallInputClientInsertText(nsText:NSString); message 'DoCallInputClientInsertText:';
|
||||
public
|
||||
callback: ICommonCallback;
|
||||
auxMouseByParent: Boolean;
|
||||
@ -56,7 +51,17 @@ type
|
||||
procedure setStringValue(avalue: NSString); override;
|
||||
function stringValue: NSString; override;
|
||||
procedure addSubView(aview: NSView); override;
|
||||
procedure doCommandBySelector (aSelector: SEL); override;
|
||||
end;
|
||||
|
||||
{ TCocoaCustomControlWithBaseInputClient }
|
||||
|
||||
TCocoaCustomControlWithBaseInputClient = objcclass(TCocoaCustomControl, NSTextInputClientProtocol)
|
||||
private
|
||||
_inIME: Boolean;
|
||||
private
|
||||
function getWindowEditor(): NSTextView; message 'getWindowEditor';
|
||||
procedure DoCallInputClientInsertText(nsText:NSString); message 'DoCallInputClientInsertText:';
|
||||
public
|
||||
// NSTextInputClientProtocol related.
|
||||
// implements a base NSTextInputClient for non-editable LCL CustomControl,
|
||||
@ -75,22 +80,17 @@ type
|
||||
function selectedRange: NSRange;
|
||||
function markedRange: NSRange;
|
||||
function hasMarkedText: LCLObjCBoolean;
|
||||
function firstRectForCharacterRange_actualRange (aRange: NSRange; actualRange: NSRangePointer): NSRect;
|
||||
|
||||
function attributedSubstringForProposedRange_actualRange (aRange: NSRange; actualRange: NSRangePointer): NSAttributedString;
|
||||
function validAttributesForMarkedText: NSArray;
|
||||
function firstRectForCharacterRange_actualRange (aRange: NSRange; actualRange: NSRangePointer): NSRect;
|
||||
function characterIndexForPoint (aPoint: NSPoint): NSUInteger;
|
||||
procedure doCommandBySelector (aSelector: SEL); override;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
{ TCocoaCustomControl }
|
||||
|
||||
function TCocoaCustomControl.getWindowEditor(): NSTextView;
|
||||
begin
|
||||
Result:= NSTextView( self.window.fieldEditor_forObject(true,nil) );
|
||||
end;
|
||||
|
||||
procedure TCocoaCustomControl.setStringValue(avalue: NSString);
|
||||
begin
|
||||
if Assigned(fstr) then fstr.release;
|
||||
@ -129,142 +129,6 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TCocoaCustomControl.keyDown(theEvent: NSEvent);
|
||||
var
|
||||
textView: NSView;
|
||||
isFirst: Boolean;
|
||||
begin
|
||||
if (not _inIME) and (theEvent.keyCode in
|
||||
[kVK_Return, kVK_ANSI_KeypadEnter, kVK_Escape, kVK_Space]) then
|
||||
begin
|
||||
inherited;
|
||||
exit;
|
||||
end;
|
||||
|
||||
isFirst:= not _inIME;
|
||||
inputContext.handleEvent(theEvent);
|
||||
if _inIME and isFirst then
|
||||
begin
|
||||
textView:= getWindowEditor();
|
||||
textView.setFrameSize( NSMakeSize(self.frame.size.width,16) );
|
||||
self.addSubView( textView );
|
||||
end
|
||||
else if not _inIME then
|
||||
inputContext.discardMarkedText;
|
||||
end;
|
||||
|
||||
procedure TCocoaCustomControl.DoCallInputClientInsertText(nsText:NSString);
|
||||
begin
|
||||
if Assigned(callback) then
|
||||
callback.InputClientInsertText(nsText.UTF8String);
|
||||
nsText.release;
|
||||
end;
|
||||
|
||||
// in TCocoaCustomControl, such as Form, Grid, ListView,
|
||||
// after inputting text, another control may be focused.
|
||||
// in insertText_replacementRange(), Cocoa/InputContext doesn't like it,
|
||||
// so calling InputClientInsertText() asynchronously.
|
||||
procedure TCocoaCustomControl.insertText_replacementRange(aString: id;
|
||||
replacementRange: NSRange);
|
||||
var
|
||||
nsText: NSString;
|
||||
begin
|
||||
if not _inIME then exit;
|
||||
|
||||
unmarkText;
|
||||
|
||||
nsText:= getNSStringObject(aString).copy;
|
||||
performSelector_withObject_afterDelay(ObjCSelector('DoCallInputClientInsertText:'), nsText, 0 );
|
||||
end;
|
||||
|
||||
procedure TCocoaCustomControl.setMarkedText_selectedRange_replacementRange(
|
||||
aString: id; selectedRange: NSRange; replacementRange: NSRange);
|
||||
var
|
||||
textView: NSTextView;
|
||||
nsText: NSString;
|
||||
begin
|
||||
nsText:= getNSStringObject(aString);
|
||||
if nsText.length > 0 then
|
||||
begin
|
||||
_inIME:= true;
|
||||
textView:= getWindowEditor();
|
||||
if Assigned(textView) then
|
||||
textView.setMarkedText_selectedRange_replacementRange(aString,selectedRange,replacementRange);
|
||||
end
|
||||
else
|
||||
unmarkText;
|
||||
end;
|
||||
|
||||
function TCocoaCustomControl.hasMarkedText: LCLObjCBoolean;
|
||||
begin
|
||||
Result := _inIME;
|
||||
end;
|
||||
|
||||
procedure TCocoaCustomControl.unmarkText;
|
||||
var
|
||||
textView: NSTextView;
|
||||
begin
|
||||
_inIME:= false;
|
||||
textView:= getWindowEditor();
|
||||
if Assigned(textView) then
|
||||
textView.removeFromSuperview;
|
||||
end;
|
||||
|
||||
function TCocoaCustomControl.firstRectForCharacterRange_actualRange(
|
||||
aRange: NSRange; actualRange: NSRangePointer): NSRect;
|
||||
var
|
||||
point: NSPoint;
|
||||
rect: NSRect;
|
||||
begin
|
||||
point:= self.convertPoint_toView(NSZeroPoint, nil);
|
||||
rect:= NSMakeRect(point.x, point.y, 0, 16);
|
||||
Result:= self.window.convertRectToScreen(rect);
|
||||
end;
|
||||
|
||||
function TCocoaCustomControl.selectedRange: NSRange;
|
||||
var
|
||||
textView: NSText;
|
||||
begin
|
||||
textView:= getWindowEditor();
|
||||
if not Assigned(textView) then
|
||||
Result:= NSMakeRange( NSNotFound, 0 )
|
||||
else
|
||||
Result:= textView.selectedRange;
|
||||
end;
|
||||
|
||||
function TCocoaCustomControl.markedRange: NSRange;
|
||||
var
|
||||
textView: NSTextView;
|
||||
begin
|
||||
textView:= getWindowEditor();
|
||||
if not Assigned(textView) then
|
||||
Result:= NSMakeRange( NSNotFound, 0 )
|
||||
else
|
||||
Result:= textView.markedRange;
|
||||
end;
|
||||
|
||||
function TCocoaCustomControl.attributedSubstringForProposedRange_actualRange(
|
||||
aRange: NSRange; actualRange: NSRangePointer): NSAttributedString;
|
||||
begin
|
||||
Result := nil;
|
||||
end;
|
||||
|
||||
function TCocoaCustomControl.validAttributesForMarkedText: NSArray;
|
||||
begin
|
||||
Result := nil;
|
||||
end;
|
||||
|
||||
function TCocoaCustomControl.characterIndexForPoint(aPoint: NSPoint
|
||||
): NSUInteger;
|
||||
begin
|
||||
Result := 0;
|
||||
end;
|
||||
|
||||
procedure TCocoaCustomControl.doCommandBySelector(aSelector: SEL);
|
||||
begin
|
||||
inherited doCommandBySelector(ASelector);
|
||||
end;
|
||||
|
||||
procedure TCocoaCustomControl.dealloc;
|
||||
begin
|
||||
if Assigned(fstr) then fstr.release;
|
||||
@ -439,5 +303,148 @@ begin
|
||||
inherited otherMouseDragged(event);
|
||||
end;
|
||||
|
||||
procedure TCocoaCustomControl.doCommandBySelector(aSelector: SEL);
|
||||
begin
|
||||
inherited doCommandBySelector(ASelector);
|
||||
end;
|
||||
|
||||
{ TCocoaCustomControlWithBaseInputClient }
|
||||
|
||||
function TCocoaCustomControlWithBaseInputClient.getWindowEditor(): NSTextView;
|
||||
begin
|
||||
Result:= NSTextView( self.window.fieldEditor_forObject(true,nil) );
|
||||
end;
|
||||
|
||||
procedure TCocoaCustomControlWithBaseInputClient.DoCallInputClientInsertText(nsText:NSString);
|
||||
begin
|
||||
if Assigned(callback) then
|
||||
callback.InputClientInsertText(nsText.UTF8String);
|
||||
nsText.release;
|
||||
end;
|
||||
|
||||
procedure TCocoaCustomControlWithBaseInputClient.keyDown(theEvent: NSEvent);
|
||||
var
|
||||
textView: NSView;
|
||||
isFirst: Boolean;
|
||||
begin
|
||||
if (not _inIME) and (theEvent.keyCode in
|
||||
[kVK_Return, kVK_ANSI_KeypadEnter, kVK_Escape, kVK_Space]) then
|
||||
begin
|
||||
inherited;
|
||||
exit;
|
||||
end;
|
||||
|
||||
isFirst:= not _inIME;
|
||||
inputContext.handleEvent(theEvent);
|
||||
if _inIME and isFirst then
|
||||
begin
|
||||
textView:= getWindowEditor();
|
||||
textView.setFrameSize( NSMakeSize(self.frame.size.width,16) );
|
||||
self.addSubView( textView );
|
||||
end
|
||||
else if not _inIME then
|
||||
inputContext.discardMarkedText;
|
||||
end;
|
||||
|
||||
// in TCocoaCustomControl, such as Form, Grid, ListView,
|
||||
// after inputting text, another control may be focused.
|
||||
// in insertText_replacementRange(), Cocoa/InputContext doesn't like it,
|
||||
// so calling InputClientInsertText() asynchronously.
|
||||
procedure TCocoaCustomControlWithBaseInputClient.insertText_replacementRange(aString: id;
|
||||
replacementRange: NSRange);
|
||||
var
|
||||
nsText: NSString;
|
||||
begin
|
||||
if not _inIME then exit;
|
||||
|
||||
unmarkText;
|
||||
|
||||
nsText:= getNSStringObject(aString).copy;
|
||||
performSelector_withObject_afterDelay(ObjCSelector('DoCallInputClientInsertText:'), nsText, 0 );
|
||||
end;
|
||||
|
||||
procedure TCocoaCustomControlWithBaseInputClient.setMarkedText_selectedRange_replacementRange(
|
||||
aString: id; selectedRange: NSRange; replacementRange: NSRange);
|
||||
var
|
||||
textView: NSTextView;
|
||||
nsText: NSString;
|
||||
begin
|
||||
nsText:= getNSStringObject(aString);
|
||||
if nsText.length > 0 then
|
||||
begin
|
||||
_inIME:= true;
|
||||
textView:= getWindowEditor();
|
||||
if Assigned(textView) then
|
||||
textView.setMarkedText_selectedRange_replacementRange(aString,selectedRange,replacementRange);
|
||||
end
|
||||
else
|
||||
unmarkText;
|
||||
end;
|
||||
|
||||
function TCocoaCustomControlWithBaseInputClient.hasMarkedText: LCLObjCBoolean;
|
||||
begin
|
||||
Result := _inIME;
|
||||
end;
|
||||
|
||||
procedure TCocoaCustomControlWithBaseInputClient.unmarkText;
|
||||
var
|
||||
textView: NSTextView;
|
||||
begin
|
||||
_inIME:= false;
|
||||
textView:= getWindowEditor();
|
||||
if Assigned(textView) then
|
||||
textView.removeFromSuperview;
|
||||
end;
|
||||
|
||||
function TCocoaCustomControlWithBaseInputClient.firstRectForCharacterRange_actualRange(
|
||||
aRange: NSRange; actualRange: NSRangePointer): NSRect;
|
||||
var
|
||||
point: NSPoint;
|
||||
rect: NSRect;
|
||||
begin
|
||||
point:= self.convertPoint_toView(NSZeroPoint, nil);
|
||||
rect:= NSMakeRect(point.x, point.y, 0, 16);
|
||||
Result:= self.window.convertRectToScreen(rect);
|
||||
end;
|
||||
|
||||
function TCocoaCustomControlWithBaseInputClient.selectedRange: NSRange;
|
||||
var
|
||||
textView: NSText;
|
||||
begin
|
||||
textView:= getWindowEditor();
|
||||
if not Assigned(textView) then
|
||||
Result:= NSMakeRange( NSNotFound, 0 )
|
||||
else
|
||||
Result:= textView.selectedRange;
|
||||
end;
|
||||
|
||||
function TCocoaCustomControlWithBaseInputClient.markedRange: NSRange;
|
||||
var
|
||||
textView: NSTextView;
|
||||
begin
|
||||
textView:= getWindowEditor();
|
||||
if not Assigned(textView) then
|
||||
Result:= NSMakeRange( NSNotFound, 0 )
|
||||
else
|
||||
Result:= textView.markedRange;
|
||||
end;
|
||||
|
||||
function TCocoaCustomControlWithBaseInputClient.attributedSubstringForProposedRange_actualRange(
|
||||
aRange: NSRange; actualRange: NSRangePointer): NSAttributedString;
|
||||
begin
|
||||
Result := nil;
|
||||
end;
|
||||
|
||||
function TCocoaCustomControlWithBaseInputClient.validAttributesForMarkedText: NSArray;
|
||||
begin
|
||||
Result := nil;
|
||||
end;
|
||||
|
||||
function TCocoaCustomControlWithBaseInputClient.characterIndexForPoint(aPoint: NSPoint
|
||||
): NSUInteger;
|
||||
begin
|
||||
Result := 0;
|
||||
end;
|
||||
|
||||
end.
|
||||
|
||||
|
@ -46,7 +46,7 @@ type
|
||||
// Key Class for Cocoa IME support
|
||||
// 1. obtain IME capability from Cocoa by implementing NSTextInputClientProtocol
|
||||
// 2. synchronize IME data with LCL via ICocoaIMEControl
|
||||
TCocoaFullControlEdit = objcclass(TCocoaCustomControl)
|
||||
TCocoaFullControlEdit = objcclass(TCocoaCustomControl, NSTextInputClientProtocol)
|
||||
private
|
||||
_currentParams: TCocoaIMEParameters;
|
||||
_currentMarkedText: NSString;
|
||||
@ -58,13 +58,17 @@ type
|
||||
procedure mouseUp(event: NSEvent); override;
|
||||
function resignFirstResponder: ObjCBOOL; override;
|
||||
|
||||
procedure setMarkedText_selectedRange_replacementRange (aString: id; newRange: NSRange; replacementRange: NSRange); override;
|
||||
procedure insertText_replacementRange (aString: id; replacementRange: NSRange); override;
|
||||
procedure unmarkText; override;
|
||||
function markedRange: NSRange; override;
|
||||
function selectedRange: NSRange; override;
|
||||
function hasMarkedText: LCLObjCBoolean; override;
|
||||
function firstRectForCharacterRange_actualRange ({%H-}aRange: NSRange; {%H-}actualRange: NSRangePointer): NSRect; override;
|
||||
procedure insertText_replacementRange (aString: id; replacementRange: NSRange);
|
||||
procedure setMarkedText_selectedRange_replacementRange (aString: id; newRange: NSRange; replacementRange: NSRange);
|
||||
procedure unmarkText;
|
||||
function selectedRange: NSRange;
|
||||
function markedRange: NSRange;
|
||||
function hasMarkedText: LCLObjCBoolean;
|
||||
function firstRectForCharacterRange_actualRange ({%H-}aRange: NSRange; {%H-}actualRange: NSRangePointer): NSRect;
|
||||
|
||||
function attributedSubstringForProposedRange_actualRange (aRange: NSRange; actualRange: NSRangePointer): NSAttributedString;
|
||||
function validAttributesForMarkedText: NSArray;
|
||||
function characterIndexForPoint (aPoint: NSPoint): NSUInteger;
|
||||
end;
|
||||
|
||||
implementation
|
||||
@ -291,5 +295,22 @@ begin
|
||||
Result:= ( _currentParams.textNSLength > 0 );
|
||||
end;
|
||||
|
||||
function TCocoaFullControlEdit.attributedSubstringForProposedRange_actualRange(
|
||||
aRange: NSRange; actualRange: NSRangePointer): NSAttributedString;
|
||||
begin
|
||||
Result := nil;
|
||||
end;
|
||||
|
||||
function TCocoaFullControlEdit.validAttributesForMarkedText: NSArray;
|
||||
begin
|
||||
Result := nil;
|
||||
end;
|
||||
|
||||
function TCocoaFullControlEdit.characterIndexForPoint(aPoint: NSPoint
|
||||
): NSUInteger;
|
||||
begin
|
||||
Result := 0;
|
||||
end;
|
||||
|
||||
end.
|
||||
|
||||
|
@ -184,7 +184,7 @@ type
|
||||
|
||||
{ TCocoaWindowContentDocument }
|
||||
|
||||
TCocoaWindowContentDocument = objcclass(TCocoaCustomControl)
|
||||
TCocoaWindowContentDocument = objcclass(TCocoaCustomControlWithBaseInputClient)
|
||||
protected
|
||||
procedure didBecomeKeyNotification(sender: NSNotification); message 'didBecomeKeyNotification:';
|
||||
procedure didResignKeyNotification(sender: NSNotification); message 'didResignKeyNotification:';
|
||||
|
@ -1978,13 +1978,13 @@ begin
|
||||
ctrl := TCocoaFullControlEdit.alloc.lclInitWithCreateParams(AParams);
|
||||
lcl := TLCLFullControlEditCallback.Create(ctrl, AWinControl);
|
||||
TCocoaFullControlEdit(ctrl).imeHandler := imeHandler;
|
||||
ctrl.unmarkText;
|
||||
TCocoaFullControlEdit(ctrl).unmarkText;
|
||||
end
|
||||
else
|
||||
begin
|
||||
// AWinControl not implements ICocoaIMEControl
|
||||
// AWinControl is a normal Custom Control
|
||||
ctrl := TCocoaCustomControl.alloc.lclInitWithCreateParams(AParams);
|
||||
ctrl := TCocoaCustomControlWithBaseInputClient.alloc.lclInitWithCreateParams(AParams);
|
||||
lcl := TLCLCommonCallback.Create(ctrl, AWinControl);
|
||||
end;
|
||||
lcl.BlockCocoaUpDown := true;
|
||||
|
@ -2375,7 +2375,7 @@ begin
|
||||
|
||||
// set a content view in order to be able to customize drawing for labels/color
|
||||
ns := GetNSRect(AParams.X, AParams.Y, AParams.Width, AParams.Height);
|
||||
lGroupBoxContents := TCocoaCustomControl(TCocoaCustomControl.alloc.initWithFrame(ns));
|
||||
lGroupBoxContents := TCocoaCustomControl.alloc.initWithFrame(ns);
|
||||
lGroupBoxContents.callback := box.callback; //TLCLCustomControlCallback.Create(lGroupBoxContents, AWinControl);
|
||||
//str := Format('%X=%X', [PtrUInt(box.callback), PtrUInt(lGroupBoxContents.callback)]);
|
||||
lGroupBoxContents.autorelease;
|
||||
|
Loading…
Reference in New Issue
Block a user