Keymap: expose tool keymaps in the preferences
authorCampbell Barton <ideasman42@gmail.com>
Wed, 3 Oct 2018 05:48:37 +0000 (15:48 +1000)
committerCampbell Barton <ideasman42@gmail.com>
Wed, 3 Oct 2018 05:55:57 +0000 (15:55 +1000)
Currently some modes share tool keymaps, we might want to disable
this since it's confusing editing one thing in multiple places.

However this should be resolved in the tool definitions.

release/scripts/modules/bl_i18n_utils/bl_extract_messages.py
release/scripts/modules/bpy_extras/keyconfig_utils.py
release/scripts/modules/rna_keymap_ui.py
release/scripts/startup/bl_ui/space_toolsystem_common.py
tests/python/bl_keymap_completeness.py

index db46bf0736a36f253f20dc3330a906855cc7e63d..fada1255e8b5ec73d666a85309b54b53698a2083 100644 (file)
@@ -437,8 +437,8 @@ def dump_rna_messages(msgs, reports, settings, verbose=False):
                     reports, check_ctxt_rna, settings)
 
     # And parse keymaps!
-    from bpy_extras.keyconfig_utils import KM_HIERARCHY
-    walk_keymap_hierarchy(KM_HIERARCHY, "KM_HIERARCHY")
+    from bpy_extras.keyconfig_utils import km_hierarchy
+    walk_keymap_hierarchy(km_hierarchy(), "KM_HIERARCHY")
 
 
 ##### Python source code #####
index ec4db69986ca8dd45aa24b820643bf63b162d6ca..3da67ed24614587eb1f63d78dd4be71c518261bd 100644 (file)
 
 # <pep8 compliant>
 
+
+def _km_expand_from_toolsystem(space_type, context_mode):
+    def _fn():
+        from bl_ui.space_toolsystem_common import ToolSelectPanelHelper
+        for cls in ToolSelectPanelHelper.__subclasses__():
+            if cls.bl_space_type == space_type:
+                return cls.keymap_ui_hierarchy(context_mode)
+        raise Exception("keymap not found")
+    return _fn
+
+
+def _km_hierarchy_iter_recursive(items):
+    for sub in items:
+        if callable(sub):
+            yield from sub()
+        else:
+            yield (*sub[:3], list(_km_hierarchy_iter_recursive(sub[3])))
+
+
+def km_hierarchy():
+    return list(_km_hierarchy_iter_recursive(_km_hierarchy))
+
+
 # bpy.type.KeyMap: (km.name, km.space_type, km.region_type, [...])
 
 #    ('Script', 'EMPTY', 'WINDOW', []),
 
 
