Skip to main content

dear_imgui_rs/drag_drop/
target.rs

1use super::flags::{DragDropTargetFlags, validate_drag_drop_target_flags};
2use super::payload::{
3    DragDropPayload, DragDropPayloadEmpty, DragDropPayloadPod, PayloadIsWrongType,
4    decode_typed_payload,
5};
6use super::validation::validate_payload_type_name;
7use crate::{Ui, sys};
8
9/// Drag drop target for accepting payloads
10///
11/// This struct is created by [`Ui::drag_drop_target`] and provides
12/// methods for accepting different types of payloads.
13#[derive(Debug)]
14pub struct DragDropTarget<'ui>(pub(super) &'ui Ui);
15
16impl<'ui> DragDropTarget<'ui> {
17    /// Accept an empty payload
18    ///
19    /// This is the safest option for drag and drop operations.
20    /// Use this when you only need to know that a drop occurred,
21    /// not transfer actual data.
22    ///
23    /// # Arguments
24    /// * `name` - Payload type name (must match source name)
25    /// * `flags` - Accept flags
26    ///
27    /// Returns payload info if accepted, `None` otherwise.
28    pub fn accept_payload_empty(
29        &self,
30        name: impl AsRef<str>,
31        flags: DragDropTargetFlags,
32    ) -> Option<DragDropPayloadEmpty> {
33        self.accept_payload(name, flags)?
34            .ok()
35            .map(|payload_pod: DragDropPayloadPod<()>| DragDropPayloadEmpty {
36                preview: payload_pod.preview,
37                delivery: payload_pod.delivery,
38            })
39    }
40
41    /// Accept a typed payload
42    ///
43    /// Attempts to accept a payload with the specified type.
44    /// Returns `Ok(payload)` if the type matches, `Err(PayloadIsWrongType)` if not.
45    ///
46    /// # Arguments
47    /// * `name` - Payload type name (must match source name)
48    /// * `flags` - Accept flags
49    ///
50    /// Returns `Some(Result<payload, error>)` if payload exists, `None` otherwise.
51    pub fn accept_payload<T: 'static + Copy, Name: AsRef<str>>(
52        &self,
53        name: Name,
54        flags: DragDropTargetFlags,
55    ) -> Option<Result<DragDropPayloadPod<T>, PayloadIsWrongType>> {
56        let output = unsafe { self.accept_payload_unchecked(name, flags) };
57
58        output.map(decode_typed_payload)
59    }
60
61    /// Accept raw payload data (unsafe)
62    ///
63    /// # Safety
64    /// The returned pointer and size are managed by ImGui and may become
65    /// invalid at any time. The caller must not access the data after
66    /// the drag operation completes.
67    ///
68    /// # Arguments
69    /// * `name` - Payload type name
70    /// * `flags` - Accept flags
71    pub unsafe fn accept_payload_unchecked(
72        &self,
73        name: impl AsRef<str>,
74        flags: DragDropTargetFlags,
75    ) -> Option<DragDropPayload> {
76        validate_payload_type_name(name.as_ref(), "DragDropTarget::accept_payload_unchecked()");
77        validate_drag_drop_target_flags("DragDropTarget::accept_payload_unchecked()", flags);
78        let name = self.0.scratch_txt(name);
79        let inner = self.0.run_with_bound_context(|| unsafe {
80            sys::igAcceptDragDropPayload(name, flags.bits() as i32)
81        });
82
83        if inner.is_null() {
84            None
85        } else {
86            Some(DragDropPayload::from_raw(unsafe { *inner }))
87        }
88    }
89
90    /// End the drag drop target
91    ///
92    /// This is called automatically when the token is dropped.
93    pub fn pop(self) {
94        // Drop will handle cleanup
95    }
96}
97
98impl Drop for DragDropTarget<'_> {
99    fn drop(&mut self) {
100        self.0.run_with_bound_context(|| unsafe {
101            sys::igEndDragDropTarget();
102        });
103    }
104}