drag_drop.rs

  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}