ADD: FsExtractCustomIcon function support

This commit is contained in:
Alexander Koblov 2025-05-24 15:59:08 +03:00
commit a824defefe
14 changed files with 317 additions and 60 deletions

View file

@ -207,6 +207,20 @@ type
HICON = THandle;
HWND = THandle;
const
FS_ICON_FORMAT_HICON = 0; // Load icon from HICON (Windows only)
FS_ICON_FORMAT_FILE = 1; // Load icon from file name returned by plugin in the RemoteName
FS_ICON_FORMAT_BINARY = 2; // Load icon from Data byte array (PNG or ICO), destroy data using Free if FS_ICON_EXTRACTED_DESTROY returned
type
PWfxIcon = ^TWfxIcon;
TWfxIcon = packed record
Data: Pointer; // Icon data
Size: UIntPtr; // Input: suggested icon size (width/height), output: size of Data byte array
Format: UIntPtr; // See FS_ICON_FORMAT_*
Free: procedure(Data: Pointer); {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; // Procedure used to destroy Data byte array
end;
type
{$IFDEF MSWINDOWS}
FILETIME = Windows.FILETIME;
@ -407,21 +421,21 @@ procedure FsGetDefRootName(DefRootName:pchar;maxlen:integer); {$IFDEF MSWINDOWS}
function FsExtractCustomIcon(RemoteName:pchar;ExtractFlags:integer;
var TheIcon:hicon):integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF};
TheIcon: PWfxIcon):integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF};
function FsExtractCustomIconW(RemoteName:pwidechar;ExtractFlags:integer;
var TheIcon:hicon):integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF};
TheIcon: PWfxIcon):integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF};
procedure FsSetDefaultParams(dps:pFsDefaultParamStruct); {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF};
function FsGetPreviewBitmap(RemoteName:pchar;width,height:integer,
var ReturnedBitmap:hbitmap):integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF};
ReturnedBitmap: PWfxIcon):integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF};
function FsGetPreviewBitmapW(RemoteName:pwidechar;width,height:integer,
var ReturnedBitmap:hbitmap):integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF};
ReturnedBitmap: PWfxIcon):integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF};
function FsLinksToLocalFiles:bool; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF};

View file

@ -5,7 +5,7 @@ unit uFileSource;
interface
uses
Classes, SysUtils, DCStrUtils, syncobjs, LCLProc, URIParser, Menus,
Classes, SysUtils, DCStrUtils, syncobjs, LCLProc, URIParser, Menus, Graphics,
uFile, uDisplayFile, uFileProperty,
uFileSourceWatcher,
uFileSourceOperation, uFileSourceOperationTypes, uFileSourceProperty;
@ -180,6 +180,7 @@ type
function GetRootDir(sPath : String): String; overload;
function GetRootDir: String; overload;
function GetPathType(sPath : String): TPathType;
function GetCustomIcon(aFile: TFile; AIconSize: Integer; out AIcon: TBitmap): IntPtr;
function GetFreeSpace(Path: String; out FreeSize, TotalSize : Int64) : Boolean;
function GetRealPath(const path: String): String;
function GetLocalName(var aFile: TFile): Boolean;
@ -381,6 +382,7 @@ type
function CreateDirectory(const Path: String): Boolean; virtual;
function FileSystemEntryExists(const Path: String): Boolean; virtual;
function GetCustomIcon(aFile: TFile; AIconSize: Integer; out AIcon: TBitmap): PtrInt; virtual;
function GetFreeSpace(Path: String; out FreeSize, TotalSize : Int64) : Boolean; virtual;
function QueryContextMenu(AFiles: TFiles; var AMenu: TPopupMenu): Boolean; virtual;
function GetDefaultView(out DefaultView: TFileSourceFields): Boolean; virtual;
@ -702,6 +704,13 @@ begin
Result := True;
end;
function TFileSource.GetCustomIcon(aFile: TFile; AIconSize: Integer; out
AIcon: TBitmap): PtrInt;
begin
AIcon:= nil;
Result:= -1;
end;
function TFileSource.GetFreeSpace(Path: String; out FreeSize, TotalSize : Int64) : Boolean;
begin
Result := False; // not supported by default

View file

@ -73,7 +73,11 @@ type
{en
Set, if the file source supports custom context menu.
}
fspContextMenu
fspContextMenu,
{en
Set, if the file source supports custom file icons.
}
fspCustomIcon
);
TFileSourceProperties = set of TFileSourceProperty;

