forked from 1b-agent/opencadstudio-upstream
Merge pull request #1805 from ramox81/codex/block-dialog-additions
Block Definition dialog: preview, empty-block band, open in block editor
This commit is contained in:
commit
cf6c50f2c0
30 files changed
+357
-13
No files matched your search
@@ -810,6 +810,14 @@ impl OpenCADStudio {
|
||||
self.refresh_properties();
|
||||
self.note_recent_block(&name);
|
||||
self.refresh_block_palette();
|
||||
// The Block Definition dialog asked to edit the new block.
|
||||
if self
|
||||
.block_definition_open_editor
|
||||
.take()
|
||||
.is_some_and(|wanted| wanted.eq_ignore_ascii_case(&name))
|
||||
{
|
||||
return Some(self.dispatch_command(&format!("BEDIT_OPEN:{name}")));
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
self.discard_last_undo_entry(i);
|
||||
|
||||
@@ -61,7 +61,11 @@ impl OpenCADStudio {
|
||||
remembered.objects_on_screen = state.objects_specify_onscreen;
|
||||
remembered.mode = state.object_mode;
|
||||
remembered.allow_exploding = state.allow_exploding;
|
||||
remembered.open_in_editor = state.open_in_editor;
|
||||
}
|
||||
self.block_definition_open_editor = state
|
||||
.open_in_editor
|
||||
.then(|| state.name.trim().to_string());
|
||||
self.persist_settings_if_changed();
|
||||
let i = self.active_tab;
|
||||
let base_point = state.parse_base_point();
|
||||
@@ -122,6 +126,59 @@ impl OpenCADStudio {
|
||||
)
|
||||
}
|
||||
|
||||
/// Draw the selected objects, or else the existing definition the name
|
||||
/// picks, in the Block Definition dialog's name card.
|
||||
pub(in crate::app) fn refresh_block_definition_preview(&mut self) {
|
||||
let scene = &self.tabs[self.active_tab].scene;
|
||||
let Some(state) = self.block_definition.as_mut() else {
|
||||
return;
|
||||
};
|
||||
state.preview = if state.selected_handles.is_empty() {
|
||||
let name = state.name.trim();
|
||||
state
|
||||
.existing_names
|
||||
.iter()
|
||||
.find(|existing| existing.eq_ignore_ascii_case(name))
|
||||
.map(|existing| scene.block_preview_wires(existing))
|
||||
.unwrap_or_default()
|
||||
} else {
|
||||
state.empty_prompt = false;
|
||||
let mut wires = Vec::new();
|
||||
for handle in &state.selected_handles {
|
||||
match scene.document.get_entity(*handle) {
|
||||
// A reference is drawn from its definition, placed by the
|
||||
// reference's transform.
|
||||
Some(codec::EntityType::Insert(insert)) => {
|
||||
let base = crate::scene::render_graph::block_base_point(
|
||||
&scene.document,
|
||||
&insert.block_name,
|
||||
);
|
||||
let xform =
|
||||
crate::scene::render_graph::insert_transform_with_base(insert, base);
|
||||
for mut wire in scene.block_preview_wires(&insert.block_name) {
|
||||
for p in &mut wire.points {
|
||||
if p.iter().all(|v| v.is_finite()) {
|
||||
let q = xform.apply(codec::types::Vector3::new(
|
||||
f64::from(p[0]),
|
||||
f64::from(p[1]),
|
||||
f64::from(p[2]),
|
||||
));
|
||||
*p = [q.x as f32, q.y as f32, q.z as f32];
|
||||
}
|
||||
}
|
||||
wires.push(wire);
|
||||
}
|
||||
}
|
||||
Some(entity) => {
|
||||
wires.extend(scene.wires_for_entities(std::slice::from_ref(entity)))
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
wires
|
||||
};
|
||||
}
|
||||
|
||||
pub(super) fn dispatch_blocks(&mut self, cmd: &str, i: usize) -> Option<Task<Message>> {
|
||||
match cmd {
|
||||
// ── BASE — drawing insertion base point ───────────────────────
|
||||
@@ -469,6 +526,7 @@ impl OpenCADStudio {
|
||||
),
|
||||
);
|
||||
self.active_modal = Some(crate::app::ModalKind::BlockDefinition);
|
||||
self.refresh_block_definition_preview();
|
||||
}
|
||||
|
||||
cmd if cmd.starts_with("BLOCK_POINT_PICKED ") => {
|
||||
@@ -504,6 +562,7 @@ impl OpenCADStudio {
|
||||
}
|
||||
self.tabs[i].active_cmd = None;
|
||||
self.active_modal = Some(crate::app::ModalKind::BlockDefinition);
|
||||
self.refresh_block_definition_preview();
|
||||
}
|
||||
|
||||
cmd if cmd.starts_with("WBLOCK_POINT_PICKED ") => {
|
||||
|
||||
@@ -120,6 +120,7 @@ pub(super) const NAMES: &[&str] = &[
|
||||
"ribbon_dropdown",
|
||||
"keytips",
|
||||
"dialog_ok",
|
||||
"block_def_dialog",
|
||||
"attdef_dialog",
|
||||
"field_dialog",
|
||||
"sheet_set",
|
||||
@@ -1504,6 +1505,26 @@ impl OpenCADStudio {
|
||||
}
|
||||
return Ok(Task::none());
|
||||
}
|
||||
// The open Block Definition dialog: `name=…`, `open_in_editor=0|1`,
|
||||
// `base_on_screen=0|1`, `objects_on_screen=0|1`, `create_empty`,
|
||||
// `select_objects`.
|
||||
"block_def_dialog" => {
|
||||
if self.block_definition.is_none() {
|
||||
return Err(failure("no_dialog", "The Block Definition dialog is not open"));
|
||||
}
|
||||
let value = string(req, "value")?;
|
||||
let (key, v) = value.split_once('=').unwrap_or((value, ""));
|
||||
let on = v == "1";
|
||||
match key {
|
||||
"name" => Message::BlockDefNameSelect(v.to_string()),
|
||||
"open_in_editor" => Message::BlockDefOpenInEditor(on),
|
||||
"base_on_screen" => Message::BlockDefBaseOnScreen(on),
|
||||
"objects_on_screen" => Message::BlockDefObjectsOnScreen(on),
|
||||
"create_empty" => Message::BlockDefCreateEmpty,
|
||||
"select_objects" => Message::BlockDefSelectObjects,
|
||||
_ => return Err(failure("invalid_value", "Unknown block definition field")),
|
||||
}
|
||||
}
|
||||
// One field of the open attribute definition dialog: `tag=…`,
|
||||
// `prompt=…`, `default=…`, `justify=MC`, `style=…`, `height=…`,
|
||||
// `rotation=…`, `width=…`, `on_screen=0|1`, `x=…` / `y=…` / `z=…`,
|
||||
|
||||
@@ -581,6 +581,9 @@ pub(super) struct OpenCADStudio {
|
||||
drawing_units: Option<crate::ui::window::drawing_units::State>,
|
||||
/// Working copy of the Block Definition dialog; `None` while it is closed.
|
||||
block_definition: Option<crate::ui::window::block_definition::BlockDefinitionState>,
|
||||
/// The block the Block Definition dialog defines with "Open in block
|
||||
/// editor" on; it opens once the definition is committed.
|
||||
block_definition_open_editor: Option<String>,
|
||||
block_edit_picker: Option<crate::ui::window::block_edit_picker::State>,
|
||||
block_save_as: Option<crate::ui::window::block_save_as::State>,
|
||||
/// PDF dialogs' working copies; `None` while closed.
|
||||
@@ -3463,6 +3466,10 @@ pub enum Message {
|
||||
BlockDefConfirmRedefine(bool),
|
||||
BlockDefDismissError,
|
||||
BlockDefHelp,
|
||||
/// Block Definition: open the new block in the block editor.
|
||||
BlockDefOpenInEditor(bool),
|
||||
/// Block Definition: define the block with no objects.
|
||||
BlockDefCreateEmpty,
|
||||
/// Write Block (WBLOCK) dialog messages
|
||||
WblockSourceMode(crate::ui::window::wblock::WblockSourceMode),
|
||||
WblockBlockName(String),
|
||||
@@ -4625,6 +4632,7 @@ impl OpenCADStudio {
|
||||
layer_translator: None,
|
||||
drawing_units: None,
|
||||
block_definition: None,
|
||||
block_definition_open_editor: None,
|
||||
block_edit_picker: None,
|
||||
block_save_as: None,
|
||||
pdf_attach: None,
|
||||
|
||||
+19
-8
@@ -5750,6 +5750,7 @@ impl OpenCADStudio {
|
||||
state.error_message = None;
|
||||
state.confirm_redefine = None;
|
||||
}
|
||||
self.refresh_block_definition_preview();
|
||||
Task::none()
|
||||
}
|
||||
Message::BlockDefNameSelect(chosen) => {
|
||||
@@ -5765,6 +5766,7 @@ impl OpenCADStudio {
|
||||
);
|
||||
state.set_base_point(glam::DVec3::new(base.x, base.y, base.z));
|
||||
}
|
||||
self.refresh_block_definition_preview();
|
||||
Task::none()
|
||||
}
|
||||
Message::BlockDefBaseOnScreen(val) => {
|
||||
@@ -5886,6 +5888,12 @@ impl OpenCADStudio {
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
Message::BlockDefOpenInEditor(on) => {
|
||||
if let Some(state) = self.block_definition.as_mut() {
|
||||
state.open_in_editor = on;
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
Message::BlockDefHelp => {
|
||||
self.command_line.push_info(
|
||||
crate::t!("BLOCK creates a block definition from objects you select.").as_ref(),
|
||||
@@ -5901,7 +5909,8 @@ impl OpenCADStudio {
|
||||
}
|
||||
self.commit_block_definition(true)
|
||||
}
|
||||
Message::BlockDefApply => {
|
||||
m @ (Message::BlockDefApply | Message::BlockDefCreateEmpty) => {
|
||||
let create_empty = matches!(m, Message::BlockDefCreateEmpty);
|
||||
let Some(state) = self.block_definition.as_mut() else {
|
||||
return Task::none();
|
||||
};
|
||||
@@ -5924,15 +5933,16 @@ impl OpenCADStudio {
|
||||
Some(crate::t!("Block name cannot start with '*'.").into_owned());
|
||||
return Task::none();
|
||||
}
|
||||
if !state.objects_specify_onscreen && state.selected_handles.is_empty() {
|
||||
state.error_message = Some(
|
||||
crate::t!(
|
||||
"No objects selected. You must select objects to define a block."
|
||||
)
|
||||
.into_owned(),
|
||||
);
|
||||
// No objects: the band offers to select some or to define
|
||||
// an empty block.
|
||||
if !state.objects_specify_onscreen
|
||||
&& state.selected_handles.is_empty()
|
||||
&& !create_empty
|
||||
{
|
||||
state.empty_prompt = true;
|
||||
return Task::none();
|
||||
}
|
||||
state.empty_prompt = false;
|
||||
let i = self.active_tab;
|
||||
if self.tabs[i]
|
||||
.scene
|
||||
@@ -7459,6 +7469,7 @@ impl OpenCADStudio {
|
||||
.collect();
|
||||
block_def.error_message = None;
|
||||
self.active_modal = Some(super::ModalKind::BlockDefinition);
|
||||
self.refresh_block_definition_preview();
|
||||
} else if let Some(ref mut wblock) = self.wblock {
|
||||
wblock.selected_handles = self.tabs[i]
|
||||
.scene
|
||||
|
||||
@@ -506,7 +506,7 @@ impl OpenCADStudio {
|
||||
}
|
||||
super::super::ModalKind::BlockDefinition => {
|
||||
let state = self.block_definition.as_ref()?;
|
||||
sized_flow(ex, 580, 390, |flow| {
|
||||
sized_flow(ex, 600, 560, |flow| {
|
||||
crate::ui::window::block_definition::view_window(state, flow)
|
||||
})
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user