Skip to content
Snippets Groups Projects
details.rs 5.06 KiB
Newer Older
Louis's avatar
Louis committed
use bevy::prelude::*;
use kayak_ui_macros::rsx;

use crate::{
    children::KChildren,
    context::WidgetName,
    prelude::KayakWidgetContext,
    styles::{ComputedStyles, KStyle, LayoutType, Units},
    widget::Widget,
    widgets::{
        create_transition, BackgroundBundle, ClipBundle, Transition, TransitionEasing,
        TransitionProps, TransitionState,
    },
};

use super::AccordionContext;

#[derive(Component, Default, Debug, Clone, PartialEq)]
pub struct AccordionDetails {
    pub index: usize,
}

impl Widget for AccordionDetails {}

#[derive(Bundle, Debug, Clone, PartialEq)]
pub struct AccordionDetailsBundle {
    pub accordion: AccordionDetails,
    pub children: KChildren,
    pub computed_styles: ComputedStyles,
    pub widget_name: WidgetName,
}

impl Default for AccordionDetailsBundle {
    fn default() -> Self {
        Self {
            accordion: Default::default(),
            children: Default::default(),
            computed_styles: Default::default(),
            widget_name: AccordionDetails::default().get_name(),
        }
    }
}

pub fn render(
    In(accordion_widget): In<Entity>,
    widget_context: Res<KayakWidgetContext>,
    mut commands: Commands,
    mut query: Query<(&AccordionDetails, &KChildren)>,
    context_query: Query<&AccordionContext>,
    mut transition_state_query: Query<&mut TransitionState>,
) -> bool {
    if let Ok((accordion, passed_children)) = query.get_mut(accordion_widget) {
        if let Some(context_entity) =
            widget_context.get_context_entity::<AccordionContext>(accordion_widget)
        {
            if let Ok(context) = context_query.get(context_entity) {
                let mut children_height = 0.0;
                if let Some(parent_layout) = widget_context.get_layout(accordion_widget) {
                    // Start with 20 the size of the margin for the parent.
                    let mut previous_y = parent_layout.posy - 20.0;
                    for child in passed_children.iter() {
                        let layout = widget_context.get_layout(*child).unwrap_or_default();
                        children_height += layout.posy - previous_y;
                        children_height += layout.height;
                        previous_y = layout.posy + layout.height;
                    }
                }

                let transition_props = TransitionProps {
                    easing: TransitionEasing::QuadraticInOut,
                    reversing: !context.is_open(accordion.index),
                    timeout: 200.0,
                    looping: false,
                    style_a: KStyle {
                        height: Units::Pixels(0.0).into(),
                        ..Default::default()
                    },
                    style_b: KStyle {
                        height: Units::Pixels(children_height).into(),
                        ..Default::default()
                    },
                    autoplay: false, // When the animation first initializes we want it to be at the end of the animation.
                };

                let transition_entity: Entity = create_transition(
                    &widget_context,
                    &mut commands,
                    accordion_widget,
                    &Transition::new(&transition_props),
                );

                if let Ok(mut transition_state) = transition_state_query.get_mut(transition_entity)
                {
                    transition_state.transition.style_b.height =
                        Units::Pixels(children_height).into();
                    if transition_state.transition.reversing != transition_props.reversing {
                        transition_state.transition.style_b.height =
                            Units::Pixels(children_height).into();
                        if transition_props.reversing {
                            transition_state.transition.start_reverse()
                        } else {
                            transition_state.transition.start();
                        }
                    }
                }

                let parent_id = Some(accordion_widget);
                rsx! {
                    <BackgroundBundle
                        styles={KStyle {
                            background_color: Color::rgba(0.133, 0.145, 0.2, 1.0).into(),
                            layout_type: LayoutType::Row.into(),
                            height: Units::Stretch(1.0).into(),
                            ..Default::default()
                        }}
                    >
                        <ClipBundle
                            styles={KStyle {
                                top: Units::Pixels(10.0).into(),
                                left: Units::Pixels(10.0).into(),
                                right: Units::Pixels(10.0).into(),
                                bottom: Units::Pixels(10.0).into(),
                                ..Default::default()
                            }}
                            children={passed_children.clone()}
                        />
                    </BackgroundBundle>
                };
            }
        }
    }

    true
}