1#![warn(clippy::pedantic)]
2#![allow(clippy::module_name_repetitions)]
3#![allow(clippy::missing_errors_doc)]
4#![allow(clippy::missing_panics_doc)]
5#![allow(clippy::let_underscore_untyped)]
6
7mod document_widget;
8mod engine;
9mod frame_history;
10mod painters;
11#[cfg(puffin)]
12mod profiler;
13mod render_data;
14pub mod viewer;
15#[cfg(target_arch = "wasm32")]
16pub mod web_handle;
17
18use eframe::CreationContext;
19use std::sync::Arc;
20pub use viewer::Viewer;
21
22pub use crate::document_widget::DocumentWidget;
23
24pub mod exports {
26 pub use ::eframe;
27 pub use ::egui;
28 pub use ::wgpu;
29}
30
31#[cfg_attr(target_arch = "wasm32", allow(dead_code))]
33struct ShowViewerApp {
34 document: Arc<vsvg::Document>,
35 tolerance: f64,
36}
37
38impl ViewerApp for ShowViewerApp {
39 fn setup(
40 &mut self,
41 _cc: &CreationContext,
42 document_widget: &mut DocumentWidget,
43 ) -> anyhow::Result<()> {
44 document_widget.set_tolerance(self.tolerance);
45 document_widget.set_document(self.document.clone());
46 Ok(())
47 }
48}
49
50const DEFAULT_RENDERER_TOLERANCE: f64 = 0.01;
51
52#[cfg(not(target_arch = "wasm32"))]
56pub fn show(document: Arc<vsvg::Document>) -> anyhow::Result<()> {
57 show_tolerance(document, DEFAULT_RENDERER_TOLERANCE)
58}
59
60#[cfg(not(target_arch = "wasm32"))]
67pub fn show_tolerance(document: Arc<vsvg::Document>, tolerance: f64) -> anyhow::Result<()> {
68 let native_options = eframe::NativeOptions::default();
69
70 eframe::run_native(
71 "vsvg-viewer",
72 native_options,
73 Box::new(move |cc| {
74 let style = egui::Style {
75 visuals: egui::Visuals::light(),
76 ..egui::Style::default()
77 };
78 cc.egui_ctx.set_style(style);
79
80 Box::new(
81 Viewer::new(
82 cc,
83 Box::new(ShowViewerApp {
84 document: document.clone(),
85 tolerance,
86 }),
87 )
88 .expect("viewer requires wgpu backend"),
89 )
90 }),
91 )?;
92
93 Ok(())
94}
95
96pub trait ViewerApp {
98 fn setup(
99 &mut self,
100 _cc: &eframe::CreationContext,
101 _document_widget: &mut DocumentWidget,
102 ) -> anyhow::Result<()> {
103 Ok(())
104 }
105
106 fn handle_input(&mut self, _ctx: &egui::Context, _document_widget: &mut DocumentWidget) {}
110
111 fn show_panels(
115 &mut self,
116 _ctx: &egui::Context,
117 _document_widget: &mut DocumentWidget,
118 ) -> anyhow::Result<()> {
119 Ok(())
120 }
121
122 fn show_central_panel(
126 &mut self,
127 _ui: &mut egui::Ui,
128 _document_widget: &mut DocumentWidget,
129 ) -> anyhow::Result<()> {
130 Ok(())
131 }
132
133 #[cfg(not(target_arch = "wasm32"))]
135 fn native_options(&self) -> eframe::NativeOptions {
136 eframe::NativeOptions::default()
137 }
138
139 fn title(&self) -> String {
141 "vsvg ViewerApp".to_owned()
142 }
143
144 fn load(&mut self, _storage: &dyn eframe::Storage) {}
148
149 fn save(&self, _storage: &mut dyn eframe::Storage) {}
153
154 fn on_exit(&mut self) {}
156}
157
158#[cfg(not(target_arch = "wasm32"))]
162pub fn show_with_viewer_app(viewer_app: impl ViewerApp + 'static) -> anyhow::Result<()> {
163 vsvg::trace_function!();
164
165 let viewer_app = Box::new(viewer_app);
166
167 let native_options = viewer_app.native_options();
168
169 eframe::run_native(
170 viewer_app.title().as_str(),
171 native_options,
172 Box::new(move |cc| {
173 let style = egui::Style {
174 visuals: egui::Visuals::light(),
175 ..egui::Style::default()
176 };
177 cc.egui_ctx.set_style(style);
178
179 Box::new(Viewer::new(cc, viewer_app).expect("viewer requires wgpu backend"))
180 }),
181 )?;
182
183 Ok(())
184}