mirror of
https://github.com/danbulant/cushy
synced 2026-06-15 04:21:06 +00:00
65 lines
2.2 KiB
Rust
65 lines
2.2 KiB
Rust
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<WidgetInstance>,
|
|
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<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)))
|
|
}
|
|
|
|
/// 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<WidgetInstance>) -> 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<ConstraintLimit>,
|
|
context: &mut LayoutContext<'_, '_, '_, '_>,
|
|
) -> Size<ConstraintLimit> {
|
|
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
|
|
}
|
|
}
|