mirror of https://github.com/kivy/kivy.git
WindowBase: Add on_drop_begin, on_droptext and on_drop_end events (#7786)
* WindowBase: Added on_drop_begin, on_droptext and on_drop_end events. * WindowBase: Renamed on_dropfile event/method to on_drop_file. * WindowSDL: Dispatching mouse pos with dropbegin event. * WindowBase: Updated docs for on_drop_xxx events. * WindowBase: Removed code from on_drop_file method. * WindowBase: Updated docs for on_drop_begin and on_drop_end events. * WindowSDL: Updated _mouse_(x|y) attributes on dropbegin event. * SDL2: Change return type from Uint8 to Uint32 for mouse state functions to match their signature from SDL_mouse.h. * WindowSDL: Update mouse_pos value and dispatch of on_cursor_enter event. * WindowBase: Use same type for mouse_pos (tuple) and _density (float) properties. * WindowBase: Passing window relative mouse pos in on_drop_begin event and skip mousewheel if the cursor pos is not within the window size.
This commit is contained in:
parent
0f5f8bfc21
commit
5fb11bf400
|
@ -12,13 +12,13 @@ class DropFile(Button):
|
|||
app = App.get_running_app()
|
||||
|
||||
# add function to the list
|
||||
app.drops.append(self.on_dropfile)
|
||||
app.drops.append(self.on_drop_file)
|
||||
|
||||
def on_dropfile(self, widget, filename):
|
||||
def on_drop_file(self, widget, filename):
|
||||
# a function catching a dropped file
|
||||
# if it's dropped in the widget's area
|
||||
if self.collide_point(*Window.mouse_pos):
|
||||
# on_dropfile's filename is bytes (py3)
|
||||
# on_drop_file's filename is bytes (py3)
|
||||
self.text = filename.decode('utf-8')
|
||||
|
||||
|
||||
|
@ -28,8 +28,8 @@ class DropApp(App):
|
|||
# with functions from widgets themselves
|
||||
self.drops = []
|
||||
|
||||
# bind handling function to 'on_dropfile'
|
||||
Window.bind(on_dropfile=self.handledrops)
|
||||
# bind handling function to 'on_drop_file'
|
||||
Window.bind(on_drop_file=self.handledrops)
|
||||
|
||||
box = BoxLayout()
|
||||
dropleft = DropFile(text='left')
|
||||
|
@ -40,9 +40,9 @@ class DropApp(App):
|
|||
|
||||
def handledrops(self, *args):
|
||||
# this will execute each function from list with arguments from
|
||||
# Window.on_dropfile
|
||||
# Window.on_drop_file
|
||||
#
|
||||
# make sure `Window.on_dropfile` works on your system first,
|
||||
# make sure `Window.on_drop_file` works on your system first,
|
||||
# otherwise the example won't work at all
|
||||
for func in self.drops:
|
||||
func(*args)
|
||||
|
|
|
@ -310,7 +310,21 @@ class WindowBase(EventDispatcher):
|
|||
The *unicode* parameter has be deprecated in favor of
|
||||
codepoint, and will be removed completely in future versions.
|
||||
|
||||
`on_dropfile`: filename (bytes or string):
|
||||
`on_drop_begin`: x, y
|
||||
Fired when text(s) or file(s) drop on the application is about to
|
||||
begin.
|
||||
|
||||
Values `x` and `y` are drop position and are relative to window
|
||||
position :attr:`left` and :attr:`top`.
|
||||
|
||||
.. note::
|
||||
On Windows it is possible to drop file(s) on window title bar
|
||||
or on it's edges and in that case :attr:`mouse_pos` won't be
|
||||
updated as the mouse cursor is not within the window size.
|
||||
|
||||
.. versionadded:: 2.1.0
|
||||
|
||||
`on_drop_file`: filename (bytes or string):
|
||||
Fired when a file is dropped on the application.
|
||||
|
||||
.. note::
|
||||
|
@ -319,6 +333,21 @@ class WindowBase(EventDispatcher):
|
|||
`#4999 <https://github.com/kivy/kivy/issues/4999>`_ for
|
||||
pointers to workarounds.
|
||||
|
||||
.. versionadded:: 1.2.0
|
||||
|
||||
.. versionchanged:: 2.1.0
|
||||
Renamed from `on_dropfile` to `on_drop_file`.
|
||||
|
||||
`on_drop_text`: text (bytes or string)
|
||||
Fired when a text is dropped on the application.
|
||||
|
||||
.. versionadded:: 2.1.0
|
||||
|
||||
`on_drop_end`:
|
||||
Fired when text(s) or file(s) drop on the application has ended.
|
||||
|
||||
.. versionadded:: 2.1.0
|
||||
|
||||
`on_memorywarning`:
|
||||
Fired when the platform have memory issue (iOS / Android mostly)
|
||||
You can listen to this one, and clean whatever you can.
|
||||
|
@ -338,7 +367,7 @@ class WindowBase(EventDispatcher):
|
|||
_fake_fullscreen = False
|
||||
|
||||
# private properties
|
||||
_density = NumericProperty(1)
|
||||
_density = NumericProperty(1.)
|
||||
_size = ListProperty([0, 0])
|
||||
_modifiers = ListProperty([])
|
||||
_rotation = NumericProperty(0)
|
||||
|
@ -754,7 +783,7 @@ class WindowBase(EventDispatcher):
|
|||
property instead.
|
||||
'''
|
||||
|
||||
mouse_pos = ObjectProperty([0, 0])
|
||||
mouse_pos = ObjectProperty((0, 0))
|
||||
'''2d position of the mouse within the window.
|
||||
|
||||
.. versionadded:: 1.2.0
|
||||
|
@ -936,7 +965,8 @@ class WindowBase(EventDispatcher):
|
|||
'on_hide', 'on_show', 'on_motion', 'on_touch_down',
|
||||
'on_touch_move', 'on_touch_up', 'on_mouse_down',
|
||||
'on_mouse_move', 'on_mouse_up', 'on_keyboard', 'on_key_down',
|
||||
'on_key_up', 'on_textinput', 'on_dropfile', 'on_request_close',
|
||||
'on_key_up', 'on_textinput', 'on_drop_begin', 'on_drop_file',
|
||||
'on_dropfile', 'on_drop_text', 'on_drop_end', 'on_request_close',
|
||||
'on_cursor_enter', 'on_cursor_leave', 'on_joy_axis',
|
||||
'on_joy_hat', 'on_joy_ball', 'on_joy_button_down',
|
||||
'on_joy_button_up', 'on_memorywarning', 'on_textedit',
|
||||
|
@ -1018,6 +1048,10 @@ class WindowBase(EventDispatcher):
|
|||
if 'shape_image' not in kwargs:
|
||||
kwargs['shape_image'] = Config.get('kivy', 'window_shape')
|
||||
|
||||
self.fbind(
|
||||
'on_drop_file',
|
||||
lambda window, filename: window.dispatch('on_dropfile', filename)
|
||||
)
|
||||
super(WindowBase, self).__init__(**kwargs)
|
||||
|
||||
# bind all the properties that need to recreate the window
|
||||
|
@ -2006,17 +2040,58 @@ class WindowBase(EventDispatcher):
|
|||
'''
|
||||
pass
|
||||
|
||||
def on_dropfile(self, filename):
|
||||
def on_drop_begin(self, x, y):
|
||||
'''Event called when a text or a file drop on the application is about
|
||||
to begin. It will be followed-up by a single or a multiple
|
||||
`on_drop_text` or `on_drop_file` events ending with an `on_drop_end`
|
||||
event.
|
||||
|
||||
.. note::
|
||||
This event works with sdl2 window provider.
|
||||
|
||||
.. versionadded:: 2.1.0
|
||||
'''
|
||||
pass
|
||||
|
||||
def on_drop_file(self, filename):
|
||||
'''Event called when a file is dropped on the application.
|
||||
|
||||
.. warning::
|
||||
|
||||
This event currently works with sdl2 window provider, on pygame
|
||||
window provider and OS X with a patched version of pygame.
|
||||
This event is left in place for further evolution
|
||||
(ios, android etc.)
|
||||
|
||||
.. versionadded:: 1.2.0
|
||||
|
||||
.. versionchanged:: 2.1.0
|
||||
Renamed from `on_dropfile` to `on_drop_file`.
|
||||
'''
|
||||
pass
|
||||
|
||||
@deprecated(msg='Deprecated in 2.1.0, use on_drop_file event instead. '
|
||||
'Event on_dropfile will be removed in next two releases.')
|
||||
def on_dropfile(self, filename):
|
||||
pass
|
||||
|
||||
def on_drop_text(self, text):
|
||||
'''Event called when a text is dropped on the application.
|
||||
|
||||
.. note::
|
||||
This event works with sdl2 window provider on x11 window.
|
||||
|
||||
.. versionadded:: 2.1.0
|
||||
'''
|
||||
pass
|
||||
|
||||
def on_drop_end(self):
|
||||
'''Event called when a text or a file drop on the application has
|
||||
ended.
|
||||
|
||||
.. note::
|
||||
This event works with sdl2 window provider.
|
||||
|
||||
.. versionadded:: 2.1.0
|
||||
'''
|
||||
pass
|
||||
|
||||
|
|
|
@ -259,6 +259,9 @@ cdef class _WindowSDL2Storage:
|
|||
SDL_SetEventFilter(_event_filter, <void *>self)
|
||||
|
||||
SDL_EventState(SDL_DROPFILE, SDL_ENABLE)
|
||||
SDL_EventState(SDL_DROPTEXT, SDL_ENABLE)
|
||||
SDL_EventState(SDL_DROPBEGIN, SDL_ENABLE)
|
||||
SDL_EventState(SDL_DROPCOMPLETE, SDL_ENABLE)
|
||||
cdef int w, h
|
||||
SDL_GetWindowSize(self.win, &w, &h)
|
||||
return w, h
|
||||
|
@ -612,12 +615,9 @@ cdef class _WindowSDL2Storage:
|
|||
rv = SDL_PollEvent(&event)
|
||||
if rv == 0:
|
||||
return False
|
||||
|
||||
action = None
|
||||
if event.type == SDL_QUIT:
|
||||
return ('quit', )
|
||||
elif event.type == SDL_DROPFILE:
|
||||
return ('dropfile', event.drop.file)
|
||||
elif event.type == SDL_MOUSEMOTION:
|
||||
x = event.motion.x
|
||||
y = event.motion.y
|
||||
|
@ -733,6 +733,14 @@ cdef class _WindowSDL2Storage:
|
|||
elif event.type == SDL_TEXTEDITING:
|
||||
s = event.edit.text.decode('utf-8')
|
||||
return ('textedit', s)
|
||||
elif event.type == SDL_DROPFILE:
|
||||
return ('dropfile', event.drop.file)
|
||||
elif event.type == SDL_DROPTEXT:
|
||||
return ('droptext', event.drop.file)
|
||||
elif event.type == SDL_DROPBEGIN:
|
||||
return ('dropbegin',)
|
||||
elif event.type == SDL_DROPCOMPLETE:
|
||||
return ('dropend',)
|
||||
else:
|
||||
# print('receive unknown sdl window event', event.type)
|
||||
pass
|
||||
|
@ -756,6 +764,11 @@ cdef class _WindowSDL2Storage:
|
|||
def grab_mouse(self, grab):
|
||||
SDL_SetWindowGrab(self.win, SDL_TRUE if grab else SDL_FALSE)
|
||||
|
||||
def get_relative_mouse_pos(self):
|
||||
cdef int x, y
|
||||
SDL_GetGlobalMouseState(&x, &y)
|
||||
wx, wy = self.get_window_pos()
|
||||
return x - wx, y - wy
|
||||
|
||||
def set_custom_titlebar(self, titlebar_widget):
|
||||
SDL_SetWindowBordered(self.win, SDL_FALSE)
|
||||
|
|
|
@ -394,7 +394,7 @@ class WindowPygame(WindowBase):
|
|||
elif event.type == pygame.USEREVENT and \
|
||||
hasattr(pygame, 'USEREVENT_DROPFILE') and \
|
||||
event.code == pygame.USEREVENT_DROPFILE:
|
||||
self.dispatch('on_dropfile', event.filename)
|
||||
self.dispatch('on_drop_file', event.filename)
|
||||
|
||||
'''
|
||||
# unhandled event !
|
||||
|
|
|
@ -160,6 +160,7 @@ class WindowSDL(WindowBase):
|
|||
def __init__(self, **kwargs):
|
||||
self._pause_loop = False
|
||||
self._win = _WindowSDL2Storage()
|
||||
self._cursor_entered = False
|
||||
super(WindowSDL, self).__init__()
|
||||
self.titlebar_widget = None
|
||||
self._mouse_x = self._mouse_y = -1
|
||||
|
@ -543,12 +544,11 @@ class WindowSDL(WindowBase):
|
|||
event = self._win.poll()
|
||||
if event is None:
|
||||
continue
|
||||
# As dropfile is send was the app is still in pause.loop
|
||||
# A drop is send while the app is still in pause.loop
|
||||
# we need to dispatch it
|
||||
action, args = event[0], event[1:]
|
||||
if action == 'dropfile':
|
||||
dropfile = args
|
||||
self.dispatch('on_dropfile', dropfile[0])
|
||||
if action.startswith('drop'):
|
||||
self._dispatch_drop_event(action, args)
|
||||
# app_terminating event might be received while the app is paused
|
||||
# in this case EventLoop.quit will be set at _event_filter
|
||||
elif EventLoop.quit:
|
||||
|
@ -584,6 +584,9 @@ class WindowSDL(WindowBase):
|
|||
x, y = self._fix_mouse_pos(x, y)
|
||||
self._mouse_x = x
|
||||
self._mouse_y = y
|
||||
if not self._cursor_entered:
|
||||
self._cursor_entered = True
|
||||
self.dispatch('on_cursor_enter')
|
||||
# don't dispatch motion if no button are pressed
|
||||
if len(self._mouse_buttons_down) == 0:
|
||||
continue
|
||||
|
@ -593,6 +596,11 @@ class WindowSDL(WindowBase):
|
|||
elif action in ('mousebuttondown', 'mousebuttonup'):
|
||||
x, y, button = args
|
||||
x, y = self._fix_mouse_pos(x, y)
|
||||
self._mouse_x = x
|
||||
self._mouse_y = y
|
||||
if not self._cursor_entered:
|
||||
self._cursor_entered = True
|
||||
self.dispatch('on_cursor_enter')
|
||||
btn = 'left'
|
||||
if button == 3:
|
||||
btn = 'right'
|
||||
|
@ -607,10 +615,13 @@ class WindowSDL(WindowBase):
|
|||
if action == 'mousebuttonup':
|
||||
eventname = 'on_mouse_up'
|
||||
self._mouse_buttons_down.remove(button)
|
||||
self._mouse_x = x
|
||||
self._mouse_y = y
|
||||
self.dispatch(eventname, x, y, btn, self.modifiers)
|
||||
elif action.startswith('mousewheel'):
|
||||
x, y = self._win.get_relative_mouse_pos()
|
||||
if not self._collide_and_dispatch_cursor_enter(x, y):
|
||||
# Ignore if the cursor position is on the window title bar
|
||||
# or on its edges
|
||||
continue
|
||||
self._update_modifiers()
|
||||
x, y, button = args
|
||||
btn = 'scrolldown'
|
||||
|
@ -633,9 +644,8 @@ class WindowSDL(WindowBase):
|
|||
self.dispatch('on_mouse_up',
|
||||
self._mouse_x, self._mouse_y, btn, self.modifiers)
|
||||
|
||||
elif action == 'dropfile':
|
||||
dropfile = args
|
||||
self.dispatch('on_dropfile', dropfile[0])
|
||||
elif action.startswith('drop'):
|
||||
self._dispatch_drop_event(action, args)
|
||||
# video resize
|
||||
elif action == 'windowresized':
|
||||
self._size = self._win.window_size
|
||||
|
@ -678,9 +688,11 @@ class WindowSDL(WindowBase):
|
|||
self._focus = False
|
||||
|
||||
elif action == 'windowenter':
|
||||
self.dispatch('on_cursor_enter')
|
||||
x, y = self._win.get_relative_mouse_pos()
|
||||
self._collide_and_dispatch_cursor_enter(x, y)
|
||||
|
||||
elif action == 'windowleave':
|
||||
self._cursor_entered = False
|
||||
self.dispatch('on_cursor_leave')
|
||||
|
||||
elif action == 'joyaxismotion':
|
||||
|
@ -759,6 +771,27 @@ class WindowSDL(WindowBase):
|
|||
else:
|
||||
Logger.trace('WindowSDL: Unhandled event %s' % str(event))
|
||||
|
||||
def _dispatch_drop_event(self, action, args):
|
||||
if action == 'dropfile':
|
||||
self.dispatch('on_drop_file', args[0])
|
||||
elif action == 'droptext':
|
||||
self.dispatch('on_drop_text', args[0])
|
||||
elif action == 'dropbegin':
|
||||
x, y = self._win.get_relative_mouse_pos()
|
||||
self._collide_and_dispatch_cursor_enter(x, y)
|
||||
self.dispatch('on_drop_begin', x, y)
|
||||
elif action == 'dropend':
|
||||
self.dispatch('on_drop_end')
|
||||
|
||||
def _collide_and_dispatch_cursor_enter(self, x, y):
|
||||
w, h = self._win.window_size
|
||||
if 0 <= x < w and 0 <= y < h:
|
||||
self._mouse_x, self._mouse_y = self._fix_mouse_pos(x, y)
|
||||
if not self._cursor_entered:
|
||||
self._cursor_entered = True
|
||||
self.dispatch('on_cursor_enter')
|
||||
return True
|
||||
|
||||
def _do_resize(self, dt):
|
||||
Logger.debug('Window: Resize window to %s' % str(self.size))
|
||||
self._win.resize_window(*self._size)
|
||||
|
|
|
@ -160,6 +160,9 @@ cdef extern from "SDL.h":
|
|||
ctypedef enum SDL_EventType:
|
||||
SDL_FIRSTEVENT = 0,
|
||||
SDL_DROPFILE = 0x1000,
|
||||
SDL_DROPTEXT
|
||||
SDL_DROPBEGIN
|
||||
SDL_DROPCOMPLETE
|
||||
SDL_QUIT = 0x100
|
||||
SDL_WINDOWEVENT = 0x200
|
||||
SDL_SYSWMEVENT
|
||||
|
@ -540,7 +543,8 @@ cdef extern from "SDL.h":
|
|||
cdef char * SDL_GetError()
|
||||
cdef SDL_bool SDL_SetHint(char *name, char *value)
|
||||
cdef SDL_bool SDL_SetHintWithPriority(char *name, char *value, SDL_HintPriority priority)
|
||||
cdef Uint8 SDL_GetMouseState(int* x,int* y)
|
||||
cdef Uint32 SDL_GetMouseState(int* x,int* y)
|
||||
cdef Uint32 SDL_GetGlobalMouseState(int *x, int *y)
|
||||
cdef SDL_GLContext SDL_GL_CreateContext(SDL_Window* window)
|
||||
cdef int SDL_GetNumVideoDisplays()
|
||||
cdef int SDL_GetNumDisplayModes(int displayIndex)
|
||||
|
|
Loading…
Reference in New Issue