Browser: F2 renames a selected group (#10005) (#10013)

* claim: #10005

Signed-off-by: Maurizio Monticelli <maurizio@whatwedo.ch>

* F2 renames a group clicked in the Browser (#10005)

A group has no selection of its own: clicking its Browser row only
records it as the picked folder, which V uses. F2's rename_selection
looked only at the selection, picked components and canvases, so on a
group it did nothing, or renamed a body that was still selected.

F2 now takes a clicked group row first, as V does, and opens the same
Rename box as the group's context-menu Rename, which commits through
browser.rename_group. This works for groups inside components as well.

Fixes #10005

Signed-off-by: Maurizio Monticelli <maurizio@whatwedo.ch>

---------

Signed-off-by: Maurizio Monticelli <maurizio@whatwedo.ch>
This commit is contained in:
rugbymauri
2026-10-31 13:35:26 +00:00
committed by GitHub
parent 3385d1c570
commit a476e645b0
3 changed files with 56 additions and 1 deletions
+8
View File
@@ -481,6 +481,14 @@ fn pick_folder(app: &mut SolveApp, key: &str) {
app.tree.picked_folder = Some(FolderPick { key: key.into(), session: app.session.uid, doc: Arc::downgrade(&app.session.doc) });
}
/// The group whose row was clicked last (its key ends in `/g<id>`), while that pick still holds
/// and the group exists: F2 renames it (#10005).
pub(crate) fn picked_group(app: &SolveApp) -> Option<u64> {
let pick = app.tree.picked_folder.as_ref().filter(|pick| pick.current(app))?;
let id = pick.key.rsplit_once("/g")?.1.parse().ok()?;
find_group(app, id).map(|g| g.id)
}
pub(crate) fn toggle_picked_folder(app: &mut SolveApp) -> bool {
let Some(pick) = app.tree.picked_folder.as_ref().filter(|pick| pick.current(app)) else { return false };
let key = pick.key.clone();
+42
View File
@@ -43,6 +43,48 @@ fn clicked_browser_folders_toggle_visibility_with_v() {
}
}
/// #10005: F2 on a group picked in the Browser opens its Rename box, as for other rows, and the
/// typed name renames the group, at the top level and inside a component; a body selected
/// alongside does not take the rename from the clicked group.
#[test]
fn f2_on_a_clicked_browser_group_renames_the_group() {
for inside_component in [false, true] {
let (mut h, component) = if inside_component {
let (h, component, _) = crate::test_support::component_box();
(h, component)
} else {
let mut h = Harness::new();
h.app.run("solid.box", json!({"length":10,"width":10,"height":10,"body_name":"Body1"})).unwrap();
(h, 0)
};
let body = h.app.session.model.state().bodies[0].name.clone();
let group = h.app.run("browser.group", json!({"component":component,"folder":"bodies","items":[body],"name":"Group"})).unwrap()["group"]
.as_u64()
.unwrap();
h.app.preferences.browser_bodies_folders = crate::prefs::BodiesFolders::Always;
h.settle();
let world_body = h.app.session.world_state().bodies[0].name.clone();
h.app.run("select.set", json!({"items":[Sel::Body { name: world_body.clone() }]})).unwrap();
h.step(&json!({"click":{"handle":"row:Group (1)"}})).unwrap();
h.step(&json!({"key":"F2"})).unwrap();
h.frames(2);
let what = h.app.menu.rename.as_ref().map(|r| (r.what.clone(), r.text.clone()));
assert_eq!(
what,
Some((crate::context_menu::RenameWhat::Group(group), "Group".to_string())),
"component {inside_component}: F2 renames the group"
);
h.step(&json!({"text":"Fasteners"})).unwrap();
h.frames(1);
h.step(&json!({"key":"Enter"})).unwrap();
h.frames(2);
assert!(h.app.menu.rename.is_none());
let names: Vec<&str> = h.app.session.doc.browser_groups.iter().map(|g| g.name.as_str()).collect();
assert_eq!(names, ["Fasteners"], "component {inside_component}: Enter renames the group; status {:?}", h.app.status);
assert!(h.app.session.world_state().body(&world_body).is_some(), "the body keeps its name");
}
}
#[test]
fn folder_visibility_target_clears_when_the_user_moves_on() {
for action in ["body click", "selection command", "empty click", "escape", "design tab", "model edit", "tool"] {
+6 -1
View File
@@ -1878,8 +1878,13 @@ pub fn toggle_visibility(app: &mut SolveApp) {
}
/// Rename what is selected (F2): one body, sketch or feature, construction plane, component
/// picked in the browser, or canvas.
/// picked in the browser, canvas, or a group whose Browser row was clicked.
pub fn rename_selection(app: &mut SolveApp, at: Pos2) -> bool {
// A clicked group row takes precedence, as it does for V: groups have no selection of their own.
if let Some(g) = crate::browser::picked_group(app) {
start_rename(app, RenameWhat::Group(g), at);
return true;
}
let what = match (app.session.selection.as_slice(), app.tree.picked_components.as_slice(), app.tree.picked_canvases.as_slice()) {
([Sel::Body { name }], [], []) => RenameWhat::Body(name.clone()),
([Sel::Feature { id }], [], []) => RenameWhat::Feature(*id),