use oxiui_core::{
geometry::Size,
paint::{DrawList, RenderBackend},
UiError,
};
use crate::SoftBackend;
#[cfg(feature = "wgpu-compat")]
use oxiui_render_wgpu::WgpuBackend;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum BackendKind {
Soft,
#[cfg(feature = "wgpu-compat")]
Wgpu,
}
pub enum DynBackend {
Soft(SoftBackend),
#[cfg(feature = "wgpu-compat")]
Wgpu(WgpuBackend),
}
impl DynBackend {
pub fn soft(width: u32, height: u32) -> Self {
DynBackend::Soft(SoftBackend::new(width, height))
}
#[cfg(feature = "wgpu-compat")]
pub fn wgpu(backend: WgpuBackend) -> Self {
DynBackend::Wgpu(backend)
}
pub fn kind(&self) -> BackendKind {
match self {
DynBackend::Soft(_) => BackendKind::Soft,
#[cfg(feature = "wgpu-compat")]
DynBackend::Wgpu(_) => BackendKind::Wgpu,
}
}
pub fn is_soft(&self) -> bool {
matches!(self, DynBackend::Soft(_))
}
#[cfg(feature = "wgpu-compat")]
pub fn is_wgpu(&self) -> bool {
matches!(self, DynBackend::Wgpu(_))
}
pub fn as_soft(&self) -> Option<&SoftBackend> {
match self {
DynBackend::Soft(b) => Some(b),
#[cfg(feature = "wgpu-compat")]
_ => None,
}
}
pub fn as_soft_mut(&mut self) -> Option<&mut SoftBackend> {
match self {
DynBackend::Soft(b) => Some(b),
#[cfg(feature = "wgpu-compat")]
_ => None,
}
}
}
impl RenderBackend for DynBackend {
fn execute(&mut self, list: &DrawList) -> Result<(), UiError> {
match self {
DynBackend::Soft(b) => b.execute(list),
#[cfg(feature = "wgpu-compat")]
DynBackend::Wgpu(b) => b.execute(list),
}
}
fn surface_size(&self) -> Size {
match self {
DynBackend::Soft(b) => b.surface_size(),
#[cfg(feature = "wgpu-compat")]
DynBackend::Wgpu(b) => b.surface_size(),
}
}
fn supports_blur(&self) -> bool {
match self {
DynBackend::Soft(b) => b.supports_blur(),
#[cfg(feature = "wgpu-compat")]
DynBackend::Wgpu(b) => b.supports_blur(),
}
}
fn supports_gradients(&self) -> bool {
match self {
DynBackend::Soft(b) => b.supports_gradients(),
#[cfg(feature = "wgpu-compat")]
DynBackend::Wgpu(b) => b.supports_gradients(),
}
}
fn supports_paths(&self) -> bool {
match self {
DynBackend::Soft(b) => b.supports_paths(),
#[cfg(feature = "wgpu-compat")]
DynBackend::Wgpu(b) => b.supports_paths(),
}
}
fn supports_images(&self) -> bool {
match self {
DynBackend::Soft(b) => b.supports_images(),
#[cfg(feature = "wgpu-compat")]
DynBackend::Wgpu(b) => b.supports_images(),
}
}
fn supports_text(&self) -> bool {
match self {
DynBackend::Soft(b) => b.supports_text(),
#[cfg(feature = "wgpu-compat")]
DynBackend::Wgpu(b) => b.supports_text(),
}
}
fn supports_blend_modes(&self) -> bool {
match self {
DynBackend::Soft(b) => b.supports_blend_modes(),
#[cfg(feature = "wgpu-compat")]
DynBackend::Wgpu(b) => b.supports_blend_modes(),
}
}
fn supports_backdrop_blur(&self) -> bool {
match self {
DynBackend::Soft(b) => b.supports_backdrop_blur(),
#[cfg(feature = "wgpu-compat")]
DynBackend::Wgpu(b) => b.supports_backdrop_blur(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn dyn_backend_soft_kind() {
let b = DynBackend::soft(64, 64);
assert_eq!(b.kind(), BackendKind::Soft);
assert!(b.is_soft());
assert_eq!(b.surface_size(), Size::new(64.0, 64.0));
}
#[test]
fn dyn_backend_soft_supports_capabilities() {
let b = DynBackend::soft(32, 32);
assert!(b.supports_blur());
assert!(b.supports_gradients());
assert!(b.supports_paths());
assert!(b.supports_images());
}
#[test]
fn dyn_backend_soft_execute_fill_rect() {
use oxiui_core::geometry::{Rect, Size};
use oxiui_core::paint::DrawList;
use oxiui_core::Color;
let mut b = DynBackend::soft(100, 100);
let mut list = DrawList::new();
list.push_rect(Rect::new(10.0, 10.0, 20.0, 20.0), Color(255, 0, 0, 255));
let result = b.execute(&list);
assert!(result.is_ok(), "execute must not fail: {result:?}");
let fb_pixel = b.as_soft().and_then(|s| s.frame().get_rgba(20, 20));
if let Some((r, _, _, _)) = fb_pixel {
assert!(r > 200, "center pixel should be red: r={r}");
}
let _ = Size::new(0.0, 0.0);
}
#[test]
fn dyn_backend_as_soft_mut() {
let mut b = DynBackend::soft(10, 10);
let soft = b.as_soft_mut();
assert!(soft.is_some());
}
}