sokol_app.h: drag'n'drop discussion

Created on 28 Jul 2020  路  18Comments  路  Source: floooh/sokol

Issue for discussing details of file drag'n'drop in sokol_app.h.

General implementation should be:

  • a new file-dropped event type to notify the application that a file had been dropped on the window (Q: can this include coordinates where exactly the file was dropped?)
  • a separate function to get the file path or URL of the dropped file (since this might be pretty long it shouldn't be embedded in the event, but instead live in a separate internal buffer like the clipboard content).

It's up to the application what to do with the file path.

enhancement

Most helpful comment

Ok, I think I'll start integrating PR #349 next. I've been reading up on the HTML5 drag'n'drop API, and it's not really possible to completely decouple the drop-operation from loading the data, because the result of a drop-action is a list of opaque Javascript File objects, not (for instance) a list of filesystem paths (it's not even possible to access the filesystem path, only the filename without path, and the file size).

But I think this should work:

  • on native platforms, the PR works as is:

    • user code receives SAPP_EVENTTYPE_FILE_DROPPED
    • ...calls sapp_get_num_dropped_files() to get the number of dropped files
    • ...calls sapp_get_dropped_file_path(int index) to get the filesystem path of a dropped file, and loads the file data however it wants...
  • on web platform:

    • user code receives SAPP_EVENTTYPE_FILE_DROPPED
    • ...calls sapp_get_num_dropped_files() to get the number of dropped files
    • and then calls a new web specific function sapp_html5_load_dropped_file(int index) to load the file data into memory, not ideal from a "software design POV" because it's not cross-platform, but I don't want to add a whole filesystem abstraction layer to sokol_app.h too ;)

This new function sapp_html5_load_dropped_file() needs to be asynchronous, so I'll probably steal some ideas from sokol_fetch.h...

All 18 comments

For the web platform I have implemented very basic drag'n'drop support in my emulators completely on the Javascript side (just as example how the whole thing works in JS):

https://github.com/floooh/chips-test/blob/df11a99d4ab131fa90aef644effb9d1a64cdd591/webpage/emsc.html#L68-L90

I've extracted our changes to https://github.com/floooh/sokol/pull/346
We'll probably need iterate on it to unify with implementations for mac and linux. Though having simple file name pointers in event seem kinda fine to me?

Though having simple file name pointers in event seem kinda fine to me?

It probably would since the internal buffer would never move elsewhere, but I'd prefer not, to have it somewhat similar to the clipboard access (where you'd receive a pasted event and then call sapp_get_clipboard_string(). Since all event types share the same event structure, I'd like to not put too much stuff in there for "exotic" events :)

I鈥檒l finish up macOS today and remove my clipboard hijacking antics ;)

Since this is a short lived event is the plan with the buffer to do something like this or a different strategy:

  • os drop event occurs
  • dupe the path to a buffer
  • fire the sapp dropped event
  • (user is expected to fetch the file path here)
  • free throws buffer

I pulled in the changes from @hb3p8 for Windows and made the macOS version follow the same paradigm. This is all in PR #347.

@floooh: this currently passes along the paths and count along with the event. Should we separate out the file path data and add a const char** sapp_get_dropped_files(void) method and just leave the drop_files_count in the event?

@floooh: Just reread your comment and see that you prefer sapp_get_dropped_files. I'll swap over the win/macOS implementations to go that route.

OK, updated the PR. I have near zero WebGL experience so I have no idea where that code would live in the sokol_app file. I'll move on to Linux supper later today if all goes well.

Since this is a short lived event is the plan with the buffer to do something like this or a different strategy:

I would prefer the same as with the clipboard buffer (e.g. only allocate once at startup, and free once at shutdown):

  • user can provide a maximum buffer size in sapp_desc or use the default size
  • buffer is allocated once at startup
  • when a dropped event comes in from the platform the "payload" is copied into the buffer and (if too long) silently(?) clamped - alternatively some sort of error should be reported, maybe in the event.
  • the SAPP event is sent to notify the user code
  • sapp_get_dropped_files() returns whatever is currently in the dropped-buffer (so it can be called right in the sokol-app event handler or later outside)
  • The buffer is never freed (except at shutdown), it's only overwritten with new content. That way the address also remains stable and the user code can't end up with a dangling pointer.

If we allow multiple files to be dropped at the same time we need to figure out a better "API" for the function to get the file paths. Maybe two functions instead?

int sapp_get_num_dropped_files(void);
const char* sapp_get_dropped_file_path(int index);

