Skip to content

Commit 258b228

Browse files
Keymap, Cursor Reset Fix, Distance Removed
Fixed the keymap registration (again, and hopefully for the last time), I had been trying to make all the keymap changes on a single map, not realizing that I should have been switching between the addon keymap that I had created and the user's active keymap. Cursor Reset behavior seems to have been updated in Blender so that the cursor will remember its last screen position. This is the 'patched' behavior that this addon previously had implemented, which made the Cursor Reset setting redundant. I have implemented the previous 'cursor centering' behavior as the new 'Cursor Reset' behavior. The settings have flipped, but now the old behavior remains. The distance threshold did not have any effect on the addon, so it has been removed. If this is something that is missed, I can see about reimplementing it.
1 parent 19c7480 commit 258b228

3 files changed

Lines changed: 96 additions & 98 deletions

File tree

Preferences.py

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,49 @@
11
import bpy
2+
from bpy.props import (
3+
BoolProperty,
4+
FloatProperty,
5+
)
6+
from bpy.types import AddonPreferences
27

38

49
def update_node_keymap(self, context):
510
wm = context.window_manager
6-
kc = wm.keyconfigs.user
7-
for key in kc.keymaps['Node Editor'].keymap_items:
11+
active_kc = wm.keyconfigs.active
12+
for key in active_kc.keymaps['Node Editor'].keymap_items:
813
if (
914
key.idname == "wm.call_menu"
1015
and key.type == "RIGHTMOUSE"
1116
):
1217
key.active = not key.active
1318

19+
addon_kc = wm.keyconfigs.addon
20+
for key in addon_kc.keymaps['Node Editor'].keymap_items:
1421
if (
1522
key.idname == "blui.right_mouse_navigation"
1623
and key.type == "RIGHTMOUSE"
1724
):
1825
key.active = not key.active
1926

2027

21-
class RightMouseNavigationPreferences(bpy.types.AddonPreferences):
28+
class RightMouseNavigationPreferences(AddonPreferences):
2229
bl_idname = __package__
2330

