fix(layers): close locked-layer gaps found in review

- Double-clicking a locked object no longer opens its text / attribute /
  in-place block editor.
- Clicking a locked object during a command's object-gather no longer
  counts as completing the selection (don't set selection_just_completed
  on the locked path).
- copy_entities skips locked entities.
- The attribute editor's Apply refuses to write when the block's layer was
  locked while the dialog was open.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
Hakan SevenandClaude Opus 4.8 committed 2026-07-01 13:14:33 +03:00
1 parent 56e1c03ac2
commit 2723e4d47f
3 files changed
+35 -12

No files matched your search

+8
View File
@@ -1286,6 +1286,14 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
let Some(handle) = self.attr_editor_handle else {
return Task::none();
};
// The block's layer may have been locked while the editor was open —
// refuse to write attributes to a locked-layer block.
if let Some(layer) = self.tabs[i].scene.locked_layer_name(handle) {
self.command_line.push_info(&format!(
"Object is on locked layer \"{layer}\" — unlock the layer to edit its attributes."
));
return Task::none();
}
// Snapshot the working copy so the document can be mutated while the
// dialog's rows stay put (it remains open for further edits).
let rows = self.attr_editor_rows.clone();
+25 -12
View File
@@ -2286,26 +2286,31 @@ pub(super) fn on_tick(&mut self, t: Instant) -> Task<Message> {
let hit =
hit.filter(|&h| self.tabs[i].scene.passes_selection_filter(h));
if let Some(handle) = hit {
// Individual picks accumulate (issue #47):
// each plain click adds to the selection,
// Shift+click removes the picked entity.
// Esc / empty-space click clears.
if let Some(layer) =
self.tabs[i].scene.locked_layer_name(handle)
{
// Locked layer: visible + snappable, but
// not selectable. Tell the user why.
// Locked layer: visible + snappable but
// not selectable. Report and do nothing
// else — in particular do NOT set
// `selection_just_completed`, or a
// gather command (MOVE's "select
// objects") would wrongly finish.
self.command_line.push_info(&format!(
"Object is on locked layer \"{layer}\" — unlock the layer to select or edit it."
));
} else if self.shift_down {
self.tabs[i].scene.deselect_entity(handle);
} else {
self.tabs[i].scene.select_entity(handle, false);
self.tabs[i].scene.expand_selection_for_groups(&[handle]);
// Individual picks accumulate (issue #47):
// each plain click adds to the selection,
// Shift+click removes the picked entity.
if self.shift_down {
self.tabs[i].scene.deselect_entity(handle);
} else {
self.tabs[i].scene.select_entity(handle, false);
self.tabs[i].scene.expand_selection_for_groups(&[handle]);
}
self.refresh_properties();
selection_just_completed = true;
}
self.refresh_properties();
selection_just_completed = true;
} else {
// Empty-space click only ARMS a box here; it
// no longer clears the selection, so a box can
@@ -2438,6 +2443,14 @@ pub(super) fn on_tick(&mut self, t: Instant) -> Task<Message> {
.and_then(|s| Scene::handle_from_wire_name(s))
.or_else(|| self.tabs[i].scene.solid_click_hit(p, view_rot, eye, bounds));
if let Some(handle) = hit {
// Locked layer: double-click must not open any editor
// (text / attribute / in-place block edit).
if let Some(layer) = self.tabs[i].scene.locked_layer_name(handle) {
self.command_line.push_info(&format!(
"Object is on locked layer \"{layer}\" — unlock the layer to edit it."
));
return Task::none();
}
// Any text-bearing entity opens its in-place editor
// (plain box or rich MText editor, per type). A
// Leader resolves to the entity it annotates.
+2
View File
@@ -209,8 +209,10 @@ impl Scene {
}
pub fn copy_entities(&mut self, handles: &[Handle], t: &EntityTransform) -> Vec<Handle> {
// Objects on a locked layer can't be copied (they can't be selected).
let clones: Vec<EntityType> = handles
.iter()
.filter(|&&h| !self.is_layer_locked(h))
.filter_map(|&h| self.document.get_entity(h).cloned())
.collect();
let mut new_handles = Vec::with_capacity(clones.len());