forked from 1b-agent/opencadstudio-upstream
feat(plot): PSETUPIN and page-setup import, page setup for new layouts
- PSETUPIN / -PSETUPIN: with no arguments a file picker offers the chosen drawing's named page setups in the Plot dialog; `PSETUPIN <file>` opens the same chooser on that file; `PSETUPIN <file> *` or `PSETUPIN <file> name,name` import straight away. Same-named setups are replaced, the import is one undo step, and the report counts both. - The Plot dialog's page-setup list gains "Import…": the chooser shows the source drawing's setups with a tick each, All, Import and Cancel, and selects the first imported setup afterwards. The source is read off the UI thread with the same reader the editor uses for its own setups (`scene::document_page_setups`), and handles that only meant something in the source drawing (plot view, visual style) are dropped on import. - Options → General → Plotting: "Show the page setup for new layouts" opens the Plot / Page Setup dialog whenever a layout is created (persisted with the plot preferences). Tests: the document reader, the command (all / named / unknown / missing file / undo) against a drawing saved by the app, the chooser flow, and the new-layout option. Nine new strings in all 21 locales. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
7efb04a666
commit
74936063f9
35 files changed
+786
-48
No files matched your search
@@ -150,6 +150,43 @@ pub enum PlotFlag {
|
||||
SaveToLayout,
|
||||
}
|
||||
|
||||
/// The page setups of another drawing, offered for import (`PSETUPIN`).
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct PageSetupImportDraft {
|
||||
/// The drawing they come from, as shown to the user.
|
||||
pub file: String,
|
||||
/// Each setup with whether it is ticked for import. The settings are
|
||||
/// carried along so the source file is read once.
|
||||
pub setups: Vec<(String, acadrust::objects::PlotSettings, bool)>,
|
||||
/// Why the file gave nothing, when it did not.
|
||||
pub error: Option<String>,
|
||||
}
|
||||
|
||||
impl PageSetupImportDraft {
|
||||
pub fn selected(&self) -> impl Iterator<Item = (&str, &acadrust::objects::PlotSettings)> {
|
||||
self.setups
|
||||
.iter()
|
||||
.filter(|(_, _, on)| *on)
|
||||
.map(|(name, ps, _)| (name.as_str(), ps))
|
||||
}
|
||||
}
|
||||
|
||||
/// Edits of the page-setup import chooser.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum PageSetupImportMsg {
|
||||
/// Ask for the drawing to import from.
|
||||
Pick,
|
||||
/// The drawing was read (or could not be): its name and page setups.
|
||||
Loaded(Result<(String, Vec<(String, acadrust::objects::PlotSettings)>), String>),
|
||||
/// Tick or untick one setup.
|
||||
Toggle(String),
|
||||
/// Tick or untick every setup.
|
||||
All(bool),
|
||||
/// Import the ticked setups and close the chooser.
|
||||
Apply,
|
||||
Cancel,
|
||||
}
|
||||
|
||||
/// Every edit the Plot dialog can emit. Wrapped in `Message::PlotDlg` so the
|
||||
/// top-level match stays a single arm.
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -208,6 +245,8 @@ pub enum PlotDlgMsg {
|
||||
CopySetup,
|
||||
/// Begin an inline rename of the given page setup row.
|
||||
RenameStart(String),
|
||||
/// Import named page setups from another drawing (`PSETUPIN`).
|
||||
Import(PageSetupImportMsg),
|
||||
/// Delete the selected named page setup.
|
||||
DeleteSetup,
|
||||
/// Live edit of the new/rename name field.
|
||||
@@ -396,6 +435,12 @@ pub struct PlotDialogState {
|
||||
/// The in-line printer-properties editor while it is open.
|
||||
#[serde(skip)]
|
||||
pub printer_editor: Option<PrinterOptionsDraft>,
|
||||
/// The page-setup import chooser while it is open.
|
||||
#[serde(skip)]
|
||||
pub import_draft: Option<PageSetupImportDraft>,
|
||||
/// Open the Plot / Page Setup dialog whenever a new layout is created,
|
||||
/// the way a page-setup manager is expected to greet a new layout.
|
||||
pub page_setup_on_new_layout: bool,
|
||||
/// Chosen printer name, or `None` for the system default.
|
||||
pub printer: Option<String>,
|
||||
/// Output goes to a PDF file instead of a printer.
|
||||
@@ -501,6 +546,8 @@ impl Default for PlotDialogState {
|
||||
custom_editor: None,
|
||||
driver_options: std::collections::BTreeMap::new(),
|
||||
printer_editor: None,
|
||||
import_draft: None,
|
||||
page_setup_on_new_layout: false,
|
||||
printer: None,
|
||||
to_file: false,
|
||||
paper: paper_catalog::default_paper().canonical.to_string(),
|
||||
@@ -727,6 +774,58 @@ fn check_enabled<'a>(
|
||||
.into()
|
||||
}
|
||||
|
||||
/// The import chooser: the source drawing's name, one tick per page setup,
|
||||
/// All / None, and Import / Cancel.
|
||||
fn page_setup_import_chooser<'a>(
|
||||
draft: &'a PageSetupImportDraft,
|
||||
height: Length,
|
||||
) -> Element<'a, Message> {
|
||||
let msg = |m: PageSetupImportMsg| Message::PlotDlg(PlotDlgMsg::Import(m));
|
||||
let mut rows = column![].spacing(3);
|
||||
if let Some(error) = &draft.error {
|
||||
rows = rows.push(text(error.clone()).size(10).style(muted_style));
|
||||
} else if draft.setups.is_empty() {
|
||||
let none = text(t!("No named page setups in this drawing.")).size(10);
|
||||
rows = rows.push(none.style(muted_style));
|
||||
}
|
||||
for (name, _, on) in &draft.setups {
|
||||
let name = name.clone();
|
||||
rows = rows.push(
|
||||
checkbox(*on)
|
||||
.label(name.clone())
|
||||
.on_toggle(move |_| msg(PageSetupImportMsg::Toggle(name.clone())))
|
||||
.size(13)
|
||||
.text_size(11),
|
||||
);
|
||||
}
|
||||
let all = !draft.setups.is_empty() && draft.setups.iter().all(|(_, _, on)| *on);
|
||||
let any = draft.setups.iter().any(|(_, _, on)| *on);
|
||||
let mut import = button(text(t!("Import")).size(11)).style(btn(true)).padding([4, 8]);
|
||||
if any {
|
||||
import = import.on_press(msg(PageSetupImportMsg::Apply));
|
||||
}
|
||||
column![
|
||||
text(draft.file.clone()).size(10).style(muted_style),
|
||||
scrollable(rows).height(height),
|
||||
checkbox(all)
|
||||
.label(t!("All"))
|
||||
.on_toggle(move |on| msg(PageSetupImportMsg::All(on)))
|
||||
.size(13)
|
||||
.text_size(11),
|
||||
row![
|
||||
import,
|
||||
button(text(t!("Cancel")).size(11))
|
||||
.on_press(msg(PageSetupImportMsg::Cancel))
|
||||
.style(btn(false))
|
||||
.padding([4, 8]),
|
||||
]
|
||||
.spacing(4),
|
||||
]
|
||||
.spacing(6)
|
||||
.padding(4)
|
||||
.into()
|
||||
}
|
||||
|
||||
/// The custom-scale row: `Custom: [paper] mm = [drawing] units`. Editing
|
||||
/// either side replaces the picked scale with the typed ratio.
|
||||
fn custom_scale_row<'a>(s: &'a PlotDialogState, enabled: bool) -> Element<'a, Message> {
|
||||
@@ -1018,6 +1117,12 @@ pub fn view_window(
|
||||
} else {
|
||||
Space::new().height(0).into()
|
||||
};
|
||||
// While an import is being chosen, the list shows the other drawing's
|
||||
// setups with a tick each instead of this drawing's.
|
||||
let list_body: Element<'_, Message> = match &s.import_draft {
|
||||
Some(draft) => page_setup_import_chooser(draft, height),
|
||||
None => list_body,
|
||||
};
|
||||
let list_panel = container(
|
||||
column![
|
||||
text(t!("Page setups")).size(10).style(muted_style),
|
||||
@@ -1069,10 +1174,18 @@ pub fn view_window(
|
||||
if is_named && !print_all_options {
|
||||
delete_button = delete_button.on_press(Message::PlotDlg(PlotDlgMsg::DeleteSetup));
|
||||
}
|
||||
let mut import_button = button(text(t!("Import…")).size(11))
|
||||
.style(btn(false))
|
||||
.padding([4, 12]);
|
||||
if !print_all_options && s.import_draft.is_none() {
|
||||
import_button = import_button
|
||||
.on_press(Message::PlotDlg(PlotDlgMsg::Import(PageSetupImportMsg::Pick)));
|
||||
}
|
||||
let left_bar = row![
|
||||
new_button,
|
||||
copy_button,
|
||||
delete_button,
|
||||
import_button,
|
||||
]
|
||||
.spacing(4);
|
||||
|
||||
|
||||
Reference in new issue
Block a user