Cocoa: Scroller Style can be dynamically updated at runtime according to macOS settings

This commit is contained in:
rich2014 2024-06-29 14:28:52 +08:00
parent fc40f7730d
commit 50cdfdfaae

View File

@ -102,7 +102,7 @@ type
{ TCocoaScrollStyleManager } { TCocoaScrollStyleManager }
TCocoaScrollStyleManager = class(TCocoaScrollBarStyleManager) TCocoaScrollStyleManager = class(TCocoaScrollBarStyleManager)
protected private
_scrollView: TCocoaManualScrollView; _scrollView: TCocoaManualScrollView;
public public
procedure updateLayout; virtual; abstract; procedure updateLayout; virtual; abstract;
@ -115,9 +115,12 @@ type
TCocoaScrollBar = objcclass(NSScroller) TCocoaScrollBar = objcclass(NSScroller)
private private
manager: TCocoaScrollBarStyleManager; _scrollView: TCocoaManualScrollView;
effect: TCocoaScrollBarEffect; _manager: TCocoaScrollBarStyleManager;
trackingArea: NSTrackingArea; _effect: TCocoaScrollBarEffect;
_trackingArea: NSTrackingArea;
private
procedure releaseManager; message 'releaseManager';
public public
callback: ICommonCallback; callback: ICommonCallback;
preventBlock : Boolean; preventBlock : Boolean;
@ -131,6 +134,13 @@ type
procedure dealloc; override; procedure dealloc; override;
function manager: TCocoaScrollBarStyleManager;
message 'manager';
function effect: TCocoaScrollBarEffect;
message 'effect';
procedure setManager( newManager:TCocoaScrollBarStyleManager );
message 'setManager:';
procedure drawKnob; override; procedure drawKnob; override;
procedure drawKnobSlotInRect_highlight(slotRect: NSRect; flag: ObjCBOOL); override; procedure drawKnobSlotInRect_highlight(slotRect: NSRect; flag: ObjCBOOL); override;
procedure setDoubleValue(newValue: double); override; procedure setDoubleValue(newValue: double); override;
@ -165,7 +175,7 @@ type
TCocoaManualScrollView = objcclass(NSView) TCocoaManualScrollView = objcclass(NSView)
private private
manager: TCocoaScrollStyleManager; _manager: TCocoaScrollStyleManager;
fdocumentView: NSView; fdocumentView: NSView;
fhscroll : TCocoaScrollBar; fhscroll : TCocoaScrollBar;
fvscroll : TCocoaScrollBar; fvscroll : TCocoaScrollBar;
@ -175,6 +185,9 @@ type
procedure dealloc; override; procedure dealloc; override;
procedure setFrame(newValue: NSRect); override; procedure setFrame(newValue: NSRect); override;
procedure resetManager; message 'resetManager';
procedure onScrollerStyleUpdated; message 'onScrollerStyleUpdated';
function lclGetCallback: ICommonCallback; override; function lclGetCallback: ICommonCallback; override;
procedure lclClearCallback; override; procedure lclClearCallback; override;
function lclContentView: NSView; override; function lclContentView: NSView; override;
@ -208,6 +221,8 @@ type
function lclClientFrame: TRect; override; function lclClientFrame: TRect; override;
procedure scrollWheel(theEvent: NSEvent); override; procedure scrollWheel(theEvent: NSEvent); override;
procedure setFrame(newValue: NSRect); override; procedure setFrame(newValue: NSRect); override;
procedure setScrollerStyle(newValue: NSScrollerStyle); override;
end; end;
function createLegacyScroller: TCocoaScrollBar; function createLegacyScroller: TCocoaScrollBar;
@ -454,20 +469,22 @@ end;
// only the Legacy Style can be used for compatibility. // only the Legacy Style can be used for compatibility.
// it's the same logical relationship as NSScrollView and NSScroller. // it's the same logical relationship as NSScrollView and NSScroller.
function createLegacyScroller: TCocoaScrollBar; function createLegacyScroller: TCocoaScrollBar;
var
scrollBar: TCocoaScrollBar Absolute Result;
manager: TCocoaScrollStyleManager;
begin begin
Result:= TCocoaScrollBar(TCocoaScrollBar.alloc); scrollBar:= TCocoaScrollBar(TCocoaScrollBar.alloc);
Result.manager:= TCocoaScrollStyleManagerLegacy.createForScrollBar; manager:= TCocoaScrollStyleManagerLegacy.createForScrollBar;
Result.effect:= Result.manager.createScrollBarEffect(Result); scrollBar.setManager( manager );
end; end;
function allocScroller(parent: TCocoaManualScrollView; dst: NSRect; aVisible: Boolean) function allocScroller(parent: TCocoaManualScrollView; dst: NSRect; aVisible: Boolean)
:TCocoaScrollBar; :TCocoaScrollBar;
var var
scrollBar: TCocoaScrollBar; scrollBar: TCocoaScrollBar Absolute Result;
begin begin
scrollBar:= TCocoaScrollBar(TCocoaScrollBar.alloc).initWithFrame(dst); scrollBar:= TCocoaScrollBar(TCocoaScrollBar.alloc).initWithFrame(dst);
scrollBar.manager:= parent.manager; scrollBar.setManager( parent._manager );
scrollBar.effect:= parent.manager.createScrollBarEffect(scrollBar);
parent.addSubview(scrollBar); parent.addSubview(scrollBar);
{$ifdef BOOLFIX} {$ifdef BOOLFIX}
scrollBar.setEnabled_(Ord(true)); scrollBar.setEnabled_(Ord(true));
@ -482,7 +499,6 @@ begin
scrollBar.suppressLCLMouse := true; scrollBar.suppressLCLMouse := true;
scrollBar.setTarget(scrollBar); scrollBar.setTarget(scrollBar);
scrollBar.setAction(objcselector('actionScrolling:')); scrollBar.setAction(objcselector('actionScrolling:'));
Result:= scrollBar;
end; end;
{ TCocoaManualScrollHost } { TCocoaManualScrollHost }
@ -526,43 +542,94 @@ begin
sc.setFrame( scFrame ); sc.setFrame( scFrame );
end; end;
procedure TCocoaManualScrollHost.setScrollerStyle(newValue: NSScrollerStyle);
begin
inherited setScrollerStyle(newValue);
if Assigned(self.lclGetTarget) and Assigned(self.documentView) then
TCocoaManualScrollView(self.documentView).onScrollerStyleUpdated;
end;
{ TCocoaManualScrollView } { TCocoaManualScrollView }
function TCocoaManualScrollView.initWithFrame(frameRect: NSRect): id; function TCocoaManualScrollView.initWithFrame(frameRect: NSRect): id;
var
style: NSScrollerStyle;
begin begin
Result:= inherited; Result:= inherited;
resetManager;
style:= CocoaConfig.CocoaScrollerPreferredStyle;
if style < 0 then
style:= NSScroller.preferredScrollerStyle;
if style = NSScrollerStyleLegacy then
self.manager:= TCocoaScrollStyleManagerLegacy.createForScrollView(self)
else
self.manager:= TCocoaScrollStyleManagerOverlay.createForScrollView(self);
end; end;
procedure TCocoaManualScrollView.dealloc; procedure TCocoaManualScrollView.dealloc;
begin begin
if Assigned(fhscroll) then begin if Assigned(fhscroll) then begin
fhscroll.removeFromSuperview; fhscroll.removeFromSuperview;
fhscroll.manager:= nil; fhscroll.setManager( nil );
fhscroll.release; fhscroll.release;
end; end;
if Assigned(fvscroll) then begin if Assigned(fvscroll) then begin
fvscroll.removeFromSuperview; fvscroll.removeFromSuperview;
fvscroll.manager:= nil; fvscroll.setManager( nil );
fvscroll.release; fvscroll.release;
end; end;
FreeAndNil(manager); FreeAndNil( _manager );
end; end;
procedure TCocoaManualScrollView.setFrame(newValue: NSRect); procedure TCocoaManualScrollView.setFrame(newValue: NSRect);
begin begin
inherited setFrame(newValue); inherited setFrame(newValue);
manager.updateLayout; _manager.updateLayout;
end;
procedure TCocoaManualScrollView.resetManager;
var
oldManager: TCocoaScrollStyleManager;
style: NSScrollerStyle;
begin
oldManager:= _manager;
style:= CocoaConfig.CocoaScrollerPreferredStyle;
if style < 0 then
style:= NSScroller.preferredScrollerStyle;
if style = NSScrollerStyleLegacy then
_manager:= TCocoaScrollStyleManagerLegacy.createForScrollView(self)
else
_manager:= TCocoaScrollStyleManagerOverlay.createForScrollView(self);
if Assigned(self.fhscroll) then begin
self.fhscroll.setManager( _manager );
end;
if Assigned(self.fvscroll) then begin
self.fvscroll.setManager( _manager );
end;
oldManager.Free;
end;
procedure TCocoaManualScrollView.onScrollerStyleUpdated;
var
horzAvailable: Boolean;
vertAvailabl: Boolean;
begin
horzAvailable:= _manager.isAvailableScrollBar( self.fhscroll );
vertAvailabl:= _manager.isAvailableScrollBar( self.fvscroll );
self.resetManager;
_manager.availScrollBar( self.fhscroll, horzAvailable );
_manager.availScrollBar( self.fvscroll, vertAvailabl );
if self.lclGetTarget is TWinControl then begin
/// TWinControl(self.lclGetTarget).InvalidateClientRectCache(True);
/// TWinControl(self.lclGetTarget).InvalidatePreferredSize;
TWinControl(self.lclGetTarget).AdjustSize;
/// TWinControl(self.lclGetTarget).Invalidate;
end;
_manager.updateLayout;
if self.hasHorizontalScroller then
_manager.showScrollBar(self.fhscroll);
if self.hasVerticalScroller then
_manager.showScrollBar(self.fvscroll);
end; end;
function TCocoaManualScrollView.lclGetCallback: ICommonCallback; function TCocoaManualScrollView.lclGetCallback: ICommonCallback;
@ -638,26 +705,26 @@ procedure TCocoaManualScrollView.setHasVerticalScroller(doshow: Boolean);
begin begin
if NOT Assigned(fvscroll) and doshow then if NOT Assigned(fvscroll) and doshow then
fvscroll:= self.allocVerticalScroller( True ); fvscroll:= self.allocVerticalScroller( True );
self.manager.availScrollBar( fvscroll, doshow ); _manager.availScrollBar( fvscroll, doshow );
self.manager.updateLayout; _manager.updateLayout;
end; end;
procedure TCocoaManualScrollView.setHasHorizontalScroller(doshow: Boolean); procedure TCocoaManualScrollView.setHasHorizontalScroller(doshow: Boolean);
begin begin
if NOT Assigned(fhscroll) and doshow then if NOT Assigned(fhscroll) and doshow then
fhscroll:= self.allocHorizontalScroller( True ); fhscroll:= self.allocHorizontalScroller( True );
self.manager.availScrollBar( fhscroll, doshow ); _manager.availScrollBar( fhscroll, doshow );
self.manager.updateLayout; _manager.updateLayout;
end; end;
function TCocoaManualScrollView.hasVerticalScroller: Boolean; function TCocoaManualScrollView.hasVerticalScroller: Boolean;
begin begin
Result:= self.manager.isAvailableScrollBar(fvscroll); Result:= _manager.isAvailableScrollBar(fvscroll);
end; end;
function TCocoaManualScrollView.hasHorizontalScroller: Boolean; function TCocoaManualScrollView.hasHorizontalScroller: Boolean;
begin begin
Result:= self.manager.isAvailableScrollBar(fhscroll); Result:= _manager.isAvailableScrollBar(fhscroll);
end; end;
function TCocoaManualScrollView.horizontalScroller: NSScroller; function TCocoaManualScrollView.horizontalScroller: NSScroller;
@ -926,20 +993,52 @@ end;
{ TCocoaScrollBar } { TCocoaScrollBar }
procedure TCocoaScrollBar.releaseManager;
begin
if NOT Assigned(_manager) then
Exit;
if NOT Assigned(_scrollView) then
FreeAndNil(_manager);
if Assigned(_effect) then begin
_effect.onDestroy;
_effect.release;
_effect:= nil;
end;
end;
procedure TCocoaScrollBar.dealloc; procedure TCocoaScrollBar.dealloc;
begin begin
FreeAndNil(manager); releaseManager;
effect.onDestroy;
effect.release;
inherited dealloc; inherited dealloc;
end; end;
procedure TCocoaScrollBar.drawKnob; function TCocoaScrollBar.manager: TCocoaScrollBarStyleManager;
var
rect: NSRect;
path: NSBezierPath;
begin begin
self.manager.onDrawKnob(self); Result:= _manager;
end;
function TCocoaScrollBar.effect: TCocoaScrollBarEffect;
begin
Result:= _effect;
end;
procedure TCocoaScrollBar.setManager( newManager: TCocoaScrollBarStyleManager);
begin
releaseManager;
_scrollView:= nil;
_manager:= newManager;
if Assigned(_manager) then begin
if _manager is TCocoaScrollStyleManager then
_scrollView:= TCocoaScrollStyleManager(_manager)._scrollView;
_effect:= _manager.createScrollBarEffect(self);
end;
end;
procedure TCocoaScrollBar.drawKnob;
begin
_manager.onDrawKnob(self);
end; end;
procedure TCocoaScrollBar.drawKnobSlotInRect_highlight(slotRect: NSRect; procedure TCocoaScrollBar.drawKnobSlotInRect_highlight(slotRect: NSRect;
@ -947,7 +1046,7 @@ procedure TCocoaScrollBar.drawKnobSlotInRect_highlight(slotRect: NSRect;
var var
drawSlot: Boolean; drawSlot: Boolean;
begin begin
drawSlot:= self.manager.onDrawKnobSlot(self, slotRect); drawSlot:= _manager.onDrawKnobSlot(self, slotRect);
if drawSlot then if drawSlot then
Inherited; Inherited;
end; end;
@ -957,7 +1056,7 @@ var
proportion: CGFloat; proportion: CGFloat;
begin begin
proportion:= self.knobProportion; proportion:= self.knobProportion;
manager.onKnobValueUpdated( self, newValue, proportion ); _manager.onKnobValueUpdated( self, newValue, proportion );
inherited; inherited;
end; end;
@ -966,7 +1065,7 @@ var
position: CGFloat; position: CGFloat;
begin begin
position:= self.doubleValue; position:= self.doubleValue;
manager.onKnobValueUpdated( self, position, newValue ); _manager.onKnobValueUpdated( self, position, newValue );
inherited; inherited;
end; end;
@ -977,28 +1076,28 @@ const
options: NSTrackingAreaOptions = NSTrackingMouseEnteredAndExited options: NSTrackingAreaOptions = NSTrackingMouseEnteredAndExited
or NSTrackingActiveAlways; or NSTrackingActiveAlways;
begin begin
if Assigned(trackingArea) then begin if Assigned(_trackingArea) then begin
removeTrackingArea(trackingArea); removeTrackingArea(_trackingArea);
trackingArea:= nil; _trackingArea:= nil;
end; end;
trackingArea:= NSTrackingArea.alloc.initWithRect_options_owner_userInfo( _trackingArea:= NSTrackingArea.alloc.initWithRect_options_owner_userInfo(
self.bounds, self.bounds,
options, options,
self, self,
nil); nil);
self.addTrackingArea( trackingArea ); self.addTrackingArea( _trackingArea );
trackingArea.release; _trackingArea.release;
end; end;
procedure TCocoaScrollBar.mouseEntered(theEvent: NSEvent); procedure TCocoaScrollBar.mouseEntered(theEvent: NSEvent);
begin begin
manager.onMouseEntered(self); _manager.onMouseEntered(self);
end; end;
procedure TCocoaScrollBar.mouseExited(theEvent: NSEvent); procedure TCocoaScrollBar.mouseExited(theEvent: NSEvent);
begin begin
manager.onMouseExited( self ); _manager.onMouseExited( self );
end; end;
procedure TCocoaScrollBar.actionScrolling(sender: NSObject); procedure TCocoaScrollBar.actionScrolling(sender: NSObject);
@ -1571,6 +1670,9 @@ begin
knobProportion:= 25/slotSize; knobProportion:= 25/slotSize;
end; end;
effect.currentKnobPosition:= knobPosition;
effect.currentKnobProportion:= knobProportion;
self.showScrollBar( scroller ); self.showScrollBar( scroller );
end; end;
@ -1634,7 +1736,7 @@ var
begin begin
effect:= TCocoaScrollBarEffectOverlay(scrollBar.effect); effect:= TCocoaScrollBarEffectOverlay(scrollBar.effect);
if scroller.knobProportion=1 then begin if effect.currentKnobProportion=1 then begin
scroller.setAlphaValue(0); scroller.setAlphaValue(0);
scroller.setHidden(True); scroller.setHidden(True);
Exit; Exit;