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 wm
19  *
20  * Utilities to help define keymaps.
21  */
22 
23 #include <string.h>
24 
25 #include "DNA_object_types.h"
26 #include "DNA_space_types.h"
27 #include "DNA_userdef_types.h"
28 #include "DNA_windowmanager_types.h"
29 
30 #include "BLI_listbase.h"
31 #include "BLI_utildefines.h"
32 
33 #include "BKE_context.h"
34 
35 #include "RNA_access.h"
36 
37 #include "WM_api.h"
38 #include "WM_types.h"
39 
40 /* menu wrapper for WM_keymap_add_item */
41 
42 /* -------------------------------------------------------------------- */
43 /** \name Wrappers for #WM_keymap_add_item
44  * \{ */
45 
46 /* menu wrapper for WM_keymap_add_item */
WM_keymap_add_menu(wmKeyMap * keymap,const char * idname,int type,int val,int modifier,int keymodifier)47 wmKeyMapItem *WM_keymap_add_menu(
48     wmKeyMap *keymap, const char *idname, int type, int val, int modifier, int keymodifier)
49 {
50   wmKeyMapItem *kmi = WM_keymap_add_item(
51       keymap, "WM_OT_call_menu", type, val, modifier, keymodifier);
52   RNA_string_set(kmi->ptr, "name", idname);
53   return kmi;
54 }
55 
WM_keymap_add_menu_pie(wmKeyMap * keymap,const char * idname,int type,int val,int modifier,int keymodifier)56 wmKeyMapItem *WM_keymap_add_menu_pie(
57     wmKeyMap *keymap, const char *idname, int type, int val, int modifier, int keymodifier)
58 {
59   wmKeyMapItem *kmi = WM_keymap_add_item(
60       keymap, "WM_OT_call_menu_pie", type, val, modifier, keymodifier);
61   RNA_string_set(kmi->ptr, "name", idname);
62   return kmi;
63 }
64 
WM_keymap_add_panel(wmKeyMap * keymap,const char * idname,int type,int val,int modifier,int keymodifier)65 wmKeyMapItem *WM_keymap_add_panel(
66     wmKeyMap *keymap, const char *idname, int type, int val, int modifier, int keymodifier)
67 {
68   wmKeyMapItem *kmi = WM_keymap_add_item(
69       keymap, "WM_OT_call_panel", type, val, modifier, keymodifier);
70   RNA_string_set(kmi->ptr, "name", idname);
71   /* TODO: we might want to disable this. */
72   RNA_boolean_set(kmi->ptr, "keep_open", false);
73   return kmi;
74 }
75 
76 /* tool wrapper for WM_keymap_add_item */
WM_keymap_add_tool(wmKeyMap * keymap,const char * idname,int type,int val,int modifier,int keymodifier)77 wmKeyMapItem *WM_keymap_add_tool(
78     wmKeyMap *keymap, const char *idname, int type, int val, int modifier, int keymodifier)
79 {
80   wmKeyMapItem *kmi = WM_keymap_add_item(
81       keymap, "WM_OT_tool_set_by_id", type, val, modifier, keymodifier);
82   RNA_string_set(kmi->ptr, "name", idname);
83   return kmi;
84 }
85 
86 /** Useful for mapping numbers to an enum. */
WM_keymap_add_context_enum_set_items(wmKeyMap * keymap,const EnumPropertyItem * items,const char * data_path,int type_start,int val,int modifier,int keymodifier)87 void WM_keymap_add_context_enum_set_items(wmKeyMap *keymap,
88                                           const EnumPropertyItem *items,
89                                           const char *data_path,
90                                           int type_start,
91                                           int val,
92                                           int modifier,
93                                           int keymodifier)
94 {
95   for (int i = 0, type_offset = 0; items[i].identifier; i++) {
96     if (items[i].identifier[0] == '\0') {
97       continue;
98     }
99     wmKeyMapItem *kmi = WM_keymap_add_item(
100         keymap, "WM_OT_context_set_enum", type_start + type_offset, val, modifier, keymodifier);
101     RNA_string_set(kmi->ptr, "data_path", data_path);
102     RNA_string_set(kmi->ptr, "value", items[i].identifier);
103     type_offset += 1;
104   }
105 }
106 
107 /** \} */
108 
109 /* -------------------------------------------------------------------- */
110 /** \name Introspection
111  * \{ */
112 
WM_keymap_guess_from_context(const bContext * C)113 wmKeyMap *WM_keymap_guess_from_context(const bContext *C)
114 {
115   SpaceLink *sl = CTX_wm_space_data(C);
116   const char *km_id = NULL;
117   if (sl->spacetype == SPACE_VIEW3D) {
118     const enum eContextObjectMode mode = CTX_data_mode_enum(C);
119     switch (mode) {
120       case CTX_MODE_EDIT_MESH:
121         km_id = "Mesh";
122         break;
123       case CTX_MODE_EDIT_CURVE:
124         km_id = "Curve";
125         break;
126       case CTX_MODE_EDIT_SURFACE:
127         km_id = "Curve";
128         break;
129       case CTX_MODE_EDIT_TEXT:
130         km_id = "Font";
131         break;
132       case CTX_MODE_EDIT_ARMATURE:
133         km_id = "Armature";
134         break;
135       case CTX_MODE_EDIT_METABALL:
136         km_id = "Metaball";
137         break;
138       case CTX_MODE_EDIT_LATTICE:
139         km_id = "Lattice";
140         break;
141       case CTX_MODE_POSE:
142         km_id = "Pose";
143         break;
144       case CTX_MODE_SCULPT:
145         km_id = "Sculpt";
146         break;
147       case CTX_MODE_PAINT_WEIGHT:
148         km_id = "Weight Paint";
149         break;
150       case CTX_MODE_PAINT_VERTEX:
151         km_id = "Vertex Paint";
152         break;
153       case CTX_MODE_PAINT_TEXTURE:
154         km_id = "Image Paint";
155         break;
156       case CTX_MODE_PARTICLE:
157         km_id = "Particle";
158         break;
159       case CTX_MODE_OBJECT:
160         km_id = "Object Mode";
161         break;
162       case CTX_MODE_PAINT_GPENCIL:
163         km_id = "Grease Pencil Stroke Paint Mode";
164         break;
165       case CTX_MODE_EDIT_GPENCIL:
166         km_id = "Grease Pencil Stroke Edit Mode";
167         break;
168       case CTX_MODE_SCULPT_GPENCIL:
169         km_id = "Grease Pencil Stroke Sculpt Mode";
170         break;
171       case CTX_MODE_WEIGHT_GPENCIL:
172         km_id = "Grease Pencil Stroke Weight Mode";
173         break;
174       case CTX_MODE_VERTEX_GPENCIL:
175         km_id = "Grease Pencil Stroke Vertex Mode";
176         break;
177     }
178   }
179   else if (sl->spacetype == SPACE_IMAGE) {
180     const SpaceImage *sima = (SpaceImage *)sl;
181     const eSpaceImage_Mode mode = sima->mode;
182     switch (mode) {
183       case SI_MODE_VIEW:
184         km_id = "Image";
185         break;
186       case SI_MODE_PAINT:
187         km_id = "Image Paint";
188         break;
189       case SI_MODE_MASK:
190         km_id = "Mask Editing";
191         break;
192       case SI_MODE_UV:
193         km_id = "UV Editor";
194         break;
195     }
196   }
197   else {
198     return NULL;
199   }
200 
201   wmKeyMap *km = WM_keymap_find_all(CTX_wm_manager(C), km_id, 0, 0);
202   BLI_assert(km);
203   return km;
204 }
205 
206 /* Guess an appropriate keymap from the operator name */
207 /* Needs to be kept up to date with Keymap and Operator naming */
WM_keymap_guess_opname(const bContext * C,const char * opname)208 wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname)
209 {
210   /* Op types purposely skipped  for now:
211    *     BRUSH_OT
212    *     BOID_OT
213    *     BUTTONS_OT
214    *     CONSTRAINT_OT
215    *     PAINT_OT
216    *     ED_OT
217    *     FLUID_OT
218    *     TEXTURE_OT
219    *     UI_OT
220    *     WORLD_OT
221    */
222 
223   wmKeyMap *km = NULL;
224   wmWindowManager *wm = CTX_wm_manager(C);
225   SpaceLink *sl = CTX_wm_space_data(C);
226 
227   /* Window */
228   if (STRPREFIX(opname, "WM_OT") || STRPREFIX(opname, "ED_OT_undo")) {
229     if (STREQ(opname, "WM_OT_tool_set_by_id")) {
230       km = WM_keymap_guess_from_context(C);
231     }
232 
233     if (km == NULL) {
234       km = WM_keymap_find_all(wm, "Window", 0, 0);
235     }
236   }
237   /* Screen & Render */
238   else if (STRPREFIX(opname, "SCREEN_OT") || STRPREFIX(opname, "RENDER_OT") ||
239            STRPREFIX(opname, "SOUND_OT") || STRPREFIX(opname, "SCENE_OT")) {
240     km = WM_keymap_find_all(wm, "Screen", 0, 0);
241   }
242   /* Grease Pencil */
243   else if (STRPREFIX(opname, "GPENCIL_OT")) {
244     km = WM_keymap_find_all(wm, "Grease Pencil", 0, 0);
245   }
246   /* Markers */
247   else if (STRPREFIX(opname, "MARKER_OT")) {
248     km = WM_keymap_find_all(wm, "Markers", 0, 0);
249   }
250   /* Import/Export*/
251   else if (STRPREFIX(opname, "IMPORT_") || STRPREFIX(opname, "EXPORT_")) {
252     km = WM_keymap_find_all(wm, "Window", 0, 0);
253   }
254 
255   /* 3D View */
256   else if (STRPREFIX(opname, "VIEW3D_OT")) {
257     km = WM_keymap_find_all(wm, "3D View", sl->spacetype, 0);
258   }
259   else if (STRPREFIX(opname, "OBJECT_OT")) {
260     /* exception, this needs to work outside object mode too */
261     if (STRPREFIX(opname, "OBJECT_OT_mode_set")) {
262       km = WM_keymap_find_all(wm, "Object Non-modal", 0, 0);
263     }
264     else {
265       km = WM_keymap_find_all(wm, "Object Mode", 0, 0);
266     }
267   }
268   /* Object mode related */
269   else if (STRPREFIX(opname, "GROUP_OT") || STRPREFIX(opname, "MATERIAL_OT") ||
270            STRPREFIX(opname, "PTCACHE_OT") || STRPREFIX(opname, "RIGIDBODY_OT")) {
271     km = WM_keymap_find_all(wm, "Object Mode", 0, 0);
272   }
273 
274   /* Editing Modes */
275   else if (STRPREFIX(opname, "MESH_OT")) {
276     km = WM_keymap_find_all(wm, "Mesh", 0, 0);
277 
278     /* some mesh operators are active in object mode too, like add-prim */
279     if (km && !WM_keymap_poll((bContext *)C, km)) {
280       km = WM_keymap_find_all(wm, "Object Mode", 0, 0);
281     }
282   }
283   else if (STRPREFIX(opname, "CURVE_OT") || STRPREFIX(opname, "SURFACE_OT")) {
284     km = WM_keymap_find_all(wm, "Curve", 0, 0);
285 
286     /* some curve operators are active in object mode too, like add-prim */
287     if (km && !WM_keymap_poll((bContext *)C, km)) {
288       km = WM_keymap_find_all(wm, "Object Mode", 0, 0);
289     }
290   }
291   else if (STRPREFIX(opname, "ARMATURE_OT") || STRPREFIX(opname, "SKETCH_OT")) {
292     km = WM_keymap_find_all(wm, "Armature", 0, 0);
293   }
294   else if (STRPREFIX(opname, "POSE_OT") || STRPREFIX(opname, "POSELIB_OT")) {
295     km = WM_keymap_find_all(wm, "Pose", 0, 0);
296   }
297   else if (STRPREFIX(opname, "SCULPT_OT")) {
298     switch (CTX_data_mode_enum(C)) {
299       case CTX_MODE_SCULPT:
300         km = WM_keymap_find_all(wm, "Sculpt", 0, 0);
301         break;
302       default:
303         break;
304     }
305   }
306   else if (STRPREFIX(opname, "MBALL_OT")) {
307     km = WM_keymap_find_all(wm, "Metaball", 0, 0);
308 
309     /* some mball operators are active in object mode too, like add-prim */
310     if (km && !WM_keymap_poll((bContext *)C, km)) {
311       km = WM_keymap_find_all(wm, "Object Mode", 0, 0);
312     }
313   }
314   else if (STRPREFIX(opname, "LATTICE_OT")) {
315     km = WM_keymap_find_all(wm, "Lattice", 0, 0);
316   }
317   else if (STRPREFIX(opname, "PARTICLE_OT")) {
318     km = WM_keymap_find_all(wm, "Particle", 0, 0);
319   }
320   else if (STRPREFIX(opname, "FONT_OT")) {
321     km = WM_keymap_find_all(wm, "Font", 0, 0);
322   }
323   /* Paint Face Mask */
324   else if (STRPREFIX(opname, "PAINT_OT_face_select")) {
325     km = WM_keymap_find_all(wm, "Paint Face Mask (Weight, Vertex, Texture)", 0, 0);
326   }
327   else if (STRPREFIX(opname, "PAINT_OT")) {
328     /* check for relevant mode */
329     switch (CTX_data_mode_enum(C)) {
330       case CTX_MODE_PAINT_WEIGHT:
331         km = WM_keymap_find_all(wm, "Weight Paint", 0, 0);
332         break;
333       case CTX_MODE_PAINT_VERTEX:
334         km = WM_keymap_find_all(wm, "Vertex Paint", 0, 0);
335         break;
336       case CTX_MODE_PAINT_TEXTURE:
337         km = WM_keymap_find_all(wm, "Image Paint", 0, 0);
338         break;
339       case CTX_MODE_SCULPT:
340         km = WM_keymap_find_all(wm, "Sculpt", 0, 0);
341         break;
342       default:
343         break;
344     }
345   }
346   /* General 2D View, not bound to a specific spacetype. */
347   else if (STRPREFIX(opname, "VIEW2D_OT")) {
348     km = WM_keymap_find_all(wm, "View2D", 0, 0);
349   }
350   /* Image Editor */
351   else if (STRPREFIX(opname, "IMAGE_OT")) {
352     km = WM_keymap_find_all(wm, "Image", sl->spacetype, 0);
353   }
354   /* Clip Editor */
355   else if (STRPREFIX(opname, "CLIP_OT")) {
356     km = WM_keymap_find_all(wm, "Clip", sl->spacetype, 0);
357   }
358   else if (STRPREFIX(opname, "MASK_OT")) {
359     km = WM_keymap_find_all(wm, "Mask Editing", 0, 0);
360   }
361   /* UV Editor */
362   else if (STRPREFIX(opname, "UV_OT")) {
363     /* Hack to allow using UV unwrapping ops from 3DView/editmode.
364      * Mesh keymap is probably not ideal, but best place I could find to put those. */
365     if (sl->spacetype == SPACE_VIEW3D) {
366       km = WM_keymap_find_all(wm, "Mesh", 0, 0);
367       if (km && !WM_keymap_poll((bContext *)C, km)) {
368         km = NULL;
369       }
370     }
371     if (!km) {
372       km = WM_keymap_find_all(wm, "UV Editor", 0, 0);
373     }
374   }
375   /* Node Editor */
376   else if (STRPREFIX(opname, "NODE_OT")) {
377     km = WM_keymap_find_all(wm, "Node Editor", sl->spacetype, 0);
378   }
379   /* Animation Editor Channels */
380   else if (STRPREFIX(opname, "ANIM_OT_channels")) {
381     km = WM_keymap_find_all(wm, "Animation Channels", 0, 0);
382   }
383   /* Animation Generic - after channels */
384   else if (STRPREFIX(opname, "ANIM_OT")) {
385     if (sl->spacetype == SPACE_VIEW3D) {
386       switch (CTX_data_mode_enum(C)) {
387         case CTX_MODE_OBJECT:
388           km = WM_keymap_find_all(wm, "Object Mode", 0, 0);
389           break;
390         case CTX_MODE_POSE:
391           km = WM_keymap_find_all(wm, "Pose", 0, 0);
392           break;
393         default:
394           break;
395       }
396       if (km && !WM_keymap_poll((bContext *)C, km)) {
397         km = NULL;
398       }
399     }
400 
401     if (!km) {
402       km = WM_keymap_find_all(wm, "Animation", 0, 0);
403     }
404   }
405   /* Graph Editor */
406   else if (STRPREFIX(opname, "GRAPH_OT")) {
407     km = WM_keymap_find_all(wm, "Graph Editor", sl->spacetype, 0);
408   }
409   /* Dopesheet Editor */
410   else if (STRPREFIX(opname, "ACTION_OT")) {
411     km = WM_keymap_find_all(wm, "Dopesheet", sl->spacetype, 0);
412   }
413   /* NLA Editor */
414   else if (STRPREFIX(opname, "NLA_OT")) {
415     km = WM_keymap_find_all(wm, "NLA Editor", sl->spacetype, 0);
416   }
417   /* Script */
418   else if (STRPREFIX(opname, "SCRIPT_OT")) {
419     km = WM_keymap_find_all(wm, "Script", sl->spacetype, 0);
420   }
421   /* Text */
422   else if (STRPREFIX(opname, "TEXT_OT")) {
423     km = WM_keymap_find_all(wm, "Text", sl->spacetype, 0);
424   }
425   /* Sequencer */
426   else if (STRPREFIX(opname, "SEQUENCER_OT")) {
427     km = WM_keymap_find_all(wm, "Sequencer", sl->spacetype, 0);
428   }
429   /* Console */
430   else if (STRPREFIX(opname, "CONSOLE_OT")) {
431     km = WM_keymap_find_all(wm, "Console", sl->spacetype, 0);
432   }
433   /* Console */
434   else if (STRPREFIX(opname, "INFO_OT")) {
435     km = WM_keymap_find_all(wm, "Info", sl->spacetype, 0);
436   }
437   /* File browser */
438   else if (STRPREFIX(opname, "FILE_OT")) {
439     km = WM_keymap_find_all(wm, "File Browser", sl->spacetype, 0);
440   }
441   /* Logic Editor */
442   else if (STRPREFIX(opname, "LOGIC_OT")) {
443     km = WM_keymap_find_all(wm, "Logic Editor", sl->spacetype, 0);
444   }
445   /* Outliner */
446   else if (STRPREFIX(opname, "OUTLINER_OT")) {
447     km = WM_keymap_find_all(wm, "Outliner", sl->spacetype, 0);
448   }
449   /* Transform */
450   else if (STRPREFIX(opname, "TRANSFORM_OT")) {
451     /* check for relevant editor */
452     switch (sl->spacetype) {
453       case SPACE_VIEW3D:
454         km = WM_keymap_find_all(wm, "3D View", sl->spacetype, 0);
455         break;
456       case SPACE_GRAPH:
457         km = WM_keymap_find_all(wm, "Graph Editor", sl->spacetype, 0);
458         break;
459       case SPACE_ACTION:
460         km = WM_keymap_find_all(wm, "Dopesheet", sl->spacetype, 0);
461         break;
462       case SPACE_NLA:
463         km = WM_keymap_find_all(wm, "NLA Editor", sl->spacetype, 0);
464         break;
465       case SPACE_IMAGE:
466         km = WM_keymap_find_all(wm, "UV Editor", 0, 0);
467         break;
468       case SPACE_NODE:
469         km = WM_keymap_find_all(wm, "Node Editor", sl->spacetype, 0);
470         break;
471       case SPACE_SEQ:
472         km = WM_keymap_find_all(wm, "Sequencer", sl->spacetype, 0);
473         break;
474     }
475   }
476 
477   return km;
478 }
479 
wm_keymap_item_uses_modifier(wmKeyMapItem * kmi,const int event_modifier)480 static bool wm_keymap_item_uses_modifier(wmKeyMapItem *kmi, const int event_modifier)
481 {
482   if (kmi->ctrl != KM_ANY) {
483     if ((kmi->ctrl == KM_NOTHING) != ((event_modifier & KM_CTRL) == 0)) {
484       return false;
485     }
486   }
487 
488   if (kmi->alt != KM_ANY) {
489     if ((kmi->alt == KM_NOTHING) != ((event_modifier & KM_ALT) == 0)) {
490       return false;
491     }
492   }
493 
494   if (kmi->shift != KM_ANY) {
495     if ((kmi->shift == KM_NOTHING) != ((event_modifier & KM_SHIFT) == 0)) {
496       return false;
497     }
498   }
499 
500   if (kmi->oskey != KM_ANY) {
501     if ((kmi->oskey == KM_NOTHING) != ((event_modifier & KM_OSKEY) == 0)) {
502       return false;
503     }
504   }
505   return true;
506 }
507 
WM_keymap_uses_event_modifier(wmKeyMap * keymap,const int event_modifier)508 bool WM_keymap_uses_event_modifier(wmKeyMap *keymap, const int event_modifier)
509 {
510   LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) {
511     if ((kmi->flag & KMI_INACTIVE) == 0) {
512       if (wm_keymap_item_uses_modifier(kmi, event_modifier)) {
513         return true;
514       }
515     }
516   }
517   return false;
518 }
519 
WM_keymap_fix_linking(void)520 void WM_keymap_fix_linking(void)
521 {
522 }
523 
524 /** \} */
525