iced-swdir-tree
A reusable iced widget for displaying a directory tree with selection, lazy loading, filtering and asynchronous traversal.
Built on top of swdir's scan_dir for
single-level, non-recursive directory listings — ideal for GUI trees that
expand one folder at a time.
Features
- Single-select. Clicks emit a
Selected(PathBuf, bool)event; theboolindicates whether the target is a directory. - Lazy loading. Only the root is created eagerly; child folders are scanned on first expand.
- Non-blocking. Directory traversal runs on a worker thread through
iced::Task::perform; the UI thread never stalls on disk I/O. - Three display filters.
FoldersOnly,FilesAndFolders(default),AllIncludingHidden. Filter changes are applied from an in-memory cache, so switching is instant — no re-scan. - Stale-result handling. Every scan carries a generation counter, so a collapse/re-expand cycle safely discards in-flight results from the cancelled round-trip.
- Error tolerance. Permission denials, missing paths, and symlink cycles are surfaced as per-node errors that the view greys out — no panics, no UI freezes.
- Optional lucide icons. Disabled by default; enable the
iconsfeature to pull in real vector glyphs. The public API is identical in both modes. - Cross-platform. Hidden-file detection follows OS conventions: dotfile
on Unix,
HIDDENattribute plus dotfile fallback on Windows, dotfile elsewhere.
Installation
[]
= "0.14"
= "0.1"
To use real lucide icons instead of the Unicode-symbol fallback:
[]
= "0.14"
= { = "0.1", = ["icons"] }
The crate works without your application adding swdir directly — the
widget internally wraps it and exposes the pieces you need through its own
API.
Quick start
use PathBuf;
use ;
use ;
For a working example with a filter picker and a selection status bar, see
examples/basic.rs. For the lucide-icons version, see
examples/with_icons.rs.
Using the icons feature
When icons is enabled, register the bundled lucide TTF with iced at
startup:
use LUCIDE_FONT_BYTES;
Without this registration the icon widgets still render, but as tofu squares — the default system font doesn't have the lucide glyphs.
Configuration
# use PathBuf;
# use ;
let tree = new
.with_filter
.with_max_depth;
| Method | Purpose |
|---|---|
new(root) |
Build a tree rooted at root. Only the root is eagerly created. |
with_filter(f) |
Builder form of set_filter. |
with_max_depth(d) |
Refuse to load below depth d (0 = root children only). |
set_filter(f) |
Change the filter at runtime. Re-derives from cache; no I/O. |
filter(), max_depth(), root_path(), selected_path() |
Read accessors. |
Events
The widget emits DirectoryTreeEvent:
Toggled(PathBuf)— the user clicked the caret on a folder.Selected(PathBuf, bool)— the user clicked a row;boolistruefor directories,falsefor files.Loaded(LoadPayload)— internal; a pending scan completed. Parent applications route it straight back intoupdate()without inspecting it.
Architecture
See ARCHITECTURE.md.