Skip to content

feat(nam): group models by folder in a nested picker menu - #294

Merged
OpenSauce merged 2 commits into
mainfrom
feat/nam-folder-menu
Oct 16, 2026
Merged

OpenSauce merged 2 commits into
mainfrom
feat/nam-folder-menu

Conversation

@OpenSauce

Copy link
Copy Markdown
Owner

Summary

Packs ship as folders of dozens of files, and the NAM stage's pick list was a flat list, so every model had to sit loose in the nam folder. This makes the nam folder's directory structure the menu structure.

  • Loader (rustortion-core): walks the nam folder recursively. Each model is keyed by its path relative to that folder, without the extension and with / separators on every platform (Pack/Clean). A top-level file keeps its bare stem, so existing presets keep resolving. The cab-from-name guess still reads the file's own name, never the folder.
  • Picker (rustortion-ui): replaces pick_list with an iced_aw menu bar with a single root. Each folder fans out sideways into its contents, nesting as deep as the tree goes; loose files sit alongside folders at the same level, sorted together by name (case-insensitive). The selected model is highlighted. The menu stays open until something is clicked, like a pick list.
  • Dependency: iced_aw = 0.14.1 with only the menu feature. It depends on the same iced_widget 0.14.2 already in the lockfile, and the plugin build (iced_baseview) compiles with it.

Layout notes

Two iced_aw quirks are worked around and commented in the code:

  • The bar lays its root out against an unbounded width, so a Fill root button never gets a size. The root button is sized through responsive.
  • The bar right-aligns a root menu whenever the button sits in the right half of the window. The root menu is given the button's width so it hangs straight below it.

Testing

  • cargo test --workspace (excluding plugin/xtask): 325 passed.
  • New tests: recursive scan produces Folder/Sub/Model keys and leaves top-level stems bare; folder names don't feed the cab-from-name guess; the picker's tree builder groups and sorts keys correctly.
  • cargo clippy --all-targets clean on core, ui, standalone; cargo check -p rustortion-plugin clean; cargo fmt --check clean.
  • Manually verified in the standalone with a nam folder containing three subfolders and a few loose files: root opens below the button, folders fan out on hover, selection works and the preset keeps the full key.

🤖 Generated with Claude Code

OpenSauce and others added 2 commits October 16, 2026 19:47
Packs ship as folders of dozens of files, and the NAM stage's pick list is a
flat list, so until now every model had to sit loose in the nam folder and the
picker grew with the collection.

The loader now walks the nam folder recursively and keys each model by its path
relative to that folder, without the extension and with `/` separators on every
platform (`Pack/Clean`). A top-level file keeps its bare stem, so presets saved
before this change keep resolving. The cab-from-name guess still reads the
file's own name, never the folder it sits in.

The picker is an `iced_aw` menu bar with a single root: each folder fans out
sideways into its contents, nesting as deep as the directory tree goes, and
loose files sit alongside the folders at the same level, sorted together by
name. The root menu is as wide as the button so it hangs straight below it like
a pick list; the bar would otherwise right-align it whenever the button sits in
the right half of the window. The root button is sized through `responsive`
because the bar lays its root out against an unbounded width, where a `Fill`
button never gets a size.

`iced_aw` is pulled in with only the `menu` feature.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…d hidden folders

Review findings on the folder picker:

- Clicking a folder row collapsed the whole menu. `Item::with_menu` inherits
  the bar's close-on-item-click, and people do click a folder to open it.
  Folder rows now opt out; only picking a model or clicking away closes.
- The recursive scan followed symlinks, so a link pointing back up the tree
  was walked until the OS refused, parsing every model dozens of times.
  The walk now checks the entry's own file type, which does not follow
  links, and skips symlinked directories.
- Dot-folders left by sync tools and desktop trash (`.stfolder`,
  `.Trash-1000`) were scanned, so a trashed model came back as a picker
  entry. They are skipped.
- A file whose path is not valid UTF-8 was dropped silently; it now warns
  like every other skipped file.
- The tree test also pins that a folder and a loose file sharing a name
  both survive side by side.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@OpenSauce
OpenSauce marked this pull request as ready for review October 16, 2026 18:59
Copilot AI balanced review requested due to automatic review settings October 16, 2026 18:59

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

It introduces a new UI dependency and menu-widget behavior relying on non-obvious runtime workarounds (float-overflow margin, responsive sizing) and affects the plugin build, none of which can be statically verified here.

0 open findings

What changed in this PR

This PR replaces the NAM stage's flat pick_list model picker with a nested, folder-grouped menu so model packs can ship as directory trees instead of loose files. The core loader now walks the nam folder recursively and keys each model by its folder-relative path, while the shared UI builds an iced_aw menu bar whose folders fan out into submenus. This fits the existing standalone + plugin architecture, where both drive the same rustortion-ui GUI.

Changes:

  • Loader walks the nam directory recursively, keying models by /-separated relative path (extension dropped), keeping top-level stems bare for backward-compatible preset resolution, and skipping hidden/symlinked directories.
  • UI replaces pick_list with a one-root iced_aw MenuBar, grouping keys into a sorted ModelNode tree with selection highlighting and pick-list-like open/close behavior.
  • Adds the iced_aw = 0.14.1 dependency (menu feature only) with corresponding Cargo.lock updates.
File Description
rustortion-core/​src/​nam/​loader.rs Recursive directory scan with folder-relative keys, symlink/hidden-folder guards, model_key helper, and new tests.
rustortion-ui/​src/​stages/​nam.rs Replaces pick list with a nested iced_aw menu bar, adds ModelNode tree building/sorting and menu rendering helpers plus tests.
rustortion-ui/​Cargo.toml Adds iced_aw = 0.14.1 with only the menu feature.
Cargo.lock Records iced_aw, iced_fonts, iced_fonts_macros and the new dependency edge.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@OpenSauce
OpenSauce merged commit 313eaef into main Oct 16, 2026
11 checks passed
@OpenSauce
OpenSauce deleted the feat/nam-folder-menu branch October 16, 2026 19:38
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.

2 participants