use gpui_kit::component::button::{Button, ButtonVariants as _};
use gpui_kit::component::resizable::{resize_handle, HandleEdge};
use gpui_kit::component::{v_flex, ActiveTheme as _, Icon, Selectable as _};
use gpui_kit::{div, px, App, AppContext as _, Axis, Context, DragMoveEvent, Entity, IntoElement, ParentElement as _, Render, SharedString, Styled as _, Window};
use crate::data::store::Store;
pub const MIN_PANEL: f32 = 180.;
pub const MAX_PANEL: f32 = 760.;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Side {
Left,
Right,
Bottom,
}
#[derive(Debug, Clone)]
pub struct PanelResize {
pub key: &'static str,
pub side: Side,
pub offset: f32,
}
impl Render for PanelResize {
fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
div()
}
}
pub fn panel_edge(key: &'static str, side: Side, offset: f32) -> impl IntoElement {
let (axis, edge) = match side {
Side::Left => (Axis::Horizontal, HandleEdge::Trailing),
Side::Right => (Axis::Horizontal, HandleEdge::Leading),
Side::Bottom => (Axis::Vertical, HandleEdge::Leading),
};
resize_handle::<PanelResize, PanelResize>(SharedString::from(format!("panel-edge-{key}")), axis)
.inside(edge)
.on_drag(PanelResize { key, side, offset }, |d, _, _, cx| cx.new(|_| d.clone()))
}
pub fn follow_panel_drag(store: &Entity<Store>, e: &DragMoveEvent<PanelResize>, cx: &mut App) {
let r = e.drag(cx).clone();
let (b, p) = (e.bounds, e.event.position);
let size = match r.side {
Side::Left => (p.x - b.origin.x).as_f32() - r.offset,
Side::Right => (b.origin.x + b.size.width - p.x).as_f32() - r.offset,
Side::Bottom => (b.origin.y + b.size.height - p.y).as_f32() - r.offset,
};
let max = match r.side {
Side::Bottom => (b.size.height.as_f32() * 0.8).max(MIN_PANEL),
_ => MAX_PANEL.min(b.size.width.as_f32() * 0.45).max(MIN_PANEL),
};
let min = if r.side == Side::Bottom { 60.0 } else { MIN_PANEL };
store.update(cx, |s, cx| s.set_panel_width(r.key, size.clamp(min, max), cx));
}
pub const RAIL_W: f32 = 40.;
pub struct RailItem {
pub id: SharedString,
pub icon: Icon,
pub tip: SharedString,
pub selected: bool,
pub on_click: Box<dyn Fn(&mut Window, &mut App)>,
}
pub fn rail(items: Vec<RailItem>, left: bool, cx: &App) -> impl IntoElement + use<> {
let t = cx.theme();
let bar = v_flex().w(px(RAIL_W)).flex_none().h_full().py_2().gap_1().items_center().bg(t.sidebar).border_color(t.border);
let bar = if left { bar.border_r_1() } else { bar.border_l_1() };
bar.children(items.into_iter().map(|it| {
let f = it.on_click;
Button::new(gpui_kit::ElementId::Name(it.id)).ghost().icon(it.icon).tooltip(it.tip).selected(it.selected).on_click(move |_, window, cx| f(window, cx))
}))
}
pub fn toggle_item(store: &Entity<Store>, key: &'static str, icon: Icon, tip: &'static str, cx: &App) -> RailItem {
let open = store.read(cx).panel_open(key);
let store = store.clone();
RailItem {
id: SharedString::from(format!("rail-{key}")),
icon,
tip: tip.into(),
selected: open,
on_click: Box::new(move |_, cx| store.update(cx, |s, cx| s.set_panel_open(key, !open, cx))),
}
}