Merge branch 'master' into blender2.8
[blender.git] / source / blender / editors / space_outliner / outliner_ops.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2008 Blender Foundation.
19  * All rights reserved.
20  *
21  *
22  * Contributor(s): Blender Foundation
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 /** \file blender/editors/space_outliner/outliner_ops.c
28  *  \ingroup spoutliner
29  */
30
31 #include "MEM_guardedalloc.h"
32
33 #include "BLI_listbase.h"
34 #include "BLI_math.h"
35
36 #include "DNA_group_types.h"
37
38 #include "BLT_translation.h"
39
40 #include "BKE_context.h"
41 #include "BKE_main.h"
42
43 #include "GPU_immediate.h"
44 #include "GPU_state.h"
45
46 #include "RNA_access.h"
47
48 #include "UI_interface.h"
49 #include "UI_view2d.h"
50
51 #include "WM_api.h"
52 #include "WM_types.h"
53
54 #include "ED_screen.h"
55
56 #include "outliner_intern.h"
57
58 typedef struct OutlinerDragDropTooltip {
59         TreeElement *te;
60         void *handle;
61 } OutlinerDragDropTooltip;
62
63 enum {
64         OUTLINER_ITEM_DRAG_CANCEL,
65         OUTLINER_ITEM_DRAG_CONFIRM,
66 };
67
68 static bool outliner_item_drag_drop_poll(bContext *C)
69 {
70         SpaceOops *soops = CTX_wm_space_outliner(C);
71         return ED_operator_outliner_active(C) &&
72                /* Only collection display modes supported for now. Others need more design work */
73                ELEM(soops->outlinevis, SO_VIEW_LAYER, SO_LIBRARIES);
74 }
75
76 static TreeElement *outliner_item_drag_element_find(SpaceOops *soops, ARegion *ar, const wmEvent *event)
77 {
78         /* note: using EVT_TWEAK_ events to trigger dragging is fine,
79          * it sends coordinates from where dragging was started */
80         const float my = UI_view2d_region_to_view_y(&ar->v2d, event->mval[1]);
81         return outliner_find_item_at_y(soops, &soops->tree, my);
82 }
83
84 static void outliner_item_drag_end(wmWindow *win, OutlinerDragDropTooltip *data)
85 {
86         MEM_SAFE_FREE(data->te->drag_data);
87
88         if (data->handle) {
89                 WM_draw_cb_exit(win, data->handle);
90         }
91
92         MEM_SAFE_FREE(data);
93 }
94
95 static void outliner_item_drag_get_insert_data(
96         const SpaceOops *soops, ARegion *ar, const wmEvent *event, TreeElement *te_dragged,
97         TreeElement **r_te_insert_handle, TreeElementInsertType *r_insert_type)
98 {
99         TreeElement *te_hovered;
100         float view_mval[2];
101
102         UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &view_mval[0], &view_mval[1]);
103         te_hovered = outliner_find_item_at_y(soops, &soops->tree, view_mval[1]);
104
105         if (te_hovered) {
106                 /* mouse hovers an element (ignoring x-axis), now find out how to insert the dragged item exactly */
107
108                 if (te_hovered == te_dragged) {
109                         *r_te_insert_handle = te_dragged;
110                 }
111                 else if (te_hovered != te_dragged) {
112                         const float margin = UI_UNIT_Y * (1.0f / 4);
113
114                         *r_te_insert_handle = te_hovered;
115                         if (view_mval[1] < (te_hovered->ys + margin)) {
116                                 if (TSELEM_OPEN(TREESTORE(te_hovered), soops)) {
117                                         /* inserting after a open item means we insert into it, but as first child */
118                                         if (BLI_listbase_is_empty(&te_hovered->subtree)) {
119                                                 *r_insert_type = TE_INSERT_INTO;
120                                         }
121                                         else {
122                                                 *r_insert_type = TE_INSERT_BEFORE;
123                                                 *r_te_insert_handle = te_hovered->subtree.first;
124                                         }
125                                 }
126                                 else {
127                                         *r_insert_type = TE_INSERT_AFTER;
128                                 }
129                         }
130                         else if (view_mval[1] > (te_hovered->ys + (3 * margin))) {
131                                 *r_insert_type = TE_INSERT_BEFORE;
132                         }
133                         else {
134                                 *r_insert_type = TE_INSERT_INTO;
135                         }
136                 }
137         }
138         else {
139                 /* mouse doesn't hover any item (ignoring x-axis), so it's either above list bounds or below. */
140
141                 TreeElement *first = soops->tree.first;
142                 TreeElement *last = soops->tree.last;
143
144                 if (view_mval[1] < last->ys) {
145                         *r_te_insert_handle = last;
146                         *r_insert_type = TE_INSERT_AFTER;
147                 }
148                 else if (view_mval[1] > (first->ys + UI_UNIT_Y)) {
149                         *r_te_insert_handle = first;
150                         *r_insert_type = TE_INSERT_BEFORE;
151                 }
152                 else {
153                         BLI_assert(0);
154                 }
155         }
156 }
157
158 static void outliner_item_drag_handle(
159         SpaceOops *soops, ARegion *ar, const wmEvent *event, TreeElement *te_dragged)
160 {
161         TreeElement *te_insert_handle;
162         TreeElementInsertType insert_type;
163
164         outliner_item_drag_get_insert_data(soops, ar, event, te_dragged, &te_insert_handle, &insert_type);
165
166         if (!te_dragged->reinsert_poll &&
167             /* there is no reinsert_poll, so we do some generic checks (same types and reinsert callback is available) */
168             (TREESTORE(te_dragged)->type == TREESTORE(te_insert_handle)->type) &&
169             te_dragged->reinsert)
170         {
171                 /* pass */
172         }
173         else if (te_dragged == te_insert_handle) {
174                 /* nothing will happen anyway, no need to do poll check */
175         }
176         else if (!te_dragged->reinsert_poll ||
177                  !te_dragged->reinsert_poll(te_dragged, &te_insert_handle, &insert_type))
178         {
179                 te_insert_handle = NULL;
180         }
181         te_dragged->drag_data->insert_type = insert_type;
182         te_dragged->drag_data->insert_handle = te_insert_handle;
183 }
184
185 /**
186  * Returns true if it is a collection and empty.
187  */
188 static bool is_empty_collection(TreeElement *te)
189 {
190         Collection *collection = outliner_collection_from_tree_element(te);
191
192         if (!collection) {
193                 return false;
194         }
195
196         return BLI_listbase_is_empty(&collection->gobject) &&
197                BLI_listbase_is_empty(&collection->children);
198 }
199
200 static bool outliner_item_drag_drop_apply(
201         Main *bmain,
202         Scene *scene,
203         SpaceOops *soops,
204         OutlinerDragDropTooltip *data,
205         const wmEvent *event)
206 {
207         TreeElement *dragged_te = data->te;
208         TreeElement *insert_handle = dragged_te->drag_data->insert_handle;
209         TreeElementInsertType insert_type = dragged_te->drag_data->insert_type;
210
211         if ((insert_handle == dragged_te) || !insert_handle) {
212                 /* No need to do anything */
213         }
214         else if (dragged_te->reinsert) {
215                 BLI_assert(!dragged_te->reinsert_poll || dragged_te->reinsert_poll(dragged_te, &insert_handle,
216                                                                                    &insert_type));
217                 /* call of assert above should not have changed insert_handle and insert_type at this point */
218                 BLI_assert(dragged_te->drag_data->insert_handle == insert_handle &&
219                            dragged_te->drag_data->insert_type == insert_type);
220
221                 /* If the collection was just created and you moved objects/collections inside it,
222                  * it is strange to have it closed and we not see the newly dragged elements. */
223                 const bool should_open_collection = (insert_type == TE_INSERT_INTO) && is_empty_collection(insert_handle);
224
225                 dragged_te->reinsert(bmain, scene, soops, dragged_te, insert_handle, insert_type, event);
226
227                 if (should_open_collection && !is_empty_collection(insert_handle)) {
228                         TREESTORE(insert_handle)->flag &= ~TSE_CLOSED;
229                 }
230                 return true;
231         }
232
233         return false;
234 }
235
236 static int outliner_item_drag_drop_modal(bContext *C, wmOperator *op, const wmEvent *event)
237 {
238         Main *bmain = CTX_data_main(C);
239         Scene *scene = CTX_data_scene(C);
240         ARegion *ar = CTX_wm_region(C);
241         SpaceOops *soops = CTX_wm_space_outliner(C);
242         OutlinerDragDropTooltip *data = op->customdata;
243         TreeElement *te_dragged = data->te;
244         int retval = OPERATOR_RUNNING_MODAL;
245         bool redraw = false;
246         bool skip_rebuild = true;
247
248         switch (event->type) {
249                 case EVT_MODAL_MAP:
250                         if (event->val == OUTLINER_ITEM_DRAG_CONFIRM) {
251                                 if (outliner_item_drag_drop_apply(bmain, scene, soops, data, event)) {
252                                         skip_rebuild = false;
253                                 }
254                                 retval = OPERATOR_FINISHED;
255                         }
256                         else if (event->val == OUTLINER_ITEM_DRAG_CANCEL) {
257                                 retval = OPERATOR_CANCELLED;
258                         }
259                         else {
260                                 BLI_assert(0);
261                         }
262                         WM_event_add_mousemove(C); /* update highlight */
263                         outliner_item_drag_end(CTX_wm_window(C), data);
264                         redraw = true;
265                         break;
266                 case MOUSEMOVE:
267                         outliner_item_drag_handle(soops, ar, event, te_dragged);
268                         redraw = true;
269                         break;
270         }
271
272         if (redraw) {
273                 if (skip_rebuild) {
274                         ED_region_tag_redraw_no_rebuild(ar);
275                 }
276                 else {
277                         ED_region_tag_redraw(ar);
278                 }
279         }
280
281         return retval;
282 }
283
284 static const char *outliner_drag_drop_tooltip_get(
285         const TreeElement *te_float)
286 {
287         const char *name = NULL;
288
289         const TreeElement *te_insert = te_float->drag_data->insert_handle;
290         if (te_float && outliner_is_collection_tree_element(te_float)) {
291                 if (te_insert == NULL) {
292                         name = TIP_("Move collection");
293                 }
294                 else {
295                         switch (te_float->drag_data->insert_type) {
296                                 case TE_INSERT_BEFORE:
297                                         if (te_insert->prev && outliner_is_collection_tree_element(te_insert->prev)) {
298                                                 name = TIP_("Move between collections");
299                                         }
300                                         else {
301                                                 name = TIP_("Move before collection");
302                                         }
303                                         break;
304                                 case TE_INSERT_AFTER:
305                                         if (te_insert->next && outliner_is_collection_tree_element(te_insert->next)) {
306                                                 name = TIP_("Move between collections");
307                                         }
308                                         else {
309                                                 name = TIP_("Move after collection");
310                                         }
311                                         break;
312                                 case TE_INSERT_INTO:
313                                         name = TIP_("Move inside collection");
314                                         break;
315                         }
316                 }
317         }
318         else if ((TREESTORE(te_float)->type == 0) && (te_float->idcode == ID_OB)) {
319                 name = TIP_("Move to collection (Ctrl to link)");
320         }
321
322         return name;
323 }
324
325 static void outliner_drag_drop_tooltip_cb(const wmWindow *win, void *vdata)
326 {
327         OutlinerDragDropTooltip *data = vdata;
328         const char *tooltip;
329
330         int cursorx, cursory;
331         int x, y;
332
333         tooltip = outliner_drag_drop_tooltip_get(data->te);
334         if (tooltip == NULL) {
335                 return;
336         }
337
338         cursorx = win->eventstate->x;
339         cursory = win->eventstate->y;
340
341         x = cursorx + U.widget_unit;
342         y = cursory - U.widget_unit;
343
344         /* Drawing. */
345         const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
346
347         const float col_fg[4] = {1.0f, 1.0f, 1.0f, 1.0f};
348         const float col_bg[4] = {0.0f, 0.0f, 0.0f, 0.2f};
349
350         GPU_blend(true);
351         UI_fontstyle_draw_simple_backdrop(fstyle, x, y, tooltip, col_fg, col_bg);
352         GPU_blend(false);
353 }
354
355 static int outliner_item_drag_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
356 {
357         ARegion *ar = CTX_wm_region(C);
358         SpaceOops *soops = CTX_wm_space_outliner(C);
359         TreeElement *te_dragged = outliner_item_drag_element_find(soops, ar, event);
360
361         if (!te_dragged) {
362                 return (OPERATOR_FINISHED | OPERATOR_PASS_THROUGH);
363         }
364
365         OutlinerDragDropTooltip *data = MEM_mallocN(sizeof(OutlinerDragDropTooltip), __func__);
366         data->te = te_dragged;
367
368         op->customdata = data;
369         te_dragged->drag_data = MEM_callocN(sizeof(*te_dragged->drag_data), __func__);
370         /* by default we don't change the item position */
371         te_dragged->drag_data->insert_handle = te_dragged;
372         /* unset highlighted tree element, dragged one will be highlighted instead */
373         outliner_flag_set(&soops->tree, TSE_HIGHLIGHTED, false);
374
375         ED_region_tag_redraw_no_rebuild(ar);
376
377         WM_event_add_modal_handler(C, op);
378
379         data->handle = WM_draw_cb_activate(CTX_wm_window(C), outliner_drag_drop_tooltip_cb, data);
380
381         return OPERATOR_RUNNING_MODAL;
382 }
383
384 /**
385  * Notes about Outliner Item Drag 'n Drop:
386  * Right now only collections display mode is supported. But ideally all/most modes would support this. There are
387  * just some open design questions that have to be answered: do we want to allow mixing order of different data types
388  * (like render-layers and objects)? Would that be a purely visual change or would that have any other effect? ...
389  */
390 static void OUTLINER_OT_item_drag_drop(wmOperatorType *ot)
391 {
392         ot->name = "Drag and Drop";
393         ot->idname = "OUTLINER_OT_item_drag_drop";
394         ot->description = "Change the hierarchical position of an item by repositioning it using drag and drop";
395
396         ot->invoke = outliner_item_drag_drop_invoke;
397         ot->modal = outliner_item_drag_drop_modal;
398
399         ot->poll = outliner_item_drag_drop_poll;
400
401         ot->flag = OPTYPE_UNDO;
402 }
403
404
405 /* ************************** registration **********************************/
406
407 void outliner_operatortypes(void)
408 {
409         WM_operatortype_append(OUTLINER_OT_highlight_update);
410         WM_operatortype_append(OUTLINER_OT_item_activate);
411         WM_operatortype_append(OUTLINER_OT_select_border);
412         WM_operatortype_append(OUTLINER_OT_item_openclose);
413         WM_operatortype_append(OUTLINER_OT_item_rename);
414         WM_operatortype_append(OUTLINER_OT_item_drag_drop);
415         WM_operatortype_append(OUTLINER_OT_operation);
416         WM_operatortype_append(OUTLINER_OT_scene_operation);
417         WM_operatortype_append(OUTLINER_OT_object_operation);
418         WM_operatortype_append(OUTLINER_OT_lib_operation);
419         WM_operatortype_append(OUTLINER_OT_lib_relocate);
420         WM_operatortype_append(OUTLINER_OT_id_operation);
421         WM_operatortype_append(OUTLINER_OT_id_delete);
422         WM_operatortype_append(OUTLINER_OT_id_remap);
423         WM_operatortype_append(OUTLINER_OT_data_operation);
424         WM_operatortype_append(OUTLINER_OT_animdata_operation);
425         WM_operatortype_append(OUTLINER_OT_action_set);
426         WM_operatortype_append(OUTLINER_OT_constraint_operation);
427         WM_operatortype_append(OUTLINER_OT_modifier_operation);
428
429         WM_operatortype_append(OUTLINER_OT_show_one_level);
430         WM_operatortype_append(OUTLINER_OT_show_active);
431         WM_operatortype_append(OUTLINER_OT_show_hierarchy);
432         WM_operatortype_append(OUTLINER_OT_scroll_page);
433
434         WM_operatortype_append(OUTLINER_OT_selected_toggle);
435         WM_operatortype_append(OUTLINER_OT_expanded_toggle);
436
437         WM_operatortype_append(OUTLINER_OT_keyingset_add_selected);
438         WM_operatortype_append(OUTLINER_OT_keyingset_remove_selected);
439
440         WM_operatortype_append(OUTLINER_OT_drivers_add_selected);
441         WM_operatortype_append(OUTLINER_OT_drivers_delete_selected);
442
443         WM_operatortype_append(OUTLINER_OT_orphans_purge);
444
445         WM_operatortype_append(OUTLINER_OT_parent_drop);
446         WM_operatortype_append(OUTLINER_OT_parent_clear);
447         WM_operatortype_append(OUTLINER_OT_scene_drop);
448         WM_operatortype_append(OUTLINER_OT_material_drop);
449         WM_operatortype_append(OUTLINER_OT_collection_drop);
450
451         /* collections */
452         WM_operatortype_append(OUTLINER_OT_collection_new);
453         WM_operatortype_append(OUTLINER_OT_collection_duplicate);
454         WM_operatortype_append(OUTLINER_OT_collection_delete);
455         WM_operatortype_append(OUTLINER_OT_collection_objects_select);
456         WM_operatortype_append(OUTLINER_OT_collection_objects_deselect);
457         WM_operatortype_append(OUTLINER_OT_collection_link);
458         WM_operatortype_append(OUTLINER_OT_collection_instance);
459         WM_operatortype_append(OUTLINER_OT_collection_exclude_set);
460         WM_operatortype_append(OUTLINER_OT_collection_include_set);
461 }
462
463 static wmKeyMap *outliner_item_drag_drop_modal_keymap(wmKeyConfig *keyconf)
464 {
465         static EnumPropertyItem modal_items[] = {
466                 {OUTLINER_ITEM_DRAG_CANCEL,  "CANCEL",  0, "Cancel", ""},
467                 {OUTLINER_ITEM_DRAG_CONFIRM, "CONFIRM", 0, "Confirm/Drop", ""},
468                 {0, NULL, 0, NULL, NULL}
469         };
470         const char *map_name = "Outliner Item Drag & Drop Modal Map";
471
472         wmKeyMap *keymap = WM_modalkeymap_get(keyconf, map_name);
473
474         /* this function is called for each spacetype, only needs to add map once */
475         if (keymap && keymap->modal_items)
476                 return NULL;
477
478         keymap = WM_modalkeymap_add(keyconf, map_name, modal_items);
479
480         /* items for modal map */
481         WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, OUTLINER_ITEM_DRAG_CANCEL);
482         WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_PRESS, KM_ANY, 0, OUTLINER_ITEM_DRAG_CANCEL);
483
484         WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, KM_ANY, 0, OUTLINER_ITEM_DRAG_CONFIRM);
485         WM_modalkeymap_add_item(keymap, RETKEY, KM_RELEASE, KM_ANY, 0, OUTLINER_ITEM_DRAG_CONFIRM);
486         WM_modalkeymap_add_item(keymap, PADENTER, KM_RELEASE, KM_ANY, 0, OUTLINER_ITEM_DRAG_CONFIRM);
487
488         WM_modalkeymap_assign(keymap, "OUTLINER_OT_item_drag_drop");
489
490         return keymap;
491 }
492
493 void outliner_keymap(wmKeyConfig *keyconf)
494 {
495         wmKeyMap *keymap = WM_keymap_find(keyconf, "Outliner", SPACE_OUTLINER, 0);
496         wmKeyMapItem *kmi;
497
498         WM_keymap_add_item(keymap, "OUTLINER_OT_highlight_update", MOUSEMOVE, KM_ANY, KM_ANY, 0);
499
500         WM_keymap_add_item(keymap, "OUTLINER_OT_item_rename", LEFTMOUSE, KM_DBL_CLICK, 0, 0);
501
502         kmi = WM_keymap_add_item(keymap, "OUTLINER_OT_item_activate", LEFTMOUSE, KM_CLICK, 0, 0);
503         RNA_boolean_set(kmi->ptr, "recursive", false);
504         RNA_boolean_set(kmi->ptr, "extend", false);
505
506         kmi = WM_keymap_add_item(keymap, "OUTLINER_OT_item_activate", LEFTMOUSE, KM_CLICK, KM_SHIFT, 0);
507         RNA_boolean_set(kmi->ptr, "recursive", false);
508         RNA_boolean_set(kmi->ptr, "extend", true);
509
510         kmi = WM_keymap_add_item(keymap, "OUTLINER_OT_item_activate", LEFTMOUSE, KM_CLICK, KM_CTRL, 0);
511         RNA_boolean_set(kmi->ptr, "recursive", true);
512         RNA_boolean_set(kmi->ptr, "extend", false);
513
514         kmi = WM_keymap_add_item(keymap, "OUTLINER_OT_item_activate", LEFTMOUSE, KM_CLICK, KM_CTRL | KM_SHIFT, 0);
515         RNA_boolean_set(kmi->ptr, "recursive", true);
516         RNA_boolean_set(kmi->ptr, "extend", true);
517
518
519         WM_keymap_add_item(keymap, "OUTLINER_OT_select_border", BKEY, KM_PRESS, 0, 0);
520
521         kmi = WM_keymap_add_item(keymap, "OUTLINER_OT_item_openclose", RETKEY, KM_PRESS, 0, 0);
522         RNA_boolean_set(kmi->ptr, "all", false);
523         kmi = WM_keymap_add_item(keymap, "OUTLINER_OT_item_openclose", RETKEY, KM_PRESS, KM_SHIFT, 0);
524         RNA_boolean_set(kmi->ptr, "all", true);
525
526         WM_keymap_add_item(keymap, "OUTLINER_OT_item_rename", LEFTMOUSE, KM_PRESS, KM_CTRL, 0);
527         WM_keymap_add_item(keymap, "OUTLINER_OT_operation", RIGHTMOUSE, KM_PRESS, 0, 0);
528
529         WM_keymap_add_item(keymap, "OUTLINER_OT_item_drag_drop", EVT_TWEAK_L, KM_ANY, 0, 0);
530
531         WM_keymap_add_item(keymap, "OUTLINER_OT_show_hierarchy", HOMEKEY, KM_PRESS, 0, 0);
532
533         WM_keymap_add_item(keymap, "OUTLINER_OT_show_active", PERIODKEY, KM_PRESS, 0, 0);
534         WM_keymap_add_item(keymap, "OUTLINER_OT_show_active", PADPERIOD, KM_PRESS, 0, 0);
535
536         kmi = WM_keymap_add_item(keymap, "OUTLINER_OT_scroll_page", PAGEDOWNKEY, KM_PRESS, 0, 0);
537         RNA_boolean_set(kmi->ptr, "up", false);
538         kmi = WM_keymap_add_item(keymap, "OUTLINER_OT_scroll_page", PAGEUPKEY, KM_PRESS, 0, 0);
539         RNA_boolean_set(kmi->ptr, "up", true);
540
541         WM_keymap_add_item(keymap, "OUTLINER_OT_show_one_level", PADPLUSKEY, KM_PRESS, 0, 0); /* open */
542         kmi = WM_keymap_add_item(keymap, "OUTLINER_OT_show_one_level", PADMINUS, KM_PRESS, 0, 0);
543         RNA_boolean_set(kmi->ptr, "open", false); /* close */
544
545         WM_keymap_add_item(keymap, "OUTLINER_OT_selected_toggle", AKEY, KM_PRESS, 0, 0);
546         WM_keymap_add_item(keymap, "OUTLINER_OT_expanded_toggle", AKEY, KM_PRESS, KM_SHIFT, 0);
547
548         /* keying sets - only for databrowse */
549         WM_keymap_add_item(keymap, "OUTLINER_OT_keyingset_add_selected", KKEY, KM_PRESS, 0, 0);
550         WM_keymap_add_item(keymap, "OUTLINER_OT_keyingset_remove_selected", KKEY, KM_PRESS, KM_ALT, 0);
551
552         WM_keymap_add_item(keymap, "ANIM_OT_keyframe_insert", IKEY, KM_PRESS, 0, 0);
553         WM_keymap_add_item(keymap, "ANIM_OT_keyframe_delete", IKEY, KM_PRESS, KM_ALT, 0);
554
555         /* Note: was D, Alt-D, keep these free for duplicate. */
556         WM_keymap_add_item(keymap, "OUTLINER_OT_drivers_add_selected", DKEY, KM_PRESS, KM_CTRL, 0);
557         WM_keymap_add_item(keymap, "OUTLINER_OT_drivers_delete_selected", DKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
558
559         WM_keymap_add_item(keymap, "OUTLINER_OT_collection_new", CKEY, KM_PRESS, 0, 0);
560
561         WM_keymap_add_item(keymap, "OUTLINER_OT_collection_delete", XKEY, KM_PRESS, 0, 0);
562         WM_keymap_add_item(keymap, "OUTLINER_OT_collection_delete", DELKEY, KM_PRESS, 0, 0);
563
564         WM_keymap_add_item(keymap, "OBJECT_OT_move_to_collection", MKEY, KM_PRESS, 0, 0);
565         WM_keymap_add_item(keymap, "OBJECT_OT_link_to_collection", MKEY, KM_PRESS, KM_SHIFT, 0);
566
567         kmi = WM_keymap_add_item(keymap, "OBJECT_OT_hide_view_clear", HKEY, KM_PRESS, KM_ALT, 0);
568         RNA_boolean_set(kmi->ptr, "select", false);
569         kmi = WM_keymap_add_item(keymap, "OBJECT_OT_hide_view_set", HKEY, KM_PRESS, 0, 0);
570         RNA_boolean_set(kmi->ptr, "unselected", false);
571         kmi = WM_keymap_add_item(keymap, "OBJECT_OT_hide_view_set", HKEY, KM_PRESS, KM_SHIFT, 0);
572         RNA_boolean_set(kmi->ptr, "unselected", true);
573
574         outliner_item_drag_drop_modal_keymap(keyconf);
575 }