use std::fmt::Debug;
use std::mem;
use ahash::HashMap;
use figures::Size;
use kludgine::KludgineId;
use crate::context::{AsEventContext, LayoutContext};
use crate::value::{Dynamic, DynamicReader, IntoDynamic, IntoReader, Source};
use crate::widget::{MountedWidget, WidgetInstance, WidgetRef, WrapperWidget};
use crate::window::WindowLocal;
use crate::ConstraintLimit;
#[derive(Debug)]
pub struct Switcher {
source: DynamicReader<WidgetInstance>,
child: WidgetRef,
pending_unmount: HashMap<KludgineId, MountedWidget>,
}
impl Switcher {
pub fn mapping<T, F>(source: impl IntoDynamic<T>, mut map: F) -> Self
where
F: FnMut(&T, &Dynamic<T>) -> WidgetInstance + Send + 'static,
T: Send + 'static,
{
let source = source.into_dynamic();
Self::new(source.clone().map_each(move |value| map(value, &source)))
}
#[must_use]
pub fn new(source: impl IntoReader<WidgetInstance>) -> Self {
let source = source.into_reader();
let child = WidgetRef::new(source.get());
Self {
source,
child,
pending_unmount: HashMap::default(),
}
}
}
impl WrapperWidget for Switcher {
fn child_mut(&mut self) -> &mut WidgetRef {
&mut self.child
}
fn adjust_child_constraints(
&mut self,
available_space: Size<ConstraintLimit>,
context: &mut LayoutContext<'_, '_, '_, '_>,
) -> Size<ConstraintLimit> {
if let Some(pending_unmount) = self.pending_unmount.remove(&context.kludgine_id()) {
context.remove_child(&pending_unmount);
}
let current_source = self.source.get_tracking_invalidate(context);
if ¤t_source != self.child.widget() {
self.child.unmount_in(context);
let old_mounts = <WindowLocal<MountedWidget>>::from(mem::replace(
&mut self.child,
WidgetRef::new(current_source),
));
for (id, mounted) in old_mounts {
let existing = self.pending_unmount.insert(id, mounted);
debug_assert!(
existing.is_none(),
"Existing unmount found, but should have already been unmounted"
);
}
}
context.invalidate_when_changed(&self.source);
available_space
}
}