1use bevy::{log::LogPlugin, prelude::*};
2use clap::Parser;
3
4mod colors;
5mod i18n;
6mod interface;
7mod intervals;
8mod lines;
9mod rw_data;
10mod search;
11mod settings;
12mod status_bar_text;
13mod troubleshoot;
14mod units;
15mod vehicles;
16
17struct PaiagramApp {
19 bevy_app: App,
20}
21
22impl PaiagramApp {
23 fn new(_cc: &eframe::CreationContext) -> Self {
24 let mut app = App::new();
25 app.add_plugins(MinimalPlugins);
26 app.add_plugins(LogPlugin::default());
27 app.add_plugins((
28 interface::InterfacePlugin,
29 intervals::IntervalsPlugin,
30 rw_data::RwDataPlugin,
31 search::SearchPlugin,
32 settings::SettingsPlugin,
33 vehicles::VehiclesPlugin,
34 lines::LinesPlugin,
35 troubleshoot::TroubleShootPlugin,
36 ));
37 let args = Cli::parse();
38 app.insert_resource(args);
39 app.add_systems(Startup, handle_args);
40 Self { bevy_app: app }
41 }
42}
43
44impl eframe::App for PaiagramApp {
45 fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
46 self.bevy_app
47 .world_mut()
48 .resource_mut::<interface::MiscUiState>()
49 .on_new_frame(ctx.input(|i| i.time), frame.info().cpu_usage);
50 self.bevy_app.update();
51 if let Err(e) = interface::show_ui(self, ctx) {
52 error!("UI Error: {:?}", e);
53 }
54 }
55}
56
57#[derive(Parser, Resource)]
58#[command(version, about, long_about = None)]
59struct Cli {
60 #[arg(
61 short = 'o',
62 long = "open",
63 help = "Path to a .paiagram file (or any other compatible file formats) to open on startup"
64 )]
65 open: Option<String>,
66}
67
68fn handle_args(cli: Res<Cli>, mut msg: MessageWriter<rw_data::ModifyData>, mut commands: Commands) {
69 if let Some(path) = &cli.open {
70 use rw_data::ModifyData;
71 match path.split('.').next_back() {
73 Some("paiagram") => {
74 warn!("Opening .paiagram files is not yet implemented.");
75 }
76 Some("json") | Some("pyetgr") => {
77 let file_content = std::fs::read_to_string(path).expect("Failed to read file");
79 msg.write(ModifyData::LoadQETRC(file_content));
80 }
81 Some("oud2") => {
82 let file_content = std::fs::read_to_string(path).expect("Failed to read file");
83 msg.write(ModifyData::LoadOuDiaSecond(file_content));
84 }
85 _ => {
86 warn!("Unsupported file format: {}", path);
87 }
88 }
89 }
90 commands.remove_resource::<Cli>();
91}
92
93#[cfg(not(target_arch = "wasm32"))]
94fn main() -> eframe::Result<()> {
95 i18n::init();
96 let native_options = eframe::NativeOptions {
97 viewport: egui::ViewportBuilder::default()
98 .with_title("Paiagram Drawer")
99 .with_inner_size([1280.0, 720.0]),
100 ..default()
101 };
102
103 eframe::run_native(
104 "Paiagram Drawer",
105 native_options,
106 Box::new(|cc| Ok(Box::new(PaiagramApp::new(cc)))),
107 )
108}
109
110#[cfg(target_arch = "wasm32")]
111use wasm_bindgen::prelude::*;
112
113#[cfg(target_arch = "wasm32")]
114#[derive(Clone)]
115#[wasm_bindgen]
116pub struct WebHandle {
117 runner: eframe::WebRunner,
118}
119
120#[cfg(target_arch = "wasm32")]
122fn main() {
123 i18n::init();
124 use eframe::wasm_bindgen::JsCast as _;
125 use eframe::web_sys;
126
127 let web_options = eframe::WebOptions::default();
128
129 wasm_bindgen_futures::spawn_local(async {
130 let document = web_sys::window()
131 .expect("No window")
132 .document()
133 .expect("No document");
134
135 let canvas = if let Some(canvas) = document.get_element_by_id("paiagram_canvas") {
136 canvas
137 .dyn_into::<web_sys::HtmlCanvasElement>()
138 .expect("paiagram_canvas was not a HtmlCanvasElement")
139 } else {
140 let canvas = document
141 .create_element("canvas")
142 .expect("Failed to create canvas element");
143 canvas.set_id("paiagram_canvas");
144
145 canvas
147 .set_attribute("style", "display: block; width: 100%; height: 100%;")
148 .ok();
149
150 let body = document.body().expect("Failed to get document body");
151 body.set_attribute(
152 "style",
153 "margin: 0; padding: 0; width: 100%; height: 100%; overflow: hidden;",
154 )
155 .ok();
156
157 let html = document.document_element().expect("No document element");
158 html.set_attribute(
159 "style",
160 "margin: 0; padding: 0; width: 100%; height: 100%; overflow: hidden;",
161 )
162 .ok();
163
164 body.append_child(&canvas).expect("Failed to append canvas");
165 canvas
166 .dyn_into::<web_sys::HtmlCanvasElement>()
167 .expect("Failed to cast canvas")
168 };
169
170 let start_result = eframe::WebRunner::new()
171 .start(
172 canvas,
173 web_options,
174 Box::new(|cc| Ok(Box::new(PaiagramApp::new(cc)))),
175 )
176 .await;
177
178 if let Some(loading_text) = document.get_element_by_id("loading_text") {
180 match start_result {
181 Ok(_) => {
182 loading_text.remove();
183 }
184 Err(e) => {
185 loading_text.set_inner_html(
186 "<p> The app has crashed. See the developer console for details. </p>",
187 );
188 panic!("Failed to start eframe: {e:?}");
189 }
190 }
191 }
192 });
193}