forked from 1b-agent/opencadstudio-upstream
app: wire web export, preview, and print flows through the plot UI
- plot dialog: the web build defaults to 'Save to PDF file...' (its only output choice); native dropdowns and defaults are untouched. - on_plot_dlg_commit forces to_file on wasm so a stale page setup can no longer route the web build into the (unreachable) printer path; both preview branches now go through preview_page_pdf, which is identical to the old inline temp-PDF + OS-viewer flow on desktop. - Print ribbon / PRINTALL on wasm render the PDF and open it in a tab instead of erroring; PrintAllPdf picks a virtual path and downloads. - pdf_plot_options maps the dialog's Quality dropdown into PdfPlotOptions.
This commit is contained in:
1 parent
4812bc775d
commit
892d693d2d
4 files changed
+101
-52
No files matched your search
@@ -3201,6 +3201,8 @@ pub enum Message {
|
|||||||
/// Send current layout to the system printer (via lp / lpr).
|
/// Send current layout to the system printer (via lp / lpr).
|
||||||
PrintToPrinter,
|
PrintToPrinter,
|
||||||
/// Callback from the async printer job.
|
/// Callback from the async printer job.
|
||||||
|
/// Web never constructs it — printing opens the PDF preview instead.
|
||||||
|
#[cfg_attr(target_arch = "wasm32", allow(dead_code))]
|
||||||
PrintResult(Result<String, String>),
|
PrintResult(Result<String, String>),
|
||||||
/// Open the full Plot / Print dialog (seeds state from the layout).
|
/// Open the full Plot / Print dialog (seeds state from the layout).
|
||||||
PlotDialogOpen,
|
PlotDialogOpen,
|
||||||
|
|||||||
+62
-39
@@ -3210,33 +3210,37 @@ impl OpenCADStudio {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn on_print_all_print(&mut self) -> Task<Message> {
|
pub(super) fn on_print_all_print(&mut self) -> Task<Message> {
|
||||||
|
let dialog = self.plot_dialog.clone();
|
||||||
|
if self.print_all_settings_override && dialog.style_missing && dialog.apply_plot_styles {
|
||||||
|
self.command_line.push_error(
|
||||||
|
crate::tf!("Plot style table '{}' is not loaded.", dialog.style_name).as_ref(),
|
||||||
|
);
|
||||||
|
return Task::none();
|
||||||
|
}
|
||||||
|
let pages = match self.print_all_pages() {
|
||||||
|
Ok(pages) => pages,
|
||||||
|
Err(error) => {
|
||||||
|
self.command_line.push_error(&error);
|
||||||
|
return Task::none();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
self.save_config();
|
||||||
|
self.close_active_modal();
|
||||||
|
// The web build has no system printers: render every layout into one
|
||||||
|
// PDF and open it in a browser tab for the browser print dialog.
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
{
|
{
|
||||||
self.command_line
|
let work = move || {
|
||||||
.push_error(crate::t!("Printing is not available in the web version.").as_ref());
|
crate::io::print_to_printer::preview_pages_pdf(&pages)
|
||||||
Task::none()
|
.map(|_| crate::t!("Opened plot preview.").into_owned())
|
||||||
|
.map_err(|e| crate::tf!("Preview failed: {e}").into_owned())
|
||||||
|
};
|
||||||
|
self.run_print_all_work(true, work)
|
||||||
}
|
}
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
{
|
{
|
||||||
let dialog = self.plot_dialog.clone();
|
|
||||||
if self.print_all_settings_override && dialog.style_missing && dialog.apply_plot_styles
|
|
||||||
{
|
|
||||||
self.command_line.push_error(
|
|
||||||
crate::tf!("Plot style table '{}' is not loaded.", dialog.style_name).as_ref(),
|
|
||||||
);
|
|
||||||
return Task::none();
|
|
||||||
}
|
|
||||||
let pages = match self.print_all_pages() {
|
|
||||||
Ok(pages) => pages,
|
|
||||||
Err(error) => {
|
|
||||||
self.command_line.push_error(&error);
|
|
||||||
return Task::none();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let options = self.plot_print_options(&dialog);
|
let options = self.plot_print_options(&dialog);
|
||||||
let temp_path = crate::io::print_to_printer::temp_pdf_path("print_all");
|
let temp_path = crate::io::print_to_printer::temp_pdf_path("print_all");
|
||||||
self.save_config();
|
|
||||||
self.close_active_modal();
|
|
||||||
self.command_line
|
self.command_line
|
||||||
.push_info(crate::t!("Sending selected layouts to the system printer…").as_ref());
|
.push_info(crate::t!("Sending selected layouts to the system printer…").as_ref());
|
||||||
let work = move || {
|
let work = move || {
|
||||||
@@ -3477,17 +3481,33 @@ impl OpenCADStudio {
|
|||||||
);
|
);
|
||||||
return Task::none();
|
return Task::none();
|
||||||
};
|
};
|
||||||
let options = self.plot_print_options(&self.plot_dialog);
|
// The web build has no system printers: PRINT opens the rendered PDF
|
||||||
self.command_line
|
// in a browser tab, where the browser's own print dialog takes over.
|
||||||
.push_info(crate::t!("Sending to system printer…").as_ref());
|
#[cfg(target_arch = "wasm32")]
|
||||||
background_task(
|
{
|
||||||
move || {
|
background_task(
|
||||||
iced::futures::executor::block_on(
|
move || {
|
||||||
crate::io::print_to_printer::print_wires_with(page, options),
|
crate::io::print_to_printer::preview_page_pdf(&page)
|
||||||
)
|
.map(|_| crate::t!("Opened plot preview.").into_owned())
|
||||||
},
|
.map_err(|e| crate::tf!("Preview failed: {e}").into_owned())
|
||||||
Message::PrintResult,
|
},
|
||||||
)
|
|result| Message::BackgroundIoFinished(result, false),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
{
|
||||||
|
let options = self.plot_print_options(&self.plot_dialog);
|
||||||
|
self.command_line
|
||||||
|
.push_info(crate::t!("Sending to system printer…").as_ref());
|
||||||
|
background_task(
|
||||||
|
move || {
|
||||||
|
iced::futures::executor::block_on(
|
||||||
|
crate::io::print_to_printer::print_wires_with(page, options),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
Message::PrintResult,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// QUICKPRINT / QP — use the current selection's bounding box as the plot
|
/// QUICKPRINT / QP — use the current selection's bounding box as the plot
|
||||||
@@ -4354,6 +4374,12 @@ impl OpenCADStudio {
|
|||||||
/// Open a preview PDF, export a PDF, or send the job to the chosen printer.
|
/// Open a preview PDF, export a PDF, or send the job to the chosen printer.
|
||||||
fn on_plot_dlg_commit(&mut self, preview: bool) -> Task<Message> {
|
fn on_plot_dlg_commit(&mut self, preview: bool) -> Task<Message> {
|
||||||
let d = self.plot_dialog.clone();
|
let d = self.plot_dialog.clone();
|
||||||
|
// The web dialog only offers PDF output, but a page setup loaded from
|
||||||
|
// the drawing can still seed `to_file = false` — always export there.
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
let to_file = true;
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
let to_file = d.to_file;
|
||||||
if d.style_missing && d.apply_plot_styles {
|
if d.style_missing && d.apply_plot_styles {
|
||||||
self.command_line.push_error(
|
self.command_line.push_error(
|
||||||
crate::tf!("Plot style table '{}' is not loaded.", d.style_name).as_ref(),
|
crate::tf!("Plot style table '{}' is not loaded.", d.style_name).as_ref(),
|
||||||
@@ -4391,16 +4417,14 @@ impl OpenCADStudio {
|
|||||||
// Preview renders to a temp PDF and opens it — never a save dialog,
|
// Preview renders to a temp PDF and opens it — never a save dialog,
|
||||||
// whatever the output target is.
|
// whatever the output target is.
|
||||||
if preview {
|
if preview {
|
||||||
let tmp = crate::io::print_to_printer::temp_pdf_path("preview");
|
|
||||||
let work = move || {
|
let work = move || {
|
||||||
crate::io::pdf_export::export_pdf(&page, &tmp)
|
crate::io::print_to_printer::preview_page_pdf(&page)
|
||||||
.and_then(|_| crate::io::print_to_printer::open_in_viewer(&tmp))
|
|
||||||
.map(|_| crate::t!("Opened plot preview.").into_owned())
|
.map(|_| crate::t!("Opened plot preview.").into_owned())
|
||||||
.map_err(|e| crate::tf!("Preview failed: {e}").into_owned())
|
.map_err(|e| crate::tf!("Preview failed: {e}").into_owned())
|
||||||
};
|
};
|
||||||
return self.run_plot_work(d.background, true, work);
|
return self.run_plot_work(d.background, true, work);
|
||||||
}
|
}
|
||||||
if d.to_file {
|
if to_file {
|
||||||
// Tested clipped export (opens a save dialog).
|
// Tested clipped export (opens a save dialog).
|
||||||
return Task::done(Message::PlotWindowExport);
|
return Task::done(Message::PlotWindowExport);
|
||||||
}
|
}
|
||||||
@@ -4420,17 +4444,15 @@ impl OpenCADStudio {
|
|||||||
let page = self.layout_plot_page();
|
let page = self.layout_plot_page();
|
||||||
|
|
||||||
if preview {
|
if preview {
|
||||||
let tmp = crate::io::print_to_printer::temp_pdf_path("preview");
|
|
||||||
let work = move || {
|
let work = move || {
|
||||||
crate::io::pdf_export::export_pdf(&page, &tmp)
|
crate::io::print_to_printer::preview_page_pdf(&page)
|
||||||
.and_then(|_| crate::io::print_to_printer::open_in_viewer(&tmp))
|
|
||||||
.map(|_| crate::t!("Opened plot preview.").into_owned())
|
.map(|_| crate::t!("Opened plot preview.").into_owned())
|
||||||
.map_err(|e| crate::tf!("Preview failed: {e}").into_owned())
|
.map_err(|e| crate::tf!("Preview failed: {e}").into_owned())
|
||||||
};
|
};
|
||||||
return self.run_plot_work(d.background, true, work);
|
return self.run_plot_work(d.background, true, work);
|
||||||
}
|
}
|
||||||
|
|
||||||
if d.to_file {
|
if to_file {
|
||||||
// Reuse the tested PDF export flow (it opens a save dialog).
|
// Reuse the tested PDF export flow (it opens a save dialog).
|
||||||
return Task::done(Message::PlotExport);
|
return Task::done(Message::PlotExport);
|
||||||
}
|
}
|
||||||
@@ -4470,6 +4492,7 @@ impl OpenCADStudio {
|
|||||||
transparency: d.transparency,
|
transparency: d.transparency,
|
||||||
stamp: d.stamp,
|
stamp: d.stamp,
|
||||||
merge_lines: d.merge_lines,
|
merge_lines: d.merge_lines,
|
||||||
|
quality: crate::io::pdf_export::PlotQuality::from_dialog(&d.quality),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8032,11 +8032,10 @@ impl OpenCADStudio {
|
|||||||
}
|
}
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
{
|
{
|
||||||
let _ = stem;
|
Task::perform(
|
||||||
self.command_line.push_error(
|
crate::io::pdf_export::pick_pdf_path_owned(stem),
|
||||||
crate::t!("PDF export is not available in the web version.").as_ref(),
|
Message::PrintAllPdfPath,
|
||||||
);
|
)
|
||||||
Task::none()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::PrintAllPdfPath(None) => Task::none(),
|
Message::PrintAllPdfPath(None) => Task::none(),
|
||||||
|
|||||||
+33
-8
@@ -3,6 +3,8 @@
|
|||||||
//! quality and output options into one dialog; on commit it either sends the
|
//! quality and output options into one dialog; on commit it either sends the
|
||||||
//! current layout to a system printer (with the chosen options) or writes a
|
//! current layout to a system printer (with the chosen options) or writes a
|
||||||
//! PDF. Styled to match the other OCS dialogs (dark pills + fields).
|
//! PDF. Styled to match the other OCS dialogs (dark pills + fields).
|
||||||
|
//! The web build has no system printers, so PDF is the only output it
|
||||||
|
//! offers — and its default.
|
||||||
|
|
||||||
use crate::app::Message;
|
use crate::app::Message;
|
||||||
use crate::io::paper_sizes::PaperSize;
|
use crate::io::paper_sizes::PaperSize;
|
||||||
@@ -211,7 +213,8 @@ impl Default for PlotDialogState {
|
|||||||
Self {
|
Self {
|
||||||
printers: Vec::new(),
|
printers: Vec::new(),
|
||||||
printer: None,
|
printer: None,
|
||||||
to_file: false,
|
// Web defaults to PDF output: it has no system printers.
|
||||||
|
to_file: cfg!(target_arch = "wasm32"),
|
||||||
paper: "A4".into(),
|
paper: "A4".into(),
|
||||||
paper_width_mm: 297.0,
|
paper_width_mm: 297.0,
|
||||||
paper_height_mm: 210.0,
|
paper_height_mm: 210.0,
|
||||||
@@ -525,6 +528,24 @@ fn choices(items: &[&str]) -> Vec<PlotChoice> {
|
|||||||
items.iter().map(|&value| PlotChoice::localized(value)).collect()
|
items.iter().map(|&value| PlotChoice::localized(value)).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Entries for the output dropdown. The web build has no system printers, so
|
||||||
|
/// PDF is the only output it offers; native lists the system default, every
|
||||||
|
/// discovered printer, then PDF.
|
||||||
|
fn output_choices(printers: &[String]) -> Vec<PlotChoice> {
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
{
|
||||||
|
let _ = printers;
|
||||||
|
vec![PlotChoice::localized(OUT_PDF)]
|
||||||
|
}
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
{
|
||||||
|
let mut out = vec![PlotChoice::localized(OUT_DEFAULT)];
|
||||||
|
out.extend(printers.iter().cloned().map(PlotChoice::raw));
|
||||||
|
out.push(PlotChoice::localized(OUT_PDF));
|
||||||
|
out
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn view_window(
|
pub fn view_window(
|
||||||
s: &PlotDialogState,
|
s: &PlotDialogState,
|
||||||
print_all_options: bool,
|
print_all_options: bool,
|
||||||
@@ -532,9 +553,15 @@ pub fn view_window(
|
|||||||
) -> Element<'_, Message> {
|
) -> Element<'_, Message> {
|
||||||
let width = sizing.width;
|
let width = sizing.width;
|
||||||
let height = sizing.height;
|
let height = sizing.height;
|
||||||
|
// The web build always outputs PDF, whatever a stored dialog state says;
|
||||||
|
// native follows the stored choice.
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
let to_file = true;
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
let to_file = s.to_file;
|
||||||
let action = if print_all_options {
|
let action = if print_all_options {
|
||||||
t!("Apply")
|
t!("Apply")
|
||||||
} else if s.to_file {
|
} else if to_file {
|
||||||
t!("Export PDF")
|
t!("Export PDF")
|
||||||
} else {
|
} else {
|
||||||
t!("Print")
|
t!("Print")
|
||||||
@@ -648,10 +675,8 @@ pub fn view_window(
|
|||||||
.spacing(4);
|
.spacing(4);
|
||||||
|
|
||||||
// ── Printer / plotter ─────────────────────────────────────────────────
|
// ── Printer / plotter ─────────────────────────────────────────────────
|
||||||
let mut printer_opts = vec![PlotChoice::localized(OUT_DEFAULT)];
|
let printer_opts = output_choices(&s.printers);
|
||||||
printer_opts.extend(s.printers.iter().cloned().map(PlotChoice::raw));
|
let printer_sel = if to_file {
|
||||||
printer_opts.push(PlotChoice::localized(OUT_PDF));
|
|
||||||
let printer_sel = if s.to_file {
|
|
||||||
Some(PlotChoice::localized(OUT_PDF))
|
Some(PlotChoice::localized(OUT_PDF))
|
||||||
} else {
|
} else {
|
||||||
Some(match &s.printer {
|
Some(match &s.printer {
|
||||||
@@ -681,7 +706,7 @@ pub fn view_window(
|
|||||||
]
|
]
|
||||||
.spacing(8)
|
.spacing(8)
|
||||||
.align_y(iced::Center);
|
.align_y(iced::Center);
|
||||||
if !s.to_file {
|
if !to_file {
|
||||||
output_row = output_row.push(
|
output_row = output_row.push(
|
||||||
button(text(t!("Properties…")).size(11))
|
button(text(t!("Properties…")).size(11))
|
||||||
.on_press(Message::PlotDlg(PlotDlgMsg::PrinterProperties))
|
.on_press(Message::PlotDlg(PlotDlgMsg::PrinterProperties))
|
||||||
@@ -695,7 +720,7 @@ pub fn view_window(
|
|||||||
]
|
]
|
||||||
.spacing(4)
|
.spacing(4)
|
||||||
.width(Length::Fill);
|
.width(Length::Fill);
|
||||||
let copies_row: Element<'_, Message> = if s.to_file {
|
let copies_row: Element<'_, Message> = if to_file {
|
||||||
Space::new().height(0).into()
|
Space::new().height(0).into()
|
||||||
} else {
|
} else {
|
||||||
field_row(t!("Copies"), &s.copies, PlotDlgMsg::Copies, 60)
|
field_row(t!("Copies"), &s.copies, PlotDlgMsg::Copies, 60)
|
||||||
|
|||||||
Reference in new issue
Block a user