drag_drop.rs

  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}