diff --git a/lcl/interfaces/cocoa/cocoaconfig.pas b/lcl/interfaces/cocoa/cocoaconfig.pas index 9214a22403..b9e84e42dd 100644 --- a/lcl/interfaces/cocoa/cocoaconfig.pas +++ b/lcl/interfaces/cocoa/cocoaconfig.pas @@ -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. diff --git a/lcl/interfaces/cocoa/cocoawscommon.pas b/lcl/interfaces/cocoa/cocoawscommon.pas index 1de3de9dd2..f99935b202 100644 --- a/lcl/interfaces/cocoa/cocoawscommon.pas +++ b/lcl/interfaces/cocoa/cocoawscommon.pas @@ -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]);