[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [54951] trunk/blender: keymap filter by keybindings in the userpreferences.

Campbell Barton ideasman42 at gmail.com
Fri Mar 1 07:18:00 CET 2013


Revision: 54951
          http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-blender&revision=54951
Author:   campbellbarton
Date:     2013-03-01 06:17:59 +0000 (Fri, 01 Mar 2013)
Log Message:
-----------
keymap filter by keybindings in the userpreferences.
- optional, select between name/keybinding.
- when key input can't be parsed, alert red to give the user some feedback.
- key shortcut parsing could be improved or swapped out for button which grabs shortcut.

Modified Paths:
--------------
    trunk/blender/release/scripts/startup/bl_ui/space_userpref_keymap.py
    trunk/blender/source/blender/makesdna/DNA_space_types.h
    trunk/blender/source/blender/makesrna/intern/rna_space.c

Modified: trunk/blender/release/scripts/startup/bl_ui/space_userpref_keymap.py
===================================================================
--- trunk/blender/release/scripts/startup/bl_ui/space_userpref_keymap.py	2013-03-01 00:35:01 UTC (rev 54950)
+++ trunk/blender/release/scripts/startup/bl_ui/space_userpref_keymap.py	2013-03-01 06:17:59 UTC (rev 54951)
@@ -213,14 +213,97 @@
                     self.draw_km(display_keymaps, kc, kmm, None, layout, level + 1)
                     layout.context_pointer_set("keymap", km)
 
-    def draw_filtered(self, display_keymaps, filter_text, layout):
+    _EVENT_TYPES = set()
+    _EVENT_TYPE_MAP = {}
+    def draw_filtered(self, display_keymaps, filter_type, filter_text, layout):
+
+        if filter_type == 'NAME':
+            def filter_func(kmi):
+                return (filter_text in kmi.idname.lower() or
+                        filter_text in kmi.name.lower())
+                
+        else:
+            if not self._EVENT_TYPES:
+                enum = bpy.types.Event.bl_rna.properties["type"].enum_items
+                self._EVENT_TYPES.update(enum.keys())
+                self._EVENT_TYPE_MAP.update({item.name.replace(" ", "_").upper(): key for key, item in enum.items()})
+
+                del enum
+                self._EVENT_TYPE_MAP.update({
+                    "*": 'NUMPAD_ASTERIX',
+                    "/": 'NUMPAD_SLASH',
+                    "RMB": 'RIGHTMOUSE',
+                    "LMB": 'LEFTMOUSE',
+                    "MMB": 'MIDDLEMOUSE',
+                    })
+            # done with once off init
+
+            filter_text_split = filter_text.strip()
+            filter_text_split = filter_text.split()
+
+            # Modifier {kmi.attribute: name} mapping
+            key_mod = {
+                "ctrl": "ctrl",
+                "alt": "alt",
+                "shift": "shift",
+                "cmd": "oskey",
+                "oskey": "oskey",
+                "any": "any",
+                }
+            # KeyMapItem like dict, use for comparing against
+            # attr: state
+            kmi_test_dict = {}
+
+            # initialize? - so if a if a kmi has a MOD assigned it wont show up.
+            #~ for kv in key_mod.values():
+            #~    kmi_test_dict[kv] = False
+
+            # altname: attr
+            for kk, kv in key_mod.items():
+                if kk in filter_text_split:
+                    filter_text_split.remove(kk)
+                    kmi_test_dict[kv] = True
+            # whats left should be the event type
+            if len(filter_text_split) > 1:
+                return False
+            elif filter_text_split:
+                kmi_type = filter_text_split[0].upper()
+                
+                if kmi_type not in self._EVENT_TYPES:
+                    # replacement table
+                    kmi_type_test = self._EVENT_TYPE_MAP.get(kmi_type)
+                    if kmi_type_test is None:
+                        # print("Unknown Type:", kmi_type)
+                        
+                        # Partial match
+                        for k, v in self._EVENT_TYPE_MAP.items():
+                            if kmi_type in k:
+                                kmi_type_test = v
+                                break
+                            if kmi_type in v:
+                                kmi_type_test = v
+                                break
+
+                        if kmi_type_test is None:
+                            return False
+
+                    kmi_type = kmi_type_test
+                    del kmi_type_test
+                    
+                kmi_test_dict["type"] = kmi_type
+
+            # main filter func, runs many times
+            def filter_func(kmi):
+                for kk, ki in kmi_test_dict.items():
+                    if getattr(kmi, kk) != ki:
+                        return False
+                return True
+
         for km, kc in display_keymaps:
             km = km.active()
             layout.context_pointer_set("keymap", km)
 
-            filtered_items = [kmi for kmi in km.keymap_items
-                              if (filter_text in kmi.idname.lower() or
-                                  filter_text in kmi.name.lower())]
+            filtered_items = [kmi for kmi in km.keymap_items if filter_func(kmi)]
 
             if filtered_items:
                 col = layout.column()
@@ -243,6 +326,7 @@
                 col = self.indented_layout(layout, 1)
                 subcol = col.split(percentage=0.2).column()
                 subcol.operator("wm.keyitem_add", text="Add New", icon='ZOOMIN')
+        return True
 
     def draw_hierarchy(self, display_keymaps, layout):
         from bpy_extras import keyconfig_utils
@@ -254,6 +338,7 @@
 
         wm = context.window_manager
         kc = wm.keyconfigs.user
+        spref = context.space_data
 
         col = layout.column()
         sub = col.column()
@@ -264,7 +349,7 @@
         row = subcol.row(align=True)
 
         #~ row.prop_search(wm.keyconfigs, "active", wm, "keyconfigs", text="Key Config:")
-        text = bpy.path.display_name(context.window_manager.keyconfigs.active.name)
+        text = bpy.path.display_name(wm.keyconfigs.active.name)
         if not text:
             text = "Blender (default)"
         row.menu("USERPREF_MT_keyconfigs", text=text)
@@ -273,18 +358,28 @@
 
         #~ layout.context_pointer_set("keyconfig", wm.keyconfigs.active)
         #~ row.operator("wm.keyconfig_remove", text="", icon='X')
+        row.separator()
+        rowsub = row.split(align=True, percentage=0.33)
+        # postpone drawing into rowsub, so we can set alert!
 
-        row.prop(context.space_data, "filter_text", icon='VIEWZOOM')
-
         col.separator()
-
         display_keymaps = keyconfig_utils.keyconfig_merge(kc, kc)
-        if context.space_data.filter_text != "":
-            filter_text = context.space_data.filter_text.lower()
-            self.draw_filtered(display_keymaps, filter_text, col)
+        filter_type = spref.filter_type
+        filter_text = spref.filter_text
+        if filter_text != "":
+            filter_text = filter_text.lower()
+            ok = self.draw_filtered(display_keymaps, filter_type, filter_text, col)
         else:
             self.draw_hierarchy(display_keymaps, col)
+            ok = True
 
+        # go back and fill in rowsub
+        rowsub.prop(spref, "filter_type", text="")
+        rowsubsub = rowsub.row(align=True)
+        if not ok:
+	        rowsubsub.alert = True
+        rowsubsub.prop(spref, "filter_text", text="", icon='VIEWZOOM')
 
+
 if __name__ == "__main__":  # only for live edit.
     bpy.utils.register_module(__name__)

Modified: trunk/blender/source/blender/makesdna/DNA_space_types.h
===================================================================
--- trunk/blender/source/blender/makesdna/DNA_space_types.h	2013-03-01 00:35:01 UTC (rev 54950)
+++ trunk/blender/source/blender/makesdna/DNA_space_types.h	2013-03-01 06:17:59 UTC (rev 54951)
@@ -1004,8 +1004,8 @@
 	ListBase regionbase;        /* storage of regions for inactive spaces */
 	int spacetype;
 	
-	int pad;
-	
+	char pad[3];
+	char filter_type;
 	char filter[64];        /* search term for filtering in the UI */
 } SpaceUserPref;
 

