Cocoa: fix OwnerDraw in TCheckListBox #41100

This commit is contained in:
rich2014 2024-08-29 19:57:03 +08:00
parent ce91d6cb54
commit 17e6884e13
4 changed files with 78 additions and 15 deletions

View File

@ -8,7 +8,8 @@ interface
uses
Classes, SysUtils,
LCLType, Graphics, Controls, ComCtrls,
CocoaAll, CocoaPrivate, CocoaCallback, CocoaWSCommon, CocoaGDIObjects;
CocoaAll, CocoaPrivate, CocoaCallback, CocoaWSCommon, CocoaGDIObjects,
CocoaUtils;
type
{
@ -97,6 +98,7 @@ type
procedure onReloadData( tv: NSTableView ); virtual; abstract;
procedure onSelectOneItem( tv: NSTableView; selection: NSIndexSet ); virtual; abstract;
procedure onSelectionChanged( tv: NSTableView ); virtual; abstract;
procedure onOwnerDrawItem( rowView: NSView ); virtual abstract;
end;
{ TCocoaTableListControlProcessor }
@ -107,6 +109,7 @@ type
public
procedure onReloadData( tv: NSTableView ); override;
procedure onSelectOneItem( tv: NSTableView; selection: NSIndexSet ); override;
procedure onOwnerDrawItem( rowView: NSView ); override;
end;
{ TCocoaListControlStringList }
@ -204,6 +207,11 @@ begin
lclcb.selectionIndexSet.addIndexes( selection );
end;
procedure TCocoaTableListControlProcessor.onOwnerDrawItem( rowView: NSView );
begin
hideAllSubviews( rowView );
end;
{ TCocoaListControlStringList }
procedure TCocoaListControlStringList.Changed;

View File

@ -90,6 +90,7 @@ type
procedure addSubview(aView: NSView); override;
procedure dealloc; override;
function lclGetPorcessor: TCocoaTableViewProcessor; message 'lclGetPorcessor';
procedure lclSetProcessor( processor: TCocoaTableViewProcessor ); message 'lclSetProcessor:';
procedure lclSetCheckBoxes( checkBoxes: Boolean); message 'lclSetCheckBoxes:';
function lclHasCheckBoxes: Boolean; message 'lclHasCheckBoxes';
@ -320,15 +321,6 @@ begin
Result := TCocoaTableListView.alloc;
end;
procedure hideAllSubviews( parent: NSView );
var
view: NSView;
begin
for view in parent.subviews do
view.setHidden( True );
end;
function updateNSTextFieldWithTFont( cocoaField: NSTextField; lclFont: TFont ):
Boolean;
var
@ -385,14 +377,15 @@ begin
Exit;
end;
done:= self.tableView.lclCallDrawItem( row , self.bounds.size, dirtyRect );
done:= self.tableView.lclCallDrawItem( row, self.bounds.size, dirtyRect );
if done then begin
// the Cocoa default drawing cannot be skipped in NSTableView,
// we can only hide the CellViews to get the same effect.
// in the Lazarus IDE, there is a ListBox with OwnerDraw in Project-Forms,
// it's a case where the default drawing must be skipped.
hideAllSubviews( self );
if Assigned(self.tableView.lclGetPorcessor) then
self.tableView.lclGetPorcessor.onOwnerDrawItem( self );
end else begin
drawNSViewBackground( self, tableView.lclGetCanvas.Brush );
inherited drawRect( dirtyRect );
@ -477,6 +470,11 @@ begin
FreeAndNil( _processor );
end;
function TCocoaTableListView.lclGetPorcessor: TCocoaTableViewProcessor;
begin
Result:= _processor;
end;
procedure TCocoaTableListView.lclSetProcessor( processor: TCocoaTableViewProcessor);
begin
_processor:= processor;

View File

@ -25,6 +25,8 @@ type
const
NSNullRect : NSRect = (origin:(x:0; y:0); size:(width:0; height:0));
procedure hideAllSubviews( parent: NSView );
function GetNSSize(width, height: CGFloat): NSSize; inline;
function GetNSPoint(x,y: single): NSPoint; inline;
@ -161,6 +163,14 @@ function AllocCursorFromCursorByDegrees(src: NSCursor; degrees: double): NSCurso
implementation
procedure hideAllSubviews( parent: NSView );
var
view: NSView;
begin
for view in parent.subviews do
view.setHidden( True );
end;
procedure ApplicationWillShowModal;
begin
// Any place that would attempt to use Cocoa-native modality.

View File

@ -29,8 +29,8 @@ uses
// Widgetset
WSCheckLst, WSLCLClasses,
// LCL Cocoa
CocoaWSCommon, CocoaPrivate, CocoaCallback, CocoaWSStdCtrls,
CocoaListControl, CocoaTables, CocoaScrollers, CocoaWSScrollers;
CocoaWSCommon, CocoaPrivate, CocoaConfig, CocoaGDIObjects,
CocoaWSStdCtrls, CocoaListControl, CocoaTables, CocoaScrollers, CocoaWSScrollers;
type
@ -43,6 +43,14 @@ type
checklist: TCustomCheckListBox;
constructor Create(AOwner: NSObject; ATarget: TWinControl; AHandleView: NSView); override;
procedure SetItemCheckedAt( row: Integer; CheckState: Integer); override;
function drawItem(row: Integer; ctx: TCocoaContext; const r: TRect;
state: TOwnerDrawState): Boolean; override;
end;
{ TCocoaTableCheckListBoxProcessor }
TCocoaTableCheckListBoxProcessor = class( TCocoaTableListBoxProcessor )
procedure onOwnerDrawItem(rowView: NSView); override;
end;
{ TCocoaWSCustomCheckListBox }
@ -52,6 +60,7 @@ type
class function CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): TLCLHandle; override;
class function GetState(const ACheckListBox: TCustomCheckListBox; const AIndex: integer): TCheckBoxState; override;
class procedure SetState(const ACheckListBox: TCustomCheckListBox; const AIndex: integer; const AState: TCheckBoxState); override;
class function GetCheckWidth(const ACheckListBox: TCustomCheckListBox): integer; override;
end;
implementation
@ -77,6 +86,38 @@ begin
LCLSendChangedMsg( self.Target, row );
end;
function TLCLCheckboxListCallback.drawItem(row: Integer; ctx: TCocoaContext;
const r: TRect; state: TOwnerDrawState): Boolean;
var
rectReducedLeftSpacing: TRect;
lv: TCocoaTableListView;
itemView: NSView;
begin
rectReducedLeftSpacing:= r;
lv:= TCocoaTableListView( self.Owner );
if Assigned(lv) then begin
itemView:= lv.viewAtColumn_row_makeIfNecessary( 0, row, false );
if Assigned(itemView) then
rectReducedLeftSpacing.Left:= Round( itemView.frame.origin.x );
end;
Result:= inherited drawItem(row, ctx, rectReducedLeftSpacing, state);
end;
{ TCocoaTableCheckListBoxProcessor }
procedure TCocoaTableCheckListBoxProcessor.onOwnerDrawItem(rowView: NSView);
var
itemView: TCocoaTableListItem;
begin
itemView:= TCocoaTableListItem( rowView.subviews.objectAtIndex(0) );
if NOT Assigned(itemView) then
Exit;
if Assigned(itemView.imageView) then
itemView.imageView.setHidden( True );
if Assigned(itemView.textField) then
itemView.textField.setHidden( True );
end;
{ TCocoaWSCustomCheckListBox }
{------------------------------------------------------------------------------
@ -101,7 +142,7 @@ begin
Result := 0;
Exit;
end;
processor:= TCocoaTableListBoxProcessor.Create;
processor:= TCocoaTableCheckListBoxProcessor.Create;
list.lclSetProcessor( processor );
list.callback := TLCLCheckboxListCallback.CreateWithView(list, AWinControl);
list.lclSetCheckboxes(true);
@ -189,4 +230,10 @@ begin
cocoaTLV.reloadDataForRow_column( AIndex, 0 );
end;
class function TCocoaWSCustomCheckListBox.GetCheckWidth(
const ACheckListBox: TCustomCheckListBox): integer;
begin
Result:= Round( CocoaConfigListView.vsList.item.checkBoxOccupiedWidth );
end;
end.