diff --git a/lcl/interfaces/cocoa/cocoaprivate.pp b/lcl/interfaces/cocoa/cocoaprivate.pp index 3add3142c8..d982f0b042 100644 --- a/lcl/interfaces/cocoa/cocoaprivate.pp +++ b/lcl/interfaces/cocoa/cocoaprivate.pp @@ -49,11 +49,9 @@ type function lclClientFrame: TRect; message 'lclClientFrame'; end; - { LCLControlExtension } + { LCLViewExtension } - LCLControlExtension = objccategory(NSControl) - function lclIsEnabled: Boolean; message 'lclIsEnabled'; - procedure lclSetEnabled(AEnabled: Boolean); message 'lclSetEnabled:'; + LCLViewExtension = objccategory(NSView) function lclIsVisible: Boolean; message 'lclIsVisible'; procedure lclInvalidateRect(const r: TRect); message 'lclInvalidateRect:'; procedure lclInvalidate; message 'lclInvalidate'; @@ -64,6 +62,13 @@ type function lclClientFrame: TRect; message 'lclClientFrame'; end; + { LCLControlExtension } + + LCLControlExtension = objccategory(NSControl) + function lclIsEnabled: Boolean; message 'lclIsEnabled'; + procedure lclSetEnabled(AEnabled: Boolean); message 'lclSetEnabled:'; + end; + { LCLWindowExtension } LCLWindowExtension = objccategory(NSWindow) @@ -102,12 +107,6 @@ type procedure Resize; virtual; abstract; end; - {todo: consider using common protocol for all TCocoa* derived objcclasses } - {TCocoaTopLeftRect = objcprotocol - procedure getTopLeftFrame(var r: TRect); message 'getTopLeftFrame:'; - procedure setTopLeftFrame(const r: TRect); message 'setTopLeftFrame:'; - end;} - { TCocoaButton } TCocoaButton = objcclass(NSButton) @@ -171,6 +170,10 @@ type procedure drawRect(dirtyRect: NSRect); override; end; + TCocoaScrollView = objcclass(NSScrollView) + callback : TCommonCallback; + end; + implementation { TCocoaButton } @@ -442,32 +445,32 @@ begin SetEnabled(AEnabled); end; -function LCLControlExtension.lclIsVisible:Boolean; +function LCLViewExtension.lclIsVisible:Boolean; begin Result:=not isHidden; end; -procedure LCLControlExtension.lclInvalidateRect(const r:TRect); +procedure LCLViewExtension.lclInvalidateRect(const r:TRect); begin setNeedsDisplayInRect(RectToViewCoord(Self, r)); end; -procedure LCLControlExtension.lclInvalidate; +procedure LCLViewExtension.lclInvalidate; begin - setNeedsDisplay; + setNeedsDisplay_(True); end; -procedure LCLControlExtension.lclLocalToScreen(var X,Y:Integer); +procedure LCLViewExtension.lclLocalToScreen(var X,Y:Integer); begin end; -function LCLControlExtension.lclParent:id; +function LCLViewExtension.lclParent:id; begin Result:=superView; end; -function LCLControlExtension.lclFrame: TRect; +function LCLViewExtension.lclFrame: TRect; var v : NSView; begin @@ -477,7 +480,7 @@ begin else NSToLCLRect(frame, Result); end; -procedure LCLControlExtension.lclSetFrame(const r:TRect); +procedure LCLViewExtension.lclSetFrame(const r:TRect); var ns : NSRect; begin @@ -487,7 +490,7 @@ begin setFrame(ns); end; -function LCLControlExtension.lclClientFrame:TRect; +function LCLViewExtension.lclClientFrame:TRect; var r: NSRect; begin diff --git a/lcl/interfaces/cocoa/cocoautils.pas b/lcl/interfaces/cocoa/cocoautils.pas index 186338e1f8..c603c2c072 100644 --- a/lcl/interfaces/cocoa/cocoautils.pas +++ b/lcl/interfaces/cocoa/cocoautils.pas @@ -9,6 +9,9 @@ uses MacOSAll, CocoaAll, Types, LCLType; +const + NSNullRect : NSRect = (origin:(x:0; y:0); size:(width:0; height:0)); + function GetNSPoint(x,y: single): NSPoint; inline; function GetCGRect(x1, y1, x2, y2: Integer): CGRect; diff --git a/lcl/interfaces/cocoa/cocoawscommon.pas b/lcl/interfaces/cocoa/cocoawscommon.pas index 77b36c8481..89d0084955 100644 --- a/lcl/interfaces/cocoa/cocoawscommon.pas +++ b/lcl/interfaces/cocoa/cocoawscommon.pas @@ -14,6 +14,12 @@ uses type + { LCLWSViewExtension } + + LCLWSViewExtension = objccategory(NSView) + function lclInitWithCreateParams(const AParams: TCreateParams): id; message 'lclInitWithCreateParams:'; + end; + { TLCLCommonCallback } TLCLCommonCallback = class(TCommonCallback) @@ -53,10 +59,12 @@ type const AParams: TCreateParams): TLCLIntfHandle; override; end; + // Utility WS functions function AllocCustomControl(const AWinControl: TWinControl): TCocoaCustomControl; -procedure SetCreateParamsToControl(AControl: NSControl; const AParams: TCreateParams); +function EmbedInScrollView(AView: NSView): TCocoaScrollView; +procedure SetViewDefaults(AView: NSView); implementation @@ -70,12 +78,32 @@ begin Result.callback:=TLCLCommonCallback.Create(Result, AWinControl); end; -procedure SetCreateParamsToControl(AControl: NSControl; const AParams: TCreateParams); +function EmbedInScrollView(AView:NSView):TCocoaScrollView; +var + r : TRect; + p : NSView; + f : NSRect; begin - if not Assigned(AControl) then Exit; - AddViewToNSObject(AControl, NSObject(AParams.WndParent), AParams.X, AParams.Y); + if not Assigned(AView) then begin + Result:=nil; + Exit; + end; + r:=AView.lclFrame; + p:=AView.superview; + Result:=TCocoaScrollView.alloc.initWithFrame(NSNullRect); + if Assigned(p) then p.addSubView(Result); + Result.lclSetFrame(r); + Result.setDocumentView(AView); + SetViewDefaults(Result); end; +procedure SetViewDefaults(AView:NSView); +begin + if not Assigned(AView) then Exit; + AView.setAutoresizingMask(NSViewMinYMargin or NSViewMaxXMargin); +end; + + { TLCLCommonCallback } constructor TLCLCommonCallback.Create(AOwner: NSObject; ATarget: TControl); @@ -204,10 +232,36 @@ class function TCocoaWSCustomControl.CreateHandle(const AWinControl: TWinControl var ctrl : TCocoaCustomControl; begin - ctrl:=AllocCustomControl(AWinControl); - SetCreateParamsToControl(ctrl, AParams); + ctrl:=TCocoaCustomControl( NSView(TCocoaCustomControl.alloc).lclInitWithCreateParams(AParams)); + ctrl.callback:=TLCLCommonCallback.Create(ctrl, AWinControl); Result:=TLCLIntfHandle(ctrl); end; +{ LCLWSViewExtension } + +function LCLWSViewExtension.lclInitWithCreateParams(const AParams:TCreateParams): id; +var + r: TRect; +begin + Result:=initWithFrame(NSNullRect); + if not Assigned(Result) then Exit; + + if (AParams.WndParent<>0) then begin + if (NSObject(AParams.WndParent).isKindOfClass_(NSView)) then + NSView(AParams.WndParent).addSubview(Self) + else if (NSObject(AParams.WndParent).isKindOfClass_(NSWindow)) then + NSWindow(AParams.WndParent).contentView.addSubview(Self) + end; + with AParams do begin + r.left:=X; + r.Top:=Y; + r.Right:=X+Width; + r.Bottom:=X+Height; + end; + Self.lclSetFrame(r); + + SetViewDefaults(Self); +end; + end. diff --git a/lcl/interfaces/cocoa/cocoawsfactory.pas b/lcl/interfaces/cocoa/cocoawsfactory.pas index 40d960c472..66625074ff 100644 --- a/lcl/interfaces/cocoa/cocoawsfactory.pas +++ b/lcl/interfaces/cocoa/cocoawsfactory.pas @@ -267,7 +267,8 @@ end; function RegisterCustomMemo: Boolean; alias : 'WSRegisterCustomMemo'; begin - Result := False; + RegisterWSComponent(TCustomMemo, TCocoaWSCustomMemo); + Result := True; end; function RegisterButtonControl: Boolean; alias : 'WSRegisterButtonControl'; diff --git a/lcl/interfaces/cocoa/cocoawsstdctrls.pp b/lcl/interfaces/cocoa/cocoawsstdctrls.pp index 47dc2f247b..f9b9022b73 100644 --- a/lcl/interfaces/cocoa/cocoawsstdctrls.pp +++ b/lcl/interfaces/cocoa/cocoawsstdctrls.pp @@ -151,14 +151,18 @@ type { TCocoaWSCustomMemo } TCocoaWSCustomMemo = class(TWSCustomMemo) - {published + published class function CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): TLCLIntfHandle; override; class function GetStrings(const ACustomMemo: TCustomMemo): TStrings; override; class procedure AppendText(const ACustomMemo: TCustomMemo; const AText: string); override; - class procedure SetAlignment(const ACustomMemo: TCustomMemo; const AAlignment: TAlignment); override; + {class procedure SetAlignment(const ACustomMemo: TCustomMemo; const AAlignment: TAlignment); override; class procedure SetScrollbars(const ACustomMemo: TCustomMemo; const NewScrollbars: TScrollStyle); override; class procedure SetWordWrap(const ACustomMemo: TCustomMemo; const NewWordWrap: boolean); override;} + class procedure SetReadOnly(const ACustomEdit: TCustomEdit; NewReadOnly: boolean); override; + + class procedure SetText(const AWinControl: TWinControl; const AText: String); override; + class function GetText(const AWinControl: TWinControl; var AText: String): Boolean; override; end; { TCocoaWSEdit } @@ -264,21 +268,15 @@ function AllocSecureTextField(ATarget: TWinControl; const AParams: TCreateParams implementation -procedure DefaultViewSettings(view: NSView); -begin - view.setAutoresizingMask(NSViewMinYMargin or NSViewMaxXMargin); -end; - function AllocButton(ATarget: TWinControl; const AParams: TCreateParams; btnBezel: NSBezelStyle; btnType: NSButtonType): NSButton; begin - Result:=TCocoaButton.alloc; + Result:=TCocoaButton.alloc.lclInitWithCreateParams(AParams); if Assigned(Result) then begin TCocoaButton(Result).callback:=TLCLCommonCallback.Create(Result, ATarget); Result.initWithFrame(CreateParamsToNSRect(AParams)); Result.setTitle(NSStringUTF8(AParams.Caption)); if btnBezel<>0 then Result.setBezelStyle(btnBezel); Result.setButtonType(btnType); - DefaultViewSettings(Result); end; end; @@ -288,19 +286,16 @@ begin if Assigned(Result) then begin TCocoaTextView(Result).callback:=TLCLCommonCallback.Create(Result, ATarget); Result.initWithFrame(CreateParamsToNSRect(AParams)); - DefaultViewSettings(Result); - Result.setFieldEditor(fieldEditor); end; end; function AllocTextField(ATarget: TWinControl; const AParams: TCreateParams): TCocoaTextField; begin - Result:=TCocoaTextField(TCocoaTextField.alloc); + Result:=TCocoaTextField(TCocoaTextField.alloc.lclInitWithCreateParams(AParams)); if Assigned(Result) then begin TCocoaTextField(Result).callback:=TLCLCommonCallback.Create(Result, ATarget); Result.initWithFrame(CreateParamsToNSRect(AParams)); SetNSControlValue(Result, AParams.Caption); - DefaultViewSettings(Result); end; end; @@ -311,7 +306,6 @@ begin TCocoaSecureTextField(Result).callback:=TLCLCommonCallback.Create(Result, ATarget); Result.initWithFrame(CreateParamsToNSRect(AParams)); SetNSText(Result.currentEditor, AParams.Caption); - DefaultViewSettings(Result); end; end; @@ -422,7 +416,6 @@ var btn : NSButton; begin btn:=AllocButton(AWinControl, AParams, 0, NSRadioButton); - SetCreateParamsToControl(btn, AParams); Result:=TLCLIntfHandle(btn); end; @@ -435,7 +428,6 @@ begin if TCustomEdit(AWinControl).PasswordChar=#0 then field:=NSTextField(AllocTextField(AWinControl, AParams)) else field:=NSTextField(AllocSecureTextField(AWinControl, AParams)); - SetCreateParamsToControl(field, AParams); Result:=TLCLIntfHandle(field); end; @@ -479,5 +471,196 @@ begin // NSTextField(ACustomEdit.Handle).setEditable(not NewReadOnly); end; + +type + + { TCocoaMemoStrings } + + TCocoaMemoStrings = class(TStrings) + private + fTextView : NSTextView; + protected + function GetTextStr: string; override; + procedure SetTextStr(const Value: string); override; + function GetCount: Integer; override; + function Get(Index: Integer): string; override; + public + constructor Create(AText: NSTextView); + procedure Clear; override; + procedure Delete(Index: Integer); override; + procedure Insert(Index: Integer; const S: string); override; + end; + +{ TCocoaMemoStrings } + +constructor TCocoaMemoStrings.Create(AText:NSTextView); +begin + fTextView:=AText; + inherited Create; +end; + +function TCocoaMemoStrings.GetTextStr:string; +begin + Result:=NSStringToString(fTextView.textStorage.string_); +end; + +procedure TCocoaMemoStrings.SetTextStr(const Value:string); +begin + fTextView.textStorage.mutableString.setString(NSStringUtf8(Value)); +end; + +procedure GetLineStart(const s: AnsiString; LineIndex: Integer; var Offset, LinesSkipped: Integer); +var + i : Integer; +begin + i:=1; + LinesSkipped:=0; + while (LinesSkipped<>LineIndex) and (i<=length(s)) do begin + if s[i] in [#10, #13] then begin + inc(i); + inc(LinesSkipped); + if (i<=length(s)) and (s[i] in [#10,#13]) and (s[i-1]<>s[i]) then + inc(i); + end else + inc(i); + end; + Offset:=i; +end; + +function GetLinesCount(const s: AnsiString): Integer; +var + ofs : Integer; +begin + GetLineStart(s, -1, ofs, Result); +end; + +function TCocoaMemoStrings.GetCount:Integer; +begin + Result:=GetLinesCount(GetTextStr); + inc(Result); +end; + +function TCocoaMemoStrings.Get(Index:Integer):string; +var + s : AnsiString; + ofs : Integer; + eofs : Integer; + t : Integer; +begin + s:=GetTextStr; + GetLineStart(s, Index, ofs, t); + eofs:=ofs; + while (eofs<=length(s)) and not (s[eofs] in [#10,#13]) do + inc(eofs); + Result:=Copy(s, ofs, eofs-ofs); +end; + +procedure TCocoaMemoStrings.Clear; +begin + SetTextStr(''); +end; + +procedure TCocoaMemoStrings.Delete(Index:Integer); +var + s : AnsiString; + ofs : Integer; + eofs : Integer; + t : Integer; +begin + s:=GetTextStr; + GetLineStart(s, Index, ofs, t); + eofs:=ofs; + while (eofs<=length(s)) and not (s[eofs] in [#10,#13]) do + inc(eofs); + if eofs<=length(s) then begin + inc(eofs); + if (eofs<=length(s)) and (s[eofs] in [#10,#13]) and (s[eofs-1]<>s[eofs]) then + inc(eofs); + end; + System.Delete(s, ofs, eofs-ofs); + SetTextStr(s); +end; + +procedure TCocoaMemoStrings.Insert(Index:Integer;const S:string); +var + txt : AnsiString; + ofs : Integer; + t : Integer; +begin + txt:=GetTextStr; + GetLineStart(txt, Index, ofs, t); + System.Insert(s+LineEnding, txt, ofs); + SetTextStr(txt) +end; + +{ TCocoaWSCustomMemo } + +function MemoTextView(AWinControl: TWinControl): TCocoaTextView; +begin + if not Assigned(AWinControl) or (AWinControl.Handle=0) then + Result:=nil + else + Result:=TCocoaTextView(NSScrollView(AWinControl.Handle).documentView); +end; + +class function TCocoaWSCustomMemo.CreateHandle(const AWinControl:TWinControl; + const AParams:TCreateParams):TLCLIntfHandle; +var + txt : TCocoaTextView; + scr : TCocoaScrollView; +begin + txt:=TCocoaTextView( NSView(TCocoaTextView.alloc).lclInitWithCreateParams(AParams)); + txt.textStorage.mutableString.setString(NSStringUtf8(AParams.Caption)); + scr:=EmbedInScrollView(txt); + scr.callback:=txt.callback; + Result:=TLCLIntfHandle(scr); +end; + +class function TCocoaWSCustomMemo.GetStrings(const ACustomMemo:TCustomMemo): TStrings; +var + txt : TCocoaTextView; +begin + txt:=MemoTextView(ACustomMemo); + if Assigned(txt) then + Result := TCocoaMemoStrings.Create(txt) + else + Result := nil +end; + +class procedure TCocoaWSCustomMemo.AppendText(const ACustomMemo:TCustomMemo; + const AText:string); +begin + //todo: +end; + +class procedure TCocoaWSCustomMemo.SetReadOnly(const ACustomEdit:TCustomEdit; + NewReadOnly:boolean); +var + txt : TCocoaTextView; +begin + txt:=MemoTextView(ACustomEdit); + if not Assigned(txt) then Exit; + txt.setEditable(not NewReadOnly); +end; + +class procedure TCocoaWSCustomMemo.SetText(const AWinControl:TWinControl;const AText:String); +var + txt : TCocoaTextView; +begin + txt:=MemoTextView(AWinControl); + if not Assigned(txt) then Exit; + txt.textStorage.mutableString.setString(NSStringUtf8(AText)); +end; + +class function TCocoaWSCustomMemo.GetText(const AWinControl:TWinControl;var AText:String):Boolean; +var + txt : TCocoaTextView; +begin + txt:=MemoTextView(AWinControl); + Result:=Assigned(txt); + if Result then + AText:=NSStringToString(txt.textStorage.string_); +end; + end.