#456: a new bin asks for its name
Problem: every New Bin entry (Cmd+B, File > New > Bin, the Project panel menu, the footer button and the context menus) ran `file.newBin` with the fixed name "New Bin", so each bin had to be renamed by hand afterwards. Fix: `file.newBin` without a `name` from the UI makes the bin in the shown bin (or the given parent), selects it and opens its inline rename field; agents that pass `name` still name it directly. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
3ad5a59321
commit
ddb3890e68
|
|
@ -482,6 +482,15 @@ pub fn invoke(app: &mut FilmcraftApp, ctx: &egui::Context, id: &str, mut params:
|
|||
crate::panels::color_dialogs::open_sequence(app);
|
||||
return Ok(json!({"dialog": "sequenceColor"}));
|
||||
}
|
||||
// New Bin from menus, shortcuts and the Project panel asks for the name (inline rename);
|
||||
// agents pass `name` to name the bin directly
|
||||
"file.newBin" if params.get("name").is_none() => {
|
||||
let r = crate::panels::project::new_bin(app, ¶ms);
|
||||
if let Err(e) = &r {
|
||||
app.ui.status = e.clone();
|
||||
}
|
||||
return r;
|
||||
}
|
||||
// From menus/shortcuts (no params) these ask first; agents pass params to act directly.
|
||||
"file.revert" if params.as_object().is_none_or(|m| m.is_empty()) && app.session.is_dirty() => {
|
||||
if app.session.path.is_none() {
|
||||
|
|
|
|||
|
|
@ -607,7 +607,7 @@ fn footer(app: &mut FilmcraftApp, ui: &mut egui::Ui, bar: Rect, v: &View, action
|
|||
"find" => actions.push(("edit.find".into(), json!({}))),
|
||||
"file.newBin" => {
|
||||
let parent = (v.bin != app.session.project.root.id).then_some(v.bin.0);
|
||||
actions.push(("file.newBin".into(), json!({"name": "New Bin", "parent": parent})));
|
||||
actions.push(("file.newBin".into(), json!({"parent": parent, "panel": pre})));
|
||||
}
|
||||
"project.delete" if app.session.state.project_selection.is_empty() => app.ui.status = tl!("Select items to clear").into(),
|
||||
_ => actions.push((id.into(), json!({}))),
|
||||
|
|
@ -700,7 +700,7 @@ pub fn panel_menu(app: &mut FilmcraftApp, ui: &mut egui::Ui) -> bool {
|
|||
ui.separator();
|
||||
if item(ui, "newBin", tl!("New Bin"), true, s_bin.as_deref()) {
|
||||
let parent = (v.bin != app.session.project.root.id).then_some(v.bin.0);
|
||||
actions.push(("file.newBin".into(), json!({"name": "New Bin", "parent": parent})));
|
||||
actions.push(("file.newBin".into(), json!({"parent": parent})));
|
||||
}
|
||||
if item(ui, "newBinFromSelection", tl!("New Bin From Selection"), !app.session.state.project_selection.is_empty(), Some("Shift+B")) {
|
||||
actions.push(("file.newBinFromSelection".into(), json!({})));
|
||||
|
|
@ -939,6 +939,32 @@ fn start_rename(app: &mut FilmcraftApp, params: &Value) -> Result<Value, String>
|
|||
Ok(json!({"item": item, "bin": bin}))
|
||||
}
|
||||
|
||||
/// New Bin from a menu, a shortcut or the panel's buttons (no `name`): make a "New Bin" in `parent`
|
||||
/// (left out: the bin the Project panel shows; null: the project's root) and start renaming it, so
|
||||
/// its name can be typed right away (#456). `panel` names the panel instance that edits the name.
|
||||
/// Agents pass `name` to `file.newBin` to name the bin directly.
|
||||
pub fn new_bin(app: &mut FilmcraftApp, params: &Value) -> Result<Value, String> {
|
||||
let shown = view_of(app, shown_inst(app));
|
||||
let parent = match params.get("parent") {
|
||||
None => (shown.bin != app.session.project.root.id).then_some(shown.bin.0),
|
||||
Some(Value::Null) => None,
|
||||
Some(p) => Some(p.as_u64().ok_or("`parent` must be a bin id")?),
|
||||
};
|
||||
let r = app.session.execute("file.newBin", json!({"name": tl!("New Bin"), "parent": parent})).map_err(|e| e.to_string())?;
|
||||
let bin = r.get("bin").and_then(Value::as_u64).ok_or("the new bin has no id")?;
|
||||
let text = app.session.project.root.find_bin(BinId(bin)).map(|b| b.name.clone()).ok_or("no such bin")?;
|
||||
// a bin made inside a collapsed bin of the list opens it, so the name field is visible
|
||||
if let Some(p) = parent
|
||||
&& !app.ui.expanded_bins.contains(&p)
|
||||
{
|
||||
app.ui.expanded_bins.push(p);
|
||||
}
|
||||
let panel = params.get("panel").and_then(Value::as_str).map_or(shown.prefix, str::to_string);
|
||||
app.ui.project_panel.selected_bin = Some(bin);
|
||||
app.ui.project_panel.rename = Some(Rename { item: None, bin: Some(bin), text, panel });
|
||||
Ok(r)
|
||||
}
|
||||
|
||||
/// Commit the inline rename (Enter / focus lost).
|
||||
pub fn commit_rename(app: &mut FilmcraftApp) {
|
||||
let Some(r) = app.ui.project_panel.rename.take() else { return };
|
||||
|
|
|
|||
|
|
@ -311,7 +311,7 @@ fn bin_menu(app: &mut FilmcraftApp, ui: &mut egui::Ui, v: &View, bin: u64, actio
|
|||
ui.close();
|
||||
}
|
||||
if ui.button(tl!("New Bin")).clicked() {
|
||||
actions.push(("file.newBin".into(), json!({"name": "New Bin", "parent": bin})));
|
||||
actions.push(("file.newBin".into(), json!({"parent": bin, "panel": v.prefix})));
|
||||
ui.close();
|
||||
}
|
||||
}
|
||||
|
|
@ -517,7 +517,7 @@ fn background_menu(app: &mut FilmcraftApp, ui: &mut egui::Ui, v: &View, bin: Opt
|
|||
(tl!("Import…"), "file.import"),
|
||||
] {
|
||||
if ui.button(label).clicked() {
|
||||
let p = if cmd == "file.newBin" { json!({"name": tl!("New Bin"), "parent": bin}) } else { json!({}) };
|
||||
let p = if cmd == "file.newBin" { json!({"parent": bin, "panel": v.prefix}) } else { json!({}) };
|
||||
actions.push((cmd.into(), p));
|
||||
ui.close();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -477,6 +477,26 @@ fn footer_buttons_are_wired() {
|
|||
assert_eq!(d.app().session.prefs.project_panel.view.icon_sort.column, "Name");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn new_bin_asks_for_its_name() {
|
||||
// #456: New Bin opens the name field of the new bin instead of leaving it "New Bin"
|
||||
let mut d = project_driver();
|
||||
d.exec("project.view.set", json!({"view": "list"}));
|
||||
d.click("project.button.file.newBin");
|
||||
d.frames(2);
|
||||
let bin = d.app().ui.project_panel.rename.as_ref().and_then(|r| r.bin).expect("the new bin's name is being edited");
|
||||
assert!(d.has("project.rename"), "the name field is shown");
|
||||
d.key("Cmd+A");
|
||||
d.ok("ui.type", json!({"text": "Interviews"}));
|
||||
d.key("Enter");
|
||||
let name = d.app().session.project.root.find_bin(filmcraft_project::BinId(bin)).unwrap().name.clone();
|
||||
assert_eq!(name, "Interviews");
|
||||
// with a name (agents) the bin is named directly and nothing is edited
|
||||
let r = d.ok("ui.menu.invoke", json!({"id": "file.newBin", "params": {"name": "B-roll"}}));
|
||||
assert!(r["bin"].as_u64().is_some(), "{r}");
|
||||
assert!(d.app().ui.project_panel.rename.is_none());
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------ Media Browser
|
||||
|
||||
fn media_dir(tag: &str) -> std::path::PathBuf {
|
||||
|
|
|
|||
Loading…
Reference in New Issue