use std::fmt::Debug; use figures::Size; use crate::context::LayoutContext; use crate::value::{Dynamic, DynamicReader, IntoDynamic, IntoReader, Source}; use crate::widget::{WidgetInstance, WidgetRef, WrapperWidget}; use crate::ConstraintLimit; /// A widget that switches its contents based on a value of `T`. #[derive(Debug)] pub struct Switcher { source: DynamicReader, child: WidgetRef, } impl Switcher { /// Returns a new widget that replaces its contents with the results of /// calling `map` each time `source` is updated. /// /// This function is equivalent to calling /// `Self::new(source.into_dynamic().map_each(map))`, but this function's /// signature helps the compiler's type inference work correctly. When using /// new directly, the compiler often requires annotating the closure's /// argument type. pub fn mapping(source: impl IntoDynamic, mut map: F) -> Self where F: FnMut(&T, &Dynamic) -> WidgetInstance + Send + 'static, T: Send + 'static, { let source = source.into_dynamic(); Self::new(source.clone().map_each(move |value| map(value, &source))) } /// Returns a new widget that replaces its contents with the result of /// `widget_factory` each time `value` changes. #[must_use] pub fn new(source: impl IntoReader) -> Self { let source = source.into_reader(); let child = WidgetRef::new(source.get()); Self { source, child } } } impl WrapperWidget for Switcher { fn child_mut(&mut self) -> &mut WidgetRef { &mut self.child } // TODO this should be moved to an invalidated() event once we have it. fn adjust_child_constraints( &mut self, available_space: Size, context: &mut LayoutContext<'_, '_, '_, '_>, ) -> Size { let current_source = self.source.get_tracking_invalidate(context); if ¤t_source != self.child.widget() { self.child.unmount_in(context); self.child = WidgetRef::new(self.source.get()); } context.invalidate_when_changed(&self.source); available_space } }