File: cocoalistcontrol.pas

package info (click to toggle)
lazarus 4.0%2Bdfsg-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 275,760 kB
  • sloc: pascal: 2,341,904; xml: 509,420; makefile: 348,726; cpp: 93,608; sh: 3,387; java: 609; perl: 297; sql: 222; ansic: 137
file content (247 lines) | stat: -rw-r--r-- 8,211 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
unit CocoaListControl;

{$mode objfpc}{$H+}
{$modeswitch objectivec2}

interface

uses
  Classes, SysUtils,
  LCLType, Graphics, Controls, ComCtrls, StdCtrls,
  CocoaAll, CocoaPrivate, CocoaCallback, CocoaWSCommon, CocoaGDIObjects,
  CocoaUtils;

type
  {
    currently the following callbacks implement IListViewCallBack,
    need to be considered before modification:
    1. TLCLListViewCallback
    2. TLCLListBoxCallback
    3. TLCLCheckboxListCallback
  }

  { IListViewCallBack }

  IListViewCallBack = interface(ICommonCallback)
    function ItemsCount: Integer;
    procedure GetRowHeight(rowidx: Integer; var height: Integer);
    function GetBorderStyle: TBorderStyle;

    function GetImageListType( out lvil: TListViewImageList ): Boolean;
    function GetItemTextAt(ARow, ACol: Integer; var Text: String): Boolean;
    function GetItemCheckedAt( row: Integer; var CheckState: Integer): Boolean;
    function GetItemImageAt(ARow, ACol: Integer; var imgIdx: Integer): Boolean;
    function GetImageFromIndex(imgIdx: Integer): NSImage;

    procedure SetItemTextAt(ARow, ACol: Integer; const Text: String);
    procedure SetItemCheckedAt( row: Integer; CheckState: Integer);

    function selectionIndexSet: NSMutableIndexSet;
    function checkedIndexSet: NSMutableIndexSet;
    function shouldSelectionChange(NewSel: Integer): Boolean;
    function getItemStableSelection(ARow: Integer): Boolean;

    procedure ColumnClicked(ACol: Integer);

    function drawItem( row: Integer; ctx: TCocoaContext; const r: TRect; state: TOwnerDrawState ): Boolean;
    function customDraw( row: Integer; col: Integer; ctx: TCocoaContext; state: TCustomDrawState ): Boolean;
    function isCustomDrawSupported: Boolean;
  end;

  { TLCLListControlCallback }

  TLCLListControlCallback = class abstract(TLCLCommonCallback, IListViewCallback)
  private
    _selectionIndexSet: NSMutableIndexSet;
    _checkedIndexSet: NSMutableIndexSet;
    _mixedCheckedIndexSet: NSMutableIndexSet;
  public
    constructor Create(AOwner: NSObject; ATarget: TWinControl; AHandleFrame: NSView = nil); override;
    destructor Destroy; override;
    function selectionIndexSet: NSMutableIndexSet; virtual;
    function checkedIndexSet: NSMutableIndexSet; virtual;
    function mixedCheckedIndexSet: NSMutableIndexSet; virtual;
    function GetItemCheckedAt( row: Integer; var CheckState: Integer): Boolean; virtual;
    procedure SetItemCheckedAt( row: Integer; CheckState: Integer); virtual;
    function getItemStableSelection(ARow: Integer): Boolean; virtual;
  public
    function ItemsCount: Integer; virtual; abstract;
    procedure GetRowHeight(rowidx: Integer; var height: Integer); virtual; abstract;
    function GetBorderStyle: TBorderStyle; virtual; abstract;

    function GetImageListType( out lvil: TListViewImageList ): Boolean; virtual; abstract;
    function GetItemTextAt(ARow, ACol: Integer; var Text: String): Boolean; virtual; abstract;
    function GetItemImageAt(ARow, ACol: Integer; var imgIdx: Integer): Boolean; virtual; abstract;
    function GetImageFromIndex(imgIdx: Integer): NSImage; virtual; abstract;
    procedure SetItemTextAt(ARow, ACol: Integer; const Text: String); virtual; abstract;

    function shouldSelectionChange(NewSel: Integer): Boolean; virtual; abstract;
    procedure ColumnClicked(ACol: Integer); virtual; abstract;

    function drawItem( row: Integer; ctx: TCocoaContext; const r: TRect; state: TOwnerDrawState ): Boolean; virtual; abstract;
    function customDraw( row: Integer; col: Integer; ctx: TCocoaContext; state: TCustomDrawState ): Boolean; virtual; abstract;
    function isCustomDrawSupported: Boolean; virtual; abstract;
  end;

  {
    1. TCocoaTableListView related need to support
       TListView/TListBox/TCheckListBox, etc.
    2. the differences between these controls can be considered to be
       implemented in the callback.
    3. however, after careful consideration, we tried to keep the original
       intention of the callback, and added TCocoaTableViewProcessor to
       isolate these differences.
  }
  { TCocoaTableViewProcessor }

  TCocoaTableViewProcessor = class
    function isInitializing( tv: NSTableView ): Boolean; virtual; abstract;
    function getLCLControlCanvas( tv:NSTableView ): TCanvas; virtual; abstract;
    procedure onReloadData( tv: NSTableView ); virtual; abstract;
    procedure onSelectionChanged( tv: NSTableView ); virtual; abstract;
    procedure onOwnerDrawItem( rowView: NSView ); virtual abstract;
  end;

  { TCocoaTableListControlProcessor }

  TCocoaTableListControlProcessor = class( TCocoaTableViewProcessor )
  protected
    function getCallback( tv: NSTableView ): TLCLListControlCallback;
  public
    procedure onReloadData( tv: NSTableView ); override;
    procedure onOwnerDrawItem( rowView: NSView ); override;
  end;

  { TCocoaListControlStringList }

  TCocoaListControlStringList = class(TStringList)
  protected
    procedure Changed; override;
  public
    Owner: NSTableView;
    // some notificaitons (i.e. selection change)
    // should not be passed to LCL while clearing
    isClearing: Boolean;
    constructor Create(AOwner: NSTableView);
    procedure Clear; override;
  end;

