KEYMAP REFACTORING
authorBrecht Van Lommel <brechtvanlommel@pandora.be>
Fri, 5 Aug 2011 20:45:26 +0000 (20:45 +0000)
committerBrecht Van Lommel <brechtvanlommel@pandora.be>
Fri, 5 Aug 2011 20:45:26 +0000 (20:45 +0000)
Diff Keymaps

User edited keymaps now no longer override the builtin keymaps entirely, but
rather save only the difference and reapply those changes. This means they can
stay better in sync when the builtin keymaps change. The diff/patch algorithm
is not perfect, but better for the common case where only a few items are changed
rather than entire keymaps The main weakness is that if a builtin keymap item
changes, user modification of that item may need to be redone in some cases.

Keymap Editor

The most noticeable change here is that there is no longer an "Edit" button for
keymaps, all are editable immediately, but a "Restore" buttons shows for keymaps
and items that have been edited. Shortcuts for addons can also be edited in the
keymap editor.

Addons

Addons now should only modify the new addon keyconfiguration, the keymap items
there will be added to the builtin ones for handling events, and not get lost
when starting new files. Example code of register/unregister:

km = wm.keyconfigs.addon.keymaps.new("3D View", space_type="VIEW_3D")
km.keymap_items.new('my.operator', 'ESC', 'PRESS')

km = wm.keyconfigs.addon.keymaps["3D View"]
km.keymap_items.remove(km.keymap_items["my.operator"])

Compatibility

The changes made are not forward compatible, i.e. if you save user preferences
with newer versions, older versions will not have key configuration changes that
were made.

20 files changed:
release/scripts/startup/bl_ui/space_userpref_keymap.py
source/blender/blenkernel/intern/blender.c
source/blender/blenloader/intern/readfile.c
source/blender/blenloader/intern/writefile.c
source/blender/editors/interface/interface_handlers.c
source/blender/editors/interface/resources.c
source/blender/makesdna/DNA_userdef_types.h
source/blender/makesdna/DNA_windowmanager_types.h
source/blender/makesrna/intern/rna_internal.h
source/blender/makesrna/intern/rna_scene.c
source/blender/makesrna/intern/rna_userdef.c
source/blender/makesrna/intern/rna_wm.c
source/blender/makesrna/intern/rna_wm_api.c
source/blender/windowmanager/WM_api.h
source/blender/windowmanager/WM_keymap.h [new file with mode: 0644]
source/blender/windowmanager/intern/wm.c
source/blender/windowmanager/intern/wm_event_system.c
source/blender/windowmanager/intern/wm_files.c
source/blender/windowmanager/intern/wm_keymap.c
source/blenderplayer/bad_level_call_stubs/stubs.c

index 585c3cf..5658cc9 100644 (file)
@@ -188,10 +188,10 @@ class InputKeyMapPanel:
 
         if km.is_modal:
             row.label(text="", icon='LINKED')
-        if km.is_user_defined:
+        if km.is_user_modified:
             row.operator("wm.keymap_restore", text="Restore")
         else:
-            row.operator("wm.keymap_edit", text="Edit")
+            row.label()
 
         if km.show_expanded_children:
             if children:
@@ -212,7 +212,6 @@ class InputKeyMapPanel:
                 # "Add New" at end of keymap item list
                 col = self.indented_layout(col, level + 1)
                 subcol = col.split(percentage=0.2).column()
-                subcol.enabled = km.is_user_defined
                 subcol.operator("wm.keyitem_add", text="Add New", icon='ZOOMIN')
 
             col.separator()
@@ -243,7 +242,7 @@ class InputKeyMapPanel:
 
         col = self.indented_layout(layout, level)
 
-        if km.is_user_defined:
+        if kmi.show_expanded:
             col = col.column(align=True)
             box = col.box()
         else:
@@ -256,7 +255,6 @@ class InputKeyMapPanel:
         row.prop(kmi, "show_expanded", text="", emboss=False)
 
         row = split.row()
-        row.enabled = km.is_user_defined
         row.prop(kmi, "active", text="", emboss=False)
 
         if km.is_modal:
@@ -265,7 +263,6 @@ class InputKeyMapPanel:
             row.label(text=kmi.name)
 
         row = split.row()
-        row.enabled = km.is_user_defined
         row.prop(kmi, "map_type", text="")
         if map_type == 'KEYBOARD':
             row.prop(kmi, "type", text="", full_event=True)
@@ -282,18 +279,17 @@ class InputKeyMapPanel:
         else:
             row.label()
 
-        if not kmi.is_user_defined:
+        if (not kmi.is_user_defined) and kmi.is_user_modified:
             op = row.operator("wm.keyitem_restore", text="", icon='BACK')
             op.item_id = kmi.id
-        op = row.operator("wm.keyitem_remove", text="", icon='X')
-        op.item_id = kmi.id
+        else:
+            op = row.operator("wm.keyitem_remove", text="", icon='X')
+            op.item_id = kmi.id
 
         # Expanded, additional event settings
         if kmi.show_expanded:
             box = col.box()
 
-            box.enabled = km.is_user_defined
-
             if map_type not in {'TEXTINPUT', 'TIMER'}:
                 split = box.split(percentage=0.4)
                 sub = split.row()
@@ -352,10 +348,10 @@ class InputKeyMapPanel:
                 row.label()
                 row.label()
 
-                if km.is_user_defined:
+                if km.is_user_modified:
                     row.operator("wm.keymap_restore", text="Restore")
                 else:
-                    row.operator("wm.keymap_edit", text="Edit")
+                    row.label()
 
                 for kmi in filtered_items:
                     self.draw_kmi(display_keymaps, kc, km, kmi, col, 1)
@@ -363,7 +359,6 @@ class InputKeyMapPanel:
                 # "Add New" at end of keymap item list
                 col = self.indented_layout(layout, 1)
                 subcol = col.split(percentage=0.2).column()
-                subcol.enabled = km.is_user_defined
                 subcol.operator("wm.keyitem_add", text="Add New", icon='ZOOMIN')
 
     def draw_hierarchy(self, display_keymaps, layout):
@@ -372,8 +367,7 @@ class InputKeyMapPanel:
 
     def draw_keymaps(self, context, layout):
         wm = context.window_manager
-        kc = wm.keyconfigs.active
-        defkc = wm.keyconfigs.default
+        kc = wm.keyconfigs.user
 
         col = layout.column()
         sub = col.column()
@@ -398,7 +392,7 @@ class InputKeyMapPanel:
 
         col.separator()
 
-        display_keymaps = _merge_keymaps(kc, defkc)
+        display_keymaps = _merge_keymaps(kc, kc)
         if context.space_data.filter_text != "":
             filter_text = context.space_data.filter_text.lower()
             self.draw_filtered(display_keymaps, filter_text, col)
@@ -609,7 +603,7 @@ class WM_OT_keyconfig_export(bpy.types.Operator):
 
         # Generate a list of keymaps to export:
         #
-        # First add all user_defined keymaps (found in inputs.edited_keymaps list),
+        # First add all user_modified keymaps (found in keyconfigs.user.keymaps list),
         # then add all remaining keymaps from the currently active custom keyconfig.
         #
         # This will create a final list of keymaps that can be used as a 'diff' against
@@ -619,7 +613,9 @@ class WM_OT_keyconfig_export(bpy.types.Operator):
         class FakeKeyConfig():
             keymaps = []
         edited_kc = FakeKeyConfig()
-        edited_kc.keymaps.extend(context.user_preferences.inputs.edited_keymaps)
+        for km in wm.keyconfigs.user.keymaps:
+            if km.is_user_modified:
+                edited_kc.keymaps.append(km)
         # merge edited keymaps with non-default keyconfig, if it exists
         if kc != wm.keyconfigs.default:
             export_keymaps = _merge_keymaps(edited_kc, kc)
@@ -669,17 +665,6 @@ class WM_OT_keyconfig_export(bpy.types.Operator):
         return {'RUNNING_MODAL'}
 
 
-class WM_OT_keymap_edit(bpy.types.Operator):
-    "Edit stored key map"
-    bl_idname = "wm.keymap_edit"
-    bl_label = "Edit Key Map"
-
-    def execute(self, context):
-        km = context.keymap
-        km.copy_to_user()
-        return {'FINISHED'}
-
-
 class WM_OT_keymap_restore(bpy.types.Operator):
     "Restore key map(s)"
     bl_idname = "wm.keymap_restore"
@@ -691,7 +676,7 @@ class WM_OT_keymap_restore(bpy.types.Operator):
         wm = context.window_manager
 
         if self.all:
-            for km in wm.keyconfigs.default.keymaps:
+            for km in wm.keyconfigs.user.keymaps:
                 km.restore_to_default()
         else:
             km = context.keymap
@@ -710,13 +695,13 @@ class WM_OT_keyitem_restore(bpy.types.Operator):
     @classmethod
     def poll(cls, context):
         keymap = getattr(context, "keymap", None)
-        return keymap and keymap.is_user_defined
+        return keymap
 
     def execute(self, context):
         km = context.keymap
         kmi = km.keymap_items.from_id(self.item_id)
 
-        if not kmi.is_user_defined:
+        if (not kmi.is_user_defined) and kmi.is_user_modified:
             km.restore_item_to_default(kmi)
 
         return {'FINISHED'}
@@ -753,7 +738,7 @@ class WM_OT_keyitem_remove(bpy.types.Operator):
 
     @classmethod
     def poll(cls, context):
-        return hasattr(context, "keymap") and context.keymap.is_user_defined
+        return hasattr(context, "keymap")
 
     def execute(self, context):
         km = context.keymap
index 8b4bbbd..7e2097d 100644 (file)
@@ -330,28 +330,45 @@ static int handle_subversion_warning(Main *main)
        return 1;
 }
 
