Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/space_outliner/outliner_ops.c
| Show All 27 Lines | |||||
| * \ingroup spoutliner | * \ingroup spoutliner | ||||
| */ | */ | ||||
| #include "MEM_guardedalloc.h" | #include "MEM_guardedalloc.h" | ||||
| #include "BLI_listbase.h" | #include "BLI_listbase.h" | ||||
| #include "BLI_math.h" | #include "BLI_math.h" | ||||
| #include "DNA_group_types.h" | |||||
| #include "BLT_translation.h" | #include "BLT_translation.h" | ||||
| #include "BKE_context.h" | #include "BKE_context.h" | ||||
| #include "BKE_main.h" | #include "BKE_main.h" | ||||
| #include "GPU_immediate.h" | #include "GPU_immediate.h" | ||||
| #include "RNA_access.h" | #include "RNA_access.h" | ||||
| Show All 18 Lines | enum { | ||||
| OUTLINER_ITEM_DRAG_CONFIRM, | OUTLINER_ITEM_DRAG_CONFIRM, | ||||
| }; | }; | ||||
| static int outliner_item_drag_drop_poll(bContext *C) | static int outliner_item_drag_drop_poll(bContext *C) | ||||
| { | { | ||||
| SpaceOops *soops = CTX_wm_space_outliner(C); | SpaceOops *soops = CTX_wm_space_outliner(C); | ||||
| return ED_operator_outliner_active(C) && | return ED_operator_outliner_active(C) && | ||||
| /* Only collection display modes supported for now. Others need more design work */ | /* Only collection display modes supported for now. Others need more design work */ | ||||
| ELEM(soops->outlinevis, SO_COLLECTIONS, SO_GROUPS); | ELEM(soops->outlinevis, SO_COLLECTIONS, SO_OBJECTS); | ||||
| } | } | ||||
| static TreeElement *outliner_item_drag_element_find(SpaceOops *soops, ARegion *ar, const wmEvent *event) | static TreeElement *outliner_item_drag_element_find(SpaceOops *soops, ARegion *ar, const wmEvent *event) | ||||
| { | { | ||||
| /* note: using EVT_TWEAK_ events to trigger dragging is fine, | /* note: using EVT_TWEAK_ events to trigger dragging is fine, | ||||
| * it sends coordinates from where dragging was started */ | * it sends coordinates from where dragging was started */ | ||||
| const float my = UI_view2d_region_to_view_y(&ar->v2d, event->mval[1]); | const float my = UI_view2d_region_to_view_y(&ar->v2d, event->mval[1]); | ||||
| return outliner_find_item_at_y(soops, &soops->tree, my); | return outliner_find_item_at_y(soops, &soops->tree, my); | ||||
| ▲ Show 20 Lines • Show All 100 Lines • ▼ Show 20 Lines | static void outliner_item_drag_handle( | ||||
| te_dragged->drag_data->insert_handle = te_insert_handle; | te_dragged->drag_data->insert_handle = te_insert_handle; | ||||
| } | } | ||||
| /** | /** | ||||
| * Returns true if it is a collection and empty. | * Returns true if it is a collection and empty. | ||||
| */ | */ | ||||
| static bool is_empty_collection(TreeElement *te) | static bool is_empty_collection(TreeElement *te) | ||||
| { | { | ||||
| if (!ELEM(TREESTORE(te)->type, TSE_SCENE_COLLECTION, TSE_LAYER_COLLECTION)) { | Collection *collection = outliner_collection_from_tree_element(te); | ||||
| return false; | |||||
| } | |||||
| SceneCollection *scene_collection; | if (!collection) { | ||||
| if (TREESTORE(te)->type == TSE_SCENE_COLLECTION) { | return false; | ||||
| scene_collection = (SceneCollection *)te->directdata; | |||||
| } | |||||
| else { | |||||
| BLI_assert(TREESTORE(te)->type == TSE_LAYER_COLLECTION); | |||||
| scene_collection = ((LayerCollection *)te->directdata)->scene_collection; | |||||
| } | } | ||||
| return BLI_listbase_is_empty(&scene_collection->objects) && | return BLI_listbase_is_empty(&collection->gobject) && | ||||
| BLI_listbase_is_empty(&scene_collection->scene_collections); | BLI_listbase_is_empty(&collection->children); | ||||
| } | } | ||||
| static bool outliner_item_drag_drop_apply( | static bool outliner_item_drag_drop_apply( | ||||
| Main *bmain, | Main *bmain, | ||||
| Scene *scene, | |||||
| SpaceOops *soops, | SpaceOops *soops, | ||||
| OutlinerDragDropTooltip *data, | OutlinerDragDropTooltip *data, | ||||
| const wmEvent *event) | const wmEvent *event) | ||||
| { | { | ||||
| TreeElement *dragged_te = data->te; | TreeElement *dragged_te = data->te; | ||||
| TreeElement *insert_handle = dragged_te->drag_data->insert_handle; | TreeElement *insert_handle = dragged_te->drag_data->insert_handle; | ||||
| TreeElementInsertType insert_type = dragged_te->drag_data->insert_type; | TreeElementInsertType insert_type = dragged_te->drag_data->insert_type; | ||||
| if ((insert_handle == dragged_te) || !insert_handle) { | if ((insert_handle == dragged_te) || !insert_handle) { | ||||
| /* No need to do anything */ | /* No need to do anything */ | ||||
| } | } | ||||
| else if (dragged_te->reinsert) { | else if (dragged_te->reinsert) { | ||||
| BLI_assert(!dragged_te->reinsert_poll || dragged_te->reinsert_poll(dragged_te, &insert_handle, | BLI_assert(!dragged_te->reinsert_poll || dragged_te->reinsert_poll(dragged_te, &insert_handle, | ||||
| &insert_type)); | &insert_type)); | ||||
| /* call of assert above should not have changed insert_handle and insert_type at this point */ | /* call of assert above should not have changed insert_handle and insert_type at this point */ | ||||
| BLI_assert(dragged_te->drag_data->insert_handle == insert_handle && | BLI_assert(dragged_te->drag_data->insert_handle == insert_handle && | ||||
| dragged_te->drag_data->insert_type == insert_type); | dragged_te->drag_data->insert_type == insert_type); | ||||
| /* If the collection was just created and you moved objects/collections inside it, | /* If the collection was just created and you moved objects/collections inside it, | ||||
| * it is strange to have it closed and we not see the newly dragged elements. */ | * it is strange to have it closed and we not see the newly dragged elements. */ | ||||
| const bool should_open_collection = (insert_type == TE_INSERT_INTO) && is_empty_collection(insert_handle); | const bool should_open_collection = (insert_type == TE_INSERT_INTO) && is_empty_collection(insert_handle); | ||||
| dragged_te->reinsert(bmain, soops, dragged_te, insert_handle, insert_type, event); | dragged_te->reinsert(bmain, scene, soops, dragged_te, insert_handle, insert_type, event); | ||||
| if (should_open_collection && !is_empty_collection(insert_handle)) { | if (should_open_collection && !is_empty_collection(insert_handle)) { | ||||
| TREESTORE(insert_handle)->flag &= ~TSE_CLOSED; | TREESTORE(insert_handle)->flag &= ~TSE_CLOSED; | ||||
| } | } | ||||
| return true; | return true; | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| static int outliner_item_drag_drop_modal(bContext *C, wmOperator *op, const wmEvent *event) | static int outliner_item_drag_drop_modal(bContext *C, wmOperator *op, const wmEvent *event) | ||||
| { | { | ||||
| Main *bmain = CTX_data_main(C); | Main *bmain = CTX_data_main(C); | ||||
| Scene *scene = CTX_data_scene(C); | |||||
| ARegion *ar = CTX_wm_region(C); | ARegion *ar = CTX_wm_region(C); | ||||
| SpaceOops *soops = CTX_wm_space_outliner(C); | SpaceOops *soops = CTX_wm_space_outliner(C); | ||||
| OutlinerDragDropTooltip *data = op->customdata; | OutlinerDragDropTooltip *data = op->customdata; | ||||
| TreeElement *te_dragged = data->te; | TreeElement *te_dragged = data->te; | ||||
| int retval = OPERATOR_RUNNING_MODAL; | int retval = OPERATOR_RUNNING_MODAL; | ||||
| bool redraw = false; | bool redraw = false; | ||||
| bool skip_rebuild = true; | bool skip_rebuild = true; | ||||
| switch (event->type) { | switch (event->type) { | ||||
| case EVT_MODAL_MAP: | case EVT_MODAL_MAP: | ||||
| if (event->val == OUTLINER_ITEM_DRAG_CONFIRM) { | if (event->val == OUTLINER_ITEM_DRAG_CONFIRM) { | ||||
| if (outliner_item_drag_drop_apply(bmain, soops, data, event)) { | if (outliner_item_drag_drop_apply(bmain, scene, soops, data, event)) { | ||||
| skip_rebuild = false; | skip_rebuild = false; | ||||
| } | } | ||||
| retval = OPERATOR_FINISHED; | retval = OPERATOR_FINISHED; | ||||
| } | } | ||||
| else if (event->val == OUTLINER_ITEM_DRAG_CANCEL) { | else if (event->val == OUTLINER_ITEM_DRAG_CANCEL) { | ||||
| retval = OPERATOR_CANCELLED; | retval = OPERATOR_CANCELLED; | ||||
| } | } | ||||
| else { | else { | ||||
| Show All 16 Lines | if (redraw) { | ||||
| else { | else { | ||||
| ED_region_tag_redraw(ar); | ED_region_tag_redraw(ar); | ||||
| } | } | ||||
| } | } | ||||
| return retval; | return retval; | ||||
| } | } | ||||
| /** | |||||
| * Check if the given TreeElement is a collection | |||||
| * | |||||
| * This test is mainly used to see if next/prev TreeElement is a collection. | |||||
| * It will fail when there is no next/prev TreeElement, or when the | |||||
| * element is an Override or something else in the future. | |||||
| */ | |||||
| static bool tree_element_is_collection_get(const TreeElement *te) | |||||
| { | |||||
| if (te == NULL) { | |||||
| return false; | |||||
| } | |||||
| TreeStoreElem *tselem = TREESTORE(te); | |||||
| return ELEM(tselem->type, TSE_LAYER_COLLECTION, TSE_SCENE_COLLECTION); | |||||
| } | |||||
| static const char *outliner_drag_drop_tooltip_get( | static const char *outliner_drag_drop_tooltip_get( | ||||
| const TreeElement *te_float) | const TreeElement *te_float) | ||||
| { | { | ||||
| const char *name = NULL; | const char *name = NULL; | ||||
| const TreeElement *te_insert = te_float->drag_data->insert_handle; | const TreeElement *te_insert = te_float->drag_data->insert_handle; | ||||
| if (tree_element_is_collection_get(te_float)) { | if (te_float && outliner_is_collection_tree_element(te_float)) { | ||||
| if (te_insert == NULL) { | if (te_insert == NULL) { | ||||
| name = TIP_("Move collection"); | name = TIP_("Move collection"); | ||||
| } | } | ||||
| else { | else { | ||||
| switch (te_float->drag_data->insert_type) { | switch (te_float->drag_data->insert_type) { | ||||
| case TE_INSERT_BEFORE: | case TE_INSERT_BEFORE: | ||||
| if (tree_element_is_collection_get(te_insert->prev)) { | if (te_insert->prev && outliner_is_collection_tree_element(te_insert->prev)) { | ||||
| name = TIP_("Move between collections"); | name = TIP_("Move between collections"); | ||||
| } | } | ||||
| else { | else { | ||||
| name = TIP_("Move before collection"); | name = TIP_("Move before collection"); | ||||
| } | } | ||||
| break; | break; | ||||
| case TE_INSERT_AFTER: | case TE_INSERT_AFTER: | ||||
| if (tree_element_is_collection_get(te_insert->next)) { | if (te_insert->next && outliner_is_collection_tree_element(te_insert->next)) { | ||||
| name = TIP_("Move between collections"); | name = TIP_("Move between collections"); | ||||
| } | } | ||||
| else { | else { | ||||
| name = TIP_("Move after collection"); | name = TIP_("Move after collection"); | ||||
| } | } | ||||
| break; | break; | ||||
| case TE_INSERT_INTO: | case TE_INSERT_INTO: | ||||
| name = TIP_("Move inside collection"); | name = TIP_("Move inside collection"); | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| else if ((TREESTORE(te_float)->type == 0) && (te_float->idcode == ID_OB)) { | else if ((TREESTORE(te_float)->type == 0) && (te_float->idcode == ID_OB)) { | ||||
| name = TIP_("Move to collection (Ctrl to add)"); | name = TIP_("Move to collection (Ctrl to link)"); | ||||
| } | } | ||||
| return name; | return name; | ||||
| } | } | ||||
| static void outliner_drag_drop_tooltip_cb(const wmWindow *win, void *vdata) | static void outliner_drag_drop_tooltip_cb(const wmWindow *win, void *vdata) | ||||
| { | { | ||||
| OutlinerDragDropTooltip *data = vdata; | OutlinerDragDropTooltip *data = vdata; | ||||
| ▲ Show 20 Lines • Show All 82 Lines • ▼ Show 20 Lines | void outliner_operatortypes(void) | ||||
| WM_operatortype_append(OUTLINER_OT_item_activate); | WM_operatortype_append(OUTLINER_OT_item_activate); | ||||
| WM_operatortype_append(OUTLINER_OT_select_border); | WM_operatortype_append(OUTLINER_OT_select_border); | ||||
| WM_operatortype_append(OUTLINER_OT_item_openclose); | WM_operatortype_append(OUTLINER_OT_item_openclose); | ||||
| WM_operatortype_append(OUTLINER_OT_item_rename); | WM_operatortype_append(OUTLINER_OT_item_rename); | ||||
| WM_operatortype_append(OUTLINER_OT_item_drag_drop); | WM_operatortype_append(OUTLINER_OT_item_drag_drop); | ||||
| WM_operatortype_append(OUTLINER_OT_operation); | WM_operatortype_append(OUTLINER_OT_operation); | ||||
| WM_operatortype_append(OUTLINER_OT_scene_operation); | WM_operatortype_append(OUTLINER_OT_scene_operation); | ||||
| WM_operatortype_append(OUTLINER_OT_object_operation); | WM_operatortype_append(OUTLINER_OT_object_operation); | ||||
| WM_operatortype_append(OUTLINER_OT_group_operation); | |||||
| WM_operatortype_append(OUTLINER_OT_lib_operation); | WM_operatortype_append(OUTLINER_OT_lib_operation); | ||||
| WM_operatortype_append(OUTLINER_OT_lib_relocate); | WM_operatortype_append(OUTLINER_OT_lib_relocate); | ||||
| WM_operatortype_append(OUTLINER_OT_id_operation); | WM_operatortype_append(OUTLINER_OT_id_operation); | ||||
| WM_operatortype_append(OUTLINER_OT_id_delete); | WM_operatortype_append(OUTLINER_OT_id_delete); | ||||
| WM_operatortype_append(OUTLINER_OT_id_remap); | WM_operatortype_append(OUTLINER_OT_id_remap); | ||||
| WM_operatortype_append(OUTLINER_OT_data_operation); | WM_operatortype_append(OUTLINER_OT_data_operation); | ||||
| WM_operatortype_append(OUTLINER_OT_animdata_operation); | WM_operatortype_append(OUTLINER_OT_animdata_operation); | ||||
| WM_operatortype_append(OUTLINER_OT_action_set); | WM_operatortype_append(OUTLINER_OT_action_set); | ||||
| WM_operatortype_append(OUTLINER_OT_constraint_operation); | WM_operatortype_append(OUTLINER_OT_constraint_operation); | ||||
| WM_operatortype_append(OUTLINER_OT_modifier_operation); | WM_operatortype_append(OUTLINER_OT_modifier_operation); | ||||
| WM_operatortype_append(OUTLINER_OT_collection_operation); | |||||
| WM_operatortype_append(OUTLINER_OT_show_one_level); | WM_operatortype_append(OUTLINER_OT_show_one_level); | ||||
| WM_operatortype_append(OUTLINER_OT_show_active); | WM_operatortype_append(OUTLINER_OT_show_active); | ||||
| WM_operatortype_append(OUTLINER_OT_show_hierarchy); | WM_operatortype_append(OUTLINER_OT_show_hierarchy); | ||||
| WM_operatortype_append(OUTLINER_OT_scroll_page); | WM_operatortype_append(OUTLINER_OT_scroll_page); | ||||
| WM_operatortype_append(OUTLINER_OT_selected_toggle); | WM_operatortype_append(OUTLINER_OT_selected_toggle); | ||||
| WM_operatortype_append(OUTLINER_OT_expanded_toggle); | WM_operatortype_append(OUTLINER_OT_expanded_toggle); | ||||
| WM_operatortype_append(OUTLINER_OT_keyingset_add_selected); | WM_operatortype_append(OUTLINER_OT_keyingset_add_selected); | ||||
| WM_operatortype_append(OUTLINER_OT_keyingset_remove_selected); | WM_operatortype_append(OUTLINER_OT_keyingset_remove_selected); | ||||
| WM_operatortype_append(OUTLINER_OT_drivers_add_selected); | WM_operatortype_append(OUTLINER_OT_drivers_add_selected); | ||||
| WM_operatortype_append(OUTLINER_OT_drivers_delete_selected); | WM_operatortype_append(OUTLINER_OT_drivers_delete_selected); | ||||
| WM_operatortype_append(OUTLINER_OT_orphans_purge); | WM_operatortype_append(OUTLINER_OT_orphans_purge); | ||||
| WM_operatortype_append(OUTLINER_OT_parent_drop); | WM_operatortype_append(OUTLINER_OT_parent_drop); | ||||
| WM_operatortype_append(OUTLINER_OT_parent_clear); | WM_operatortype_append(OUTLINER_OT_parent_clear); | ||||
| WM_operatortype_append(OUTLINER_OT_scene_drop); | WM_operatortype_append(OUTLINER_OT_scene_drop); | ||||
| WM_operatortype_append(OUTLINER_OT_material_drop); | WM_operatortype_append(OUTLINER_OT_material_drop); | ||||
| WM_operatortype_append(OUTLINER_OT_group_link); | WM_operatortype_append(OUTLINER_OT_collection_drop); | ||||
| /* collections */ | /* collections */ | ||||
| WM_operatortype_append(OUTLINER_OT_collections_delete); | |||||
| WM_operatortype_append(OUTLINER_OT_collection_select); | |||||
| WM_operatortype_append(OUTLINER_OT_collection_toggle); | |||||
| WM_operatortype_append(OUTLINER_OT_collection_link); | |||||
| WM_operatortype_append(OUTLINER_OT_collection_unlink); | |||||
| WM_operatortype_append(OUTLINER_OT_collection_new); | WM_operatortype_append(OUTLINER_OT_collection_new); | ||||
| WM_operatortype_append(OUTLINER_OT_collection_duplicate); | WM_operatortype_append(OUTLINER_OT_collection_duplicate); | ||||
| WM_operatortype_append(OUTLINER_OT_collection_delete); | |||||
| WM_operatortype_append(OUTLINER_OT_collection_nested_new); | |||||
| WM_operatortype_append(OUTLINER_OT_collection_delete_selected); | |||||
| WM_operatortype_append(OUTLINER_OT_collection_objects_add); | |||||
| WM_operatortype_append(OUTLINER_OT_collection_objects_remove); | |||||
| WM_operatortype_append(OUTLINER_OT_collection_objects_select); | WM_operatortype_append(OUTLINER_OT_collection_objects_select); | ||||
| WM_operatortype_append(OUTLINER_OT_object_add_to_new_collection); | WM_operatortype_append(OUTLINER_OT_collection_objects_deselect); | ||||
| WM_operatortype_append(OUTLINER_OT_object_remove_from_collection); | WM_operatortype_append(OUTLINER_OT_collection_link); | ||||
| WM_operatortype_append(OUTLINER_OT_collection_instance); | |||||
| } | } | ||||
| static wmKeyMap *outliner_item_drag_drop_modal_keymap(wmKeyConfig *keyconf) | static wmKeyMap *outliner_item_drag_drop_modal_keymap(wmKeyConfig *keyconf) | ||||
| { | { | ||||
| static EnumPropertyItem modal_items[] = { | static EnumPropertyItem modal_items[] = { | ||||
| {OUTLINER_ITEM_DRAG_CANCEL, "CANCEL", 0, "Cancel", ""}, | {OUTLINER_ITEM_DRAG_CANCEL, "CANCEL", 0, "Cancel", ""}, | ||||
| {OUTLINER_ITEM_DRAG_CONFIRM, "CONFIRM", 0, "Confirm/Drop", ""}, | {OUTLINER_ITEM_DRAG_CONFIRM, "CONFIRM", 0, "Confirm/Drop", ""}, | ||||
| {0, NULL, 0, NULL, NULL} | {0, NULL, 0, NULL, NULL} | ||||
| ▲ Show 20 Lines • Show All 81 Lines • ▼ Show 20 Lines | void outliner_keymap(wmKeyConfig *keyconf) | ||||
| WM_keymap_verify_item(keymap, "OUTLINER_OT_keyingset_remove_selected", KKEY, KM_PRESS, KM_ALT, 0); | WM_keymap_verify_item(keymap, "OUTLINER_OT_keyingset_remove_selected", KKEY, KM_PRESS, KM_ALT, 0); | ||||
| WM_keymap_verify_item(keymap, "ANIM_OT_keyframe_insert", IKEY, KM_PRESS, 0, 0); | WM_keymap_verify_item(keymap, "ANIM_OT_keyframe_insert", IKEY, KM_PRESS, 0, 0); | ||||
| WM_keymap_verify_item(keymap, "ANIM_OT_keyframe_delete", IKEY, KM_PRESS, KM_ALT, 0); | WM_keymap_verify_item(keymap, "ANIM_OT_keyframe_delete", IKEY, KM_PRESS, KM_ALT, 0); | ||||
| WM_keymap_verify_item(keymap, "OUTLINER_OT_drivers_add_selected", DKEY, KM_PRESS, 0, 0); | WM_keymap_verify_item(keymap, "OUTLINER_OT_drivers_add_selected", DKEY, KM_PRESS, 0, 0); | ||||
| WM_keymap_verify_item(keymap, "OUTLINER_OT_drivers_delete_selected", DKEY, KM_PRESS, KM_ALT, 0); | WM_keymap_verify_item(keymap, "OUTLINER_OT_drivers_delete_selected", DKEY, KM_PRESS, KM_ALT, 0); | ||||
| WM_keymap_verify_item(keymap, "OUTLINER_OT_collection_nested_new", CKEY, KM_PRESS, 0, 0); | WM_keymap_verify_item(keymap, "OUTLINER_OT_collection_new", CKEY, KM_PRESS, 0, 0); | ||||
| WM_keymap_verify_item(keymap, "OUTLINER_OT_collection_delete_selected", XKEY, KM_PRESS, 0, 0); | WM_keymap_verify_item(keymap, "OUTLINER_OT_collection_delete", XKEY, KM_PRESS, 0, 0); | ||||
| outliner_item_drag_drop_modal_keymap(keyconf); | outliner_item_drag_drop_modal_keymap(keyconf); | ||||
| } | } | ||||