forked from 1b-agent/opencadstudio-upstream
Merge pull request #1777 from ramox81/codex/refedit-dialog
REFEDIT: Reference Edit dialog and unique names for xref objects # Conflicts: # locales/ar-SA/opencadstudio.ftl # locales/bg-BG/opencadstudio.ftl # locales/cs-CZ/opencadstudio.ftl # locales/de-DE/opencadstudio.ftl # locales/el-GR/opencadstudio.ftl # locales/en-US/opencadstudio.ftl # locales/es-ES/opencadstudio.ftl # locales/fi-FI/opencadstudio.ftl # locales/fr-FR/opencadstudio.ftl # locales/hi-IN/opencadstudio.ftl # locales/hu-HU/opencadstudio.ftl # locales/it-IT/opencadstudio.ftl # locales/ja-JP/opencadstudio.ftl # locales/ko-KR/opencadstudio.ftl # locales/lo-LA/opencadstudio.ftl # locales/nl-NL/opencadstudio.ftl # locales/pl-PL/opencadstudio.ftl # locales/pt-BR/opencadstudio.ftl # locales/ru-RU/opencadstudio.ftl # locales/tr-TR/opencadstudio.ftl # locales/zh-CN/opencadstudio.ftl # locales/zh-TW/opencadstudio.ftl # src/app/control/actions.rs # src/app/mod.rs # src/app/view/modal.rs
This commit is contained in:
commit
21f33e933e
34 files changed
+1070
-23
No files matched your search
+338
-18
@@ -4,10 +4,11 @@
|
||||
|
||||
use crate::app::{Message, OpenCADStudio};
|
||||
use crate::modules::draw::modify::refedit::{
|
||||
apply_insert_inverse_transform, apply_insert_transform, level_hits,
|
||||
nesting_chain, RefCloseCommand, RefEditOptionsCommand, RefEditPickCommand, RefEditSession,
|
||||
RefSetCommand, NOT_CHECKED_OUT,
|
||||
apply_insert_inverse_transform, apply_insert_transform, level_hits, nesting_chain,
|
||||
rename_symbols, ChainLevel, RefCloseCommand, RefEditNames, RefEditOptionsCommand,
|
||||
RefEditPickCommand, RefEditSession, RefSetCommand, SymbolKind, NOT_CHECKED_OUT,
|
||||
};
|
||||
use crate::ui::window::refedit_dialog::{RefEditDialogMsg, RefEditDialogState, RefEditLevel};
|
||||
use codec::{EntityType, Handle};
|
||||
use iced::Task;
|
||||
use std::collections::HashSet;
|
||||
@@ -147,25 +148,127 @@ impl OpenCADStudio {
|
||||
.iter()
|
||||
.map(|level| level_hits(&self.tabs[i].scene.document, level))
|
||||
.collect();
|
||||
let command = RefEditOptionsCommand::new(top, chain, hits);
|
||||
let command = RefEditOptionsCommand::new(
|
||||
top,
|
||||
chain,
|
||||
hits,
|
||||
self.refedit_options.lock,
|
||||
self.refedit_options.unique_names,
|
||||
);
|
||||
use crate::command::CadCommand;
|
||||
self.command_line.push_info(&command.prompt());
|
||||
self.tabs[i].active_cmd = Some(Box::new(command));
|
||||
} else {
|
||||
// The dialog's defaults: the innermost reference, all objects,
|
||||
// attribute definitions not displayed.
|
||||
let path: Vec<String> = chain[1..]
|
||||
.iter()
|
||||
.map(|l| l.insert.value().to_string())
|
||||
.collect();
|
||||
let _ = self.dispatch_command(&format!(
|
||||
"REFEDIT_BEGIN:{}:{}:0:",
|
||||
top.value(),
|
||||
path.join(",")
|
||||
));
|
||||
self.open_refedit_dialog(i, top, chain);
|
||||
}
|
||||
}
|
||||
|
||||
/// The Edit Reference dialog over the picked chain: the innermost level
|
||||
/// chosen, the remembered settings.
|
||||
fn open_refedit_dialog(&mut self, i: usize, top: Handle, chain: Vec<ChainLevel>) {
|
||||
let scene = &self.tabs[i].scene;
|
||||
let document = &scene.document;
|
||||
let levels = chain
|
||||
.iter()
|
||||
.map(|level| {
|
||||
let record = document.block_records.get(&level.block_name);
|
||||
RefEditLevel {
|
||||
insert: level.insert,
|
||||
name: level.block_name.clone(),
|
||||
wires: scene.block_preview_wires(&level.block_name),
|
||||
has_attdefs: record.is_some_and(|br| {
|
||||
br.entity_handles.iter().any(|h| {
|
||||
matches!(document.get_entity(*h), Some(EntityType::AttributeDefinition(_)))
|
||||
})
|
||||
}),
|
||||
xref_path: record
|
||||
.filter(|br| br.flags.is_xref || br.flags.is_xref_overlay)
|
||||
.map(|br| br.xref_path.clone())
|
||||
.filter(|p| !p.is_empty()),
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let options = &self.refedit_options;
|
||||
self.refedit_dialog = Some(RefEditDialogState {
|
||||
top,
|
||||
level: levels.len().saturating_sub(1),
|
||||
levels,
|
||||
chain,
|
||||
nested: options.nested,
|
||||
attributes: options.attributes,
|
||||
lock: options.lock,
|
||||
unique: options.unique_names,
|
||||
});
|
||||
self.active_modal = Some(crate::app::ModalKind::RefEdit);
|
||||
}
|
||||
|
||||
pub(in crate::app) fn update_refedit_dialog(&mut self, message: RefEditDialogMsg) -> Task<Message> {
|
||||
let Some(state) = self.refedit_dialog.as_mut() else {
|
||||
return Task::none();
|
||||
};
|
||||
match message {
|
||||
RefEditDialogMsg::Level(level) => {
|
||||
state.level = level.min(state.levels.len().saturating_sub(1))
|
||||
}
|
||||
RefEditDialogMsg::Nested(on) => state.nested = on,
|
||||
RefEditDialogMsg::Attributes(on) => state.attributes = on,
|
||||
RefEditDialogMsg::Lock(on) => state.lock = on,
|
||||
RefEditDialogMsg::Unique(on) => state.unique = on,
|
||||
RefEditDialogMsg::Help => {
|
||||
self.command_line
|
||||
.push_info(&crate::tr!("ref-edit", "dialog-help"));
|
||||
}
|
||||
RefEditDialogMsg::Ok => {
|
||||
let Some(state) = self.refedit_dialog.take() else {
|
||||
return Task::none();
|
||||
};
|
||||
self.close_active_modal();
|
||||
let attributes = state.attributes && state.attributes_enabled();
|
||||
self.refedit_options = crate::app::settings::RefEditOptions {
|
||||
unique_names: state.unique,
|
||||
attributes: state.attributes,
|
||||
lock: state.lock,
|
||||
nested: state.nested,
|
||||
};
|
||||
let i = self.active_tab;
|
||||
if state.nested {
|
||||
let hits = state
|
||||
.chain
|
||||
.iter()
|
||||
.map(|level| level_hits(&self.tabs[i].scene.document, level))
|
||||
.collect();
|
||||
let command = RefEditOptionsCommand::nested_pick(
|
||||
state.top,
|
||||
state.chain,
|
||||
hits,
|
||||
state.level,
|
||||
attributes,
|
||||
state.lock,
|
||||
state.unique,
|
||||
);
|
||||
use crate::command::CadCommand;
|
||||
self.command_line.push_info(&command.prompt());
|
||||
self.tabs[i].active_cmd = Some(Box::new(command));
|
||||
} else {
|
||||
let last = state.level.min(state.chain.len().saturating_sub(1));
|
||||
let path: Vec<String> = state.chain[1..=last]
|
||||
.iter()
|
||||
.map(|l| l.insert.value().to_string())
|
||||
.collect();
|
||||
return self.dispatch_command(&format!(
|
||||
"REFEDIT_BEGIN:{}:{}:{}::{}:{}",
|
||||
state.top.value(),
|
||||
path.join(","),
|
||||
attributes as u8,
|
||||
state.lock as u8,
|
||||
state.unique as u8
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
|
||||
/// `top[:path[:attributes[:nested]]]` — open the session.
|
||||
fn begin_refedit(&mut self, i: usize, args: &str) {
|
||||
let mut parts = args.split(':');
|
||||
@@ -186,6 +289,10 @@ impl OpenCADStudio {
|
||||
let path = handles(parts.next());
|
||||
let attributes = parts.next() == Some("1");
|
||||
let nested = handles(parts.next());
|
||||
let lock = parts.next().map_or(self.refedit_options.lock, |v| v == "1");
|
||||
let unique = parts
|
||||
.next()
|
||||
.map_or(self.refedit_options.unique_names, |v| v == "1");
|
||||
if self.tabs[i].refedit_session.is_some() || self.reject_locked_edit(i, top) {
|
||||
return;
|
||||
}
|
||||
@@ -211,6 +318,15 @@ impl OpenCADStudio {
|
||||
});
|
||||
}
|
||||
let level = chain.last().expect("non-empty chain").clone();
|
||||
// An external reference's dependent names (`XREF|NAME`) of the
|
||||
// outermost xref in the chain.
|
||||
let xref_prefix = chain.iter().find_map(|l| {
|
||||
document
|
||||
.block_records
|
||||
.get(&l.block_name)
|
||||
.filter(|br| br.flags.is_xref || br.flags.is_xref_overlay)
|
||||
.map(|br| format!("{}|", br.name))
|
||||
});
|
||||
let Some(br) = document.block_records.get(&level.block_name) else {
|
||||
return;
|
||||
};
|
||||
@@ -245,6 +361,8 @@ impl OpenCADStudio {
|
||||
// Everything allocated from here on is part of the session.
|
||||
handle_watermark: document.next_handle().max(document.header.handle_seed),
|
||||
xref_path,
|
||||
lock,
|
||||
names: RefEditNames::default(),
|
||||
};
|
||||
let copies: Vec<EntityType> = extracted
|
||||
.iter()
|
||||
@@ -252,6 +370,15 @@ impl OpenCADStudio {
|
||||
.collect();
|
||||
|
||||
self.push_undo_snapshot(i, "REFEDIT");
|
||||
let mut session = session;
|
||||
let copies = match xref_prefix {
|
||||
Some(prefix) => {
|
||||
let (copies, names) = self.refedit_host_names(i, copies, &prefix, unique);
|
||||
session.names = names;
|
||||
copies
|
||||
}
|
||||
None => copies,
|
||||
};
|
||||
let mut temp_handles = Vec::new();
|
||||
for mut entity in copies {
|
||||
apply_insert_transform(&mut entity, &session);
|
||||
@@ -259,7 +386,6 @@ impl OpenCADStudio {
|
||||
entity.common_mut().owner_handle = Handle::NULL;
|
||||
temp_handles.push(self.tabs[i].scene.add_entity(entity));
|
||||
}
|
||||
let mut session = session;
|
||||
session.temp_handles = temp_handles.clone();
|
||||
self.tabs[i].refedit_session = Some(session);
|
||||
self.tabs[i].refedit_closed.clear();
|
||||
@@ -267,7 +393,7 @@ impl OpenCADStudio {
|
||||
self.tabs[i]
|
||||
.scene
|
||||
.set_refedit_keep(Some(temp_handles.iter().copied().collect::<rustc_hash::FxHashSet<_>>()));
|
||||
self.tabs[i].scene.refedit_lock = true;
|
||||
self.tabs[i].scene.refedit_lock = lock;
|
||||
self.tabs[i].scene.deselect_all();
|
||||
self.tabs[i].dirty = true;
|
||||
// No active command — the definition's objects are edited freely
|
||||
@@ -375,6 +501,10 @@ impl OpenCADStudio {
|
||||
.iter()
|
||||
.filter_map(|h| self.tabs[i].scene.document.get_entity(*h).cloned())
|
||||
.map(|mut entity| {
|
||||
// Back to the reference's own dependent names.
|
||||
rename_symbols(&mut entity, &|kind, name| {
|
||||
session.names.original(kind, name).map(str::to_string)
|
||||
});
|
||||
apply_insert_inverse_transform(&mut entity, &session);
|
||||
let mut entity = normalize_entity_for_block(entity);
|
||||
entity.common_mut().handle = Handle::NULL;
|
||||
@@ -457,6 +587,7 @@ impl OpenCADStudio {
|
||||
}
|
||||
|
||||
fn finish_refedit_close(&mut self, i: usize, session: RefEditSession) {
|
||||
self.drop_refedit_names(i, &session.names);
|
||||
self.tabs[i].refedit_closed.push(session);
|
||||
self.tabs[i].scene.refedit_lock = false;
|
||||
self.tabs[i].scene.set_refedit_keep(None);
|
||||
@@ -586,8 +717,8 @@ impl OpenCADStudio {
|
||||
.map(|e| e.common().handle)
|
||||
.filter(|h| session.in_working_set(*h))
|
||||
.collect();
|
||||
self.tabs[i].scene.refedit_lock = session.lock;
|
||||
self.tabs[i].refedit_session = Some(session);
|
||||
self.tabs[i].scene.refedit_lock = true;
|
||||
self.tabs[i].scene.set_refedit_keep(Some(keep));
|
||||
}
|
||||
}
|
||||
@@ -605,4 +736,193 @@ impl OpenCADStudio {
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
/// The working set's objects of an external reference under host names:
|
||||
/// `XREF|NAME` becomes `$N$NAME` (the first free N) with records of its
|
||||
/// own when `unique`, else `NAME`, sharing a host record of that name when
|
||||
/// one exists. Missing records are copied from the reference's.
|
||||
fn refedit_host_names(
|
||||
&mut self,
|
||||
i: usize,
|
||||
mut copies: Vec<EntityType>,
|
||||
prefix: &str,
|
||||
unique: bool,
|
||||
) -> (Vec<EntityType>, RefEditNames) {
|
||||
let document = &mut self.tabs[i].scene.document;
|
||||
let deps = crate::app::ClipboardDeps::capture(document, &copies);
|
||||
let strip = |name: &str| -> Option<String> {
|
||||
(name.len() > prefix.len()
|
||||
&& name.is_char_boundary(prefix.len())
|
||||
&& name[..prefix.len()].eq_ignore_ascii_case(prefix))
|
||||
.then(|| name[prefix.len()..].to_string())
|
||||
};
|
||||
let exists = |document: &codec::CadDocument, kind: SymbolKind, name: &str| match kind {
|
||||
SymbolKind::Layer => document.layers.contains(name),
|
||||
SymbolKind::Linetype => document.line_types.contains(name),
|
||||
SymbolKind::TextStyle => document.text_styles.contains(name),
|
||||
SymbolKind::Block => document.block_records.get(name).is_some(),
|
||||
};
|
||||
let wanted: Vec<(SymbolKind, String)> = deps
|
||||
.layers
|
||||
.iter()
|
||||
.map(|r| (SymbolKind::Layer, r.name.clone()))
|
||||
.chain(deps.linetypes.iter().map(|r| (SymbolKind::Linetype, r.name.clone())))
|
||||
.chain(deps.text_styles.iter().map(|r| (SymbolKind::TextStyle, r.name.clone())))
|
||||
.chain(deps.blocks.iter().map(|b| (SymbolKind::Block, b.name.clone())))
|
||||
.collect();
|
||||
let mut names = RefEditNames::default();
|
||||
for (kind, original) in wanted {
|
||||
let Some(base) = strip(&original) else {
|
||||
continue;
|
||||
};
|
||||
let taken = |names: &RefEditNames, candidate: &str| {
|
||||
exists(document, kind, candidate)
|
||||
|| names
|
||||
.renamed
|
||||
.iter()
|
||||
.any(|(k, used, _)| *k == kind && used.eq_ignore_ascii_case(candidate))
|
||||
};
|
||||
// Layer 0 is the host's own in every drawing.
|
||||
let used = if kind == SymbolKind::Layer && base == "0" {
|
||||
base
|
||||
} else if unique {
|
||||
(0u32..)
|
||||
.map(|n| format!("${n}${base}"))
|
||||
.find(|candidate| !taken(&names, candidate))
|
||||
.expect("a free name")
|
||||
} else {
|
||||
base
|
||||
};
|
||||
if !exists(document, kind, &used)
|
||||
&& !names
|
||||
.created
|
||||
.iter()
|
||||
.any(|(k, n)| *k == kind && n.eq_ignore_ascii_case(&used))
|
||||
{
|
||||
names.created.push((kind, used.clone()));
|
||||
}
|
||||
names.renamed.push((kind, used, original));
|
||||
}
|
||||
let used_for = |kind: SymbolKind, name: &str| {
|
||||
names
|
||||
.renamed
|
||||
.iter()
|
||||
.find(|(k, _, original)| *k == kind && original.eq_ignore_ascii_case(name))
|
||||
.map(|(_, used, _)| used.clone())
|
||||
};
|
||||
let created = |kind: SymbolKind, name: &str| -> Option<String> {
|
||||
used_for(kind, name).filter(|used| {
|
||||
names
|
||||
.created
|
||||
.iter()
|
||||
.any(|(k, n)| *k == kind && n.eq_ignore_ascii_case(used))
|
||||
})
|
||||
};
|
||||
for record in &deps.layers {
|
||||
if let Some(used) = created(SymbolKind::Layer, &record.name) {
|
||||
let mut copy = record.clone();
|
||||
copy.name = used;
|
||||
copy.flags.xref_dependent = false;
|
||||
copy.xref_block_record_handle = Handle::NULL;
|
||||
if let Some(linetype) = used_for(SymbolKind::Linetype, ©.line_type) {
|
||||
copy.line_type = linetype;
|
||||
}
|
||||
copy.handle = document.allocate_handle();
|
||||
let _ = document.layers.add(copy);
|
||||
}
|
||||
}
|
||||
for record in &deps.linetypes {
|
||||
if let Some(used) = created(SymbolKind::Linetype, &record.name) {
|
||||
let mut copy = record.clone();
|
||||
copy.name = used;
|
||||
copy.xref_dependent = false;
|
||||
copy.xref_block_record_handle = Handle::NULL;
|
||||
copy.handle = document.allocate_handle();
|
||||
let _ = document.line_types.add(copy);
|
||||
}
|
||||
}
|
||||
for record in &deps.text_styles {
|
||||
if let Some(used) = created(SymbolKind::TextStyle, &record.name) {
|
||||
let mut copy = record.clone();
|
||||
copy.name = used;
|
||||
copy.xref_dependent = false;
|
||||
copy.xref_block_record_handle = Handle::NULL;
|
||||
copy.handle = document.allocate_handle();
|
||||
let _ = document.text_styles.add(copy);
|
||||
}
|
||||
}
|
||||
let rename = |kind: SymbolKind, name: &str| used_for(kind, name);
|
||||
let blocks: Vec<crate::app::BlockDef> = deps
|
||||
.blocks
|
||||
.iter()
|
||||
.filter_map(|def| {
|
||||
let used = created(SymbolKind::Block, &def.name)?;
|
||||
let mut entities = def.entities.clone();
|
||||
for entity in &mut entities {
|
||||
rename_symbols(entity, &rename);
|
||||
}
|
||||
Some(crate::app::BlockDef {
|
||||
name: used,
|
||||
base_point: def.base_point,
|
||||
entities,
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
crate::app::command_driver::clipboard::merge_block_defs(document, &blocks);
|
||||
for entity in &mut copies {
|
||||
rename_symbols(entity, &rename);
|
||||
}
|
||||
(copies, names)
|
||||
}
|
||||
|
||||
/// Removes the host records made for a session that nothing uses any more.
|
||||
fn drop_refedit_names(&mut self, i: usize, names: &RefEditNames) {
|
||||
for (kind, name) in names.created.iter().rev() {
|
||||
let scene = &mut self.tabs[i].scene;
|
||||
let in_use = scene.document.entities().any(|entity| {
|
||||
let common = entity.common();
|
||||
match kind {
|
||||
SymbolKind::Layer => common.layer.eq_ignore_ascii_case(name),
|
||||
SymbolKind::Linetype => common.linetype.eq_ignore_ascii_case(name),
|
||||
SymbolKind::TextStyle => match entity {
|
||||
EntityType::Text(t) => t.style.eq_ignore_ascii_case(name),
|
||||
EntityType::MText(t) => t.style.eq_ignore_ascii_case(name),
|
||||
EntityType::AttributeDefinition(a) => {
|
||||
a.text_style.eq_ignore_ascii_case(name)
|
||||
}
|
||||
_ => false,
|
||||
},
|
||||
SymbolKind::Block => matches!(
|
||||
entity,
|
||||
EntityType::Insert(insert) if insert.block_name.eq_ignore_ascii_case(name)
|
||||
),
|
||||
}
|
||||
});
|
||||
// A linetype made for the session may also be a kept layer's.
|
||||
let in_use = in_use
|
||||
|| (*kind == SymbolKind::Linetype
|
||||
&& scene
|
||||
.document
|
||||
.layers
|
||||
.iter()
|
||||
.any(|layer| layer.line_type.eq_ignore_ascii_case(name)));
|
||||
if in_use {
|
||||
continue;
|
||||
}
|
||||
match kind {
|
||||
SymbolKind::Layer => {
|
||||
scene.document.layers.remove(name);
|
||||
}
|
||||
SymbolKind::Linetype => {
|
||||
scene.document.line_types.remove(name);
|
||||
}
|
||||
SymbolKind::TextStyle => {
|
||||
scene.document.text_styles.remove(name);
|
||||
}
|
||||
SymbolKind::Block => {
|
||||
let _ = crate::scene::block_service::erase(scene, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -105,6 +105,7 @@ pub(super) const NAMES: &[&str] = &[
|
||||
"pdf_dialog_ok",
|
||||
"view_background",
|
||||
"image_adjust",
|
||||
"refedit_dialog",
|
||||
"pdf_layer_toggle",
|
||||
"pc_manager_toggle",
|
||||
"pc_manager",
|
||||
@@ -1885,6 +1886,36 @@ impl OpenCADStudio {
|
||||
})
|
||||
}
|
||||
"ribbon_dropdown" => Message::ToggleRibbonDropdown(string(req, "value")?.into()),
|
||||
// The Edit Reference dialog, one field per call: "level=<n>" (0 =
|
||||
// the picked reference), "nested=0|1" (pick the working set in the
|
||||
// drawing), "attributes=0|1", "lock=0|1", "unique=0|1", "ok" or
|
||||
// "cancel".
|
||||
"refedit_dialog" => {
|
||||
use crate::ui::window::refedit_dialog::RefEditDialogMsg as R;
|
||||
if self.active_modal != Some(crate::app::ModalKind::RefEdit) {
|
||||
return Err(failure("no_dialog", "The Reference Edit dialog is not open"));
|
||||
}
|
||||
let spec = string(req, "value")?;
|
||||
let (key, value) = spec.split_once('=').unwrap_or((spec, ""));
|
||||
let flag = || match value {
|
||||
"1" => Ok(true),
|
||||
"0" => Ok(false),
|
||||
_ => Err(failure("invalid_value", spec)),
|
||||
};
|
||||
if key == "cancel" {
|
||||
Message::CloseModal
|
||||
} else {
|
||||
Message::RefEditDialog(match key {
|
||||
"ok" => R::Ok,
|
||||
"level" => R::Level(value.parse().map_err(|_| failure("invalid_value", spec))?),
|
||||
"nested" => R::Nested(flag()?),
|
||||
"attributes" => R::Attributes(flag()?),
|
||||
"lock" => R::Lock(flag()?),
|
||||
"unique" => R::Unique(flag()?),
|
||||
_ => return Err(failure("invalid_value", "Unknown Reference Edit field")),
|
||||
})
|
||||
}
|
||||
}
|
||||
// The -VIEW Background dialog, one field per call: "type=gradient",
|
||||
// "color|top|middle|bottom=r,g,b", "three=1", "rotation=30",
|
||||
// "image=<path>", "position=center|stretch|tile", "aspect=1", "offset=x,y" (pixels), "scale=x,y",
|
||||
|
||||
@@ -586,6 +586,8 @@ pub(super) struct OpenCADStudio {
|
||||
view_background: Option<crate::ui::window::pdf_dialogs::ViewBackgroundState>,
|
||||
/// IMAGEADJUST dialog.
|
||||
image_adjust: Option<crate::ui::window::pdf_dialogs::ImageAdjustState>,
|
||||
/// The Edit Reference dialog (REFEDIT).
|
||||
refedit_dialog: Option<crate::ui::window::refedit_dialog::RefEditDialogState>,
|
||||
underlay_layers: Option<crate::ui::window::pdf_dialogs::UnderlayLayersState>,
|
||||
pdf_import_settings: Option<crate::modules::insert::pdf_import::PdfImportSettings>,
|
||||
pdf_import_file: Option<crate::ui::window::pdf_dialogs::PdfImportFileState>,
|
||||
@@ -794,6 +796,8 @@ pub(super) struct OpenCADStudio {
|
||||
block_freq: std::collections::HashMap<String, u32>,
|
||||
/// BLOCKMRULIST: how many recent blocks the palette keeps (0–100).
|
||||
pub(crate) block_mru_list: u8,
|
||||
/// The Edit Reference dialog's remembered settings.
|
||||
pub(crate) refedit_options: crate::app::settings::RefEditOptions,
|
||||
/// BLOCKREDEFINEMODE (0–2).
|
||||
pub(crate) block_redefine_mode: u8,
|
||||
/// BLOCKNAVIGATE: the Libraries tab's start folder ("." for none).
|
||||
@@ -2158,6 +2162,7 @@ pub enum ModalKind {
|
||||
PcSection,
|
||||
ViewBackground,
|
||||
ImageAdjust,
|
||||
RefEdit,
|
||||
UnderlayLayers,
|
||||
PdfImportSettings,
|
||||
PdfImportFile,
|
||||
@@ -4356,6 +4361,8 @@ pub enum Message {
|
||||
PdfDialog(crate::ui::window::pdf_dialogs::PdfDialogMsg),
|
||||
AttdefDialog(crate::ui::window::attdef_dialog::AttdefDialogMsg),
|
||||
FieldDialog(crate::ui::window::field_dialog::FieldDialogMsg),
|
||||
/// An edit in the Edit Reference dialog.
|
||||
RefEditDialog(crate::ui::window::refedit_dialog::RefEditDialogMsg),
|
||||
/// A click or search in the Point Cloud Manager.
|
||||
PcManager(crate::ui::window::pc_manager::PcManagerMsg),
|
||||
Count(crate::ui::window::count_palette::CountMsg),
|
||||
@@ -4569,6 +4576,7 @@ impl OpenCADStudio {
|
||||
pc_section: None,
|
||||
view_background: None,
|
||||
image_adjust: None,
|
||||
refedit_dialog: None,
|
||||
underlay_layers: None,
|
||||
pdf_import_settings: None,
|
||||
pdf_import_file: None,
|
||||
@@ -4668,6 +4676,7 @@ impl OpenCADStudio {
|
||||
block_mru: Vec::new(),
|
||||
block_freq: std::collections::HashMap::new(),
|
||||
block_mru_list: 50,
|
||||
refedit_options: Default::default(),
|
||||
block_redefine_mode: 1,
|
||||
block_navigate: ".".to_string(),
|
||||
insname: String::new(),
|
||||
|
||||
@@ -652,6 +652,9 @@ pub struct UserSettings {
|
||||
/// BLOCKNAVIGATE (default ".").
|
||||
#[serde(default = "default_block_navigate")]
|
||||
pub block_navigate: String,
|
||||
/// The Edit Reference dialog's settings.
|
||||
#[serde(default)]
|
||||
pub refedit: RefEditOptions,
|
||||
/// XFADECTL: how far objects outside the REFEDIT working set fade (0–90, default 70).
|
||||
#[serde(default = "default_xfadectl")]
|
||||
pub xfadectl: u8,
|
||||
@@ -687,6 +690,30 @@ pub struct PaletteBlockRef {
|
||||
pub drawing: bool,
|
||||
}
|
||||
|
||||
/// The Edit Reference dialog's settings, remembered between sessions: give
|
||||
/// an external reference's clashing named objects unique names, check out
|
||||
/// attribute definitions, lock what is outside the working set, pick the
|
||||
/// working set's objects in the drawing.
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct RefEditOptions {
|
||||
pub unique_names: bool,
|
||||
pub attributes: bool,
|
||||
pub lock: bool,
|
||||
pub nested: bool,
|
||||
}
|
||||
|
||||
impl Default for RefEditOptions {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
unique_names: true,
|
||||
attributes: false,
|
||||
lock: true,
|
||||
nested: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The Blocks palette's insertion options.
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct BlockInsertOptions {
|
||||
@@ -938,6 +965,7 @@ impl Default for UserSettings {
|
||||
block_mru_list: 50,
|
||||
block_redefine_mode: 1,
|
||||
block_navigate: ".".to_string(),
|
||||
refedit: RefEditOptions::default(),
|
||||
xfadectl: 70,
|
||||
count_color: 3,
|
||||
count_error_color: 1,
|
||||
|
||||
@@ -873,6 +873,7 @@ impl OpenCADStudio {
|
||||
block_mru_list: self.block_mru_list,
|
||||
block_redefine_mode: self.block_redefine_mode,
|
||||
block_navigate: self.block_navigate.clone(),
|
||||
refedit: self.refedit_options.clone(),
|
||||
xfadectl: crate::scene::cache::block_cache::refedit_fade_ctl() as u8,
|
||||
count_color: self.count_palette.color,
|
||||
count_error_color: self.count_palette.error_color,
|
||||
@@ -1036,6 +1037,7 @@ impl OpenCADStudio {
|
||||
self.block_redefine_mode = s.block_redefine_mode.min(2);
|
||||
self.block_navigate = s.block_navigate.clone();
|
||||
crate::scene::cache::block_cache::set_refedit_fade_ctl(i32::from(s.xfadectl.min(90)));
|
||||
self.refedit_options = s.refedit.clone();
|
||||
self.count_palette.color = s.count_color;
|
||||
self.count_palette.error_color = s.count_error_color;
|
||||
self.count_palette.service = s.count_service;
|
||||
|
||||
@@ -2281,6 +2281,7 @@ impl OpenCADStudio {
|
||||
Message::PdfDialog(message) => self.update_pdf_dialog(message),
|
||||
Message::AttdefDialog(message) => self.on_attdef_dialog(message),
|
||||
Message::FieldDialog(message) => self.on_field_dialog(message),
|
||||
Message::RefEditDialog(message) => self.update_refedit_dialog(message),
|
||||
Message::PcManager(message) => self.update_pc_manager(message),
|
||||
Message::Count(message) => self.on_count(message),
|
||||
Message::SheetSet(message) => self.on_sheet_set(message),
|
||||
@@ -9503,6 +9504,9 @@ impl OpenCADStudio {
|
||||
Task::none()
|
||||
};
|
||||
}
|
||||
if self.active_modal == Some(super::ModalKind::RefEdit) {
|
||||
self.refedit_dialog = None;
|
||||
}
|
||||
// Cancelling the section settings drops the waiting extraction.
|
||||
if self.active_modal == Some(super::ModalKind::PcSection) {
|
||||
crate::modules::insert::pc_extract::drop_job();
|
||||
|
||||
@@ -41,6 +41,7 @@ impl OpenCADStudio {
|
||||
self.view_background.as_ref().map_or("", |s| s.view.as_str())
|
||||
),
|
||||
Some(K::ImageAdjust) => crate::tr!("image-adjust", "title"),
|
||||
Some(K::RefEdit) => crate::tr!("ref-edit", "dialog-title"),
|
||||
Some(K::UnderlayLayers) => crate::t!("Underlay Layers").into_owned(),
|
||||
Some(K::PdfImportSettings) => crate::t!("PDF Import Settings").into_owned(),
|
||||
Some(K::PdfImportFile) => crate::t!("Import PDF").into_owned(),
|
||||
@@ -542,6 +543,12 @@ impl OpenCADStudio {
|
||||
crate::ui::window::pdf_dialogs::image_adjust(state, flow)
|
||||
})
|
||||
}
|
||||
super::super::ModalKind::RefEdit => {
|
||||
let state = self.refedit_dialog.as_ref()?;
|
||||
sized_flow(ex, 560, 470, |flow| {
|
||||
crate::ui::window::refedit_dialog::view(state, flow)
|
||||
})
|
||||
}
|
||||
super::super::ModalKind::UnderlayLayers => {
|
||||
let state = self.underlay_layers.as_ref()?;
|
||||
sized_flow(ex, 460, 520, |flow| {
|
||||
|
||||
+1
-1
@@ -32,7 +32,7 @@ const MODERN_PROTOCOL_VERSION: &str = "2026-07-28";
|
||||
///
|
||||
/// `block_delete` gained its optional `force` parameter.
|
||||
#[cfg(test)]
|
||||
const TOOL_SCHEMA_DIGEST: &str = "dde915fd17f3cc4667e1eee8d796030156e7ff9423b0fa9b48a648a1481df723";
|
||||
const TOOL_SCHEMA_DIGEST: &str = "c5f9ad00e04c0acc809c7de0c75e789fd9bf3ad6db68bdde36bd771a859fef79";
|
||||
const MAX_REQUEST: usize = 1_048_576;
|
||||
const MAX_RESPONSE: u64 = 16 * 1024 * 1024;
|
||||
const CACHE_TTL_MS: u64 = 3_600_000;
|
||||
|
||||
@@ -94,6 +94,79 @@ pub struct RefEditSession {
|
||||
pub handle_watermark: u64,
|
||||
/// The referenced file when the definition is an xref.
|
||||
pub xref_path: Option<String>,
|
||||
/// Objects outside the working set can't be selected while it is open.
|
||||
pub lock: bool,
|
||||
/// The external reference's named objects the working set uses under
|
||||
/// host names, and the host records made for the session.
|
||||
pub names: RefEditNames,
|
||||
}
|
||||
|
||||
/// A kind of named object the working set's objects refer to.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum SymbolKind {
|
||||
Layer,
|
||||
Linetype,
|
||||
TextStyle,
|
||||
Block,
|
||||
}
|
||||
|
||||
/// How an external reference's dependent names (`XREF|NAME`) are used in
|
||||
/// the host while its objects are checked out: as `$0$NAME` records of
|
||||
/// their own (unique names), or under the plain name, sharing a host record
|
||||
/// of that name when there is one.
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct RefEditNames {
|
||||
/// (kind, name used in the host, the reference's dependent name).
|
||||
pub renamed: Vec<(SymbolKind, String, String)>,
|
||||
/// Records added to the host for the session, removed when it closes.
|
||||
pub created: Vec<(SymbolKind, String)>,
|
||||
}
|
||||
|
||||
impl RefEditNames {
|
||||
/// The reference's own name for a host name used in the session.
|
||||
pub fn original(&self, kind: SymbolKind, name: &str) -> Option<&str> {
|
||||
self.renamed
|
||||
.iter()
|
||||
.find(|(k, used, _)| *k == kind && used.eq_ignore_ascii_case(name))
|
||||
.map(|(_, _, original)| original.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
/// Rewrites every named-object reference of an entity through `map`
|
||||
/// (layer, linetype, text style, block).
|
||||
pub fn rename_symbols(entity: &mut EntityType, map: &dyn Fn(SymbolKind, &str) -> Option<String>) {
|
||||
let common = entity.common_mut();
|
||||
if let Some(name) = map(SymbolKind::Layer, &common.layer) {
|
||||
common.layer = name;
|
||||
common.layer_handle = None;
|
||||
}
|
||||
if let Some(name) = map(SymbolKind::Linetype, &common.linetype) {
|
||||
common.linetype = name;
|
||||
common.linetype_handle = None;
|
||||
}
|
||||
match entity {
|
||||
EntityType::Insert(insert) => {
|
||||
if let Some(name) = map(SymbolKind::Block, &insert.block_name) {
|
||||
insert.block_name = name;
|
||||
}
|
||||
}
|
||||
EntityType::Text(text) => {
|
||||
if let Some(name) = map(SymbolKind::TextStyle, &text.style) {
|
||||
text.style = name;
|
||||
}
|
||||
}
|
||||
EntityType::MText(text) => {
|
||||
if let Some(name) = map(SymbolKind::TextStyle, &text.style) {
|
||||
text.style = name;
|
||||
}
|
||||
}
|
||||
EntityType::AttributeDefinition(attdef) => {
|
||||
if let Some(name) = map(SymbolKind::TextStyle, &attdef.text_style) {
|
||||
attdef.text_style = name;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
impl RefEditSession {
|
||||
@@ -334,10 +407,23 @@ pub struct RefEditOptionsCommand {
|
||||
level: usize,
|
||||
step: OptionStep,
|
||||
nested: Vec<Handle>,
|
||||
/// The session settings (lock objects outside the working set, unique
|
||||
/// names for an external reference's named objects).
|
||||
lock: bool,
|
||||
unique: bool,
|
||||
/// Set when the Edit Reference dialog already chose the attribute
|
||||
/// option: the nested pick then opens the session directly.
|
||||
attributes: Option<bool>,
|
||||
}
|
||||
|
||||
impl RefEditOptionsCommand {
|
||||
pub fn new(top: Handle, chain: Vec<ChainLevel>, hits: Vec<LevelHits>) -> Self {
|
||||
pub fn new(
|
||||
top: Handle,
|
||||
chain: Vec<ChainLevel>,
|
||||
hits: Vec<LevelHits>,
|
||||
lock: bool,
|
||||
unique: bool,
|
||||
) -> Self {
|
||||
let level = chain.len().saturating_sub(1);
|
||||
Self {
|
||||
top,
|
||||
@@ -346,9 +432,30 @@ impl RefEditOptionsCommand {
|
||||
level,
|
||||
step: OptionStep::Nesting,
|
||||
nested: Vec::new(),
|
||||
lock,
|
||||
unique,
|
||||
attributes: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// `Select nested objects:` for the dialog's "pick in the drawing"
|
||||
/// working set at `level`.
|
||||
pub fn nested_pick(
|
||||
top: Handle,
|
||||
chain: Vec<ChainLevel>,
|
||||
hits: Vec<LevelHits>,
|
||||
level: usize,
|
||||
attributes: bool,
|
||||
lock: bool,
|
||||
unique: bool,
|
||||
) -> Self {
|
||||
let mut command = Self::new(top, chain, hits, lock, unique);
|
||||
command.level = level.min(command.chain.len().saturating_sub(1));
|
||||
command.step = OptionStep::Nested;
|
||||
command.attributes = Some(attributes);
|
||||
command
|
||||
}
|
||||
|
||||
fn begin(&self, attributes: bool) -> CmdResult {
|
||||
let path: Vec<String> = self.chain[1..=self.level]
|
||||
.iter()
|
||||
@@ -357,11 +464,13 @@ impl RefEditOptionsCommand {
|
||||
let nested: Vec<String> = self.nested.iter().map(|h| h.value().to_string()).collect();
|
||||
CmdResult::Relaunch(
|
||||
format!(
|
||||
"REFEDIT_BEGIN:{}:{}:{}:{}",
|
||||
"REFEDIT_BEGIN:{}:{}:{}:{}:{}:{}",
|
||||
self.top.value(),
|
||||
path.join(","),
|
||||
attributes as u8,
|
||||
nested.join(",")
|
||||
nested.join(","),
|
||||
self.lock as u8,
|
||||
self.unique as u8
|
||||
),
|
||||
vec![],
|
||||
)
|
||||
@@ -469,6 +578,9 @@ impl CadCommand for RefEditOptionsCommand {
|
||||
if n == 0 {
|
||||
return CmdResult::CancelWithMessage(t!("0 items selected").into_owned());
|
||||
}
|
||||
if let Some(attributes) = self.attributes {
|
||||
return self.begin(attributes);
|
||||
}
|
||||
self.step = OptionStep::Attributes;
|
||||
CmdResult::ReportMeasurement(if n == 1 {
|
||||
t!("1 item selected").into_owned()
|
||||
|
||||
@@ -30,6 +30,7 @@ pub mod plot;
|
||||
pub mod plugin_manager;
|
||||
pub mod print_all;
|
||||
pub mod recovery;
|
||||
pub mod refedit_dialog;
|
||||
pub mod sheet_set;
|
||||
pub mod shortcuts;
|
||||
pub mod update_notice;
|
||||
|
||||
@@ -312,7 +312,7 @@ pub(crate) fn well_style(theme: &Theme) -> container::Style {
|
||||
}
|
||||
|
||||
/// A titled card.
|
||||
fn card<'a>(title: String, content: impl Into<Element<'a, Message>>) -> Element<'a, Message> {
|
||||
pub(crate) fn card<'a>(title: String, content: impl Into<Element<'a, Message>>) -> Element<'a, Message> {
|
||||
container(
|
||||
column![
|
||||
text(title.to_uppercase()).size(10).style(accent_text),
|
||||
|
||||
@@ -0,0 +1,247 @@
|
||||
//! Edit Reference dialog (REFEDIT): the nesting level to check out, shown as
|
||||
//! a chain of chips beside a preview of the chosen definition, how the
|
||||
//! working set is filled, whether attribute definitions come along, and the
|
||||
//! session settings (lock what is outside the working set, give clashing
|
||||
//! named objects of an external reference unique names).
|
||||
|
||||
use iced::widget::{button, column, container, row, text, toggler, Space};
|
||||
use iced::{Border, Element, Fill, Length, Theme};
|
||||
|
||||
use crate::app::Message;
|
||||
use crate::scene::model::wire_model::WireModel;
|
||||
use crate::ui::style::common::muted_style;
|
||||
use crate::ui::style::form::{button_style, dialog_button};
|
||||
use crate::ui::window::pdf_dialogs::{card, well_style};
|
||||
|
||||
/// One edit in the Edit Reference dialog.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum RefEditDialogMsg {
|
||||
/// The nesting level picked in the chain (0 = the selected reference).
|
||||
Level(usize),
|
||||
/// Pick the working set's objects in the drawing (else all of them).
|
||||
Nested(bool),
|
||||
Attributes(bool),
|
||||
Lock(bool),
|
||||
Unique(bool),
|
||||
Help,
|
||||
Ok,
|
||||
}
|
||||
|
||||
fn msg(m: RefEditDialogMsg) -> Message {
|
||||
Message::RefEditDialog(m)
|
||||
}
|
||||
|
||||
/// One level of the nesting chain as the dialog shows it.
|
||||
pub struct RefEditLevel {
|
||||
/// The reference's handle: the picked object for level 0, the
|
||||
/// definition-owned reference below it.
|
||||
pub insert: codec::Handle,
|
||||
pub name: String,
|
||||
/// The definition's preview.
|
||||
pub wires: Vec<WireModel>,
|
||||
/// The definition holds attribute definitions (the attribute switch is
|
||||
/// only offered then).
|
||||
pub has_attdefs: bool,
|
||||
/// The referenced file of an external reference.
|
||||
pub xref_path: Option<String>,
|
||||
}
|
||||
|
||||
pub struct RefEditDialogState {
|
||||
pub top: codec::Handle,
|
||||
/// The picked chain, outermost first.
|
||||
pub chain: Vec<crate::modules::draw::modify::refedit::ChainLevel>,
|
||||
pub levels: Vec<RefEditLevel>,
|
||||
pub level: usize,
|
||||
pub nested: bool,
|
||||
pub attributes: bool,
|
||||
pub lock: bool,
|
||||
pub unique: bool,
|
||||
}
|
||||
|
||||
impl RefEditDialogState {
|
||||
/// The attribute switch counts only where the chosen definition has
|
||||
/// attribute definitions.
|
||||
pub fn attributes_enabled(&self) -> bool {
|
||||
self.levels.get(self.level).is_some_and(|l| l.has_attdefs)
|
||||
}
|
||||
}
|
||||
|
||||
fn label<'a>(value: String, enabled: bool) -> Element<'a, Message> {
|
||||
text(value)
|
||||
.size(12)
|
||||
.style(move |theme: &Theme| {
|
||||
if enabled {
|
||||
text::Style::default()
|
||||
} else {
|
||||
text::Style {
|
||||
color: Some(theme.palette().background.strong.color),
|
||||
}
|
||||
}
|
||||
})
|
||||
.width(Fill)
|
||||
.into()
|
||||
}
|
||||
|
||||
/// A labelled switch on one row; inactive while `on_toggle` is None.
|
||||
fn switch_row<'a>(
|
||||
name: String,
|
||||
value: bool,
|
||||
on_toggle: Option<fn(bool) -> RefEditDialogMsg>,
|
||||
) -> Element<'a, Message> {
|
||||
let enabled = on_toggle.is_some();
|
||||
let mut switch = toggler(value).size(18.0);
|
||||
if let Some(on) = on_toggle {
|
||||
switch = switch.on_toggle(move |v| msg(on(v)));
|
||||
}
|
||||
row![label(name, enabled), switch]
|
||||
.spacing(8)
|
||||
.align_y(iced::Center)
|
||||
.into()
|
||||
}
|
||||
|
||||
/// A level of the chain as a pill; the chosen one framed in the accent colour.
|
||||
fn level_chip<'a>(name: &str, index: usize, chosen: bool) -> Element<'a, Message> {
|
||||
button(text(name.to_string()).size(12))
|
||||
.on_press(msg(RefEditDialogMsg::Level(index)))
|
||||
.padding([5, 12])
|
||||
.style(move |theme: &Theme, status| {
|
||||
let mut style = button_style(false)(theme, status);
|
||||
style.border = Border {
|
||||
width: if chosen { 1.5 } else { 1.0 },
|
||||
radius: 14.0.into(),
|
||||
color: if chosen {
|
||||
theme.palette().primary.base.color
|
||||
} else {
|
||||
theme.palette().background.strong.color
|
||||
},
|
||||
};
|
||||
if chosen {
|
||||
style.text_color = theme.palette().primary.base.color;
|
||||
}
|
||||
style
|
||||
})
|
||||
.into()
|
||||
}
|
||||
|
||||
pub fn view<'a>(
|
||||
state: &'a RefEditDialogState,
|
||||
sizing: crate::ui::modal::ModalSizing,
|
||||
) -> Element<'a, Message> {
|
||||
let current = state.levels.get(state.level);
|
||||
let preview: Element<'a, Message> = container(match current {
|
||||
Some(level) => crate::ui::window::block_palette::preview_canvas(&level.wires, 104.0),
|
||||
None => Space::new().into(),
|
||||
})
|
||||
.width(Length::Fixed(150.0))
|
||||
.height(Length::Fixed(104.0))
|
||||
.padding(4)
|
||||
.style(well_style)
|
||||
.into();
|
||||
let mut chips = row![].spacing(6).align_y(iced::Center);
|
||||
for (index, level) in state.levels.iter().enumerate() {
|
||||
if index > 0 {
|
||||
chips = chips.push(text("›").size(13).style(muted_style));
|
||||
}
|
||||
chips = chips.push(level_chip(&level.name, index, index == state.level));
|
||||
}
|
||||
let mut about = column![text(crate::tr!("ref-edit", "dialog-chain-hint"))
|
||||
.size(11)
|
||||
.style(muted_style)]
|
||||
.spacing(4);
|
||||
if let Some(path) = current.and_then(|l| l.xref_path.as_deref()) {
|
||||
// A long path keeps its end, where the file name is.
|
||||
const MAX: usize = 64;
|
||||
let count = path.chars().count();
|
||||
let shown = if count > MAX {
|
||||
format!("…{}", path.chars().skip(count - (MAX - 1)).collect::<String>())
|
||||
} else {
|
||||
path.to_string()
|
||||
};
|
||||
about = about.push(
|
||||
text(format!("{} {}", crate::tr!("ref-edit", "dialog-path"), shown))
|
||||
.size(11)
|
||||
.style(muted_style),
|
||||
);
|
||||
}
|
||||
let reference = card(
|
||||
crate::tr!("ref-edit", "dialog-reference"),
|
||||
row![
|
||||
preview,
|
||||
column![iced::widget::scrollable(chips).direction(
|
||||
iced::widget::scrollable::Direction::Horizontal(
|
||||
iced::widget::scrollable::Scrollbar::new().width(4).scroller_width(4)
|
||||
)
|
||||
), about]
|
||||
.spacing(8)
|
||||
.width(Fill)
|
||||
]
|
||||
.spacing(12),
|
||||
);
|
||||
|
||||
let segment = |nested: bool, name: String| {
|
||||
button(text(name).size(12).width(Fill).align_x(iced::Center))
|
||||
.on_press(msg(RefEditDialogMsg::Nested(nested)))
|
||||
.style(button_style(state.nested == nested))
|
||||
.padding([6, 8])
|
||||
.width(Fill)
|
||||
};
|
||||
let method = container(
|
||||
row![
|
||||
segment(false, crate::tr!("ref-edit", "dialog-all-objects")),
|
||||
segment(true, crate::tr!("ref-edit", "dialog-pick-objects")),
|
||||
]
|
||||
.spacing(2),
|
||||
)
|
||||
.padding(2)
|
||||
.width(Fill)
|
||||
.style(well_style);
|
||||
let attributes_enabled = state.attributes_enabled();
|
||||
let working_set = card(
|
||||
crate::tr!("ref-edit", "dialog-working-set"),
|
||||
column![
|
||||
method,
|
||||
switch_row(
|
||||
crate::tr!("ref-edit", "dialog-attributes"),
|
||||
state.attributes && attributes_enabled,
|
||||
attributes_enabled.then_some(RefEditDialogMsg::Attributes as fn(bool) -> _),
|
||||
),
|
||||
]
|
||||
.spacing(10),
|
||||
);
|
||||
let session = card(
|
||||
crate::tr!("ref-edit", "dialog-session"),
|
||||
column![
|
||||
switch_row(
|
||||
crate::tr!("ref-edit", "dialog-lock"),
|
||||
state.lock,
|
||||
Some(RefEditDialogMsg::Lock),
|
||||
),
|
||||
switch_row(
|
||||
crate::tr!("ref-edit", "dialog-unique"),
|
||||
state.unique,
|
||||
Some(RefEditDialogMsg::Unique),
|
||||
),
|
||||
]
|
||||
.spacing(10),
|
||||
);
|
||||
let footer = row![
|
||||
button(text("?").size(12))
|
||||
.on_press(msg(RefEditDialogMsg::Help))
|
||||
.style(button_style(false))
|
||||
.padding([5, 11]),
|
||||
Space::new().width(Fill),
|
||||
dialog_button(crate::t!("Cancel"), Message::CloseModal, false),
|
||||
dialog_button(
|
||||
std::borrow::Cow::Owned(crate::tr!("ref-edit", "dialog-start")),
|
||||
msg(RefEditDialogMsg::Ok),
|
||||
true
|
||||
),
|
||||
]
|
||||
.spacing(6)
|
||||
.align_y(iced::Center);
|
||||
column![reference, working_set, session, footer]
|
||||
.spacing(10)
|
||||
.padding([10, 12])
|
||||
.width(sizing.width)
|
||||
.into()
|
||||
}
|
||||
Reference in new issue
Block a user