1use gpui::{
6 div, px, relative, Bounds, Context, EntityId, IntoElement, ParentElement, Pixels, Point,
7 Render, SharedString, Styled, Window,
8};
9
10use crate::SplitDirection;
11
12use super::{ItemId, PaneId};
13
14#[derive(Clone, Copy, PartialEq, Eq, Debug)]
16pub enum DropEdge {
17 Left,
18 Right,
19 Top,
20 Bottom,
21}
22
23impl DropEdge {
24 pub fn split(self) -> (SplitDirection, bool) {
26 match self {
27 DropEdge::Left => (SplitDirection::Horizontal, true),
28 DropEdge::Right => (SplitDirection::Horizontal, false),
29 DropEdge::Top => (SplitDirection::Vertical, true),
30 DropEdge::Bottom => (SplitDirection::Vertical, false),
31 }
32 }
33}
34
35#[derive(Clone)]
37pub struct TabDrag {
38 pub group: EntityId,
39 pub item: ItemId,
40 pub from_pane: PaneId,
41 pub label: SharedString,
42}
43
44impl Render for TabDrag {
45 fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
46 div()
47 .px(px(10.0))
48 .py(px(4.0))
49 .rounded(px(6.0))
50 .bg(gpui::rgb(0x2a2a2e))
51 .text_color(gpui::rgb(0xf2f2f7))
52 .text_size(px(12.0))
53 .child(self.label.clone())
54 }
55}
56
57const EDGE: f32 = 0.28;
59
60pub fn drop_edge(bounds: Bounds<Pixels>, cursor: Point<Pixels>) -> Option<DropEdge> {
63 let w = f32::from(bounds.size.width);
64 let h = f32::from(bounds.size.height);
65 if w <= 0.0 || h <= 0.0 {
66 return None;
67 }
68 let x = f32::from(cursor.x - bounds.origin.x);
69 let y = f32::from(cursor.y - bounds.origin.y);
70 if x < 0.0 || y < 0.0 || x > w || y > h {
71 return None;
72 }
73 let edge = w.min(h) * EDGE;
74 if x >= edge && x <= w - edge && y >= edge && y <= h - edge {
75 return None;
76 }
77 let (left, right, top, bottom) = (x, w - x, y, h - y);
78 let min = left.min(right).min(top).min(bottom);
79 Some(if min == left {
80 DropEdge::Left
81 } else if min == right {
82 DropEdge::Right
83 } else if min == top {
84 DropEdge::Top
85 } else {
86 DropEdge::Bottom
87 })
88}
89
90pub fn drop_overlay(edge: Option<DropEdge>) -> impl IntoElement {
93 let fill = gpui::rgba(0x4a9eff33);
94 let border = gpui::rgb(0x4a9eff);
95 let base = div().absolute().bg(fill).border_2().border_color(border);
96 match edge {
97 None => base.top_0().left_0().size_full(),
98 Some(DropEdge::Left) => base.top_0().left_0().bottom_0().w(relative(0.5)),
99 Some(DropEdge::Right) => base.top_0().right_0().bottom_0().w(relative(0.5)),
100 Some(DropEdge::Top) => base.top_0().left_0().right_0().h(relative(0.5)),
101 Some(DropEdge::Bottom) => base.bottom_0().left_0().right_0().h(relative(0.5)),
102 }
103}