Refactored `view` node into `View!` widget.

This commit is contained in:
Samuel Guerra 2023-06-22 00:15:47 -03:00
parent 8f3fe0dd1e
commit c108c4b551
4 changed files with 86 additions and 39 deletions

View File

@ -34,12 +34,6 @@
- Is a different event from Winit.
- The next version of Winit will fix this: https://github.com/rust-windowing/winit/issues/753
# View!
* `view` really needs to be a widget.
- In the icon example the view is not centered in the stack because
stack align does not work with non-widget nodes.
# Align
* Review align in window background.

View File

@ -113,33 +113,37 @@ fn icons() -> impl UiNode {
select_font("two_tone"),
]
},
Container!(view(merge_var!(selected_font, search, |f, s| (*f, s.clone())), hn!(|a: &ViewArgs<(&'static str, Txt)>| {
if let Some((f, s)) = a.get_new() {
let mut icons = match f {
"filled" => icons::filled::all(),
"outlined" => icons::outlined::all(),
"rounded" => icons::rounded::all(),
"sharp" => icons::sharp::all(),
"two_tone" => icons::two_tone::all(),
_ => unreachable!(),
};
if !s.is_empty() {
let s = s.to_uppercase();
icons.retain(|f| {
f.name.contains(&s) ||
f.display_name().to_uppercase().contains(&s)
});
View!(
::<(&'static str, Txt)>,
merge_var!(selected_font, search, |f, s| (*f, s.clone())),
hn!(|a: &ViewArgs<(&'static str, Txt)>| {
if let Some((f, s)) = a.get_new() {
let mut icons = match f {
"filled" => icons::filled::all(),
"outlined" => icons::outlined::all(),
"rounded" => icons::rounded::all(),
"sharp" => icons::sharp::all(),
"two_tone" => icons::two_tone::all(),
_ => unreachable!(),
};
if !s.is_empty() {
let s = s.to_uppercase();
icons.retain(|f| {
f.name.contains(&s) ||
f.display_name().to_uppercase().contains(&s)
});
}
if icons.is_empty() {
a.set_view(Text! {
txt = formatx!("no icons found for '{s}'");
margin = (10, 0, 0, 0);
})
} else {
a.set_view(show_font(icons, f));
}
}
if icons.is_empty() {
a.set_view(Text! {
txt = formatx!("no icons found for '{s}'");
margin = (10, 0, 0, 0);
})
} else {
a.set_view(show_font(icons, f));
}
}
}))),
}),
),
]
}
}

View File

@ -1088,7 +1088,7 @@ pub fn focused_removed_by_deleting() {
let buttons = ui_vec! {
Button! { child = Text!("Button 0") },
view(exist.clone(), hn!(|a: &ViewArgs<bool>| {
View!(::<bool>, exist.clone(), hn!(|a: &ViewArgs<bool>| {
if a.data().get() {
a.set_view(Button! { id = button1_id; child = Text!("Button 1") });
} else {
@ -1183,7 +1183,8 @@ pub fn focus_continued_after_widget_id_move() {
let do_move_id = var(false);
let mut app = app.run(view(
let mut app = app.run(View!(
::<bool>,
do_move_id.clone(),
hn!(|a: &ViewArgs<bool>| {
if a.data().get() {

View File

@ -239,7 +239,9 @@ pub fn presenter_opt<D: VarValue>(data: impl IntoVar<Option<D>>, update: impl In
})
}
/// Arguments for the [`view`] widget function.
/// Arguments for the [`View!`] widget function.
///
/// [`View!`]: struct@View
#[derive(Clone)]
pub struct ViewArgs<D: VarValue> {
data: BoxedVar<D>,
@ -297,11 +299,13 @@ impl<D: VarValue> ViewArgs<D> {
///
/// # Examples
///
/// View using the shorthand syntax:
///
/// ```
/// use zero_ui::prelude::*;
///
/// fn countdown(n: impl IntoVar<usize>) -> impl UiNode {
/// Container!(view(n, hn!(|a: &ViewArgs<usize>| {
/// View!(::<usize>, n, hn!(|a: &ViewArgs<usize>| {
/// // we generate a new view on the first call or when the data has changed to zero.
/// if a.is_nil() || a.data().get_new() == Some(0) {
/// a.set_view(if a.data().get() > 0 {
@ -320,15 +324,59 @@ impl<D: VarValue> ViewArgs<D> {
/// }
/// });
/// }
/// })))
/// }))
/// }
/// ```
pub fn view<D: VarValue>(data: impl IntoVar<D>, update: impl WidgetHandler<ViewArgs<D>>) -> impl UiNode {
///
/// You can also use the normal widget syntax and set the `view` property.
///
/// ```
/// use zero_ui::prelude::*;
///
/// fn countdown(n: impl IntoVar<usize>) -> impl UiNode {
/// View! {
/// view::<usize> = {
/// data: n,
/// update: hn!(|a: &ViewArgs<usize>| { }),
/// };
/// background_color = colors::GRAY;
/// }
/// }
/// ```
#[widget($crate::widgets::View {
(::<$T:ty>, $data:expr, $update:expr $(,)?) => {
view::<$T> = {
data: $data,
update: $update,
};
}
})]
pub struct View(WidgetBase);
impl View {
widget_impl! {
/// Spacing around content, inside the border.
pub crate::properties::padding(padding: impl IntoVar<SideOffsets>);
/// Content alignment.
pub crate::properties::child_align(align: impl IntoVar<Align>);
/// Content overflow clipping.
pub crate::properties::clip_to_bounds(clip: impl IntoVar<bool>);
}
}
/// The view generator.
///
/// See [`View!`] for more details.
///
/// [`View!`]: struct@View
#[property(CHILD, widget_impl(View))]
pub fn view<D: VarValue>(child: impl UiNode, data: impl IntoVar<D>, update: impl WidgetHandler<ViewArgs<D>>) -> impl UiNode {
let data = data.into_var().boxed();
let mut update = update.cfg_boxed();
let replace = Arc::new(Mutex::new(None));
match_node(NilUiNode.boxed(), move |c, op| match op {
match_node(child, move |c, op| match op {
UiNodeOp::Init => {
WIDGET.sub_var(&data);
update.event(&ViewArgs {