-
Notifications
You must be signed in to change notification settings - Fork 380
Adding dragdrop support #428
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
Okay then, I think there are roughly three ways to use this API that we should support.
fn show_ui(ui: &imgui::Ui<'_>) {
static NAME_PAYLOAD_HANDLER: Lazy<Mutex<Option<String>>> = Lazy::new(|| Mutex::new(None));
ui.button(im_str!("Drag me!"));
if imgui::DragDropSource::new(im_str!("Test Drag")).begin(ui).is_some() {
*NAME_PAYLOAD_HANDLER.lock() = Some("Drag me!".to_string());
}
ui.button(im_str!("Target me!"));
// drag drop TARGET
if let Some(target) = imgui::DragDropTarget::new(ui) {
if target
.accept_drag_drop_payload(im_str!("Test Drag"), imgui::DragDropFlags::empty())
.is_some()
{
if let Some(msg) = NAME_PAYLOAD_HANDLER.lock().take() {
println!("Message is {}", msg);
}
}
target.pop();
}
} Effectively, the payload is just a signal that the Lazy has data in it. The Lazy is not necessary, but convenient.
|
Yeah it's fine if stuff leaks so long as that's properly signposted in the API and it's either safe (or requires the |
@thomcc yup, sounds good. the current plan is that Additionally, there will be Last up is A question for |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lots of comments, since this code is pretty tricky. Broadly summarizing:
- I think the unsafe code needs to worry more about align_of::
- PhantomData should probably be over a reference not a value
- There are some tricks we can do to improve error reporting for debugging
- I find what's public and non-public confusing/inconsistent in this API.
- Several less serious nits.
P.S. thanks for the docs, made this much easier.
delivery: unsafe_payload.delivery, | ||
}) | ||
} else { | ||
Err(PayloadIsWrongType { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Certainly here we could easily know type_name
of the expected type. If we store the type_name of the actual type on TypedPayload, the debugging experience might improve as mentioned elsewhere.
|
||
/// Ends the current target. Ironically, this doesn't really do anything in ImGui | ||
/// or in imgui-rs, but it might in the future. | ||
pub fn pop(self) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto with end/pop concerns.
imgui/src/drag_drop.rs
Outdated
pub data: *const ffi::c_void, | ||
|
||
/// The size of the data in bytes. | ||
pub size: i32, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this type is not a mapping of a C++ type (hopefully! It's not #[repr(C)]!) we should probably use usize
here and just handle the conversion ourselves rather than pushing it to the user.
let should_begin = sys::igBeginDragDropSource(self.flags.bits() as i32); | ||
|
||
if should_begin { | ||
sys::igSetDragDropPayload(self.name.as_ptr(), ptr, size, self.cond as i32); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, i think imgui c++ tends to truncate usize to 32 bits (often signed). We should probably have an assert somewhere that the size is within that... (I assume this is one of the places where that happens, since we have an i32 size later on).
... I bet our existing code mishandles this too in lots of places...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
left this unimplemented for now, mostly because it's just very late -- will add a note in a second
PHEW -- okay @thomcc -- addressed all of the above except handling >i32 size packets. i think we'll wnat to look at the rest of the codebase for that / also i'm very tired. One thing to bring your attention to is like 467 and line 335 where I read off half the struct. Is that sound? I believe it is since both are repr(C), but want to make sure in your opinion if they are. Also, let me know if this way of doing cfgs is fine. I wasn't trying to get too clever here |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Needs a changelog entry and module header comment for the newly-pub mod, but other than that looks great.
imgui/src/drag_drop.rs
Outdated
} | ||
|
||
/// Indicates that an incorrect payload type was received. It is opaque, | ||
/// but you can view questionably useful debug information with Debug formatting. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
questionably useful
Yeah I mean, having the type name in debug builds would helps a lot. I've had to debug "what the fuck is in this Box<dyn Any>
"-issues before and it was... not fun.
That said if you don't think it's useful, feel free to push back on review comments I make in the future.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah no sorry, this comment predates adding the typename -- I hadn't thought of that idea at the time. Will remove -- I was previously just dumping out the typeid which is definitely "questionably" useful at best since it's not like a user could tell what that was. Now it's definitely useful
@@ -0,0 +1,534 @@ | |||
use std::{any, ffi, marker::PhantomData}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this is pub mod
now: Can you add a //!
that says this module is for the drag and drop stuff, but the most commonly used types are reexported at the crate root.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will do along with a changelog
Okay! will merge in the morning in case there are any last minute edits |
In the future can you update branches by rebasing rather than merging (e.g. |
Hello,
This shouldn't be merged in its current form.
I'm looking for some comments and ideas on how we can make this better.
Right now, the API for drag/drop with nothing in the payload is basically good to go -- however, that's not very useful! So we get into a more complicated situation with handling drag/drop with data in it.
ImGui will copy (with just a simple memcpy) the fat pointer (ptr + size) we provide to it. There are tons of edge cases (I'm not even sure they're "edge", really just unsafety is everywhere), so I've made only the uber unsafe version right now. There are, however, some safe variants we could claw back if we were willing to wrap this API. Specifically, I'm imagining:
This though, isn't really what we want. Really, we want to say "gimme some Pod". We might be able to use bytemuck's Pod trait here, but that would be another dependency.
The case we really want to be able to handle isn't arbitrary data though, but Strings (since users can encode arbitrary data in strings), and we COULD handle this manually, reducing a string to raw parts and then reconstructing it in
accept_payload
. However, that's got a serious downside -- that string will never be deallocated by ImGui. This isn't memory unsafety, but it is a huge problem that we can't accept.Imo, the solution I would gravitate towards is using an AnyMap type struct and then encoding usize's of TypeId and putting that in the payload. Users would just get the typeid out of
accept_payload
and handle getting the "real" data from there. That should probably be in UserLand code, not in imgui, although I'm not against ImGui handling that either.Anyway, I'm curious what you think. I haven't done much rust FFI, so I may have made some newbie mistakes. Looking forward to any pointers! (I've left a few @fixme throughout the code for weird issues I ran into)