Skip to main content

native/guppy_nif/src/bridge_view/render_scroll.rs

use super::{identity::NodeIdentity, render_pass::RenderPass, style::apply_div_style};
use crate::bridge_view::BridgeView;
use crate::ir::{DivStyle, IrNode, ScrollAxis};
use gpui::{
    AnyElement, Context, InteractiveElement, IntoElement, ParentElement,
    StatefulInteractiveElement, Styled, Window, div,
};

pub(crate) struct ScrollSpec<'a> {
    pub path: &'a str,
    pub id: Option<&'a str>,
    pub axis: ScrollAxis,
    pub style: &'a DivStyle,
    pub children: &'a [IrNode],
}

pub(crate) fn render(
    pass: &mut RenderPass<'_>,
    spec: ScrollSpec<'_>,
    window: &mut Window,
    cx: &mut Context<BridgeView>,
) -> AnyElement {
    let node_id = NodeIdentity::new(pass.view_id(), spec.path, spec.id);
    let scroll_handle = pass.retain_scroll_handle(node_id.as_ref());
    let child_elements = pass.render_children(
        spec.path,
        spec.children,
        Some(scroll_handle.clone()),
        window,
        cx,
    );

    let element = apply_div_style(
        div()
            .id(node_id.to_shared_string())
            .children(child_elements)
            .track_scroll(&scroll_handle),
        spec.style,
    );

    let mut element = match spec.axis {
        ScrollAxis::X => element.overflow_x_scroll(),
        ScrollAxis::Y => element.overflow_y_scroll(),
        ScrollAxis::Both => element.overflow_scroll(),
    };

    if should_restrict_scroll_to_axis(spec.axis) {
        element.style().restrict_scroll_to_axis = Some(true);
    }

    element.into_any_element()
}

fn should_restrict_scroll_to_axis(axis: ScrollAxis) -> bool {
    matches!(axis, ScrollAxis::X | ScrollAxis::Y)
}

#[cfg(test)]
mod tests {
    use super::should_restrict_scroll_to_axis;
    use crate::ir::ScrollAxis;

    #[test]
    fn axis_specific_scroll_nodes_restrict_wheel_translation() {
        assert!(should_restrict_scroll_to_axis(ScrollAxis::X));
        assert!(should_restrict_scroll_to_axis(ScrollAxis::Y));
        assert!(!should_restrict_scroll_to_axis(ScrollAxis::Both));
    }
}