control: ui.drop drops files on the window

The Open dialog is a native picker the control channel cannot click, so
nothing could walk a person's open path end to end: ui.start file.open
opens the command's JSON form instead. ui.drop {paths} hands the paths
to the next frame with the window system's drops, which open them
through the same route a picked file takes (open_path: by type, in the
background, the unsaved-changes prompt, the recent list). At most 16
paths of at most 4096 bytes each.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm
This commit is contained in:
jyvikoandClaude Opus 5.5 authored and Irakli Kourtis committed 2026-10-14 08:46:50 -04:00
1 parent cf72503f76
commit 8a4209a20c
4 files changed
+50 -2

No files matched your search

+4 -2
View File
@@ -540,10 +540,12 @@ impl ModelApp {
true
}
/// Files dropped on the window open in turn; a hovered drop shows where it goes.
/// Files dropped on the window (and by the control channel's `ui.drop`) open in turn; a
/// hovered drop shows where it goes.
pub(crate) fn dropped_files(&mut self, ctx: &egui::Context) {
let dropped: Vec<String> = ctx
let mut dropped: Vec<String> = ctx
.input(|i| i.raw.dropped_files.iter().filter_map(|f| Some(f.path().to_string_lossy().to_string()).filter(|p| !p.is_empty())).collect());
dropped.append(&mut self.synthetic_drops);
// A model first: it replaces the session, then designs and meshes go into it.
let (models, rest): (Vec<String>, Vec<String>) = dropped.into_iter().partition(|p| Kind::of(p) == Some(Kind::Model));
for p in models.into_iter().take(1).chain(rest) {