use crate::prelude::*;
use zng_app::widget::info;
#[property(CONTEXT, default(true))]
pub fn visibility(child: impl UiNode, visibility: impl IntoVar<Visibility>) -> impl UiNode {
let visibility = visibility.into_var();
let mut prev_vis = Visibility::Visible;
match_node(child, move |child, op| match op {
UiNodeOp::Init => {
WIDGET.sub_var(&visibility);
prev_vis = visibility.get();
}
UiNodeOp::Update { .. } => {
if let Some(vis) = visibility.get_new() {
use Visibility::*;
match (prev_vis, vis) {
(Collapsed, Visible) | (Visible, Collapsed) => {
WIDGET.layout().render();
}
(Hidden, Visible) | (Visible, Hidden) => {
WIDGET.render();
}
(Collapsed, Hidden) | (Hidden, Collapsed) => {
WIDGET.layout();
}
_ => {}
}
prev_vis = vis;
}
}
UiNodeOp::Measure { wm, desired_size } => {
if Visibility::Collapsed != visibility.get() {
*desired_size = child.measure(wm);
} else {
child.delegated();
}
}
UiNodeOp::Layout { wl, final_size } => {
if Visibility::Collapsed != visibility.get() {
*final_size = child.layout(wl);
} else {
wl.collapse();
child.delegated();
}
}
UiNodeOp::Render { frame } => match visibility.get() {
Visibility::Visible => child.render(frame),
Visibility::Hidden => frame.hide(|frame| child.render(frame)),
Visibility::Collapsed => {
child.delegated();
#[cfg(debug_assertions)]
{
tracing::error!(
"collapsed {} rendered, to fix, layout the widget, or `WidgetLayout::collapse_child` the widget",
WIDGET.trace_id()
)
}
}
},
UiNodeOp::RenderUpdate { update } => match visibility.get() {
Visibility::Visible => child.render_update(update),
Visibility::Hidden => update.hidden(|update| child.render_update(update)),
Visibility::Collapsed => {
child.delegated();
#[cfg(debug_assertions)]
{
tracing::error!(
"collapsed {} render-updated, to fix, layout the widget, or `WidgetLayout::collapse_child` the widget",
WIDGET.trace_id()
)
}
}
},
_ => {}
})
}
fn visibility_eq_state(child: impl UiNode, state: impl IntoVar<bool>, expected: Visibility) -> impl UiNode {
event_state(
child,
state,
expected == Visibility::Visible,
info::VISIBILITY_CHANGED_EVENT,
move |a| {
let vis = a.tree.get(WIDGET.id()).map(|w| w.visibility()).unwrap_or(Visibility::Visible);
Some(vis == expected)
},
)
}
#[property(CONTEXT)]
pub fn is_visible(child: impl UiNode, state: impl IntoVar<bool>) -> impl UiNode {
visibility_eq_state(child, state, Visibility::Visible)
}
#[property(CONTEXT)]
pub fn is_hidden(child: impl UiNode, state: impl IntoVar<bool>) -> impl UiNode {
visibility_eq_state(child, state, Visibility::Hidden)
}
#[property(CONTEXT)]
pub fn is_collapsed(child: impl UiNode, state: impl IntoVar<bool>) -> impl UiNode {
visibility_eq_state(child, state, Visibility::Collapsed)
}
#[property(CONTEXT, default(true))]
pub fn auto_hide(child: impl UiNode, enabled: impl IntoVar<bool>) -> impl UiNode {
let enabled = enabled.into_var();
match_node(child, move |_, op| match op {
UiNodeOp::Init => {
WIDGET.sub_var(&enabled);
}
UiNodeOp::Update { .. } => {
if let Some(new) = enabled.get_new() {
if WIDGET.bounds().can_auto_hide() != new {
WIDGET.layout().render();
}
}
}
UiNodeOp::Layout { wl, .. } => {
wl.allow_auto_hide(enabled.get());
}
_ => {}
})
}
event_property! {
pub fn transform_changed {
event: info::TRANSFORM_CHANGED_EVENT,
args: info::TransformChangedArgs,
}
pub fn move {
event: info::TRANSFORM_CHANGED_EVENT,
args: info::TransformChangedArgs,
filter: |a| a.offset(WIDGET.id()).unwrap_or_default() != PxVector::zero(),
}
}