#[cfg(feature = "runtime")]
use crate::{LayoutError, LayoutItem};
#[cfg(all(feature = "runtime", not(target_os = "android")))]
use crate::{AppConfig, AvailableSpace, ComponentList, compute_layout};
#[cfg(feature = "runtime")]
#[derive(Clone)]
pub struct PreviewEntry {
pub component_name: &'static str,
pub preview_name: &'static str,
pub build: fn() -> Result<Box<dyn LayoutItem>, LayoutError>,
pub surface: Option<PreviewSurface>,
}
#[cfg(feature = "runtime")]
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct PreviewSurface {
pub width: f32,
pub height: f32,
pub animate: bool,
}
#[cfg(feature = "runtime")]
impl PreviewSurface {
pub fn new(width: f32, height: f32) -> Self {
Self {
width,
height,
animate: false,
}
}
pub fn animated(self) -> Self {
Self {
animate: true,
..self
}
}
}
#[cfg(all(feature = "runtime", not(target_os = "android")))]
pub fn dev_entry<F>(entries: F, config: AppConfig, setup: impl FnOnce()) -> bool
where
F: Fn() -> Vec<PreviewEntry>,
{
let wanted = [
"TELAR_PREVIEW_LIST",
"TELAR_TEST",
"TELAR_PREVIEW",
"TELAR_PREVIEW_PNG",
]
.iter()
.any(|var| std::env::var(var).is_ok());
if !wanted {
return false;
}
setup();
#[cfg(feature = "preview-headless")]
if let Ok(out_dir) = std::env::var("TELAR_PREVIEW_PNG") {
crate::run_preview_png(entries(), config, std::path::Path::new(&out_dir));
}
if std::env::var("TELAR_PREVIEW_LIST").is_ok() {
for entry in entries() {
println!("{}\t{}", entry.component_name, entry.preview_name);
}
std::process::exit(0);
}
if std::env::var("TELAR_TEST").is_ok() {
try_run_test(entries(), config);
}
if std::env::var("TELAR_PREVIEW").is_ok() {
#[cfg(feature = "preview")]
{
crate::run_app_with_name(
config,
crate::preview::PreviewApp { entries: entries() },
"telar-preview",
);
return true;
}
}
false
}
#[cfg(all(feature = "runtime", not(target_os = "android")))]
pub fn try_run_test(entries: Vec<PreviewEntry>, config: AppConfig) -> ! {
use std::panic::{AssertUnwindSafe, catch_unwind};
let width = config.window.width as f32;
let height = config.window.height as f32;
println!("running {} preview component(s)", entries.len());
let mut passed = 0usize;
let mut failed = 0usize;
for entry in &entries {
let label = format!("{}::{}", entry.component_name, entry.preview_name);
let outcome = catch_unwind(AssertUnwindSafe(|| -> Result<usize, LayoutError> {
crate::reset_layout_runtime();
let item = (entry.build)()?;
let node = item.layout_node();
compute_layout(
node,
AvailableSpace::Definite(width),
AvailableSpace::Definite(height),
)?;
let tree = ComponentList::new(item);
Ok(tree.commands().len())
}));
match outcome {
Ok(Ok(count)) => {
passed += 1;
println!(" ok {label} ({count} draw commands)");
}
Ok(Err(err)) => {
failed += 1;
println!(" FAIL {label} layout error: {err}");
}
Err(_) => {
failed += 1;
println!(" FAIL {label} panicked during render");
}
}
}
println!();
println!("test result: {passed} passed, {failed} failed");
std::process::exit(if failed == 0 { 0 } else { 1 });
}