+static void keymap_item_free(wmKeyMapItem *kmi)
+{
+       if(kmi->properties) {
+               IDP_FreeProperty(kmi->properties);
+               MEM_freeN(kmi->properties);
+       }
+       if(kmi->ptr)
+               MEM_freeN(kmi->ptr);
+}
+
 void BKE_userdef_free(void)
 {
        wmKeyMap *km;
        wmKeyMapItem *kmi;
+       wmKeyMapDiffItem *kmdi;
 
-       for(km=U.keymaps.first; km; km=km->next) {
-               for(kmi=km->items.first; kmi; kmi=kmi->next) {
-                       if(kmi->properties) {
-                               IDP_FreeProperty(kmi->properties);
-                               MEM_freeN(kmi->properties);
+       for(km=U.user_keymaps.first; km; km=km->next) {
+               for(kmdi=km->diff_items.first; kmdi; kmdi=kmdi->next) {
+                       if(kmdi->add_item) {
+                               keymap_item_free(kmdi->add_item);
+                               MEM_freeN(kmdi->add_item);
+                       }
+                       if(kmdi->remove_item) {
+                               keymap_item_free(kmdi->remove_item);
+                               MEM_freeN(kmdi->remove_item);
                        }
-                       if(kmi->ptr)
-                               MEM_freeN(kmi->ptr);
                }
 
+               for(kmi=km->items.first; kmi; kmi=kmi->next)
+                       keymap_item_free(kmi);
+
+               BLI_freelistN(&km->diff_items);
                BLI_freelistN(&km->items);
        }
        
        BLI_freelistN(&U.uistyles);
        BLI_freelistN(&U.uifonts);
        BLI_freelistN(&U.themes);
-       BLI_freelistN(&U.keymaps);
+       BLI_freelistN(&U.user_keymaps);
        BLI_freelistN(&U.addons);
 }
 
index 44c8ca9..bd12677 100644 (file)
@@ -4726,6 +4726,8 @@ static void direct_link_windowmanager(FileData *fd, wmWindowManager *wm)
 
        wm->keyconfigs.first= wm->keyconfigs.last= NULL;
        wm->defaultconf= NULL;
+       wm->addonconf= NULL;
+       wm->userconf= NULL;
 
        wm->jobs.first= wm->jobs.last= NULL;
        wm->drags.first= wm->drags.last= NULL;
@@ -11762,33 +11764,57 @@ static void lib_link_all(FileData *fd, Main *main)
        lib_link_library(fd, main);             /* only init users */
 }
 
+static void direct_link_keymapitem(FileData *fd, wmKeyMapItem *kmi)
+{
+       kmi->properties= newdataadr(fd, kmi->properties);
+       if(kmi->properties)
+               IDP_DirectLinkProperty(kmi->properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+       kmi->ptr= NULL;
+       kmi->flag &= ~KMI_UPDATE;
+}
 
 static BHead *read_userdef(BlendFileData *bfd, FileData *fd, BHead *bhead)
 {
        UserDef *user;
        wmKeyMap *keymap;
        wmKeyMapItem *kmi;
+       wmKeyMapDiffItem *kmdi;
 
        bfd->user= user= read_struct(fd, bhead, "user def");
 
        /* read all data into fd->datamap */
        bhead= read_data_into_oldnewmap(fd, bhead, "user def");
 
+       if(user->keymaps.first) {
+               /* backwards compatibility */
+               user->user_keymaps= user->keymaps;
+               user->keymaps.first= user->keymaps.last= NULL;
+       }
+
        link_list(fd, &user->themes);
-       link_list(fd, &user->keymaps);
+       link_list(fd, &user->user_keymaps);
        link_list(fd, &user->addons);
 
-       for(keymap=user->keymaps.first; keymap; keymap=keymap->next) {
+       for(keymap=user->user_keymaps.first; keymap; keymap=keymap->next) {
                keymap->modal_items= NULL;
                keymap->poll= NULL;
+               keymap->flag &= ~KEYMAP_UPDATE;
 
+               link_list(fd, &keymap->diff_items);
                link_list(fd, &keymap->items);
-               for(kmi=keymap->items.first; kmi; kmi=kmi->next) {
-                       kmi->properties= newdataadr(fd, kmi->properties);
-                       if(kmi->properties)
-                               IDP_DirectLinkProperty(kmi->properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
-                       kmi->ptr= NULL;
+               
+               for(kmdi=keymap->diff_items.first; kmdi; kmdi=kmdi->next) {
+                       kmdi->remove_item= newdataadr(fd, kmdi->remove_item);
+                       kmdi->add_item= newdataadr(fd, kmdi->add_item);
+
+                       if(kmdi->remove_item)
+                               direct_link_keymapitem(fd, kmdi->remove_item);
+                       if(kmdi->add_item)
+                               direct_link_keymapitem(fd, kmdi->add_item);
                }
+
+               for(kmi=keymap->items.first; kmi; kmi=kmi->next)
+                       direct_link_keymapitem(fd, kmi);
        }
 
        // XXX
index bf86527..7d65248 100644 (file)
@@ -717,11 +717,19 @@ static void write_renderinfo(WriteData *wd, Main *mainvar)                /* for renderdeamon
        }
 }
 
+static void write_keymapitem(WriteData *wd, wmKeyMapItem *kmi)
+{
+       writestruct(wd, DATA, "wmKeyMapItem", 1, kmi);
+       if(kmi->properties)
+               IDP_WriteProperty(kmi->properties, wd);
+}
+
 static void write_userdef(WriteData *wd)
 {
        bTheme *btheme;
        wmKeyMap *keymap;
        wmKeyMapItem *kmi;
+       wmKeyMapDiffItem *kmdi;
        bAddon *bext;
        uiStyle *style;
        
@@ -730,15 +738,19 @@ static void write_userdef(WriteData *wd)
        for(btheme= U.themes.first; btheme; btheme=btheme->next)
                writestruct(wd, DATA, "bTheme", 1, btheme);
 
-       for(keymap= U.keymaps.first; keymap; keymap=keymap->next) {
+       for(keymap= U.user_keymaps.first; keymap; keymap=keymap->next) {
                writestruct(wd, DATA, "wmKeyMap", 1, keymap);
 
-               for(kmi=keymap->items.first; kmi; kmi=kmi->next) {
-                       writestruct(wd, DATA, "wmKeyMapItem", 1, kmi);
-
-                       if(kmi->properties)
-                               IDP_WriteProperty(kmi->properties, wd);
+               for(kmdi=keymap->diff_items.first; kmdi; kmdi=kmdi->next) {
+                       writestruct(wd, DATA, "wmKeyMapDiffItem", 1, kmdi);
+                       if(kmdi->remove_item)
+                               write_keymapitem(wd, kmdi->remove_item);
+                       if(kmdi->add_item)
+                               write_keymapitem(wd, kmdi->add_item);
                }
+
+               for(kmi=keymap->items.first; kmi; kmi=kmi->next)
+                       write_keymapitem(wd, kmi);
        }
 
        for(bext= U.addons.first; bext; bext=bext->next)
index b3272a2..d8d8354 100644 (file)
@@ -4067,7 +4067,6 @@ static void but_shortcut_name_func(bContext *C, void *arg1, int UNUSED(event))
                
                /* complex code to change name of button */
                if(WM_key_event_operator_string(C, but->optype->idname, but->opcontext, prop, buf, sizeof(buf))) {
-                       wmKeyMap *km= NULL;
                        char *butstr_orig;
 
                        // XXX but->str changed... should not, remove the hotkey from it
@@ -4080,10 +4079,6 @@ static void but_shortcut_name_func(bContext *C, void *arg1, int UNUSED(event))
                        but->str= but->strdata;
 
                        ui_check_but(but);
-
-                       /* set the keymap editable else the key wont save */
-                       WM_key_event_operator_id(C, but->optype->idname, but->opcontext, prop, 1, &km);
-                       WM_keymap_copy_to_user(km);
                }
                else {
                        /* shortcut was removed */
@@ -4095,6 +4090,7 @@ static void but_shortcut_name_func(bContext *C, void *arg1, int UNUSED(event))
 
 static uiBlock *menu_change_shortcut(bContext *C, ARegion *ar, void *arg)
 {
+       wmWindowManager *wm= CTX_wm_manager(C);
        uiBlock *block;
        uiBut *but = (uiBut *)arg;
        wmKeyMap *km;
@@ -4107,7 +4103,7 @@ static uiBlock *menu_change_shortcut(bContext *C, ARegion *ar, void *arg)
 
        kmi = WM_keymap_item_find_id(km, kmi_id);
        
-       RNA_pointer_create(NULL, &RNA_KeyMapItem, kmi, &ptr);
+       RNA_pointer_create(&wm->id, &RNA_KeyMapItem, kmi, &ptr);
        
        block= uiBeginBlock(C, ar, "_popup", UI_EMBOSS);
        uiBlockSetHandleFunc(block, but_shortcut_name_func, but);
@@ -4126,6 +4122,7 @@ static uiBlock *menu_change_shortcut(bContext *C, ARegion *ar, void *arg)
 
 static uiBlock *menu_add_shortcut(bContext *C, ARegion *ar, void *arg)
 {
+       wmWindowManager *wm= CTX_wm_manager(C);
        uiBlock *block;
        uiBut *but = (uiBut *)arg;
        wmKeyMap *km;
@@ -4134,19 +4131,25 @@ static uiBlock *menu_add_shortcut(bContext *C, ARegion *ar, void *arg)
        uiLayout *layout;
        uiStyle *style= U.uistyles.first;
        IDProperty *prop= (but->opptr)? but->opptr->data: NULL;
+       int kmi_id;
        
        /* XXX this guess_opname can potentially return a different keymap than being found on adding later... */
        km = WM_keymap_guess_opname(C, but->optype->idname);            
        kmi = WM_keymap_add_item(km, but->optype->idname, AKEY, KM_PRESS, 0, 0);
+       kmi_id = kmi->id;
 
-       if (prop) {
+       /* copy properties, prop can be NULL for reset */       
+       if(prop)
                prop= IDP_CopyProperty(prop);
-       }
-
-       /* prop can be NULL */  
        WM_keymap_properties_reset(kmi, prop);
 
-       RNA_pointer_create(NULL, &RNA_KeyMapItem, kmi, &ptr);
+       /* update and get pointers again */
+       WM_keyconfig_update(wm);
+
+       km = WM_keymap_guess_opname(C, but->optype->idname);            
+       kmi = WM_keymap_item_find_id(km, kmi_id);
+
+       RNA_pointer_create(&wm->id, &RNA_KeyMapItem, kmi, &ptr);
 
        block= uiBeginBlock(C, ar, "_popup", UI_EMBOSS);
        uiBlockSetHandleFunc(block, but_shortcut_name_func, but);
index 32e87b3..f3db6ad 100644 (file)
@@ -1425,7 +1425,7 @@ void init_userdef_do_versions(void)
        if (bmain->versionfile < 250 || (bmain->versionfile == 250 && bmain->subversionfile < 8)) {
                wmKeyMap *km;
                
-               for(km=U.keymaps.first; km; km=km->next) {
+               for(km=U.user_keymaps.first; km; km=km->next) {
                        if (strcmp(km->idname, "Armature_Sketch")==0)
                                strcpy(km->idname, "Armature Sketch");
                        else if (strcmp(km->idname, "View3D")==0)
index aa6da3a..a555a19 100644 (file)
@@ -341,7 +341,8 @@ typedef struct UserDef {
        struct ListBase themes;
        struct ListBase uifonts;
        struct ListBase uistyles;
-       struct ListBase keymaps;
+       struct ListBase keymaps;                /* deprecated in favor of user_keymaps */
+       struct ListBase user_keymaps;
        struct ListBase addons;
        char keyconfigstr[64];
        
index 31e59f1..1f0ae28 100644 (file)
@@ -144,7 +144,9 @@ typedef struct wmWindowManager {
        ListBase drags;                 /* active dragged items */
        
        ListBase keyconfigs;                            /* known key configurations */
-       struct wmKeyConfig *defaultconf;        /* default configuration, not saved */
+       struct wmKeyConfig *defaultconf;        /* default configuration */
+       struct wmKeyConfig *addonconf;          /* addon configuration */
+       struct wmKeyConfig *userconf;           /* user configuration */
 
        ListBase timers;                                        /* active timers */
        struct wmTimer *autosavetimer;          /* timer for auto save */
@@ -239,15 +241,26 @@ typedef struct wmKeyMapItem {
        struct PointerRNA *ptr;                 /* rna pointer to access properties */
 } wmKeyMapItem;
 
+/* used instead of wmKeyMapItem for diff keymaps */
+typedef struct wmKeyMapDiffItem {
+       struct wmKeyMapDiffItem *next, *prev;
+
+       wmKeyMapItem *remove_item;
+       wmKeyMapItem *add_item;
+} wmKeyMapDiffItem;
+
 /* wmKeyMapItem.flag */
-#define KMI_INACTIVE   1
-#define KMI_EXPANDED   2
+#define KMI_INACTIVE           1
+#define KMI_EXPANDED           2
+#define KMI_USER_MODIFIED      4
+#define KMI_UPDATE                     8
 
 /* stored in WM, the actively used keymaps */
 typedef struct wmKeyMap {
        struct wmKeyMap *next, *prev;
        
        ListBase items;
+       ListBase diff_items;
        
        char idname[64];        /* global editor keymaps, or for more per space/region */
        short spaceid;          /* same IDs as in DNA_space_types.h */
@@ -263,9 +276,12 @@ typedef struct wmKeyMap {
 
 /* wmKeyMap.flag */
 #define KEYMAP_MODAL                           1       /* modal map, not using operatornames */
-#define KEYMAP_USER                                    2       /* user created keymap */
+#define KEYMAP_USER                                    2       /* user keymap */
 #define KEYMAP_EXPANDED                                4
 #define KEYMAP_CHILDREN_EXPANDED       8
+#define KEYMAP_DIFF                                    16      /* diff keymap for user preferences */
+#define KEYMAP_USER_MODIFIED           32      /* keymap has user modifications */
+#define KEYMAP_UPDATE                          64
 
 typedef struct wmKeyConfig {
        struct wmKeyConfig *next, *prev;
index 9175806..c0ae7b0 100644 (file)
@@ -238,9 +238,12 @@ void RNA_api_image(struct StructRNA *srna);
 void RNA_api_operator(struct StructRNA *srna);
 void RNA_api_macro(struct StructRNA *srna);
 void RNA_api_keyconfig(struct StructRNA *srna);
+void RNA_api_keyconfigs(struct StructRNA *srna);
 void RNA_api_keyingset(struct StructRNA *srna);
 void RNA_api_keymap(struct StructRNA *srna);
+void RNA_api_keymaps(struct StructRNA *srna);
 void RNA_api_keymapitem(struct StructRNA *srna);
+void RNA_api_keymapitems(struct StructRNA *srna);
 void RNA_api_area(struct StructRNA *srna);
 void RNA_api_main(struct StructRNA *srna);
 void RNA_api_material(StructRNA *srna);
index b3d8bc8..29cfc69 100644 (file)
@@ -1409,7 +1409,7 @@ void rna_def_render_layer_common(StructRNA *srna, int scene)
        prop= RNA_def_property(srna, "layers_zmask", PROP_BOOLEAN, PROP_LAYER);
        RNA_def_property_boolean_sdna(prop, NULL, "lay_zmask", 1);
        RNA_def_property_array(prop, 20);
-       RNA_def_property_ui_text(prop, "Zmask Layers", "Zmask scene layers");
+       RNA_def_property_ui_text(prop, "Zmask Layers", "Zmask scene layers for solid faces");
        if(scene) RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, NULL);
        else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
 
index a1a99c3..b3dbafe 100644 (file)
@@ -2795,12 +2795,6 @@ static void rna_def_userdef_input(BlenderRNA *brna)
        RNA_def_property_range(prop, 0, 32);
        RNA_def_property_ui_text(prop, "Wheel Scroll Lines", "The number of lines scrolled at a time with the mouse wheel");
        
-       /* U.keymaps - custom keymaps that have been edited from default configs */
-       prop= RNA_def_property(srna, "edited_keymaps", PROP_COLLECTION, PROP_NONE);
-       RNA_def_property_collection_sdna(prop, NULL, "keymaps", NULL);
-       RNA_def_property_struct_type(prop, "KeyMap");
-       RNA_def_property_ui_text(prop, "Edited Keymaps", "");
-       
        prop= RNA_def_property(srna, "active_keyconfig", PROP_STRING, PROP_DIRPATH);
        RNA_def_property_string_sdna(prop, NULL, "keyconfigstr");
        RNA_def_property_ui_text(prop, "Key Config", "The name of the active key configuration");
index a046be5..307cf0e 100644 (file)
@@ -578,22 +578,6 @@ static EnumPropertyItem *rna_KeyMapItem_propvalue_itemf(bContext *C, PointerRNA
        wmKeyConfig *kc;
        wmKeyMap *km;
 
-       /* check user keymaps */
-       for(km=U.keymaps.first; km; km=km->next) {
-               wmKeyMapItem *kmi;
-               for (kmi=km->items.first; kmi; kmi=kmi->next) {
-                       if (kmi == ptr->data) {
-                               if (!km->modal_items) {
-                                       if (!WM_keymap_user_init(wm, km)) {
-                                               return keymap_propvalue_items; /* ERROR */
-                                       }
-                               }
-
-                               return km->modal_items;
-                       }
-               }
-       }
-
        for(kc=wm->keyconfigs.first; kc; kc=kc->next) {
                for(km=kc->keymaps.first; km; km=km->next) {
                        /* only check if it's a modal keymap */
@@ -654,12 +638,13 @@ static PointerRNA rna_WindowManager_active_keyconfig_get(PointerRNA *ptr)
        return rna_pointer_inherit_refine(ptr, &RNA_KeyConfig, kc);
 }
 
-static void rna_WindowManager_active_keyconfig_set(PointerRNA *UNUSED(ptr), PointerRNA value)
+static void rna_WindowManager_active_keyconfig_set(PointerRNA *ptr, PointerRNA value)
 {
+       wmWindowManager *wm= ptr->data;
        wmKeyConfig *kc= value.data;
 
        if(kc)
-               BLI_strncpy(U.keyconfigstr, kc->idname, sizeof(U.keyconfigstr));
+               WM_keyconfig_set_active(wm, kc->idname);
 }
 
 static void rna_wmKeyMapItem_idname_get(PointerRNA *ptr, char *value)
@@ -1130,93 +1115,6 @@ static StructRNA* rna_MacroOperator_refine(PointerRNA *opr)
        return (op->type && op->type->ext.srna)? op->type->ext.srna: &RNA_Macro;
 }
 
-static wmKeyMapItem *rna_KeyMap_item_new(wmKeyMap *km, ReportList *reports, const char *idname, int type, int value, int any, int shift, int ctrl, int alt, int oskey, int keymodifier)
-{
-//     wmWindowManager *wm = CTX_wm_manager(C);
-       char idname_bl[OP_MAX_TYPENAME];
-       int modifier= 0;
-
-       /* only on non-modal maps */
-       if (km->flag & KEYMAP_MODAL) {
-               BKE_report(reports, RPT_ERROR, "Not a non-modal keymap.");
-               return NULL;
-       }
-
-       WM_operator_bl_idname(idname_bl, idname);
-
-       if(shift) modifier |= KM_SHIFT;
-       if(ctrl) modifier |= KM_CTRL;
-       if(alt) modifier |= KM_ALT;
-       if(oskey) modifier |= KM_OSKEY;
-
-       if(any) modifier = KM_ANY;
-
-       return WM_keymap_add_item(km, idname_bl, type, value, modifier, keymodifier);
-}
-
-static wmKeyMapItem *rna_KeyMap_item_new_modal(wmKeyMap *km, bContext *C, ReportList *reports, const char *propvalue_str, int type, int value, int any, int shift, int ctrl, int alt, int oskey, int keymodifier)
-{
-       wmWindowManager *wm = CTX_wm_manager(C);
-       int modifier= 0;
-       int propvalue = 0;
-
-       /* only modal maps */
-       if ((km->flag & KEYMAP_MODAL) == 0) {
-               BKE_report(reports, RPT_ERROR, "Not a modal keymap.");
-               return NULL;
-       }
-
-       if (!km->modal_items) {
-               if(!WM_keymap_user_init(wm, km)) {
-                       BKE_report(reports, RPT_ERROR, "User defined keymap doesn't correspond to a system keymap.");
-                       return NULL;
-               }
-       }
-
-       if (!km->modal_items) {
-               BKE_report(reports, RPT_ERROR, "No property values defined.");
-               return NULL;
-       }
-
-
-       if(RNA_enum_value_from_id(km->modal_items, propvalue_str, &propvalue)==0) {
-               BKE_report(reports, RPT_WARNING, "Property value not in enumeration.");
-       }
-
-       if(shift) modifier |= KM_SHIFT;
-       if(ctrl) modifier |= KM_CTRL;
-       if(alt) modifier |= KM_ALT;
-       if(oskey) modifier |= KM_OSKEY;
-
-       if(any) modifier = KM_ANY;
-
-       return WM_modalkeymap_add_item(km, type, value, modifier, keymodifier, propvalue);
-}
-
-static wmKeyMap *rna_keymap_new(wmKeyConfig *keyconf, const char *idname, int spaceid, int regionid, int modal)
-{
-       if (modal == 0) {
-               return WM_keymap_find(keyconf, idname, spaceid, regionid);
-       } else {
-               return WM_modalkeymap_add(keyconf, idname, NULL); /* items will be lazy init */
-       }
-}
-
-static wmKeyMap *rna_keymap_find(wmKeyConfig *keyconf, const char *idname, int spaceid, int regionid)
-{
-       return WM_keymap_list_find(&keyconf->keymaps, idname, spaceid, regionid);
-}
-
-static wmKeyMap *rna_keymap_find_modal(wmKeyConfig *UNUSED(keyconf), const char *idname)
-{
-       wmOperatorType *ot = WM_operatortype_find(idname, 0);
-
-       if (!ot)
-               return NULL;
-       else
-               return ot->modalkeymap;
-}
-
 /* just to work around 'const char *' warning and to ensure this is a python op */
 static void rna_Operator_bl_idname_set(PointerRNA *ptr, const char *value)
 {
@@ -1242,6 +1140,12 @@ static void rna_Operator_bl_description_set(PointerRNA *ptr, const char *value)
        else            assert(!"setting the bl_description on a non-builtin operator");
 }
 
+static void rna_KeyMapItem_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+       wmKeyMapItem *kmi= ptr->data;
+       WM_keyconfig_update_tag(NULL, kmi);
+}
+
 #else /* RNA_RUNTIME */
 
 static void rna_def_operator(BlenderRNA *brna)
@@ -1566,9 +1470,6 @@ static void rna_def_wm_keyconfigs(BlenderRNA *brna, PropertyRNA *cprop)
        StructRNA *srna;
        PropertyRNA *prop;
 
-       FunctionRNA *func;
-       PropertyRNA *parm;
-
        RNA_def_property_srna(cprop, "KeyConfigurations");
        srna= RNA_def_struct(brna, "KeyConfigurations", NULL);
        RNA_def_struct_sdna(srna, "wmWindowManager");
@@ -1578,23 +1479,24 @@ static void rna_def_wm_keyconfigs(BlenderRNA *brna, PropertyRNA *cprop)
        RNA_def_property_struct_type(prop, "KeyConfig");
        RNA_def_property_pointer_funcs(prop, "rna_WindowManager_active_keyconfig_get", "rna_WindowManager_active_keyconfig_set", NULL, NULL);
        RNA_def_property_flag(prop, PROP_EDITABLE);
-       RNA_def_property_ui_text(prop, "Active KeyConfig", "Active wm KeyConfig");
+       RNA_def_property_ui_text(prop, "Active KeyConfig", "Active key configuration (preset)");
        
        prop= RNA_def_property(srna, "default", PROP_POINTER, PROP_NEVER_NULL);
        RNA_def_property_pointer_sdna(prop, NULL, "defaultconf");
        RNA_def_property_struct_type(prop, "KeyConfig");
-       RNA_def_property_ui_text(prop, "Default Key Configuration", "");
+       RNA_def_property_ui_text(prop, "Default Key Configuration", "Default builtin key configuration");
+
+       prop= RNA_def_property(srna, "addon", PROP_POINTER, PROP_NEVER_NULL);
+       RNA_def_property_pointer_sdna(prop, NULL, "addonconf");
+       RNA_def_property_struct_type(prop, "KeyConfig");
+       RNA_def_property_ui_text(prop, "Addon Key Configuration", "Key configuration that can be extended by addons, and is added to the active configuration when handling events");
+
+       prop= RNA_def_property(srna, "user", PROP_POINTER, PROP_NEVER_NULL);
+       RNA_def_property_pointer_sdna(prop, NULL, "userconf");
+       RNA_def_property_struct_type(prop, "KeyConfig");
+       RNA_def_property_ui_text(prop, "User Key Configuration", "Final key configuration that combines keymaps from the active and addon configurations, and can be edited by the user");
        
-       /* funcs */
-       func= RNA_def_function(srna, "new", "WM_keyconfig_new_user"); // add_keyconfig
-       parm= RNA_def_string(func, "name", "", 0, "Name", "");
-       RNA_def_property_flag(parm, PROP_REQUIRED);
-       parm= RNA_def_pointer(func, "keyconfig", "KeyConfig", "Key Configuration", "Added key configuration.");
-       RNA_def_function_return(func, parm);
-
-       func= RNA_def_function(srna, "remove", "WM_keyconfig_remove"); // remove_keyconfig
-       parm= RNA_def_pointer(func, "keyconfig", "KeyConfig", "Key Configuration", "Removed key configuration.");
-       RNA_def_property_flag(parm, PROP_REQUIRED);
+       RNA_api_keyconfigs(srna);
 }
 
 static void rna_def_windowmanager(BlenderRNA *brna)
@@ -1631,107 +1533,30 @@ static void rna_def_windowmanager(BlenderRNA *brna)
 static void rna_def_keymap_items(BlenderRNA *brna, PropertyRNA *cprop)
 {
        StructRNA *srna;
-//     PropertyRNA *prop;
-
-       FunctionRNA *func;
-       PropertyRNA *parm;
        
        RNA_def_property_srna(cprop, "KeyMapItems");
        srna= RNA_def_struct(brna, "KeyMapItems", NULL);
        RNA_def_struct_sdna(srna, "wmKeyMap");
        RNA_def_struct_ui_text(srna, "KeyMap Items", "Collection of keymap items");
 
-       func= RNA_def_function(srna, "new", "rna_KeyMap_item_new");
-       RNA_def_function_flag(func, FUNC_USE_REPORTS);
-       parm= RNA_def_string(func, "idname", "", 0, "Operator Identifier", "");
-       RNA_def_property_flag(parm, PROP_REQUIRED);
-       parm= RNA_def_enum(func, "type", event_type_items, 0, "Type", "");
-       RNA_def_property_flag(parm, PROP_REQUIRED);
-       parm= RNA_def_enum(func, "value", event_value_items, 0, "Value", "");
-       RNA_def_property_flag(parm, PROP_REQUIRED);
-       RNA_def_boolean(func, "any", 0, "Any", "");
-       RNA_def_boolean(func, "shift", 0, "Shift", "");
-       RNA_def_boolean(func, "ctrl", 0, "Ctrl", "");
-       RNA_def_boolean(func, "alt", 0, "Alt", "");
-       RNA_def_boolean(func, "oskey", 0, "OS Key", "");
-       RNA_def_enum(func, "key_modifier", event_type_items, 0, "Key Modifier", "");
-       parm= RNA_def_pointer(func, "item", "KeyMapItem", "Item", "Added key map item.");
-       RNA_def_function_return(func, parm);
-
-       func= RNA_def_function(srna, "new_modal", "rna_KeyMap_item_new_modal");
-       RNA_def_function_flag(func, FUNC_USE_CONTEXT|FUNC_USE_REPORTS);
-       parm= RNA_def_string(func, "propvalue", "", 0, "Property Value", "");
-       RNA_def_property_flag(parm, PROP_REQUIRED);
-       parm= RNA_def_enum(func, "type", event_type_items, 0, "Type", "");
-       RNA_def_property_flag(parm, PROP_REQUIRED);
-       parm= RNA_def_enum(func, "value", event_value_items, 0, "Value", "");
-       RNA_def_property_flag(parm, PROP_REQUIRED);
-       RNA_def_boolean(func, "any", 0, "Any", "");
-       RNA_def_boolean(func, "shift", 0, "Shift", "");
-       RNA_def_boolean(func, "ctrl", 0, "Ctrl", "");
-       RNA_def_boolean(func, "alt", 0, "Alt", "");
-       RNA_def_boolean(func, "oskey", 0, "OS Key", "");
-       RNA_def_enum(func, "key_modifier", event_type_items, 0, "Key Modifier", "");
-       parm= RNA_def_pointer(func, "item", "KeyMapItem", "Item", "Added key map item.");
-       RNA_def_function_return(func, parm);
-       
-       func= RNA_def_function(srna, "remove", "WM_keymap_remove_item");
-       parm= RNA_def_pointer(func, "item", "KeyMapItem", "Item", "");
-       RNA_def_property_flag(parm, PROP_REQUIRED);
-
-       func= RNA_def_function(srna, "from_id", "WM_keymap_item_find_id");
-       parm= RNA_def_property(func, "id", PROP_INT, PROP_NONE);
-       RNA_def_property_flag(parm, PROP_REQUIRED);
-       RNA_def_property_ui_text(parm, "id", "ID of the item");
-       parm= RNA_def_pointer(func, "item", "KeyMapItem", "Item", "");
-       RNA_def_function_return(func, parm);
-       
+       RNA_api_keymapitems(srna);
 }
 
 static void rna_def_wm_keymaps(BlenderRNA *brna, PropertyRNA *cprop)
 {
        StructRNA *srna;
-       //PropertyRNA *prop;
-
-       FunctionRNA *func;
-       PropertyRNA *parm;
-
 
        RNA_def_property_srna(cprop, "KeyMaps");
        srna= RNA_def_struct(brna, "KeyMaps", NULL);
        RNA_def_struct_sdna(srna, "wmKeyConfig");
        RNA_def_struct_ui_text(srna, "Key Maps", "Collection of keymaps");
 
-       func= RNA_def_function(srna, "new", "rna_keymap_new"); // add_keymap
-       parm= RNA_def_string(func, "name", "", 0, "Name", "");
-       RNA_def_property_flag(parm, PROP_REQUIRED);
-       RNA_def_enum(func, "space_type", space_type_items, SPACE_EMPTY, "Space Type", "");
-       RNA_def_enum(func, "region_type", region_type_items, RGN_TYPE_WINDOW, "Region Type", "");
-       RNA_def_boolean(func, "modal", 0, "Modal", "");
-       parm= RNA_def_pointer(func, "keymap", "KeyMap", "Key Map", "Added key map.");
-       RNA_def_function_return(func, parm);
-
-       func= RNA_def_function(srna, "find", "rna_keymap_find"); // find_keymap
-       parm= RNA_def_string(func, "name", "", 0, "Name", "");
-       RNA_def_property_flag(parm, PROP_REQUIRED);
-       RNA_def_enum(func, "space_type", space_type_items, SPACE_EMPTY, "Space Type", "");
-       RNA_def_enum(func, "region_type", region_type_items, RGN_TYPE_WINDOW, "Region Type", "");
-       parm= RNA_def_pointer(func, "keymap", "KeyMap", "Key Map", "Corresponding key map.");
-       RNA_def_function_return(func, parm);
-
-       func= RNA_def_function(srna, "find_modal", "rna_keymap_find_modal"); // find_keymap_modal
-       parm= RNA_def_string(func, "name", "", 0, "Operator Name", "");
-       RNA_def_property_flag(parm, PROP_REQUIRED);
-       parm= RNA_def_pointer(func, "keymap", "KeyMap", "Key Map", "Corresponding key map.");
-       RNA_def_function_return(func, parm);
-       
+       RNA_api_keymaps(srna);
 }
 
 static void rna_def_keyconfig(BlenderRNA *brna)
 {
        StructRNA *srna;
-       // FunctionRNA *func;
-       // PropertyRNA *parm;
        PropertyRNA *prop;
 
        static EnumPropertyItem map_type_items[] = {
@@ -1794,8 +1619,8 @@ static void rna_def_keyconfig(BlenderRNA *brna)
        RNA_def_property_ui_text(prop, "Items", "Items in the keymap, linking an operator to an input event");
        rna_def_keymap_items(brna, prop);
 
-       prop= RNA_def_property(srna, "is_user_defined", PROP_BOOLEAN, PROP_NEVER_NULL);
-       RNA_def_property_boolean_sdna(prop, NULL, "flag", KEYMAP_USER);
+       prop= RNA_def_property(srna, "is_user_modified", PROP_BOOLEAN, PROP_NEVER_NULL);
+       RNA_def_property_boolean_sdna(prop, NULL, "flag", KEYMAP_USER_MODIFIED);
        RNA_def_property_ui_text(prop, "User Defined", "Keymap is defined by the user");
 
        prop= RNA_def_property(srna, "is_modal", PROP_BOOLEAN, PROP_NONE);
@@ -1826,6 +1651,7 @@ static void rna_def_keyconfig(BlenderRNA *brna)
        RNA_def_property_ui_text(prop, "Identifier", "Identifier of operator to call on input event");
        RNA_def_property_string_funcs(prop, "rna_wmKeyMapItem_idname_get", "rna_wmKeyMapItem_idname_length", "rna_wmKeyMapItem_idname_set");
        RNA_def_struct_name_property(srna, prop);
+       RNA_def_property_update(prop, 0, "rna_KeyMapItem_update");
        
        prop= RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
        RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -1836,62 +1662,73 @@ static void rna_def_keyconfig(BlenderRNA *brna)
        RNA_def_property_struct_type(prop, "OperatorProperties");
        RNA_def_property_pointer_funcs(prop, "rna_KeyMapItem_properties_get", NULL, NULL, NULL);
        RNA_def_property_ui_text(prop, "Properties", "Properties to set when the operator is called");
+       RNA_def_property_update(prop, 0, "rna_KeyMapItem_update");
 
        prop= RNA_def_property(srna, "map_type", PROP_ENUM, PROP_NONE);
        RNA_def_property_enum_sdna(prop, NULL, "maptype");
        RNA_def_property_enum_items(prop, map_type_items);
        RNA_def_property_enum_funcs(prop, "rna_wmKeyMapItem_map_type_get", "rna_wmKeyMapItem_map_type_set", NULL);
        RNA_def_property_ui_text(prop, "Map Type", "Type of event mapping");
+       RNA_def_property_update(prop, 0, "rna_KeyMapItem_update");
 
        prop= RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
        RNA_def_property_enum_sdna(prop, NULL, "type");
        RNA_def_property_enum_items(prop, event_type_items);
        RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_KeyMapItem_type_itemf");
        RNA_def_property_ui_text(prop, "Type", "Type of event");
+       RNA_def_property_update(prop, 0, "rna_KeyMapItem_update");
 
        prop= RNA_def_property(srna, "value", PROP_ENUM, PROP_NONE);
        RNA_def_property_enum_sdna(prop, NULL, "val");
        RNA_def_property_enum_items(prop, event_value_items);
        RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_KeyMapItem_value_itemf");
        RNA_def_property_ui_text(prop, "Value", "");
+       RNA_def_property_update(prop, 0, "rna_KeyMapItem_update");
 
        prop= RNA_def_property(srna, "id", PROP_INT, PROP_NONE);
        RNA_def_property_int_sdna(prop, NULL, "id");
        RNA_def_property_clear_flag(prop, PROP_EDITABLE);
        RNA_def_property_ui_text(prop, "id", "ID of the item");
+       RNA_def_property_update(prop, 0, "rna_KeyMapItem_update");
 
        prop= RNA_def_property(srna, "any", PROP_BOOLEAN, PROP_NONE);
        RNA_def_property_boolean_funcs(prop, "rna_KeyMapItem_any_getf", "rna_KeyMapItem_any_setf");
        RNA_def_property_ui_text(prop, "Any", "Any modifier keys pressed");
+       RNA_def_property_update(prop, 0, "rna_KeyMapItem_update");
 
        prop= RNA_def_property(srna, "shift", PROP_BOOLEAN, PROP_NONE);
        RNA_def_property_boolean_sdna(prop, NULL, "shift", 0);
 //     RNA_def_property_enum_sdna(prop, NULL, "shift");
 //     RNA_def_property_enum_items(prop, keymap_modifiers_items);
        RNA_def_property_ui_text(prop, "Shift", "Shift key pressed");
+       RNA_def_property_update(prop, 0, "rna_KeyMapItem_update");
 
        prop= RNA_def_property(srna, "ctrl", PROP_BOOLEAN, PROP_NONE);
        RNA_def_property_boolean_sdna(prop, NULL, "ctrl", 0);
 //     RNA_def_property_enum_sdna(prop, NULL, "ctrl");
 //     RNA_def_property_enum_items(prop, keymap_modifiers_items);
        RNA_def_property_ui_text(prop, "Ctrl", "Control key pressed");
+       RNA_def_property_update(prop, 0, "rna_KeyMapItem_update");
 
        prop= RNA_def_property(srna, "alt", PROP_BOOLEAN, PROP_NONE);
        RNA_def_property_boolean_sdna(prop, NULL, "alt", 0);
 //     RNA_def_property_enum_sdna(prop, NULL, "alt");
 //     RNA_def_property_enum_items(prop, keymap_modifiers_items);
        RNA_def_property_ui_text(prop, "Alt", "Alt key pressed");
+       RNA_def_property_update(prop, 0, "rna_KeyMapItem_update");
 
        prop= RNA_def_property(srna, "oskey", PROP_BOOLEAN, PROP_NONE);
        RNA_def_property_boolean_sdna(prop, NULL, "oskey", 0);
 //     RNA_def_property_enum_sdna(prop, NULL, "oskey");
 //     RNA_def_property_enum_items(prop, keymap_modifiers_items);
        RNA_def_property_ui_text(prop, "OS Key", "Operating system key pressed");
+       RNA_def_property_update(prop, 0, "rna_KeyMapItem_update");
 
        prop= RNA_def_property(srna, "key_modifier", PROP_ENUM, PROP_NONE);
        RNA_def_property_enum_sdna(prop, NULL, "keymodifier");
        RNA_def_property_enum_items(prop, event_type_items);
        RNA_def_property_ui_text(prop, "Key Modifier", "Regular key pressed as a modifier");
+       RNA_def_property_update(prop, 0, "rna_KeyMapItem_update");
 
        prop= RNA_def_property(srna, "show_expanded", PROP_BOOLEAN, PROP_NONE);
        RNA_def_property_boolean_sdna(prop, NULL, "flag", KMI_EXPANDED);
@@ -1903,15 +1740,21 @@ static void rna_def_keyconfig(BlenderRNA *brna)
        RNA_def_property_enum_items(prop, keymap_propvalue_items);
        RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_KeyMapItem_propvalue_itemf");
        RNA_def_property_ui_text(prop, "Property Value", "The value this event translates to in a modal keymap");
+       RNA_def_property_update(prop, 0, "rna_KeyMapItem_update");
 
        prop= RNA_def_property(srna, "active", PROP_BOOLEAN, PROP_NONE);
        RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", KMI_INACTIVE);
        RNA_def_property_ui_text(prop, "Active", "Activate or deactivate item");
        RNA_def_property_ui_icon(prop, ICON_CHECKBOX_DEHLT, 1);
 
+       prop= RNA_def_property(srna, "is_user_modified", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "flag", KMI_USER_MODIFIED);
+       RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+       RNA_def_property_ui_text(prop, "User Modified", "Is this keymap item modified by the user");
+
        prop= RNA_def_property(srna, "is_user_defined", PROP_BOOLEAN, PROP_NONE);
        RNA_def_property_clear_flag(prop, PROP_EDITABLE);
-       RNA_def_property_ui_text(prop, "User Defined", "Is this keymap item user defined (doesn't just override a builtin item)");
+       RNA_def_property_ui_text(prop, "User Defined", "Is this keymap item user defined (doesn't just replace a builtin item)");
        RNA_def_property_boolean_funcs(prop, "rna_KeyMapItem_userdefined_get", NULL);
 
        RNA_api_keymapitem(srna);
index d44b689..89e946f 100644 (file)
@@ -84,6 +84,85 @@ void rna_event_timer_remove(struct wmWindowManager *wm, wmTimer *timer)
        WM_event_remove_timer(wm, timer->win, timer);
 }
 
+static wmKeyMapItem *rna_KeyMap_item_new(wmKeyMap *km, ReportList *reports, const char *idname, int type, int value, int any, int shift, int ctrl, int alt, int oskey, int keymodifier)
+{
+//     wmWindowManager *wm = CTX_wm_manager(C);
+       char idname_bl[OP_MAX_TYPENAME];
+       int modifier= 0;
+
+       /* only on non-modal maps */
+       if (km->flag & KEYMAP_MODAL) {
+               BKE_report(reports, RPT_ERROR, "Not a non-modal keymap.");
+               return NULL;
+       }
+
+       WM_operator_bl_idname(idname_bl, idname);
+
+       if(shift) modifier |= KM_SHIFT;
+       if(ctrl) modifier |= KM_CTRL;
+       if(alt) modifier |= KM_ALT;
+       if(oskey) modifier |= KM_OSKEY;
+
+       if(any) modifier = KM_ANY;
+
+       return WM_keymap_add_item(km, idname_bl, type, value, modifier, keymodifier);
+}
+
+static wmKeyMapItem *rna_KeyMap_item_new_modal(wmKeyMap *km, ReportList *reports, const char *propvalue_str, int type, int value, int any, int shift, int ctrl, int alt, int oskey, int keymodifier)
+{
+       int modifier= 0;
+       int propvalue = 0;
+
+       /* only modal maps */
+       if ((km->flag & KEYMAP_MODAL) == 0) {
+               BKE_report(reports, RPT_ERROR, "Not a modal keymap.");
+               return NULL;
+       }
+
+       if (!km->modal_items) {
+               BKE_report(reports, RPT_ERROR, "No property values defined.");
+               return NULL;
+       }
+
+
+       if(RNA_enum_value_from_id(km->modal_items, propvalue_str, &propvalue)==0) {
+               BKE_report(reports, RPT_WARNING, "Property value not in enumeration.");
+       }
+
+       if(shift) modifier |= KM_SHIFT;
+       if(ctrl) modifier |= KM_CTRL;
+       if(alt) modifier |= KM_ALT;
+       if(oskey) modifier |= KM_OSKEY;
+
+       if(any) modifier = KM_ANY;
+
+       return WM_modalkeymap_add_item(km, type, value, modifier, keymodifier, propvalue);
+}
+
+static wmKeyMap *rna_keymap_new(wmKeyConfig *keyconf, const char *idname, int spaceid, int regionid, int modal)
+{
+       if (modal == 0) {
+               return WM_keymap_find(keyconf, idname, spaceid, regionid);
+       } else {
+               return WM_modalkeymap_add(keyconf, idname, NULL); /* items will be lazy init */
+       }
+}
+
+static wmKeyMap *rna_keymap_find(wmKeyConfig *keyconf, const char *idname, int spaceid, int regionid)
+{
+       return WM_keymap_list_find(&keyconf->keymaps, idname, spaceid, regionid);
+}
+
+static wmKeyMap *rna_keymap_find_modal(wmKeyConfig *UNUSED(keyconf), const char *idname)
+{
+       wmOperatorType *ot = WM_operatortype_find(idname, 0);
+
+       if (!ot)
+               return NULL;
+       else
+               return ot->modalkeymap;
+}
+
 #else
 
 #define WM_GEN_INVOKE_EVENT (1<<0)
@@ -301,11 +380,8 @@ void RNA_api_keymap(StructRNA *srna)
        parm= RNA_def_pointer(func, "keymap", "KeyMap", "Key Map", "Active key map.");
        RNA_def_function_return(func, parm);
 
-       func= RNA_def_function(srna, "copy_to_user", "WM_keymap_copy_to_user");
-       parm= RNA_def_pointer(func, "keymap", "KeyMap", "Key Map", "User editable key map.");
-       RNA_def_function_return(func, parm);
-
-       RNA_def_function(srna, "restore_to_default", "WM_keymap_restore_to_default");
+       func= RNA_def_function(srna, "restore_to_default", "WM_keymap_restore_to_default");
+       RNA_def_function_flag(func, FUNC_USE_CONTEXT);
 
        func= RNA_def_function(srna, "restore_item_to_default", "rna_keymap_restore_item_to_default");
        RNA_def_function_flag(func, FUNC_USE_CONTEXT);
@@ -324,5 +400,102 @@ void RNA_api_keymapitem(StructRNA *srna)
        parm= RNA_def_boolean(func, "result", 0, "Comparison result", "");
        RNA_def_function_return(func, parm);
 }
+
+void RNA_api_keymapitems(StructRNA *srna)
+{
+       FunctionRNA *func;
+       PropertyRNA *parm;
+
+       func= RNA_def_function(srna, "new", "rna_KeyMap_item_new");
+       RNA_def_function_flag(func, FUNC_USE_REPORTS);
+       parm= RNA_def_string(func, "idname", "", 0, "Operator Identifier", "");
+       RNA_def_property_flag(parm, PROP_REQUIRED);
+       parm= RNA_def_enum(func, "type", event_type_items, 0, "Type", "");
+       RNA_def_property_flag(parm, PROP_REQUIRED);
+       parm= RNA_def_enum(func, "value", event_value_items, 0, "Value", "");
+       RNA_def_property_flag(parm, PROP_REQUIRED);
+       RNA_def_boolean(func, "any", 0, "Any", "");
+       RNA_def_boolean(func, "shift", 0, "Shift", "");
+       RNA_def_boolean(func, "ctrl", 0, "Ctrl", "");
+       RNA_def_boolean(func, "alt", 0, "Alt", "");
+       RNA_def_boolean(func, "oskey", 0, "OS Key", "");
+       RNA_def_enum(func, "key_modifier", event_type_items, 0, "Key Modifier", "");
+       parm= RNA_def_pointer(func, "item", "KeyMapItem", "Item", "Added key map item.");
+       RNA_def_function_return(func, parm);
+
+       func= RNA_def_function(srna, "new_modal", "rna_KeyMap_item_new_modal");
+       RNA_def_function_flag(func, FUNC_USE_REPORTS);
+       parm= RNA_def_string(func, "propvalue", "", 0, "Property Value", "");
+       RNA_def_property_flag(parm, PROP_REQUIRED);
+       parm= RNA_def_enum(func, "type", event_type_items, 0, "Type", "");
+       RNA_def_property_flag(parm, PROP_REQUIRED);
+       parm= RNA_def_enum(func, "value", event_value_items, 0, "Value", "");
+       RNA_def_property_flag(parm, PROP_REQUIRED);
+       RNA_def_boolean(func, "any", 0, "Any", "");
+       RNA_def_boolean(func, "shift", 0, "Shift", "");
+       RNA_def_boolean(func, "ctrl", 0, "Ctrl", "");
+       RNA_def_boolean(func, "alt", 0, "Alt", "");
+       RNA_def_boolean(func, "oskey", 0, "OS Key", "");
+       RNA_def_enum(func, "key_modifier", event_type_items, 0, "Key Modifier", "");
+       parm= RNA_def_pointer(func, "item", "KeyMapItem", "Item", "Added key map item.");
+       RNA_def_function_return(func, parm);
+       
+       func= RNA_def_function(srna, "remove", "WM_keymap_remove_item");
+       parm= RNA_def_pointer(func, "item", "KeyMapItem", "Item", "");
+       RNA_def_property_flag(parm, PROP_REQUIRED);
+
+       func= RNA_def_function(srna, "from_id", "WM_keymap_item_find_id");
+       parm= RNA_def_property(func, "id", PROP_INT, PROP_NONE);
+       RNA_def_property_flag(parm, PROP_REQUIRED);
+       RNA_def_property_ui_text(parm, "id", "ID of the item");
+       parm= RNA_def_pointer(func, "item", "KeyMapItem", "Item", "");
+       RNA_def_function_return(func, parm);
+}
+
+void RNA_api_keymaps(StructRNA *srna)
+{
+       FunctionRNA *func;
+       PropertyRNA *parm;
+
+       func= RNA_def_function(srna, "new", "rna_keymap_new"); // add_keymap
+       parm= RNA_def_string(func, "name", "", 0, "Name", "");
+       RNA_def_property_flag(parm, PROP_REQUIRED);
+       RNA_def_enum(func, "space_type", space_type_items, SPACE_EMPTY, "Space Type", "");
+       RNA_def_enum(func, "region_type", region_type_items, RGN_TYPE_WINDOW, "Region Type", "");
+       RNA_def_boolean(func, "modal", 0, "Modal", "");
+       parm= RNA_def_pointer(func, "keymap", "KeyMap", "Key Map", "Added key map.");
+       RNA_def_function_return(func, parm);
+
+       func= RNA_def_function(srna, "find", "rna_keymap_find"); // find_keymap
+       parm= RNA_def_string(func, "name", "", 0, "Name", "");
+       RNA_def_property_flag(parm, PROP_REQUIRED);
+       RNA_def_enum(func, "space_type", space_type_items, SPACE_EMPTY, "Space Type", "");
+       RNA_def_enum(func, "region_type", region_type_items, RGN_TYPE_WINDOW, "Region Type", "");
+       parm= RNA_def_pointer(func, "keymap", "KeyMap", "Key Map", "Corresponding key map.");
+       RNA_def_function_return(func, parm);
+
+       func= RNA_def_function(srna, "find_modal", "rna_keymap_find_modal"); // find_keymap_modal
+       parm= RNA_def_string(func, "name", "", 0, "Operator Name", "");
+       RNA_def_property_flag(parm, PROP_REQUIRED);
+       parm= RNA_def_pointer(func, "keymap", "KeyMap", "Key Map", "Corresponding key map.");
+       RNA_def_function_return(func, parm);
+}
+
+void RNA_api_keyconfigs(StructRNA *srna)
+{
+       FunctionRNA *func;
+       PropertyRNA *parm;
+
+       func= RNA_def_function(srna, "new", "WM_keyconfig_new_user"); // add_keyconfig
+       parm= RNA_def_string(func, "name", "", 0, "Name", "");
+       RNA_def_property_flag(parm, PROP_REQUIRED);
+       parm= RNA_def_pointer(func, "keyconfig", "KeyConfig", "Key Configuration", "Added key configuration.");
+       RNA_def_function_return(func, parm);
+
+       func= RNA_def_function(srna, "remove", "WM_keyconfig_remove"); // remove_keyconfig
+       parm= RNA_def_pointer(func, "keyconfig", "KeyConfig", "Key Configuration", "Removed key configuration.");
+       RNA_def_property_flag(parm, PROP_REQUIRED);
+}
+
 #endif
 
index e6325e2..42c3096 100644 (file)
@@ -41,6 +41,7 @@
 
 /* dna-savable wmStructs here */
 #include "DNA_windowmanager_types.h"
+#include "WM_keymap.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -114,50 +115,9 @@ void               WM_paint_cursor_end(struct wmWindowManager *wm, void *handle);
 
 void           WM_cursor_warp          (struct wmWindow *win, int x, int y);
 
-                       /* keyconfig and keymap */
-wmKeyConfig *WM_keyconfig_new  (struct wmWindowManager *wm, const char *idname);
-wmKeyConfig *WM_keyconfig_new_user(struct wmWindowManager *wm, const char *idname);
-void           WM_keyconfig_remove     (struct wmWindowManager *wm, struct wmKeyConfig *keyconf);
-void           WM_keyconfig_free       (struct wmKeyConfig *keyconf);
-void           WM_keyconfig_userdef(void);
-
-void           WM_keymap_init          (struct bContext *C);
-void           WM_keymap_free          (struct wmKeyMap *keymap);
-
-wmKeyMapItem *WM_keymap_verify_item(struct wmKeyMap *keymap, const char *idname, int type, 
-                                                                int val, int modifier, int keymodifier);
-wmKeyMapItem *WM_keymap_add_item(struct wmKeyMap *keymap, const char *idname, int type, 
-                                                                int val, int modifier, int keymodifier);
-wmKeyMapItem *WM_keymap_add_menu(struct wmKeyMap *keymap, const char *idname, int type,
-                                                                int val, int modifier, int keymodifier);
-
-void           WM_keymap_remove_item(struct wmKeyMap *keymap, struct wmKeyMapItem *kmi);
-char            *WM_keymap_item_to_string(wmKeyMapItem *kmi, char *str, int len);
-
-wmKeyMap       *WM_keymap_list_find(ListBase *lb, const char *idname, int spaceid, int regionid);
-wmKeyMap       *WM_keymap_find(struct wmKeyConfig *keyconf, const char *idname, int spaceid, int regionid);
-wmKeyMap       *WM_keymap_find_all(const struct bContext *C, const char *idname, int spaceid, int regionid);
-wmKeyMap       *WM_keymap_active(struct wmWindowManager *wm, struct wmKeyMap *keymap);
-wmKeyMap       *WM_keymap_guess_opname(const struct bContext *C, const char *opname);
-int                     WM_keymap_user_init(struct wmWindowManager *wm, struct wmKeyMap *keymap);
-wmKeyMap       *WM_keymap_copy_to_user(struct wmKeyMap *keymap);
-void           WM_keymap_restore_to_default(struct wmKeyMap *keymap);
-void           WM_keymap_properties_reset(struct wmKeyMapItem *kmi, struct IDProperty *properties);
-void           WM_keymap_restore_item_to_default(struct bContext *C, struct wmKeyMap *keymap, struct wmKeyMapItem *kmi);
-
-wmKeyMapItem *WM_keymap_item_find_id(struct wmKeyMap *keymap, int id);
-int                    WM_keymap_item_compare(struct wmKeyMapItem *k1, struct wmKeyMapItem *k2);
+                       /* event map */
 int                    WM_userdef_event_map(int kmitype);
 
-wmKeyMap       *WM_modalkeymap_add(struct wmKeyConfig *keyconf, const char *idname, struct EnumPropertyItem *items);
-wmKeyMap       *WM_modalkeymap_get(struct wmKeyConfig *keyconf, const char *idname);
-wmKeyMapItem *WM_modalkeymap_add_item(struct wmKeyMap *km, int type, int val, int modifier, int keymodifier, int value);
-void           WM_modalkeymap_assign(struct wmKeyMap *km, const char *opname);
-
-const char     *WM_key_event_string(short type);
-int                    WM_key_event_operator_id(const struct bContext *C, const char *opname, int opcontext, struct IDProperty *properties, int hotkey, struct wmKeyMap **keymap_r);
-char           *WM_key_event_operator_string(const struct bContext *C, const char *opname, int opcontext, struct IDProperty *properties, char *str, int len);
-
                        /* handlers */
 
 struct wmEventHandler *WM_event_add_keymap_handler(ListBase *handlers, wmKeyMap *keymap);
diff --git a/source/blender/windowmanager/WM_keymap.h b/source/blender/windowmanager/WM_keymap.h
new file mode 100644 (file)
index 0000000..e00cd28
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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 2
+ * 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, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2007 Blender Foundation.
+ * All rights reserved.
+ * 
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef WM_KEYMAP_H
+#define WM_KEYMAP_H
+
+/** \file WM_keymap.h
+ *  \ingroup wm
+ */
+
+/* dna-savable wmStructs here */
+#include "DNA_windowmanager_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct EnumPropertyItem;
+
+/* Key Configuration */
+
+wmKeyConfig *WM_keyconfig_new  (struct wmWindowManager *wm, const char *idname);
+wmKeyConfig *WM_keyconfig_new_user(struct wmWindowManager *wm, const char *idname);
+void           WM_keyconfig_remove     (struct wmWindowManager *wm, struct wmKeyConfig *keyconf);
+void           WM_keyconfig_free       (struct wmKeyConfig *keyconf);
+
+void           WM_keyconfig_set_active(struct wmWindowManager *wm, const char *idname);
+
+void           WM_keyconfig_update(struct wmWindowManager *wm);
+void           WM_keyconfig_update_tag(struct wmKeyMap *keymap, struct wmKeyMapItem *kmi);
+
+/* Keymap */
+
+void           WM_keymap_init          (struct bContext *C);
+void           WM_keymap_free          (struct wmKeyMap *keymap);
+
+wmKeyMapItem *WM_keymap_verify_item(struct wmKeyMap *keymap, const char *idname, int type, 
+                                                                int val, int modifier, int keymodifier);
+wmKeyMapItem *WM_keymap_add_item(struct wmKeyMap *keymap, const char *idname, int type, 
+                                                                int val, int modifier, int keymodifier);
+wmKeyMapItem *WM_keymap_add_menu(struct wmKeyMap *keymap, const char *idname, int type,
+                                                                int val, int modifier, int keymodifier);
+
+void           WM_keymap_remove_item(struct wmKeyMap *keymap, struct wmKeyMapItem *kmi);
+char            *WM_keymap_item_to_string(wmKeyMapItem *kmi, char *str, int len);
+
+wmKeyMap       *WM_keymap_list_find(ListBase *lb, const char *idname, int spaceid, int regionid);
+wmKeyMap       *WM_keymap_find(struct wmKeyConfig *keyconf, const char *idname, int spaceid, int regionid);
+wmKeyMap       *WM_keymap_find_all(const struct bContext *C, const char *idname, int spaceid, int regionid);
+wmKeyMap       *WM_keymap_active(struct wmWindowManager *wm, struct wmKeyMap *keymap);
+wmKeyMap       *WM_keymap_guess_opname(const struct bContext *C, const char *opname);
+
+wmKeyMapItem *WM_keymap_item_find_id(struct wmKeyMap *keymap, int id);
+int                    WM_keymap_item_compare(struct wmKeyMapItem *k1, struct wmKeyMapItem *k2);
+
+/* Modal Keymap */
+
+wmKeyMap       *WM_modalkeymap_add(struct wmKeyConfig *keyconf, const char *idname, struct EnumPropertyItem *items);
+wmKeyMap       *WM_modalkeymap_get(struct wmKeyConfig *keyconf, const char *idname);
+wmKeyMapItem *WM_modalkeymap_add_item(struct wmKeyMap *km, int type, int val, int modifier, int keymodifier, int value);
+void           WM_modalkeymap_assign(struct wmKeyMap *km, const char *opname);
+
+/* Keymap Editor */
+
+void           WM_keymap_restore_to_default(struct wmKeyMap *keymap, struct bContext *C);
+void           WM_keymap_properties_reset(struct wmKeyMapItem *kmi, struct IDProperty *properties);
+void           WM_keymap_restore_item_to_default(struct bContext *C, struct wmKeyMap *keymap, struct wmKeyMapItem *kmi);
+
+/* Key Event */
+
+const char     *WM_key_event_string(short type);
+int                    WM_key_event_operator_id(const struct bContext *C, const char *opname, int opcontext, struct IDProperty *properties, int hotkey, struct wmKeyMap **keymap_r);
+char           *WM_key_event_operator_string(const struct bContext *C, const char *opname, int opcontext, struct IDProperty *properties, char *str, int len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* WM_KEYMAP_H */
+
index a535c0b..1d5cf1c 100644 (file)
@@ -210,12 +210,18 @@ void WM_keymap_init(bContext *C)
 
        if(!wm->defaultconf)
                wm->defaultconf= WM_keyconfig_new(wm, "Blender");
+       if(!wm->addonconf)
+               wm->addonconf= WM_keyconfig_new(wm, "Blender Addon");
+       if(!wm->userconf)
+               wm->userconf= WM_keyconfig_new(wm, "Blender User");
        
-       if(wm && CTX_py_init_get(C) && (wm->initialized & WM_INIT_KEYMAP) == 0) {
+       if(CTX_py_init_get(C) && (wm->initialized & WM_INIT_KEYMAP) == 0) {
                /* create default key config */
                wm_window_keymap(wm->defaultconf);
                ED_spacetypes_keymap(wm->defaultconf);
-               WM_keyconfig_userdef();
+
+               WM_keyconfig_update_tag(NULL, NULL);
+               WM_keyconfig_update(wm);
 
                wm->initialized |= WM_INIT_KEYMAP;
        }
index 2f0c1a7..0dac0bd 100644 (file)
@@ -1735,6 +1735,9 @@ void wm_event_do_handlers(bContext *C)
        wmWindowManager *wm= CTX_wm_manager(C);
        wmWindow *win;
 
+       /* update key configuration before handling events */
+       WM_keyconfig_update(wm);
+
        for(win= wm->windows.first; win; win= win->next) {
                wmEvent *event;
                
@@ -1938,6 +1941,9 @@ void wm_event_do_handlers(bContext *C)
                
                CTX_wm_window_set(C, NULL);
        }
+
+       /* update key configuration after handling events */
+       WM_keyconfig_update(wm);
 }
 
 /* ********** filesector handling ************ */
index 27fc0ca..20f9d22 100644 (file)
@@ -224,6 +224,14 @@ static void wm_window_match_do(bContext *C, ListBase *oldwmlist)
                        oldwm= oldwmlist->first;
                        wm= G.main->wm.first;
 
+                       /* move addon key configuration to new wm, to preserve their keymaps */
+                       if(oldwm->addonconf) {
+                               wm->addonconf= oldwm->addonconf;
+                               BLI_remlink(&oldwm->keyconfigs, oldwm->addonconf);
+                               oldwm->addonconf= NULL;
+                               BLI_addtail(&wm->keyconfigs, wm->addonconf);
+                       }
+
                        /* ensure making new keymaps and set space types */
                        wm->initialized= 0;
                        wm->winactive= NULL;
@@ -794,11 +802,14 @@ int WM_write_homefile(bContext *C, wmOperator *op)
        wmWindow *win= CTX_wm_window(C);
        char filepath[FILE_MAXDIR+FILE_MAXFILE];
        int fileflags;
-       
+
        /* check current window and close it if temp */
        if(win->screen->temp)
                wm_window_close(C, wm, win);
        
+       /* update keymaps in user preferences */
+       WM_keyconfig_update(wm);
+       
        BLI_make_file_string("/", filepath, BLI_get_folder_create(BLENDER_USER_CONFIG, NULL), BLENDER_STARTUP_FILE);
        printf("trying to save homefile at %s ", filepath);
        
index 1720c73..bf48f0e 100644 (file)
 #include "wm_event_system.h"
 #include "wm_event_types.h"
 
-/* ********************* key config ***********************/
+/******************************* Keymap Item **********************************
+ * Item in a keymap, that maps from an event to an operator or modal map item */
 
-static void keymap_properties_set(wmKeyMapItem *kmi)
+static wmKeyMapItem *wm_keymap_item_copy(wmKeyMapItem *kmi)
+{
+       wmKeyMapItem *kmin = MEM_dupallocN(kmi);
+
+       kmin->prev= kmin->next= NULL;
+       kmin->flag &= ~KMI_UPDATE;
+
+       if(kmin->properties) {
+               kmin->ptr= MEM_callocN(sizeof(PointerRNA), "UserKeyMapItemPtr");
+               WM_operator_properties_create(kmin->ptr, kmin->idname);
+
+               kmin->properties= IDP_CopyProperty(kmin->properties);
+               kmin->ptr->data= kmin->properties;
+       }
+
+       return kmin;
+}
+
+static void wm_keymap_item_free(wmKeyMapItem *kmi)
+{
+       /* not kmi itself */
+       if(kmi->ptr) {
+               WM_operator_properties_free(kmi->ptr);
+               MEM_freeN(kmi->ptr);
+       }
+}
+
+static void wm_keymap_item_properties_set(wmKeyMapItem *kmi)
 {
        WM_operator_properties_alloc(&(kmi->ptr), &(kmi->properties), kmi->idname);
        WM_operator_properties_sanitize(kmi->ptr, 1);
 }
 
+static int wm_keymap_item_equals_result(wmKeyMapItem *a, wmKeyMapItem *b)
+{
+       if(strcmp(a->idname, b->idname) != 0)
+               return 0;
+       
+       if(!((a->ptr==NULL && b->ptr==NULL) ||
+            (a->ptr && b->ptr && IDP_EqualsProperties(a->ptr->data, b->ptr->data))))
+               return 0;
+       
+       return (a->propvalue == b->propvalue);
+}
+
+static int wm_keymap_item_equals(wmKeyMapItem *a, wmKeyMapItem *b)
+{
+       return (wm_keymap_item_equals_result(a, b) &&
+               a->type == b->type &&
+               a->val == b->val &&
+               a->shift == b->shift &&
+               a->ctrl == b->ctrl &&
+               a->alt == b->alt &&
+               a->oskey == b->oskey &&
+               a->keymodifier == b->keymodifier &&
+               a->maptype == b->maptype);
+}
+
 /* properties can be NULL, otherwise the arg passed is used and ownership is given to the kmi */
 void WM_keymap_properties_reset(wmKeyMapItem *kmi, struct IDProperty *properties)
 {
@@ -78,9 +131,41 @@ void WM_keymap_properties_reset(wmKeyMapItem *kmi, struct IDProperty *properties
        kmi->ptr = NULL;
        kmi->properties = properties;
 
-       keymap_properties_set(kmi);
+       wm_keymap_item_properties_set(kmi);
+}
+
+/**************************** Keymap Diff Item *********************************
+ * Item in a diff keymap, used for saving diff of keymaps in user preferences */
+
+static wmKeyMapDiffItem *wm_keymap_diff_item_copy(wmKeyMapDiffItem *kmdi)
+{
+       wmKeyMapDiffItem *kmdin = MEM_dupallocN(kmdi);
+
+       kmdin->next = kmdin->prev = NULL;
+       if(kmdi->add_item)
+               kmdin->add_item = wm_keymap_item_copy(kmdi->add_item);
+       if(kmdi->remove_item)
+               kmdin->remove_item = wm_keymap_item_copy(kmdi->remove_item);
+       
+       return kmdin;
+}
+
+static void wm_keymap_diff_item_free(wmKeyMapDiffItem *kmdi)
+{
+       if(kmdi->remove_item) {
+               wm_keymap_item_free(kmdi->remove_item);
+               MEM_freeN(kmdi->remove_item);
+       }
+       if(kmdi->add_item) {
+               wm_keymap_item_free(kmdi->add_item);
+               MEM_freeN(kmdi->add_item);
+       }
 }
 
+/***************************** Key Configuration ******************************
+ * List of keymaps for all editors, modes, ... . There is a builtin default key
+ * configuration, a user key configuration, and other preset configurations. */
+
 wmKeyConfig *WM_keyconfig_new(wmWindowManager *wm, const char *idname)
 {
        wmKeyConfig *keyconf;
@@ -106,6 +191,7 @@ void WM_keyconfig_remove(wmWindowManager *wm, wmKeyConfig *keyconf)
        if (keyconf) {
                if (strncmp(U.keyconfigstr, keyconf->idname, sizeof(U.keyconfigstr)) == 0) {
                        BLI_strncpy(U.keyconfigstr, wm->defaultconf->idname, sizeof(U.keyconfigstr));
+                       WM_keyconfig_update_tag(NULL, NULL);
                }
 
                BLI_remlink(&wm->keyconfigs, keyconf);
@@ -125,21 +211,6 @@ void WM_keyconfig_free(wmKeyConfig *keyconf)
        MEM_freeN(keyconf);
 }
 
-void WM_keyconfig_userdef(void)
-{
-       wmKeyMap *km;
-       wmKeyMapItem *kmi;
-
-       for(km=U.keymaps.first; km; km=km->next) {
-               /* modal keymaps don't have operator properties */
-               if ((km->flag & KEYMAP_MODAL) == 0) {
-                       for(kmi=km->items.first; kmi; kmi=kmi->next) {
-                               keymap_properties_set(kmi);
-                       }
-               }
-       }
-}
-
 static wmKeyConfig *wm_keyconfig_list_find(ListBase *lb, char *idname)
 {
        wmKeyConfig *kc;
@@ -151,23 +222,84 @@ static wmKeyConfig *wm_keyconfig_list_find(ListBase *lb, char *idname)
        return NULL;
 }
 
-/* ************************ free ************************* */
+wmKeyConfig *WM_keyconfig_active(wmWindowManager *wm)
+{
+       wmKeyConfig *keyconf;
 
-void WM_keymap_free(wmKeyMap *keymap)
+       /* first try from preset */
+       keyconf= wm_keyconfig_list_find(&wm->keyconfigs, U.keyconfigstr);
+       if(keyconf)
+               return keyconf;
+       
+       /* otherwise use default */
+       return wm->defaultconf;
+}
+
+void WM_keyconfig_set_active(wmWindowManager *wm, const char *idname)
 {
-       wmKeyMapItem *kmi;
+       /* setting a different key configuration as active: we ensure all is
+          updated properly before and after making the change */
+
+       WM_keyconfig_update(wm);
+
+       BLI_strncpy(U.keyconfigstr, idname, sizeof(U.keyconfigstr));
+
+       WM_keyconfig_update_tag(NULL, NULL);
+       WM_keyconfig_update(wm);
+}
+
+/********************************** Keymap *************************************
+ * List of keymap items for one editor, mode, modal operator, ... */
+
+static wmKeyMap *wm_keymap_new(const char *idname, int spaceid, int regionid)
+{
+       wmKeyMap *km= MEM_callocN(sizeof(struct wmKeyMap), "keymap list");
+
+       BLI_strncpy(km->idname, idname, KMAP_MAX_NAME);
+       km->spaceid= spaceid;
+       km->regionid= regionid;
+
+       return km;
+}
+
+static wmKeyMap *wm_keymap_copy(wmKeyMap *keymap)
+{
+       wmKeyMap *keymapn = MEM_dupallocN(keymap);
+       wmKeyMapItem *kmi, *kmin;
+       wmKeyMapDiffItem *kmdi, *kmdin;
+
+       keymapn->modal_items= keymap->modal_items;
+       keymapn->poll= keymap->poll;
+       keymapn->items.first= keymapn->items.last= NULL;
+       keymapn->flag &= ~(KEYMAP_UPDATE|KEYMAP_EXPANDED);
+
+       for(kmdi=keymap->diff_items.first; kmdi; kmdi=kmdi->next) {
+               kmdin= wm_keymap_diff_item_copy(kmdi);
+               BLI_addtail(&keymapn->items, kmdin);
+       }
 
        for(kmi=keymap->items.first; kmi; kmi=kmi->next) {
-               if(kmi->ptr) {
-                       WM_operator_properties_free(kmi->ptr);
-                       MEM_freeN(kmi->ptr);
-               }
+               kmin= wm_keymap_item_copy(kmi);
+               BLI_addtail(&keymapn->items, kmin);
        }
 
-       BLI_freelistN(&keymap->items);
+       return keymapn;
 }
 
-/* ***************** generic call, exported **************** */
+void WM_keymap_free(wmKeyMap *keymap)
+{
+       wmKeyMapItem *kmi;
+       wmKeyMapDiffItem *kmdi;
+
+       for(kmdi=keymap->diff_items.first; kmdi; kmdi=kmdi->next)
+               wm_keymap_diff_item_free(kmdi);
+
+       for(kmi=keymap->items.first; kmi; kmi=kmi->next)
+               wm_keymap_item_free(kmi);
+
+       BLI_freelistN(&keymap->diff_items);
+       BLI_freelistN(&keymap->items);
+}
 
 static void keymap_event_set(wmKeyMapItem *kmi, short type, short val, int modifier, short keymodifier)
 {
@@ -229,7 +361,7 @@ wmKeyMapItem *WM_keymap_verify_item(wmKeyMap *keymap, const char *idname, int ty
                keymap_item_set_id(keymap, kmi);
 
                keymap_event_set(kmi, type, val, modifier, keymodifier);
-               keymap_properties_set(kmi);
+               wm_keymap_item_properties_set(kmi);
        }
        return kmi;
 }
@@ -243,10 +375,12 @@ wmKeyMapItem *WM_keymap_add_item(wmKeyMap *keymap, const char *idname, int type,
        BLI_strncpy(kmi->idname, idname, OP_MAX_TYPENAME);
 
        keymap_event_set(kmi, type, val, modifier, keymodifier);
-       keymap_properties_set(kmi);
+       wm_keymap_item_properties_set(kmi);
 
        keymap_item_set_id(keymap, kmi);
 
+       WM_keyconfig_update_tag(keymap, kmi);
+
        return kmi;
 }
 
@@ -266,6 +400,232 @@ void WM_keymap_remove_item(wmKeyMap *keymap, wmKeyMapItem *kmi)
                        MEM_freeN(kmi->ptr);
                }
                BLI_freelinkN(&keymap->items, kmi);
+
+               WM_keyconfig_update_tag(keymap, kmi);
+       }
+}
+
+/************************** Keymap Diff and Patch ****************************
+ * Rather than saving the entire keymap for user preferences, we only save a
+ * diff so that changes in the defaults get synced. This system is not perfect
+ * but works better than overriding the keymap entirely when only few items
+ * are changed. */
+
+static void wm_keymap_addon_add(wmKeyMap *keymap, wmKeyMap *addonmap)
+{
+       wmKeyMapItem *kmi, *kmin;
+
+       for(kmi=addonmap->items.first; kmi; kmi=kmi->next) {
+               kmin = wm_keymap_item_copy(kmi);
+               keymap_item_set_id(keymap, kmin);
+               BLI_addhead(&keymap->items, kmin);
+       }
+}
+
+static wmKeyMapItem *wm_keymap_find_item_equals(wmKeyMap *km, wmKeyMapItem *needle)
+{
+       wmKeyMapItem *kmi;
+
+       for(kmi=km->items.first; kmi; kmi=kmi->next)
+               if(wm_keymap_item_equals(kmi, needle))
+                       return kmi;
+       
+       return NULL;
+}
+
+static wmKeyMapItem *wm_keymap_find_item_equals_result(wmKeyMap *km, wmKeyMapItem *needle)
+{
+       wmKeyMapItem *kmi;
+
+       for(kmi=km->items.first; kmi; kmi=kmi->next)
+               if(wm_keymap_item_equals_result(kmi, needle))
+                       return kmi;
+       
+       return NULL;
+}
+
+static void wm_keymap_diff(wmKeyMap *diff_km, wmKeyMap *from_km, wmKeyMap *to_km, wmKeyMap *orig_km, wmKeyMap *addon_km)
+{
+       wmKeyMapItem *kmi, *to_kmi, *orig_kmi;
+       wmKeyMapDiffItem *kmdi;
+
+       for(kmi=from_km->items.first; kmi; kmi=kmi->next) {
+               to_kmi = WM_keymap_item_find_id(to_km, kmi->id);
+
+               if(!to_kmi) {
+                       /* remove item */
+                       kmdi = MEM_callocN(sizeof(wmKeyMapDiffItem), "wmKeyMapDiffItem");
+                       kmdi->remove_item = wm_keymap_item_copy(kmi);
+                       BLI_addtail(&diff_km->diff_items, kmdi);
+               }
+               else if(to_kmi && !wm_keymap_item_equals(kmi, to_kmi)) {
+                       /* replace item */
+                       kmdi = MEM_callocN(sizeof(wmKeyMapDiffItem), "wmKeyMapDiffItem");
+                       kmdi->remove_item = wm_keymap_item_copy(kmi);
+                       kmdi->add_item = wm_keymap_item_copy(to_kmi);
+                       BLI_addtail(&diff_km->diff_items, kmdi);
+               }
+
+               /* sync expanded flag back to original so we don't loose it on repatch */
+               if(to_kmi) {
+                       orig_kmi = WM_keymap_item_find_id(orig_km, kmi->id);
+
+                       if(!orig_kmi)
+                               orig_kmi = wm_keymap_find_item_equals(addon_km, kmi);
+
+                       if(orig_kmi) {
+                               orig_kmi->flag &= ~KMI_EXPANDED;
+                               orig_kmi->flag |= (to_kmi->flag & KMI_EXPANDED);
+                       }
+               }
+       }
+
+       for(kmi=to_km->items.first; kmi; kmi=kmi->next) {
+               if(kmi->id < 0) {
+                       /* add item */
+                       kmdi = MEM_callocN(sizeof(wmKeyMapDiffItem), "wmKeyMapDiffItem");
+                       kmdi->add_item = wm_keymap_item_copy(kmi);
+                       BLI_addtail(&diff_km->diff_items, kmdi);
+               }
+       }
+}
+
+static void wm_keymap_patch(wmKeyMap *km, wmKeyMap *diff_km)
+{
+       wmKeyMapDiffItem *kmdi;
+       wmKeyMapItem *kmi_remove, *kmi_add;
+
+       for(kmdi=diff_km->diff_items.first; kmdi; kmdi=kmdi->next) {
+               /* find item to remove */
+               kmi_remove = NULL;
+               if(kmdi->remove_item) {
+                       kmi_remove = wm_keymap_find_item_equals(km, kmdi->remove_item);
+                       if(!kmi_remove)
+                               kmi_remove = wm_keymap_find_item_equals_result(km, kmdi->remove_item);
+               }
+
+               /* add item */
+               if(kmdi->add_item) {
+                       /* only if nothing to remove or item to remove found */
+                       if(!kmdi->remove_item || kmi_remove) {
+                               kmi_add = wm_keymap_item_copy(kmdi->add_item);
+                               kmi_add->flag |= KMI_USER_MODIFIED;
+
+                               if(kmi_remove) {
+                                       kmi_add->flag &= ~KMI_EXPANDED;
+                                       kmi_add->flag |= (kmi_remove->flag & KMI_EXPANDED);
+                                       kmi_add->id = kmi_remove->id;
+                                       BLI_insertlinkbefore(&km->items, kmi_remove, kmi_add);
+                               }
+                               else {
+                                       keymap_item_set_id(km, kmi_add);
+                                       BLI_addtail(&km->items, kmi_add);
+                               }
+                       }
+               }
+
+               /* remove item */
+               if(kmi_remove) {
+                       wm_keymap_item_free(kmi_remove);
+                       BLI_freelinkN(&km->items, kmi_remove);
+               }
+       }
+}
+
+static void wm_keymap_patch_update(ListBase *lb, wmKeyMap *defaultmap, wmKeyMap *addonmap, wmKeyMap *usermap)
+{
+       wmKeyMap *km;
+       int expanded = 0;
+
+       /* remove previous keymap in list, we will replace it */
+       km = WM_keymap_list_find(lb, defaultmap->idname, defaultmap->spaceid, defaultmap->regionid);
+       if(km) {
+               expanded = (km->flag & (KEYMAP_EXPANDED|KEYMAP_CHILDREN_EXPANDED));
+               WM_keymap_free(km);
+               BLI_freelinkN(lb, km);
+       }
+
+       /* copy new keymap from an existing one */
+       if(usermap && !(usermap->flag & KEYMAP_DIFF)) {
+               /* for compatibiltiy with old user preferences with non-diff
+                  keymaps we override the original entirely */
+               wmKeyMapItem *kmi, *orig_kmi;
+
+               km = wm_keymap_copy(usermap);
+               km->modal_items = defaultmap->modal_items;
+               km->poll = defaultmap->poll;
+
+               /* try to find corresponding id's for items */
+               for(kmi=km->items.first; kmi; kmi=kmi->next) {
+                       orig_kmi = wm_keymap_find_item_equals(defaultmap, kmi);
+                       if(!orig_kmi)
+                               orig_kmi = wm_keymap_find_item_equals_result(defaultmap, kmi);
+
+                       if(orig_kmi)
+                               kmi->id = orig_kmi->id;
+                       else
+                               kmi->id = -(km->kmi_id++);
+               }
+
+               km->flag |= KEYMAP_UPDATE; /* update again to create diff */
+       }
+       else
+               km = wm_keymap_copy(defaultmap);
+
+       /* add addon keymap items */
+       if(addonmap)
+               wm_keymap_addon_add(km, addonmap);
+
+       /* tag as being user edited */
+       if(usermap)
+               km->flag |= KEYMAP_USER_MODIFIED;
+       km->flag |= KEYMAP_USER|expanded;
+
+       /* apply user changes of diff keymap */
+       if(usermap && (usermap->flag & KEYMAP_DIFF))
+               wm_keymap_patch(km, usermap);
+
+       /* add to list */
+       BLI_addtail(lb, km);
+}
+
+static void wm_keymap_diff_update(ListBase *lb, wmKeyMap *defaultmap, wmKeyMap *addonmap, wmKeyMap *km)
+{
+       wmKeyMap *diffmap, *prevmap, *origmap;
+
+       /* create temporary default + addon keymap for diff */
+       origmap = defaultmap;
+
+       if(addonmap) {
+               defaultmap = wm_keymap_copy(defaultmap);
+               wm_keymap_addon_add(defaultmap, addonmap);
+       }
+
+       /* remove previous diff keymap in list, we will replace it */
+       prevmap = WM_keymap_list_find(lb, km->idname, km->spaceid, km->regionid);
+       if(prevmap) {
+               WM_keymap_free(prevmap);
+               BLI_freelinkN(lb, prevmap);
+       }
+
+       /* create diff keymap */
+       diffmap= wm_keymap_new(km->idname, km->spaceid, km->regionid);
+       diffmap->flag |= KEYMAP_DIFF;
+       wm_keymap_diff(diffmap, defaultmap, km, origmap, addonmap);
+
+       /* add to list if not empty */
+       if(diffmap->diff_items.first) {
+               BLI_addtail(lb, diffmap);
+       }
+       else {
+               WM_keymap_free(diffmap);
+               MEM_freeN(diffmap);
+       }
+
+       /* free temporary default map */
+       if(addonmap) {
+               WM_keymap_free(defaultmap);
+               MEM_freeN(defaultmap);
        }
 }
 
@@ -292,11 +652,10 @@ wmKeyMap *WM_keymap_find(wmKeyConfig *keyconf, const char *idname, int spaceid,
        wmKeyMap *km= WM_keymap_list_find(&keyconf->keymaps, idname, spaceid, regionid);
        
        if(km==NULL) {
-               km= MEM_callocN(sizeof(struct wmKeyMap), "keymap list");
-               BLI_strncpy(km->idname, idname, KMAP_MAX_NAME);
-               km->spaceid= spaceid;
-               km->regionid= regionid;
+               km= wm_keymap_new(idname, spaceid, regionid);
                BLI_addtail(&keyconf->keymaps, km);
+
+               WM_keyconfig_update_tag(km, NULL);
        }
        
        return km;
@@ -304,29 +663,9 @@ wmKeyMap *WM_keymap_find(wmKeyConfig *keyconf, const char *idname, int spaceid,
 
 wmKeyMap *WM_keymap_find_all(const bContext *C, const char *idname, int spaceid, int regionid)
 {
-       wmWindowManager *wm = CTX_wm_manager(C);
-       wmKeyConfig *keyconf;
-       wmKeyMap *km;
-       
-       /* first user defined keymaps */
-       km= WM_keymap_list_find(&U.keymaps, idname, spaceid, regionid);
-       if (km)
-               return km;
-       
-       /* then user key config */
-       keyconf= wm_keyconfig_list_find(&wm->keyconfigs, U.keyconfigstr);
-       if(keyconf) {
-               km= WM_keymap_list_find(&keyconf->keymaps, idname, spaceid, regionid);
-               if (km)
-                       return km;
-       }
-       
-       /* then use default */
-       km= WM_keymap_list_find(&wm->defaultconf->keymaps, idname, spaceid, regionid);
-       if (km)
-               return km;
-       else
-               return NULL;
+       wmWindowManager *wm= CTX_wm_manager(C);
+
+       return WM_keymap_list_find(&wm->userconf->keymaps, idname, spaceid, regionid);
 }
 
 /* ****************** modal keymaps ************ */
@@ -366,6 +705,8 @@ wmKeyMapItem *WM_modalkeymap_add_item(wmKeyMap *km, int type, int val, int modif
 
        keymap_item_set_id(km, kmi);
 
+       WM_keyconfig_update_tag(km, kmi);
+
        return kmi;
 }
 
@@ -588,169 +929,209 @@ int     WM_keymap_item_compare(wmKeyMapItem *k1, wmKeyMapItem *k2)
        return 1;
 }
 
-/* ***************** user preferences ******************* */
+/************************* Update Final Configuration *************************
+ * On load or other changes, the final user key configuration is rebuilt from
+ * the preset, addon and user preferences keymaps. We also test if the final
+ * configuration changed and write the changes to the user preferences. */
+
+static int WM_KEYMAP_UPDATE = 0;
 
-int WM_keymap_user_init(wmWindowManager *wm, wmKeyMap *keymap)
+void WM_keyconfig_update_tag(wmKeyMap *km, wmKeyMapItem *kmi)
 {
-       wmKeyConfig *keyconf;
-       wmKeyMap *km;
+       /* quick tag to do delayed keymap updates */
+       WM_KEYMAP_UPDATE= 1;
 
-       if(!keymap)
-               return 0;
+       if(km)
+               km->flag |= KEYMAP_UPDATE;
+       if(kmi)
+               kmi->flag |= KMI_UPDATE;
+}
 
-       /* init from user key config */
-       keyconf= wm_keyconfig_list_find(&wm->keyconfigs, U.keyconfigstr);
-       if(keyconf) {
-               km= WM_keymap_list_find(&keyconf->keymaps, keymap->idname, keymap->spaceid, keymap->regionid);
-               if(km) {
-                       keymap->poll= km->poll; /* lazy init */
-                       keymap->modal_items= km->modal_items;
-                       return 1;
-               }
-       }
+static int wm_keymap_test_and_clear_update(wmKeyMap *km)
+{
+       wmKeyMapItem *kmi;
+       int update;
+       
+       update= (km->flag & KEYMAP_UPDATE);
+       km->flag &= ~KEYMAP_UPDATE;
 
-       /* or from default */
-       km= WM_keymap_list_find(&wm->defaultconf->keymaps, keymap->idname, keymap->spaceid, keymap->regionid);
-       if(km) {
-               keymap->poll= km->poll; /* lazy init */
-               keymap->modal_items= km->modal_items;
-               return 1;
+       for(kmi=km->items.first; kmi; kmi=kmi->next) {
+               update= update || (kmi->flag & KMI_UPDATE);
+               kmi->flag &= ~KMI_UPDATE;
        }
-
-       return 0;
+       
+       return update;
 }
 
-wmKeyMap *WM_keymap_active(wmWindowManager *wm, wmKeyMap *keymap)
+static wmKeyMap *wm_keymap_preset(wmWindowManager *wm, wmKeyMap *km)
 {
-       wmKeyConfig *keyconf;
-       wmKeyMap *km;
+       wmKeyConfig *keyconf= WM_keyconfig_active(wm);
+       wmKeyMap *keymap;
 
+       keymap= WM_keymap_list_find(&keyconf->keymaps, km->idname, km->spaceid, km->regionid);
        if(!keymap)
-               return NULL;
-       
-       /* first user defined keymaps */
-       km= WM_keymap_list_find(&U.keymaps, keymap->idname, keymap->spaceid, keymap->regionid);
-       if(km) {
-               km->poll= keymap->poll; /* lazy init */
-               km->modal_items= keymap->modal_items;
-               return km;
-       }
-       
-       /* then user key config */
-       keyconf= wm_keyconfig_list_find(&wm->keyconfigs, U.keyconfigstr);
-       if(keyconf) {
-               km= WM_keymap_list_find(&keyconf->keymaps, keymap->idname, keymap->spaceid, keymap->regionid);
-               if(km) {
-                       km->poll= keymap->poll; /* lazy init */
-                       km->modal_items= keymap->modal_items;
-                       return km;
-               }
-       }
+               keymap= WM_keymap_list_find(&wm->defaultconf->keymaps, km->idname, km->spaceid, km->regionid);
 
-       /* then use default */
-       km= WM_keymap_list_find(&wm->defaultconf->keymaps, keymap->idname, keymap->spaceid, keymap->regionid);
-       return km;
+       return keymap;
 }
 
-wmKeyMap *WM_keymap_copy_to_user(wmKeyMap *keymap)
+void WM_keyconfig_update(wmWindowManager *wm)
 {
-       wmKeyMap *usermap;
+       wmKeyMap *km, *defaultmap, *addonmap, *usermap;
        wmKeyMapItem *kmi;
+       wmKeyMapDiffItem *kmdi;
+       int compat_update = 0;
 
-       usermap= WM_keymap_list_find(&U.keymaps, keymap->idname, keymap->spaceid, keymap->regionid);
-
-       /* XXX this function is only used by RMB setting hotkeys, and it clears maps on 2nd try this way */
-       if(keymap==usermap)
-               return keymap;
+       if(!WM_KEYMAP_UPDATE)
+               return;
        
-       if(!usermap) {
-               /* not saved yet, duplicate existing */
-               usermap= MEM_dupallocN(keymap);
-               usermap->modal_items= NULL;
-               usermap->poll= NULL;
-               usermap->flag |= KEYMAP_USER;
+       /* update operator properties for non-modal user keymaps */
+       for(km=U.user_keymaps.first; km; km=km->next) {
+               if((km->flag & KEYMAP_MODAL) == 0) {
+                       for(kmdi=km->diff_items.first; kmdi; kmdi=kmdi->next) {
+                               if(kmdi->add_item)
+                                       wm_keymap_item_properties_set(kmdi->add_item);
+                               if(kmdi->remove_item)
+                                       wm_keymap_item_properties_set(kmdi->remove_item);
+                       }
 
-               BLI_addtail(&U.keymaps, usermap);
+                       for(kmi=km->items.first; kmi; kmi=kmi->next)
+                               wm_keymap_item_properties_set(kmi);
+               }
        }
-       else {
-               /* already saved, free items for re-copy */
-               WM_keymap_free(usermap);
+
+       /* update U.user_keymaps with user key configuration changes */
+       for(km=wm->userconf->keymaps.first; km; km=km->next) {
+               /* only diff if the user keymap was modified */
+               if(wm_keymap_test_and_clear_update(km)) {
+                       /* find keymaps */
+                       defaultmap= wm_keymap_preset(wm, km);
+                       addonmap= WM_keymap_list_find(&wm->addonconf->keymaps, km->idname, km->spaceid, km->regionid);
+
+                       /* diff */
+                       wm_keymap_diff_update(&U.user_keymaps, defaultmap, addonmap, km);
+               }
        }
 
-       BLI_duplicatelist(&usermap->items, &keymap->items);
+       /* create user key configuration from preset + addon + user preferences */
+       for(km=wm->defaultconf->keymaps.first; km; km=km->next) {
+               /* find keymaps */
+               defaultmap= wm_keymap_preset(wm, km);
+               addonmap= WM_keymap_list_find(&wm->addonconf->keymaps, km->idname, km->spaceid, km->regionid);
+               usermap= WM_keymap_list_find(&U.user_keymaps, km->idname, km->spaceid, km->regionid);
 
-       for(kmi=usermap->items.first; kmi; kmi=kmi->next) {
-               if(kmi->properties) {
-                       kmi->ptr= MEM_callocN(sizeof(PointerRNA), "UserKeyMapItemPtr");
-                       WM_operator_properties_create(kmi->ptr, kmi->idname);
+               /* add */
+               wm_keymap_patch_update(&wm->userconf->keymaps, defaultmap, addonmap, usermap);
 
-                       kmi->properties= IDP_CopyProperty(kmi->properties);
-                       kmi->ptr->data= kmi->properties;
-               }
+               /* in case of old non-diff keymaps, force extra update to create diffs */
+               compat_update = compat_update || (usermap && !(usermap->flag & KEYMAP_DIFF));
        }
 
-       for(kmi=keymap->items.first; kmi; kmi=kmi->next)
-               kmi->flag &= ~KMI_EXPANDED;
+       WM_KEYMAP_UPDATE= 0;
+
+       if(compat_update) {
+               WM_keyconfig_update_tag(NULL, NULL);
+               WM_keyconfig_update(wm);
+       }
+}
+
+/********************************* Event Handling *****************************
+ * Handlers have pointers to the keymap in the default configuration. During
+ * event handling this function is called to get the keymap from the final
+ * configuration. */
+
+wmKeyMap *WM_keymap_active(wmWindowManager *wm, wmKeyMap *keymap)
+{
+       wmKeyMap *km;
+
+       if(!keymap)
+               return NULL;
+       
+       /* first user defined keymaps */
+       km= WM_keymap_list_find(&wm->userconf->keymaps, keymap->idname, keymap->spaceid, keymap->regionid);
+
+       if(km)
+               return km;
 
-       return usermap;
+       return keymap;
 }
 
+/******************************* Keymap Editor ********************************
+ * In the keymap editor the user key configuration is edited. */
+
 void WM_keymap_restore_item_to_default(bContext *C, wmKeyMap *keymap, wmKeyMapItem *kmi)
 {
        wmWindowManager *wm = CTX_wm_manager(C);
-       wmKeyConfig *keyconf;
-       wmKeyMap *km = NULL;
+       wmKeyMap *defaultmap, *addonmap;
+       wmKeyMapItem *orig;
 
-       /* look in user key config */
-       keyconf= wm_keyconfig_list_find(&wm->keyconfigs, U.keyconfigstr);
-       if(keyconf) {
-               km= WM_keymap_list_find(&keyconf->keymaps, keymap->idname, keymap->spaceid, keymap->regionid);
-       }
+       if(!keymap)
+               return;
+
+       /* construct default keymap from preset + addons */
+       defaultmap= wm_keymap_preset(wm, keymap);
+       addonmap= WM_keymap_list_find(&wm->addonconf->keymaps, keymap->idname, keymap->spaceid, keymap->regionid);
 
-       if (!km) {
-               /* or from default */
-               km= WM_keymap_list_find(&wm->defaultconf->keymaps, keymap->idname, keymap->spaceid, keymap->regionid);
+       if(addonmap) {
+               defaultmap = wm_keymap_copy(defaultmap);
+               wm_keymap_addon_add(defaultmap, addonmap);
        }
 
-       if (km) {
-               wmKeyMapItem *orig = WM_keymap_item_find_id(km, kmi->id);
+       /* find original item */
+       orig = WM_keymap_item_find_id(defaultmap, kmi->id);
 
-               if (orig) {
-                       if(strcmp(orig->idname, kmi->idname) != 0) {
-                               BLI_strncpy(kmi->idname, orig->idname, sizeof(kmi->idname));
+       if(orig) {
+               /* restore to original */
+               if(strcmp(orig->idname, kmi->idname) != 0) {
+                       BLI_strncpy(kmi->idname, orig->idname, sizeof(kmi->idname));
+                       WM_keymap_properties_reset(kmi, NULL);
+               }
 
-                               WM_keymap_properties_reset(kmi, NULL);
-                       }
-                       
-                       if (orig->properties) {
-                               kmi->properties= IDP_CopyProperty(orig->properties);
-                               kmi->ptr->data= kmi->properties;
+               if (orig->properties) {
+                       if(kmi->properties) {
+                               IDP_FreeProperty(kmi->properties);
+                               MEM_freeN(kmi->properties);
+                               kmi->properties= NULL;
                        }
 
-                       kmi->propvalue = orig->propvalue;
-                       kmi->type = orig->type;
-                       kmi->val = orig->val;
-                       kmi->shift = orig->shift;
-                       kmi->ctrl = orig->ctrl;
-                       kmi->alt = orig->alt;
-                       kmi->oskey = orig->oskey;
-                       kmi->keymodifier = orig->keymodifier;
-                       kmi->maptype = orig->maptype;
-
+                       kmi->properties= IDP_CopyProperty(orig->properties);
+                       kmi->ptr->data= kmi->properties;
                }
 
+               kmi->propvalue = orig->propvalue;
+               kmi->type = orig->type;
+               kmi->val = orig->val;
+               kmi->shift = orig->shift;
+               kmi->ctrl = orig->ctrl;
+               kmi->alt = orig->alt;
+               kmi->oskey = orig->oskey;
+               kmi->keymodifier = orig->keymodifier;
+               kmi->maptype = orig->maptype;
+
+               WM_keyconfig_update_tag(keymap, kmi);
+       }
+
+       /* free temporary keymap */
+       if(addonmap) {
+               WM_keymap_free(defaultmap);
+               MEM_freeN(defaultmap);
        }
 }
 
-void WM_keymap_restore_to_default(wmKeyMap *keymap)
+void WM_keymap_restore_to_default(wmKeyMap *keymap, bContext *C)
 {
+       wmWindowManager *wm = CTX_wm_manager(C);
        wmKeyMap *usermap;
 
-       usermap= WM_keymap_list_find(&U.keymaps, keymap->idname, keymap->spaceid, keymap->regionid);
+       /* remove keymap from U.user_keymaps and update */
+       usermap= WM_keymap_list_find(&U.user_keymaps, keymap->idname, keymap->spaceid, keymap->regionid);
 
        if(usermap) {
                WM_keymap_free(usermap);
-               BLI_freelinkN(&U.keymaps, usermap);
+               BLI_freelinkN(&U.user_keymaps, usermap);
+
+               WM_keyconfig_update_tag(NULL, NULL);
+               WM_keyconfig_update(wm);
        }
 }
 
@@ -951,3 +1332,4 @@ wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname)
        
        return km;
 }
+
index 548d272..983d4ec 100644 (file)
@@ -208,10 +208,12 @@ struct wmKeyMap *WM_keymap_list_find(struct ListBase *lb, char *idname, int spac
 struct wmKeyConfig *WM_keyconfig_new(struct wmWindowManager *wm, char *idname){return (struct wmKeyConfig *) NULL;}
 struct wmKeyConfig *WM_keyconfig_new_user(struct wmWindowManager *wm, char *idname){return (struct wmKeyConfig *) NULL;}
 void WM_keyconfig_remove(struct wmWindowManager *wm, char *idname){}
+void WM_keyconfig_set_active(struct wmWindowManager *wm, const char *idname) {}
 void WM_keymap_remove_item(struct wmKeyMap *keymap, struct wmKeyMapItem *kmi){}
 void WM_keymap_restore_to_default(struct wmKeyMap *keymap){}
 void WM_keymap_restore_item_to_default(struct bContext *C, struct wmKeyMap *keymap, struct wmKeyMapItem *kmi){}
 void WM_keymap_properties_reset(struct wmKeyMapItem *kmi){}
+void WM_keyconfig_update_tag(struct wmKeyMap *keymap, struct wmKeyMapItem *kmi) {}
 int WM_keymap_user_init(struct wmWindowManager *wm, struct wmKeyMap *keymap) {return 0;}
 int WM_keymap_item_compare(struct wmKeyMapItem *k1, struct wmKeyMapItem *k2){return 0;}