1use gpui::{
2 App, Application, Bounds, Context, Half, Hsla, Pixels, Point, Window, WindowBounds,
3 WindowOptions, div, prelude::*, px, rgb, size,
4};
5
6#[derive(Clone, Copy)]
7struct DragInfo {
8 ix: usize,
9 color: Hsla,
10 position: Point<Pixels>,
11}
12
13impl DragInfo {
14 fn new(ix: usize, color: Hsla) -> Self {
15 Self {
16 ix,
17 color,
18 position: Point::default(),
19 }
20 }
21
22 fn position(mut self, pos: Point<Pixels>) -> Self {
23 self.position = pos;
24 self
25 }
26}
27
28impl Render for DragInfo {
29 fn render(&mut self, _: &mut Window, _: &mut Context<'_, Self>) -> impl IntoElement {
30 let size = gpui::size(px(120.), px(50.));
31
32 div()
33 .pl(self.position.x - size.width.half())
34 .pt(self.position.y - size.height.half())
35 .child(
36 div()
37 .flex()
38 .justify_center()
39 .items_center()
40 .w(size.width)
41 .h(size.height)
42 .bg(self.color.opacity(0.5))
43 .text_color(gpui::white())
44 .text_xs()
45 .shadow_md()
46 .child(format!("Item {}", self.ix)),
47 )
48 }
49}
50
51struct DragDrop {
52 drop_on: Option<DragInfo>,
53}
54
55impl DragDrop {
56 fn new() -> Self {
57 Self { drop_on: None }
58 }
59}
60
61impl Render for DragDrop {
62 fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
63 let items = [gpui::blue(), gpui::red(), gpui::green()];
64
65 div()
66 .size_full()
67 .flex()
68 .flex_col()
69 .gap_5()
70 .bg(gpui::white())
71 .justify_center()
72 .items_center()
73 .text_color(rgb(0x333333))
74 .child(div().text_xl().text_center().child("Drop & Drop"))
75 .child(
76 div()
77 .w_full()
78 .mb_10()
79 .justify_center()
80 .flex()
81 .flex_row()
82 .gap_4()
83 .items_center()
84 .children(items.into_iter().enumerate().map(|(ix, color)| {
85 let drag_info = DragInfo::new(ix, color);
86
87 div()
88 .id(("item", ix))
89 .size_32()
90 .flex()
91 .justify_center()
92 .items_center()
93 .border_2()
94 .border_color(color)
95 .text_color(color)
96 .cursor_move()
97 .hover(|this| this.bg(color.opacity(0.2)))
98 .child(format!("Item ({})", ix))
99 .on_drag(drag_info, |info: &DragInfo, position, _, cx| {
100 cx.new(|_| info.position(position))
101 })
102 })),
103 )
104 .child(
105 div()
106 .id("drop-target")
107 .w_128()
108 .h_32()
109 .flex()
110 .justify_center()
111 .items_center()
112 .border_3()
113 .border_color(self.drop_on.map(|info| info.color).unwrap_or(gpui::black()))
114 .when_some(self.drop_on, |this, info| this.bg(info.color.opacity(0.5)))
115 .on_drop(cx.listener(|this, info: &DragInfo, _, _| {
116 this.drop_on = Some(*info);
117 }))
118 .child("Drop items here"),
119 )
120 }
121}
122
123fn main() {
124 Application::new().run(|cx: &mut App| {
125 let bounds = Bounds::centered(None, size(px(800.), px(600.0)), cx);
126 cx.open_window(
127 WindowOptions {
128 window_bounds: Some(WindowBounds::Windowed(bounds)),
129 ..Default::default()
130 },
131 |_, cx| cx.new(|_| DragDrop::new()),
132 )
133 .unwrap();
134
135 cx.activate(true);
136 });
137}