use std::collections::HashMap;
use bevy::prelude::*;
use crate::brushes::BrushSpec;
use crate::dp::DpValue;
use crate::render::{NoesisRenderState, NoesisSet};
#[derive(Debug, Clone, PartialEq)]
pub enum ResourceEntry {
Brush(BrushSpec),
Value(DpValue),
}
#[derive(Resource, Clone, Default, Debug)]
pub struct NoesisResources {
pub entries: HashMap<String, ResourceEntry>,
pub merged_xaml: Vec<String>,
}
impl NoesisResources {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn entry(mut self, key: impl Into<String>, entry: ResourceEntry) -> Self {
self.entries.insert(key.into(), entry);
self
}
#[must_use]
pub fn brush(self, key: impl Into<String>, spec: BrushSpec) -> Self {
self.entry(key, ResourceEntry::Brush(spec))
}
#[must_use]
pub fn solid(self, key: impl Into<String>, rgba: [f32; 4]) -> Self {
self.brush(key, BrushSpec::Solid(rgba))
}
#[must_use]
pub fn value(self, key: impl Into<String>, value: DpValue) -> Self {
self.entry(key, ResourceEntry::Value(value))
}
#[must_use]
pub fn merged(mut self, xaml: impl Into<String>) -> Self {
self.merged_xaml.push(xaml.into());
self
}
}
#[derive(Message, Debug, Clone)]
pub struct NoesisResourcesInstalled {
pub present: Vec<String>,
}
#[allow(clippy::needless_pass_by_value)]
pub(crate) fn sync_resources_bridge(
resources: Option<Res<NoesisResources>>,
state: Option<NonSendMut<NoesisRenderState>>,
mut installed: MessageWriter<NoesisResourcesInstalled>,
) {
let Some(resources) = resources else {
return;
};
let Some(mut state) = state else {
return;
};
if !resources.is_changed() {
return;
}
let present = state.install_app_resources_from(&resources.entries, &resources.merged_xaml);
installed.write(NoesisResourcesInstalled { present });
}
pub struct NoesisResourcesPlugin;
impl Plugin for NoesisResourcesPlugin {
fn build(&self, app: &mut App) {
app.add_message::<NoesisResourcesInstalled>()
.add_systems(PostUpdate, sync_resources_bridge.in_set(NoesisSet::Sync));
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn builder_collects_entries() {
let r = NoesisResources::new()
.solid("AccentBrush", [1.0, 0.0, 0.0, 1.0])
.value("PanelWidth", DpValue::F64(40.0))
.merged("<ResourceDictionary/>");
assert_eq!(
r.entries.get("AccentBrush"),
Some(&ResourceEntry::Brush(BrushSpec::Solid([
1.0, 0.0, 0.0, 1.0
]))),
);
assert_eq!(
r.entries.get("PanelWidth"),
Some(&ResourceEntry::Value(DpValue::F64(40.0))),
);
assert_eq!(r.merged_xaml, vec!["<ResourceDictionary/>".to_string()]);
}
}