drag_drop.rs

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