Skip to content

Commit 0d3c705

Browse files
committed
Batch rename for multiple entities in hierarchy context menu
1 parent 3a3e9d2 commit 0d3c705

4 files changed

Lines changed: 86 additions & 3 deletions

File tree

crates/renzora_hierarchy/src/lib.rs

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use renzora_editor_framework::{
1515
};
1616
use renzora::core::ShapeRegistry;
1717
use renzora_theme::ThemeManager;
18-
use renzora_undo::{self, CompoundCmd, ReparentCmd, SetHierarchyOrderCmd, SpawnEntityCmd, SpawnEntityKind, SpawnShapeCmd, UndoCommand, UndoContext};
18+
use renzora_undo::{self, CompoundCmd, RenameCmd, ReparentCmd, SetHierarchyOrderCmd, SpawnEntityCmd, SpawnEntityKind, SpawnShapeCmd, UndoCommand, UndoContext};
1919

2020
use cache::{HierarchyDirty, HierarchyTreeCache};
2121
use state::{filter_tree, HierarchyState};
@@ -293,6 +293,71 @@ impl EditorPanel for HierarchyPanel {
293293
}
294294
}
295295

296+
// Batch Rename dialog
297+
if state.batch_rename_active {
298+
let count = state.batch_rename_entities.len();
299+
let mut open = true;
300+
egui::Window::new("Batch Rename")
301+
.collapsible(false)
302+
.resizable(false)
303+
.open(&mut open)
304+
.anchor(egui::Align2::CENTER_CENTER, [0.0, 0.0])
305+
.show(ui.ctx(), |ui| {
306+
ui.horizontal(|ui| {
307+
ui.label("Base name:");
308+
ui.text_edit_singleline(&mut state.batch_rename_base);
309+
});
310+
ui.horizontal(|ui| {
311+
ui.label("Start at:");
312+
ui.add(egui::DragValue::new(&mut state.batch_rename_start).range(0..=9999));
313+
});
314+
ui.add_space(4.0);
315+
ui.label(
316+
egui::RichText::new(format!(
317+
"Preview: {}_{:02}, {}_{:02}, … ({} entities)",
318+
state.batch_rename_base,
319+
state.batch_rename_start,
320+
state.batch_rename_base,
321+
state.batch_rename_start + 1,
322+
count,
323+
))
324+
.size(11.0)
325+
.color(theme.text.muted.to_color32()),
326+
);
327+
ui.add_space(4.0);
328+
ui.horizontal(|ui| {
329+
if ui.button("Rename").clicked() && !state.batch_rename_base.is_empty() {
330+
let entities = state.batch_rename_entities.clone();
331+
let base = state.batch_rename_base.clone();
332+
let start = state.batch_rename_start;
333+
commands.push(move |world: &mut World| {
334+
let mut cmds: Vec<Box<dyn UndoCommand>> = Vec::new();
335+
for (i, entity) in entities.iter().enumerate() {
336+
let old = world
337+
.get::<Name>(*entity)
338+
.map(|n| n.as_str().to_string())
339+
.unwrap_or_default();
340+
let new = format!("{}_{:02}", base, start as usize + i);
341+
cmds.push(Box::new(RenameCmd { entity: *entity, old, new }));
342+
}
343+
renzora_undo::execute(
344+
world,
345+
UndoContext::Scene,
346+
Box::new(CompoundCmd { label: "Batch Rename".to_string(), cmds }),
347+
);
348+
});
349+
state.batch_rename_active = false;
350+
}
351+
if ui.button("Cancel").clicked() {
352+
state.batch_rename_active = false;
353+
}
354+
});
355+
});
356+
if !open {
357+
state.batch_rename_active = false;
358+
}
359+
}
360+
296361
// Read the cached entity tree. Rebuilt by `update_hierarchy_cache`
297362
// (Update schedule) only when the tree actually changed. When no
298363
// search is active we read directly from the cache (no clone);

crates/renzora_hierarchy/src/state.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@ pub struct HierarchyState {
3232
/// (otherwise clicking a mesh in the viewport selects a parent that's
3333
/// collapsed in the tree, and the user sees nothing).
3434
pub last_selection: Vec<Entity>,
35+
36+
// Batch rename
37+
pub batch_rename_active: bool,
38+
pub batch_rename_base: String,
39+
pub batch_rename_start: u32,
40+
pub batch_rename_entities: Vec<Entity>,
3541
}
3642

3743
impl Default for HierarchyState {
@@ -49,6 +55,10 @@ impl Default for HierarchyState {
4955
visible_entity_order: Vec::new(),
5056
building_entity_order: Vec::new(),
5157
last_selection: Vec::new(),
58+
batch_rename_active: false,
59+
batch_rename_base: String::new(),
60+
batch_rename_start: 1,
61+
batch_rename_entities: Vec::new(),
5262
}
5363
}
5464
}

crates/renzora_hierarchy/src/tree.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -511,7 +511,7 @@ fn context_menu(
511511
ui.close();
512512
}
513513

514-
// Group as Children (multi-selection)
514+
// Multi-selection actions
515515
if selection.has_multi_selection() {
516516
if ui.button(format!("{} Group as Children", regular::FOLDER_SIMPLE)).clicked() {
517517
let selected = selection.get_all();
@@ -527,6 +527,14 @@ fn context_menu(
527527
});
528528
ui.close();
529529
}
530+
531+
if ui.button(format!("{} Batch Rename…", regular::TEXT_AA)).clicked() {
532+
state.batch_rename_active = true;
533+
state.batch_rename_base = node.name.clone();
534+
state.batch_rename_start = 1;
535+
state.batch_rename_entities = selection.get_all();
536+
ui.close();
537+
}
530538
}
531539

532540
ui.separator();

roadmap.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
## Inspector — Views & Filtering
2626
- Add lock inspector to entity (stop following selection)
2727
- Add multi-entity comparison view
28-
- Add component search/filter
28+
- Add component search/filter[3a3e9d2](https://github.com/renzora/engine/commit/3a3e9d2)
2929
- Add component presets/templates
3030

3131
## Asset Browser — Organization

0 commit comments

Comments
 (0)