Get file explorer icon based on file type.

Fixes #15
This commit is contained in:
2026-02-07 18:01:31 -05:00
parent 6f2a655497
commit aa42ec6072
6 changed files with 44 additions and 19 deletions

10
Cargo.lock generated
View File

@@ -295,6 +295,7 @@ dependencies = [
"cxx-qt", "cxx-qt",
"cxx-qt-build", "cxx-qt-build",
"cxx-qt-lib", "cxx-qt-lib",
"devicons",
"dirs", "dirs",
"edtui", "edtui",
"log", "log",
@@ -667,6 +668,15 @@ dependencies = [
"syn 2.0.114", "syn 2.0.114",
] ]
[[package]]
name = "devicons"
version = "0.6.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830e47e2f330cf4fdd5a958dcef921b9523ffc21ab6713aa5e77ba2cce03904b"
dependencies = [
"lazy_static",
]
[[package]] [[package]]
name = "digest" name = "digest"
version = "0.10.7" version = "0.10.7"

View File

@@ -18,6 +18,7 @@ tui-logger = "0.18.1"
edtui = "0.11.1" edtui = "0.11.1"
strum = "0.27.2" strum = "0.27.2"
uuid = { version = "1.19.0", features = ["v4"] } uuid = { version = "1.19.0", features = ["v4"] }
devicons = "0.6.12"
[build-dependencies] [build-dependencies]
# The link_qt_object_files feature is required for statically linking Qt 6. # The link_qt_object_files feature is required for statically linking Qt 6.

View File

@@ -21,7 +21,7 @@ TreeView {
boundsBehavior: Flickable.StopAtBounds boundsBehavior: Flickable.StopAtBounds
boundsMovement: Flickable.StopAtBounds boundsMovement: Flickable.StopAtBounds
clip: true clip: true
leftMargin: 5 leftMargin: 25
model: FileSystem model: FileSystem
rootIndex: FileSystem.setDirectory(fileSystemTreeView.rootDirectory) rootIndex: FileSystem.setDirectory(fileSystemTreeView.rootDirectory)
@@ -66,36 +66,30 @@ TreeView {
color: RustColors.explorer_text color: RustColors.explorer_text
text: treeDelegate.fileName text: treeDelegate.fileName
} }
indicator: Image { indicator: Label {
id: directoryIcon id: directoryIcon
function setSourceImage() {
let folderOpen = "data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 576 512\"><!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d=\"M88.7 223.8L0 375.8 0 96C0 60.7 28.7 32 64 32l117.5 0c17 0 33.3 6.7 45.3 18.7l26.5 26.5c12 12 28.3 18.7 45.3 18.7L416 96c35.3 0 64 28.7 64 64l0 32-336 0c-22.8 0-43.8 12.1-55.3 31.8zm27.6 16.1C122.1 230 132.6 224 144 224l400 0c11.5 0 22 6.1 27.7 16.1s5.7 22.2-.1 32.1l-112 192C453.9 474 443.4 480 432 480L32 480c-11.5 0-22-6.1-27.7-16.1s-5.7-22.2 .1-32.1l112-192z\"/></svg>";
let folderClosed = "data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 512 512\"><!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d=\"M64 480H448c35.3 0 64-28.7 64-64V160c0-35.3-28.7-64-64-64H288c-10.1 0-19.6-4.7-25.6-12.8L243.2 57.6C231.1 41.5 212.1 32 192 32H64C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64z\"/></svg>";
let file = "data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 384 512\"><!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d=\"M0 64C0 28.7 28.7 0 64 0L224 0l0 128c0 17.7 14.3 32 32 32l128 0 0 288c0 35.3-28.7 64-64 64L64 512c-35.3 0-64-28.7-64-64L0 64zm384 64l-128 0L256 0 384 128z\"/></svg>";
// If the item has children, it's a directory.
if (treeDelegate.hasChildren) {
return treeDelegate.expanded ? folderOpen : folderClosed;
}
return file;
}
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
antialiasing: true antialiasing: true
asynchronous: true font.family: localFont.font.family
fillMode: Image.PreserveAspectFit font.pixelSize: 18
smooth: true smooth: true
source: setSourceImage() text: fileSystemTreeView.model.icon(filePath)
sourceSize.height: 15
sourceSize.width: 15
x: treeDelegate.leftMargin + (treeDelegate.depth * treeDelegate.indentation) + (indicator.visible ? indicator.width : 0) x: treeDelegate.leftMargin + (treeDelegate.depth * treeDelegate.indentation) + (indicator.visible ? indicator.width : 0)
} }
FontLoader {
id: localFont
source: "qrc:/fonts/saucecodepro-xlight.ttf"
}
Label { Label {
id: indicator id: indicator
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
font.family: localFont.font.family
font.pixelSize: 10 font.pixelSize: 10
font.weight: localFont.font.weight
text: expanded ? "⮟" : "⮞" text: expanded ? "⮟" : "⮞"
visible: isTreeNode && hasChildren visible: isTreeNode && hasChildren
x: padding + (depth * indentation) x: padding + (depth * indentation)

View File

@@ -1,5 +1,10 @@
<RCC> <RCC>
<qresource prefix="/images"> <qresource prefix="/images">
<file alias="kilroy.png">images/kilroy-256.png</file> <file alias="kilroy.png">resources/images/kilroy-256.png</file>
</qresource>
<qresource prefix="/fonts">
<file alias="saucecodepro.ttf">resources/SauceCodeProNerdFont-Black.ttf</file>
<file alias="saucecodepro-light.ttf">resources/SauceCodeProNerdFont-Light.ttf</file>
<file alias="saucecodepro-xlight.ttf">resources/SauceCodeProNerdFont-ExtraLight.ttf</file>
</qresource> </qresource>
</RCC> </RCC>

View File

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

View File

@@ -3,6 +3,7 @@
// SPDX-License-Identifier: GNU General Public License v3.0 or later // SPDX-License-Identifier: GNU General Public License v3.0 or later
use cxx_qt_lib::{QModelIndex, QString}; use cxx_qt_lib::{QModelIndex, QString};
use devicons::FileIcon;
use dirs; use dirs;
use log::warn; use log::warn;
use std::fs; use std::fs;
@@ -52,6 +53,9 @@ pub mod qobject {
#[qinvokable] #[qinvokable]
#[cxx_name = "setDirectory"] #[cxx_name = "setDirectory"]
fn set_directory(self: Pin<&mut FileSystem>, path: &QString) -> QModelIndex; fn set_directory(self: Pin<&mut FileSystem>, path: &QString) -> QModelIndex;
#[qinvokable]
fn icon(self: Pin<&mut FileSystem>, path: &QString) -> QString;
} }
} }
@@ -139,4 +143,15 @@ impl qobject::FileSystem {
self.set_root_path(&QString::from(homedir)) self.set_root_path(&QString::from(homedir))
} }
} }
fn icon(self: std::pin::Pin<&mut Self>, path: &QString) -> QString {
let str = path.to_string();
if Path::new(&str).is_dir() {
// Ensures directories are given a folder icon and not mistakenly resolved to a language.
// For example, a directory named `cpp` would otherwise return a C++ icon.
return QString::from(FileIcon::from("dir/").to_string())
}
let icon = FileIcon::from(str);
QString::from(icon.to_string())
}
} }