1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
17 /** \file
18  * \ingroup bke
19  */
20 
21 #include <stddef.h>
22 #include <stdlib.h>
23 
24 #include "RNA_types.h"
25 
26 #include "BLI_ghash.h"
27 #include "BLI_listbase.h"
28 #include "BLI_string.h"
29 #include "BLI_utildefines.h"
30 
31 #include "DNA_listBase.h"
32 #include "DNA_userdef_types.h"
33 #include "DNA_windowmanager_types.h"
34 
35 #include "BKE_idprop.h"
36 #include "BKE_keyconfig.h" /* own include */
37 
38 #include "MEM_guardedalloc.h"
39 
40 /* -------------------------------------------------------------------- */
41 /** \name Key-Config Preference (UserDef) API
42  *
43  * \see #BKE_addon_pref_type_init for logic this is bases on.
44  * \{ */
45 
BKE_keyconfig_pref_ensure(UserDef * userdef,const char * kc_idname)46 wmKeyConfigPref *BKE_keyconfig_pref_ensure(UserDef *userdef, const char *kc_idname)
47 {
48   wmKeyConfigPref *kpt = BLI_findstring(
49       &userdef->user_keyconfig_prefs, kc_idname, offsetof(wmKeyConfigPref, idname));
50   if (kpt == NULL) {
51     kpt = MEM_callocN(sizeof(*kpt), __func__);
52     STRNCPY(kpt->idname, kc_idname);
53     BLI_addtail(&userdef->user_keyconfig_prefs, kpt);
54   }
55   if (kpt->prop == NULL) {
56     IDPropertyTemplate val = {0};
57     kpt->prop = IDP_New(IDP_GROUP, &val, kc_idname); /* name is unimportant  */
58   }
59   return kpt;
60 }
61 
62 /** \} */
63 
64 /* -------------------------------------------------------------------- */
65 /** \name Key-Config Preference (RNA Type) API
66  *
67  * \see #BKE_addon_pref_type_init for logic this is bases on.
68  * \{ */
69 
70 static GHash *global_keyconfigpreftype_hash = NULL;
71 
BKE_keyconfig_pref_type_find(const char * idname,bool quiet)72 wmKeyConfigPrefType_Runtime *BKE_keyconfig_pref_type_find(const char *idname, bool quiet)
73 {
74   if (idname[0]) {
75     wmKeyConfigPrefType_Runtime *kpt_rt;
76 
77     kpt_rt = BLI_ghash_lookup(global_keyconfigpreftype_hash, idname);
78     if (kpt_rt) {
79       return kpt_rt;
80     }
81 
82     if (!quiet) {
83       printf("search for unknown keyconfig-pref '%s'\n", idname);
84     }
85   }
86   else {
87     if (!quiet) {
88       printf("search for empty keyconfig-pref\n");
89     }
90   }
91 
92   return NULL;
93 }
94 
BKE_keyconfig_pref_type_add(wmKeyConfigPrefType_Runtime * kpt_rt)95 void BKE_keyconfig_pref_type_add(wmKeyConfigPrefType_Runtime *kpt_rt)
96 {
97   BLI_ghash_insert(global_keyconfigpreftype_hash, kpt_rt->idname, kpt_rt);
98 }
99 
BKE_keyconfig_pref_type_remove(const wmKeyConfigPrefType_Runtime * kpt_rt)100 void BKE_keyconfig_pref_type_remove(const wmKeyConfigPrefType_Runtime *kpt_rt)
101 {
102   BLI_ghash_remove(global_keyconfigpreftype_hash, kpt_rt->idname, NULL, MEM_freeN);
103 }
104 
BKE_keyconfig_pref_type_init(void)105 void BKE_keyconfig_pref_type_init(void)
106 {
107   BLI_assert(global_keyconfigpreftype_hash == NULL);
108   global_keyconfigpreftype_hash = BLI_ghash_str_new(__func__);
109 }
110 
BKE_keyconfig_pref_type_free(void)111 void BKE_keyconfig_pref_type_free(void)
112 {
113   BLI_ghash_free(global_keyconfigpreftype_hash, NULL, MEM_freeN);
114   global_keyconfigpreftype_hash = NULL;
115 }
116 
117 /** \} */
118 
119 /* -------------------------------------------------------------------- */
120 /** \name Key-Config Versioning
121  * \{ */
122 
123 /* Set select mouse, for versioning code. */
BKE_keyconfig_pref_set_select_mouse(UserDef * userdef,int value,bool override)124 void BKE_keyconfig_pref_set_select_mouse(UserDef *userdef, int value, bool override)
125 {
126   wmKeyConfigPref *kpt = BKE_keyconfig_pref_ensure(userdef, WM_KEYCONFIG_STR_DEFAULT);
127   IDProperty *idprop = IDP_GetPropertyFromGroup(kpt->prop, "select_mouse");
128   if (!idprop) {
129     IDPropertyTemplate tmp = {
130         .i = value,
131     };
132     IDP_AddToGroup(kpt->prop, IDP_New(IDP_INT, &tmp, "select_mouse"));
133   }
134   else if (override) {
135     IDP_Int(idprop) = value;
136   }
137 }
138 
keymap_item_free(wmKeyMapItem * kmi)139 static void keymap_item_free(wmKeyMapItem *kmi)
140 {
141   IDP_FreeProperty(kmi->properties);
142   if (kmi->ptr) {
143     MEM_freeN(kmi->ptr);
144   }
145   MEM_freeN(kmi);
146 }
147 
keymap_diff_item_free(wmKeyMapDiffItem * kmdi)148 static void keymap_diff_item_free(wmKeyMapDiffItem *kmdi)
149 {
150   if (kmdi->add_item) {
151     keymap_item_free(kmdi->add_item);
152   }
153   if (kmdi->remove_item) {
154     keymap_item_free(kmdi->remove_item);
155   }
156   MEM_freeN(kmdi);
157 }
158 
BKE_keyconfig_keymap_filter_item(wmKeyMap * keymap,const struct wmKeyConfigFilterItemParams * params,bool (* filter_fn)(wmKeyMapItem * kmi,void * user_data),void * user_data)159 void BKE_keyconfig_keymap_filter_item(wmKeyMap *keymap,
160                                       const struct wmKeyConfigFilterItemParams *params,
161                                       bool (*filter_fn)(wmKeyMapItem *kmi, void *user_data),
162                                       void *user_data)
163 {
164   if (params->check_diff_item_add || params->check_diff_item_remove) {
165     for (wmKeyMapDiffItem *kmdi = keymap->diff_items.first, *kmdi_next; kmdi; kmdi = kmdi_next) {
166       kmdi_next = kmdi->next;
167       bool remove = false;
168 
169       if (params->check_diff_item_add) {
170         if (kmdi->add_item) {
171           if (filter_fn(kmdi->add_item, user_data)) {
172             remove = true;
173           }
174         }
175       }
176 
177       if (!remove && params->check_diff_item_remove) {
178         if (kmdi->remove_item) {
179           if (filter_fn(kmdi->remove_item, user_data)) {
180             remove = true;
181           }
182         }
183       }
184 
185       if (remove) {
186         BLI_remlink(&keymap->diff_items, kmdi);
187         keymap_diff_item_free(kmdi);
188       }
189     }
190   }
191 
192   if (params->check_item) {
193     for (wmKeyMapItem *kmi = keymap->items.first, *kmi_next; kmi; kmi = kmi_next) {
194       kmi_next = kmi->next;
195       if (filter_fn(kmi, user_data)) {
196         BLI_remlink(&keymap->items, kmi);
197         keymap_item_free(kmi);
198       }
199     }
200   }
201 }
202 
203 /**
204  * Filter & optionally remove key-map items,
205  * intended for versioning, but may be used in other situations too.
206  */
BKE_keyconfig_pref_filter_items(struct UserDef * userdef,const struct wmKeyConfigFilterItemParams * params,bool (* filter_fn)(wmKeyMapItem * kmi,void * user_data),void * user_data)207 void BKE_keyconfig_pref_filter_items(struct UserDef *userdef,
208                                      const struct wmKeyConfigFilterItemParams *params,
209                                      bool (*filter_fn)(wmKeyMapItem *kmi, void *user_data),
210                                      void *user_data)
211 {
212   LISTBASE_FOREACH (wmKeyMap *, keymap, &userdef->user_keymaps) {
213     BKE_keyconfig_keymap_filter_item(keymap, params, filter_fn, user_data);
214   }
215 }
216 
217 /** \} */
218