Cocoa: FocusRing configurable infrastructure added

This commit is contained in:
rich2014 2024-08-16 11:38:53 +08:00
parent 20445109d5
commit e06ed5230f
2 changed files with 93 additions and 2 deletions

View File

@ -9,8 +9,31 @@ uses
CocoaAll, Cocoa_Extra, CocoaConst;
type
NSColorFunction = Function(): NSColor;
// on macOS, the FocusRing takes up extra space, which may cause strange
// display in some cases. it may block other controls, or be partially cut off.
// for example, in the Lazarus IDE - About dialog, the FocusRing of the
// Tab of TPageControl is partially cut off.
// by providing a configurable infrastructure, FocusRing can be controlled
// for different control types.
{$scopedEnums on}
TCocoaFocusRingStrategy = (
default, // by macOS Default
none, // no FoucsRing
required, // have FocusRing
border // by LCL Control Border
);
// set the FocusRing strategy of the control according to ClassName
// (eg. 'TCocoaTabControl')
// APP can change the default setting of Cocoa WidgetSet
// by calling setCocoaControlFocusRingStrategy() too.
procedure setCocoaControlFocusRingStrategry( frs: TCocoaFocusRingStrategy; AClassName: NSString );
// getCocoaControlFocusRingStrategy() is mainly used internally by Cocoa WidgetSet
function getCocoaControlFocusRingStrategry( AClassName: NSString ): TCocoaFocusRingStrategy;
type
NSColorFunction = Function(): NSColor;
function getCocoaScrollerDefaultKnobColor: NSColor;
var
@ -129,6 +152,46 @@ var
implementation
var
FocusRingStrategySetting: NSMutableDictionary;
procedure setCocoaControlFocusRingStrategry( frs: TCocoaFocusRingStrategy; AClassName: NSString );
var
valueObject: NSNumber;
begin
valueObject:= NSNumber.numberWithInt( Ord(frs) );
FocusRingStrategySetting.setValue_forKey( valueObject , AClassName );
end;
function getCocoaControlFocusRingStrategry( AClassName: NSString ): TCocoaFocusRingStrategy;
var
valueObject: NSNumber;
begin
Result:= TCocoaFocusRingStrategy.default;
valueObject:= NSNumber( FocusRingStrategySetting.valueForKey(AClassName) );
if Assigned(valueObject) then
Result:= TCocoaFocusRingStrategy(valueObject.intValue);
if Result = TCocoaFocusRingStrategy.required then
Writeln( 'required' );
end;
// no need to set TCocoaFocusRingStrategy.default control
// the controls not in FocusRingStrategySetting are TCocoaFocusRingStrategy.default
procedure initDefaultFoucsRingSetting;
begin
FocusRingStrategySetting:= NSMutableDictionary.alloc.initWithCapacity( 16 );
setCocoaControlFocusRingStrategry( TCocoaFocusRingStrategy.none, NSSTR('TCocoaTabControl') );
setCocoaControlFocusRingStrategry( TCocoaFocusRingStrategy.none, NSSTR('TCocoaButton') );
setCocoaControlFocusRingStrategry( TCocoaFocusRingStrategy.none, NSSTR('TCocoaTextField') );
setCocoaControlFocusRingStrategry( TCocoaFocusRingStrategy.none, NSSTR('TCocoaComboBox') );
setCocoaControlFocusRingStrategry( TCocoaFocusRingStrategy.none, NSSTR('TCocoaReadOnlyComboBox') );
setCocoaControlFocusRingStrategry( TCocoaFocusRingStrategy.none, NSSTR('TCocoaTableListView') );
setCocoaControlFocusRingStrategry( TCocoaFocusRingStrategy.none, NSSTR('TCocoaCollectionView') );
setCocoaControlFocusRingStrategry( TCocoaFocusRingStrategy.border, NSSTR('TCocoaTextView') );
end;
function getCocoaScrollerDefaultKnobColor: NSColor;
begin
Result:= NSColor.controlTextColor;
@ -137,6 +200,6 @@ end;
initialization
CocoaDefaultCheckMenuImageName:= NSSTR('NSMenuCheckmark');
CocoaDefaultRadioMenuImageName:= NSSTR('NSDatePickerCalendarHome');
initDefaultFoucsRingSetting;
end.

View File

@ -173,6 +173,7 @@ type
end;
procedure UpdateFocusRing(v: NSView; astyle: TBorderStyle);
procedure UpdateControlFocusRing( cocoaControl: NSView; lclControl: TWinControl );
procedure ScrollViewSetScrollStyles(AScroll: TCocoaScrollView; AStyles: TScrollStyle);
procedure ScrollViewSetBorderStyle(sv: NSScrollView; astyle: TBorderStyle);
@ -221,6 +222,9 @@ implementation
uses
Math;
type
TWinControlAccess = class(TWinControl);
var
LastMouse: TLastMouseInfo;
@ -264,6 +268,30 @@ begin
v.setFocusRingType( NSFocusRing[astyle] );
end;
procedure UpdateControlFocusRing(cocoaControl: NSView; lclControl: TWinControl);
const
NSFocusRing : array [TBorderStyle] of NSBorderType = (
NSFocusRingTypeNone, // bsNone
NSFocusRingTypeDefault // bsSingle
);
var
frs: CocoaConfig.TCocoaFocusRingStrategy;
borderStyle: TBorderStyle;
begin
frs:= CocoaConfig.getCocoaControlFocusRingStrategry( cocoaControl.className );
case frs of
TCocoaFocusRingStrategy.none:
cocoaControl.setFocusRingType( NSFocusRingTypeNone );
TCocoaFocusRingStrategy.required:
cocoaControl.setFocusRingType( NSFocusRingTypeExterior );
TCocoaFocusRingStrategy.border: begin
borderStyle:= TWinControlAccess(lclControl).BorderStyle;
cocoaControl.setFocusRingType( NSFocusRing[borderStyle] );
end;
// TCocoaFocusRingStrategy.default: no need to set FocusRing
end;
end;
procedure ScrollViewSetScrollStyles(AScroll: TCocoaScrollView; AStyles: TScrollStyle);
begin
AScroll.setHasVerticalScroller(VerticalScrollerVisible[AStyles]);