Modified: trunk/blender/source/blender/makesrna/intern/rna_space.c
===================================================================
--- trunk/blender/source/blender/makesrna/intern/rna_space.c	2013-03-01 00:35:01 UTC (rev 54950)
+++ trunk/blender/source/blender/makesrna/intern/rna_space.c	2013-03-01 06:17:59 UTC (rev 54951)
@@ -3054,13 +3054,24 @@
 
 static void rna_def_space_userpref(BlenderRNA *brna)
 {
+	static EnumPropertyItem filter_type_items[] = {
+	    {0,     "NAME",     0,      "Name",        "Filter based on the operator name"},
+	    {1,     "KEY",      0,      "Key-Binding", "Filter based on key bindings"},
+	    {0, NULL, 0, NULL, NULL}};
+
 	StructRNA *srna;
 	PropertyRNA *prop;
 	
 	srna = RNA_def_struct(brna, "SpaceUserPreferences", "Space");
 	RNA_def_struct_sdna(srna, "SpaceUserPref");
 	RNA_def_struct_ui_text(srna, "Space User Preferences", "User preferences space data");
-	
+
+	prop = RNA_def_property(srna, "filter_type", PROP_ENUM, PROP_NONE);
+	RNA_def_property_enum_sdna(prop, NULL, "filter_type");
+	RNA_def_property_enum_items(prop, filter_type_items);
+	RNA_def_property_ui_text(prop, "Filter Type", "Filter method");
+	RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NODE, NULL);
+
 	prop = RNA_def_property(srna, "filter_text", PROP_STRING, PROP_NONE);
 	RNA_def_property_string_sdna(prop, NULL, "filter");
 	RNA_def_property_ui_text(prop, "Filter", "Search term for filtering in the UI");




More information about the Bf-blender-cvs mailing list