bezel-ui 0.2.25

SwiftUI-flavored components for gpui — popovers, menus, buttons, toggles, and loaders
Documentation
use gpui::{
    Context, Entity, Modifiers, MouseButton, Render, TestAppContext, VisualTestContext, Window,
    div, point, prelude::*, px, size,
};
use theme::{Appearance, Theme};
use ui::split::Split;

struct Host {
    ratios: [f32; 2],
    vertical: bool,
}

impl Render for Host {
    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
        div()
            .size_full()
            .flex()
            .flex_col()
            .children((0..2).map(|i| {
                let make = if self.vertical {
                    Split::vertical
                } else {
                    Split::horizontal
                };
                make(
                    ("split", i),
                    div()
                        .size_full()
                        .debug_selector(move || format!("first-{i}")),
                    div()
                        .size_full()
                        .debug_selector(move || format!("second-{i}")),
                )
                .ratio(self.ratios[i])
                .min(px(if self.vertical { 10.0 } else { 50.0 }))
                .h(px(100.0))
                .on_resize(cx.listener(move |host, ratio, _, cx| {
                    host.ratios[i] = *ratio;
                    cx.notify();
                }))
            }))
    }
}

fn host(cx: &mut TestAppContext) -> (Entity<Host>, VisualTestContext) {
    cx.update(|cx| Theme::install(Appearance::Dark, cx));
    let window = cx.add_window(|_, _| Host {
        ratios: [0.5, 0.25],
        vertical: false,
    });
    let host = window.root(cx).unwrap();
    let visual = VisualTestContext::from_window(window.into(), cx);
    visual.simulate_resize(size(px(409.0), px(200.0)));
    visual.run_until_parked();
    (host, visual)
}

#[gpui::test]
fn ratios_exclude_the_divider_and_minimums_constrain_layout(cx: &mut TestAppContext) {
    let (host, mut cx) = host(cx);
    assert_eq!(cx.debug_bounds("first-0").unwrap().size.width, px(200.0));
    assert_eq!(cx.debug_bounds("first-1").unwrap().size.width, px(100.0));
    cx.update(|_, cx| {
        host.update(cx, |host, cx| {
            host.ratios[0] = 0.0;
            cx.notify();
        })
    });
    cx.run_until_parked();
    assert_eq!(cx.debug_bounds("first-0").unwrap().size.width, px(50.0));
    assert_eq!(cx.debug_bounds("second-0").unwrap().size.width, px(350.0));
}

#[gpui::test]
fn a_drag_updates_only_its_split_and_stops_at_the_minimum(cx: &mut TestAppContext) {
    let (host, mut cx) = host(cx);
    let start = point(px(204.5), px(50.0));
    cx.simulate_mouse_move(start, None, Modifiers::default());
    cx.simulate_mouse_down(start, MouseButton::Left, Modifiers::default());
    for x in [210.0, 300.0, 408.0] {
        cx.simulate_mouse_move(
            point(px(x), px(50.0)),
            MouseButton::Left,
            Modifiers::default(),
        );
        cx.run_until_parked();
    }
    cx.simulate_mouse_up(
        point(px(408.0), px(50.0)),
        MouseButton::Left,
        Modifiers::default(),
    );
    cx.run_until_parked();
    let ratios = cx.update(|_, cx| host.read(cx).ratios);
    assert_eq!(ratios, [0.875, 0.25]);
    assert_eq!(cx.debug_bounds("second-0").unwrap().size.width, px(50.0));
}

#[gpui::test]
fn vertical_splits_resize_along_the_y_axis(cx: &mut TestAppContext) {
    let (host, mut cx) = host(cx);
    cx.update(|_, cx| {
        host.update(cx, |host, cx| {
            host.vertical = true;
            cx.notify();
        })
    });
    cx.run_until_parked();
    let first = cx.debug_bounds("first-0").unwrap();
    assert!((first.size.height - px(45.5)).abs() < px(1.0), "{first:?}");
    let start = point(px(100.0), first.bottom() + px(4.5));
    cx.simulate_mouse_move(start, None, Modifiers::default());
    cx.simulate_mouse_down(start, MouseButton::Left, Modifiers::default());
    for y in [55.0, 80.0] {
        cx.simulate_mouse_move(
            point(px(100.0), px(y)),
            MouseButton::Left,
            Modifiers::default(),
        );
        cx.run_until_parked();
    }
    cx.simulate_mouse_up(
        point(px(100.0), px(80.0)),
        MouseButton::Left,
        Modifiers::default(),
    );
    let ratios = cx.update(|_, cx| host.read(cx).ratios);
    assert!(ratios[0] > 0.75);
    assert_eq!(ratios[1], 0.25);
}