View file

@ -6,7 +6,7 @@ unit uWfxPluginFileSource;
interface
uses
Classes, SysUtils, URIParser, uWFXModule, WfxPlugin,
Classes, SysUtils, URIParser, Graphics, uWFXModule, WfxPlugin,
uFile, uFileSourceProperty, uFileSourceOperationTypes,
uFileProperty, uFileSource, uFileSourceOperation;
@ -129,6 +129,7 @@ type
function GetLocalName(var aFile: TFile): Boolean; override;
function CreateDirectory(const Path: String): Boolean; override;
function GetDefaultView(out DefaultView: TFileSourceFields): Boolean; override;
function GetCustomIcon(aFile: TFile; AIconSize: Integer; out AIcon: TBitmap): PtrInt; override;
class function IsSupportedPath(const Path: String): Boolean; override;
class function CreateByRootName(aRootName: String): IWfxPluginFileSource;
@ -170,7 +171,7 @@ uses
uWfxPluginCopyInOperation, uWfxPluginCopyOutOperation, uWfxPluginMoveOperation, uVfsModule,
uWfxPluginExecuteOperation, uWfxPluginListOperation, uWfxPluginCreateDirectoryOperation,
uWfxPluginDeleteOperation, uWfxPluginSetFilePropertyOperation, uWfxPluginCopyOperation,
DCConvertEncoding, uWfxPluginCalcStatisticsOperation, uFileFunctions;
DCConvertEncoding, uWfxPluginCalcStatisticsOperation, uFileFunctions, uPixMapManager;
const
connCopyIn = 0;
@ -642,6 +643,8 @@ begin
if (BackgroundFlags and BG_DOWNLOAD = 0) then
Result:= Result + [fspCopyOutOnMainThread];
end;
if Assigned(FsExtractCustomIcon) or Assigned(FsExtractCustomIconW) then
Result := Result + [fspCustomIcon];
if Assigned(FsContentGetDefaultView) or Assigned(FsContentGetDefaultViewW) then
Result := Result + [fspDefaultView];
end;
@ -949,6 +952,29 @@ begin
Result:= FWFXModule.WfxContentGetDefaultView(DefaultView);
end;
function TWfxPluginFileSource.GetCustomIcon(aFile: TFile; AIconSize: Integer;
out AIcon: TBitmap): PtrInt;
var
Status: Integer;
TheIcon: TWfxIcon;
AIconName: String;
UniqueName: String;
begin
AIconName:= aFile.FullPath;
Status:= FWfxModule.WfxExtractCustomIcon(AIconName, AIconSize, TheIcon);
if Status in [FS_ICON_EXTRACTED, FS_ICON_EXTRACTED_DESTROY] then
begin
if AIconName <> aFile.FullPath then
UniqueName:= AIconName
else begin
UniqueName:= EmptyStr;
end;
Result:= PixmapManager.CheckAddPixmap(UniqueName, AIconSize, (Status = FS_ICON_EXTRACTED_DESTROY), @TheIcon, AIcon);
end;
end;
class function TWfxPluginFileSource.IsSupportedPath(const Path: String): Boolean;
begin
Result:= Pos('wfx://', Path) = 1;

View file

