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