use std::sync::Arc;
use bevy::prelude::*;
use crate::resources::{PfValue, ResourceDictionary, ResourceKey};
#[derive(Resource, Default, Clone)]
pub struct PfApplicationResources {
pub dict: Arc<ResourceDictionary>,
pub revision: u64,
}
#[derive(Component, Debug, Clone)]
pub struct PfResources(pub Arc<ResourceDictionary>);
#[derive(Debug, Clone)]
pub struct DynEntry {
pub key: ResourceKey,
pub target: crate::provider::PropertyTarget,
pub tier: crate::provider::ValueSource,
}
#[derive(Component, Debug, Default, Clone)]
pub struct PfDynamicResources(pub Vec<DynEntry>);
#[derive(Resource, Default)]
pub(crate) struct LastDynRevision(pub u64);
pub fn resolve_dynamic(world: &World, entity: Entity, key: &ResourceKey) -> Option<PfValue> {
let mut current = Some(entity);
while let Some(e) = current {
if let Some(res) = world.get::<PfResources>(e)
&& let Some(v) = res.0.get(key) {
return Some(v.clone());
}
current = world
.get::<crate::components::PfLogicalParent>(e)
.map(|l| l.0)
.or_else(|| world.get::<ChildOf>(e).map(|c| c.parent()));
}
world
.get_resource::<PfApplicationResources>()
.and_then(|app| app.dict.get(key).cloned())
}
pub(crate) fn refresh_dynamic_resources(world: &mut World) {
let revision = world
.get_resource::<PfApplicationResources>()
.map(|r| r.revision)
.unwrap_or(0);
let theme_gen = world
.get_resource::<crate::app_theme::PfAppTheme>()
.map(|t| t.generation())
.unwrap_or(0);
let rev_changed = world
.get_resource::<LastDynRevision>()
.is_none_or(|l| l.0 != revision);
let theme_changed = world
.get_resource::<crate::app_theme::LastAppThemeGen>()
.is_none_or(|l| l.0 != theme_gen);
if !rev_changed && !theme_changed {
return;
}
world.insert_resource(LastDynRevision(revision));
world.insert_resource(crate::app_theme::LastAppThemeGen(theme_gen));
if rev_changed {
let mut query = world.query::<(Entity, &PfDynamicResources)>();
let targets: Vec<(Entity, Vec<DynEntry>)> = query
.iter(world)
.map(|(e, d)| (e, d.0.clone()))
.collect();
for (entity, entries) in targets {
for entry in entries {
if let Some(value) = resolve_dynamic(world, entity, &entry.key) {
crate::provider::store_and_apply(
world,
entity,
entry.target,
entry.tier,
Some(value),
);
}
}
}
}
let theme = crate::app_theme::app_theme(world);
let mut query = world.query::<(Entity, &crate::app_theme::PfAppThemeRefs)>();
let themed: Vec<(Entity, Vec<crate::app_theme::AppThemeEntry>)> = query
.iter(world)
.map(|(e, r)| (e, r.0.clone()))
.collect();
for (entity, entries) in themed {
for entry in entries {
let value = match entry.arms.pick(theme) {
Some(crate::app_theme::ThemeArm::Value(v)) => v.clone(),
Some(crate::app_theme::ThemeArm::Dynamic(key)) => {
match resolve_dynamic(world, entity, key) {
Some(v) => Some(v),
None => continue, }
}
None => None,
};
crate::provider::store_and_apply(world, entity, entry.target, entry.tier, value);
}
}
}
pub fn set_application_resources_dict(world: &mut World, dict: ResourceDictionary) {
let revision = world
.get_resource::<PfApplicationResources>()
.map(|r| r.revision)
.unwrap_or(0);
world.insert_resource(PfApplicationResources {
dict: Arc::new(dict),
revision: revision + 1,
});
}
pub fn merge_application_resources(world: &mut World, entries: ResourceDictionary) {
let (mut dict, revision) = world
.get_resource::<PfApplicationResources>()
.map(|r| ((*r.dict).clone(), r.revision))
.unwrap_or_default();
dict.extend(entries);
world.insert_resource(PfApplicationResources {
dict: Arc::new(dict),
revision: revision + 1,
});
}