Skip to content

Configurable treemap expand depth - #3

Closed
Li3age wants to merge 3 commits into
gitRasheed:mainfrom
Li3age:feat/treemap-expand-depth
Closed

Li3age wants to merge 3 commits into
gitRasheed:mainfrom
Li3age:feat/treemap-expand-depth

Conversation

@Li3age

@Li3age Li3age commented Sep 19, 2026

Copy link
Copy Markdown

Closes #2.

Adds a Treemap depth setting under Settings → View: All / 1 / 2 / 3, defaulting to All, so nothing changes for anyone who doesn't touch it.

Depth counts from the folder in view, not from the scan root. That is what makes it work with the drill the treemap already had — click a block, the view fills with that folder, and the setting decides how much of the next layer is on screen. Measured absolutely, drilling into a folder would leave its own children permanently out of reach.

The plate a cap stops at

Every directory plate carries a grain texture that means "real bytes here, too small to draw". A plate whose contents are hidden by the depth preference means something else, so it is left bare and marked with a +. It has to be painted after the grain pass, not before: the grain lands on whole ancestor rects, so a bare plate drawn first would be textured right back.

Why changing depth does not make the map jump

A rect's frame comes from its ancestors' sibling sizes and the area cull, never from max_depth, and the cap is tested after the rect is pushed. A capped layout is therefore exactly the prefix of a deeper one — switching depth dissolves deeper tiles back into their parent plate and moves nothing. a_depth_cap_only_hides_deeper_rects in crates/core/src/treemap.rs pins that property; it is the reason the UI does not have to freeze hit-testing while a new layout is in flight.

Smaller things in here

  • get_treemap is over clippy's argument limit now, so it carries the same allow(clippy::too_many_arguments) that lay_row already does.
  • The light-theme colour for the + is #6b7280. The first pick was 2.04:1 against the plate, and the mark is the only thing distinguishing a collapsed plate from dead space, so it counts as a meaningful graphic rather than decoration.
  • The clamp floors at 1 on purpose: at a cap of 0 no rect has depth == 1, and double-click, wheel and the context menu's zoom-in all hit-test depth == 1 rects, so every way into the tree but the breadcrumbs would go dead.

Heads up, unrelated to this PR

cargo clippy --workspace fails on crates/scanner-ntfs/src/record.rs:276 with clippy::chunks_exact_to_as_chunks, which is new in clippy 1.98 (-D warnings makes it fatal). The repo doesn't pin a toolchain and CI uses @stable, so I think main is red for this too. Happy to send that fix separately if useful.

The UI is about to let the user change how deep the treemap lays out, and
re-layouts on every change. That is only smooth because of a property the
layout already had without anyone writing it down: a rect's frame comes from
its ancestors' sibling sizes and the area cull, never from max_depth, and the
cap is tested after the rect is pushed. So the capped layout is exactly the
prefix of a deeper one — changing depth dissolves deeper tiles back into
their parent plate and moves nothing.

Worth a test rather than a comment: the whole feature is unpleasant to use if
it ever stops holding, and the assertion compares whole TreemapRects, so any
field that starts depending on depth fails here first.

The second test pins the other half of the semantics, that depth counts from
the laid-out root. An absolute depth would leave a drilled-into folder with
nothing left to show at a cap of 1.
get_treemap takes an optional maxDepth, laid out relative to root_id. Null is
"as deep as the layout goes", which is the 24 that used to be hardcoded, so a
caller that does not care keeps the existing picture byte for byte. The
treemap has always drawn at most 24 levels; this only lets the UI ask for
fewer.

The clamp's floor of 1 is a contract with the UI rather than defensive
programming. At a cap of 0 no rect has depth 1, and double-click, wheel and
the context menu's zoom-in all hit-test `depth == 1` rects — every way into
the tree but the breadcrumbs would go dead. The ceiling is what bounds the
recursion and the IPC payload against a number the UI would never send
itself, since the argument crosses IPC as a u32 and the layout option is a
u8.

Kept as a free function so it is testable without Tauri's State, the way
delete_block_reason and filters_by_extension_only already are. The argument
list is over clippy's limit now; the allow says why, matching lay_row's.
The treemap opened every scan fully expanded, which is a lot of pixels to
read in a big folder and there was no way to ask for less. Settings now
carries a Treemap depth of All, 1, 2 or 3 levels, defaulting to All so
nothing changes for anyone who does not touch it.

Depth is measured from the folder in view rather than from the scan root.
That is what makes the setting work with the drill the treemap already had:
a click fills the view with a folder and it expands one level down from
there, so the setting decides how much of the *next* layer is on screen, not
how deep the original scan was opened. Measured absolutely, drilling into a
folder would find its own children permanently out of reach.

The plate a cap stops at is painted differently, and that is the whole
reason this is not a one-line layout change. Every directory plate carries a
grain texture meaning "real bytes here, too small to draw"; a plate whose
contents are hidden by the depth preference means something else, so it is
left bare over the grain its expanded ancestors laid down and marked with a
"+" in place of the texture. It has to be painted after the grain pass, not
before: the grain lands on whole ancestor rects, so a bare plate drawn first
would be textured right back. Both passes key off the same
`depth === layoutCap(maxDepth)` test, and layoutCap mirrors the back end's
clamp in one place so the plate the UI calls collapsed is the plate the
layout actually stopped at.

The mark is 3:1 or better against the plate in both themes — it is the only
thing distinguishing a collapsed plate from dead space, so it counts as
meaningful graphics, not decoration.

Persisted in localStorage next to the theme. Node ids are per scan, so
"remember which folders were expanded" cannot survive a rescan by id; the
depth is the part of that request that can be remembered, and it is the part
that caused the initial visual overload.

The treemap already had the rest of the SpaceSniffer feel this was asked
for — clicking a block zooms into it, the crumbs go back — so nothing about
the drill or its hit-testing changed.
@Li3age
Li3age marked this pull request as draft September 19, 2026 14:17
@Li3age

Li3age commented Sep 20, 2026

Copy link
Copy Markdown
Author

Superseded by #4.

This branch's depth setting was reimplemented from scratch there, beside the
adaptive layout, so the two are one control rather than two mechanisms. Closing
this one to keep the comparison in a single place.

@Li3age Li3age closed this Sep 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature request: configurable default expand depth (or remember expand state) to avoid visual overload

1 participant