forked from 1b-agent/opencadstudio-upstream
feat(block): BEDIT block editor as a dedicated space tab (#261)
Selecting a block and running BEDIT (command, ribbon button, or a double-click on the block) opens a block-editor "space" tab, named after the block, alongside Model/Layout in the status bar. The tab draws ONLY the block record's own entities in block-local coordinates; edits are live on the definition, so every INSERT updates. Save Block / Discard buttons (side toolbar) finish the session; Discard restores the on-entry snapshot. Space switching is locked while a block is open, and BEDIT and REFEDIT are mutually exclusive. Implementation: a Scene.block_edit_block override at the top of current_layout_block_handle scopes render/pick/new-entity ownership to the edited block while current_layout stays "Model" (so the pervasive Model-vs-paper code keeps model behaviour). The model render/pick paths that hardcoded model_space_block_handle (wire tile set, hatch render + pick, block-instance meshes) are made binding-aware so the block isolation actually takes effect and model content does not leak in. Entering fits the camera to the block (fit_all already scopes via the binding). Renaming the block tab renames the block itself — new Scene::rename_block re-keys the record, updates the Block marker and repoints every INSERT reference. Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
1 parent
a4fc34c6a2
commit
3548de332c
8 files changed
+435
-18
No files matched your search
@@ -0,0 +1,99 @@
|
||||
// BEDIT — block editor as a dedicated "space" tab (issue #261).
|
||||
//
|
||||
// Workflow:
|
||||
// 1. BEDIT: user picks an INSERT (or has one pre-selected).
|
||||
// 2. A block-editor space opens: rendering, picking and new geometry are
|
||||
// scoped to the block's record, so ONLY the block's own (block-local)
|
||||
// entities are drawn — no INSERT transform, they show exactly as stored.
|
||||
// 3. The user edits them with normal commands. Because they ARE the block
|
||||
// definition's entities, edits are live.
|
||||
// 4. Save Block (BEDIT_SAVE): keep the edits and leave the block space.
|
||||
// Discard (BEDIT_DISCARD): restore the block to its on-entry snapshot.
|
||||
//
|
||||
// Unlike REFEDIT (which copies entities into model space with the INSERT
|
||||
// transform and inverse-transforms them back on save), a BEDIT space edits the
|
||||
// block record in place, so there is no copy-back and no transform — the space
|
||||
// render filter (`current_layout_block_handle`) already draws only the block.
|
||||
|
||||
use acadrust::{EntityType, Handle};
|
||||
use glam::DVec3;
|
||||
|
||||
use crate::command::{CadCommand, CmdResult};
|
||||
use crate::modules::{IconKind, ModuleEvent, ToolDef};
|
||||
|
||||
/// Right-edge side-toolbar buttons shown while a BEDIT block-editor space is
|
||||
/// active: save the block edits and leave, or discard them.
|
||||
pub fn block_edit_tools() -> Vec<ToolDef> {
|
||||
vec![
|
||||
ToolDef {
|
||||
id: "BEDIT_SAVE",
|
||||
label: "Save Block",
|
||||
icon: IconKind::Svg(include_bytes!("../../../../assets/icons/mt_ok.svg")),
|
||||
event: ModuleEvent::Command("BEDIT_SAVE".to_string()),
|
||||
},
|
||||
ToolDef {
|
||||
id: "BEDIT_DISCARD",
|
||||
label: "Discard Block Edit",
|
||||
icon: IconKind::Svg(include_bytes!("../../../../assets/icons/mt_cancel.svg")),
|
||||
event: ModuleEvent::Command("BEDIT_DISCARD".to_string()),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
// ── Session state (held in DocumentTab) ───────────────────────────────────
|
||||
|
||||
/// Active BEDIT block-editor session. Lives in `DocumentTab::block_edit`.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct BlockEditSession {
|
||||
/// Name of the block being edited (also the space-tab label).
|
||||
pub block_name: String,
|
||||
/// Handle of the block record whose entities are being edited.
|
||||
pub br_handle: Handle,
|
||||
/// Space to return to when the block editor closes (the layout that was
|
||||
/// active when BEDIT began).
|
||||
pub return_layout: String,
|
||||
/// The block's block-local entities captured on entry, so Discard can
|
||||
/// restore the definition (structural Block/BlockEnd/AttDef excluded).
|
||||
pub snapshot: Vec<EntityType>,
|
||||
}
|
||||
|
||||
// ── BEDIT pick command ─────────────────────────────────────────────────────
|
||||
|
||||
/// Step 1: wait for the user to pick a single INSERT entity to edit.
|
||||
pub struct BlockEditPickCommand;
|
||||
|
||||
impl BlockEditPickCommand {
|
||||
pub fn new() -> Self {
|
||||
Self
|
||||
}
|
||||
}
|
||||
|
||||
impl CadCommand for BlockEditPickCommand {
|
||||
fn name(&self) -> &'static str {
|
||||
"BEDIT"
|
||||
}
|
||||
fn prompt(&self) -> String {
|
||||
"BEDIT Select block reference to edit:".into()
|
||||
}
|
||||
fn needs_entity_pick(&self) -> bool {
|
||||
true
|
||||
}
|
||||
fn on_entity_pick(&mut self, handle: Handle, _pt: DVec3) -> CmdResult {
|
||||
if handle.is_null() {
|
||||
return CmdResult::NeedPoint;
|
||||
}
|
||||
// Signal the host to open the block-editor space for this INSERT.
|
||||
CmdResult::Relaunch(format!("BEDIT_BEGIN:{}", handle.value()), vec![handle])
|
||||
}
|
||||
fn on_point(&mut self, _pt: DVec3) -> CmdResult {
|
||||
CmdResult::NeedPoint
|
||||
}
|
||||
fn on_enter(&mut self) -> CmdResult {
|
||||
CmdResult::Cancel
|
||||
}
|
||||
}
|
||||
|
||||
// ── Autocomplete registry ─────────────────────────────────
|
||||
inventory::submit!(crate::command::CommandRegistration { names: &["BEDIT"] }); // BlockEditPickCommand
|
||||
inventory::submit!(crate::command::CommandRegistration { names: &["BEDIT_SAVE"] });
|
||||
inventory::submit!(crate::command::CommandRegistration { names: &["BEDIT_DISCARD"] });
|
||||
@@ -11,6 +11,7 @@ pub mod lengthen;
|
||||
pub mod mirror;
|
||||
pub mod offset;
|
||||
pub mod pedit;
|
||||
pub mod block_edit;
|
||||
pub mod refedit;
|
||||
pub mod reverse;
|
||||
pub mod rotate;
|
||||
|
||||
Reference in new issue
Block a user