-
Notifications
You must be signed in to change notification settings - Fork 69
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
Introduce drag and drop handling #83
Conversation
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.
clang-tidy made some suggestions
examples/drag_and_drop.cpp
Outdated
os::draw_text(s, nullptr, buf, gfx::Point(0, y), &paint); | ||
y += 12; | ||
|
||
for (auto line : lines) { |
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.
warning: 'auto line' can be declared as 'const auto *line' [readability-qualified-auto]
for (auto line : lines) { | |
for (const auto *line : lines) { |
examples/drag_and_drop.cpp
Outdated
{ | ||
// If all windows are hidden, show them again | ||
auto hidden = std::count_if(windows.begin(), windows.end(), | ||
[](os::WindowRef window){ |
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.
warning: the parameter 'window' is copied for each invocation but only used as a const reference; consider making it a const reference [performance-unnecessary-value-param]
[](os::WindowRef window){ | |
[](const os::WindowRef& window){ |
examples/drag_and_drop.cpp
Outdated
}); | ||
if (hidden == windows.size()) { | ||
std::for_each(windows.begin(), windows.end(), | ||
[](os::WindowRef window){ |
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.
warning: the parameter 'window' is copied for each invocation but only used as a const reference; consider making it a const reference [performance-unnecessary-value-param]
[](os::WindowRef window){ | |
[](const os::WindowRef& window){ |
examples/drag_and_drop.cpp
Outdated
os::ScreenList screens; | ||
system->listScreens(screens); | ||
char chr = 'A'; | ||
for (os::ScreenRef& screen : screens) { |
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.
warning: variable 'screen' of type 'os::ScreenRef &' (aka 'Refos::Screen &') can be declared 'const' [misc-const-correctness]
for (os::ScreenRef& screen : screens) { | |
for (os::ScreenRef const& screen : screens) { |
examples/drag_and_drop.cpp
Outdated
for (auto& p : pos) { | ||
os::WindowSpec s = spec; | ||
gfx::Rect frame = s.frame(); | ||
frame.x += frame.w*p.x; |
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.
warning: narrowing conversion from 'double' to 'int' [bugprone-narrowing-conversions]
frame.x += frame.w*p.x;
^
examples/drag_and_drop.cpp
Outdated
os::WindowSpec s = spec; | ||
gfx::Rect frame = s.frame(); | ||
frame.x += frame.w*p.x; | ||
frame.y += frame.h*p.y; |
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.
warning: narrowing conversion from 'double' to 'int' [bugprone-narrowing-conversions]
frame.y += frame.h*p.y;
^
examples/drag_and_drop.cpp
Outdated
|
||
// Duplicate window | ||
case os::kKeyD: { | ||
std::string title = ev.window()->title(); |
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.
warning: variable 'title' of type 'std::string' (aka 'basic_string') can be declared 'const' [misc-const-correctness]
std::string title = ev.window()->title(); | |
std::string const title = ev.window()->title(); |
examples/drag_and_drop.cpp
Outdated
case os::kKeyF: | ||
case os::kKeyC: | ||
case os::kKeyW: { | ||
std::string title = ev.window()->title(); |
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.
warning: variable 'title' of type 'std::string' (aka 'basic_string') can be declared 'const' [misc-const-correctness]
std::string title = ev.window()->title(); | |
std::string const title = ev.window()->title(); |
@dacap this is just to iterate over the design of the solution. This is not complete, just has the basic elements I come up with to draft a first approach to drag and drop handling. Let me know if you had something different in mind, because I also had another idea involving observers, but since we are not using observers in laf I had discarded that idea. |
Although it's not a bad idea to use these kind of delegates, I think it will make a little harder to process the events in the same order in Aseprite I think it would be better to keep all event handling as a queue of events (so we know the exact order of events). |
Actually my first approach was just about translating the event to laf as it is done for every other event. This method is called periodically for the destination window when the user is dragging an "image" (as they call it on the docs) around. The destination window that implements the draggingUpdated must return the NSDragOperation value depending if it wants to accept the future drop or not, so when I realized that by creating a laf event and sending it to the queue it would be treated asynchronously, thus loosing the chance of returning the appropriate NSDragOperation at the requested time, I've decided to change the approach. Also I believe the same issue exists when implementing IDropTarget::DragOver method for Windows. Maybe there is a workaround for this that I'm not aware of, or I am missing something. |
It looks like a similar case to We could offer some others I was also thinking that the drag and drop events will require several new fields that regular Some comments:
|
Yeah, I saw those and I imagined that there were there because of a similar reason, in fact I've considered using functions instead of the delegates, but I think I saw the comment you mention so I decided to go for delegates at the end.
Ok, I'll go ahead with the proposed delegates then.
Alright, will create a new os::DndEvent class that doesn't inherit from os::Event.
Sure, that is the idea. Making a copy of multiple_windows just was the quicker thing to do for me at the time.
Sure. We could also create a dnd namespace I guess, and use Source and Target as class names. But it is up to you, I don't have any preference. Just let me know if you want to go ahead with the names you proposed.
Sounds good.
Perfect.
👍 |
66f9381
to
8408f84
Compare
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.
clang-tidy made some suggestions
examples/drag_and_drop.cpp
Outdated
case os::Event::KeyDown: | ||
switch (ev.scancode()) { | ||
|
||
case os::kKeyT: |
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.
warning: switch has 2 consecutive identical branches [bugprone-branch-clone]
case os::kKeyT:
^
Additional context
examples/drag_and_drop.cpp:151: last of these clones ends here
break;
^
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.
clang-tidy made some suggestions
examples/drag_and_drop.cpp
Outdated
case os::Event::KeyDown: | ||
switch (ev.scancode()) { | ||
|
||
case os::kKeyT: |
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.
warning: switch has 2 consecutive identical branches [bugprone-branch-clone]
case os::kKeyT:
^
Additional context
examples/drag_and_drop.cpp:203: last of these clones ends here
break;
^
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.
clang-tidy made some suggestions
examples/drag_and_drop.cpp
Outdated
case os::Event::KeyDown: | ||
switch (ev.scancode()) { | ||
|
||
case os::kKeyT: |
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.
warning: switch has 2 consecutive identical branches [bugprone-branch-clone]
case os::kKeyT:
^
Additional context
examples/drag_and_drop.cpp:221: last of these clones ends here
break;
^
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.
clang-tidy made some suggestions
examples/drag_and_drop.cpp
Outdated
case os::Event::KeyDown: | ||
switch (ev.scancode()) { | ||
|
||
case os::kKeyT: |
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.
warning: switch has 2 consecutive identical branches [bugprone-branch-clone]
case os::kKeyT:
^
Additional context
examples/drag_and_drop.cpp:232: last of these clones ends here
break;
^
@dacap This is still in draft but I want you to take a look at the current status. You can run the drag_and_drop example (which is not finished yet) to see some of things in action.
Things missing:
However, I think that with the current status (and once we got this implemented in Windows and Linux) we have the basic blocks in place to start with aseprite/aseprite#131 in Aseprite. Then we can implement the rest in laf in the future. What do you think? |
Hehe...yeah, it can't be dragged...the DragSource is not implemented. So just try to drop files from finder...or any other DnD source app that provides NSFilenamesPboardType items. |
Probably we should create an example showing only the functionality we're implementing/need for the feature. Drop paths and images, nothing else. |
Yes, I agree. Once we are okay with the approach taken I will remove the things that are not functional from the example. Images are not supported at the moment. There are some commented code just to show how they could be approached, but nothing else. |
My idea was to implement the minimum necessary for supporting drag & dropping of files with realtime update of the UI while dragging them. |
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 far it looks good, some minor changes to the API and still some decisions to take (e.g. should we use unique pointers for targets/sources or leave the owning decision to the client side).
The example could be simplified just showing a box where we can drop things (files/images) and accept or not the DragEvent if we drop things inside that box (to avoid switching flags so many flags).
About data types, we need only filenames/paths and images. Generally the "drag and drop" functions are related to the clipboard functions, so it might be possible that some functions from the clip library can be used (which might require changes in the clip library). |
One last time at the moment is if we can merge dropResult/acceptDrop in some way, or explain when each field must be set/used on each event (and if we need a DropEvent class to separate fields for a drop-only event). |
We can remove the acceptDrop field and let DragTarget::drop return a boolean that indicates if the drop was accepted or not. Something similar could be done for DragTarget::dragEnter and DragTarget::draggingUpdated by making them return a DropOperation and then removing the dropResult field from DragEvent. |
… the alpha component
…om a source image that doesn't support alpha
…mages and offer the possibility of configuring the decoding functions to be used This is achieved by looking at the clipboard for a file that contains data in some of the supported image formats, because in Windows, the Chrome implementation puts the image's file content in the clipboard. Then after determining that the file contents corresponds to one of our supported image formats, the configured decoding function is used (which might be the default one)
…tails from the public interface
This is how most examples are working right now, draw and invalidate the updated area in the same function just to avoid calling invalidate() each time.
We need drag & drop working with scale parameter (as Aseprite uses scale=2 by default), so I've made some changes to test: 1) draw_window() must use the surface bounds which are scaled (not the windows bounds, which aren't) 2) The drop zone must use the same scaled bounds 3) Moved all logic to create the window inside create_window()
…f flags instead of any of the specified flags
Good job @martincapello! merged just right now 🍾 |
😅 tough one |
This PR contains the drag and drop implementation in each platform for laf.
Also exposes the API that can be used by laf clients to use drag and drop in a platform-independent way.