mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-22 01:59:12 +02:00
Cocoa: add CocoaCollectionView unit
This commit is contained in:
parent
26fd4fe123
commit
18b030e5f9
388
lcl/interfaces/cocoa/cocoacollectionview.pas
Normal file
388
lcl/interfaces/cocoa/cocoacollectionview.pas
Normal file
@ -0,0 +1,388 @@
|
|||||||
|
unit CocoaCollectionView;
|
||||||
|
|
||||||
|
{$mode objfpc}{$H+}
|
||||||
|
{$modeswitch objectivec1}
|
||||||
|
{$modeswitch objectivec2}
|
||||||
|
{$interfaces corba}
|
||||||
|
{$include cocoadefines.inc}
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
Classes, SysUtils, Controls, ComCtrls,
|
||||||
|
MacOSAll, CocoaAll, CocoaPrivate, Cocoa_Extra, CocoaUtils,
|
||||||
|
CocoaWSComCtrls;
|
||||||
|
|
||||||
|
type
|
||||||
|
|
||||||
|
{ TCocoaCollectionItem }
|
||||||
|
TCocoaCollectionItem = objcclass(NSCollectionViewItem)
|
||||||
|
public
|
||||||
|
procedure loadView; override;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TCocoaCollectionItemView }
|
||||||
|
TCocoaCollectionItemView = objcclass(NSView)
|
||||||
|
private
|
||||||
|
item: TCocoaCollectionItem;
|
||||||
|
public
|
||||||
|
procedure drawRect(dirtyRect: NSRect); override;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TCocoaCollectionView }
|
||||||
|
TCocoaCollectionView = objcclass(
|
||||||
|
NSCollectionView,
|
||||||
|
NSCollectionViewDataSourceProtocol,
|
||||||
|
NSCollectionViewDelegateProtocol_1011 )
|
||||||
|
public
|
||||||
|
iconSize: NSSize;
|
||||||
|
itemSize: NSSize;
|
||||||
|
public
|
||||||
|
callback: TLCLListViewCallback;
|
||||||
|
function lclGetCallback: ICommonCallback; override;
|
||||||
|
procedure lclClearCallback; override;
|
||||||
|
procedure updateItemValue( indexPath:NSIndexPath; cocoaItem:TCocoaCollectionItem );
|
||||||
|
message 'updateItemValue:cocoaItem:';
|
||||||
|
procedure updateItemSize( baseSize: NSSize );
|
||||||
|
message 'updateItemSize:';
|
||||||
|
procedure updateItemLayout( item:TCocoaCollectionItem );
|
||||||
|
message 'updateItemLayout:';
|
||||||
|
|
||||||
|
procedure redrawVisibleItems; message 'redrawVisibleItems';
|
||||||
|
procedure restoreFromStableSelection; message 'restoreFromStableSelection';
|
||||||
|
procedure reloadData; override;
|
||||||
|
|
||||||
|
procedure selectOneItemByIndex( index: Integer; isSelected: Boolean );
|
||||||
|
message 'selectOneItemByIndex:isSelected:';
|
||||||
|
public
|
||||||
|
function collectionView_numberOfItemsInSection(
|
||||||
|
collectionView: NSCollectionView; section: NSInteger ): NSInteger;
|
||||||
|
function collectionView_itemForRepresentedObjectAtIndexPath(
|
||||||
|
collectionView: NSCollectionView; indexPath: NSIndexPath
|
||||||
|
): NSCollectionViewItem;
|
||||||
|
|
||||||
|
function collectionView_shouldChangeItemsAtIndexPaths_toHighlightState(
|
||||||
|
collectionView: NSCollectionView;
|
||||||
|
indexPaths: NSSet;
|
||||||
|
highlightState: NSCollectionViewItemHighlightState): NSSet;
|
||||||
|
procedure collectionView_didChangeItemsAtIndexPaths_toHighlightState(
|
||||||
|
collectionView: NSCollectionView;
|
||||||
|
indexPaths: NSSet;
|
||||||
|
highlightState: NSCollectionViewItemHighlightState );
|
||||||
|
|
||||||
|
procedure collectionView_willDisplayItem_forRepresentedObjectAtIndexPath(
|
||||||
|
collectionView: NSCollectionView;
|
||||||
|
item:NSCollectionViewItem;
|
||||||
|
indexPath:NSIndexPath );
|
||||||
|
procedure collectionView_didEndDisplayingItem_forRepresentedObjectAtIndexPath(
|
||||||
|
collectionView: NSCollectionView;
|
||||||
|
item:NSCollectionViewItem;
|
||||||
|
indexPath:NSIndexPath );
|
||||||
|
|
||||||
|
function collectionView_shouldSelectItemsAtIndexPaths(
|
||||||
|
collectionView: NSCollectionView; indexPaths:NSSet ): NSSet;
|
||||||
|
message 'collectionView:shouldSelectItemsAtIndexPaths:';
|
||||||
|
procedure collectionView_didSelectItemsAtIndexPaths(
|
||||||
|
collectionView: NSCollectionView; indexPaths:NSSet );
|
||||||
|
message 'collectionView:didSelectItemsAtIndexPaths:';
|
||||||
|
function collectionView_shouldDeselectItemsAtIndexPaths(
|
||||||
|
collectionView: NSCollectionView; indexPaths:NSSet ): NSSet;
|
||||||
|
message 'collectionView:shouldDeselectItemsAtIndexPaths:';
|
||||||
|
procedure collectionView_didDeselectItemsAtIndexPaths(
|
||||||
|
collectionView: NSCollectionView; indexPaths:NSSet );
|
||||||
|
message 'collectionView:didDeselectItemsAtIndexPaths:';
|
||||||
|
end;
|
||||||
|
|
||||||
|
function AllocCocoaCollectionView: TCocoaCollectionView;
|
||||||
|
function indexPathsWithOneIndex( cv: NSCollectionView; AIndex: Integer ): NSSet;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
function AllocCocoaCollectionView: TCocoaCollectionView;
|
||||||
|
var
|
||||||
|
layout: NSCollectionViewFlowLayout;
|
||||||
|
minSize: NSSize;
|
||||||
|
begin
|
||||||
|
layout:= NSCollectionViewFlowLayout.new;
|
||||||
|
|
||||||
|
minSize.width:= 64;
|
||||||
|
minSize.height:= 68;
|
||||||
|
layout.setItemSize( minSize );
|
||||||
|
|
||||||
|
layout.setMinimumInteritemSpacing( 4 );
|
||||||
|
layout.setMinimumLineSpacing( 4 );
|
||||||
|
|
||||||
|
Result:= TCocoaCollectionView.new;
|
||||||
|
Result.setDataSource( Result );
|
||||||
|
Result.setDelegate( NSCollectionViewDelegateProtocol_1011(Result) );
|
||||||
|
Result.setCollectionViewLayout( layout );
|
||||||
|
Result.registerClass_forItemWithIdentifier( TCocoaCollectionItem, NSSTR('Cell') );
|
||||||
|
Result.setSelectable( True );
|
||||||
|
layout.release;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function indexPathsWithOneIndex( cv: NSCollectionView; AIndex: Integer ): NSSet;
|
||||||
|
var
|
||||||
|
item: NSCollectionViewItem;
|
||||||
|
indexPath: NSIndexPath;
|
||||||
|
begin
|
||||||
|
item:= cv.itemAtIndex( AIndex );
|
||||||
|
indexPath:= cv.indexPathForItem( item );
|
||||||
|
Result:= NSSet.setWithObject( indexPath );
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TCocoaCollectionItem }
|
||||||
|
|
||||||
|
procedure TCocoaCollectionItem.loadView;
|
||||||
|
var
|
||||||
|
itemView: TCocoaCollectionItemView;
|
||||||
|
fieldControl: NSTextField;
|
||||||
|
imageControl: NSImageView;
|
||||||
|
begin
|
||||||
|
itemView:= TCocoaCollectionItemView.alloc.initWithFrame( NSZeroRect);
|
||||||
|
itemView.item:= self;
|
||||||
|
|
||||||
|
imageControl:= NSImageView.alloc.initWithFrame( NSZeroRect );
|
||||||
|
imageControl.cell.setImageScaling( NSImageScaleProportionallyUpOrDown );
|
||||||
|
self.setImageView( imageControl );
|
||||||
|
itemView.addSubview( imageControl );
|
||||||
|
|
||||||
|
fieldControl:= NSTextField.alloc.initWithFrame(NSZeroRect);
|
||||||
|
fieldControl.setAlignment( 1 ); // center
|
||||||
|
fieldControl.setBordered( False );
|
||||||
|
fieldControl.setDrawsBackground( False );
|
||||||
|
fieldControl.setEditable( False );
|
||||||
|
fieldControl.setLineBreakMode( NSLineBreakByTruncatingTail );
|
||||||
|
self.setTextField( fieldControl );
|
||||||
|
itemView.addSubview( fieldControl );
|
||||||
|
|
||||||
|
self.setView( itemView );
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TCocoaCollectionItemView }
|
||||||
|
|
||||||
|
procedure TCocoaCollectionItemView.drawRect(dirtyRect: NSRect);
|
||||||
|
begin
|
||||||
|
inherited;
|
||||||
|
if self.item.isSelected then begin
|
||||||
|
NSColor.selectedControlColor.set_;
|
||||||
|
NSRectFill( dirtyRect );
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TCocoaCollectionView }
|
||||||
|
|
||||||
|
function TCocoaCollectionView.lclGetCallback: ICommonCallback;
|
||||||
|
begin
|
||||||
|
Result:= callback;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TCocoaCollectionView.lclClearCallback;
|
||||||
|
begin
|
||||||
|
callback:= nil;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TCocoaCollectionView.updateItemValue(
|
||||||
|
indexPath:NSIndexPath; cocoaItem: TCocoaCollectionItem );
|
||||||
|
var
|
||||||
|
lclListView: TCustomListView;
|
||||||
|
lclItem: TListItem;
|
||||||
|
cocoaImage: NSImage;
|
||||||
|
lclText: String;
|
||||||
|
isSelected: Boolean;
|
||||||
|
begin
|
||||||
|
lclListView:= TCustomListView( self.lclGetTarget );
|
||||||
|
if NOT Assigned(lclListView) then
|
||||||
|
Exit;
|
||||||
|
|
||||||
|
lclItem:= lclListView.Items[indexPath.item];
|
||||||
|
cocoaImage:= callback.GetImageFromIndex( lclItem.ImageIndex );
|
||||||
|
cocoaItem.imageView.setImage( cocoaImage );
|
||||||
|
|
||||||
|
callback.GetItemTextAt( indexPath.item, 0, lclText );
|
||||||
|
cocoaItem.textField.setStringValue( StrToNSString(lclText) );
|
||||||
|
|
||||||
|
isSelected:= self.callback.getItemStableSelection(indexPath.item);
|
||||||
|
cocoaItem.setSelected( isSelected );
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TCocoaCollectionView.updateItemSize( baseSize: NSSize );
|
||||||
|
begin
|
||||||
|
self.iconSize:= baseSize;
|
||||||
|
if self.iconSize.Width < 32 then
|
||||||
|
self.iconSize.Width:= 32;
|
||||||
|
if self.iconSize.Height < 32 then
|
||||||
|
self.iconSize.Height:= 32;
|
||||||
|
|
||||||
|
self.itemSize.Width:= 10 + baseSize.Width + 10;
|
||||||
|
self.itemSize.Height:= 10 + baseSize.Height + 2 + 14 + 10;
|
||||||
|
if self.itemSize.Width < 64 then
|
||||||
|
self.itemSize.Width:= 64;
|
||||||
|
if self.itemSize.Height < 68 then
|
||||||
|
self.itemSize.Height:= 68;
|
||||||
|
|
||||||
|
NSCollectionViewFlowLayout(self.collectionViewLayout).setItemSize( self.itemSize );
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TCocoaCollectionView.updateItemLayout(item: TCocoaCollectionItem);
|
||||||
|
var
|
||||||
|
aFrame: NSRect;
|
||||||
|
newView: NSView;
|
||||||
|
fieldControl: NSTextField;
|
||||||
|
imageControl: NSImageView;
|
||||||
|
begin
|
||||||
|
aFrame.origin.x:= (self.itemSize.Width - self.iconSize.Width) / 2;
|
||||||
|
aFrame.origin.y:= self.itemSize.Height - self.iconSize.Height - 10;
|
||||||
|
aFrame.size:= self.iconSize;
|
||||||
|
item.imageView.setFrame( aFrame );
|
||||||
|
|
||||||
|
aFrame.origin.x:= 0;
|
||||||
|
aFrame.origin.y:= 10;
|
||||||
|
aFrame.size.width:= self.itemSize.Width;
|
||||||
|
aFrame.size.height:= 14;
|
||||||
|
item.textField.setFrame( aFrame );
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TCocoaCollectionView.redrawVisibleItems;
|
||||||
|
var
|
||||||
|
item: NSCollectionViewItem;
|
||||||
|
begin
|
||||||
|
for item in self.visibleItems do begin
|
||||||
|
item.view.setNeedsDisplay_( True );
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TCocoaCollectionView.restoreFromStableSelection;
|
||||||
|
begin
|
||||||
|
self.setSelectionIndexes( callback.selectionIndexSet );
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TCocoaCollectionView.reloadData;
|
||||||
|
begin
|
||||||
|
inherited reloadData;
|
||||||
|
restoreFromStableSelection;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TCocoaCollectionView.selectOneItemByIndex(
|
||||||
|
index: Integer; isSelected: Boolean );
|
||||||
|
var
|
||||||
|
item: NSCollectionViewItem;
|
||||||
|
indexPath: NSIndexPath;
|
||||||
|
indexPaths: NSSet;
|
||||||
|
begin
|
||||||
|
item:= self.itemAtIndex( index );
|
||||||
|
indexPath:= self.indexPathForItem( item );
|
||||||
|
indexPaths:= NSSet.setWithObject( indexPath );
|
||||||
|
|
||||||
|
if isSelected then begin
|
||||||
|
if NOT self.allowsMultipleSelection then begin
|
||||||
|
if NOT self.selectionIndexPaths.containsObject(indexPath) then begin
|
||||||
|
self.collectionView_didDeselectItemsAtIndexPaths( self, self.selectionIndexPaths );
|
||||||
|
self.deselectAll( self );
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
if NOT self.selectionIndexPaths.containsObject(indexPath) then begin
|
||||||
|
self.collectionView_didSelectItemsAtIndexPaths( self, indexPaths );
|
||||||
|
self.selectItemsAtIndexPaths_scrollPosition(
|
||||||
|
indexPaths, NSCollectionViewScrollPositionNone );
|
||||||
|
end;
|
||||||
|
end else begin
|
||||||
|
if self.selectionIndexPaths.containsObject(indexPath) then begin
|
||||||
|
self.collectionView_didDeselectItemsAtIndexPaths( self, indexPaths );
|
||||||
|
self.deselectItemsAtIndexPaths( indexPaths );
|
||||||
|
end;
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TCocoaCollectionView.collectionView_numberOfItemsInSection(
|
||||||
|
collectionView: NSCollectionView; section: NSInteger): NSInteger;
|
||||||
|
begin
|
||||||
|
Result:= 0;
|
||||||
|
if Assigned(self.callback) then
|
||||||
|
Result:= self.callback.ItemsCount;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TCocoaCollectionView.collectionView_itemForRepresentedObjectAtIndexPath
|
||||||
|
(collectionView: NSCollectionView; indexPath: NSIndexPath
|
||||||
|
): NSCollectionViewItem;
|
||||||
|
var
|
||||||
|
item: TCocoaCollectionItem Absolute Result;
|
||||||
|
begin
|
||||||
|
Result:= collectionView.makeItemWithIdentifier_forIndexPath(
|
||||||
|
NSSTR('Cell'), indexPath );
|
||||||
|
self.updateItemValue( indexPath, item );
|
||||||
|
self.updateItemLayout( item );
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TCocoaCollectionView.collectionView_shouldChangeItemsAtIndexPaths_toHighlightState
|
||||||
|
(collectionView: NSCollectionView; indexPaths: NSSet;
|
||||||
|
highlightState: NSCollectionViewItemHighlightState): NSSet;
|
||||||
|
begin
|
||||||
|
Result:= indexPaths;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// don't remove
|
||||||
|
procedure TCocoaCollectionView.collectionView_didChangeItemsAtIndexPaths_toHighlightState
|
||||||
|
(collectionView: NSCollectionView; indexPaths: NSSet;
|
||||||
|
highlightState: NSCollectionViewItemHighlightState);
|
||||||
|
begin
|
||||||
|
end;
|
||||||
|
|
||||||
|
// don't remove
|
||||||
|
procedure TCocoaCollectionView.collectionView_willDisplayItem_forRepresentedObjectAtIndexPath
|
||||||
|
(collectionView: NSCollectionView; item: NSCollectionViewItem;
|
||||||
|
indexPath: NSIndexPath);
|
||||||
|
begin
|
||||||
|
end;
|
||||||
|
|
||||||
|
// don't remove
|
||||||
|
procedure TCocoaCollectionView.collectionView_didEndDisplayingItem_forRepresentedObjectAtIndexPath
|
||||||
|
(collectionView: NSCollectionView; item: NSCollectionViewItem;
|
||||||
|
indexPath: NSIndexPath);
|
||||||
|
begin
|
||||||
|
end;
|
||||||
|
|
||||||
|
// don't remove
|
||||||
|
function TCocoaCollectionView.collectionView_shouldSelectItemsAtIndexPaths(
|
||||||
|
collectionView: NSCollectionView; indexPaths: NSSet): NSSet;
|
||||||
|
begin
|
||||||
|
Result:= indexPaths;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TCocoaCollectionView.collectionView_didSelectItemsAtIndexPaths(
|
||||||
|
collectionView: NSCollectionView; indexPaths: NSSet);
|
||||||
|
var
|
||||||
|
indexPath: NSIndexPath;
|
||||||
|
item: TCocoaCollectionItem;
|
||||||
|
begin
|
||||||
|
for indexPath in indexPaths do begin
|
||||||
|
item:= TCocoaCollectionItem( self.itemAtIndex(indexPath.item) );
|
||||||
|
item.setSelected( True );
|
||||||
|
item.textField.setToolTip( item.textField.stringValue );
|
||||||
|
item.view.setNeedsDisplay_(True);
|
||||||
|
callback.selectOne( indexPath.item, True );
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TCocoaCollectionView.collectionView_shouldDeselectItemsAtIndexPaths(
|
||||||
|
collectionView: NSCollectionView; indexPaths: NSSet): NSSet;
|
||||||
|
begin
|
||||||
|
Result:= indexPaths;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TCocoaCollectionView.collectionView_didDeselectItemsAtIndexPaths(
|
||||||
|
collectionView: NSCollectionView; indexPaths: NSSet);
|
||||||
|
var
|
||||||
|
indexPath: NSIndexPath;
|
||||||
|
item: TCocoaCollectionItem;
|
||||||
|
begin
|
||||||
|
for indexPath in indexPaths do begin
|
||||||
|
item:= TCocoaCollectionItem( self.itemAtIndex(indexPath.item) );
|
||||||
|
item.setSelected( False );
|
||||||
|
item.textField.setToolTip( nil );
|
||||||
|
item.view.setNeedsDisplay_(True);
|
||||||
|
callback.selectOne( indexPath.item, False );
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
@ -131,7 +131,7 @@ end;"/>
|
|||||||
<License Value="modified LGPL-2
|
<License Value="modified LGPL-2
|
||||||
"/>
|
"/>
|
||||||
<Version Major="3" Minor="99"/>
|
<Version Major="3" Minor="99"/>
|
||||||
<Files Count="536">
|
<Files Count="537">
|
||||||
<Item1>
|
<Item1>
|
||||||
<Filename Value="carbon/agl.pp"/>
|
<Filename Value="carbon/agl.pp"/>
|
||||||
<AddToUsesPkgSection Value="False"/>
|
<AddToUsesPkgSection Value="False"/>
|
||||||
@ -2648,6 +2648,11 @@ end;"/>
|
|||||||
<AddToUsesPkgSection Value="False"/>
|
<AddToUsesPkgSection Value="False"/>
|
||||||
<UnitName Value="CocoaWSScrollers"/>
|
<UnitName Value="CocoaWSScrollers"/>
|
||||||
</Item536>
|
</Item536>
|
||||||
|
<Item537>
|
||||||
|
<Filename Value="cocoa/cocoacollectionview.pas"/>
|
||||||
|
<AddToUsesPkgSection Value="False"/>
|
||||||
|
<UnitName Value="cocoacollectionview"/>
|
||||||
|
</Item537>
|
||||||
</Files>
|
</Files>
|
||||||
<CompatibilityMode Value="True"/>
|
<CompatibilityMode Value="True"/>
|
||||||
<LazDoc Paths="../../docs/xml/lcl"/>
|
<LazDoc Paths="../../docs/xml/lcl"/>
|
||||||
|
Loading…
Reference in New Issue
Block a user