implementation

{ TLCLListControlCallback }

constructor TLCLListControlCallback.Create(AOwner: NSObject;
  ATarget: TWinControl; AHandleFrame: NSView);
begin
  inherited;
  _selectionIndexSet:= NSMutableIndexSet.new;
  _checkedIndexSet:= NSMutableIndexSet.new;
  _mixedCheckedIndexSet:= NSMutableIndexSet.new;
end;

destructor TLCLListControlCallback.Destroy;
begin
  _selectionIndexSet.release;
  _checkedIndexSet.release;
  _mixedCheckedIndexSet.release;
  inherited Destroy;
end;

function TLCLListControlCallback.selectionIndexSet: NSMutableIndexSet;
begin
  Result:= _selectionIndexSet;
end;

function TLCLListControlCallback.checkedIndexSet: NSMutableIndexSet;
begin
  Result:= _checkedIndexSet;
end;

function TLCLListControlCallback.mixedCheckedIndexSet: NSMutableIndexSet;
begin
  Result:= _mixedCheckedIndexSet;
end;

function TLCLListControlCallback.GetItemCheckedAt(row: Integer;
  var CheckState: Integer): Boolean;
var
  checkStateArray : array [Boolean] of Integer = (NSOffState, NSOnState);
  mixStateArray : array [Boolean] of Integer = (NSOffState, NSMixedState);
begin
  CheckState := checkStateArray[self.checkedIndexSet.containsIndex(row)];
  if CheckState = NSOffState then
    CheckState := mixStateArray[self.mixedCheckedIndexSet.containsIndex(row)];
  Result := true;
end;

procedure TLCLListControlCallback.SetItemCheckedAt(row: Integer;
  CheckState: Integer);
begin
  case CheckState of
    NSOnState: begin
      self.checkedIndexSet.addIndex( row );
      self.mixedCheckedIndexSet.removeIndex( row );
    end;
    NSMixedState: begin
      self.checkedIndexSet.removeIndex( row );
      self.mixedCheckedIndexSet.addIndex( row );
    end;
    else begin
      self.checkedIndexSet.removeIndex( row );
      self.mixedCheckedIndexSet.removeIndex( row );
    end;
  end;
end;

function TLCLListControlCallback.getItemStableSelection(ARow: Integer): Boolean;
begin
  Result:= selectionIndexSet.containsIndex( ARow );
end;

{ TCocoaTableListControlProcessor }

function TCocoaTableListControlProcessor.getCallback(tv: NSTableView
  ): TLCLListControlCallback;
begin
  Result:= TLCLListControlCallback( tv.lclGetCallback.GetCallbackObject );
end;

procedure TCocoaTableListControlProcessor.onReloadData( tv: NSTableView );
begin
  tv.cancelPreviousPerformRequestsWithTarget_selector_object(
    tv, ObjcSelector('restoreFromStableSelection'), nil );
  tv.performSelector_withObject_afterDelay(
    ObjcSelector('restoreFromStableSelection'), nil, 0 );
end;

procedure TCocoaTableListControlProcessor.onOwnerDrawItem( rowView: NSView );
begin
  hideAllSubviews( rowView );
end;

{ TCocoaListControlStringList }

procedure TCocoaListControlStringList.Changed;
begin
  inherited Changed;
  Owner.reloadData;
end;

constructor TCocoaListControlStringList.Create(AOwner: NSTableView);
begin
  Owner:=AOwner;
  inherited Create;
end;

procedure TCocoaListControlStringList.Clear;
begin
  isClearing := true;
  try
    inherited Clear;
  finally
    isClearing := false;
  end;
end;

end.