Skip to main content

jag_surface/
lib.rs

1//! jag-surface: Canvas-style API on top of jag-draw.
2#![allow(
3    clippy::collapsible_if,
4    clippy::collapsible_match,
5    clippy::too_many_arguments,
6    clippy::type_complexity
7)]
8
9mod canvas;
10pub mod shapes;
11mod surface;
12
13pub use canvas::{Canvas, ImageFitMode, RawImageDraw, ScrimDraw};
14pub use surface::{CachedFrameData, JagSurface, get_last_raw_image_rect};
15
16/// Resolve an asset path by checking multiple locations:
17/// 1. Absolute path (as-is)
18/// 2. `JAG_ASSETS_ROOT` override (if set) – supports a single
19///    directory or a path-list (e.g. "dir1:dir2") using platform
20///    `PATH` semantics.
21/// 3. Relative to current directory
22/// 4. In macOS app bundle Resources directory
23/// 5. In app bundle Resources with just filename
24pub fn resolve_asset_path(source: &std::path::Path) -> std::path::PathBuf {
25    // If absolute path exists, use it
26    if source.is_absolute() && source.exists() {
27        return source.to_path_buf();
28    }
29
30    // Try JAG_ASSETS_ROOT override. This allows launchers (e.g. WAID dev)
31    // to point Jag at one or more workspaces where shared assets like
32    // `images/` and `fonts/` live, even when the current directory is
33    // different from the Jag binary's source tree.
34    //
35    // The value may be a single directory or a platform-specific
36    // path list (e.g. "dir1:dir2" on Unix).
37    if let Ok(root_list) = std::env::var("JAG_ASSETS_ROOT") {
38        for base in std::env::split_paths(&root_list) {
39            let candidate = base.join(source);
40            if candidate.exists() {
41                return candidate;
42            }
43
44            if let Some(filename) = source.file_name() {
45                let candidate = base.join(filename);
46                if candidate.exists() {
47                    return candidate;
48                }
49            }
50        }
51    }
52
53    // Try relative to current directory
54    if source.exists() {
55        return source.to_path_buf();
56    }
57
58    // Try in macOS app bundle Resources directory
59    if let Ok(exe_path) = std::env::current_exe() {
60        // exe is at App.app/Contents/MacOS/binary
61        // resources are at App.app/Contents/Resources/
62        if let Some(contents_dir) = exe_path.parent().and_then(|p| p.parent()) {
63            let resources_path = contents_dir.join("Resources").join(source);
64            if resources_path.exists() {
65                return resources_path;
66            }
67            // Also try without the leading directory (e.g., "images/foo.png" -> "foo.png")
68            if let Some(filename) = source.file_name() {
69                let resources_path = contents_dir.join("Resources").join(filename);
70                if resources_path.exists() {
71                    return resources_path;
72                }
73            }
74        }
75    }
76
77    // Return original path (caller will handle non-existent case)
78    source.to_path_buf()
79}