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