2025-07-01
This commit is contained in:
@@ -0,0 +1,425 @@
|
||||
'''
|
||||
Copyright (C) 2023 CG Cookie
|
||||
http://cgcookie.com
|
||||
hello@cgcookie.com
|
||||
|
||||
Created by Jonathan Denning, Jonathan Williamson
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
'''
|
||||
|
||||
import re
|
||||
import time
|
||||
import inspect
|
||||
from copy import deepcopy
|
||||
|
||||
import bpy
|
||||
|
||||
from .debug import dprint
|
||||
from .decorators import blender_version_wrapper
|
||||
from .human_readable import convert_actions_to_human_readable, convert_human_readable_to_actions
|
||||
from .maths import Point2D, Vec2D
|
||||
from .timerhandler import TimerHandler
|
||||
from . import blender_preferences as bprefs
|
||||
|
||||
|
||||
###
|
||||
###
|
||||
### The classes here will _eventually_ replace those in useractions.py
|
||||
###
|
||||
###
|
||||
|
||||
|
||||
'''
|
||||
copied from:
|
||||
- https://docs.blender.org/api/current/bpy.types.Event.html
|
||||
- https://docs.blender.org/api/current/bpy.types.KeyMapItem.html
|
||||
|
||||
direction: { 'ANY', 'NORTH', 'NORTH_EAST', 'EAST', 'SOUTH_EAST', 'SOUTH', 'SOUTH_WEST', 'WEST', 'NORTH_WEST' }
|
||||
type: {
|
||||
'NONE',
|
||||
|
||||
# System
|
||||
'WINDOW_DEACTIVATE', # window lost focus (minimized, switch away from, etc.)
|
||||
'ACTIONZONE_AREA', 'ACTIONZONE_REGION', 'ACTIONZONE_FULLSCREEN',
|
||||
|
||||
# Mouse
|
||||
'LEFTMOUSE', 'MIDDLEMOUSE', 'RIGHTMOUSE', 'BUTTON4MOUSE', 'BUTTON5MOUSE', 'BUTTON6MOUSE', 'BUTTON7MOUSE',
|
||||
'MOUSEMOVE', 'INBETWEEN_MOUSEMOVE',
|
||||
'MOUSEROTATE', 'MOUSESMARTZOOM', 'WHEELUPMOUSE', 'WHEELDOWNMOUSE', 'WHEELINMOUSE', 'WHEELOUTMOUSE',
|
||||
'PEN', 'ERASER',
|
||||
'TRACKPADPAN', 'TRACKPADZOOM',
|
||||
|
||||
# Keyboard
|
||||
'LEFT_CTRL', 'LEFT_ALT', 'LEFT_SHIFT', 'RIGHT_ALT', 'RIGHT_CTRL', 'RIGHT_SHIFT', 'OSKEY',
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
|
||||
'ZERO', 'ONE', 'TWO', 'THREE', 'FOUR', 'FIVE', 'SIX', 'SEVEN', 'EIGHT', 'NINE',
|
||||
'SEMI_COLON', 'PERIOD', 'COMMA', 'QUOTE', 'ACCENT_GRAVE', 'MINUS', 'PLUS', 'SLASH', 'BACK_SLASH', 'EQUAL', 'LEFT_BRACKET', 'RIGHT_BRACKET',
|
||||
'GRLESS',
|
||||
'NUMPAD_2', 'NUMPAD_4', 'NUMPAD_6', 'NUMPAD_8', 'NUMPAD_1', 'NUMPAD_3', 'NUMPAD_5', 'NUMPAD_7', 'NUMPAD_9',
|
||||
'NUMPAD_PERIOD', 'NUMPAD_SLASH', 'NUMPAD_ASTERIX', 'NUMPAD_0', 'NUMPAD_MINUS', 'NUMPAD_ENTER', 'NUMPAD_PLUS',
|
||||
'F1', 'F2', 'F3', 'F4', 'F5', 'F6', 'F7', 'F8', 'F9', 'F10', 'F11', 'F12', 'F13', 'F14', 'F15', 'F16', 'F17', 'F18', 'F19', 'F20', 'F21', 'F22', 'F23', 'F24',
|
||||
'PAUSE', 'INSERT',
|
||||
'HOME', 'PAGE_UP', 'PAGE_DOWN', 'END',
|
||||
'MEDIA_PLAY', 'MEDIA_STOP', 'MEDIA_FIRST', 'MEDIA_LAST',
|
||||
'ESC', 'TAB', 'RET', 'SPACE', 'LINE_FEED', 'BACK_SPACE', 'DEL',
|
||||
'LEFT_ARROW', 'DOWN_ARROW', 'RIGHT_ARROW', 'UP_ARROW',
|
||||
|
||||
# ???
|
||||
'APP',
|
||||
|
||||
# Text Input
|
||||
'TEXTINPUT',
|
||||
|
||||
# Timer
|
||||
'TIMER', 'TIMER0', 'TIMER1', 'TIMER2', 'TIMER_JOBS', 'TIMER_AUTOSAVE', 'TIMER_REPORT', 'TIMERREGION',
|
||||
|
||||
# NDOF
|
||||
'NDOF_MOTION', 'NDOF_BUTTON_MENU', 'NDOF_BUTTON_FIT', 'NDOF_BUTTON_TOP', 'NDOF_BUTTON_BOTTOM', 'NDOF_BUTTON_LEFT', 'NDOF_BUTTON_RIGHT',
|
||||
'NDOF_BUTTON_FRONT', 'NDOF_BUTTON_BACK', 'NDOF_BUTTON_ISO1', 'NDOF_BUTTON_ISO2', 'NDOF_BUTTON_ROLL_CW', 'NDOF_BUTTON_ROLL_CCW',
|
||||
'NDOF_BUTTON_SPIN_CW', 'NDOF_BUTTON_SPIN_CCW', 'NDOF_BUTTON_TILT_CW', 'NDOF_BUTTON_TILT_CCW', 'NDOF_BUTTON_ROTATE', 'NDOF_BUTTON_PANZOOM',
|
||||
'NDOF_BUTTON_DOMINANT', 'NDOF_BUTTON_PLUS', 'NDOF_BUTTON_MINUS',
|
||||
'NDOF_BUTTON_1', 'NDOF_BUTTON_2', 'NDOF_BUTTON_3', 'NDOF_BUTTON_4', 'NDOF_BUTTON_5', 'NDOF_BUTTON_6', 'NDOF_BUTTON_7', 'NDOF_BUTTON_8', 'NDOF_BUTTON_9', 'NDOF_BUTTON_10',
|
||||
'NDOF_BUTTON_A', 'NDOF_BUTTON_B', 'NDOF_BUTTON_C',
|
||||
|
||||
# ???
|
||||
'XR_ACTION'
|
||||
}
|
||||
value: { 'ANY', 'PRESS', 'RELEASE', 'CLICK', 'DOUBLE_CLICK', 'CLICK_DRAG', 'NOTHING' }
|
||||
|
||||
class bpy.types.Event:
|
||||
alt True when the Alt/Option key is held (unless both alt keys pressed and one is released)
|
||||
ascii single ASCII character for this event
|
||||
ctrl True when Ctrl key is held (unless both ctrl keys pressed and one is released)
|
||||
direction drag direction (never used?)
|
||||
is_mouse_absolute last motion event was an absolute input
|
||||
is_repeat event is generated by holding a key down
|
||||
is_tablet event has tablet data
|
||||
mouse_prev_press_x window relative location of the last press event (most recent press)
|
||||
mouse_prev_press_y
|
||||
mouse_prev_x window relative location of mouse (in last event?)
|
||||
mouse_prev_y
|
||||
mouse_region_x region relative location of mouse
|
||||
mouse_region_y
|
||||
mouse_x window relative location of mouse
|
||||
mouse_y
|
||||
oskey True when Cmd key is held
|
||||
pressure pressure of tablet or 1.0 if no tablet present
|
||||
shift True when Shift key is held (unless both shift keys pressed and one is released)
|
||||
tilt pressure (tilt?) of tablet or zeros if no tablet present ([float, float])
|
||||
type (Type of event?)
|
||||
type_prev: (type of last event?)
|
||||
unicode: single unicode character for this event
|
||||
value: type of event, only applies to some
|
||||
value_prev: type of (last?) event, only applies to some
|
||||
xr: XR event data
|
||||
|
||||
class bpy.types.KeyMapItem:
|
||||
active True when KMI is active
|
||||
alt Alt key pressed (int), -1 for any state
|
||||
alt_ui (bool)
|
||||
any any modifier keys pressed
|
||||
ctrl Control key pressed (int), -1 for any state
|
||||
ctrl_ui (bool)
|
||||
direction drag direction
|
||||
id ID of item (int [-32768, 32767], default 0)
|
||||
idname identifier of operator to call on input event
|
||||
is_user_defined True if KMI is user defined (doesn't just replace a builtin item)
|
||||
is_user_modified True if KMI is modified by user
|
||||
key_modifier Regular key pressed as a modifier (see type above)
|
||||
map_type type of event mapping, { 'KEYBOARD', 'MOUSE', 'NDOF', 'TEXTINPUT', 'TIMER' }
|
||||
name name of operator (translated) to call on input event
|
||||
oskey Operating System Key pressed (int), -1 for any state
|
||||
oskey_ui (bool)
|
||||
properties Properties to set when the operator is called
|
||||
propvalue the value this event translates to in a modal keymap
|
||||
repeat active on key-repeat events (when key is held)
|
||||
shift Shift key pressed (int), -1 for any state
|
||||
shift_ui (bool)
|
||||
show_expanded Show key map event and property details in the user interface
|
||||
type type of event
|
||||
value (value of event?)
|
||||
|
||||
bprefs.mouse_doubleclick()
|
||||
bprefs.mouse_drag()
|
||||
bprefs.mouse_move()
|
||||
bprefs.mouse_select()
|
||||
|
||||
notes:
|
||||
|
||||
* if lshift is pressed, then shift is True. if rshift is pressed, then shift will still be True.
|
||||
if lshift or rshift are released, shift will be False! but, this isn't an issue, as blender handles it in the same way.
|
||||
|
||||
* if modal operator invokes another operator on action, modal operator will only see the release of the action in (type_prev, value_prev)
|
||||
|
||||
* mouse_prev_press_* will hold location of mouse at most recent press (keyboard, mouse, anything!)
|
||||
|
||||
'''
|
||||
|
||||
class EventHandler:
|
||||
keyboard_modifier_types = {
|
||||
'LEFT_CTRL', 'LEFT_ALT', 'LEFT_SHIFT', 'RIGHT_ALT', 'RIGHT_CTRL', 'RIGHT_SHIFT', 'OSKEY',
|
||||
}
|
||||
keyboard_alpha_types = {
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
|
||||
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
|
||||
}
|
||||
keyboard_number_types = {
|
||||
'ZERO', 'ONE', 'TWO', 'THREE', 'FOUR', 'FIVE', 'SIX', 'SEVEN', 'EIGHT', 'NINE',
|
||||
'NUMPAD_2', 'NUMPAD_4', 'NUMPAD_6', 'NUMPAD_8', 'NUMPAD_1', 'NUMPAD_3', 'NUMPAD_5', 'NUMPAD_7', 'NUMPAD_9', 'NUMPAD_0',
|
||||
}
|
||||
keyboard_numpad_types = {
|
||||
'NUMPAD_2', 'NUMPAD_4', 'NUMPAD_6', 'NUMPAD_8', 'NUMPAD_1', 'NUMPAD_3', 'NUMPAD_5', 'NUMPAD_7', 'NUMPAD_9', 'NUMPAD_0',
|
||||
'NUMPAD_PERIOD', 'NUMPAD_SLASH', 'NUMPAD_ASTERIX', 'NUMPAD_MINUS', 'NUMPAD_PLUS',
|
||||
'NUMPAD_ENTER',
|
||||
}
|
||||
keyboard_function_types = {
|
||||
'F1', 'F2', 'F3', 'F4', 'F5', 'F6', 'F7', 'F8', 'F9', 'F10', 'F11', 'F12',
|
||||
'F13', 'F14', 'F15', 'F16', 'F17', 'F18', 'F19', 'F20', 'F21', 'F22', 'F23', 'F24',
|
||||
}
|
||||
keyboard_symbols_types = {
|
||||
'SEMI_COLON', 'PERIOD', 'COMMA', 'QUOTE', 'ACCENT_GRAVE', 'MINUS', 'PLUS', 'SLASH', 'BACK_SLASH', 'EQUAL', 'LEFT_BRACKET', 'RIGHT_BRACKET',
|
||||
'NUMPAD_PERIOD', 'NUMPAD_SLASH', 'NUMPAD_ASTERIX', 'NUMPAD_MINUS', 'NUMPAD_PLUS',
|
||||
'GRLESS',
|
||||
}
|
||||
keyboard_media_types = {
|
||||
'MEDIA_PLAY', 'MEDIA_STOP', 'MEDIA_FIRST', 'MEDIA_LAST',
|
||||
'PAUSE', # ???
|
||||
}
|
||||
keyboard_movement_types = {
|
||||
'HOME', 'PAGE_UP', 'PAGE_DOWN', 'END',
|
||||
'LEFT_ARROW', 'DOWN_ARROW', 'RIGHT_ARROW', 'UP_ARROW',
|
||||
}
|
||||
keyboard_escape_types = {
|
||||
'ESC',
|
||||
# 'TAB', ???
|
||||
}
|
||||
keyboard_edit_types = {
|
||||
'INSERT', 'TAB', 'RET', 'SPACE', 'LINE_FEED', 'BACK_SPACE', 'DEL',
|
||||
}
|
||||
keyboard_drag_types = {
|
||||
*keyboard_alpha_types,
|
||||
*keyboard_number_types,
|
||||
*keyboard_numpad_types,
|
||||
*keyboard_symbols_types,
|
||||
}
|
||||
keyboard_types = {
|
||||
*keyboard_modifier_types,
|
||||
*keyboard_alpha_types,
|
||||
*keyboard_number_types,
|
||||
*keyboard_numpad_types,
|
||||
*keyboard_function_types,
|
||||
*keyboard_symbols_types,
|
||||
*keyboard_media_types,
|
||||
*keyboard_movement_types,
|
||||
*keyboard_edit_types,
|
||||
}
|
||||
|
||||
mouse_button_types = {
|
||||
'LEFTMOUSE', 'MIDDLEMOUSE', 'RIGHTMOUSE', 'BUTTON4MOUSE', 'BUTTON5MOUSE', 'BUTTON6MOUSE', 'BUTTON7MOUSE',
|
||||
'MOUSEROTATE', 'MOUSESMARTZOOM', 'WHEELUPMOUSE', 'WHEELDOWNMOUSE', 'WHEELINMOUSE', 'WHEELOUTMOUSE',
|
||||
'PEN', 'ERASER',
|
||||
'TRACKPADPAN', 'TRACKPADZOOM',
|
||||
}
|
||||
mouse_move_types = {
|
||||
'MOUSEMOVE', 'INBETWEEN_MOUSEMOVE',
|
||||
}
|
||||
mouse_types = { *mouse_button_types, *mouse_move_types, }
|
||||
|
||||
ndof_types = {
|
||||
'NDOF_MOTION',
|
||||
'NDOF_BUTTON_MENU', 'NDOF_BUTTON_FIT', 'NDOF_BUTTON_TOP', 'NDOF_BUTTON_BOTTOM', 'NDOF_BUTTON_LEFT', 'NDOF_BUTTON_RIGHT',
|
||||
'NDOF_BUTTON_FRONT', 'NDOF_BUTTON_BACK', 'NDOF_BUTTON_ISO1', 'NDOF_BUTTON_ISO2', 'NDOF_BUTTON_ROLL_CW', 'NDOF_BUTTON_ROLL_CCW',
|
||||
'NDOF_BUTTON_SPIN_CW', 'NDOF_BUTTON_SPIN_CCW', 'NDOF_BUTTON_TILT_CW', 'NDOF_BUTTON_TILT_CCW', 'NDOF_BUTTON_ROTATE', 'NDOF_BUTTON_PANZOOM',
|
||||
'NDOF_BUTTON_DOMINANT', 'NDOF_BUTTON_PLUS', 'NDOF_BUTTON_MINUS',
|
||||
'NDOF_BUTTON_1', 'NDOF_BUTTON_2', 'NDOF_BUTTON_3', 'NDOF_BUTTON_4', 'NDOF_BUTTON_5', 'NDOF_BUTTON_6', 'NDOF_BUTTON_7', 'NDOF_BUTTON_8', 'NDOF_BUTTON_9', 'NDOF_BUTTON_10',
|
||||
'NDOF_BUTTON_A', 'NDOF_BUTTON_B', 'NDOF_BUTTON_C',
|
||||
}
|
||||
|
||||
timer_types = {
|
||||
'TIMER', 'TIMER0', 'TIMER1', 'TIMER2', 'TIMER_JOBS', 'TIMER_AUTOSAVE', 'TIMER_REPORT', 'TIMERREGION',
|
||||
}
|
||||
|
||||
|
||||
scrollable_types = {
|
||||
'HOME', 'PAGE_UP', 'PAGE_DOWN', 'END',
|
||||
'LEFT_ARROW', 'DOWN_ARROW', 'RIGHT_ARROW', 'UP_ARROW',
|
||||
'WHEELUPMOUSE', 'WHEELDOWNMOUSE', 'WHEELINMOUSE', 'WHEELOUTMOUSE',
|
||||
'TRACKPADPAN',
|
||||
}
|
||||
|
||||
pressable_types = {
|
||||
# pressable also means releasable, clickable, double-clickable
|
||||
*keyboard_types,
|
||||
*mouse_button_types,
|
||||
*ndof_types
|
||||
}
|
||||
|
||||
special_types = {
|
||||
'mousemove': { 'MOUSEMOVE', 'INBETWEEN_MOUSEMOVE' },
|
||||
'timer': { 'TIMER', 'TIMER_REPORT', 'TIMERREGION' },
|
||||
'deactivate': { 'WINDOW_DEACTIVATE' },
|
||||
}
|
||||
|
||||
modifier_keys = {
|
||||
'alt', 'ctrl', 'shift', 'oskey',
|
||||
}
|
||||
|
||||
def __init__(self, context, *, allow_keyboard_dragging=False):
|
||||
self._allow_keyboard_dragging = allow_keyboard_dragging
|
||||
|
||||
self.reset()
|
||||
|
||||
def reset(self):
|
||||
# current states
|
||||
self.mods = { mod: False for mod in self.modifier_keys }
|
||||
self.mouse = None
|
||||
self.mouse_prev = None
|
||||
self._held = {} # types that are currently held. {event.type: time of first held}
|
||||
self._is_dragging = False
|
||||
self.is_navigating = False # <- need this???
|
||||
|
||||
# memory
|
||||
self._first_held = None # contains details of when first held action happened (held type, mouse loc, time)
|
||||
self._last_event_type = None
|
||||
self._just_released = None # keep track of last pressed for double click
|
||||
|
||||
|
||||
|
||||
# these properties are for very temporal state changes
|
||||
@property
|
||||
def is_mousemove(self):
|
||||
return self._last_event_type in self.special_types['mousemove']
|
||||
@property
|
||||
def is_timer(self):
|
||||
return self._last_event_type in self.special_types['timer']
|
||||
@property
|
||||
def is_deactivate(self):
|
||||
return self._last_event_type in self.special_types['deactivate']
|
||||
|
||||
|
||||
def is_draggable(self, event):
|
||||
if self._allow_keyboard_dragging and event.type in self.keyboard_drag_types:
|
||||
return True
|
||||
if event.type in self.mouse_button_types:
|
||||
return True
|
||||
return False
|
||||
|
||||
def is_double_click(self, *, event=None):
|
||||
if event and event.type != self.get_just_held('type'):
|
||||
return False
|
||||
delta = self.get_just_held('time') - time.time()
|
||||
return delta < prefs.mouse_doubleclick()
|
||||
|
||||
def is_dragging(self, *, event=None):
|
||||
return get_held(event.type, prop='dragging') if event else self.get_first_held(prop='dragging')
|
||||
|
||||
def holding_non_modifiers(self):
|
||||
return bool(t for t in self._held if t not in self.keyboard_modifier_types)
|
||||
|
||||
def get_held(self, etype, *, prop=None, default=None):
|
||||
if etype not in self._held: return default
|
||||
d = self._held[etype]
|
||||
return d[prop] if prop else d
|
||||
|
||||
def get_first_held(self, *, ignore_mods=True, prop=None, default=None):
|
||||
held = self._held
|
||||
if ignore_mods:
|
||||
held = {htype:held[htype] for htype in held if htype not in self.keyboard_modifier_types}
|
||||
if not held: return default
|
||||
d = min(held, key=lambda htype: held[htype]['time'])
|
||||
return d[prop] if prop else d
|
||||
|
||||
def get_just_held(self, *, prop=None, default=None):
|
||||
return self._first_held[prop] if self._first_held else default
|
||||
|
||||
def _update_press(self, event):
|
||||
# ignore non-pressable events
|
||||
if event.type not in self.pressable_types:
|
||||
return
|
||||
|
||||
# FIRST, if nothing is held (ignoring modifiers), record first held details
|
||||
if not self.holding_non_modifiers():
|
||||
self._first_held = {
|
||||
'type': event.type,
|
||||
'time': time.time(),
|
||||
'mouse': self.mouse,
|
||||
'dragging': False,
|
||||
'can drag': self.is_type_draggable(event),
|
||||
'double': self.is_double_click(event),
|
||||
}
|
||||
|
||||
self._held[event.type] = {
|
||||
'type': event.type,
|
||||
'time': time.time(),
|
||||
'mouse': self.mouse,
|
||||
'dragging': False,
|
||||
'can drag': self.is_type_draggable(event),
|
||||
'double': self.is_double_click(event),
|
||||
}
|
||||
|
||||
def _update_release(self, event, *, prev=False):
|
||||
etype = event.type if not prev else event.prev_type
|
||||
|
||||
if etype == self.get_first_held(prop='type'):
|
||||
self._just_released = self._first_held
|
||||
self._first_held = None
|
||||
|
||||
if etype in self.held:
|
||||
del self._held[etype]
|
||||
|
||||
def _update_drag(self, event):
|
||||
first_held = self.get_first_held()
|
||||
if first_held['dragging'] or not first_held['can drag']:
|
||||
return
|
||||
|
||||
# has mouse moved far enough?
|
||||
mouse_travel = (first_held['mouse'] - self.mouse).length
|
||||
if mouse_travel > bprefs.mouse_drag():
|
||||
self._first_held['dragging'] = True
|
||||
|
||||
fhtype = self._first_held['type']
|
||||
if self._allow_keyboard_dragging and fhtype in self.keyboard_drag_types:
|
||||
self._first_held['dragging'] = True
|
||||
elif fhtype in self.mouse_button_types:
|
||||
self._first_held['dragging'] = True
|
||||
|
||||
def update(self, context, event):
|
||||
self._last_event_type = event.type
|
||||
|
||||
if self.is_deactivate:
|
||||
# any time these actions are received, all action states will be flushed
|
||||
self.reset()
|
||||
|
||||
self.mods['alt'] = event.alt
|
||||
self.mods['ctrl'] = event.ctrl
|
||||
self.mods['oskey'] = event.oskey
|
||||
self.mods['shift'] = event.shift
|
||||
self.mouse = Point2D((event.mouse_x, event.mouse_y))
|
||||
self.mouse_prev = Point2D((event.mouse_prev_x, event.mouse_prev_y))
|
||||
|
||||
if event.value_prev == 'RELEASE':
|
||||
self._update_release(event, prev=True)
|
||||
|
||||
if event.value == 'PRESS':
|
||||
self._update_press(event)
|
||||
elif event.value == 'RELEASE':
|
||||
self._update_release(event)
|
||||
elif event.value == 'NOTHING':
|
||||
if event.type == 'MOUSEMOVE':
|
||||
pass
|
||||
|
||||
if event.type not in self.mouse_move_types:
|
||||
self._update_drag(event)
|
||||
|
||||
Reference in New Issue
Block a user