1#[cfg(not(target_arch = "wasm32"))]
2#[macro_use]
3mod macros;
4
5pub mod actionlist;
6pub mod actions;
7pub mod configeditor;
8pub mod dockmanager;
9pub mod docks;
10pub mod editcamera;
11pub mod editor;
12pub mod editor_tools;
13pub mod hud;
14#[cfg(not(target_arch = "wasm32"))]
15pub mod i18n;
16pub mod mapeditor;
17pub mod minimap;
18pub mod misc;
19#[cfg(all(not(target_arch = "wasm32"), feature = "self-update"))]
20pub mod self_update;
21pub mod sidebar;
22pub mod textplay;
23pub mod toollist;
24pub mod tools;
25pub mod treasury;
26pub mod undo;
27pub mod utils;
28
29use rust_embed::RustEmbed;
30#[derive(RustEmbed)]
31#[folder = "embedded/"]
32#[exclude = "*.DS_Store"]
33pub struct Embedded;
34
35pub const DEFAULT_VLAYOUT_RATIO: f32 = 0.62;
36
37#[allow(ambiguous_glob_reexports)]
38pub mod prelude {
39 pub use ::serde::{Deserialize, Serialize};
40
41 pub use codegridfx::prelude::*;
42 pub use shared::prelude::*;
43 pub use std::sync::{LazyLock, RwLock};
44 pub use theframework::prelude::*;
45
46 pub use crate::mapeditor::*;
47 pub use crate::misc::*;
48 pub use crate::actionlist::*;
50 pub use crate::sidebar::*;
51 pub use crate::textplay::*;
52 pub use crate::toollist::*;
53 pub use crate::treasury::*;
54 pub use crate::undo::project_atoms::*;
55 pub use crate::undo::project_helper::*;
56 pub use crate::undo::project_undo::*;
57 pub use crate::undo::*;
58 pub use crate::utils::*;
59
60 pub use crate::tools::game::GameTool;
61 pub use crate::tools::linedef::LinedefTool;
62 pub use crate::tools::sector::SectorTool;
63 pub use crate::tools::vertex::VertexTool;
65
66 pub use crate::docks::tiles::*;
67
68 pub use crate::actions::*;
69 pub use crate::docks::*;
70 pub use crate::editor_tools::*;
71 pub use crate::tools::*;
72
73 pub use crate::configeditor::ConfigEditor;
74 pub use crate::editcamera::{CustomMoveAction, EditCamera};
75
76 pub use crate::dockmanager::{DockManager, DockManagerState};
77
78 pub use toml::Table;
79
80 pub const KEY_ESCAPE: u32 = 0;
81 pub const KEY_RETURN: u32 = 1;
82 pub const KEY_DELETE: u32 = 2;
83 pub const KEY_UP: u32 = 3;
84 pub const KEY_RIGHT: u32 = 4;
85 pub const KEY_DOWN: u32 = 5;
86 pub const KEY_LEFT: u32 = 6;
87 pub const KEY_SPACE: u32 = 7;
88 pub const KEY_TAB: u32 = 8;
89}
90
91#[cfg(feature = "staticlib")]
95mod ffi {
96 use super::editor::Editor;
97 use super::prelude::*;
98
99 use std::ffi::{CStr, CString};
100 use std::os::raw::c_char;
101 use std::ptr;
102
103 use lazy_static::lazy_static;
104 use std::sync::Mutex;
105
106 lazy_static! {
107 static ref APP: Mutex<Editor> = Mutex::new(Editor::new());
108 static ref CTX: Mutex<TheContext> = Mutex::new(TheContext::new(800, 600, 1.0));
109 static ref UI: Mutex<TheUI> = Mutex::new(TheUI::new());
110 }
111
112 #[unsafe(no_mangle)]
113 pub extern "C" fn rust_init() {
114 UI.lock().unwrap().init(&mut CTX.lock().unwrap());
115 APP.lock().unwrap().init(&mut CTX.lock().unwrap());
116 APP.lock()
117 .unwrap()
118 .init_ui(&mut UI.lock().unwrap(), &mut CTX.lock().unwrap());
119
120 APP.lock().unwrap().set_cmd_line_args(
122 vec!["eldiron-creator".to_string()],
123 &mut CTX.lock().unwrap(),
124 );
125 }
126
127 #[unsafe(no_mangle)]
128 pub extern "C" fn rust_resize(width: u32, height: u32, scale_factor: f32) {
129 let mut ctx = CTX.lock().unwrap();
130 if ctx.width != width as usize
131 || ctx.height != height as usize
132 || (ctx.scale_factor - scale_factor).abs() > f32::EPSILON
133 {
134 ctx.width = width as usize;
135 ctx.height = height as usize;
136 ctx.scale_factor = scale_factor;
137 ctx.ui.relayout = true;
138 ctx.ui.redraw_all = true;
139 }
140 }
141
142 #[unsafe(no_mangle)]
144 pub unsafe extern "C" fn rust_draw(pixels: *mut u8, width: u32, height: u32) {
145 let length = width as usize * height as usize * 4;
146 let slice = unsafe { std::slice::from_raw_parts_mut(pixels, length) };
147
148 CTX.lock().unwrap().width = width as usize;
149 CTX.lock().unwrap().height = height as usize;
150
151 UI.lock().unwrap().draw(slice, &mut CTX.lock().unwrap());
152 }
153
154 #[unsafe(no_mangle)]
155 pub extern "C" fn rust_update() -> bool {
156 UI.lock().unwrap().update(&mut CTX.lock().unwrap());
157 APP.lock()
158 .unwrap()
159 .update_ui(&mut UI.lock().unwrap(), &mut CTX.lock().unwrap());
160 APP.lock().unwrap().update(&mut CTX.lock().unwrap())
161 }
162
163 #[unsafe(no_mangle)]
164 pub extern "C" fn rust_target_fps() -> u32 {
165 APP.lock().unwrap().target_fps().clamp(1.0, 120.0) as u32
166 }
167
168 #[unsafe(no_mangle)]
169 pub extern "C" fn rust_hover(x: f32, y: f32) -> bool {
170 UI.lock().unwrap().hover(x, y, &mut CTX.lock().unwrap())
171 }
172
173 #[unsafe(no_mangle)]
174 pub extern "C" fn rust_touch_down(x: f32, y: f32) -> bool {
175 UI.lock()
176 .unwrap()
177 .touch_down(x, y, &mut CTX.lock().unwrap())
178 }
179
180 #[unsafe(no_mangle)]
181 pub extern "C" fn rust_touch_dragged(x: f32, y: f32) -> bool {
182 UI.lock()
183 .unwrap()
184 .touch_dragged(x, y, &mut CTX.lock().unwrap())
185 }
186
187 #[unsafe(no_mangle)]
188 pub extern "C" fn rust_touch_up(x: f32, y: f32) -> bool {
189 UI.lock().unwrap().touch_up(x, y, &mut CTX.lock().unwrap())
190 }
191
192 #[unsafe(no_mangle)]
193 pub extern "C" fn rust_touch_wheel(x: f32, y: f32) -> bool {
194 UI.lock()
195 .unwrap()
196 .mouse_wheel((x as i32, y as i32), &mut CTX.lock().unwrap())
197 }
198
199 #[unsafe(no_mangle)]
201 pub unsafe extern "C" fn rust_key_down(p: *const c_char) -> bool {
202 let c_str = unsafe { CStr::from_ptr(p) };
203 if let Ok(key) = c_str.to_str() {
204 if let Some(ch) = key.chars().next() {
205 return UI
206 .lock()
207 .unwrap()
208 .key_down(Some(ch), None, &mut CTX.lock().unwrap());
209 }
210 }
211 false
212 }
213
214 #[unsafe(no_mangle)]
216 pub unsafe extern "C" fn rust_key_up(p: *const c_char) -> bool {
217 let c_str = unsafe { CStr::from_ptr(p) };
218 if let Ok(key) = c_str.to_str() {
219 if let Some(ch) = key.chars().next() {
220 return UI
221 .lock()
222 .unwrap()
223 .key_up(Some(ch), None, &mut CTX.lock().unwrap());
224 }
225 }
226 false
227 }
228
229 #[unsafe(no_mangle)]
230 pub extern "C" fn rust_special_key_down(key: u32) -> bool {
231 if key == KEY_ESCAPE {
232 UI.lock()
233 .unwrap()
234 .key_down(None, Some(TheKeyCode::Escape), &mut CTX.lock().unwrap())
235 } else if key == KEY_RETURN {
236 UI.lock()
237 .unwrap()
238 .key_down(None, Some(TheKeyCode::Return), &mut CTX.lock().unwrap())
239 } else if key == KEY_DELETE {
240 UI.lock()
241 .unwrap()
242 .key_down(None, Some(TheKeyCode::Delete), &mut CTX.lock().unwrap())
243 } else if key == KEY_UP {
244 UI.lock()
245 .unwrap()
246 .key_down(None, Some(TheKeyCode::Up), &mut CTX.lock().unwrap())
247 } else if key == KEY_RIGHT {
248 UI.lock()
249 .unwrap()
250 .key_down(None, Some(TheKeyCode::Right), &mut CTX.lock().unwrap())
251 } else if key == KEY_DOWN {
252 UI.lock()
253 .unwrap()
254 .key_down(None, Some(TheKeyCode::Down), &mut CTX.lock().unwrap())
255 } else if key == KEY_LEFT {
256 UI.lock()
257 .unwrap()
258 .key_down(None, Some(TheKeyCode::Left), &mut CTX.lock().unwrap())
259 } else if key == KEY_SPACE {
260 UI.lock()
261 .unwrap()
262 .key_down(None, Some(TheKeyCode::Space), &mut CTX.lock().unwrap())
263 } else {
264 UI.lock()
265 .unwrap()
266 .key_down(None, Some(TheKeyCode::Tab), &mut CTX.lock().unwrap())
267 }
268 }
269
270 #[unsafe(no_mangle)]
271 pub extern "C" fn rust_key_modifier_changed(
272 shift: bool,
273 ctrl: bool,
274 alt: bool,
275 logo: bool,
276 ) -> bool {
277 UI.lock()
278 .unwrap()
279 .modifier_changed(shift, ctrl, alt, logo, &mut CTX.lock().unwrap());
280 APP.lock().unwrap().modifier_changed(shift, ctrl, alt, logo)
281 }
282
283 #[unsafe(no_mangle)]
285 pub unsafe extern "C" fn rust_dropped_file(p: *const c_char) {
286 let path_str = unsafe { CStr::from_ptr(p) };
287 if let Ok(path) = path_str.to_str() {
288 APP.lock().unwrap().dropped_file(path.to_string());
289 }
290 }
291
292 #[unsafe(no_mangle)]
293 pub extern "C" fn rust_new() {
294 CTX.lock().unwrap().ui.send(TheEvent::StateChanged(
295 TheId::named("New"),
296 TheWidgetState::Clicked,
297 ));
298 }
299
300 #[unsafe(no_mangle)]
301 pub extern "C" fn rust_play() {
302 CTX.lock().unwrap().ui.send(TheEvent::StateChanged(
303 TheId::named("Play"),
304 TheWidgetState::Clicked,
305 ));
306 }
307
308 #[unsafe(no_mangle)]
309 pub extern "C" fn rust_pause() {
310 CTX.lock().unwrap().ui.send(TheEvent::StateChanged(
311 TheId::named("Pause"),
312 TheWidgetState::Clicked,
313 ));
314 }
315
316 #[unsafe(no_mangle)]
317 pub extern "C" fn rust_stop() {
318 CTX.lock().unwrap().ui.send(TheEvent::StateChanged(
319 TheId::named("Stop"),
320 TheWidgetState::Clicked,
321 ));
322 }
323
324 #[unsafe(no_mangle)]
325 pub extern "C" fn rust_open() {
326 CTX.lock().unwrap().ui.send(TheEvent::StateChanged(
327 TheId::named("Open"),
328 TheWidgetState::Clicked,
329 ));
330 }
331
332 #[unsafe(no_mangle)]
333 pub extern "C" fn rust_close() {
334 CTX.lock().unwrap().ui.send(TheEvent::StateChanged(
335 TheId::named("Close"),
336 TheWidgetState::Clicked,
337 ));
338 }
339
340 #[unsafe(no_mangle)]
341 pub extern "C" fn rust_save() {
342 CTX.lock().unwrap().ui.send(TheEvent::StateChanged(
343 TheId::named("Save"),
344 TheWidgetState::Clicked,
345 ));
346 }
347
348 #[unsafe(no_mangle)]
349 pub extern "C" fn rust_save_as() {
350 CTX.lock().unwrap().ui.send(TheEvent::StateChanged(
351 TheId::named("Save As"),
352 TheWidgetState::Clicked,
353 ));
354 }
355
356 #[unsafe(no_mangle)]
357 pub extern "C" fn rust_show_settings() {
358 CTX.lock().unwrap().ui.send(TheEvent::StateChanged(
359 TheId::named("Show Settings"),
360 TheWidgetState::Clicked,
361 ));
362 }
363
364 #[unsafe(no_mangle)]
365 pub extern "C" fn rust_show_rules() {
366 CTX.lock().unwrap().ui.send(TheEvent::StateChanged(
367 TheId::named("Show Rules"),
368 TheWidgetState::Clicked,
369 ));
370 }
371
372 #[unsafe(no_mangle)]
373 pub extern "C" fn rust_show_locales() {
374 CTX.lock().unwrap().ui.send(TheEvent::StateChanged(
375 TheId::named("Show Locales"),
376 TheWidgetState::Clicked,
377 ));
378 }
379
380 #[unsafe(no_mangle)]
381 pub extern "C" fn rust_show_audio_fx() {
382 CTX.lock().unwrap().ui.send(TheEvent::StateChanged(
383 TheId::named("Show Audio FX"),
384 TheWidgetState::Clicked,
385 ));
386 }
387
388 #[unsafe(no_mangle)]
389 pub extern "C" fn rust_show_authoring() {
390 CTX.lock().unwrap().ui.send(TheEvent::StateChanged(
391 TheId::named("Show Authoring"),
392 TheWidgetState::Clicked,
393 ));
394 }
395
396 #[unsafe(no_mangle)]
397 pub extern "C" fn rust_show_debug_log() {
398 CTX.lock().unwrap().ui.send(TheEvent::StateChanged(
399 TheId::named("Show Debug Log"),
400 TheWidgetState::Clicked,
401 ));
402 }
403
404 #[unsafe(no_mangle)]
405 pub extern "C" fn rust_show_console() {
406 CTX.lock().unwrap().ui.send(TheEvent::StateChanged(
407 TheId::named("Show Console"),
408 TheWidgetState::Clicked,
409 ));
410 }
411
412 #[unsafe(no_mangle)]
413 pub extern "C" fn rust_cut() -> *mut c_char {
414 CTX.lock().unwrap().ui.send(TheEvent::StateChanged(
415 TheId::named("Cut"),
416 TheWidgetState::Clicked,
417 ));
418 APP.lock()
419 .unwrap()
420 .update_ui(&mut UI.lock().unwrap(), &mut CTX.lock().unwrap());
421
422 if let Some(TheValue::Text(text)) = &CTX.lock().unwrap().ui.clipboard {
423 return CString::new(text.clone()).unwrap().into_raw();
424 }
425 ptr::null_mut()
426 }
427
428 #[unsafe(no_mangle)]
429 pub extern "C" fn rust_copy() -> *mut c_char {
430 CTX.lock().unwrap().ui.send(TheEvent::StateChanged(
431 TheId::named("Copy"),
432 TheWidgetState::Clicked,
433 ));
434 APP.lock()
435 .unwrap()
436 .update_ui(&mut UI.lock().unwrap(), &mut CTX.lock().unwrap());
437
438 if let Some(TheValue::Text(text)) = &CTX.lock().unwrap().ui.clipboard {
439 return CString::new(text.clone()).unwrap().into_raw();
440 }
441 ptr::null_mut()
442 }
443
444 #[unsafe(no_mangle)]
446 pub unsafe extern "C" fn rust_paste(p: *const c_char) {
447 let text_str = unsafe { CStr::from_ptr(p) };
448 if let Ok(text) = text_str.to_str() {
449 {
450 let mut ctx = CTX.lock().unwrap();
451 ctx.ui.clipboard = Some(TheValue::Text(text.to_string()));
452 ctx.ui.clipboard_app_type = Some("text/plain".to_string());
453 }
454
455 CTX.lock().unwrap().ui.send(TheEvent::StateChanged(
456 TheId::named("Paste"),
457 TheWidgetState::Clicked,
458 ));
459
460 APP.lock()
461 .unwrap()
462 .update_ui(&mut UI.lock().unwrap(), &mut CTX.lock().unwrap());
463 }
464 }
465
466 #[unsafe(no_mangle)]
467 pub extern "C" fn rust_undo() {
468 CTX.lock().unwrap().ui.send(TheEvent::StateChanged(
469 TheId::named("Undo"),
470 TheWidgetState::Clicked,
471 ));
472 }
473
474 #[unsafe(no_mangle)]
475 pub extern "C" fn rust_redo() {
476 CTX.lock().unwrap().ui.send(TheEvent::StateChanged(
477 TheId::named("Redo"),
478 TheWidgetState::Clicked,
479 ));
480 }
481
482 #[unsafe(no_mangle)]
483 pub extern "C" fn rust_has_changes() -> bool {
484 APP.lock().unwrap().has_changes()
485 }
486}