forked from 1b-agent/opencadstudio-upstream
Merge pull request #1486 from ramox81/codex/xref-context-tab
Selection tools on the right-edge toolbar for PDF underlays and xrefs
This commit is contained in:
commit
82fe204a70
34 files changed
+387
-353
No files matched your search
@@ -0,0 +1,9 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="64" height="64" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<rect x="4" y="4" width="16" height="16" rx="1" stroke="#B4B6B9" stroke-width="1.5" stroke-dasharray="3 2"/>
|
||||
<polygon points="4,4 14,4 14,14 4,14" fill="#6DB7ED" fill-opacity="0.15" stroke="#6DB7ED" stroke-width="1.5"/>
|
||||
<line x1="14" y1="4" x2="14" y2="20" stroke="#6DB7ED" stroke-width="1.5" stroke-dasharray="3 2"/>
|
||||
<line x1="4" y1="14" x2="20" y2="14" stroke="#6DB7ED" stroke-width="1.5" stroke-dasharray="3 2"/>
|
||||
<circle cx="19" cy="19" r="4.3" fill="#1a1a1a"/>
|
||||
<line x1="16.9" y1="16.9" x2="21.1" y2="21.1" stroke="#E53935" stroke-width="1.9"/>
|
||||
<line x1="21.1" y1="16.9" x2="16.9" y2="21.1" stroke="#E53935" stroke-width="1.9"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 797 B |
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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ı
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
//! The contextual PDF Underlay ribbon tab: its values come from the selected
|
||||
//! underlays, its buttons edit them.
|
||||
//! The right-edge PDF underlay and xref tools: their state comes from the
|
||||
//! selection, their buttons edit it.
|
||||
|
||||
use super::*;
|
||||
use codec::entities::{Underlay, UnderlayDisplayFlags, UnderlayType};
|
||||
use crate::ui::ribbon::{UnderlayContext, UnderlayTabMsg};
|
||||
use crate::ui::ribbon::UnderlayContext;
|
||||
|
||||
impl OpenCADStudio {
|
||||
/// The selected PDF underlays, or nothing when anything else is selected.
|
||||
@@ -20,23 +20,44 @@ 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
|
||||
}
|
||||
|
||||
/// The selection context for the right-edge tools: the selected PDF
|
||||
/// underlay's switches while only underlays are selected, or that 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 {
|
||||
self.selected_pdf_underlays(i).first().map(|(_, u)| {
|
||||
UnderlayContext::new(
|
||||
u.contrast,
|
||||
u.fade,
|
||||
u.flags.contains(UnderlayDisplayFlags::MONOCHROME),
|
||||
u.flags.contains(UnderlayDisplayFlags::ON),
|
||||
crate::scene::model::pdf_vector::pdf_osnap(),
|
||||
)
|
||||
UnderlayContext {
|
||||
monochrome: u.flags.contains(UnderlayDisplayFlags::MONOCHROME),
|
||||
shown: u.flags.contains(UnderlayDisplayFlags::ON),
|
||||
snap: crate::scene::model::pdf_vector::pdf_osnap(),
|
||||
}
|
||||
})
|
||||
};
|
||||
self.ribbon.set_underlay_context(context);
|
||||
self.ribbon.set_underlay_context(context, xref);
|
||||
}
|
||||
|
||||
/// One undo step that edits every selected PDF underlay.
|
||||
@@ -68,43 +89,7 @@ impl OpenCADStudio {
|
||||
self.refresh_properties();
|
||||
}
|
||||
|
||||
pub(in crate::app) fn update_underlay_tab(&mut self, message: UnderlayTabMsg) -> Task<Message> {
|
||||
let i = self.active_tab;
|
||||
let Some(ctx) = self.ribbon.underlay_context_mut() else {
|
||||
return Task::none();
|
||||
};
|
||||
match message {
|
||||
UnderlayTabMsg::Contrast(v) => {
|
||||
ctx.contrast = v;
|
||||
ctx.contrast_text = v.to_string();
|
||||
}
|
||||
UnderlayTabMsg::Fade(v) => {
|
||||
ctx.fade = v;
|
||||
ctx.fade_text = v.to_string();
|
||||
}
|
||||
UnderlayTabMsg::ContrastText(s) => ctx.contrast_text = s,
|
||||
UnderlayTabMsg::FadeText(s) => ctx.fade_text = s,
|
||||
UnderlayTabMsg::Commit => {
|
||||
// A typed value outside 0–100 or not a number keeps the value.
|
||||
let parse = |s: &str, old: u8| {
|
||||
s.trim().parse::<u8>().ok().filter(|v| *v <= 100).unwrap_or(old)
|
||||
};
|
||||
let (contrast, fade) = (
|
||||
parse(&ctx.contrast_text, ctx.contrast),
|
||||
parse(&ctx.fade_text, ctx.fade),
|
||||
);
|
||||
ctx.contrast_text = contrast.to_string();
|
||||
ctx.fade_text = fade.to_string();
|
||||
self.edit_selected_underlays(i, "PDFADJUST", |u| {
|
||||
u.set_contrast(contrast);
|
||||
u.set_fade(fade);
|
||||
});
|
||||
}
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
|
||||
/// The tab's buttons (host-only command names).
|
||||
/// The right-edge tools (host-only command names).
|
||||
pub(super) fn dispatch_pdf_underlay(&mut self, cmd: &str, i: usize) -> Option<Task<Message>> {
|
||||
match cmd {
|
||||
"_PDFULMONO" => {
|
||||
@@ -127,6 +112,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();
|
||||
|
||||
@@ -700,8 +700,7 @@ impl OpenCADStudio {
|
||||
state.selected = pages;
|
||||
return Ok(Task::none());
|
||||
}
|
||||
// Bring a ribbon tab forward by module id ("pdf_underlay" for the
|
||||
// contextual underlay tab).
|
||||
// Bring a ribbon tab forward by module id.
|
||||
"ribbon_tab" => {
|
||||
let id = string(req, "value")?;
|
||||
if !self.ribbon.select_by_id(id) {
|
||||
|
||||
@@ -3838,11 +3838,8 @@ pub enum Message {
|
||||
PdfAttachPick,
|
||||
/// PDFIMPORT File: pick the PDF to import.
|
||||
PdfImportPick,
|
||||
/// The contextual PDF Underlay tab.
|
||||
RibbonSelectUnderlayTab,
|
||||
/// An edit in one of the PDF dialogs.
|
||||
PdfDialog(crate::ui::window::pdf_dialogs::PdfDialogMsg),
|
||||
UnderlayTab(crate::ui::ribbon::UnderlayTabMsg),
|
||||
PdfImportPickResult(Result<(std::path::PathBuf, std::sync::Arc<Vec<u8>>), String>),
|
||||
/// Result of the PDFATTACH file picker.
|
||||
PdfAttachPickResult(Result<(std::path::PathBuf, std::sync::Arc<Vec<u8>>), String>),
|
||||
|
||||
+12
-5
@@ -318,6 +318,18 @@ impl OpenCADStudio {
|
||||
}
|
||||
|
||||
pub fn update(&mut self, msg: Message) -> Task<Message> {
|
||||
// Whatever makes another document active (switching, opening,
|
||||
// creating or closing a tab), the contextual ribbon tab follows that
|
||||
// document's selection.
|
||||
let before = self.tabs.get(self.active_tab).map(|tab| tab.id);
|
||||
let task = self.update_message(msg);
|
||||
if self.tabs.get(self.active_tab).map(|tab| tab.id) != before {
|
||||
self.sync_underlay_tab();
|
||||
}
|
||||
task
|
||||
}
|
||||
|
||||
fn update_message(&mut self, msg: Message) -> Task<Message> {
|
||||
if let Some(tab) = self.tabs.get(self.active_tab) {
|
||||
crate::entities::common::set_unit_context(
|
||||
crate::entities::common::UnitContext::from_header(&tab.scene.document.header),
|
||||
@@ -1772,11 +1784,6 @@ impl OpenCADStudio {
|
||||
Task::none()
|
||||
}
|
||||
|
||||
Message::RibbonSelectUnderlayTab => {
|
||||
self.ribbon.select_underlay_tab();
|
||||
Task::none()
|
||||
}
|
||||
Message::UnderlayTab(message) => self.update_underlay_tab(message),
|
||||
Message::PdfDialog(message) => self.update_pdf_dialog(message),
|
||||
Message::RibbonSelectTab(idx) => {
|
||||
self.ribbon.select(idx);
|
||||
|
||||
+26
-3
@@ -1601,9 +1601,32 @@ bg={bg_ms:.1}ms n={view_count}"
|
||||
}
|
||||
}
|
||||
|
||||
// Paper-space context actions: a right-edge vertical toolbar
|
||||
// (viewport / page setup / plot) instead of a contextual ribbon tab.
|
||||
if is_paper && !tab.is_start {
|
||||
// Selection actions: with only PDF underlays or only xrefs
|
||||
// selected, their tools take the right edge (over the paper-space
|
||||
// tools, which come back when the selection changes).
|
||||
// ponytail: one right-edge toolbar at a time; stack them if both
|
||||
// are ever needed together.
|
||||
let selection_tools = if tab.is_start {
|
||||
None
|
||||
} else if self.ribbon.xref_context() {
|
||||
crate::ui::side_toolbar::view(&crate::ui::ribbon::xref_tools())
|
||||
} else if let Some(ctx) = self.ribbon.underlay_context() {
|
||||
let ctx = ctx.clone();
|
||||
crate::ui::side_toolbar::view_with_active(
|
||||
&crate::ui::ribbon::pdf_underlay_tools(),
|
||||
&move |id| match id {
|
||||
"_PDFULMONO" => ctx.monochrome,
|
||||
"_PDFULSHOW" => ctx.shown,
|
||||
"_PDFULSNAP" => ctx.snap,
|
||||
_ => false,
|
||||
},
|
||||
)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
if let Some(tb) = selection_tools {
|
||||
viewport_stack = viewport_stack.push(tb);
|
||||
} else if is_paper && !tab.is_start {
|
||||
if let Some(tb) =
|
||||
crate::ui::side_toolbar::view(&crate::modules::layout::paper_space_tools())
|
||||
{
|
||||
|
||||
@@ -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")),
|
||||
|
||||
@@ -109,6 +109,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(),
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
//! Selection-driven tools: while only PDF underlays (or only xrefs) are
|
||||
//! selected their actions show on the right-edge toolbar; they go when the
|
||||
//! selection changes. Contrast and fade stay in the Properties panel.
|
||||
|
||||
use super::*;
|
||||
use crate::modules::{ModuleEvent, ToolDef};
|
||||
|
||||
/// The switches of the selected underlay (the first one) the toolbar shows
|
||||
/// as on.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct UnderlayContext {
|
||||
pub monochrome: bool,
|
||||
pub shown: bool,
|
||||
pub snap: bool,
|
||||
}
|
||||
|
||||
fn tool(id: &'static str, label: &'static str, icon: &'static [u8]) -> ToolDef {
|
||||
ToolDef {
|
||||
id,
|
||||
label,
|
||||
icon: IconKind::Svg(icon),
|
||||
event: ModuleEvent::Command(id.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
const CLIP: &[u8] = include_bytes!("../../../assets/icons/xclip.svg");
|
||||
/// The clip icon with a small red cross at its lower right.
|
||||
const UNCLIP: &[u8] = include_bytes!("../../../assets/icons/xclip_remove.svg");
|
||||
|
||||
/// PDF underlay tools: display, clipping, options, layers and import.
|
||||
pub fn pdf_underlay_tools() -> Vec<ToolDef> {
|
||||
const FRAMES: &[u8] = include_bytes!("../../../assets/icons/underlay_frames.svg");
|
||||
vec![
|
||||
tool("_PDFULMONO", "Display in\nMonochrome", FRAMES),
|
||||
tool("_PDFULCLIP", "Create Clipping\nBoundary", CLIP),
|
||||
tool("_PDFULUNCLIP", "Remove\nClipping", UNCLIP),
|
||||
tool("_PDFULSHOW", "Show\nUnderlay", FRAMES),
|
||||
tool(
|
||||
"_PDFULSNAP",
|
||||
"Enable\nSnap",
|
||||
include_bytes!("../../../assets/icons/snap_underlays.svg"),
|
||||
),
|
||||
tool("EXTERNALREFERENCES", "External\nReferences", crate::ui::icons::FOLDER_OPEN),
|
||||
tool(
|
||||
"ULAYERS",
|
||||
"Edit\nLayers",
|
||||
include_bytes!("../../../assets/icons/underlay_layers.svg"),
|
||||
),
|
||||
tool(
|
||||
"_PDFULIMPORT",
|
||||
"Import As\nObjects",
|
||||
include_bytes!("../../../assets/icons/cui_import.svg"),
|
||||
),
|
||||
]
|
||||
}
|
||||
|
||||
/// External reference tools: edit, open, clipping and the palette.
|
||||
pub fn xref_tools() -> Vec<ToolDef> {
|
||||
vec![
|
||||
tool(
|
||||
"_XREFEDIT",
|
||||
"Edit Reference\nIn-Place",
|
||||
include_bytes!("../../../assets/icons/edit_block.svg"),
|
||||
),
|
||||
tool("_XREFOPEN", "Open\nReference", crate::ui::icons::FOLDER_OPEN),
|
||||
tool("_XREFCLIP", "Create Clipping\nBoundary", CLIP),
|
||||
tool("_XREFUNCLIP", "Remove\nClipping", UNCLIP),
|
||||
tool("EXTERNALREFERENCES", "External\nReferences", crate::ui::icons::FOLDER_OPEN),
|
||||
]
|
||||
}
|
||||
|
||||
impl Ribbon {
|
||||
/// The selection context: the selected underlay's switches, or that
|
||||
/// only xrefs are selected, or neither.
|
||||
pub fn set_underlay_context(&mut self, context: Option<UnderlayContext>, xref: bool) {
|
||||
self.underlay_ctx = context;
|
||||
self.xref_ctx = xref;
|
||||
}
|
||||
|
||||
pub fn underlay_context(&self) -> Option<&UnderlayContext> {
|
||||
self.underlay_ctx.as_ref()
|
||||
}
|
||||
|
||||
pub fn xref_context(&self) -> bool {
|
||||
self.xref_ctx
|
||||
}
|
||||
|
||||
/// Select a tab by its module id.
|
||||
pub fn select_by_id(&mut self, id: &str) -> bool {
|
||||
match self.modules.iter().position(|m| m.id() == id) {
|
||||
Some(index) => {
|
||||
self.select(index);
|
||||
true
|
||||
}
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
-50
@@ -25,8 +25,8 @@ mod draw_panel;
|
||||
pub(crate) use draw_panel::tools as panel_tools;
|
||||
mod modify_panel;
|
||||
mod color_dropdown;
|
||||
mod underlay_tab;
|
||||
pub use underlay_tab::{UnderlayContext, UnderlayTabMsg};
|
||||
mod context_tools;
|
||||
pub use context_tools::{pdf_underlay_tools, xref_tools, UnderlayContext};
|
||||
use widgets::{StyleContext, *};
|
||||
pub(crate) use widgets::{REDO_HISTORY_ID, UNDO_HISTORY_ID};
|
||||
mod collapse;
|
||||
@@ -105,10 +105,10 @@ pub struct Ribbon {
|
||||
/// Set by `CollapsePanels` when the tool row is in its tight state; the mode
|
||||
/// selector hides itself then to give the cramped tab row its space back.
|
||||
collapse_tight: Arc<AtomicBool>,
|
||||
/// The selected PDF underlay's values while the contextual tab exists.
|
||||
/// The selected PDF underlay's switches while only underlays are selected.
|
||||
underlay_ctx: Option<UnderlayContext>,
|
||||
/// The contextual underlay tab is the one shown.
|
||||
underlay_tab_active: bool,
|
||||
/// Only xrefs are selected.
|
||||
xref_ctx: bool,
|
||||
/// XDWGFADECTL as the Reference slide-out shows it (negative = off).
|
||||
pub xref_fade: i32,
|
||||
}
|
||||
@@ -205,7 +205,7 @@ impl Ribbon {
|
||||
collapse_mode: CollapseMode::default(),
|
||||
collapse_tight: Arc::new(AtomicBool::new(false)),
|
||||
underlay_ctx: None,
|
||||
underlay_tab_active: false,
|
||||
xref_ctx: false,
|
||||
xref_fade: 50,
|
||||
}
|
||||
}
|
||||
@@ -284,7 +284,6 @@ impl Ribbon {
|
||||
pub fn select(&mut self, index: usize) {
|
||||
if index < self.modules.len() {
|
||||
self.active = index;
|
||||
self.underlay_tab_active = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -348,9 +347,6 @@ impl Ribbon {
|
||||
show_block_palette,
|
||||
show_file_tabs: self.show_file_tabs,
|
||||
show_layout_tabs: self.show_layout_tabs,
|
||||
underlay_mono: self.underlay_ctx.as_ref().is_some_and(|c| c.monochrome),
|
||||
underlay_shown: self.underlay_ctx.as_ref().is_some_and(|c| c.shown),
|
||||
underlay_snap: self.underlay_ctx.as_ref().is_some_and(|c| c.snap),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -518,7 +514,7 @@ impl Ribbon {
|
||||
return acc;
|
||||
}
|
||||
|
||||
let is_active = i == self.active && !self.underlay_tab_shown();
|
||||
let is_active = i == self.active;
|
||||
let is_contextual = module.id() == "layout";
|
||||
let btn = container(
|
||||
button(text(crate::i18n::ribbon_module_title(module.id(), module.title())).size(12))
|
||||
@@ -588,10 +584,6 @@ impl Ribbon {
|
||||
},
|
||||
);
|
||||
|
||||
let mut tab_items = tab_items;
|
||||
if self.underlay_ctx.is_some() {
|
||||
tab_items.push(underlay_tab_button(self.underlay_tab_shown()));
|
||||
}
|
||||
|
||||
// Tabs may squeeze their gaps to fit before wrapping: from the normal 6px
|
||||
// down to -12px on a narrow (e.g. phone) tab row, tucking neighbours into
|
||||
@@ -673,14 +665,10 @@ impl Ribbon {
|
||||
// shrink to compact icon columns, then it collapses to a ▾ flyout
|
||||
// button. See `CollapsePanels`.
|
||||
let ts = self.toggle_state(show_block_palette);
|
||||
let panels: Vec<Panel<'_>> = if self.underlay_tab_shown() {
|
||||
self.underlay_panels(ts, &style_ctx)
|
||||
} else {
|
||||
groups
|
||||
.iter()
|
||||
.map(|g| self.panel(g, ts, &style_ctx, &|_| Vec::new()))
|
||||
.collect()
|
||||
};
|
||||
let panels: Vec<Panel<'_>> = groups
|
||||
.iter()
|
||||
.map(|g| self.panel(g, ts, &style_ctx, &|_| Vec::new()))
|
||||
.collect();
|
||||
CollapsePanels::new(panels, self.collapsed_open.clone(), TOOL_BAR_H)
|
||||
.report_height(self.tool_bar_h.clone())
|
||||
.report_tight(self.collapse_tight.clone())
|
||||
@@ -1627,30 +1615,3 @@ 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))
|
||||
.on_press(Message::RibbonSelectUnderlayTab)
|
||||
.style(move |theme: &Theme, status| {
|
||||
let palette = theme.palette();
|
||||
let pair = match (active, status) {
|
||||
(true, _) => palette.background.weakest,
|
||||
(false, button::Status::Hovered) => palette.background.weak,
|
||||
_ => palette.background.base,
|
||||
};
|
||||
button::Style {
|
||||
background: (active || matches!(status, button::Status::Hovered))
|
||||
.then_some(Background::Color(pair.color)),
|
||||
text_color: if active { pair.text } else { palette.primary.base.color },
|
||||
border: Border {
|
||||
color: palette.primary.base.color,
|
||||
width: if active { 2.0 } else { 1.0 },
|
||||
radius: 0.0.into(),
|
||||
},
|
||||
shadow: iced::Shadow::default(),
|
||||
snap: false,
|
||||
}
|
||||
})
|
||||
.padding([5, 14]);
|
||||
container(btn).into()
|
||||
}
|
||||
@@ -1,230 +0,0 @@
|
||||
//! The contextual "PDF Underlay" tab: shown and brought forward while only
|
||||
//! PDF underlays are selected, gone when the selection changes.
|
||||
|
||||
use iced::widget::{column, row, slider, text, text_input};
|
||||
use iced::{Element, Length};
|
||||
|
||||
use super::*;
|
||||
use crate::modules::{ModuleEvent, ToolDef};
|
||||
|
||||
/// What the tab shows for the selected underlay (the first one).
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct UnderlayContext {
|
||||
pub contrast: u8,
|
||||
pub fade: u8,
|
||||
pub monochrome: bool,
|
||||
pub shown: bool,
|
||||
pub snap: bool,
|
||||
pub contrast_text: String,
|
||||
pub fade_text: String,
|
||||
}
|
||||
|
||||
impl UnderlayContext {
|
||||
pub fn new(contrast: u8, fade: u8, monochrome: bool, shown: bool, snap: bool) -> Self {
|
||||
Self {
|
||||
contrast,
|
||||
fade,
|
||||
monochrome,
|
||||
shown,
|
||||
snap,
|
||||
contrast_text: contrast.to_string(),
|
||||
fade_text: fade.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The tab's edits; the host writes them to the selected underlays.
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum UnderlayTabMsg {
|
||||
Contrast(u8),
|
||||
Fade(u8),
|
||||
ContrastText(String),
|
||||
FadeText(String),
|
||||
/// Slider released or value submitted: write contrast and fade.
|
||||
Commit,
|
||||
}
|
||||
|
||||
pub(super) const ADJUST: &str = "Adjust";
|
||||
|
||||
fn tool(id: &'static str, label: &'static str, icon: &'static [u8]) -> ToolDef {
|
||||
ToolDef {
|
||||
id,
|
||||
label,
|
||||
icon: IconKind::Svg(icon),
|
||||
event: ModuleEvent::Command(id.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
fn groups() -> &'static [RibbonGroup] {
|
||||
static GROUPS: std::sync::OnceLock<Vec<RibbonGroup>> = std::sync::OnceLock::new();
|
||||
const FRAMES: &[u8] = include_bytes!("../../../assets/icons/underlay_frames.svg");
|
||||
const CLIP: &[u8] = include_bytes!("../../../assets/icons/xclip.svg");
|
||||
GROUPS.get_or_init(|| {
|
||||
vec![
|
||||
RibbonGroup {
|
||||
title: ADJUST,
|
||||
tools: vec![RibbonItem::LargeTool(tool(
|
||||
"_PDFULMONO",
|
||||
"Display in\nMonochrome",
|
||||
FRAMES,
|
||||
))],
|
||||
},
|
||||
RibbonGroup {
|
||||
title: "Clipping",
|
||||
tools: vec![
|
||||
RibbonItem::LargeTool(tool("_PDFULCLIP", "Create Clipping\nBoundary", CLIP)),
|
||||
RibbonItem::LargeTool(tool("_PDFULUNCLIP", "Remove\nClipping", CLIP)),
|
||||
],
|
||||
},
|
||||
RibbonGroup {
|
||||
title: "Options",
|
||||
tools: vec![
|
||||
RibbonItem::LargeTool(tool("_PDFULSHOW", "Show\nUnderlay", FRAMES)),
|
||||
RibbonItem::LargeTool(tool(
|
||||
"_PDFULSNAP",
|
||||
"Enable\nSnap",
|
||||
include_bytes!("../../../assets/icons/snap_underlays.svg"),
|
||||
)),
|
||||
RibbonItem::LargeTool(tool(
|
||||
"EXTERNALREFERENCES",
|
||||
"External\nReferences",
|
||||
crate::ui::icons::FOLDER_OPEN,
|
||||
)),
|
||||
],
|
||||
},
|
||||
RibbonGroup {
|
||||
title: "PDF Layers",
|
||||
tools: vec![RibbonItem::LargeTool(tool(
|
||||
"ULAYERS",
|
||||
"Edit\nLayers",
|
||||
include_bytes!("../../../assets/icons/underlay_layers.svg"),
|
||||
))],
|
||||
},
|
||||
RibbonGroup {
|
||||
title: "PDF Import",
|
||||
tools: vec![RibbonItem::LargeTool(tool(
|
||||
"_PDFULIMPORT",
|
||||
"Import As\nObjects",
|
||||
include_bytes!("../../../assets/icons/cui_import.svg"),
|
||||
))],
|
||||
},
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
/// 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,
|
||||
value: u8,
|
||||
buffer: &'a str,
|
||||
on_slide: fn(u8) -> UnderlayTabMsg,
|
||||
on_text: fn(String) -> UnderlayTabMsg| {
|
||||
row![
|
||||
text(t!(label)).size(11).width(Length::Fixed(64.0)),
|
||||
slider(0..=100u8, value, move |v| Message::UnderlayTab(on_slide(v)))
|
||||
.on_release(Message::UnderlayTab(UnderlayTabMsg::Commit))
|
||||
.width(Length::Fixed(110.0)),
|
||||
text_input("", buffer)
|
||||
.on_input(move |s| Message::UnderlayTab(on_text(s)))
|
||||
.on_submit(Message::UnderlayTab(UnderlayTabMsg::Commit))
|
||||
.size(11)
|
||||
.padding([2, 4])
|
||||
.width(Length::Fixed(44.0)),
|
||||
]
|
||||
.spacing(6)
|
||||
.align_y(iced::Center)
|
||||
};
|
||||
column![
|
||||
line(
|
||||
"Contrast",
|
||||
ctx.contrast,
|
||||
&ctx.contrast_text,
|
||||
UnderlayTabMsg::Contrast,
|
||||
UnderlayTabMsg::ContrastText,
|
||||
),
|
||||
line(
|
||||
"Fade",
|
||||
ctx.fade,
|
||||
&ctx.fade_text,
|
||||
UnderlayTabMsg::Fade,
|
||||
UnderlayTabMsg::FadeText,
|
||||
),
|
||||
]
|
||||
.spacing(8)
|
||||
.padding([6, 4])
|
||||
.into()
|
||||
}
|
||||
|
||||
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,
|
||||
_ => {}
|
||||
}
|
||||
// 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) {
|
||||
if (old.contrast, old.fade) == (new.contrast, new.fade) {
|
||||
new.contrast_text = old.contrast_text.clone();
|
||||
new.fade_text = old.fade_text.clone();
|
||||
}
|
||||
}
|
||||
self.underlay_ctx = context;
|
||||
}
|
||||
|
||||
pub fn underlay_context_mut(&mut self) -> Option<&mut UnderlayContext> {
|
||||
self.underlay_ctx.as_mut()
|
||||
}
|
||||
|
||||
/// Select a tab by its module id; "pdf_underlay" is the contextual tab.
|
||||
pub fn select_by_id(&mut self, id: &str) -> bool {
|
||||
if id == "pdf_underlay" {
|
||||
self.select_underlay_tab();
|
||||
return self.underlay_tab_active;
|
||||
}
|
||||
match self.modules.iter().position(|m| m.id() == id) {
|
||||
Some(index) => {
|
||||
self.select(index);
|
||||
true
|
||||
}
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn select_underlay_tab(&mut self) {
|
||||
if self.underlay_ctx.is_some() {
|
||||
self.underlay_tab_active = true;
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn underlay_tab_shown(&self) -> bool {
|
||||
self.underlay_tab_active && self.underlay_ctx.is_some()
|
||||
}
|
||||
|
||||
pub(super) fn underlay_panels<'a>(
|
||||
&'a self,
|
||||
ts: widgets::ToggleState,
|
||||
style_ctx: &StyleContext<'_>,
|
||||
) -> Vec<Panel<'a>> {
|
||||
let Some(ctx) = self.underlay_ctx.as_ref() else {
|
||||
return Vec::new();
|
||||
};
|
||||
groups()
|
||||
.iter()
|
||||
.map(|g| {
|
||||
let lead = |_: bool| -> Vec<Element<'a, Message>> {
|
||||
if g.title == ADJUST {
|
||||
vec![adjust_rows(ctx)]
|
||||
} else {
|
||||
Vec::new()
|
||||
}
|
||||
};
|
||||
self.panel(g, ts, style_ctx, &lead)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
@@ -40,9 +40,6 @@ pub(super) struct ToggleState {
|
||||
pub show_block_palette: bool,
|
||||
pub show_file_tabs: bool,
|
||||
pub show_layout_tabs: bool,
|
||||
pub underlay_mono: bool,
|
||||
pub underlay_shown: bool,
|
||||
pub underlay_snap: bool,
|
||||
}
|
||||
|
||||
// ── Layout constants (single source of truth: ROW_H from ui::mod) ─────────
|
||||
@@ -378,9 +375,6 @@ pub(super) fn is_active_tool(
|
||||
"UCSICON" => state.show_ucs_icon,
|
||||
"PROPERTIES" => state.show_properties,
|
||||
"BLOCKPALETTE" => state.show_block_palette,
|
||||
"_PDFULMONO" => state.underlay_mono,
|
||||
"_PDFULSHOW" => state.underlay_shown,
|
||||
"_PDFULSNAP" => state.underlay_snap,
|
||||
"FILETAB" => state.show_file_tabs,
|
||||
"LAYOUTTAB" => state.show_layout_tabs,
|
||||
id => active_tool.as_deref() == Some(id),
|
||||
|
||||
+23
-4
@@ -17,6 +17,9 @@ const ICON_SIZE: f32 = 22.0;
|
||||
const BTN_SIZE: f32 = 38.0;
|
||||
/// Gap between the toolbar and the right edge of the canvas.
|
||||
const EDGE_MARGIN: f32 = 8.0;
|
||||
/// Room kept free at the top right for the view cube and the UCS list; the
|
||||
/// toolbar is centred in the height below it.
|
||||
const TOP_RESERVE: f32 = 200.0;
|
||||
|
||||
fn icon_el(icon: IconKind) -> Element<'static, Message> {
|
||||
match icon {
|
||||
@@ -26,6 +29,8 @@ fn icon_el(icon: IconKind) -> Element<'static, Message> {
|
||||
}
|
||||
|
||||
fn tip_panel(label: &'static str) -> Element<'static, Message> {
|
||||
// Ribbon labels break over two lines; a tooltip reads them on one.
|
||||
let label = crate::t!(label).replace('\n', " ");
|
||||
container(text(label).size(11))
|
||||
.padding([2, 6])
|
||||
.style(|theme: &Theme| {
|
||||
@@ -48,12 +53,21 @@ fn tip_panel(label: &'static str) -> Element<'static, Message> {
|
||||
/// centred over the canvas. Returns `None` when `tools` is empty so the caller
|
||||
/// can skip pushing an overlay.
|
||||
pub fn view(tools: &[ToolDef]) -> Option<Element<'static, Message>> {
|
||||
view_with_active(tools, &|_| false)
|
||||
}
|
||||
|
||||
/// As [`view`], with the tools `active` names drawn as switched on.
|
||||
pub fn view_with_active(
|
||||
tools: &[ToolDef],
|
||||
active: &dyn Fn(&str) -> bool,
|
||||
) -> Option<Element<'static, Message>> {
|
||||
if tools.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut col = column![].spacing(4).align_x(iced::Center);
|
||||
for t in tools {
|
||||
let on = active(t.id);
|
||||
let btn = button(icon_el(t.icon))
|
||||
.on_press(Message::RibbonToolClick {
|
||||
tool_id: t.id.to_string(),
|
||||
@@ -61,18 +75,22 @@ pub fn view(tools: &[ToolDef]) -> Option<Element<'static, Message>> {
|
||||
})
|
||||
.width(Length::Fixed(BTN_SIZE))
|
||||
.height(Length::Fixed(BTN_SIZE))
|
||||
.style(|theme: &Theme, status| {
|
||||
.style(move |theme: &Theme, status| {
|
||||
let palette = theme.palette();
|
||||
let hovered = matches!(
|
||||
status,
|
||||
button::Status::Hovered | button::Status::Pressed
|
||||
);
|
||||
button::Style {
|
||||
background: hovered
|
||||
.then_some(Background::Color(palette.background.strong.color)),
|
||||
background: if on {
|
||||
Some(Background::Color(palette.primary.weak.color))
|
||||
} else {
|
||||
hovered.then_some(Background::Color(palette.background.strong.color))
|
||||
},
|
||||
border: Border {
|
||||
radius: 3.0.into(),
|
||||
..Default::default()
|
||||
color: palette.primary.base.color,
|
||||
width: if on { 1.0 } else { 0.0 },
|
||||
},
|
||||
text_color: palette.background.base.text,
|
||||
..Default::default()
|
||||
@@ -107,6 +125,7 @@ pub fn view(tools: &[ToolDef]) -> Option<Element<'static, Message>> {
|
||||
.align_y(iced::Center)
|
||||
.padding(iced::Padding {
|
||||
right: EDGE_MARGIN,
|
||||
top: TOP_RESERVE,
|
||||
..iced::Padding::ZERO
|
||||
})
|
||||
.into(),
|
||||
|
||||
Reference in new issue
Block a user