use crate::document::Document;
use crate::event::{Color, Event};
use crate::sys;
use crate::util::{cstring, ensure_abi, NotThreadSafe};
use crate::view::View;
use std::os::raw::c_char;
use std::rc::Rc;
#[derive(Clone, Debug)]
pub struct Config {
pub title: String,
pub width: i32,
pub height: i32,
pub clear_color: Color,
pub high_dpi: bool,
pub vsync: bool,
pub default_font_family: String,
pub default_font_size: i32,
pub asset_folders: Vec<String>,
pub perf_overlay: bool,
}
impl Default for Config {
fn default() -> Config {
Config {
title: "AffineUI".to_owned(),
width: 1024,
height: 768,
clear_color: Color::rgba(30, 30, 46, 255),
high_dpi: true,
vsync: true,
default_font_family: "sans-serif".to_owned(),
default_font_size: 16,
asset_folders: vec![".".to_owned()],
perf_overlay: false,
}
}
}
impl Config {
pub fn title(mut self, title: &str) -> Config {
self.title = title.to_owned();
self
}
pub fn size(mut self, width: i32, height: i32) -> Config {
self.width = width;
self.height = height;
self
}
pub fn clear_color(mut self, color: Color) -> Config {
self.clear_color = color;
self
}
pub fn font(mut self, family: &str, size: i32) -> Config {
self.default_font_family = family.to_owned();
self.default_font_size = size;
self
}
pub fn asset_folders(mut self, folders: &[&str]) -> Config {
self.asset_folders = folders.iter().map(|f| (*f).to_owned()).collect();
self
}
pub fn perf_overlay(mut self, on: bool) -> Config {
self.perf_overlay = on;
self
}
}
pub(crate) struct AppInner {
raw: *mut sys::affineui_app,
_not_send: NotThreadSafe,
}
impl Drop for AppInner {
fn drop(&mut self) {
unsafe { sys::affineui_app_destroy(self.raw) };
}
}
#[derive(Clone)]
pub struct App {
inner: Rc<AppInner>,
}
impl App {
pub fn new(cfg: Config) -> App {
ensure_abi();
let title = cstring(&cfg.title);
let font = cstring(&cfg.default_font_family);
let folders: Vec<_> = cfg.asset_folders.iter().map(|f| cstring(f)).collect();
let folder_ptrs: Vec<*const c_char> = folders.iter().map(|f| f.as_ptr()).collect();
let c_cfg = sys::affineui_app_config {
title: title.as_ptr(),
width: cfg.width,
height: cfg.height,
clear_color: sys::affineui_color {
r: cfg.clear_color.r,
g: cfg.clear_color.g,
b: cfg.clear_color.b,
a: cfg.clear_color.a,
},
high_dpi: cfg.high_dpi as i32,
vsync: cfg.vsync as i32,
default_font_family: font.as_ptr(),
default_font_size: cfg.default_font_size,
asset_folders: if folder_ptrs.is_empty() { std::ptr::null() } else { folder_ptrs.as_ptr() },
asset_folder_count: folder_ptrs.len(),
perf_overlay: cfg.perf_overlay as i32,
};
let raw = unsafe { sys::affineui_app_create(&c_cfg) };
App { inner: Rc::new(AppInner { raw, _not_send: NotThreadSafe::default() }) }
}
fn raw(&self) -> *mut sys::affineui_app {
self.inner.raw
}
pub fn load_html(&self, html: &str) {
let html = cstring(html);
unsafe { sys::affineui_app_load_html(self.raw(), html.as_ptr()) };
}
pub fn load_html_file(&self, path: &str) -> bool {
let path = cstring(path);
unsafe { sys::affineui_app_load_html_file(self.raw(), path.as_ptr()) != 0 }
}
pub fn load_view(&self, view: &View) {
unsafe { sys::affineui_app_load_view(self.raw(), view.raw()) };
}
pub fn set_stylesheet(&self, css: &str, base_url: Option<&str>) {
let css = cstring(css);
let base = base_url.map(cstring);
unsafe {
sys::affineui_app_set_stylesheet(
self.raw(),
css.as_ptr(),
base.as_ref().map_or(std::ptr::null(), |b| b.as_ptr()),
)
};
}
pub fn invalidate(&self) {
unsafe { sys::affineui_app_invalidate(self.raw()) };
}
pub fn set_perf_overlay_enabled(&self, enabled: bool) {
unsafe { sys::affineui_app_set_perf_overlay_enabled(self.raw(), enabled as i32) };
}
pub fn perf_overlay_enabled(&self) -> bool {
unsafe { sys::affineui_app_perf_overlay_enabled(self.raw()) != 0 }
}
pub fn dispatch(&self, ev: &Event) -> bool {
ev.with_sys(|sys_ev| unsafe { sys::affineui_app_dispatch(self.raw(), sys_ev) != 0 })
}
pub fn run(&self) -> i32 {
unsafe { sys::affineui_app_run(self.raw()) }
}
pub fn quit(&self, code: i32) {
unsafe { sys::affineui_app_quit(self.raw(), code) };
}
pub fn window_size(&self) -> (i32, i32) {
let (mut w, mut h) = (0, 0);
unsafe { sys::affineui_app_window_size(self.raw(), &mut w, &mut h) };
(w, h)
}
pub fn framebuffer_size(&self) -> (i32, i32) {
let (mut w, mut h) = (0, 0);
unsafe { sys::affineui_app_framebuffer_size(self.raw(), &mut w, &mut h) };
(w, h)
}
pub fn dpi_scale(&self) -> f32 {
unsafe { sys::affineui_app_dpi_scale(self.raw()) }
}
pub fn document(&self) -> Document {
let raw = unsafe { sys::affineui_app_document(self.raw()) };
Document::borrowed(raw, Rc::clone(&self.inner))
}
}