Contextual External Reference ribbon tab

Shown and brought forward while only xrefs are selected: Edit Reference
In-Place, Open Reference, Create Clipping Boundary, Remove Clipping and
External References.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
ramox81andClaude Opus 5.5 committed 2026-09-25 10:33:50 +03:00
1 parent 857f2f2e58
commit 68721813f4
26 files changed
+278 -22

No files matched your search

+6
View File
@@ -3586,6 +3586,12 @@ insert =
.refui-requires-int-90 = Requires an integer between -90 and 90.
.refui-xref-fading = Xref fading
.refui-edit-reference = Edit Reference
.refui-edit-reference-in-place =
Edit Reference
In-Place
.refui-open-reference =
Open
Reference
.refui-snap-to-underlays-off = Snap to Underlays OFF
.refui-snap-to-underlays-on = Snap to Underlays ON
.refui-snap-to-underlays = Snap to Underlays
+6
View File
@@ -3573,6 +3573,12 @@ insert =
.refui-requires-int-90 = Requires an integer between -90 and 90.
.refui-xref-fading = Xref fading
.refui-edit-reference = Edit Reference
.refui-edit-reference-in-place =
Edit Reference
In-Place
.refui-open-reference =
Open
Reference
.refui-snap-to-underlays-off = Snap to Underlays OFF
.refui-snap-to-underlays-on = Snap to Underlays ON
.refui-snap-to-underlays = Snap to Underlays
+6
View File
@@ -3571,6 +3571,12 @@ insert =
.refui-requires-int-90 = Requires an integer between -90 and 90.
.refui-xref-fading = Xref fading
.refui-edit-reference = Edit Reference
.refui-edit-reference-in-place =
Edit Reference
In-Place
.refui-open-reference =
Open
Reference
.refui-snap-to-underlays-off = Snap to Underlays OFF
.refui-snap-to-underlays-on = Snap to Underlays ON
.refui-snap-to-underlays = Snap to Underlays
+6
View File
@@ -3574,6 +3574,12 @@ insert =
.refui-requires-int-90 = Requires an integer between -90 and 90.
.refui-xref-fading = Xref fading
.refui-edit-reference = Edit Reference
.refui-edit-reference-in-place =
Edit Reference
In-Place
.refui-open-reference =
Open
Reference
.refui-snap-to-underlays-off = Snap to Underlays OFF
.refui-snap-to-underlays-on = Snap to Underlays ON
.refui-snap-to-underlays = Snap to Underlays
+6
View File
@@ -3574,6 +3574,12 @@ insert =
.refui-requires-int-90 = Requires an integer between -90 and 90.
.refui-xref-fading = Xref fading
.refui-edit-reference = Edit Reference
.refui-edit-reference-in-place =
Edit Reference
In-Place
.refui-open-reference =
Open
Reference
.refui-snap-to-underlays-off = Snap to Underlays OFF
.refui-snap-to-underlays-on = Snap to Underlays ON
.refui-snap-to-underlays = Snap to Underlays
+6
View File
@@ -3575,6 +3575,12 @@ insert =
.refui-requires-int-90 = Requires an integer between -90 and 90.
.refui-xref-fading = Xref fading
.refui-edit-reference = Edit Reference
.refui-edit-reference-in-place =
Edit Reference
In-Place
.refui-open-reference =
Open
Reference
.refui-snap-to-underlays-off = Snap to Underlays OFF
.refui-snap-to-underlays-on = Snap to Underlays ON
.refui-snap-to-underlays = Snap to Underlays
+6
View File
@@ -3574,6 +3574,12 @@ insert =
.refui-requires-int-90 = Requires an integer between -90 and 90.
.refui-xref-fading = Xref fading
.refui-edit-reference = Edit Reference
.refui-edit-reference-in-place =
Edit Reference
In-Place
.refui-open-reference =
Open
Reference
.refui-snap-to-underlays-off = Snap to Underlays OFF
.refui-snap-to-underlays-on = Snap to Underlays ON
.refui-snap-to-underlays = Snap to Underlays
+6
View File
@@ -3573,6 +3573,12 @@ insert =
.refui-requires-int-90 = Requires an integer between -90 and 90.
.refui-xref-fading = Xref fading
.refui-edit-reference = Edit Reference
.refui-edit-reference-in-place =
Edit Reference
In-Place
.refui-open-reference =
Open
Reference
.refui-snap-to-underlays-off = Snap to Underlays OFF
.refui-snap-to-underlays-on = Snap to Underlays ON
.refui-snap-to-underlays = Snap to Underlays
+6
View File
@@ -3574,6 +3574,12 @@ insert =
.refui-requires-int-90 = Requires an integer between -90 and 90.
.refui-xref-fading = Xref fading
.refui-edit-reference = Edit Reference
.refui-edit-reference-in-place =
Edit Reference
In-Place
.refui-open-reference =
Open
Reference
.refui-snap-to-underlays-off = Snap to Underlays OFF
.refui-snap-to-underlays-on = Snap to Underlays ON
.refui-snap-to-underlays = Snap to Underlays
+6
View File
@@ -3562,6 +3562,12 @@ insert =
.refui-requires-int-90 = Requires an integer between -90 and 90.
.refui-xref-fading = Xref fading
.refui-edit-reference = Edit Reference
.refui-edit-reference-in-place =
Edit Reference
In-Place
.refui-open-reference =
Open
Reference
.refui-snap-to-underlays-off = Snap to Underlays OFF
.refui-snap-to-underlays-on = Snap to Underlays ON
.refui-snap-to-underlays = Snap to Underlays
+6
View File
@@ -3573,6 +3573,12 @@ insert =
.refui-requires-int-90 = Requires an integer between -90 and 90.
.refui-xref-fading = Xref fading
.refui-edit-reference = Edit Reference
.refui-edit-reference-in-place =
Edit Reference
In-Place
.refui-open-reference =
Open
Reference
.refui-snap-to-underlays-off = Snap to Underlays OFF
.refui-snap-to-underlays-on = Snap to Underlays ON
.refui-snap-to-underlays = Snap to Underlays
+6
View File
@@ -3573,6 +3573,12 @@ insert =
.refui-requires-int-90 = Requires an integer between -90 and 90.
.refui-xref-fading = Xref fading
.refui-edit-reference = Edit Reference
.refui-edit-reference-in-place =
Edit Reference
In-Place
.refui-open-reference =
Open
Reference
.refui-snap-to-underlays-off = Snap to Underlays OFF
.refui-snap-to-underlays-on = Snap to Underlays ON
.refui-snap-to-underlays = Snap to Underlays
+6
View File
@@ -3564,6 +3564,12 @@ insert =
.refui-requires-int-90 = Requires an integer between -90 and 90.
.refui-xref-fading = Xref fading
.refui-edit-reference = Edit Reference
.refui-edit-reference-in-place =
Edit Reference
In-Place
.refui-open-reference =
Open
Reference
.refui-snap-to-underlays-off = Snap to Underlays OFF
.refui-snap-to-underlays-on = Snap to Underlays ON
.refui-snap-to-underlays = Snap to Underlays
+6
View File
@@ -3573,6 +3573,12 @@ insert =
.refui-requires-int-90 = Requires an integer between -90 and 90.
.refui-xref-fading = Xref fading
.refui-edit-reference = Edit Reference
.refui-edit-reference-in-place =
Edit Reference
In-Place
.refui-open-reference =
Open
Reference
.refui-snap-to-underlays-off = Snap to Underlays OFF
.refui-snap-to-underlays-on = Snap to Underlays ON
.refui-snap-to-underlays = Snap to Underlays
+6
View File
@@ -3572,6 +3572,12 @@ insert =
.refui-requires-int-90 = Requires an integer between -90 and 90.
.refui-xref-fading = Xref fading
.refui-edit-reference = Edit Reference
.refui-edit-reference-in-place =
Edit Reference
In-Place
.refui-open-reference =
Open
Reference
.refui-snap-to-underlays-off = Snap to Underlays OFF
.refui-snap-to-underlays-on = Snap to Underlays ON
.refui-snap-to-underlays = Snap to Underlays
+6
View File
@@ -3573,6 +3573,12 @@ insert =
.refui-requires-int-90 = Requires an integer between -90 and 90.
.refui-xref-fading = Xref fading
.refui-edit-reference = Edit Reference
.refui-edit-reference-in-place =
Edit Reference
In-Place
.refui-open-reference =
Open
Reference
.refui-snap-to-underlays-off = Snap to Underlays OFF
.refui-snap-to-underlays-on = Snap to Underlays ON
.refui-snap-to-underlays = Snap to Underlays
+6
View File
@@ -3574,6 +3574,12 @@ insert =
.refui-requires-int-90 = Requires an integer between -90 and 90.
.refui-xref-fading = Xref fading
.refui-edit-reference = Edit Reference
.refui-edit-reference-in-place =
Edit Reference
In-Place
.refui-open-reference =
Open
Reference
.refui-snap-to-underlays-off = Snap to Underlays OFF
.refui-snap-to-underlays-on = Snap to Underlays ON
.refui-snap-to-underlays = Snap to Underlays
+6
View File
@@ -3575,6 +3575,12 @@ insert =
.refui-requires-int-90 = Requires an integer between -90 and 90.
.refui-xref-fading = Xref fading
.refui-edit-reference = Edit Reference
.refui-edit-reference-in-place =
Edit Reference
In-Place
.refui-open-reference =
Open
Reference
.refui-snap-to-underlays-off = Snap to Underlays OFF
.refui-snap-to-underlays-on = Snap to Underlays ON
.refui-snap-to-underlays = Snap to Underlays
+7 -1
View File
@@ -3548,6 +3548,12 @@ insert =
.refui-requires-int-90 = -90 ile 90 arasında bir tam sayı gerekir.
.refui-xref-fading = Xref soldurma
.refui-edit-reference = Referansı Düzenle
.refui-edit-reference-in-place =
Yerinde Referansı
Düzenle
.refui-open-reference =
Referansı
Aç
.refui-snap-to-underlays-off = Altlıklara Yakala Kapalı
.refui-snap-to-underlays-on = Altlıklara Yakala Açık
.refui-snap-to-underlays = Altlıklara Yakala
@@ -4501,7 +4507,7 @@ properties =
.extended-lighting = Gelişmiş Aydınlatma
.extents-max = En Büyük Sınırlar
.extents-min = En Küçük Sınırlar
.external-reference = Dış Referans
.external-reference = Harici Referans
.face = Yüz
.face-count = Yüz sayısı
.falloff-angle = Düşüş Açısı
+6
View File
@@ -3561,6 +3561,12 @@ insert =
.refui-requires-int-90 = Requires an integer between -90 and 90.
.refui-xref-fading = Xref fading
.refui-edit-reference = Edit Reference
.refui-edit-reference-in-place =
Edit Reference
In-Place
.refui-open-reference =
Open
Reference
.refui-snap-to-underlays-off = Snap to Underlays OFF
.refui-snap-to-underlays-on = Snap to Underlays ON
.refui-snap-to-underlays = Snap to Underlays
+6
View File
@@ -3573,6 +3573,12 @@ insert =
.refui-requires-int-90 = Requires an integer between -90 and 90.
.refui-xref-fading = Xref fading
.refui-edit-reference = Edit Reference
.refui-edit-reference-in-place =
Edit Reference
In-Place
.refui-open-reference =
Open
Reference
.refui-snap-to-underlays-off = Snap to Underlays OFF
.refui-snap-to-underlays-on = Snap to Underlays ON
.refui-snap-to-underlays = Snap to Underlays
+59 -2
View File
@@ -20,9 +20,31 @@ impl OpenCADStudio {
out
}
/// Show the tab while only PDF underlays are selected.
/// The selected xrefs, or nothing when anything else is selected.
pub(in crate::app) fn selected_xrefs(&self, i: usize) -> Vec<codec::Handle> {
let doc = &self.tabs[i].scene.document;
let mut out = Vec::new();
for (handle, entity) in self.tabs[i].scene.selected_entities() {
let xref = match entity {
codec::EntityType::Insert(ins) => doc
.block_records
.get(&ins.block_name)
.is_some_and(|br| br.flags.is_xref || br.flags.is_xref_overlay),
_ => false,
};
if !xref {
return Vec::new();
}
out.push(handle);
}
out
}
/// Show the PDF Underlay tab while only PDF underlays are selected, the
/// External Reference tab while only xrefs are.
pub(in crate::app) fn sync_underlay_tab(&mut self) {
let i = self.active_tab;
let xref = !self.tabs[i].is_start && !self.selected_xrefs(i).is_empty();
let context = if self.tabs[i].is_start {
None
} else {
@@ -36,7 +58,7 @@ impl OpenCADStudio {
)
})
};
self.ribbon.set_underlay_context(context);
self.ribbon.set_underlay_context(context, xref);
}
/// One undo step that edits every selected PDF underlay.
@@ -127,6 +149,41 @@ impl OpenCADStudio {
self.tabs[i].scene.reseed_underlays();
self.sync_underlay_tab();
}
// External Reference tab: the selected xrefs.
"_XREFEDIT" | "_XREFOPEN" => {
let Some(&handle) = self.selected_xrefs(i).first() else {
return Some(Task::none());
};
self.tabs[i].scene.deselect_all();
self.tabs[i].scene.select_entity(handle, true);
let command = if cmd == "_XREFEDIT" { "REFEDIT" } else { "XOPEN" };
return Some(self.dispatch_command(command));
}
"_XREFCLIP" => {
use crate::command::CadCommand;
let inserts = self.selected_xrefs(i);
if inserts.is_empty() {
return Some(Task::none());
}
let clipped = inserts.iter().any(|h| {
crate::scene::pick::xclip::filter_handle(&self.tabs[i].scene.document, *h).is_some()
});
let (command, first) =
crate::modules::insert::xclip::XclipCommand::start_new_boundary(inserts, clipped);
if let crate::command::CmdResult::ReportMeasurement(text) = first {
for line in text.lines() {
self.command_line.push_output(line);
}
}
self.command_line.push_info(&command.prompt());
self.tabs[i].active_cmd = Some(Box::new(command));
}
"_XREFUNCLIP" => {
let inserts = self.selected_xrefs(i);
if !inserts.is_empty() {
self.apply_xclip(i, inserts, crate::modules::insert::xclip::XclipAction::Delete);
}
}
"_PDFULUNCLIP" => {
self.edit_selected_underlays(i, "PDFCLIP", |u| {
u.clip_boundary_vertices.clear();
+2
View File
@@ -2950,6 +2950,8 @@ pub(super) fn message_attribute(source: &str) -> Option<(&'static str, &'static
"Snap to Underlays ON" => Some(("insert", "refui-snap-to-underlays-on")),
"Snap to Underlays OFF" => Some(("insert", "refui-snap-to-underlays-off")),
"Edit Reference" => Some(("insert", "refui-edit-reference")),
"Edit Reference\nIn-Place" => Some(("insert", "refui-edit-reference-in-place")),
"Open\nReference" => Some(("insert", "refui-open-reference")),
"Xref fading" => Some(("insert", "refui-xref-fading")),
"Requires an integer between -90 and 90." => Some(("insert", "refui-requires-int-90")),
"Underlay" => Some(("properties", "underlay")),
+9
View File
@@ -103,6 +103,15 @@ impl XclipCommand {
}
}
/// A new boundary for block references already chosen (the External
/// Reference tab's Create Clipping Boundary): the New boundary branch at
/// once. Returns the command and the result of its first step.
pub fn start_new_boundary(inserts: Vec<Handle>, clipped: bool) -> (Self, CmdResult) {
let mut command = Self::for_inserts(inserts, clipped);
let first = command.option("N");
(command, first)
}
fn act(&self, action: XclipAction) -> CmdResult {
CmdResult::XClip {
inserts: self.inserts.clone(),
+8 -5
View File
@@ -109,6 +109,8 @@ pub struct Ribbon {
underlay_ctx: Option<UnderlayContext>,
/// The contextual underlay tab is the one shown.
underlay_tab_active: bool,
/// Only xrefs are selected: the External Reference tab is offered.
xref_ctx: bool,
/// XDWGFADECTL as the Reference slide-out shows it (negative = off).
pub xref_fade: i32,
}
@@ -206,6 +208,7 @@ impl Ribbon {
collapse_tight: Arc::new(AtomicBool::new(false)),
underlay_ctx: None,
underlay_tab_active: false,
xref_ctx: false,
xref_fade: 50,
}
}
@@ -589,8 +592,8 @@ impl Ribbon {
);
let mut tab_items = tab_items;
if self.underlay_ctx.is_some() {
tab_items.push(underlay_tab_button(self.underlay_tab_shown()));
if let Some(title) = self.contextual_tab() {
tab_items.push(underlay_tab_button(title, self.underlay_tab_shown()));
}
// Tabs may squeeze their gaps to fit before wrapping: from the normal 6px
@@ -1627,9 +1630,9 @@ mod tests {
}
}
/// The contextual underlay tab's button: framed in the accent colour.
fn underlay_tab_button<'a>(active: bool) -> Element<'a, Message> {
let btn = button(text(t!("PDF Underlay")).size(12))
/// The contextual tab's button: framed in the accent colour.
fn underlay_tab_button<'a>(title: &'static str, active: bool) -> Element<'a, Message> {
let btn = button(text(t!(title)).size(12))
.on_press(Message::RibbonSelectUnderlayTab)
.style(move |theme: &Theme, status| {
let palette = theme.palette();
+73 -14
View File
@@ -1,5 +1,6 @@
//! The contextual "PDF Underlay" tab: shown and brought forward while only
//! PDF underlays are selected, gone when the selection changes.
//! The contextual tabs: "PDF Underlay" while only PDF underlays are
//! selected, "External Reference" while only xrefs are; shown and brought
//! forward with the selection, gone when it changes.
use iced::widget::{column, row, slider, text, text_input};
use iced::{Element, Length};
@@ -112,6 +113,47 @@ fn groups() -> &'static [RibbonGroup] {
})
}
/// The External Reference tab: edit or open the reference, clip it, and the
/// External References palette.
fn xref_groups() -> &'static [RibbonGroup] {
static GROUPS: std::sync::OnceLock<Vec<RibbonGroup>> = std::sync::OnceLock::new();
const CLIP: &[u8] = include_bytes!("../../../assets/icons/xclip.svg");
GROUPS.get_or_init(|| {
vec![
RibbonGroup {
title: "Edit",
tools: vec![
RibbonItem::LargeTool(tool(
"_XREFEDIT",
"Edit Reference\nIn-Place",
include_bytes!("../../../assets/icons/edit_block.svg"),
)),
RibbonItem::LargeTool(tool(
"_XREFOPEN",
"Open\nReference",
crate::ui::icons::FOLDER_OPEN,
)),
],
},
RibbonGroup {
title: "Clipping",
tools: vec![
RibbonItem::LargeTool(tool("_XREFCLIP", "Create Clipping\nBoundary", CLIP)),
RibbonItem::LargeTool(tool("_XREFUNCLIP", "Remove\nClipping", CLIP)),
],
},
RibbonGroup {
title: "Options",
tools: vec![RibbonItem::LargeTool(tool(
"EXTERNALREFERENCES",
"External\nReferences",
crate::ui::icons::FOLDER_OPEN,
))],
},
]
})
}
/// Contrast / Fade: a label, a 0–100 slider and the value box.
fn adjust_rows<'a>(ctx: &'a UnderlayContext) -> Element<'a, Message> {
let line = |label: &'static str,
@@ -156,15 +198,16 @@ fn adjust_rows<'a>(ctx: &'a UnderlayContext) -> Element<'a, Message> {
}
impl Ribbon {
/// Show the tab for the selected underlay, or drop it (`None`). A tab
/// that appears comes to the front; one that goes returns the tab that
/// was active before it.
pub fn set_underlay_context(&mut self, context: Option<UnderlayContext>) {
match (&self.underlay_ctx, &context) {
(None, Some(_)) => self.underlay_tab_active = true,
(Some(_), None) => self.underlay_tab_active = false,
_ => {}
/// Show the tab for the selected underlay (`context`) or the selected
/// xrefs (`xref`), or drop it. A tab that appears comes to the front;
/// one that goes returns the tab that was active before it.
pub fn set_underlay_context(&mut self, context: Option<UnderlayContext>, xref: bool) {
let before = (self.underlay_ctx.is_some(), self.xref_ctx);
let after = (context.is_some(), xref);
if before != after {
self.underlay_tab_active = after.0 || after.1;
}
self.xref_ctx = xref;
// A value being typed survives a refresh that leaves the value as is.
let mut context = context;
if let (Some(old), Some(new)) = (&self.underlay_ctx, &mut context) {
@@ -180,9 +223,10 @@ impl Ribbon {
self.underlay_ctx.as_mut()
}
/// Select a tab by its module id; "pdf_underlay" is the contextual tab.
/// Select a tab by its module id; "pdf_underlay" and "xref" are the
/// contextual tabs.
pub fn select_by_id(&mut self, id: &str) -> bool {
if id == "pdf_underlay" {
if (id == "pdf_underlay" && self.underlay_ctx.is_some()) || (id == "xref" && self.xref_ctx) {
self.select_underlay_tab();
return self.underlay_tab_active;
}
@@ -196,13 +240,22 @@ impl Ribbon {
}
pub fn select_underlay_tab(&mut self) {
if self.underlay_ctx.is_some() {
if self.contextual_tab().is_some() {
self.underlay_tab_active = true;
}
}
pub(super) fn underlay_tab_shown(&self) -> bool {
self.underlay_tab_active && self.underlay_ctx.is_some()
self.underlay_tab_active && self.contextual_tab().is_some()
}
/// The contextual tab's title, while one is offered.
pub(super) fn contextual_tab(&self) -> Option<&'static str> {
if self.xref_ctx {
Some("External Reference")
} else {
self.underlay_ctx.as_ref().map(|_| "PDF Underlay")
}
}
pub(super) fn underlay_panels<'a>(
@@ -210,6 +263,12 @@ impl Ribbon {
ts: widgets::ToggleState,
style_ctx: &StyleContext<'_>,
) -> Vec<Panel<'a>> {
if self.xref_ctx {
return xref_groups()
.iter()
.map(|g| self.panel(g, ts, style_ctx, &|_| Vec::new()))
.collect();
}
let Some(ctx) = self.underlay_ctx.as_ref() else {
return Vec::new();
};