24-
time: bpy.props.FloatProperty(
31+
time: FloatProperty(
2532
name="Time Threshold",
2633
description="How long you have hold right mouse to open menu",
27-
default=0.3,
34+
default=1.0,
2835
min=0.1,
29-
max=2
36+
max=10,
3037
)
3138

32-
distance: bpy.props.FloatProperty(
33-
name="Distance Threshold",
34-
description="How far you have to move the mouse to trigger navigation",
35-
default=20,
36-
min=1,
37-
max=200
38-
)
39-
40-
reset_cursor_on_exit: bpy.props.BoolProperty(
39+
reset_cursor_on_exit: BoolProperty(
4140
name="Reset Cursor on Exit",
42-
description="After exiting navigation, this determines if the cursor resets to where RMB was clicked (if checked) or stays in the center (if unchecked)",
43-
default=True
41+
description="After exiting navigation, this determines if the cursor stays "
42+
"where RMB was clicked (if unchecked) or resets to the center (if checked)",
43+
default=False,
4444
)
4545

46-
enable_for_node_editors: bpy.props.BoolProperty(
46+
enable_for_node_editors: BoolProperty(
4747
name="Enable for Node Editors",
4848
description="Right Mouse will pan the view / open the Node Add/Search Menu",
4949
default=False,
@@ -55,14 +55,12 @@ def draw(self, context):
5555

5656
box = layout.box()
5757
box.label(text="Menu / Movement", icon='DRIVER_DISTANCE')
58-
row = box.row()
59-
row.prop(self, 'time')
60-
row.prop(self, 'distance')
58+
box.prop(self, 'time')
6159

6260
row = layout.row()
6361
box = row.box()
6462
box.label(text="Cursor", icon='ORIENTATION_CURSOR')
6563
box.prop(self, 'reset_cursor_on_exit')
6664
box = row.box()
6765
box.label(text='Node Editor', icon='NODETREE')
68-
box.prop(self, 'enable_for_node_editors')
66+
box.prop(self, 'enable_for_node_editors')

RightMouseNavigation.py

Lines changed: 40 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
1-
import bpy, ctypes, math, sys
1+
import bpy
2+
from bpy.types import Operator
3+
import ctypes
4+
import sys
25

3-
class BLUI_OT_right_mouse_navigation(bpy.types.Operator):
6+
7+
class BLUI_OT_right_mouse_navigation(Operator):
48
"""Timer that decides whether to display a menu after Right Click"""
59
bl_idname = "blui.right_mouse_navigation"
610
bl_label = "Right Mouse Navigation"
711
bl_options = {'REGISTER', 'UNDO'}
812

913
_timer = None
1014
_count = 0
11-
_move_distance = 0
1215
MOUSE_RIGHTUP = 0x0010
1316
_finished = False
1417
_callMenu = False
@@ -27,34 +30,44 @@ class BLUI_OT_right_mouse_navigation(bpy.types.Operator):
2730
'PAINT_VERTEX': 'VIEW3D_PT_paint_vertex_context_menu',
2831
'PAINT_WEIGHT': 'VIEW3D_PT_paint_weight_context_menu',
2932
'PAINT_TEXTURE': 'VIEW3D_PT_paint_texture_context_menu',
30-
'SCULPT': 'VIEW3D_PT_sculpt_context_menu'}
33+
'SCULPT': 'VIEW3D_PT_sculpt_context_menu',
34+
}
3135

3236
def modal(self, context, event):
3337

3438
preferences = context.preferences
3539
addon_prefs = preferences.addons[__package__].preferences
40+
enable_nodes = addon_prefs.enable_for_node_editors
41+
42+
space_type = context.space_data.type
3643

37-
if context.space_data.type == 'VIEW_3D':
44+
if space_type == 'VIEW_3D':
3845
# Check if the Viewport is Perspective or Orthographic
3946
if bpy.context.region_data.is_perspective:
4047
self._ortho = False
4148
else:
4249
self._back_to_ortho = True
4350

44-
# The _finished Boolean acts as a flag to exit the modal loop,
51+
# The _finished Boolean acts as a flag to exit the modal loop,
4552
# it is not made True until after the cancel function is called
4653
if self._finished:
4754

4855
def reset_cursor():
4956
# Reset blender window cursor to previous position
50-
context.window.cursor_warp(self.view_x, self.view_y)
57+
area = context.area
58+
x = area.x
59+
y = area.y
60+
x += int(area.width / 2)
61+
y += int(area.height / 2)
62+
bpy.context.window.cursor_warp(x, y)
5163

5264
if self._callMenu:
5365
# Always reset the cursor if menu is called, as that implies a canceled navigation
54-
reset_cursor()
66+
if addon_prefs.reset_cursor_on_exit and not space_type == 'NODE_EDITOR':
67+
reset_cursor()
5568
self.callMenu(context)
5669
else:
57-
# Exit of a full navigation. Only reset the cursor if the preference (default False) is enabled
70+
# Exit of a full navigation. Only reset the cursor if the preference is enabled
5871
if addon_prefs.reset_cursor_on_exit:
5972
reset_cursor()
6073

@@ -63,44 +76,37 @@ def reset_cursor():
6376

6477
return {'CANCELLED'}
6578

66-
if context.space_data.type == 'VIEW_3D' or addon_prefs.enable_for_node_editors and context.space_data.type == 'NODE_EDITOR':
67-
# Calculate mousemove distance before it reaches threshold
68-
if event.type == "MOUSEMOVE" and self._move_distance < addon_prefs.distance:
69-
xDelta = event.mouse_x - event.mouse_prev_x
70-
yDelta = event.mouse_y - event.mouse_prev_y
71-
deltaDistance = math.sqrt(xDelta*xDelta + yDelta*yDelta)
72-
self._move_distance += deltaDistance
73-
79+
if space_type == 'VIEW_3D' or space_type == 'NODE_EDITOR' and enable_nodes:
7480
if event.type in {'RIGHTMOUSE'}:
7581
if event.value in {'RELEASE'}:
76-
if sys.platform == 'win32':
82+
if sys.platform.startswith('win'):
7783
# This fakes a Right Mouse Up event using Ctypes
7884
ctypes.windll.user32.mouse_event(self.MOUSE_RIGHTUP)
7985
# This brings back our mouse cursor to use with the menu
8086
context.window.cursor_modal_restore()
81-
# If the length of time you've been holding down
82-
# Right Mouse and Mouse move distance is longer than the threshold value,
87+
# If the length of time you've been holding down
88+
# Right Mouse and Mouse move distance is longer than the threshold value,
8389
# then set flag to call a context menu
84-
if self._move_distance < addon_prefs.distance and self._count < addon_prefs.time:
90+
if self._count < addon_prefs.time:
8591
self._callMenu = True
8692
self.cancel(context)
87-
# We now set the flag to true to exit the modal operator on the next loop through
93+
# We now set the flag to true to exit the modal operator on the next loop
8894
self._finished = True
8995
return {'PASS_THROUGH'}
9096

9197
if event.type == 'TIMER':
9298
if self._count <= addon_prefs.time:
93-
self._count += 0.01
99+
self._count += 0.1
94100
return {'PASS_THROUGH'}
95101

96102
def callMenu(self, context):
97103
if context.space_data.type == 'NODE_EDITOR':
98104
if context.space_data.node_tree:
99-
bpy.ops.wm.search_menu('INVOKE_DEFAULT')
105+
bpy.ops.wm.search_single_menu('INVOKE_DEFAULT', menu_idname='NODE_MT_add')
100106
else:
101107
try:
102108
bpy.ops.wm.call_menu(name=self.menu_by_mode[context.mode])
103-
except:
109+
except RuntimeError:
104110
bpy.ops.wm.call_panel(name=self.menu_by_mode[context.mode])
105111

106112
def invoke(self, context, event):
@@ -112,30 +118,32 @@ def invoke(self, context, event):
112118
def execute(self, context):
113119
preferences = context.preferences
114120
addon_prefs = preferences.addons[__package__].preferences
121+
enable_nodes = addon_prefs.enable_for_node_editors
122+
123+
space_type = context.space_data.type
115124

116125
# Execute is the first thing called in our operator, so we start by
117126
# calling Blender's built-in Walk Navigation
118-
if context.space_data.type == 'VIEW_3D':
127+
if space_type == 'VIEW_3D':
119128
bpy.ops.view3d.walk('INVOKE_DEFAULT')
120129
# Adding the timer and starting the loop
121130
wm = context.window_manager
122131
self._timer = wm.event_timer_add(0.1, window=context.window)
123132
wm.modal_handler_add(self)
124133
return {'RUNNING_MODAL'}
125134

126-
elif addon_prefs.enable_for_node_editors and context.space_data.type == 'NODE_EDITOR':
135+
elif space_type == 'NODE_EDITOR' and enable_nodes:
127136
bpy.ops.view2d.pan('INVOKE_DEFAULT')
128-
129137
wm = context.window_manager
130138
# Adding the timer and starting the loop
131-
self._timer = wm.event_timer_add(0.1, window=context.window)
139+
self._timer = wm.event_timer_add(0.01, window=context.window)
132140
wm.modal_handler_add(self)
133141
return {'RUNNING_MODAL'}
134-
135-
elif context.space_data.type == 'IMAGE_EDITOR':
142+
143+
elif space_type == 'IMAGE_EDITOR':
136144
bpy.ops.wm.call_panel(name="VIEW3D_PT_paint_texture_context_menu")
137145
return {'FINISHED'}
138146

139147
def cancel(self, context):
140148
wm = context.window_manager
141-
wm.event_timer_remove(self._timer)
149+
wm.event_timer_remove(self._timer)

0 commit comments

Comments
 (0)