...and instead of providing a single dropped-buffer size, instead:

int max_dropped_files;
int max_dropped_file_path_length;

(not happy yet with the names, but anyway...)

...again the idea being that the returned addresses remain stable, e.g. sapp_get_dropped_file_path(1) would always return the same address of a "path buffer slot", instead of a random address in a big buffer which holds multiple strings, so that one could end up pointing into the middle of a string if the content of the drop buffer changes).

The drop buffer should probably still be a single allocation, which is then "partitioned" into slots.

Gotcha. Assuming the multi-file route, the buffer size would then just be max_dropped_files * max_dropped_file_path_length allocated at startup and freed at shutdown. I see you already have SOKOL_STRCPY in there for truncated strings as well.

I鈥檒l switch over Mac/win to this API today. What do you prefer default values to be? 1 and 1024 perhaps?

Reworked the API in PR #349

Max file path lengths for each OS:

  • Windows MAX_PATH is 260 characters (although NTFS can support MUCH more...)
  • OSX max path is 1024 characters
  • iOS max path is 1024 characters
  • Linux max path is 4096 characters
  • Android undefined fallback to Linux

You should be able to set this depending on OS and get sane defaults. (Or just use 4096 and it should work for everyone...)

Can you really drag and drop files from different locations?
So to be memory optimized, it would be better to have one base path and then multiple file names.

whats the status on this? i think drag&drop is a must have - i have seen some PR's which look good to me

I haven't looked into it in detail yet, but I think it will be this PR:

https://github.com/floooh/sokol/pull/349

Some conflicts that must be resolved, and I think an envent SAPP_EVENTTYPE_DROPPED should be added (similar to SAPP_EVENTTYPE_PASTED), so that an application can decide between polling each frame, or only querying the drop-result when the event happened.

I鈥檝e been using this since I opened the PR. Works quite well.

@floooh there is a dropped event in there already: https://github.com/prime31/sokol/blob/0817b779d308e28e0fe9922667cc945c890f22c0/sokol_app.h#L659

there is a dropped event in there already

Whoops I missed that sorry. One thing I still need to figure out is whether that proposed API can also be used for the web, the drag'n'drop code I wrote for my emulators receives opaque JS File objects from the drop events, and then directly uses those File objects with the JS FileReader class to load the file content into a blob (so the drop event is closely coupled to loading the file content). Question is whether I can get some sort of path/URL from a File object to decouple the drop-event from the file reading operation.

Is this isn't possible I need to come up with special API functions for WASM, and a way to tunnel the JS File object out of sokol_app.h, both things don't sound all that great...

...somehow I seem to be clicking on links which lead to outdated PR commits, I think this is why I missed the dropped event, and now the same happened with calloc/free vs SOKOL_CALLOC/SOKOL_FREE... there is one place where a call to free() is still there though. I added a comment to the PR.

Ok, I think I'll start integrating PR #349 next. I've been reading up on the HTML5 drag'n'drop API, and it's not really possible to completely decouple the drop-operation from loading the data, because the result of a drop-action is a list of opaque Javascript File objects, not (for instance) a list of filesystem paths (it's not even possible to access the filesystem path, only the filename without path, and the file size).

But I think this should work:

  • on native platforms, the PR works as is:

    • user code receives SAPP_EVENTTYPE_FILE_DROPPED
    • ...calls sapp_get_num_dropped_files() to get the number of dropped files
    • ...calls sapp_get_dropped_file_path(int index) to get the filesystem path of a dropped file, and loads the file data however it wants...
  • on web platform:

    • user code receives SAPP_EVENTTYPE_FILE_DROPPED
    • ...calls sapp_get_num_dropped_files() to get the number of dropped files
    • and then calls a new web specific function sapp_html5_load_dropped_file(int index) to load the file data into memory, not ideal from a "software design POV" because it's not cross-platform, but I don't want to add a whole filesystem abstraction layer to sokol_app.h too ;)

This new function sapp_html5_load_dropped_file() needs to be asynchronous, so I'll probably steal some ideas from sokol_fetch.h...

Closing this since the drag'n'drop implementation for Win32+macOS+Linux has been merged, I'll work on the WASM/HTML5 stuff next.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

PeterHiber picture PeterHiber  路  5Comments

ilar81 picture ilar81  路  7Comments

siavashserver picture siavashserver  路  6Comments

floooh picture floooh  路  3Comments

datgame picture datgame  路  6Comments