diff options
Diffstat (limited to 'source/blender/windowmanager')
-rw-r--r-- | source/blender/windowmanager/WM_api.h | 44 | ||||
-rw-r--r-- | source/blender/windowmanager/WM_keymap.h | 104 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm.c | 10 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_event_system.c | 6 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_files.c | 13 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_keymap.c | 718 |
6 files changed, 682 insertions, 213 deletions
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index e6325e2101a..42c3096dfc9 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -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 index 00000000000..e00cd288c9a --- /dev/null +++ b/source/blender/windowmanager/WM_keymap.h @@ -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 */ + diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c index a535c0bc1f8..1d5cf1cdc53 100644 --- a/source/blender/windowmanager/intern/wm.c +++ b/source/blender/windowmanager/intern/wm.c @@ -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; } diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 2f0c1a72be9..0dac0bd7401 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -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 ************ */ diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index 27fc0caeccc..20f9d2237c2 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -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); 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; } + |