Repository navigation
implemented Event::FilesDropped for Windows #1222
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
|
|
||
| set(SRCROOT ${PROJECT_SOURCE_DIR}/examples/file_dropping) | ||
|
|
||
| # all source files | ||
| set(SRC ${SRCROOT}/FileDropping.cpp) | ||
|
|
||
| # define the file_dropping target | ||
| sfml_add_example(file_dropping GUI_APP | ||
| SOURCES ${SRC} | ||
| DEPENDS sfml-graphics sfml-window sfml-system) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,92 @@ | ||
| //////////////////////////////////////////////////////////// | ||
| // Headers | ||
| //////////////////////////////////////////////////////////// | ||
| #include <SFML/Graphics.hpp> | ||
| #include <SFML/Window.hpp> | ||
| #include <iostream> | ||
| #include <algorithm> | ||
|
|
||
| //////////////////////////////////////////////////////////// | ||
| /// Entry point of application | ||
| /// | ||
| /// \return Application exit code | ||
| /// | ||
| //////////////////////////////////////////////////////////// | ||
| int main() | ||
| { | ||
| // Create the main window | ||
| sf::RenderWindow window(sf::VideoMode(640, 480), "Drop image files here!"); | ||
|
|
||
| // If the platform doesn't support file dropping, abort | ||
| if (!window.setFileDroppingEnabled(true)) | ||
| { | ||
| std::cerr << "Platform not supported!\n"; | ||
| return EXIT_FAILURE; | ||
| } | ||
|
|
||
| // The texture for displaying dropped images | ||
| sf::Texture texture; | ||
| texture.setSmooth(true); | ||
|
|
||
| // The sprite to draw the texture with | ||
| sf::Sprite sprite; | ||
| sprite.setTexture(texture); | ||
|
|
||
| // Start the game loop | ||
| while (window.isOpen()) | ||
| { | ||
| // If this flag is set, we have to realign the view and the sprite | ||
| bool realign = false; | ||
|
|
||
| // Process events | ||
| sf::Event event; | ||
| while (window.pollEvent(event)) | ||
| { | ||
| // Close event: close the window | ||
| if (event.type == sf::Event::Closed) | ||
| window.close(); | ||
|
|
||
| // Resize event: request realignment | ||
| if (event.type == sf::Event::Resized) | ||
| realign = true; | ||
|
|
||
| // Files dropped event: try to load as image, set the title, and request realignment | ||
| if (event.type == sf::Event::FilesDropped) | ||
| { | ||
| for (unsigned int i = 0; i < event.droppedFiles.count; ++i) | ||
| { | ||
| if (texture.loadFromFile(event.droppedFiles.files[i])) | ||
| { | ||
| window.setTitle(event.droppedFiles.files[i]); | ||
| realign = true; | ||
| break; | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // Align the sprite tidily into the center of the window and reset the view | ||
| if (realign) | ||
| { | ||
| window.setView(sf::View(sf::FloatRect(0.f, 0.f, static_cast<float>(window.getSize().x), static_cast<float>(window.getSize().y)))); | ||
| sprite.setTextureRect(sf::IntRect(0, 0, texture.getSize().x, texture.getSize().y)); | ||
| sprite.setOrigin(texture.getSize().x / 2.f, texture.getSize().y / 2.f); | ||
| sprite.setPosition(window.getSize().x / 2.f, window.getSize().y / 2.f); | ||
| float scalingFactor = 1.f; | ||
| if (texture.getSize().x > window.getSize().x || texture.getSize().y > window.getSize().y) | ||
| { | ||
| scalingFactor = std::min( | ||
| static_cast<float>(window.getSize().x) / static_cast<float>(texture.getSize().x), | ||
| static_cast<float>(window.getSize().y) / static_cast<float>(texture.getSize().y)); | ||
| } | ||
| sprite.setScale(scalingFactor, scalingFactor); | ||
| } | ||
|
|
||
| // Display the image | ||
| window.clear(); | ||
| window.draw(sprite); | ||
| window.display(); | ||
| } | ||
|
|
||
| return EXIT_SUCCESS; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -221,7 +221,7 @@ m_cursorGrabbed (m_fullscreen) | |
|
|
||
| ++handleCount; | ||
| } | ||
|
|
||
| // By default, the OS limits the size of the window the the desktop size, | ||
| // we have to resize it after creation to apply the real size | ||
| setSize(Vector2u(mode.width, mode.height)); | ||
|
|
@@ -413,6 +413,13 @@ void WindowImplWin32::setKeyRepeatEnabled(bool enabled) | |
| } | ||
|
|
||
|
|
||
| //////////////////////////////////////////////////////////// | ||
| bool WindowImplWin32::setFileDroppingEnabled(bool enabled) | ||
| { | ||
| DragAcceptFiles(m_handle, enabled); | ||
| return true; | ||
| } | ||
|
|
||
| //////////////////////////////////////////////////////////// | ||
| void WindowImplWin32::requestFocus() | ||
| { | ||
|
|
@@ -972,6 +979,49 @@ void WindowImplWin32::processEvent(UINT message, WPARAM wParam, LPARAM lParam) | |
| JoystickImpl::updateConnections(); | ||
| break; | ||
| } | ||
|
|
||
| // File drop event | ||
| case WM_DROPFILES: | ||
| { | ||
| const HDROP hDrop = (HDROP)wParam; | ||
|
|
||
| // Generate a FilesDropped event | ||
| Event event; | ||
| event.type = Event::FilesDropped; | ||
|
|
||
| // Get the count | ||
| event.droppedFiles.count = DragQueryFileW(hDrop, 0xFFFFFFFF, NULL, 0); | ||
| if (event.droppedFiles.count == 0) | ||
| break; | ||
|
|
||
| // Expand the buffer list by one vector | ||
| FilesType& files = *m_droppedFiles.insert(m_droppedFiles.end(), FilesType()); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This doesn't make any sense either. First you append an element, then resize? Or did I miss something? And why the reference?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah,, right, should probably read it twice next time. So you're appending a new list for every drag&drop operation. Too bad we can't free them unless we assume that it's only valid till the next event is polled.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Exactly. I append a new vector to the list for every drop operation. I decided this way because I would rather waste some Kilobytes than get nasty SIGSEGVs. User friendliness is more important to me. |
||
|
|
||
| // Resize and fill said buffer vector | ||
| files.resize(event.droppedFiles.count); | ||
| for (unsigned int i = 0; i < event.droppedFiles.count; ++i) | ||
| { | ||
| std::vector<wchar_t> buf; | ||
| buf.resize(DragQueryFileW(hDrop, i, NULL, 0) + 1); | ||
| DragQueryFileW(hDrop, i, &buf.front(), buf.size()); | ||
| files[i] = &buf.front(); | ||
| } | ||
|
|
||
| // Let the event point to the buffer vector | ||
| event.droppedFiles.files = &files.front(); | ||
|
|
||
| // Fetch the cursor's window-relative position | ||
| POINT point; | ||
| DragQueryPoint(hDrop, &point); | ||
| event.droppedFiles.x = static_cast<int>(point.x); | ||
| event.droppedFiles.y = static_cast<int>(point.y); | ||
|
|
||
| // Tell the WinAPI to release the internal buffer | ||
| DragFinish(hDrop); | ||
|
|
||
| pushEvent(event); | ||
| break; | ||
| } | ||
| } | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -32,6 +32,8 @@ | |
| #include <SFML/Window/WindowImpl.hpp> | ||
| #include <SFML/System/String.hpp> | ||
| #include <windows.h> | ||
| #include <vector> | ||
| #include <list> | ||
|
|
||
|
|
||
| namespace sf | ||
|
|
@@ -161,6 +163,16 @@ class WindowImplWin32 : public WindowImpl | |
| //////////////////////////////////////////////////////////// | ||
| virtual void setKeyRepeatEnabled(bool enabled); | ||
|
|
||
| //////////////////////////////////////////////////////////// | ||
| /// \brief Enable or disable file dropping | ||
| /// | ||
| /// \param enabled True to enable, false to disable | ||
| /// | ||
| /// \return True if operation was successful, false otherwise | ||
| /// | ||
| //////////////////////////////////////////////////////////// | ||
| virtual bool setFileDroppingEnabled(bool enabled); | ||
|
|
||
| //////////////////////////////////////////////////////////// | ||
| /// \brief Request the current window to be made the active | ||
| /// foreground window | ||
|
|
@@ -261,20 +273,26 @@ class WindowImplWin32 : public WindowImpl | |
| //////////////////////////////////////////////////////////// | ||
| static LRESULT CALLBACK globalOnEvent(HWND handle, UINT message, WPARAM wParam, LPARAM lParam); | ||
|
|
||
| //////////////////////////////////////////////////////////// | ||
| // Type for storing a batch of dropped files | ||
| //////////////////////////////////////////////////////////// | ||
| typedef std::vector<String> FilesType; | ||
|
|
||
| //////////////////////////////////////////////////////////// | ||
| // Member data | ||
| //////////////////////////////////////////////////////////// | ||
| HWND m_handle; ///< Win32 handle of the window | ||
| LONG_PTR m_callback; ///< Stores the original event callback function of the control | ||
| HCURSOR m_cursor; ///< The system cursor to display into the window | ||
| HICON m_icon; ///< Custom icon assigned to the window | ||
| bool m_keyRepeatEnabled; ///< Automatic key-repeat state for keydown events | ||
| Vector2u m_lastSize; ///< The last handled size of the window | ||
| bool m_resizing; ///< Is the window being resized? | ||
| Uint16 m_surrogate; ///< First half of the surrogate pair, in case we're receiving a Unicode character in two events | ||
| bool m_mouseInside; ///< Mouse is inside the window? | ||
| bool m_fullscreen; ///< Is the window fullscreen? | ||
| bool m_cursorGrabbed; ///< Is the mouse cursor trapped? | ||
| HWND m_handle; ///< Win32 handle of the window | ||
| LONG_PTR m_callback; ///< Stores the original event callback function of the control | ||
| HCURSOR m_cursor; ///< The system cursor to display into the window | ||
| HICON m_icon; ///< Custom icon assigned to the window | ||
| bool m_keyRepeatEnabled; ///< Automatic key-repeat state for keydown events | ||
| Vector2u m_lastSize; ///< The last handled size of the window | ||
| bool m_resizing; ///< Is the window being resized? | ||
| Uint16 m_surrogate; ///< First half of the surrogate pair, in case we're receiving a Unicode character in two events | ||
| bool m_mouseInside; ///< Mouse is inside the window? | ||
| bool m_fullscreen; ///< Is the window fullscreen? | ||
| bool m_cursorGrabbed; ///< Is the mouse cursor trapped? | ||
| std::list<FilesType> m_droppedFiles; ///< Buffer for the dropped files | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this member even needed? The list of files is in the event after all.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, the event only stores a pointer to the buffer. See the first two bullet points in my issues list. |
||
| }; | ||
|
|
||
| } // namespace priv | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -108,6 +108,16 @@ void WindowImpl::setJoystickThreshold(float threshold) | |
| } | ||
|
|
||
|
|
||
| //////////////////////////////////////////////////////////// | ||
| bool WindowImpl::setFileDroppingEnabled(bool enabled) | ||
| { | ||
| // This is the fallback for unsupported platforms. | ||
| // Trying to enable file dropping returns a bad value | ||
| // indicating an error, whereas disabling it is fine. | ||
| return !enabled; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is confusing. Why would it return
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, disabling a non-existent function is always possible. Only enabling it would be troublesome because it - well - doesn't exist.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, okay, from that perspective it makes sense. But I'm not 100% sure how it should react considering it's not implemented/available. You're making it fail silently.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In my opinion, it doesn't fail silently. Disabling it is indistinguishable from it not being implemented, so why generate an error?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I can live with that when disabling. |
||
| } | ||
|
|
||
|
|
||
| //////////////////////////////////////////////////////////// | ||
| bool WindowImpl::popEvent(Event& event, bool block) | ||
| { | ||
|
|
||
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.
I'd rather see a
std::vector<string>here, which would also makecountobsolete.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.
See the point above:
Uh oh!
There was an error while loading. Please reload this page.
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.
All event data is stored in a
union, so usingstd::vector<string>is not possible. Since C++11, it would theoretically be allowed using placement new and manual destructor invocations. Alternatively, there's alsostd::variant/boost::variant(which is essentially a wrapper of the method described).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, right, the destructor getting broken data. Damn. :(