use crate::style::{IntoPrimitive, Style, StyleProperty, StyledProperty};
use fyrox_core::visitor::error::VisitError;
use fyrox_core::{
io::FileError,
log::Log,
type_traits::prelude::*,
visitor::{prelude::*, Visitor},
ImmutableString, Uuid,
};
use fyrox_resource::{
io::ResourceIo,
loader::{BoxedLoaderFuture, LoaderPayload, ResourceLoader},
manager::ResourceManager,
state::LoadError,
Resource, ResourceData,
};
use std::{
error::Error,
fmt::{Display, Formatter},
path::{Path, PathBuf},
sync::Arc,
};
#[derive(Debug)]
pub enum StyleResourceError {
Io(FileError),
Visit(VisitError),
}
impl Display for StyleResourceError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::Io(v) => {
write!(f, "A file load error has occurred {v:?}")
}
Self::Visit(v) => {
write!(
f,
"An error that may occur due to version incompatibilities. {v:?}"
)
}
}
}
}
impl From<FileError> for StyleResourceError {
fn from(e: FileError) -> Self {
Self::Io(e)
}
}
impl From<VisitError> for StyleResourceError {
fn from(e: VisitError) -> Self {
Self::Visit(e)
}
}
impl ResourceData for Style {
fn type_uuid(&self) -> Uuid {
<Self as TypeUuidProvider>::type_uuid()
}
fn save(&mut self, path: &Path) -> Result<(), Box<dyn Error>> {
let mut visitor = Visitor::new();
self.visit("Style", &mut visitor)?;
visitor.save_ascii_to_file(path)?;
Ok(())
}
fn can_be_saved(&self) -> bool {
true
}
fn try_clone_box(&self) -> Option<Box<dyn ResourceData>> {
Some(Box::new(self.clone()))
}
}
pub struct StyleLoader {
pub resource_manager: ResourceManager,
}
impl ResourceLoader for StyleLoader {
fn extensions(&self) -> &[&str] {
&["style"]
}
fn is_native_extension(&self, ext: &str) -> bool {
fyrox_core::cmp_strings_case_insensitive(ext, "style")
}
fn data_type_uuid(&self) -> Uuid {
<Style as TypeUuidProvider>::type_uuid()
}
fn load(&self, path: PathBuf, io: Arc<dyn ResourceIo>) -> BoxedLoaderFuture {
let resource_manager = self.resource_manager.clone();
Box::pin(async move {
let tile_set = Style::from_file(&path, io.as_ref(), resource_manager)
.await
.map_err(LoadError::new)?;
Ok(LoaderPayload::new(tile_set))
})
}
}
pub type StyleResource = Resource<Style>;
pub trait StyleResourceExt {
fn set(&self, name: impl Into<ImmutableString>, property: impl Into<StyleProperty>);
fn get<P>(&self, name: impl Into<ImmutableString>) -> Option<P>
where
StyleProperty: IntoPrimitive<P>;
fn get_or<P>(&self, name: impl Into<ImmutableString>, default: P) -> P
where
StyleProperty: IntoPrimitive<P>;
fn get_or_default<P>(&self, name: impl Into<ImmutableString>) -> P
where
P: Default,
StyleProperty: IntoPrimitive<P>;
fn property<P>(&self, name: impl Into<ImmutableString>) -> StyledProperty<P>
where
P: Default,
StyleProperty: IntoPrimitive<P>;
}
impl StyleResourceExt for StyleResource {
fn set(&self, name: impl Into<ImmutableString>, property: impl Into<StyleProperty>) {
let mut state = self.state();
if let Some(data) = state.data() {
data.set(name, property);
} else {
Log::err("Unable to set style property, because the resource is invalid!")
}
}
fn get<P>(&self, name: impl Into<ImmutableString>) -> Option<P>
where
StyleProperty: IntoPrimitive<P>,
{
let state = self.state();
if let Some(data) = state.data_ref() {
data.get(name)
} else {
Log::err("Unable to get style property, because the resource is invalid!");
None
}
}
fn get_or<P>(&self, name: impl Into<ImmutableString>, default: P) -> P
where
StyleProperty: IntoPrimitive<P>,
{
let state = self.state();
if let Some(data) = state.data_ref() {
data.get_or(name, default)
} else {
Log::err("Unable to get style property, because the resource is invalid!");
default
}
}
fn get_or_default<P>(&self, name: impl Into<ImmutableString>) -> P
where
P: Default,
StyleProperty: IntoPrimitive<P>,
{
let state = self.state();
if let Some(data) = state.data_ref() {
data.get_or_default(name)
} else {
Log::err("Unable to get style property, because the resource is invalid!");
P::default()
}
}
fn property<P>(&self, name: impl Into<ImmutableString>) -> StyledProperty<P>
where
P: Default,
StyleProperty: IntoPrimitive<P>,
{
let state = self.state();
if let Some(data) = state.data_ref() {
data.property(name)
} else {
Log::err("Unable to get style property, because the resource is invalid!");
Default::default()
}
}
}