-KM_HIERARCHY = [
+# Access via 'km_hierarchy'.
+_km_hierarchy = [
     ('Window', 'EMPTY', 'WINDOW', []),  # file save, window change, exit
     ('Screen', 'EMPTY', 'WINDOW', [     # full screen, undo, screenshot
         ('Screen Editing', 'EMPTY', 'WINDOW', []),    # re-sizing, action corners
@@ -36,24 +60,51 @@ KM_HIERARCHY = [
     ('User Interface', 'EMPTY', 'WINDOW', []),
 
     ('3D View', 'VIEW_3D', 'WINDOW', [  # view 3d navigation and generic stuff (select, transform)
-        ('Object Mode', 'EMPTY', 'WINDOW', []),
-        ('Mesh', 'EMPTY', 'WINDOW', []),
-        ('Curve', 'EMPTY', 'WINDOW', []),
-        ('Armature', 'EMPTY', 'WINDOW', []),
-        ('Metaball', 'EMPTY', 'WINDOW', []),
-        ('Lattice', 'EMPTY', 'WINDOW', []),
-        ('Font', 'EMPTY', 'WINDOW', []),
-
-        ('Pose', 'EMPTY', 'WINDOW', []),
-
-        ('Vertex Paint', 'EMPTY', 'WINDOW', []),
-        ('Weight Paint', 'EMPTY', 'WINDOW', []),
+        ('Object Mode', 'EMPTY', 'WINDOW', [
+            _km_expand_from_toolsystem('VIEW_3D', 'OBJECT'),
+        ]),
+        ('Mesh', 'EMPTY', 'WINDOW', [
+            _km_expand_from_toolsystem('VIEW_3D', 'EDIT_MESH'),
+        ]),
+        ('Curve', 'EMPTY', 'WINDOW', [
+            _km_expand_from_toolsystem('VIEW_3D', 'EDIT_CURVE'),
+        ]),
+        ('Armature', 'EMPTY', 'WINDOW', [
+            _km_expand_from_toolsystem('VIEW_3D', 'EDIT_ARMATURE'),
+        ]),
+        ('Metaball', 'EMPTY', 'WINDOW', [
+            _km_expand_from_toolsystem('VIEW_3D', 'EDIT_METABALL'),
+        ]),
+        ('Lattice', 'EMPTY', 'WINDOW', [
+            _km_expand_from_toolsystem('VIEW_3D', 'EDIT_LATTICE'),
+        ]),
+        ('Font', 'EMPTY', 'WINDOW', [
+            _km_expand_from_toolsystem('VIEW_3D', 'EDIT_TEXT'),
+        ]),
+
+        ('Pose', 'EMPTY', 'WINDOW', [
+            _km_expand_from_toolsystem('VIEW_3D', 'POSE'),
+        ]),
+
+        ('Vertex Paint', 'EMPTY', 'WINDOW', [
+            _km_expand_from_toolsystem('VIEW_3D', 'PAINT_VERTEX'),
+        ]),
+        ('Weight Paint', 'EMPTY', 'WINDOW', [
+            _km_expand_from_toolsystem('VIEW_3D', 'PAINT_WEIGHT'),
+        ]),
         ('Weight Paint Vertex Selection', 'EMPTY', 'WINDOW', []),
         ('Face Mask', 'EMPTY', 'WINDOW', []),
-        ('Image Paint', 'EMPTY', 'WINDOW', []),  # image and view3d
-        ('Sculpt', 'EMPTY', 'WINDOW', []),
-
-        ('Particle', 'EMPTY', 'WINDOW', []),
+        # image and view3d
+        ('Image Paint', 'EMPTY', 'WINDOW', [
+            _km_expand_from_toolsystem('VIEW_3D', 'PAINT_TEXTURE'),
+        ]),
+        ('Sculpt', 'EMPTY', 'WINDOW', [
+            _km_expand_from_toolsystem('VIEW_3D', 'SCULPT'),
+        ]),
+
+        ('Particle', 'EMPTY', 'WINDOW', [
+            _km_expand_from_toolsystem('VIEW_3D', 'PARTICLE'),
+        ]),
 
         ('Knife Tool Modal Map', 'EMPTY', 'WINDOW', []),
         ('Custom Normals Modal Map', 'EMPTY', 'WINDOW', []),
@@ -69,7 +120,10 @@ KM_HIERARCHY = [
         ('View3D Zoom Modal', 'EMPTY', 'WINDOW', []),
         ('View3D Dolly Modal', 'EMPTY', 'WINDOW', []),
 
-        ('3D View Generic', 'VIEW_3D', 'WINDOW', []),    # toolbar and properties
+        # toolbar and properties
+        ('3D View Generic', 'VIEW_3D', 'WINDOW', [
+            _km_expand_from_toolsystem('VIEW_3D', None),
+        ]),
     ]),
 
     ('Graph Editor', 'GRAPH_EDITOR', 'WINDOW', [
@@ -88,7 +142,9 @@ KM_HIERARCHY = [
         ('UV Editor', 'EMPTY', 'WINDOW', []),  # image (reverse order, UVEdit before Image)
         ('Image Paint', 'EMPTY', 'WINDOW', []),  # image and view3d
         ('UV Sculpt', 'EMPTY', 'WINDOW', []),
-        ('Image Generic', 'IMAGE_EDITOR', 'WINDOW', []),
+        ('Image Generic', 'IMAGE_EDITOR', 'WINDOW', [
+            _km_expand_from_toolsystem('IMAGE_EDITOR', None),
+        ]),
     ]),
 
     ('Outliner', 'OUTLINER', 'WINDOW', []),
@@ -410,7 +466,7 @@ def keyconfig_test(kc):
     # Function body
 
     result = False
-    for entry in KM_HIERARCHY:
+    for entry in km_hierarchy():
         if testEntry(kc, entry):
             result = True
     return result
index 776d2d81d98ebcf5598f15f75f6f3051c33706f9..2581d7782f1254b19db866bfaf4d45d56c3d59d6 100644 (file)
@@ -356,7 +356,7 @@ def draw_filtered(display_keymaps, filter_type, filter_text, layout):
 
 def draw_hierarchy(display_keymaps, layout):
     from bpy_extras import keyconfig_utils
-    for entry in keyconfig_utils.KM_HIERARCHY:
+    for entry in keyconfig_utils.km_hierarchy():
         draw_entry(display_keymaps, entry, layout)
 
 
index f5cb0d006f6bc623d17430e4ad68f3f9563ddfda..5a32264bc5add99d40a05224904802c0d20b32ff 100644 (file)
@@ -302,25 +302,32 @@ class ToolSelectPanelHelper:
         return context.button_operator.name
 
     @classmethod
-    def _km_action_simple(cls, kc, context_mode, text, keymap_fn):
-        if context_mode is None:
-            context_mode = "All"
-        km_idname = f"{cls.keymap_prefix:s} {context_mode:s}, {text:s}"
+    def _km_action_simple(cls, kc, context_descr, text, keymap_fn):
+        km_idname = f"{cls.keymap_prefix:s} {context_descr:s}, {text:s}"
         km = kc.keymaps.get(km_idname)
         if km is None:
             km = kc.keymaps.new(km_idname, space_type=cls.bl_space_type, region_type='WINDOW')
             keymap_fn[0](km)
         keymap_fn[0] = km
 
+    # Special internal function, gives use items that contain keymaps.
+    @staticmethod
+    def _tools_flatten_with_keymap(tools):
+        for item_parent in tools:
+            if item_parent is None:
+                continue
+            for item in item_parent if (type(item_parent) is tuple) else (item_parent,):
+                # skip None or generator function
+                if item is None or _item_is_fn(item):
+                    continue
+                if item.keymap is not None:
+                    yield item
+
     @classmethod
     def register(cls):
         wm = bpy.context.window_manager
-
-        # XXX, should we be manipulating the user-keyconfig on load?
-        # Perhaps this should only add when keymap items don't already exist.
-        #
-        # This needs some careful consideration.
-        kc = wm.keyconfigs.user
+        # Write into defaults, users may modify in preferences.
+        kc = wm.keyconfigs.default
 
         # Track which tool-group was last used for non-active groups.
         # Blender stores the active tool-group index.
@@ -333,17 +340,26 @@ class ToolSelectPanelHelper:
             return
 
         for context_mode, tools in cls.tools_all():
-            for item_parent in tools:
-                if item_parent is None:
-                    continue
-                for item in item_parent if (type(item_parent) is tuple) else (item_parent,):
-                    # skip None or generator function
-                    if item is None or _item_is_fn(item):
-                        continue
-                    keymap_data = item.keymap
-                    if keymap_data is not None and callable(keymap_data[0]):
-                        text = item.text
-                        cls._km_action_simple(kc, context_mode, text, keymap_data)
+            if context_mode is None:
+                context_descr = "All"
+            else:
+                context_descr = context_mode.replace("_", " ").title()
+
+            for item in cls._tools_flatten_with_keymap(tools):
+                keymap_data = item.keymap
+                if callable(keymap_data[0]):
+                    text = item.text
+                    cls._km_action_simple(kc, context_descr, text, keymap_data)
+
+    @classmethod
+    def keymap_ui_hierarchy(cls, context_mode):
+        # See: bpy_extras.keyconfig_utils
+        for context_mode_test, tools in cls.tools_all():
+            if context_mode_test == context_mode:
+                for item in cls._tools_flatten_with_keymap(tools):
+                    km = item.keymap[0]
+                    # print((km.name, cls.bl_space_type, 'WINDOW', []))
+                    yield (km.name, cls.bl_space_type, 'WINDOW', [])
 
     # -------------------------------------------------------------------------
     # Layout Generators
index 652ed449a3caf6f447d60a8144a2cee438c71b64..0edee3b02f0fa6f2f49a548d9948517f86267f92 100644 (file)
@@ -27,12 +27,12 @@ from bpy_extras import keyconfig_utils
 def check_maps():
     maps = {}
 
-    def fill_maps(ls):
-        for km_name, km_space_type, km_region_type, km_sub in ls:
+    def fill_maps(seq):
+        for km_name, km_space_type, km_region_type, km_sub in seq:
             maps[km_name] = (km_space_type, km_region_type)
             fill_maps(km_sub)
 
-    fill_maps(keyconfig_utils.KM_HIERARCHY)
+    fill_maps(keyconfig_utils.km_hierarchy())
 
     import bpy
     keyconf = bpy.context.window_manager.keyconfigs.active