From 98712b414afa9a89cd6a0bde36932ab02eaba854 Mon Sep 17 00:00:00 2001 From: dmitry Date: Thu, 4 Jan 2018 02:54:59 +0000 Subject: [PATCH] cocoa: rework TCocoaScrollBar implementation - removed direct binding to LCL control. Initial implementation of ScrollWindowsEx. added scrolling messages for TCocoaManualScrollView git-svn-id: trunk@56944 - --- lcl/interfaces/cocoa/cocoaint.pas | 62 +++++++++++++++++++++++++ lcl/interfaces/cocoa/cocoaprivate.pp | 45 +++++++++++------- lcl/interfaces/cocoa/cocoawinapi.inc | 62 ++++++++++++++++++++++--- lcl/interfaces/cocoa/cocoawinapih.inc | 1 + lcl/interfaces/cocoa/cocoawscommon.pas | 22 ++++++++- lcl/interfaces/cocoa/cocoawsstdctrls.pp | 5 +- 6 files changed, 170 insertions(+), 27 deletions(-) diff --git a/lcl/interfaces/cocoa/cocoaint.pas b/lcl/interfaces/cocoa/cocoaint.pas index 2305ec53b5..346db194ce 100644 --- a/lcl/interfaces/cocoa/cocoaint.pas +++ b/lcl/interfaces/cocoa/cocoaint.pas @@ -188,6 +188,8 @@ type var CocoaWidgetSet: TCocoaWidgetSet; +function CocoaScrollBarSetScrollInfo(bar: TCocoaScrollBar; const ScrollInfo: TScrollInfo): Integer; +function CocoaScrollBarGetScrollInfo(bar: TCocoaScrollBar; var ScrollInfo: TScrollInfo): Boolean; procedure NSScrollerGetScrollInfo(docSz, pageSz: CGFloat; rl: NSSCroller; Var ScrollInfo: TScrollInfo); procedure NSScrollViewGetScrollInfo(sc: NSScrollView; BarFlag: Integer; Var ScrollInfo: TScrollInfo); procedure NSScrollerSetScrollInfo(docSz, pageSz: CGFloat; rl: NSSCroller; const ScrollInfo: TScrollInfo); @@ -204,6 +206,66 @@ uses CocoaCaret, CocoaThemes; +function CocoaScrollBarSetScrollInfo(bar: TCocoaScrollBar; const ScrollInfo: TScrollInfo): Integer; +var + pg : Integer; + mn : Integer; + mx : Integer; + dl : Integer; + pos : CGFloat; +begin + if not Assigned(bar) then + begin + Result := 0; + Exit; + end; + + if ScrollInfo.fMask and SIF_PAGE>0 then + begin + pg:=ScrollInfo.nPage; + if pg=0 then pg:=1; // zero page is not allowed? + end + else pg:=bar.pageInt; + + if ScrollInfo.fMask and SIF_RANGE>0 then + begin + mn:=ScrollInfo.nMin; + mx:=ScrollInfo.nMax; + end + else + begin + mn:=bar.minInt; + mx:=bar.maxInt; + end; + + dl:=mx-mn; + if ScrollInfo.fMask and SIF_POS > 0 then + begin + if dl<>0 then + bar.setDoubleValue( ScrollInfo.nPos / dl ) + else + bar.setDoubleValue( 0 ) + end; + + bar.setEnabled(dl<>0); + + // if changed page or range, the knob changes + if ScrollInfo.fMask and (SIF_RANGE or SIF_PAGE)>0 then + begin + if dl<>0 then + //bar.setKnobProportion(pg/dl) + bar.setKnobProportion(0.5) + else + bar.setKnobProportion(1); + bar.pageInt:=pg; + bar.minInt:=mn; + bar.maxInt:=mx; + end; +end; + +function CocoaScrollBarGetScrollInfo(bar: TCocoaScrollBar; var ScrollInfo: TScrollInfo): Boolean; +begin +end; procedure NSScrollerGetScrollInfo(docSz, pageSz: CGFloat; rl: NSSCroller; Var ScrollInfo: TScrollInfo); begin diff --git a/lcl/interfaces/cocoa/cocoaprivate.pp b/lcl/interfaces/cocoa/cocoaprivate.pp index 045731864a..6d9ea24379 100644 --- a/lcl/interfaces/cocoa/cocoaprivate.pp +++ b/lcl/interfaces/cocoa/cocoaprivate.pp @@ -65,6 +65,7 @@ type procedure DidResignKeyNotification; procedure SendOnChange; procedure SendOnTextChanged; + procedure scroll(isVert: Boolean; Pos: Integer); // non event methods function DeliverMessage(Msg: Cardinal; WParam: WParam; LParam: LParam): LResult; function GetPropStorage: TStringList; @@ -507,6 +508,10 @@ type procedure setHasHorizontalScroller(doshow: Boolean); message 'setHasHorizontalScroller:'; function hasVerticalScroller: Boolean; message 'hasVerticalScroller'; function hasHorizontalScroller: Boolean; message 'hasHorizontalScroller'; + + function horizontalScroller: NSScroller; message 'horizontalScroller'; + function verticalScroller: NSScroller; message 'verticalScroller'; + end; TStatusItemData = record @@ -605,7 +610,10 @@ type TCocoaScrollBar = objcclass(NSScroller) public callback: ICommonCallback; - LCLScrollBar: TCustomScrollBar; + // minInt,maxInt are used to calculate POS on callback event + minInt : Integer; + maxInt : Integer; + pageInt : Integer; procedure actionScrolling(sender: NSObject); message 'actionScrolling:'; function IsHorizontal: Boolean; message 'IsHorizontal'; function acceptsFirstResponder: Boolean; override; @@ -1040,11 +1048,15 @@ begin Result:=fdocumentView; end; -procedure allocScroller(parent: NSView; var sc: NSScroller; dst: NSRect); +procedure allocScroller(parent: TCocoaManualScrollView; var sc: NSScroller; dst: NSRect); begin if Assigned(sc) then Exit; - sc:=NSScroller(NSScroller.alloc).initWithFrame(dst); + sc:=TCocoaScrollBar(TCocoaScrollBar.alloc).initWithFrame(dst); parent.addSubview(sc); + TCocoaScrollBar(sc).callback:=parent.callback; + sc.setTarget(sc); + sc.setAction(objcselector('actionScrolling:')); + end; procedure updateDocSize(parent: NSView; doc: NSView; hrz, vrt: NSScroller); @@ -1145,6 +1157,16 @@ begin Result:=Assigned(fhscroll) and (not fhscroll.isHidden); end; +function TCocoaManualScrollView.horizontalScroller: NSScroller; +begin + Result:=fhscroll; +end; + +function TCocoaManualScrollView.verticalScroller: NSScroller; +begin + Result:=fvscroll; +end; + { TCocoaWindowContent } function TCocoaWindowContent.lclIsHandle: Boolean; @@ -1840,22 +1862,9 @@ end; { TCocoaScrollBar } procedure TCocoaScrollBar.actionScrolling(sender: NSObject); -var - LMScroll: TLMScroll; - b: Boolean; begin - FillChar(LMScroll{%H-}, SizeOf(LMScroll), #0); - LMScroll.ScrollBar := PtrUInt(Self); - - if IsHorizontal() then - LMScroll.Msg := LM_HSCROLL - else - LMScroll.Msg := LM_VSCROLL; - - LMScroll.Pos := Round(floatValue * LCLScrollBar.Max); - LMScroll.ScrollCode := SIF_POS; - - LCLMessageGlue.DeliverMessage(LCLScrollBar, LMScroll); + if Assigned(callback) then + callback.scroll( not IsHorizontal(), Round(floatValue * (maxInt-minInt))); end; function TCocoaScrollBar.IsHorizontal: Boolean; diff --git a/lcl/interfaces/cocoa/cocoawinapi.inc b/lcl/interfaces/cocoa/cocoawinapi.inc index 19a8f04206..0490f7194f 100644 --- a/lcl/interfaces/cocoa/cocoawinapi.inc +++ b/lcl/interfaces/cocoa/cocoawinapi.inc @@ -1752,19 +1752,47 @@ var si : TScrollInfo; obj : NSObject; sc : TCocoaScrollView; + bar : TCocoaScrollBar; begin obj := HandleToNSObject(Handle); Result := 0; if not Assigned(obj) then Exit; - if not obj.isKindOfClass(TCocoaScrollView) then Exit; + if obj.isKindOfClass(TCocoaScrollView) then + begin + sc:=TCocoaScrollView(obj); + NSScrollViewSetScrollInfo(NSScrollView(obj), SBStyle, ScrollInfo); + FillChar(si, sizeof(si), 0); + si.cbSize:=sizeof(si); + NSScrollViewGetScrollInfo(NSScrollView(obj), SBStyle, si); + Result:=si.nPos; + end else if obj.isKindOfClass(TCocoaManualScrollView) then + begin + bar:=nil; + if SBStyle=SB_Vert then + begin + // Win32 forced the scrollbar to show up on SetScrollInfo + // TCocoaManualScrollView - also allocates on setting visible + TCocoaManualScrollView(obj).setHasVerticalScroller(true); + bar:=TCocoaScrollBar(TCocoaManualScrollView(obj).verticalScroller); + end + else if SBStyle=SB_Horz then + begin + TCocoaManualScrollView(obj).setHasHorizontalScroller(true); + bar := TCocoaScrollBar(TCocoaManualScrollView(obj).horizontalScroller); + end; - sc:=TCocoaScrollView(obj); - NSScrollViewSetScrollInfo(NSScrollView(obj), SBStyle, ScrollInfo); - FillChar(si, sizeof(si), 0); - si.cbSize:=sizeof(si); - NSScrollViewGetScrollInfo(NSScrollView(obj), SBStyle, si); - Result:=si.nPos; + if Assigned(bar) then + Result := CocoaScrollBarSetScrollInfo(bar, ScrollInfo) + else + Result := 0; + + end else if obj.isKindOfClass(TCocoaScrollBar) then + begin + Result := CocoaScrollBarSetScrollInfo(TCocoaScrollBar(obj), ScrollInfo); + end + else + Result := 0; end; function TCocoaWidgetSet.ShowScrollBar(Handle: HWND; wBar: Integer; bShow: Boolean): Boolean; @@ -2583,6 +2611,26 @@ begin NSObject(Handle).lclScreenToLocal(P.X, P.Y); end; +function TCocoaWidgetSet.ScrollWindowEx(hWnd: HWND; dx, dy: Integer; prcScroll, prcClip: PRect; hrgnUpdate: HRGN; prcUpdate: PRect; flags: UINT): Boolean; +var + obj: NSOBject; + b: NSRect; + v : NSView; +begin + obj:=NSObject(HandleToNSObject(hWnd)); + Result:=Assigned(obj) and (obj.isKindOfClass(NSView)); + if not Result then Exit; + + v:=NSView(obj).lclContentView; + + b:=v.bounds; + b.origin.x:=b.origin.x-dx; + b.origin.y:=b.origin.y+dy; // reversed + v.setBounds(b); + // ignore all updates + v.setNeedsDisplay_(true); +end; + function TCocoaWidgetSet.SelectClipRGN(DC: hDC; RGN: HRGN): Longint; begin Result := ExtSelectClipRgn(DC, RGN, RGN_COPY); diff --git a/lcl/interfaces/cocoa/cocoawinapih.inc b/lcl/interfaces/cocoa/cocoawinapih.inc index 9614b13959..4204974216 100644 --- a/lcl/interfaces/cocoa/cocoawinapih.inc +++ b/lcl/interfaces/cocoa/cocoawinapih.inc @@ -155,6 +155,7 @@ function RoundRect(DC: HDC; X1, Y1, X2, Y2: Integer; RX, RY : Integer): Boolean; function SaveDC(DC: HDC): Integer; override; function ScreenToClient(Handle: HWND; var P: TPoint): Integer; override; +function ScrollWindowEx(hWnd: HWND; dx, dy: Integer; prcScroll, prcClip: PRect; hrgnUpdate: HRGN; prcUpdate: PRect; flags: UINT): Boolean; override; function SelectClipRGN(DC : hDC; RGN : HRGN) : Longint; override; function SelectObject(ADC: HDC; GDIObj: HGDIOBJ): HGDIOBJ; override; function SendMessage(Handle: HWND; Msg: Cardinal; WParam: WParam; LParam: LParam): LResult; override; diff --git a/lcl/interfaces/cocoa/cocoawscommon.pas b/lcl/interfaces/cocoa/cocoawscommon.pas index 4d8b18b060..41bebcb5e4 100644 --- a/lcl/interfaces/cocoa/cocoawscommon.pas +++ b/lcl/interfaces/cocoa/cocoawscommon.pas @@ -63,7 +63,7 @@ type procedure DidResignKeyNotification; virtual; procedure SendOnChange; virtual; procedure SendOnTextChanged; virtual; // text controls (like spin) respond to OnChange for this event, but not for SendOnChange - + procedure scroll(isVert: Boolean; Pos: Integer); virtual; function DeliverMessage(var Msg): LRESULT; virtual; overload; function DeliverMessage(Msg: Cardinal; WParam: WParam; LParam: LParam): LResult; virtual; overload; procedure Draw(ControlContext: NSGraphicsContext; const bounds, dirty: NSRect); virtual; @@ -1042,6 +1042,26 @@ begin SendSimpleMessage(Target, CM_TEXTCHANGED); end; +procedure TLCLCommonCallback.scroll(isVert: Boolean; Pos: Integer); +var + LMScroll: TLMScroll; + b: Boolean; +begin + FillChar(LMScroll{%H-}, SizeOf(LMScroll), #0); + //todo: this should be a part of a parameter + //LMScroll.ScrollBar := Target.Handle; + + if IsVert then + LMScroll.Msg := LM_VSCROLL + else + LMScroll.Msg := LM_HSCROLL; + + LMScroll.Pos := Pos; + LMScroll.ScrollCode := SB_THUMBPOSITION; //SIF_POS; + + LCLMessageGlue.DeliverMessage(Target, LMScroll); +end; + function TLCLCommonCallback.DeliverMessage(var Msg): LRESULT; begin Result := LCLMessageGlue.DeliverMessage(Target, Msg); diff --git a/lcl/interfaces/cocoa/cocoawsstdctrls.pp b/lcl/interfaces/cocoa/cocoawsstdctrls.pp index 03ca03f82d..f6ecc00829 100644 --- a/lcl/interfaces/cocoa/cocoawsstdctrls.pp +++ b/lcl/interfaces/cocoa/cocoawsstdctrls.pp @@ -1387,10 +1387,13 @@ begin scr.callback:=TLCLCommonCallback.Create(scr, AWinControl); // OnChange (scrolling) event handling - scr.LCLScrollBar := TCustomScrollBar(AWinControl); scr.setTarget(scr); scr.setAction(objcselector('actionScrolling:')); + scr.minInt:=TCustomScrollBar(AWinControl).Min; + scr.maxInt:=TCustomScrollBar(AWinControl).Max; + scr.pageInt:=TCustomScrollBar(AWinControl).PageSize; + Result:=TLCLIntfHandle(scr); end;