mirror of
https://github.com/SFML/SFML.git
synced 2024-11-25 04:41:05 +08:00
Add file dropping support
This commit is contained in:
parent
74dfd76b25
commit
89a23ea996
@ -35,6 +35,7 @@
|
||||
#include <SFML/System/Vector2.hpp>
|
||||
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace sf
|
||||
@ -294,6 +295,16 @@ public:
|
||||
Vector3f value; //!< Current value of the sensor on the X, Y, and Z axes
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Files dropped event subtype
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
struct FilesDropped
|
||||
{
|
||||
std::vector<sf::String> filenames; //!< The files which were dropped
|
||||
Vector2i position; //!< The position of the cursor at the time the files were dropped
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Construct from a given `sf::Event` subtype
|
||||
///
|
||||
@ -364,7 +375,8 @@ private:
|
||||
TouchBegan,
|
||||
TouchMoved,
|
||||
TouchEnded,
|
||||
SensorChanged>
|
||||
SensorChanged,
|
||||
FilesDropped>
|
||||
m_data; //!< Event data
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
@ -546,6 +546,18 @@ public:
|
||||
VkSurfaceKHR& surface,
|
||||
const VkAllocationCallbacks* allocator = nullptr);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Enable or disable file dropping.
|
||||
///
|
||||
/// If this is disabled, then when a user drags a file on to the window
|
||||
/// the file will be automatically denied. When this is enabled, the file
|
||||
/// will be accepted, no matter the type
|
||||
///
|
||||
/// \param enabled True to enable, false to disable
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void setFileDroppingEnabled(bool enabled = true);
|
||||
|
||||
protected:
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Function called after the window has been created
|
||||
|
@ -1608,6 +1608,9 @@ void WindowImplX11::initialize()
|
||||
// Flush the commands queue
|
||||
XFlush(m_display.get());
|
||||
|
||||
// Make sure that file dropping is disabled
|
||||
setFileDroppingEnabled(false);
|
||||
|
||||
// Add this window to the global list of windows (required for focus request)
|
||||
const std::lock_guard lock(allWindowsMutex);
|
||||
allWindows.push_back(this);
|
||||
@ -1799,6 +1802,146 @@ bool WindowImplX11::processEvent(XEvent& windowEvent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Specifications for Xdnd: https://wiki.freedesktop.org/www/Specifications/XDND/
|
||||
|
||||
// Drag and drop position update
|
||||
if (windowEvent.xclient.message_type == getAtom("XdndPosition"))
|
||||
{
|
||||
const Atom xdndStatus = XInternAtom(m_display.get(), "XdndStatus", false);
|
||||
|
||||
XEvent message;
|
||||
message.xclient.type = ClientMessage;
|
||||
message.xclient.display = windowEvent.xclient.display;
|
||||
message.xclient.window = m_dropSource;
|
||||
message.xclient.message_type = xdndStatus;
|
||||
message.xclient.format = 32;
|
||||
|
||||
message.xclient.data.l[0] = static_cast<long>(m_window); // The current window
|
||||
|
||||
// Specify if we want the drop or not, and if we want XdndPosition events whenever the mouse moves out of the rectangle
|
||||
message.xclient.data.l[1] = (m_acceptedFileType != None);
|
||||
|
||||
// Send back window rectangle coordinates and width
|
||||
message.xclient.data.l[2] = 0;
|
||||
message.xclient.data.l[3] = 0;
|
||||
|
||||
// Specify action we accept
|
||||
message.xclient.data.l[4] = static_cast<long>(getAtom("XdndActionCopy"));
|
||||
|
||||
XSendEvent(m_display.get(), m_dropSource, false, 0, &message);
|
||||
}
|
||||
|
||||
if (windowEvent.xclient.message_type == getAtom("XdndEnter"))
|
||||
{
|
||||
// Store the source window
|
||||
m_dropSource = static_cast<::Window>(windowEvent.xclient.data.l[0]);
|
||||
|
||||
m_acceptedFileType = None;
|
||||
|
||||
if (windowEvent.xclient.data.l[1] & 0x1)
|
||||
{
|
||||
// There are more than 3 types supported by the source, so we must get the XdndTypeList
|
||||
Atom actualType = None;
|
||||
int actualFormat = 0;
|
||||
unsigned long numOfItems = 0;
|
||||
unsigned long bytesAfterReturn = 0;
|
||||
unsigned char* data = nullptr;
|
||||
// Get the list of types that the source supports
|
||||
if (XGetWindowProperty(m_display.get(),
|
||||
m_dropSource,
|
||||
getAtom("XdndTypeList"),
|
||||
0,
|
||||
1024,
|
||||
false,
|
||||
AnyPropertyType,
|
||||
&actualType,
|
||||
&actualFormat,
|
||||
&numOfItems,
|
||||
&bytesAfterReturn,
|
||||
&data) == Success)
|
||||
{
|
||||
if (actualType != None)
|
||||
{
|
||||
Atom* supportedAtoms = reinterpret_cast<Atom*>(data);
|
||||
|
||||
// Go through all of them and check if we support any of them
|
||||
for (int i = 0; i < static_cast<int>(numOfItems); i++)
|
||||
{
|
||||
if (canAcceptFileType(supportedAtoms[i]))
|
||||
{
|
||||
m_acceptedFileType = supportedAtoms[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Go through the 3 types that the source supports and check if we support any of them
|
||||
for (int i = 2; i < 5; i++)
|
||||
{
|
||||
if (canAcceptFileType(static_cast<Atom>(windowEvent.xclient.data.l[i])))
|
||||
{
|
||||
m_acceptedFileType = static_cast<Atom>(windowEvent.xclient.data.l[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// An item has been dropped
|
||||
if (windowEvent.xclient.message_type == getAtom("XdndDrop"))
|
||||
{
|
||||
// Make sure that an acceptable file type was found
|
||||
if (m_acceptedFileType != None)
|
||||
{
|
||||
// Get the timestamp
|
||||
const auto dropTimestamp = static_cast<::Time>(windowEvent.xclient.data.l[2]);
|
||||
|
||||
// Get the selection using the given timestamp
|
||||
XConvertSelection(m_display.get(),
|
||||
getAtom("XdndSelection"),
|
||||
m_acceptedFileType,
|
||||
getAtom("XDND_DATA"),
|
||||
m_window,
|
||||
dropTimestamp);
|
||||
}
|
||||
|
||||
XEvent message;
|
||||
|
||||
message.xclient.type = ClientMessage;
|
||||
message.xclient.display = m_display.get();
|
||||
message.xclient.window = m_dropSource;
|
||||
message.xclient.message_type = getAtom("XdndFinished");
|
||||
message.xclient.format = 32;
|
||||
message.xclient.data.l[0] = static_cast<long>(m_window);
|
||||
if (m_acceptedFileType != None)
|
||||
{
|
||||
// Tell the application we copied the data
|
||||
message.xclient.data.l[1] = 1;
|
||||
message.xclient.data.l[2] = static_cast<long>(getAtom("XdndActionCopy"));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Tell the application we did nothing
|
||||
message.xclient.data.l[1] = 0;
|
||||
message.xclient.data.l[2] = None;
|
||||
}
|
||||
|
||||
XSendEvent(m_display.get(), m_dropSource, false, NoEventMask, &message);
|
||||
|
||||
m_acceptedFileType = None;
|
||||
m_dropSource = 0;
|
||||
}
|
||||
|
||||
// The cursor left the window, so make sure we clean up
|
||||
if (windowEvent.xclient.message_type == getAtom("XdndLeave"))
|
||||
{
|
||||
m_acceptedFileType = None;
|
||||
m_dropSource = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@ -2073,6 +2216,92 @@ bool WindowImplX11::processEvent(XEvent& windowEvent)
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// XConvertSelection response
|
||||
case SelectionNotify:
|
||||
{
|
||||
if (windowEvent.xclient.message_type == getAtom("XdndSelection"))
|
||||
{
|
||||
// Notification that the current selection owner
|
||||
// has responded to our request
|
||||
|
||||
Atom type = 0;
|
||||
int format = 0;
|
||||
unsigned long items = 0;
|
||||
unsigned long remainingBytes = 0;
|
||||
unsigned char* data = nullptr;
|
||||
|
||||
// The selection owner should have written the selection
|
||||
// data to the specified window property
|
||||
const int result = XGetWindowProperty(m_display.get(),
|
||||
m_window,
|
||||
windowEvent.xselection.property,
|
||||
0,
|
||||
0x7fffffff,
|
||||
False,
|
||||
AnyPropertyType,
|
||||
&type,
|
||||
&format,
|
||||
&items,
|
||||
&remainingBytes,
|
||||
&data);
|
||||
|
||||
String filenames;
|
||||
|
||||
if (result == Success)
|
||||
{
|
||||
// We don't support INCR for now
|
||||
// It is very unlikely that this will be returned
|
||||
// for purely text data transfer anyway
|
||||
if (type != getAtom("INCR", false))
|
||||
{
|
||||
filenames = reinterpret_cast<char*>(data);
|
||||
}
|
||||
|
||||
XFree(data);
|
||||
|
||||
// The selection requestor must always delete the property themselves
|
||||
XDeleteProperty(m_display.get(), m_window, windowEvent.xselection.property);
|
||||
}
|
||||
|
||||
// Split sf::String into std::vector<sf::String> by the new lines
|
||||
|
||||
std::vector<String> filenamesVector;
|
||||
size_t lastPosition = 0;
|
||||
|
||||
while (filenames.find("\n", lastPosition) != std::string::npos)
|
||||
{
|
||||
filenamesVector.push_back(
|
||||
filenames.substring(lastPosition, filenames.find("\n", lastPosition) - lastPosition + 1));
|
||||
|
||||
lastPosition = filenames.find("\n", lastPosition) + 1;
|
||||
}
|
||||
|
||||
if (lastPosition < filenames.getSize())
|
||||
{
|
||||
filenamesVector.push_back(filenames.substring(lastPosition, filenames.getSize() - lastPosition));
|
||||
}
|
||||
|
||||
for (String& filename : filenamesVector)
|
||||
{
|
||||
// To signify that it is giving a file, a program may put file:// at the start, so remove it
|
||||
if (filename.find("file://") == 0)
|
||||
{
|
||||
filename = filename.substring(7, filename.getSize() - 7);
|
||||
}
|
||||
|
||||
// The last character can be a newline for file lists, so remove it if it is there
|
||||
while (filename[filename.getSize() - 1] == '\n' || filename[filename.getSize() - 1] == '\r')
|
||||
{
|
||||
filename = filename.substring(0, filename.getSize() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
pushEvent(Event::FilesDropped{filenamesVector, Mouse::getPosition()});
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -2171,4 +2400,58 @@ void WindowImplX11::setWindowSizeConstraints() const
|
||||
XSetWMNormalHints(m_display.get(), m_window, &sizeHints);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void WindowImplX11::setFileDroppingEnabled(bool enabled)
|
||||
{
|
||||
// Xdnd does not work on Wayland, so we check if Wayland is currently active before we enable Xdnd
|
||||
// Checking if this exists isn't a perfect solution, as a user could set this
|
||||
// in their environment variables, but it's better than crashing
|
||||
|
||||
const char* value = getenv("WAYLAND_DISPLAY");
|
||||
|
||||
// If this variable exists, then that (usually) means that wayland is being used instead of X11, so don't turn on file dropping
|
||||
if (value != nullptr)
|
||||
{
|
||||
// If we are enabling it give it an error, but don't give an error if we are disabling it
|
||||
if (enabled)
|
||||
{
|
||||
sf::err() << "Drag and drop is not supported on Xwayland!" << std::endl;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// In order for item dropping to be enabled, the XdndAware property must be set.
|
||||
if (enabled)
|
||||
{
|
||||
Atom xdndVersion = 5;
|
||||
XChangeProperty(m_display.get(),
|
||||
m_window,
|
||||
getAtom("XdndAware"),
|
||||
XA_ATOM,
|
||||
32,
|
||||
PropModeReplace,
|
||||
reinterpret_cast<unsigned char*>(&xdndVersion),
|
||||
true);
|
||||
}
|
||||
else
|
||||
{
|
||||
XDeleteProperty(m_display.get(), m_window, getAtom("XdndAware"));
|
||||
}
|
||||
}
|
||||
|
||||
bool sf::priv::WindowImplX11::canAcceptFileType(const Atom& fileType)
|
||||
{
|
||||
// We currently only accept uri-lists, but this can be changed if you want to add more types to be supported
|
||||
|
||||
// Array of acceptable file types, this is static so we don't get the Atoms every time
|
||||
static const std::array<Atom, 1> acceptableFileTypes({
|
||||
getAtom("text/uri-list"),
|
||||
});
|
||||
|
||||
return std::any_of(acceptableFileTypes.begin(),
|
||||
acceptableFileTypes.end(),
|
||||
[fileType](const Atom& atom) { return atom == fileType; });
|
||||
}
|
||||
|
||||
} // namespace sf::priv
|
||||
|
@ -197,6 +197,14 @@ public:
|
||||
////////////////////////////////////////////////////////////
|
||||
void requestFocus() override;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Enable or disable file dropping.
|
||||
///
|
||||
/// \param enabled True to enable, false to disable
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void setFileDroppingEnabled(bool enabled = true) override;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Check whether the window has the input focus
|
||||
///
|
||||
@ -212,6 +220,16 @@ protected:
|
||||
////////////////////////////////////////////////////////////
|
||||
void processEvents() override;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Check if the given file type can be accepted
|
||||
///
|
||||
/// \param fileType The file type to check
|
||||
///
|
||||
/// \return If the file type is acceptable
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
bool canAcceptFileType(const Atom& fileType);
|
||||
|
||||
private:
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Request the WM to make the current window active
|
||||
@ -336,6 +354,8 @@ private:
|
||||
Pixmap m_iconPixmap{}; ///< The current icon pixmap if in use
|
||||
Pixmap m_iconMaskPixmap{}; ///< The current icon mask pixmap if in use
|
||||
::Time m_lastInputTime{}; ///< Last time we received user input
|
||||
::Window m_dropSource{0}; ///< The window which is giving the dropped item
|
||||
Atom m_acceptedFileType{0}; ///< The MIME type that the other window supports that we also support for file dropping
|
||||
};
|
||||
|
||||
} // namespace sf::priv
|
||||
|
@ -38,6 +38,7 @@
|
||||
// or mingw-w64 addresses files in a case insensitive manner.
|
||||
#include <dbt.h>
|
||||
#include <ostream>
|
||||
#include <shellapi.h>
|
||||
#include <vector>
|
||||
|
||||
#include <cstddef>
|
||||
@ -304,6 +305,11 @@ WindowHandle WindowImplWin32::getNativeHandle() const
|
||||
}
|
||||
|
||||
|
||||
void WindowImplWin32::setFileDroppingEnabled(bool enabled)
|
||||
{
|
||||
DragAcceptFiles(m_handle, enabled);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void WindowImplWin32::processEvents()
|
||||
{
|
||||
@ -1165,6 +1171,38 @@ void WindowImplWin32::processEvent(UINT message, WPARAM wParam, LPARAM lParam)
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Files dropped event
|
||||
case WM_DROPFILES:
|
||||
{
|
||||
auto* hDrop = reinterpret_cast<HDROP>(wParam);
|
||||
|
||||
const unsigned int count = DragQueryFileW(hDrop, 0xFFFFFFFF, nullptr, 0);
|
||||
|
||||
if (count == 0)
|
||||
break;
|
||||
|
||||
std::vector<String> files;
|
||||
|
||||
// Get the filenames as wchar_t then add it to the files vector
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
std::vector<wchar_t> buffer(DragQueryFileW(hDrop, i, nullptr, 0) + 1);
|
||||
|
||||
DragQueryFileW(hDrop, i, buffer.data(), static_cast<UINT>(buffer.size()));
|
||||
|
||||
files.emplace_back(buffer.data());
|
||||
}
|
||||
|
||||
// Let the Windows API know we are done
|
||||
DragFinish(hDrop);
|
||||
|
||||
const Vector2i mousePosition = Mouse::getPosition();
|
||||
|
||||
pushEvent(Event::FilesDropped{files, mousePosition});
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -189,6 +189,14 @@ public:
|
||||
////////////////////////////////////////////////////////////
|
||||
[[nodiscard]] bool hasFocus() const override;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Enable or disable file dropping.
|
||||
///
|
||||
/// \param enabled True to enable, false to disable
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void setFileDroppingEnabled(bool enabled = true) override;
|
||||
|
||||
protected:
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Process incoming events from the operating system
|
||||
|
@ -343,6 +343,12 @@ bool WindowBase::createVulkanSurface(const VkInstance& instance, VkSurfaceKHR& s
|
||||
}
|
||||
|
||||
|
||||
void WindowBase::setFileDroppingEnabled(bool enabled)
|
||||
{
|
||||
if (m_impl)
|
||||
m_impl->setFileDroppingEnabled(enabled);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void WindowBase::onCreate()
|
||||
{
|
||||
|
@ -398,4 +398,10 @@ bool WindowImpl::createVulkanSurface([[maybe_unused]] const VkInstance&
|
||||
#endif
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void WindowImpl::setFileDroppingEnabled(bool /* enabled */)
|
||||
{
|
||||
// Backup for platforms that don't support drag & drop
|
||||
}
|
||||
|
||||
} // namespace sf::priv
|
||||
|
@ -305,6 +305,18 @@ public:
|
||||
////////////////////////////////////////////////////////////
|
||||
bool createVulkanSurface(const VkInstance& instance, VkSurfaceKHR& surface, const VkAllocationCallbacks* allocator) const;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Enable or disable file dropping.
|
||||
///
|
||||
/// If this is disabled, then when a user drags a file on to the window
|
||||
/// the file will be automatically denied. When this is enabled, the file
|
||||
/// will be accepted, no matter the type
|
||||
///
|
||||
/// \param enabled True to enable, false to disable
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setFileDroppingEnabled(bool enabled = true);
|
||||
|
||||
protected:
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Default constructor
|
||||
|
@ -140,6 +140,12 @@ class WindowImplCocoa;
|
||||
////////////////////////////////////////////////////////////
|
||||
- (CGFloat)displayScaleFactor;
|
||||
|
||||
// Event called by MacOS when a file is dragged on top of of the window
|
||||
- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender;
|
||||
|
||||
// Function called by MacOS when a file is dropped on top of the window
|
||||
- (BOOL)performDragOperation:(id<NSDraggingInfo>)sender;
|
||||
|
||||
@end
|
||||
|
||||
@interface SFOpenGLView (keyboard)
|
||||
|
@ -186,6 +186,9 @@
|
||||
// Now that we have a window, set up correctly the scale factor and cursor grabbing
|
||||
[self updateScaleFactor];
|
||||
[self updateCursorGrabbed]; // update for fullscreen
|
||||
|
||||
// Register the drag types that this view can accept
|
||||
//[self registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType, nil]];
|
||||
}
|
||||
|
||||
|
||||
@ -341,6 +344,62 @@
|
||||
m_mouseIsIn = NO;
|
||||
}
|
||||
|
||||
- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender
|
||||
{
|
||||
// Check if what is being dragged is a file
|
||||
if ([sender.draggingPasteboard.types containsObject:NSFilenamesPboardType])
|
||||
{
|
||||
// Make sure that we can get the filename (not just the contents)
|
||||
if (sender.draggingSourceOperationMask & NSDragOperationLink)
|
||||
{
|
||||
// Return that we can accept a filename
|
||||
return NSDragOperationLink;
|
||||
}
|
||||
}
|
||||
|
||||
// Return that we can't accept this file
|
||||
return NSDragOperationNone;
|
||||
}
|
||||
|
||||
- (BOOL)performDragOperation:(id<NSDraggingInfo>)sender
|
||||
{
|
||||
// Make sure that the dragged item is a file
|
||||
if ([sender.draggingPasteboard.types containsObject:NSFilenamesPboardType])
|
||||
{
|
||||
// Get the filenames from the sender
|
||||
NSArray* files = [sender.draggingPasteboard propertyListForType:NSFilenamesPboardType];
|
||||
|
||||
// Convert to std::vector<std::string>
|
||||
|
||||
std::vector<sf::String> filenames;
|
||||
|
||||
for (NSUInteger i = 0; i < [files count]; i++)
|
||||
{
|
||||
NSObject* item = files[i];
|
||||
|
||||
// Make sure that we can cast the NSObject*
|
||||
if ([item isKindOfClass:[NSMutableString class]])
|
||||
{
|
||||
auto* filename = reinterpret_cast<NSMutableString*>(item);
|
||||
|
||||
filenames.emplace_back([filename UTF8String]);
|
||||
}
|
||||
}
|
||||
|
||||
NSPoint mousePosition = [self cursorPositionFromEvent:nil];
|
||||
|
||||
if (m_requester != nullptr)
|
||||
m_requester->handleFileDroppingEvent(filenames, sf::Vector2i{int(mousePosition.x), int(mousePosition.y)});
|
||||
}
|
||||
else
|
||||
{
|
||||
// If somehow we get a drag operation for an item we cant accept, return no
|
||||
return NO;
|
||||
}
|
||||
|
||||
// Everything went well, return yes
|
||||
return YES;
|
||||
}
|
||||
|
||||
#pragma mark
|
||||
#pragma mark Subclassing methods
|
||||
|
@ -284,5 +284,17 @@
|
||||
[context setView:m_oglView];
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
- (void)setFileDroppingEnabled:(bool)enabled
|
||||
{
|
||||
if (enabled)
|
||||
{
|
||||
[m_oglView registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType, nil]];
|
||||
}
|
||||
else
|
||||
{
|
||||
[m_oglView unregisterDraggedTypes];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
@ -628,4 +628,17 @@
|
||||
return static_cast<float>(NSHeight([m_window frame]) - NSHeight([[m_window contentView] frame]));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
- (void)setFileDroppingEnabled:(bool)enabled
|
||||
{
|
||||
if (enabled)
|
||||
{
|
||||
[m_oglView registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType, nil]];
|
||||
}
|
||||
else
|
||||
{
|
||||
[m_oglView unregisterDraggedTypes];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
@ -228,6 +228,16 @@ public:
|
||||
////////////////////////////////////////////////////////////
|
||||
void applyContext(NSOpenGLContextRef context) const;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Handle the file dropping event
|
||||
///
|
||||
/// Called by SFOpenGLView to handle the file dropping event
|
||||
///
|
||||
/// \param files The files that were dropped
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void handleFileDroppingEvent(std::vector<sf::String> files, sf::Vector2i position);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Change the type of the current process
|
||||
///
|
||||
@ -369,6 +379,18 @@ public:
|
||||
////////////////////////////////////////////////////////////
|
||||
[[nodiscard]] bool hasFocus() const override;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Enable or disable file dropping.
|
||||
///
|
||||
/// If this is disabled, then when a user drags a file on to the window
|
||||
/// the file will be automatically denied. When this is enabled, the file
|
||||
/// will be accepted, no matter the type
|
||||
///
|
||||
/// \param enabled True to enable, false to disable
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void setFileDroppingEnabled(bool enabled = true) override;
|
||||
|
||||
protected:
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Process incoming events from the operating system
|
||||
|
@ -246,6 +246,11 @@ void WindowImplCocoa::windowFocusGained()
|
||||
pushEvent(Event::FocusGained{});
|
||||
}
|
||||
|
||||
void WindowImplCocoa::handleFileDroppingEvent(std::vector<sf::String> files, sf::Vector2i position)
|
||||
{
|
||||
pushEvent(Event::FilesDropped{std::move(files), position});
|
||||
}
|
||||
|
||||
#pragma mark
|
||||
#pragma mark WindowImplCocoa's mouse-event methods
|
||||
|
||||
@ -492,5 +497,10 @@ bool WindowImplCocoa::hasFocus() const
|
||||
return [m_delegate hasFocus];
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void WindowImplCocoa::setFileDroppingEnabled(bool enabled)
|
||||
{
|
||||
[m_delegate setFileDroppingEnabled:enabled];
|
||||
}
|
||||
|
||||
} // namespace sf::priv
|
||||
|
@ -251,6 +251,14 @@ class WindowImplCocoa;
|
||||
////////////////////////////////////////////////////////////
|
||||
- (void)applyContext:(NSOpenGLContext*)context;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Enable or disable file dropping
|
||||
///
|
||||
/// \param enable True to enable, false to disable
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
- (void)setFileDroppingEnabled:(bool)enabled;
|
||||
|
||||
@end
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
|
Loading…
Reference in New Issue
Block a user