@ -485,16 +485,10 @@ var
procedure DrawIconCell;
//------------------------------------------------------
var
IconID: PtrInt;
targetWidth: Integer;
begin
if (gShowIcons <> sim_none) then
begin
IconID := AFile.IconID;
// Draw default icon if there is no icon for the file.
if IconID = -1 then
IconID := PixMapManager.GetDefaultIcon(AFile.FSFile);
// center icon vertically
params.iconRect.Left:= aRect.Left + CELL_PADDING;
params.iconRect.Top:= aRect.Top + (aRect.Height - gIconsSize) div 2;
@ -502,14 +496,14 @@ var
params.iconRect.Height:= gIconsSize;
if gShowHiddenDimmed and FBriefView.FileSource.IsHiddenFile(AFile.FSFile) then
PixMapManager.DrawBitmapAlpha(IconID,
PixMapManager.DrawBitmapAlpha(AFile,
Canvas,
params.iconRect.Left,
params.iconRect.Top
)
else
// Draw icon for a file
PixMapManager.DrawBitmap(IconID,
PixMapManager.DrawBitmap(AFile,
Canvas,
params.iconRect.Left,
params.iconRect.Top

View file

@ -1567,16 +1567,10 @@ var
procedure DrawIconCell;
//------------------------------------------------------
var
IconID: PtrInt;
targetWidth: Integer;
begin
if (gShowIcons <> sim_none) then
begin
IconID := AFile.IconID;
// Draw default icon if there is no icon for the file.
if IconID = -1 then
IconID := PixMapManager.GetDefaultIcon(AFile.FSFile);
// center icon vertically
params.iconRect.Left:= aRect.Left + CELL_PADDING;
params.iconRect.Top:= aRect.Top + (aRect.Height - gIconsSize) div 2;
@ -1584,14 +1578,14 @@ var
params.iconRect.Height:= gIconsSize;
if gShowHiddenDimmed and ColumnsView.FileSource.isHiddenFile(AFile.FSFile) then
PixMapManager.DrawBitmapAlpha(IconID,
PixMapManager.DrawBitmapAlpha(AFile,
Canvas,
params.iconRect.Left,
params.iconRect.Top
)
else
// Draw icon for a file
PixMapManager.DrawBitmap(IconID,
PixMapManager.DrawBitmap(AFile,
Canvas,
params.iconRect.Left,
params.iconRect.Top

View file

@ -1156,6 +1156,7 @@ begin
FHashedNames.Remove(OldFileKey);
FHashedNames.Add(NewFileKey, ADisplayFile);
ADisplayFile.Busy:= [];
ADisplayFile.Icon:= nil;
ADisplayFile.IconID := -1;
ADisplayFile.Selected := False;
ADisplayFile.IconOverlayID := -1;
@ -2032,6 +2033,12 @@ begin
aFile.Properties[propType] := UpdatedFile.FSFile.ReleaseProperty(propType);
end;
if UpdatedFile.Icon <> nil then
begin
OrigDisplayFile.Icon := TBitmap.Create;
OrigDisplayFile.Icon.Assign(UpdatedFile.Icon);
end;
if UpdatedFile.IconID <> -1 then
OrigDisplayFile.IconID := UpdatedFile.IconID;

View file

@ -777,7 +777,8 @@ begin
if HaveIcons then
begin
AFile.IconID := PixMapManager.GetIconByFile(AFile.FSFile,
AFile.IconID := PixMapManager.GetIconByFile(fs,
AFile,
DirectAccess,
not gLoadIconsSeparately,
gShowIcons,
@ -831,7 +832,8 @@ begin
if HaveIcons then
begin
AFile.IconID := PixMapManager.GetIconByFile(AFile.FSFile,
AFile.IconID := PixMapManager.GetIconByFile(fs,
AFile,
DirectAccess,
not gLoadIconsSeparately,
gShowIcons,
@ -947,9 +949,10 @@ begin
if HaveIcons then
begin
if FWorkingFile.IconID < 0 then
if (FWorkingFile.IconID < 0) and (FWorkingFile.Icon = nil) then
FWorkingFile.IconID := PixMapManager.GetIconByFile(
FWorkingFile.FSFile,
FFileSource,
FWorkingFile,
DirectAccess,
True,
gShowIcons,

View file

@ -399,6 +399,7 @@ var
AFile: TDisplayFile;
HaveIcons: Boolean;
DirectAccess: Boolean;
AFileSource: IFileSource;
AFilePropertiesNeeded: TFilePropertiesTypes;
begin
if (csDestroying in ComponentState) or
@ -406,10 +407,11 @@ begin
IsEmpty then
Exit;
AFileSource := FileSource;
HaveIcons := gShowIcons <> sim_none;
VisibleFiles := GetVisibleFilesIndexes;
AFilePropertiesNeeded := FilePropertiesNeeded;
DirectAccess := fspDirectAccess in FileSource.Properties;
DirectAccess := fspDirectAccess in AFileSource.Properties;
// Property fpComment should be retrieved in main thread
if gListFilesInThread and (fpComment in AFilePropertiesNeeded) then
@ -417,9 +419,9 @@ begin
for i := VisibleFiles.First to VisibleFiles.Last do
begin
AFile := FFiles[i];
if FileSource.CanRetrieveProperties(AFile.FSFile, [fpComment]) then
if AFileSource.CanRetrieveProperties(AFile.FSFile, [fpComment]) then
try
FileSource.RetrieveProperties(AFile.FSFile, [fpComment], []);
AFileSource.RetrieveProperties(AFile.FSFile, [fpComment], []);
except
on EFileNotFound do;
end;
@ -442,20 +444,20 @@ begin
begin
if HaveIcons then
begin
if AFile.IconID < 0 then
AFile.IconID := PixMapManager.GetIconByFile(AFile.FSFile,
DirectAccess, True, gShowIcons, not gIconOverlays);
if (AFile.IconID < 0) and (AFile.Icon = nil) then
begin
AFile.IconID := PixMapManager.GetIconByFile(AFileSource, AFile, DirectAccess, True, gShowIcons, not gIconOverlays);
end;
{$IF DEFINED(MSWINDOWS) OR DEFINED(RabbitVCS)}
if gIconOverlays and (AFile.IconOverlayID < 0) then
begin
AFile.IconOverlayID := PixMapManager.GetIconOverlayByFile(AFile.FSFile,
DirectAccess);
AFile.IconOverlayID := PixMapManager.GetIconOverlayByFile(AFile.FSFile, DirectAccess);
end;
{$ENDIF}
end;
if FileSource.CanRetrieveProperties(AFile.FSFile, FilePropertiesNeeded) then
if AFileSource.CanRetrieveProperties(AFile.FSFile, FilePropertiesNeeded) then
try
FileSource.RetrieveProperties(AFile.FSFile, FilePropertiesNeeded, GetVariantFileProperties);
AFileSource.RetrieveProperties(AFile.FSFile, FilePropertiesNeeded, GetVariantFileProperties);
except
on EFileNotFound do;
end;
@ -469,9 +471,9 @@ begin
begin
AFile := FFiles[i];
if (AFile.FSFile.Name <> '..') and (AFile.Busy * [bsProp] = []) and
(FileSource.CanRetrieveProperties(AFile.FSFile, AFilePropertiesNeeded) or
(AFileSource.CanRetrieveProperties(AFile.FSFile, AFilePropertiesNeeded) or
(AFile.TextColor = clNone) or
(HaveIcons and ((AFile.IconID < 0)
(HaveIcons and ( ((AFile.IconID < 0) and (AFile.Icon = nil))
{$IF DEFINED(MSWINDOWS) OR DEFINED(RabbitVCS)}
or (gIconOverlays and (AFile.IconOverlayID < 0))
{$ENDIF}
@ -487,7 +489,7 @@ begin
if Assigned(AFileList) and (AFileList.Count > 0) then
begin
Worker := TFilePropertiesRetriever.Create(
FileSource,
AFileSource,
WorkersThread,
AFilePropertiesNeeded,
GetVariantFileProperties,

View file

@ -489,17 +489,12 @@ var
end
else
begin
IconID := AFile.IconID;
// Draw default icon if there is no icon for the file.
if IconID = -1 then
IconID := PixMapManager.GetDefaultIcon(AFile.FSFile);
// Center icon
X:= aRect.Left + (aRect.Right - aRect.Left - gIconsSize) div 2;
Y:= aRect.Top + (iTextTop - aRect.Top - gIconsSize) div 2;
// Draw icon for a file
PixMapManager.DrawBitmap(IconID, Canvas, X, Y);
PixMapManager.DrawBitmap(AFile, Canvas, X, Y);
end;
// Draw overlay icon for a file if needed

View file

@ -47,7 +47,7 @@ interface
uses
Classes, SysUtils, Graphics, syncobjs, uFileSorting, DCStringHashListUtf8,
uFile, uIconTheme, uDrive, uDisplayFile, uGlobs, uDCReadPSD, uOSUtils, FPImage,
LCLVersion, uVectorImage, uMultiArc
LCLVersion, uVectorImage, uMultiArc, uFileSource, WfxPlugin
{$IF DEFINED(MSWINDOWS)}
, ShlObj
{$ELSEIF DEFINED(MSWINDOWS) and DEFINED(LCLQT5)}
@ -289,7 +289,8 @@ type
}
function GetBitmap(iIndex : PtrInt) : TBitmap;
function DrawBitmap(iIndex: PtrInt; Canvas : TCanvas; X, Y: Integer) : Boolean;
function DrawBitmapAlpha(iIndex: PtrInt; Canvas : TCanvas; X, Y: Integer) : Boolean;
function DrawBitmap(AFile: TDisplayFile; Canvas : TCanvas; X, Y: Integer) : Boolean;
function DrawBitmapAlpha(AFile: TDisplayFile; Canvas : TCanvas; X, Y: Integer) : Boolean;
{en
Draws bitmap stretching it if needed to Width x Height.
If Width is 0 then full bitmap width is used.
@ -298,6 +299,7 @@ type
Index of pixmap manager's bitmap.)
}
function DrawBitmap(iIndex: PtrInt; Canvas : TCanvas; X, Y, Width, Height: Integer) : Boolean;
function DrawBitmap(AFile: TDisplayFile; Canvas : TCanvas; X, Y, Width, Height: Integer) : Boolean;
{en
Draws overlay bitmap for a file.
@param(AFile
@ -306,6 +308,7 @@ type
Whether the file is on a directly accessible file source.)
}
function DrawBitmapOverlay(AFile: TDisplayFile; DirectAccess: Boolean; Canvas : TCanvas; X, Y: Integer) : Boolean;
function CheckAddPixmap(AUniqueName: String; AIconSize: Integer; ADestroy: Boolean; TheIcon: PWfxIcon; out AIcon: TBitmap): PtrInt;
function GetIconBySortingDirection(SortingDirection: TSortDirection): PtrInt;
{en
Retrieves icon index in FPixmapList table for a file.
@ -330,6 +333,8 @@ type
}
function GetIconByFile(AFile: TFile; DirectAccess: Boolean; LoadIcon: Boolean;
IconsMode: TShowIconsMode; GetIconWithLink: Boolean): PtrInt;
function GetIconByFile(constref AFileSource: IFileSource; AFile: TDisplayFile; DirectAccess: Boolean; LoadIcon: Boolean;
IconsMode: TShowIconsMode; GetIconWithLink: Boolean): PtrInt; overload;
{$IF DEFINED(MSWINDOWS) OR DEFINED(RabbitVCS)}
{en
Retrieves overlay icon index for a file.
@ -380,8 +385,8 @@ function getBestNSImageWithSize( const srcImage:NSImage; const size:Integer ): N
implementation
uses
GraphType, LCLIntf, LCLType, LCLProc, Forms, uGlobsPaths, WcxPlugin,
DCStrUtils, uDCUtils, uFileSystemFileSource, uReSample, uDebug,
GraphType, LCLIntf, LCLType, LCLProc, Forms, uGlobsPaths, WcxPlugin, uClassesEx,
DCStrUtils, uDCUtils, uFileSystemFileSource, uReSample, uDebug, uFileSourceProperty,
IntfGraphics, DCOSUtils, DCClassesUtf8, LazUTF8, uGraphics, uHash, uSysFolders
{$IFDEF GTK2_FIX}
, uPixMapGtk, gdk2pixbuf, gdk2, glib2
@ -1984,12 +1989,30 @@ begin
Result := DrawBitmap(iIndex, Canvas, X, Y, gIconsSize, gIconsSize); // No bitmap stretching.
end;
function TPixMapManager.DrawBitmapAlpha(iIndex: PtrInt; Canvas: TCanvas; X, Y: Integer): Boolean;
function TPixMapManager.DrawBitmap(AFile: TDisplayFile; Canvas: TCanvas; X, Y: Integer): Boolean;
begin
Result := DrawBitmap(AFile, Canvas, X, Y, gIconsSize, gIconsSize); // No bitmap stretching.
end;
function TPixMapManager.DrawBitmapAlpha(AFile: TDisplayFile; Canvas: TCanvas; X, Y: Integer): Boolean;
var
ARect: TRect;
IconID: PtrInt;
ABitmap: Graphics.TBitmap;
begin
ABitmap:= GetBitmap(iIndex);
if Assigned(AFile.Icon) then
begin
ABitmap:= TBitmap.Create;
ABitmap.Assign(AFile.Icon);
end
else begin
if AFile.IconID < 0 then
IconID:= GetDefaultIcon(AFile.FSFile)
else begin
IconID:= AFile.IconID;
end;
ABitmap:= GetBitmap(IconID);
end;
Result := Assigned(ABitmap);
if Result then
begin
@ -2098,6 +2121,29 @@ begin
{$ENDIF}
end;
function TPixMapManager.DrawBitmap(AFile: TDisplayFile; Canvas: TCanvas; X, Y, Width, Height: Integer): Boolean;
var
aRect: TRect;
IconID: PtrInt;
begin
if (AFile.Icon = nil) then
begin
// Draw default icon if there is no icon for the file
if AFile.IconID < 0 then
IconID:= GetDefaultIcon(AFile.FSFile)
else begin
IconID:= AFile.IconID;
end;
Result:= DrawBitmap(IconID, Canvas, X, Y, Width, Height);
end
else begin
if Width = 0 then Width:= AFile.Icon.Width;
if Height = 0 then Height:= AFile.Icon.Height;
aRect:= Classes.Bounds(X, Y, Width, Height);
Canvas.StretchDraw(aRect, AFile.Icon);
end;
end;
function TPixMapManager.DrawBitmapOverlay(AFile: TDisplayFile; DirectAccess: Boolean; Canvas: TCanvas; X, Y: Integer): Boolean;
var
I: Integer;
@ -2133,6 +2179,84 @@ begin
;
end;
function TPixMapManager.CheckAddPixmap(AUniqueName: String; AIconSize: Integer;
ADestroy: Boolean; TheIcon: PWfxIcon; out AIcon: TBitmap): PtrInt;
var
Index: PtrInt;
Picture: TPicture;
Stream: TBlobStream;
begin
AIcon:= nil;
// Icon has a unique name
if Length(AUniqueName) > 0 then
begin
FPixmapsLock.Acquire;
try
// Try to find in the cache
Index:= FPixmapsFileNames.Find(AUniqueName);
if (Index >= 0) then
begin
if ADestroy then
begin
case TheIcon^.Format of
{$IF DEFINED(MSWINDOWS)}
FS_ICON_FORMAT_HICON: DestroyIcon(HICON(TheIcon^.Data));
{$ENDIF}
FS_ICON_FORMAT_BINARY: TheIcon^.Free(TheIcon^.Data);
end;
end;
Exit(PtrInt(FPixmapsFileNames.List[Index]^.Data));
end;
finally
FPixmapsLock.Release;
end;
end;
Result:= -1;
case TheIcon^.Format of
{$IF DEFINED(MSWINDOWS)}
FS_ICON_FORMAT_HICON:
begin
AIcon:= BitmapCreateFromHICON(HICON(TheIcon^.Data));
if ADestroy then DestroyIcon(HICON(TheIcon^.Data));
end;
{$ENDIF}
FS_ICON_FORMAT_FILE:
begin
Result:= CheckAddPixmap(AUniqueName, AIconSize);
end;
FS_ICON_FORMAT_BINARY:
begin
Picture:= TPicture.Create;
try
Stream:= TBlobStream.Create(TheIcon^.Data, TheIcon^.Size);
try
Picture.LoadFromStream(Stream);
AIcon:= Graphics.TBitmap.Create;
BitmapAssign(AIcon, TRasterImage(Picture.Graphic));
finally
Stream.Free;
end;
except
// Ignore;
end;
Picture.Free;
if ADestroy then TheIcon^.Free(TheIcon^.Data);
end;
end;
// Icon has a unique name, save to the cache
if Assigned(AIcon) and (Length(AUniqueName) > 0) then
begin
FPixmapsLock.Acquire;
try
Result := FPixmapList.Add(AIcon);
FPixmapsFileNames.Add(AUniqueName, Pointer(Result));
finally
FPixmapsLock.Release;
end;
end;
end;
function TPixMapManager.GetIconBySortingDirection(SortingDirection: TSortDirection): PtrInt;
begin
case SortingDirection of
@ -2150,7 +2274,7 @@ begin
end;
function TPixMapManager.GetIconByFile(AFile: TFile; DirectAccess: Boolean; LoadIcon: Boolean;
IconsMode: TShowIconsMode; GetIconWithLink: Boolean): PtrInt;
IconsMode: TShowIconsMode; GetIconWithLink: Boolean): PtrInt;
var
Ext: String;
{$IFDEF MSWINDOWS}
@ -2436,6 +2560,33 @@ begin
end;
end;
function TPixMapManager.GetIconByFile(constref AFileSource: IFileSource; AFile: TDisplayFile;
DirectAccess: Boolean; LoadIcon: Boolean; IconsMode: TShowIconsMode; GetIconWithLink: Boolean): PtrInt;
var
ABitmap: TBitmap;
begin
if Assigned(AFile.Icon) then Exit(-1);
if (fspCustomIcon in AFileSource.Properties) and AFileSource.IsPathAtRoot(AFile.FSFile.Path) then
begin
if AFile.FSFile.Name = '..' then
begin
Result := FiUpDirIconID;
Exit;
end;
Result:= AFileSource.GetCustomIcon(AFile.FSFile, gIconsSize, ABitmap);
if (Result >= 0) then Exit;
if Assigned(ABitmap) then
begin
AFile.Icon:= ABitmap;
Exit(-1);
end;
end;
Result:= GetIconByFile(AFile.FSFile, DirectAccess, LoadIcon, IconsMode, GetIconWithLink);
end;
{$IF DEFINED(MSWINDOWS)}
procedure TPixMapManager.ClearSystemCache;
var

View file

@ -31,6 +31,7 @@ type
FTag: PtrInt; //<en File view related info
FSelected: Boolean; //<en If is selected
FBusy: TDisplayFileBusy; //<en File properties is busy
FIcon: TBitmap; //<en File icon (local cache)
FIconID: PtrInt; //<en Icon ID for PixmapManager
FIconOverlayID: PtrInt; //<en Overlay icon ID for PixmapManager
FTextColor: TColor; //<en Text color in file list
@ -42,6 +43,7 @@ type
// Cache of displayed strings.
FDisplayStrings: TStringList;
procedure SetIcon(AValue: TBitmap);
public
{en
@ -72,6 +74,7 @@ type
property FSFile: TFile read FFSFile write FFSFile;
property DisplayItem: TDisplayItemPtr read FDisplayItem write FDisplayItem;
property Selected: Boolean read FSelected write FSelected;
property Icon: TBitmap read FIcon write SetIcon;
property IconID: PtrInt read FIconID write FIconID;
property IconOverlayID: PtrInt read FIconOverlayID write FIconOverlayID;
property TextColor: TColor read FTextColor write FTextColor;
@ -126,6 +129,12 @@ type
implementation
procedure TDisplayFile.SetIcon(AValue: TBitmap);
begin
FIcon.Free;
FIcon:= AValue;
end;
constructor TDisplayFile.Create(ReferenceFile: TFile);
begin
FTag := -1;
@ -141,6 +150,7 @@ begin
inherited Destroy;
FDisplayStrings.Free;
FSFile.Free;
FIcon.Free;
end;
function TDisplayFile.Clone(NewReferenceFile: TFile): TDisplayFile;
@ -170,6 +180,13 @@ begin
AFile.FIconOverlayID := FIconOverlayID;
AFile.FTextColor := FTextColor;
if (FIcon = nil) then
AFile.Icon:= nil
else begin
AFile.Icon:= TBitmap.Create;
AFile.FIcon.Assign(FIcon);
end;
if Assigned(AFile.FFSFile) then
begin
AFile.FDisplayStrings.AddStrings(FDisplayStrings);

View file

@ -30,7 +30,7 @@ unit uWFXmodule;
interface
uses
SysUtils, Classes, WfxPlugin, uWFXprototypes,
SysUtils, Classes, Graphics, WfxPlugin, uWFXprototypes,
dynlibs, DCClassesUtf8, Extension, DCBasicTypes, DCXmlConfig,
uWdxPrototypes, uWdxModule, uFileSource;
@ -63,6 +63,7 @@ type
TWFXModule = class(TPluginWDX)
private
FBackgroundFlags: Integer;
FIconMutex: TRTLCriticalSection;
public
{ Mandatory }
FsInit : TFsInit;
@ -137,6 +138,7 @@ type
function WfxGetLocalName(var sFileName: String): Boolean;
function WfxDisconnect(const DisconnectRoot: String): Boolean;
function WfxContentGetDefaultView(out DefaultView: TFileSourceFields): Boolean;
function WfxExtractCustomIcon(var RemoteName: String; AIconSize: Integer; out TheIcon: TWfxIcon): Integer;
private
function LoadModule(const sName: String):Boolean; overload; {Load plugin}
procedure UnloadModule; override;
@ -191,7 +193,7 @@ uses
LazUTF8, FileUtil,
//DC
uDCUtils, uLng, uGlobsPaths, uOSUtils, uWfxPluginUtil, fDialogBox, DCOSUtils,
uDCUtils, uLng, uGlobsPaths, uOSUtils, uWfxPluginUtil, DCOSUtils,
DCStrUtils, DCConvertEncoding, uComponentsSignature, uOSForms, uExtension;
const
@ -614,10 +616,48 @@ begin
end;
end;
function TWFXModule.WfxExtractCustomIcon(var RemoteName: String; AIconSize: Integer; out TheIcon: TWfxIcon): Integer;
var
Flags: Integer = FS_ICONFLAG_BACKGROUND;
asFileName: array[0..MAX_PATH] of AnsiChar;
wsFileName: array[0..MAX_PATH] of WideChar;
begin
TheIcon:= Default(TWfxIcon);
if (AIconSize = 16) then begin
Flags:= Flags or FS_ICONFLAG_SMALL;
end;
TheIcon.Size:= AIconSize;
EnterCriticalSection(FIconMutex);
try
if Assigned(FsExtractCustomIconW) then
begin
StrPLCopy(wsFileName, CeUtf8ToUtf16(RemoteName), MAX_PATH);
Result:= FsExtractCustomIconW(wsFileName, Flags, @TheIcon);
if Result in [FS_ICON_EXTRACTED, FS_ICON_EXTRACTED_DESTROY] then
RemoteName:= CeUtf16ToUtf8(UnicodeString(wsFileName));
end
else if Assigned(FsExtractCustomIcon) then
begin
StrPLCopy(asFileName, CeUtf8ToSys(RemoteName), MAX_PATH);
Result:= FsExtractCustomIcon(asFileName, Flags, @TheIcon);
if Result in [FS_ICON_EXTRACTED, FS_ICON_EXTRACTED_DESTROY] then
RemoteName:= CeSysToUtf8(StrPas(asFileName));
end
else begin
Result:= FS_ICON_USEDEFAULT;
end;
finally
LeaveCriticalSection(FIconMutex);
end;
end;
constructor TWFXModule.Create;
begin
inherited;
FName:= 'FS';
InitCriticalSection(FIconMutex);
end;
destructor TWFXModule.Destroy;
@ -630,6 +670,7 @@ begin
ExtensionFinalize(nil);
end;
inherited Destroy;
DoneCriticalSection(FIconMutex);
end;
function TWFXModule.LoadModule(const sName: String): Boolean;

View file

@ -32,10 +32,10 @@ type
//------------------------------------------------------
{R} TFsSetAttr=function (RemoteName:pansichar;NewAttr:integer):bool;
{R} TFsSetTime=Function(RemoteName:pansichar;CreationTime,LastAccessTime,LastWriteTime:PWfxFileTime):bool;
{U} TFsExtractCustomIcon=function(RemoteName:pansichar;ExtractFlags:integer;var TheIcon:hicon):integer;
{U} TFsExtractCustomIcon=function(RemoteName:pansichar;ExtractFlags:integer; TheIcon: PWfxIcon):integer;
{R} TFsRenMovFile= function(OldName,NewName:pansichar; Move, OverWrite:bool; ri:pRemoteInfo):Integer;
{U} TFsDisconnect = function (DisconnectRoot:pansichar):bool;
{U} TFsGetPreviewBitmap = function ( RemoteName:pansichar; width,height:integer; ReturnedBitmap:HBITMAP):integer;
{U} TFsGetPreviewBitmap = function ( RemoteName:pansichar; width,height:integer; ReturnedBitmap: PWfxIcon):integer;
{R} TFsLinksToLocalFiles = function:bool;
{R} TFsGetLocalName = function (RemoteName:pansichar;maxlen:integer):bool;
//------------------------------------------------------
@ -68,8 +68,8 @@ type
TFsSetAttrW = function(RemoteName:pwidechar;NewAttr:integer):bool;
TFsSetTimeW = function(RemoteName:pwidechar;CreationTime,LastAccessTime, LastWriteTime:PWfxFileTime):bool;
TFsStatusInfoW = procedure(RemoteDir:pwidechar;InfoStartEnd,InfoOperation:integer);
TFsExtractCustomIconW = function(RemoteName:pwidechar;ExtractFlags:integer; var TheIcon:hicon):integer;
TFsGetPreviewBitmapW = function(RemoteName:pwidechar;width,height:integer; var ReturnedBitmap:hbitmap):integer;
TFsExtractCustomIconW = function(RemoteName:pwidechar;ExtractFlags:integer; TheIcon: PWfxIcon):integer;
TFsGetPreviewBitmapW = function(RemoteName:pwidechar;width,height:integer; ReturnedBitmap: PWfxIcon):integer;
TFsGetLocalNameW = function(RemoteName:pwidechar;maxlen:integer):bool;
//------------------------------------------------------
TFsContentGetValueW = function(FileName:pwidechar;FieldIndex,UnitIndex:integer;FieldValue:pbyte; maxlen,flags:integer):integer;