LCL/ShellCtrls: On Windows automatically show shell icons in TShellTreeView when no imagelist is attached.

git-svn-id: trunk@64575 -
This commit is contained in:
wp 2021-02-13 22:11:24 +00:00
parent fcff9d8ea7
commit e32b62e6b4
3 changed files with 121 additions and 13 deletions

View File

@ -3511,7 +3511,9 @@ type
procedure DoAutoAdjustLayout(const AMode: TLayoutAdjustmentPolicy; procedure DoAutoAdjustLayout(const AMode: TLayoutAdjustmentPolicy;
const AXProportion, AYProportion: Double); override; const AXProportion, AYProportion: Double); override;
function ExpandSignSizeIsStored: Boolean; function ExpandSignSizeIsStored: Boolean;
function GetBuiltinIconSize: TSize; virtual;
function GetDragImages: TDragImageList; override; function GetDragImages: TDragImageList; override;
function GetImageSize: TSize;
function GetMaxLvl: integer; function GetMaxLvl: integer;
function GetMaxScrollLeft: integer; function GetMaxScrollLeft: integer;
function GetMaxScrollTop: integer; function GetMaxScrollTop: integer;
@ -3545,6 +3547,7 @@ type
procedure DoStartDrag(var DragObject: TDragObject); override; procedure DoStartDrag(var DragObject: TDragObject); override;
procedure DragOver(Source: TObject; X,Y: Integer; State: TDragState; procedure DragOver(Source: TObject; X,Y: Integer; State: TDragState;
var Accept: Boolean); override; var Accept: Boolean); override;
function DrawBuiltinIcon(ANode: TTreeNode; ARect: TRect): TSize; virtual;
procedure EndEditing(Cancel: boolean = false); virtual; procedure EndEditing(Cancel: boolean = false); virtual;
procedure EnsureNodeIsVisible(ANode: TTreeNode); procedure EnsureNodeIsVisible(ANode: TTreeNode);
procedure Expand(Node: TTreeNode); virtual; procedure Expand(Node: TTreeNode); virtual;

View File

@ -1754,16 +1754,24 @@ function TTreeNode.DisplayTextLeft: integer;
var var
TV: TCustomTreeView; TV: TCustomTreeView;
ImgIndex: TImageIndex; ImgIndex: TImageIndex;
sz: TSize;
begin begin
Result := DisplayIconLeft; Result := DisplayIconLeft;
TV := TreeView; TV := TreeView;
if (TV = nil) or (TV.Images = nil) then Exit; if TV = nil then
exit;
sz := TV.GetImageSize;
if (TV.Images = nil) then
begin
inc(Result, sz.CX);
exit;
end;
if (TV.Selected = Self) then if (TV.Selected = Self) then
ImgIndex:=SelectedIndex ImgIndex:=SelectedIndex
else else
ImgIndex:=ImageIndex; ImgIndex:=ImageIndex;
if (ImgIndex<0) or (ImgIndex>=TV.Images.Count) then Exit; if (ImgIndex<0) or (ImgIndex>=TV.Images.Count) then Exit;
Inc(Result, TV.Images.WidthForPPI[TV.StateImagesWidth, TV.Font.PixelsPerInch] + TV.FDefItemSpace); Inc(Result, sz.CX + TV.FDefItemSpace);
end; end;
function TTreeNode.DisplayTextRight: integer; function TTreeNode.DisplayTextRight: integer;
@ -3667,12 +3675,11 @@ begin
if (tvoAutoItemHeight in FOptions) if (tvoAutoItemHeight in FOptions)
and HandleAllocated and Canvas.HandleAllocated then begin and HandleAllocated and Canvas.HandleAllocated then begin
NewDefItemHeight:=Canvas.TextHeight(TVAutoHeightString)+FDefItemSpace; NewDefItemHeight:=Canvas.TextHeight(TVAutoHeightString)+FDefItemSpace;
if Assigned(FImages) then ImageSize := GetImageSize;
ImageSize := Images.SizeForPPI[ImagesWidth, Font.PixelsPerInch];
if Assigned(FStateImages) then if Assigned(FStateImages) then
StateImageSize := StateImages.SizeForPPI[StateImagesWidth, Font.PixelsPerInch]; StateImageSize := StateImages.SizeForPPI[StateImagesWidth, Font.PixelsPerInch];
if NewDefItemHeight<FDefItemSpace then NewDefItemHeight:=FDefItemSpace; if NewDefItemHeight<FDefItemSpace then NewDefItemHeight:=FDefItemSpace;
if (Images<>nil) and (ImageSize.cy+FDefItemSpace>NewDefItemHeight) then if (ImageSize.cy > 0) and (ImageSize.cy + FDefItemSpace > NewDefItemHeight) then
NewDefItemHeight:=ImageSize.cy+FDefItemSpace; NewDefItemHeight:=ImageSize.cy+FDefItemSpace;
if (StateImages<>nil) and (StateImageSize.cy+FDefItemSpace>NewDefItemHeight) then if (StateImages<>nil) and (StateImageSize.cy+FDefItemSpace>NewDefItemHeight) then
NewDefItemHeight:=StateImageSize.cy+FDefItemSpace; NewDefItemHeight:=StateImageSize.cy+FDefItemSpace;
@ -4704,6 +4711,20 @@ begin
Result := nil; Result := nil;
end; end;
function TCustomTreeView.GetBuiltinIconSize: TSize;
begin
Result := Types.Size(0, 0);
end;
function TCustomTreeView.GetImageSize: TSize;
begin
if FImages <> nil then
begin
Result := Images.SizeForPPI[ImagesWidth, Font.PixelsPerInch]
end else
Result := GetBuiltinIconSize;
end;
procedure TCustomTreeView.UpdateInsertMark(X,Y: integer); procedure TCustomTreeView.UpdateInsertMark(X,Y: integer);
begin begin
if (tvoAutoInsertMark in Options) and (not (csDesigning in ComponentState)) if (tvoAutoInsertMark in Options) and (not (csDesigning in ComponentState))
@ -5339,7 +5360,7 @@ var
var var
x, ImgIndex: integer; x, ImgIndex: integer;
CurTextRect: TRect; CurTextRect, ImgRect: TRect;
DrawState: TCustomDrawState; DrawState: TCustomDrawState;
PaintImages: boolean; PaintImages: boolean;
OverlayIndex: Integer; OverlayIndex: Integer;
@ -5404,7 +5425,12 @@ begin
end; end;
// draw icon // draw icon
if (Images <> nil) then if (Images = nil) then
begin
imgRect := NodeRect;
imgRect.Left := x+1;
inc(x, DrawBuiltinIcon(Node, imgRect).CX + FDefItemSpace);
end else
begin begin
if FSelectedNode <> Node then if FSelectedNode <> Node then
begin begin
@ -5479,6 +5505,11 @@ begin
end; end;
end; end;
function TCustomTreeView.DrawBuiltinIcon(ANode: TTreeNode; ARect: TRect): TSize;
begin
Result := Size(0, 0);
end;
procedure TCustomTreeView.GetImageIndex(Node: TTreeNode); procedure TCustomTreeView.GetImageIndex(Node: TTreeNode);
begin begin
if Assigned(FOnGetImageIndex) then if Assigned(FOnGetImageIndex) then

