Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrecht Van Lommel <brechtvanlommel@pandora.be>2011-08-06 00:45:26 +0400
committerBrecht Van Lommel <brechtvanlommel@pandora.be>2011-08-06 00:45:26 +0400
commite6e4c7ef8bd53b06c879302bbfd3d6a00c6c48af (patch)
tree4147f9502e965705092d773380d70792633daffa /source/blender/windowmanager/intern/wm_keymap.c
parent7368298a45f96667a548e10cfe9d227fcf18e114 (diff)
KEYMAP REFACTORING
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.
Diffstat (limited to 'source/blender/windowmanager/intern/wm_keymap.c')
-rw-r--r--source/blender/windowmanager/intern/wm_keymap.c718
1 files changed, 550 insertions, 168 deletions
diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c
index 1720c738dd7..bf48f0e21e4 100644
--- a/source/blender/windowmanager/intern/wm_keymap.c
+++ b/source/blender/windowmanager/intern/wm_keymap.c
@@ -61,14 +61,67 @@
#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;
}
+