View File

@ -24,7 +24,7 @@ interface
uses uses
Classes, SysUtils, Laz_AVL_Tree, Classes, SysUtils, Laz_AVL_Tree,
// LCL // LCL
Forms, Graphics, ComCtrls, LCLProc, LCLStrConsts, Forms, Graphics, ComCtrls, LCLProc, LCLType, LCLStrConsts, Types,
// LazUtils // LazUtils
FileUtil, LazFileUtils, LazUTF8, Masks; FileUtil, LazFileUtils, LazUTF8, Masks;
@ -64,6 +64,7 @@ type
FShellListView: TCustomShellListView; FShellListView: TCustomShellListView;
FFileSortType: TFileSortType; FFileSortType: TFileSortType;
FInitialRoot: String; FInitialRoot: String;
FUseBuiltinIcons: Boolean;
FOnAddItem: TAddItemEvent; FOnAddItem: TAddItemEvent;
{ Setters and getters } { Setters and getters }
function GetPath: string; function GetPath: string;
@ -72,6 +73,7 @@ type
procedure SetPath(AValue: string); procedure SetPath(AValue: string);
procedure SetRoot(const AValue: string); procedure SetRoot(const AValue: string);
procedure SetShellListView(const Value: TCustomShellListView); procedure SetShellListView(const Value: TCustomShellListView);
procedure SetUseBuiltinIcons(const AValue: Boolean);
protected protected
procedure DoCreateNodeClass(var NewNodeClass: TTreeNodeClass); override; procedure DoCreateNodeClass(var NewNodeClass: TTreeNodeClass); override;
procedure Loaded; override; procedure Loaded; override;
@ -82,6 +84,15 @@ type
procedure DoSelectionChanged; override; procedure DoSelectionChanged; override;
procedure DoAddItem(const ABasePath: String; const AFileInfo: TSearchRec; var CanAdd: Boolean); procedure DoAddItem(const ABasePath: String; const AFileInfo: TSearchRec; var CanAdd: Boolean);
function CanExpand(Node: TTreeNode): Boolean; override; function CanExpand(Node: TTreeNode): Boolean; override;
{$ifdef mswindows}
private
FBuiltinIconSize: TSize;
protected
function DrawBuiltInIcon(ANode: TTreeNode; ARect: TRect): TSize; override;
function GetBuiltinIconSize: TSize; override;
{$endif}
public public
{ Basic methods } { Basic methods }
constructor Create(AOwner: TComponent); override; constructor Create(AOwner: TComponent); override;
@ -97,6 +108,7 @@ type
function GetPathFromNode(ANode: TTreeNode): string; function GetPathFromNode(ANode: TTreeNode): string;
procedure PopulateWithBaseFiles; procedure PopulateWithBaseFiles;
procedure Refresh(ANode: TTreeNode); overload; procedure Refresh(ANode: TTreeNode); overload;
property UseBuiltinIcons: Boolean read FUseBuiltinIcons write SetUseBuiltinIcons default true;
{ Properties } { Properties }
property ObjectTypes: TObjectTypes read FObjectTypes write SetObjectTypes; property ObjectTypes: TObjectTypes read FObjectTypes write SetObjectTypes;
@ -365,7 +377,7 @@ procedure Register;
implementation implementation
{$ifdef windows} {$ifdef windows}
uses Windows; uses Windows, ShellApi;
{$endif} {$endif}
const const
@ -411,7 +423,6 @@ begin
end; end;
{ TShellTreeNode } { TShellTreeNode }
procedure TShellTreeNode.SetBasePath(ABasePath: String); procedure TShellTreeNode.SetBasePath(ABasePath: String);
@ -470,6 +481,12 @@ begin
Value.ShellTreeView := Self; Value.ShellTreeView := Self;
end; end;
procedure TCustomShellTreeView.SetUseBuiltinIcons(const AValue: Boolean);
begin
if FUseBuiltinIcons = AValue then exit;
FUseBuiltinIcons := AValue;
Invalidate;
end;
procedure TCustomShellTreeView.DoCreateNodeClass( procedure TCustomShellTreeView.DoCreateNodeClass(
var NewNodeClass: TTreeNodeClass); var NewNodeClass: TTreeNodeClass);
@ -608,6 +625,7 @@ constructor TCustomShellTreeView.Create(AOwner: TComponent);
begin begin
inherited Create(AOwner); inherited Create(AOwner);
FInitialRoot := ''; FInitialRoot := '';
FUseBuiltinIcons := true;
// Initial property values // Initial property values
FObjectTypes:= [otFolders]; FObjectTypes:= [otFolders];
@ -984,6 +1002,65 @@ begin
FOnAddItem(Self, ABasePath, AFileInfo, CanAdd); FOnAddItem(Self, ABasePath, AFileInfo, CanAdd);
end; end;
{$ifdef mswindows}
{ Extracts the windows shell icon of the specified file. }
function GetShellIcon(const AFileName: WideString): TIcon;
var
FileInfo: TSHFileInfoW;
imgHandle: DWORD_PTR;
begin
imgHandle := SHGetFileInfoW(PWideChar(AFileName), 0, FileInfo, SizeOf(FileInfo),
SHGFI_ICON + SHGFI_SMALLICON + SHGFI_SYSICONINDEX);
if imgHandle <> 0 then
begin
Result := TIcon.Create;
Result.Handle := FileInfo.hIcon;
end else
Result := nil;
end;
function TCustomShellTreeView.DrawBuiltinIcon(ANode: TTreeNode; ARect: TRect): TSize;
var
filename: widestring;
ico: TIcon;
begin
if FUseBuiltinIcons then
begin
fileName := widestring(GetPathFromNode(ANode));
ico := GetShellIcon(fileName);
try
Canvas.Draw(ARect.Left, (ARect.Top + ARect.Bottom - ico.Height) div 2, ico);
Result := Types.Size(ico.Width, ico.Height);
finally
ico.Free;
end;
end else
Result := Types.Size(0, 0);
end;
function TCustomShellTreeView.GetBuiltinIconSize: TSize;
var
ico: TIcon;
begin
if FUseBuiltinIcons then
begin
if (FBuiltinIconSize.CX > 0) and (FBuiltinIconSize.CY > 0) then
Result := FBuiltinIconSize
else
begin
ico := GetShellIcon(WideString('C:'));
try
Result := Types.Size(ico.Width, ico.Height);
FBuiltinIconSize := Result;
finally
ico.Free;
end;
end;
end else
Result := Types.Size(0, 0);
end;
{$endif}
function TCustomShellTreeView.GetPathFromNode(ANode: TTreeNode): string; function TCustomShellTreeView.GetPathFromNode(ANode: TTreeNode): string;
begin begin
if Assigned(ANode) then if Assigned(ANode) then
@ -998,7 +1075,6 @@ begin
Result := ''; Result := '';
end; end;
procedure TCustomShellTreeView.Refresh(ANode: TTreeNode); procedure TCustomShellTreeView.Refresh(ANode: TTreeNode);
//nil will refresh root //nil will refresh root
var var
@ -1271,8 +1347,6 @@ begin
for i := 0 to sl.Count - 1 do debugln(['sl[',i,']="',sl[i],'"']); for i := 0 to sl.Count - 1 do debugln(['sl[',i,']="',sl[i],'"']);
{$endif} {$endif}
BeginUpdate; BeginUpdate;
try try
Node := Items.GetFirstVisibleNode; Node := Items.GetFirstVisibleNode;