diff options
Diffstat (limited to 'source/blender/editors/space_outliner')
10 files changed, 1598 insertions, 1800 deletions
diff --git a/source/blender/editors/space_outliner/CMakeLists.txt b/source/blender/editors/space_outliner/CMakeLists.txt index 96d27c6fd89..796e8732fca 100644 --- a/source/blender/editors/space_outliner/CMakeLists.txt +++ b/source/blender/editors/space_outliner/CMakeLists.txt @@ -39,6 +39,7 @@ set(INC_SYS set(SRC outliner_collections.c + outliner_dragdrop.c outliner_draw.c outliner_edit.c outliner_ops.c diff --git a/source/blender/editors/space_outliner/outliner_collections.c b/source/blender/editors/space_outliner/outliner_collections.c index ad94615a0d2..d4c85ce28bd 100644 --- a/source/blender/editors/space_outliner/outliner_collections.c +++ b/source/blender/editors/space_outliner/outliner_collections.c @@ -99,6 +99,24 @@ Collection *outliner_collection_from_tree_element(const TreeElement *te) return NULL; } +TreeTraversalAction outliner_find_selected_objects(TreeElement *te, void *customdata) +{ + struct ObjectsSelectedData *data = customdata; + TreeStoreElem *tselem = TREESTORE(te); + + if (outliner_is_collection_tree_element(te)) { + return TRAVERSE_CONTINUE; + } + + if (tselem->type || (tselem->id == NULL) || (GS(tselem->id->name) != ID_OB)) { + return TRAVERSE_SKIP_CHILDS; + } + + BLI_addtail(&data->objects_selected_array, BLI_genericNodeN(te)); + + return TRAVERSE_CONTINUE; +} + /* -------------------------------------------------------------------- */ /* Poll functions. */ @@ -138,8 +156,10 @@ static TreeTraversalAction collection_find_selected_to_add(TreeElement *te, void static int collection_new_exec(bContext *C, wmOperator *op) { SpaceOops *soops = CTX_wm_space_outliner(C); + ARegion *ar = CTX_wm_region(C); Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); struct CollectionNewData data = { .error = false, @@ -147,6 +167,8 @@ static int collection_new_exec(bContext *C, wmOperator *op) }; if (RNA_boolean_get(op->ptr, "nested")) { + outliner_build_tree(bmain, scene, view_layer, soops, ar); + outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_find_selected_to_add, &data); if (data.error) { @@ -574,7 +596,7 @@ static TreeTraversalAction layer_collection_find_data_to_edit(TreeElement *te, v return TRAVERSE_CONTINUE; } -static bool collections_view_layer_poll(bContext *C, bool include) +static bool collections_view_layer_poll(bContext *C, bool clear, int flag) { /* Poll function so the right click menu show current state of selected collections. */ SpaceOops *soops = CTX_wm_space_outliner(C); @@ -593,10 +615,10 @@ static bool collections_view_layer_poll(bContext *C, bool include) GSET_ITER(collections_to_edit_iter, data.collections_to_edit) { LayerCollection *lc = BLI_gsetIterator_getKey(&collections_to_edit_iter); - if (include && (lc->flag & LAYER_COLLECTION_EXCLUDE)) { + if (clear && (lc->flag & flag)) { result = true; } - else if (!include && !(lc->flag & LAYER_COLLECTION_EXCLUDE)) { + else if (!clear && !(lc->flag & flag)) { result = true; } } @@ -605,27 +627,47 @@ static bool collections_view_layer_poll(bContext *C, bool include) return result; } -static bool collections_exclude_poll(bContext *C) +static bool collections_exclude_set_poll(bContext *C) +{ + return collections_view_layer_poll(C, false, LAYER_COLLECTION_EXCLUDE); +} + +static bool collections_exclude_clear_poll(bContext *C) { - return collections_view_layer_poll(C, false); + return collections_view_layer_poll(C, true, LAYER_COLLECTION_EXCLUDE); } -static bool collections_include_poll(bContext *C) +static bool collections_holdout_set_poll(bContext *C) { - return collections_view_layer_poll(C, true); + return collections_view_layer_poll(C, false, LAYER_COLLECTION_HOLDOUT); } -static void layer_collection_exclude_recursive_set(LayerCollection *lc) +static bool collections_holdout_clear_poll(bContext *C) +{ + return collections_view_layer_poll(C, true, LAYER_COLLECTION_HOLDOUT); +} + +static bool collections_indirect_only_set_poll(bContext *C) +{ + return collections_view_layer_poll(C, false, LAYER_COLLECTION_INDIRECT_ONLY); +} + +static bool collections_indirect_only_clear_poll(bContext *C) +{ + return collections_view_layer_poll(C, true, LAYER_COLLECTION_INDIRECT_ONLY); +} + +static void layer_collection_flag_recursive_set(LayerCollection *lc, int flag) { for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) { - if (lc->flag & LAYER_COLLECTION_EXCLUDE) { - nlc->flag |= LAYER_COLLECTION_EXCLUDE; + if (lc->flag & flag) { + nlc->flag |= flag; } else { - nlc->flag &= ~LAYER_COLLECTION_EXCLUDE; + nlc->flag &= ~flag; } - layer_collection_exclude_recursive_set(nlc); + layer_collection_flag_recursive_set(nlc, flag); } } @@ -636,7 +678,10 @@ static int collection_view_layer_exec(bContext *C, wmOperator *op) ViewLayer *view_layer = CTX_data_view_layer(C); SpaceOops *soops = CTX_wm_space_outliner(C); struct CollectionEditData data = {.scene = scene, .soops = soops}; - bool include = STREQ(op->idname, "OUTLINER_OT_collection_include_set"); + bool clear = strstr(op->idname, "clear") != NULL; + int flag = strstr(op->idname, "holdout") ? LAYER_COLLECTION_HOLDOUT : + strstr(op->idname, "indirect_only") ? LAYER_COLLECTION_INDIRECT_ONLY : + LAYER_COLLECTION_EXCLUDE; data.collections_to_edit = BLI_gset_ptr_new(__func__); @@ -647,14 +692,14 @@ static int collection_view_layer_exec(bContext *C, wmOperator *op) LayerCollection *lc = BLI_gsetIterator_getKey(&collections_to_edit_iter); if (!(lc->collection->flag & COLLECTION_IS_MASTER)) { - if (include) { - lc->flag &= ~LAYER_COLLECTION_EXCLUDE; + if (clear) { + lc->flag &= ~flag; } else { - lc->flag |= LAYER_COLLECTION_EXCLUDE; + lc->flag |= flag; } - layer_collection_exclude_recursive_set(lc); + layer_collection_flag_recursive_set(lc, flag); } } @@ -671,28 +716,88 @@ static int collection_view_layer_exec(bContext *C, wmOperator *op) void OUTLINER_OT_collection_exclude_set(wmOperatorType *ot) { /* identifiers */ - ot->name = "Exclude from View Layer"; + ot->name = "Set Exclude"; ot->idname = "OUTLINER_OT_collection_exclude_set"; ot->description = "Exclude collection from the active view layer"; /* api callbacks */ ot->exec = collection_view_layer_exec; - ot->poll = collections_exclude_poll; + ot->poll = collections_exclude_set_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -void OUTLINER_OT_collection_include_set(wmOperatorType *ot) +void OUTLINER_OT_collection_exclude_clear(wmOperatorType *ot) { /* identifiers */ - ot->name = "Include in View Layer"; - ot->idname = "OUTLINER_OT_collection_include_set"; + ot->name = "Clear Exclude"; + ot->idname = "OUTLINER_OT_collection_exclude_clear"; ot->description = "Include collection in the active view layer"; /* api callbacks */ ot->exec = collection_view_layer_exec; - ot->poll = collections_include_poll; + ot->poll = collections_exclude_clear_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +void OUTLINER_OT_collection_holdout_set(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Set Holdout"; + ot->idname = "OUTLINER_OT_collection_holdout_set"; + ot->description = "Mask collection in the active view layer"; + + /* api callbacks */ + ot->exec = collection_view_layer_exec; + ot->poll = collections_holdout_set_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +void OUTLINER_OT_collection_holdout_clear(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Clear Holdout"; + ot->idname = "OUTLINER_OT_collection_holdout_clear"; + ot->description = "Clear masking of collection in the active view layer"; + + /* api callbacks */ + ot->exec = collection_view_layer_exec; + ot->poll = collections_holdout_clear_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +void OUTLINER_OT_collection_indirect_only_set(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Set Indirect Only"; + ot->idname = "OUTLINER_OT_collection_indirect_only_set"; + ot->description = "Set collection to only contribute indirectly (through shadows and reflections) in the view layer"; + + /* api callbacks */ + ot->exec = collection_view_layer_exec; + ot->poll = collections_indirect_only_set_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +void OUTLINER_OT_collection_indirect_only_clear(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Clear Indirect Only"; + ot->idname = "OUTLINER_OT_collection_indirect_only_clear"; + ot->description = "Clear collection contributing only indirectly in the view layer"; + + /* api callbacks */ + ot->exec = collection_view_layer_exec; + ot->poll = collections_indirect_only_clear_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; diff --git a/source/blender/editors/space_outliner/outliner_dragdrop.c b/source/blender/editors/space_outliner/outliner_dragdrop.c new file mode 100644 index 00000000000..55b9a561503 --- /dev/null +++ b/source/blender/editors/space_outliner/outliner_dragdrop.c @@ -0,0 +1,954 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2004 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Joshua Leung + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/space_outliner/outliner_dragdrop.c + * \ingroup spoutliner + */ + +#include <string.h> + +#include "MEM_guardedalloc.h" + +#include "DNA_group_types.h" +#include "DNA_material_types.h" +#include "DNA_object_types.h" +#include "DNA_space_types.h" + +#include "BLI_listbase.h" +#include "BLI_string.h" + +#include "BLT_translation.h" + +#include "BKE_collection.h" +#include "BKE_context.h" +#include "BKE_layer.h" +#include "BKE_main.h" +#include "BKE_material.h" +#include "BKE_report.h" +#include "BKE_scene.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" + +#include "ED_object.h" +#include "ED_outliner.h" +#include "ED_screen.h" + +#include "UI_interface.h" +#include "UI_resources.h" +#include "UI_view2d.h" + +#include "GPU_state.h" + +#include "RNA_access.h" +#include "RNA_define.h" +#include "RNA_enum_types.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "outliner_intern.h" + +/* ******************** Drop Target Find *********************** */ + +static TreeElement *outliner_dropzone_element(TreeElement *te, const float fmval[2], const bool children) +{ + if ((fmval[1] > te->ys) && (fmval[1] < (te->ys + UI_UNIT_Y))) { + /* name and first icon */ + if ((fmval[0] > te->xs + UI_UNIT_X) && (fmval[0] < te->xend)) + return te; + } + /* Not it. Let's look at its children. */ + if (children && (TREESTORE(te)->flag & TSE_CLOSED) == 0 && (te->subtree.first)) { + for (te = te->subtree.first; te; te = te->next) { + TreeElement *te_valid = outliner_dropzone_element(te, fmval, children); + if (te_valid) + return te_valid; + } + } + return NULL; +} + +/* Find tree element to drop into. */ +static TreeElement *outliner_dropzone_find(const SpaceOops *soops, const float fmval[2], const bool children) +{ + TreeElement *te; + + for (te = soops->tree.first; te; te = te->next) { + TreeElement *te_valid = outliner_dropzone_element(te, fmval, children); + if (te_valid) + return te_valid; + } + return NULL; +} + +static TreeElement *outliner_drop_find(bContext *C, const wmEvent *event) +{ + ARegion *ar = CTX_wm_region(C); + SpaceOops *soops = CTX_wm_space_outliner(C); + float fmval[2]; + UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); + + return outliner_dropzone_find(soops, fmval, true); +} + +static ID *outliner_ID_drop_find(bContext *C, const wmEvent *event, short idcode) +{ + TreeElement *te = outliner_drop_find(C, event); + TreeStoreElem *tselem = (te) ? TREESTORE(te) : NULL; + + if (te && te->idcode == idcode && tselem->type == 0) { + return tselem->id; + } + else { + return NULL; + } +} + +/* Find tree element to drop into, with additional before and after reorder support. */ +static TreeElement *outliner_drop_insert_find( + bContext *C, const wmEvent *event, + TreeElementInsertType *r_insert_type) +{ + SpaceOops *soops = CTX_wm_space_outliner(C); + ARegion *ar = CTX_wm_region(C); + TreeElement *te_hovered; + float view_mval[2]; + + UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &view_mval[0], &view_mval[1]); + te_hovered = outliner_find_item_at_y(soops, &soops->tree, view_mval[1]); + + if (te_hovered) { + /* mouse hovers an element (ignoring x-axis), now find out how to insert the dragged item exactly */ + const float margin = UI_UNIT_Y * (1.0f / 4); + + if (view_mval[1] < (te_hovered->ys + margin)) { + if (TSELEM_OPEN(TREESTORE(te_hovered), soops)) { + /* inserting after a open item means we insert into it, but as first child */ + if (BLI_listbase_is_empty(&te_hovered->subtree)) { + *r_insert_type = TE_INSERT_INTO; + return te_hovered; + } + else { + *r_insert_type = TE_INSERT_BEFORE; + return te_hovered->subtree.first; + } + } + else { + *r_insert_type = TE_INSERT_AFTER; + return te_hovered; + } + } + else if (view_mval[1] > (te_hovered->ys + (3 * margin))) { + *r_insert_type = TE_INSERT_BEFORE; + return te_hovered; + } + else { + *r_insert_type = TE_INSERT_INTO; + return te_hovered; + } + } + else { + /* mouse doesn't hover any item (ignoring x-axis), so it's either above list bounds or below. */ + TreeElement *first = soops->tree.first; + TreeElement *last = soops->tree.last; + + if (view_mval[1] < last->ys) { + *r_insert_type = TE_INSERT_AFTER; + return last; + } + else if (view_mval[1] > (first->ys + UI_UNIT_Y)) { + *r_insert_type = TE_INSERT_BEFORE; + return first; + } + else { + BLI_assert(0); + return NULL; + } + } +} + +static TreeElement *outliner_drop_insert_collection_find( + bContext *C, const wmEvent *event, + TreeElementInsertType *r_insert_type) +{ + TreeElement *te = outliner_drop_insert_find(C, event, r_insert_type); + if (!te) { + return NULL; + } + + Collection *collection = outliner_collection_from_tree_element(te); + if (!collection) { + return NULL; + } + + /* We can't insert/before after master collection. */ + if (collection->flag & COLLECTION_IS_MASTER) { + if (*r_insert_type == TE_INSERT_BEFORE) { + /* can't go higher than master collection, insert into it */ + *r_insert_type = TE_INSERT_INTO; + } + else if (*r_insert_type == TE_INSERT_AFTER) { + te = te->subtree.last; + collection = outliner_collection_from_tree_element(te); + if (!collection) { + return NULL; + } + } + } + + return te; +} + +/* ******************** Parent Drop Operator *********************** */ + +static bool parent_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event, const char **UNUSED(tooltip)) +{ + SpaceOops *soops = CTX_wm_space_outliner(C); + Object *ob = (Object *)WM_drag_ID(drag, ID_OB); + if (!ob) { + return false; + } + + /* Ensure item under cursor is valid drop target */ + TreeElement *te = outliner_drop_find(C, event); + TreeStoreElem *tselem = te ? TREESTORE(te) : NULL; + + if (!te) { + /* pass */ + } + else if (te->idcode == ID_OB && tselem->type == 0) { + Scene *scene; + ID *te_id = tselem->id; + + /* check if dropping self or parent */ + if (te_id == &ob->id || (Object *)te_id == ob->parent) + return false; + + /* check that parent/child are both in the same scene */ + scene = (Scene *)outliner_search_back(soops, te, ID_SCE); + + /* currently outliner organized in a way that if there's no parent scene + * element for object it means that all displayed objects belong to + * active scene and parenting them is allowed (sergey) + */ + if (!scene) { + return true; + } + else { + for (ViewLayer *view_layer = scene->view_layers.first; + view_layer; + view_layer = view_layer->next) + { + if (BKE_view_layer_base_find(view_layer, ob)) { + return true; + } + } + } + } + + return false; +} + +static int parent_drop_exec(bContext *C, wmOperator *op) +{ + Object *par = NULL, *ob = NULL; + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + int partype = -1; + char parname[MAX_ID_NAME], childname[MAX_ID_NAME]; + + partype = RNA_enum_get(op->ptr, "type"); + RNA_string_get(op->ptr, "parent", parname); + par = (Object *)BKE_libblock_find_name(bmain, ID_OB, parname); + RNA_string_get(op->ptr, "child", childname); + ob = (Object *)BKE_libblock_find_name(bmain, ID_OB, childname); + + if (ID_IS_LINKED(ob)) { + BKE_report(op->reports, RPT_INFO, "Can't edit library linked object"); + return OPERATOR_CANCELLED; + } + + ED_object_parent_set(op->reports, C, scene, ob, par, partype, false, false, NULL); + + DEG_relations_tag_update(bmain); + WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); + WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, NULL); + + return OPERATOR_FINISHED; +} + +static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + Main *bmain = CTX_data_main(C); + SpaceOops *soops = CTX_wm_space_outliner(C); + TreeElement *te = outliner_drop_find(C, event); + TreeStoreElem *tselem = te ? TREESTORE(te) : NULL; + + if (!(te && te->idcode == ID_OB && tselem->type == 0)) { + return OPERATOR_CANCELLED; + } + + Object *par = (Object *)tselem->id; + Object *ob = (Object *)WM_drag_ID_from_event(event, ID_OB); + + if (ELEM(NULL, ob, par)) { + return OPERATOR_CANCELLED; + } + if (ob == par) { + return OPERATOR_CANCELLED; + } + if (ID_IS_LINKED(ob)) { + BKE_report(op->reports, RPT_INFO, "Can't edit library linked object"); + return OPERATOR_CANCELLED; + } + + char childname[MAX_ID_NAME]; + char parname[MAX_ID_NAME]; + STRNCPY(childname, ob->id.name); + STRNCPY(parname, par->id.name); + RNA_string_set(op->ptr, "child", childname); + RNA_string_set(op->ptr, "parent", parname); + + Scene *scene = (Scene *)outliner_search_back(soops, te, ID_SCE); + + if (scene == NULL) { + /* currently outlier organized in a way, that if there's no parent scene + * element for object it means that all displayed objects belong to + * active scene and parenting them is allowed (sergey) + */ + + scene = CTX_data_scene(C); + } + + if ((par->type != OB_ARMATURE) && (par->type != OB_CURVE) && (par->type != OB_LATTICE)) { + int partype = 0; + if (ED_object_parent_set(op->reports, C, scene, ob, par, partype, false, false, NULL)) { + DEG_relations_tag_update(bmain); + WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); + WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, NULL); + } + } + else { + /* Menu creation */ + wmOperatorType *ot = WM_operatortype_find("OUTLINER_OT_parent_drop", false); + uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("Set Parent To"), ICON_NONE); + uiLayout *layout = UI_popup_menu_layout(pup); + PointerRNA ptr; + + /* Cannot use uiItemEnumO()... have multiple properties to set. */ + uiItemFullO_ptr(layout, ot, IFACE_("Object"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr); + RNA_string_set(&ptr, "parent", parname); + RNA_string_set(&ptr, "child", childname); + RNA_enum_set(&ptr, "type", PAR_OBJECT); + + /* par becomes parent, make the associated menus */ + if (par->type == OB_ARMATURE) { + uiItemFullO_ptr(layout, ot, IFACE_("Armature Deform"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr); + RNA_string_set(&ptr, "parent", parname); + RNA_string_set(&ptr, "child", childname); + RNA_enum_set(&ptr, "type", PAR_ARMATURE); + + uiItemFullO_ptr(layout, ot, IFACE_(" With Empty Groups"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr); + RNA_string_set(&ptr, "parent", parname); + RNA_string_set(&ptr, "child", childname); + RNA_enum_set(&ptr, "type", PAR_ARMATURE_NAME); + + uiItemFullO_ptr(layout, ot, IFACE_(" With Envelope Weights"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr); + RNA_string_set(&ptr, "parent", parname); + RNA_string_set(&ptr, "child", childname); + RNA_enum_set(&ptr, "type", PAR_ARMATURE_ENVELOPE); + + uiItemFullO_ptr(layout, ot, IFACE_(" With Automatic Weights"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr); + RNA_string_set(&ptr, "parent", parname); + RNA_string_set(&ptr, "child", childname); + RNA_enum_set(&ptr, "type", PAR_ARMATURE_AUTO); + + uiItemFullO_ptr(layout, ot, IFACE_("Bone"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr); + RNA_string_set(&ptr, "parent", parname); + RNA_string_set(&ptr, "child", childname); + RNA_enum_set(&ptr, "type", PAR_BONE); + } + else if (par->type == OB_CURVE) { + uiItemFullO_ptr(layout, ot, IFACE_("Curve Deform"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr); + RNA_string_set(&ptr, "parent", parname); + RNA_string_set(&ptr, "child", childname); + RNA_enum_set(&ptr, "type", PAR_CURVE); + + uiItemFullO_ptr(layout, ot, IFACE_("Follow Path"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr); + RNA_string_set(&ptr, "parent", parname); + RNA_string_set(&ptr, "child", childname); + RNA_enum_set(&ptr, "type", PAR_FOLLOW); + + uiItemFullO_ptr(layout, ot, IFACE_("Path Constraint"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr); + RNA_string_set(&ptr, "parent", parname); + RNA_string_set(&ptr, "child", childname); + RNA_enum_set(&ptr, "type", PAR_PATH_CONST); + } + else if (par->type == OB_LATTICE) { + uiItemFullO_ptr(layout, ot, IFACE_("Lattice Deform"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr); + RNA_string_set(&ptr, "parent", parname); + RNA_string_set(&ptr, "child", childname); + RNA_enum_set(&ptr, "type", PAR_LATTICE); + } + + UI_popup_menu_end(C, pup); + + return OPERATOR_INTERFACE; + } + + return OPERATOR_FINISHED; +} + +void OUTLINER_OT_parent_drop(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Drop to Set Parent"; + ot->description = "Drag to parent in Outliner"; + ot->idname = "OUTLINER_OT_parent_drop"; + + /* api callbacks */ + ot->invoke = parent_drop_invoke; + ot->exec = parent_drop_exec; + + ot->poll = ED_operator_outliner_active; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; + + /* properties */ + RNA_def_string(ot->srna, "child", "Object", MAX_ID_NAME, "Child", "Child Object"); + RNA_def_string(ot->srna, "parent", "Object", MAX_ID_NAME, "Parent", "Parent Object"); + RNA_def_enum(ot->srna, "type", prop_make_parent_types, 0, "Type", ""); +} + +static bool parenting_poll(bContext *C) +{ + SpaceOops *soops = CTX_wm_space_outliner(C); + + if (soops) { + if (soops->outlinevis == SO_SCENES) { + return true; + } + else if ((soops->outlinevis == SO_VIEW_LAYER) && + (soops->filter & SO_FILTER_NO_COLLECTION)) + { + return true; + } + } + + return false; +} + +/* ******************** Parent Clear Operator *********************** */ + +static bool parent_clear_poll(bContext *C, wmDrag *drag, const wmEvent *event, const char **UNUSED(tooltip)) +{ + SpaceOops *soops = CTX_wm_space_outliner(C); + + if (!ELEM(soops->outlinevis, SO_VIEW_LAYER)) { + return false; + } + + Object *ob = (Object *)WM_drag_ID(drag, ID_OB); + if (!(ob && ob->parent)) { + return false; + } + + TreeElement *te = outliner_drop_find(C, event); + if (te) { + TreeStoreElem *tselem = TREESTORE(te); + + switch (te->idcode) { + case ID_SCE: + return (ELEM(tselem->type, TSE_R_LAYER_BASE, TSE_R_LAYER)); + case ID_OB: + return (ELEM(tselem->type, TSE_MODIFIER_BASE, TSE_CONSTRAINT_BASE)); + /* Other codes to ignore? */ + } + } + return (te == NULL); +} + +static int parent_clear_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) +{ + Main *bmain = CTX_data_main(C); + Object *ob = (Object *)WM_drag_ID_from_event(event, ID_OB); + + if (ob == NULL) { + return OPERATOR_CANCELLED; + } + + ED_object_parent_clear(ob, 0); + + DEG_relations_tag_update(bmain); + WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); + WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, NULL); + return OPERATOR_FINISHED; +} + +void OUTLINER_OT_parent_clear(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Drop to Clear Parent"; + ot->description = "Drag to clear parent in Outliner"; + ot->idname = "OUTLINER_OT_parent_clear"; + + /* api callbacks */ + ot->invoke = parent_clear_invoke; + + ot->poll = parenting_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; +} + +/* ******************** Scene Drop Operator *********************** */ + +static bool scene_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event, const char **UNUSED(tooltip)) +{ + /* Ensure item under cursor is valid drop target */ + Object *ob = (Object *)WM_drag_ID(drag, ID_OB); + return (ob && (outliner_ID_drop_find(C, event, ID_SCE) != NULL)); +} + +static int scene_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) +{ + Main *bmain = CTX_data_main(C); + Scene *scene = (Scene *)outliner_ID_drop_find(C, event, ID_SCE); + Object *ob = (Object *)WM_drag_ID_from_event(event, ID_OB); + + if (ELEM(NULL, ob, scene) || ID_IS_LINKED(scene)) { + return OPERATOR_CANCELLED; + } + + if (BKE_scene_has_object(scene, ob)) { + return OPERATOR_CANCELLED; + } + + Collection *collection; + if (scene != CTX_data_scene(C)) { + /* when linking to an inactive scene link to the master collection */ + collection = BKE_collection_master(scene); + } + else { + collection = CTX_data_collection(C); + } + + BKE_collection_object_add(bmain, collection, ob); + + for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { + Base *base = BKE_view_layer_base_find(view_layer, ob); + if (base) { + ED_object_base_select(base, BA_SELECT); + } + } + + DEG_relations_tag_update(bmain); + + DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE); + WM_main_add_notifier(NC_SCENE | ND_OB_SELECT, scene); + + return OPERATOR_FINISHED; +} + +void OUTLINER_OT_scene_drop(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Drop Object to Scene"; + ot->description = "Drag object to scene in Outliner"; + ot->idname = "OUTLINER_OT_scene_drop"; + + /* api callbacks */ + ot->invoke = scene_drop_invoke; + + ot->poll = ED_operator_outliner_active; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; +} + +/* ******************** Material Drop Operator *********************** */ + +static bool material_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event, const char **UNUSED(tooltip)) +{ + /* Ensure item under cursor is valid drop target */ + Material *ma = (Material *)WM_drag_ID(drag, ID_MA); + return (ma && (outliner_ID_drop_find(C, event, ID_OB) != NULL)); +} + +static int material_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) +{ + Main *bmain = CTX_data_main(C); + Object *ob = (Object *)outliner_ID_drop_find(C, event, ID_OB); + Material *ma = (Material *)WM_drag_ID_from_event(event, ID_MA); + + if (ELEM(NULL, ob, ma)) { + return OPERATOR_CANCELLED; + } + + assign_material(bmain, ob, ma, ob->totcol + 1, BKE_MAT_ASSIGN_USERPREF); + + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, CTX_wm_view3d(C)); + WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_LINKS, ma); + + return OPERATOR_FINISHED; +} + +void OUTLINER_OT_material_drop(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Drop Material on Object"; + ot->description = "Drag material to object in Outliner"; + ot->idname = "OUTLINER_OT_material_drop"; + + /* api callbacks */ + ot->invoke = material_drop_invoke; + + ot->poll = ED_operator_outliner_active; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; +} + +/* ******************** Collection Drop Operator *********************** */ + +typedef struct CollectionDrop { + Collection *from; + Collection *to; + + TreeElement *te; + TreeElementInsertType insert_type; +} CollectionDrop; + +static Collection *collection_parent_from_ID(ID *id) +{ + /* Can't change linked parent collections. */ + if (!id || ID_IS_LINKED(id)) { + return NULL; + } + + /* Also support dropping into/from scene collection. */ + if (GS(id->name) == ID_SCE) { + return ((Scene *)id)->master_collection; + } + else if (GS(id->name) == ID_GR) { + return (Collection *)id; + } + + return NULL; +} + +static bool collection_drop_init(bContext *C, wmDrag *drag, const wmEvent *event, CollectionDrop *data) +{ + /* Get collection to drop into. */ + TreeElementInsertType insert_type; + TreeElement *te = outliner_drop_insert_collection_find(C, event, &insert_type); + if (!te) { + return false; + } + + Collection *to_collection = outliner_collection_from_tree_element(te); + if (ID_IS_LINKED(to_collection)) { + return false; + } + + /* Get drag datablocks. */ + if (drag->type != WM_DRAG_ID) { + return false; + } + + wmDragID *drag_id = drag->ids.first; + if (drag_id == NULL) { + return false; + } + + ID *id = drag_id->id; + if (!(id && ELEM(GS(id->name), ID_GR, ID_OB))) { + return false; + } + + /* Get collection to drag out of. */ + ID *parent = drag_id->from_parent; + Collection *from_collection = collection_parent_from_ID(parent); + if (event->ctrl) { + from_collection = NULL; + } + + /* Get collections. */ + if (GS(id->name) == ID_GR) { + if (id == &to_collection->id) { + return false; + } + } + else { + insert_type = TE_INSERT_INTO; + } + + data->from = from_collection; + data->to = to_collection; + data->te = te; + data->insert_type = insert_type; + + return true; +} + +static bool collection_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event, const char **tooltip) +{ + SpaceOops *soops = CTX_wm_space_outliner(C); + ARegion *ar = CTX_wm_region(C); + bool changed = outliner_flag_set(&soops->tree, TSE_HIGHLIGHTED | TSE_DRAG_ANY, false); + + CollectionDrop data; + if (collection_drop_init(C, drag, event, &data)) { + if (!data.from || event->ctrl) { + *tooltip = IFACE_("Link inside Collection"); + } + else { + TreeElement *te = data.te; + TreeStoreElem *tselem = TREESTORE(te); + + switch (data.insert_type) { + case TE_INSERT_BEFORE: + tselem->flag |= TSE_DRAG_BEFORE; + changed = true; + if (te->prev && outliner_is_collection_tree_element(te->prev)) { + *tooltip = TIP_("Move between collections"); + } + else { + *tooltip = TIP_("Move before collection"); + } + break; + case TE_INSERT_AFTER: + tselem->flag |= TSE_DRAG_AFTER; + changed = true; + if (te->next && outliner_is_collection_tree_element(te->next)) { + *tooltip = TIP_("Move between collections"); + } + else { + *tooltip = TIP_("Move after collection"); + } + break; + case TE_INSERT_INTO: + tselem->flag |= TSE_DRAG_INTO; + changed = true; + *tooltip = TIP_("Move inside collection (Ctrl to link)"); + break; + } + } + } + + if (changed) { + ED_region_tag_redraw_no_rebuild(ar); + } + + return true; +} + +static int collection_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) +{ + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + + if (event->custom != EVT_DATA_DRAGDROP) { + return OPERATOR_CANCELLED; + } + + ListBase *lb = event->customdata; + wmDrag *drag = lb->first; + + CollectionDrop data; + if (!collection_drop_init(C, drag, event, &data)) { + return OPERATOR_CANCELLED; + } + + /* Before/after insert handling. */ + Collection *relative = NULL; + bool relative_after = false; + + if (ELEM(data.insert_type, TE_INSERT_BEFORE, TE_INSERT_AFTER)) { + SpaceOops *soops = CTX_wm_space_outliner(C); + + relative = data.to; + relative_after = (data.insert_type == TE_INSERT_AFTER); + + TreeElement *parent_te = outliner_find_parent_element(&soops->tree, NULL, data.te); + data.to = (parent_te) ? outliner_collection_from_tree_element(parent_te) : NULL; + } + + if (!data.to) { + return OPERATOR_CANCELLED; + } + + for (wmDragID *drag_id = drag->ids.first; drag_id; drag_id = drag_id->next) { + /* Ctrl enables linking, so we don't need a from collection then. */ + Collection *from = (event->ctrl) ? NULL : collection_parent_from_ID(drag_id->from_parent); + + if (GS(drag_id->id->name) == ID_OB) { + /* Move/link object into collection. */ + Object *object = (Object *)drag_id->id; + + if (from) { + BKE_collection_object_move(bmain, scene, data.to, from, object); + } + else { + BKE_collection_object_add(bmain, data.to, object); + } + } + else if (GS(drag_id->id->name) == ID_GR) { + /* Move/link collection into collection. */ + Collection *collection = (Collection *)drag_id->id; + + if (collection != from) { + BKE_collection_move(bmain, data.to, from, relative, relative_after, collection); + } + } + + if (from) { + DEG_id_tag_update(&from->id, DEG_TAG_COPY_ON_WRITE); + } + } + + /* Update dependency graph. */ + DEG_id_tag_update(&data.to->id, DEG_TAG_COPY_ON_WRITE); + DEG_relations_tag_update(bmain); + WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene); + + return OPERATOR_FINISHED; +} + +void OUTLINER_OT_collection_drop(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Move to Collection"; + ot->description = "Drag to move to collection in Outliner"; + ot->idname = "OUTLINER_OT_collection_drop"; + + /* api callbacks */ + ot->invoke = collection_drop_invoke; + ot->poll = ED_operator_outliner_active; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; +} + +/* ********************* Outliner Drag Operator ******************** */ + +static TreeElement *outliner_item_drag_element_find(SpaceOops *soops, ARegion *ar, const wmEvent *event) +{ + /* note: using EVT_TWEAK_ events to trigger dragging is fine, + * it sends coordinates from where dragging was started */ + const float my = UI_view2d_region_to_view_y(&ar->v2d, event->mval[1]); + return outliner_find_item_at_y(soops, &soops->tree, my); +} + +static int outliner_item_drag_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) +{ + ARegion *ar = CTX_wm_region(C); + SpaceOops *soops = CTX_wm_space_outliner(C); + TreeElement *te = outliner_item_drag_element_find(soops, ar, event); + + if (!te) { + return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH); + } + + TreeElementIcon data = tree_element_get_icon(TREESTORE(te), te); + if (!data.drag_id) { + return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH); + } + + wmDrag *drag = WM_event_start_drag(C, data.icon, WM_DRAG_ID, NULL, 0.0, WM_DRAG_NOP); + + if (GS(data.drag_id->name) == ID_OB) { + /* For objects we cheat and drag all selected objects. */ + TREESTORE(te)->flag |= TSE_SELECTED; + + struct ObjectsSelectedData selected = { + .objects_selected_array = {NULL, NULL}, + }; + + outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, outliner_find_selected_objects, &selected); + LISTBASE_FOREACH (LinkData *, link, &selected.objects_selected_array) { + TreeElement *ten_selected = (TreeElement *)link->data; + Object *ob = (Object *)TREESTORE(ten_selected)->id; + + /* Find parent collection of object. */ + Collection *parent = NULL; + + if (ten_selected->parent) { + for (TreeElement *te_ob_parent = ten_selected->parent; te_ob_parent; te_ob_parent = te_ob_parent->parent) { + if (outliner_is_collection_tree_element(te_ob_parent)) { + parent = outliner_collection_from_tree_element(te_ob_parent); + break; + } + } + } + else { + Scene *scene = CTX_data_scene(C); + parent = BKE_collection_master(scene); + } + + WM_drag_add_ID(drag, &ob->id, &parent->id); + } + + BLI_freelistN(&selected.objects_selected_array); + } + else { + /* Add single ID. */ + WM_drag_add_ID(drag, data.drag_id, data.drag_parent); + } + + return (OPERATOR_FINISHED | OPERATOR_PASS_THROUGH); +} + +/* Outliner drag and drop. This operator mostly exists to support dragging + * from outliner text instead of only from the icon, and also to show a + * hint in the statusbar keymap. */ + +void OUTLINER_OT_item_drag_drop(wmOperatorType *ot) +{ + ot->name = "Drag and Drop"; + ot->idname = "OUTLINER_OT_item_drag_drop"; + ot->description = "Drag and drop element to another place"; + + ot->invoke = outliner_item_drag_drop_invoke; + ot->poll = ED_operator_outliner_active; +} + +/* *************************** Drop Boxes ************************** */ + +/* region dropbox definition */ +void outliner_dropboxes(void) +{ + ListBase *lb = WM_dropboxmap_find("Outliner", SPACE_OUTLINER, RGN_TYPE_WINDOW); + + WM_dropbox_add(lb, "OUTLINER_OT_parent_drop", parent_drop_poll, NULL); + WM_dropbox_add(lb, "OUTLINER_OT_parent_clear", parent_clear_poll, NULL); + WM_dropbox_add(lb, "OUTLINER_OT_scene_drop", scene_drop_poll, NULL); + WM_dropbox_add(lb, "OUTLINER_OT_material_drop", material_drop_poll, NULL); + WM_dropbox_add(lb, "OUTLINER_OT_collection_drop", collection_drop_poll, NULL); +} diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index 8e111beec54..5244c364b80 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -32,6 +32,7 @@ #include "DNA_anim_types.h" #include "DNA_armature_types.h" #include "DNA_gpencil_types.h" +#include "DNA_gpencil_modifier_types.h" #include "DNA_group_types.h" #include "DNA_lamp_types.h" #include "DNA_lightprobe_types.h" @@ -50,6 +51,7 @@ #include "BKE_context.h" #include "BKE_deform.h" #include "BKE_fcurve.h" +#include "BKE_gpencil.h" #include "BKE_global.h" #include "BKE_idcode.h" #include "BKE_layer.h" @@ -438,12 +440,16 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname) } case TSE_GP_LAYER: { - bGPdata *gpd = (bGPdata *)tselem->id; // id = GP Datablock + bGPdata *gpd = (bGPdata *)tselem->id; /* id = GP Datablock */ bGPDlayer *gpl = te->directdata; + /* always make layer active */ + BKE_gpencil_layer_setactive(gpd, gpl); + // XXX: name needs translation stuff BLI_uniquename(&gpd->layers, gpl, "GP Layer", '.', offsetof(bGPDlayer, info), sizeof(gpl->info)); + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, gpd); break; } @@ -742,11 +748,11 @@ static void outliner_draw_rnacols(ARegion *ar, int sizex) GPU_line_width(1.0f); - uint pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); immUniformThemeColorShadeAlpha(TH_BACK, -15, -200); - immBegin(GWN_PRIM_LINES, 4); + immBegin(GPU_PRIM_LINES, 4); immVertex2f(pos, sizex, v2d->cur.ymax); immVertex2f(pos, sizex, miny); @@ -844,394 +850,389 @@ static void outliner_buttons(const bContext *C, uiBlock *block, ARegion *ar, Tre /* ****************************************************** */ /* Normal Drawing... */ -/* make function calls a bit compacter */ -struct DrawIconArg { - uiBlock *block; - ID *id; - float xmax, x, y, xb, yb; - float alpha; -}; - -static void tselem_draw_icon_uibut(struct DrawIconArg *arg, int icon) +TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te) { - /* restrict column clip... it has been coded by simply overdrawing, doesnt work for buttons */ - if (arg->x >= arg->xmax) { - GPU_blend(true); - UI_icon_draw_alpha(arg->x, arg->y, icon, arg->alpha); - GPU_blend(false); - } - else { - uiBut *but = uiDefIconBut( - arg->block, UI_BTYPE_LABEL, 0, icon, arg->xb, arg->yb, UI_UNIT_X, UI_UNIT_Y, NULL, - 0.0, 0.0, 1.0, arg->alpha, - (arg->id && ID_IS_LINKED(arg->id)) ? arg->id->lib->name : ""); - - if (arg->id) - UI_but_drag_set_id(but, arg->id); - } - -} - -static void UNUSED_FUNCTION(tselem_draw_gp_icon_uibut)(struct DrawIconArg *arg, ID *id, bGPDlayer *gpl) -{ - /* restrict column clip - skip it for now... */ - if (arg->x >= arg->xmax) { - /* pass */ - } - else { - PointerRNA ptr; - const float eps = 0.001f; - const bool is_stroke_visible = (gpl->color[3] > eps); - const bool is_fill_visible = (gpl->fill[3] > eps); - float w = 0.5f * UI_UNIT_X; - float h = 0.85f * UI_UNIT_Y; - - RNA_pointer_create(id, &RNA_GPencilLayer, gpl, &ptr); - - UI_block_align_begin(arg->block); - - UI_block_emboss_set(arg->block, is_stroke_visible ? UI_EMBOSS : UI_EMBOSS_NONE); - uiDefButR(arg->block, UI_BTYPE_COLOR, 1, "", arg->xb, arg->yb, w, h, - &ptr, "color", -1, - 0, 0, 0, 0, NULL); - - UI_block_emboss_set(arg->block, is_fill_visible ? UI_EMBOSS : UI_EMBOSS_NONE); - uiDefButR(arg->block, UI_BTYPE_COLOR, 1, "", arg->xb + w, arg->yb, w, h, - &ptr, "fill_color", -1, - 0, 0, 0, 0, NULL); - - UI_block_emboss_set(arg->block, UI_EMBOSS_NONE); - UI_block_align_end(arg->block); - } -} - -static void tselem_draw_icon( - uiBlock *block, int xmax, float x, float y, TreeStoreElem *tselem, TreeElement *te, - float alpha, const bool is_clickable) -{ - struct DrawIconArg arg; - float aspect; - - /* make function calls a bit compacter */ - arg.block = block; - arg.id = tselem->id; - arg.xmax = xmax; - arg.xb = x; /* for ui buttons */ - arg.yb = y; - arg.alpha = alpha; - - /* placement of icons, copied from interface_widgets.c */ - aspect = (0.8f * UI_UNIT_Y) / ICON_DEFAULT_HEIGHT; - x += 2.0f * aspect; - y += 2.0f * aspect; - arg.x = x; - arg.y = y; - -#define ICON_DRAW(_icon) UI_icon_draw_alpha(x, y, _icon, alpha) -#define ICON_CLICK_DRAW(_icon) if (!is_clickable) ICON_DRAW(_icon); else tselem_draw_icon_uibut(&arg, _icon) + TreeElementIcon data = {0}; if (tselem->type) { switch (tselem->type) { case TSE_ANIM_DATA: - ICON_DRAW(ICON_ANIM_DATA); /* XXX */ + data.icon = ICON_ANIM_DATA; /* XXX */ break; case TSE_NLA: - ICON_DRAW(ICON_NLA); + data.icon = ICON_NLA; break; case TSE_NLA_TRACK: - ICON_DRAW(ICON_NLA); /* XXX */ + data.icon = ICON_NLA; /* XXX */ break; case TSE_NLA_ACTION: - ICON_DRAW(ICON_ACTION); + data.icon = ICON_ACTION; break; case TSE_DRIVER_BASE: - ICON_DRAW(ICON_DRIVER); + data.icon = ICON_DRIVER; break; case TSE_DEFGROUP_BASE: - ICON_DRAW(ICON_GROUP_VERTEX); + data.icon = ICON_GROUP_VERTEX; break; case TSE_BONE: case TSE_EBONE: - ICON_DRAW(ICON_BONE_DATA); + data.icon = ICON_BONE_DATA; break; case TSE_CONSTRAINT_BASE: - ICON_DRAW(ICON_CONSTRAINT); + data.icon = ICON_CONSTRAINT; break; case TSE_MODIFIER_BASE: - ICON_DRAW(ICON_MODIFIER); + data.icon = ICON_MODIFIER; break; case TSE_LINKED_OB: - ICON_DRAW(ICON_OBJECT_DATA); + data.icon = ICON_OBJECT_DATA; break; case TSE_LINKED_PSYS: - ICON_DRAW(ICON_PARTICLES); + data.icon = ICON_PARTICLES; break; case TSE_MODIFIER: { Object *ob = (Object *)tselem->id; - ModifierData *md = BLI_findlink(&ob->modifiers, tselem->nr); - switch ((ModifierType)md->type) { - case eModifierType_Subsurf: - ICON_DRAW(ICON_MOD_SUBSURF); - break; - case eModifierType_Armature: - ICON_DRAW(ICON_MOD_ARMATURE); - break; - case eModifierType_Lattice: - ICON_DRAW(ICON_MOD_LATTICE); - break; - case eModifierType_Curve: - ICON_DRAW(ICON_MOD_CURVE); - break; - case eModifierType_Build: - ICON_DRAW(ICON_MOD_BUILD); - break; - case eModifierType_Mirror: - ICON_DRAW(ICON_MOD_MIRROR); - break; - case eModifierType_Decimate: - ICON_DRAW(ICON_MOD_DECIM); - break; - case eModifierType_Wave: - ICON_DRAW(ICON_MOD_WAVE); - break; - case eModifierType_Hook: - ICON_DRAW(ICON_HOOK); - break; - case eModifierType_Softbody: - ICON_DRAW(ICON_MOD_SOFT); - break; - case eModifierType_Boolean: - ICON_DRAW(ICON_MOD_BOOLEAN); - break; - case eModifierType_ParticleSystem: - ICON_DRAW(ICON_MOD_PARTICLES); - break; - case eModifierType_ParticleInstance: - ICON_DRAW(ICON_MOD_PARTICLES); - break; - case eModifierType_EdgeSplit: - ICON_DRAW(ICON_MOD_EDGESPLIT); - break; - case eModifierType_Array: - ICON_DRAW(ICON_MOD_ARRAY); - break; - case eModifierType_UVProject: - case eModifierType_UVWarp: /* TODO, get own icon */ - ICON_DRAW(ICON_MOD_UVPROJECT); - break; - case eModifierType_Displace: - ICON_DRAW(ICON_MOD_DISPLACE); - break; - case eModifierType_Shrinkwrap: - ICON_DRAW(ICON_MOD_SHRINKWRAP); - break; - case eModifierType_Cast: - ICON_DRAW(ICON_MOD_CAST); - break; - case eModifierType_MeshDeform: - case eModifierType_SurfaceDeform: - ICON_DRAW(ICON_MOD_MESHDEFORM); - break; - case eModifierType_Bevel: - ICON_DRAW(ICON_MOD_BEVEL); - break; - case eModifierType_Smooth: - case eModifierType_LaplacianSmooth: - case eModifierType_CorrectiveSmooth: - ICON_DRAW(ICON_MOD_SMOOTH); - break; - case eModifierType_SimpleDeform: - ICON_DRAW(ICON_MOD_SIMPLEDEFORM); - break; - case eModifierType_Mask: - ICON_DRAW(ICON_MOD_MASK); - break; - case eModifierType_Cloth: - ICON_DRAW(ICON_MOD_CLOTH); - break; - case eModifierType_Explode: - ICON_DRAW(ICON_MOD_EXPLODE); - break; - case eModifierType_Collision: - case eModifierType_Surface: - ICON_DRAW(ICON_MOD_PHYSICS); - break; - case eModifierType_Fluidsim: - ICON_DRAW(ICON_MOD_FLUIDSIM); - break; - case eModifierType_Multires: - ICON_DRAW(ICON_MOD_MULTIRES); - break; - case eModifierType_Smoke: - ICON_DRAW(ICON_MOD_SMOKE); - break; - case eModifierType_Solidify: - ICON_DRAW(ICON_MOD_SOLIDIFY); - break; - case eModifierType_Screw: - ICON_DRAW(ICON_MOD_SCREW); - break; - case eModifierType_Remesh: - ICON_DRAW(ICON_MOD_REMESH); - break; - case eModifierType_WeightVGEdit: - case eModifierType_WeightVGMix: - case eModifierType_WeightVGProximity: - ICON_DRAW(ICON_MOD_VERTEX_WEIGHT); - break; - case eModifierType_DynamicPaint: - ICON_DRAW(ICON_MOD_DYNAMICPAINT); - break; - case eModifierType_Ocean: - ICON_DRAW(ICON_MOD_OCEAN); - break; - case eModifierType_Warp: - ICON_DRAW(ICON_MOD_WARP); - break; - case eModifierType_Skin: - ICON_DRAW(ICON_MOD_SKIN); - break; - case eModifierType_Triangulate: - ICON_DRAW(ICON_MOD_TRIANGULATE); - break; - case eModifierType_MeshCache: - ICON_DRAW(ICON_MOD_MESHDEFORM); /* XXX, needs own icon */ - break; - case eModifierType_MeshSequenceCache: - ICON_DRAW(ICON_MOD_MESHDEFORM); /* XXX, needs own icon */ - break; - case eModifierType_Wireframe: - ICON_DRAW(ICON_MOD_WIREFRAME); - break; - case eModifierType_LaplacianDeform: - ICON_DRAW(ICON_MOD_MESHDEFORM); /* XXX, needs own icon */ - break; - case eModifierType_DataTransfer: - ICON_DRAW(ICON_MOD_DATA_TRANSFER); - break; - case eModifierType_NormalEdit: - ICON_DRAW(ICON_MOD_NORMALEDIT); - break; - case eModifierType_Hair: - ICON_DRAW(ICON_STRANDS); - break; - /* Default */ - case eModifierType_None: - case eModifierType_ShapeKey: - case NUM_MODIFIER_TYPES: - ICON_DRAW(ICON_DOT); - break; + if (ob->type != OB_GPENCIL) { + ModifierData *md = BLI_findlink(&ob->modifiers, tselem->nr); + switch ((ModifierType)md->type) { + case eModifierType_Subsurf: + data.icon = ICON_MOD_SUBSURF; + break; + case eModifierType_Armature: + data.icon = ICON_MOD_ARMATURE; + break; + case eModifierType_Lattice: + data.icon = ICON_MOD_LATTICE; + break; + case eModifierType_Curve: + data.icon = ICON_MOD_CURVE; + break; + case eModifierType_Build: + data.icon = ICON_MOD_BUILD; + break; + case eModifierType_Mirror: + data.icon = ICON_MOD_MIRROR; + break; + case eModifierType_Decimate: + data.icon = ICON_MOD_DECIM; + break; + case eModifierType_Wave: + data.icon = ICON_MOD_WAVE; + break; + case eModifierType_Hook: + data.icon = ICON_HOOK; + break; + case eModifierType_Softbody: + data.icon = ICON_MOD_SOFT; + break; + case eModifierType_Boolean: + data.icon = ICON_MOD_BOOLEAN; + break; + case eModifierType_ParticleSystem: + data.icon = ICON_MOD_PARTICLES; + break; + case eModifierType_ParticleInstance: + data.icon = ICON_MOD_PARTICLES; + break; + case eModifierType_EdgeSplit: + data.icon = ICON_MOD_EDGESPLIT; + break; + case eModifierType_Array: + data.icon = ICON_MOD_ARRAY; + break; + case eModifierType_UVProject: + case eModifierType_UVWarp: /* TODO, get own icon */ + data.icon = ICON_MOD_UVPROJECT; + break; + case eModifierType_Displace: + data.icon = ICON_MOD_DISPLACE; + break; + case eModifierType_Shrinkwrap: + data.icon = ICON_MOD_SHRINKWRAP; + break; + case eModifierType_Cast: + data.icon = ICON_MOD_CAST; + break; + case eModifierType_MeshDeform: + case eModifierType_SurfaceDeform: + data.icon = ICON_MOD_MESHDEFORM; + break; + case eModifierType_Bevel: + data.icon = ICON_MOD_BEVEL; + break; + case eModifierType_Smooth: + case eModifierType_LaplacianSmooth: + case eModifierType_CorrectiveSmooth: + data.icon = ICON_MOD_SMOOTH; + break; + case eModifierType_SimpleDeform: + data.icon = ICON_MOD_SIMPLEDEFORM; + break; + case eModifierType_Mask: + data.icon = ICON_MOD_MASK; + break; + case eModifierType_Cloth: + data.icon = ICON_MOD_CLOTH; + break; + case eModifierType_Explode: + data.icon = ICON_MOD_EXPLODE; + break; + case eModifierType_Collision: + case eModifierType_Surface: + data.icon = ICON_MOD_PHYSICS; + break; + case eModifierType_Fluidsim: + data.icon = ICON_MOD_FLUIDSIM; + break; + case eModifierType_Multires: + data.icon = ICON_MOD_MULTIRES; + break; + case eModifierType_Smoke: + data.icon = ICON_MOD_SMOKE; + break; + case eModifierType_Solidify: + data.icon = ICON_MOD_SOLIDIFY; + break; + case eModifierType_Screw: + data.icon = ICON_MOD_SCREW; + break; + case eModifierType_Remesh: + data.icon = ICON_MOD_REMESH; + break; + case eModifierType_WeightVGEdit: + case eModifierType_WeightVGMix: + case eModifierType_WeightVGProximity: + data.icon = ICON_MOD_VERTEX_WEIGHT; + break; + case eModifierType_DynamicPaint: + data.icon = ICON_MOD_DYNAMICPAINT; + break; + case eModifierType_Ocean: + data.icon = ICON_MOD_OCEAN; + break; + case eModifierType_Warp: + data.icon = ICON_MOD_WARP; + break; + case eModifierType_Skin: + data.icon = ICON_MOD_SKIN; + break; + case eModifierType_Triangulate: + data.icon = ICON_MOD_TRIANGULATE; + break; + case eModifierType_MeshCache: + data.icon = ICON_MOD_MESHDEFORM; /* XXX, needs own icon */ + break; + case eModifierType_MeshSequenceCache: + data.icon = ICON_MOD_MESHDEFORM; /* XXX, needs own icon */ + break; + case eModifierType_Wireframe: + data.icon = ICON_MOD_WIREFRAME; + break; + case eModifierType_LaplacianDeform: + data.icon = ICON_MOD_MESHDEFORM; /* XXX, needs own icon */ + break; + case eModifierType_DataTransfer: + data.icon = ICON_MOD_DATA_TRANSFER; + break; + case eModifierType_NormalEdit: + case eModifierType_WeightedNormal: + data.icon = ICON_MOD_NORMALEDIT; + break; + case eModifierType_Hair: + data.icon = ICON_STRANDS; + break; + /* Default */ + case eModifierType_None: + case eModifierType_ShapeKey: + + case NUM_MODIFIER_TYPES: + data.icon = ICON_DOT; + break; + } + } + else { + /* grease pencil modifiers */ + GpencilModifierData *md = BLI_findlink(&ob->greasepencil_modifiers, tselem->nr); + switch ((GpencilModifierType)md->type) { + case eGpencilModifierType_Noise: + data.icon = ICON_RNDCURVE; + break; + case eGpencilModifierType_Subdiv: + data.icon = ICON_MOD_SUBSURF; + break; + case eGpencilModifierType_Thick: + data.icon = ICON_MAN_ROT; + break; + case eGpencilModifierType_Tint: + data.icon = ICON_COLOR; + break; + case eGpencilModifierType_Instance: + data.icon = ICON_MOD_ARRAY; + break; + case eGpencilModifierType_Build: + data.icon = ICON_MOD_BUILD; + break; + case eGpencilModifierType_Opacity: + data.icon = ICON_MOD_MASK; + break; + case eGpencilModifierType_Color: + data.icon = ICON_GROUP_VCOL; + break; + case eGpencilModifierType_Lattice: + data.icon = ICON_MOD_LATTICE; + break; + case eGpencilModifierType_Mirror: + data.icon = ICON_MOD_MIRROR; + break; + case eGpencilModifierType_Simplify: + data.icon = ICON_MOD_DECIM; + break; + case eGpencilModifierType_Smooth: + data.icon = ICON_MOD_SMOOTH; + break; + case eGpencilModifierType_Hook: + data.icon = ICON_HOOK; + break; + case eGpencilModifierType_Offset: + data.icon = ICON_MOD_DISPLACE; + break; + + /* Default */ + default: + data.icon = ICON_DOT; + break; + } } break; } case TSE_POSE_BASE: - ICON_DRAW(ICON_ARMATURE_DATA); + data.icon = ICON_ARMATURE_DATA; break; case TSE_POSE_CHANNEL: - ICON_DRAW(ICON_BONE_DATA); + data.icon = ICON_BONE_DATA; break; case TSE_PROXY: - ICON_DRAW(ICON_GHOST); + data.icon = ICON_GHOST; break; case TSE_R_LAYER_BASE: - ICON_DRAW(ICON_RENDERLAYERS); + data.icon = ICON_RENDERLAYERS; break; case TSE_SCENE_OBJECTS_BASE: - ICON_DRAW(ICON_OUTLINER_OB_GROUP_INSTANCE); + data.icon = ICON_OUTLINER_OB_GROUP_INSTANCE; break; case TSE_R_LAYER: - ICON_DRAW(ICON_RENDER_RESULT); + data.icon = ICON_RENDER_RESULT; break; case TSE_LINKED_LAMP: - ICON_DRAW(ICON_LIGHT_DATA); + data.icon = ICON_LIGHT_DATA; break; case TSE_LINKED_MAT: - ICON_DRAW(ICON_MATERIAL_DATA); + data.icon = ICON_MATERIAL_DATA; break; case TSE_POSEGRP_BASE: - ICON_DRAW(ICON_GROUP_BONE); + data.icon = ICON_GROUP_BONE; break; case TSE_SEQUENCE: if (te->idcode == SEQ_TYPE_MOVIE) - ICON_DRAW(ICON_SEQUENCE); + data.icon = ICON_SEQUENCE; else if (te->idcode == SEQ_TYPE_META) - ICON_DRAW(ICON_DOT); + data.icon = ICON_DOT; else if (te->idcode == SEQ_TYPE_SCENE) - ICON_DRAW(ICON_SCENE); + data.icon = ICON_SCENE; else if (te->idcode == SEQ_TYPE_SOUND_RAM) - ICON_DRAW(ICON_SOUND); + data.icon = ICON_SOUND; else if (te->idcode == SEQ_TYPE_IMAGE) - ICON_DRAW(ICON_IMAGE_COL); + data.icon = ICON_IMAGE_COL; else - ICON_DRAW(ICON_PARTICLES); + data.icon = ICON_PARTICLES; break; case TSE_SEQ_STRIP: - ICON_DRAW(ICON_LIBRARY_DATA_DIRECT); + data.icon = ICON_LIBRARY_DATA_DIRECT; break; case TSE_SEQUENCE_DUP: - ICON_DRAW(ICON_OBJECT_DATA); + data.icon = ICON_OBJECT_DATA; break; case TSE_RNA_STRUCT: if (RNA_struct_is_ID(te->rnaptr.type)) { - arg.id = (ID *)te->rnaptr.data; - tselem_draw_icon_uibut(&arg, RNA_struct_ui_icon(te->rnaptr.type)); + data.drag_id = (ID *)te->rnaptr.data; + data.icon = RNA_struct_ui_icon(te->rnaptr.type); } else { - int icon = RNA_struct_ui_icon(te->rnaptr.type); - ICON_DRAW(icon); + data.icon = RNA_struct_ui_icon(te->rnaptr.type); } break; case TSE_LAYER_COLLECTION: case TSE_SCENE_COLLECTION_BASE: case TSE_VIEW_COLLECTION_BASE: - ICON_DRAW(ICON_GROUP); + { + Collection *collection = outliner_collection_from_tree_element(te); + if (collection && !(collection->flag & COLLECTION_IS_MASTER)) { + data.drag_id = tselem->id; + data.drag_parent = (data.drag_id && te->parent) ? TREESTORE(te->parent)->id : NULL; + } + + data.icon = ICON_GROUP; break; + } /* Removed the icons from outliner. Need a better structure with Layers, Palettes and Colors */ -#if 0 case TSE_GP_LAYER: - tselem_draw_gp_icon_uibut(&arg, tselem->id, te->directdata); + { + /* indicate whether layer is active */ + bGPDlayer *gpl = te->directdata; + if (gpl->flag & GP_LAYER_ACTIVE) { + data.icon = ICON_GREASEPENCIL; + } + else { + data.icon = ICON_DOT; + } break; -#endif + } default: - ICON_DRAW(ICON_DOT); + data.icon = ICON_DOT; break; } } else if (tselem->id) { + data.drag_id = tselem->id; + data.drag_parent = (data.drag_id && te->parent) ? TREESTORE(te->parent)->id : NULL; + if (GS(tselem->id->name) == ID_OB) { Object *ob = (Object *)tselem->id; switch (ob->type) { case OB_LAMP: - ICON_CLICK_DRAW(ICON_OUTLINER_OB_LIGHT); break; + data.icon = ICON_OUTLINER_OB_LIGHT; break; case OB_MESH: - ICON_CLICK_DRAW(ICON_OUTLINER_OB_MESH); break; + data.icon = ICON_OUTLINER_OB_MESH; break; case OB_CAMERA: - ICON_CLICK_DRAW(ICON_OUTLINER_OB_CAMERA); break; + data.icon = ICON_OUTLINER_OB_CAMERA; break; case OB_CURVE: - ICON_CLICK_DRAW(ICON_OUTLINER_OB_CURVE); break; + data.icon = ICON_OUTLINER_OB_CURVE; break; case OB_MBALL: - ICON_CLICK_DRAW(ICON_OUTLINER_OB_META); break; + data.icon = ICON_OUTLINER_OB_META; break; case OB_LATTICE: - ICON_CLICK_DRAW(ICON_OUTLINER_OB_LATTICE); break; + data.icon = ICON_OUTLINER_OB_LATTICE; break; case OB_ARMATURE: - ICON_CLICK_DRAW(ICON_OUTLINER_OB_ARMATURE); break; + data.icon = ICON_OUTLINER_OB_ARMATURE; break; case OB_FONT: - ICON_CLICK_DRAW(ICON_OUTLINER_OB_FONT); break; + data.icon = ICON_OUTLINER_OB_FONT; break; case OB_SURF: - ICON_CLICK_DRAW(ICON_OUTLINER_OB_SURFACE); break; + data.icon = ICON_OUTLINER_OB_SURFACE; break; case OB_SPEAKER: - ICON_CLICK_DRAW(ICON_OUTLINER_OB_SPEAKER); break; + data.icon = ICON_OUTLINER_OB_SPEAKER; break; case OB_LIGHTPROBE: - ICON_CLICK_DRAW(ICON_OUTLINER_OB_LIGHTPROBE); break; + data.icon = ICON_OUTLINER_OB_LIGHTPROBE; break; case OB_EMPTY: if (ob->dup_group) { - ICON_CLICK_DRAW(ICON_OUTLINER_OB_GROUP_INSTANCE); + data.icon = ICON_OUTLINER_OB_GROUP_INSTANCE; } else { - ICON_CLICK_DRAW(ICON_OUTLINER_OB_EMPTY); + data.icon = ICON_OUTLINER_OB_EMPTY; } break; + case OB_GPENCIL: + data.icon = ICON_OUTLINER_OB_GREASEPENCIL; break; + break; } } else { @@ -1240,101 +1241,129 @@ static void tselem_draw_icon( */ switch ((short)GS(tselem->id->name)) { case ID_SCE: - tselem_draw_icon_uibut(&arg, ICON_SCENE_DATA); break; + data.icon = ICON_SCENE_DATA; break; case ID_ME: - tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_MESH); break; + data.icon = ICON_OUTLINER_DATA_MESH; break; case ID_CU: - tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_CURVE); break; + data.icon = ICON_OUTLINER_DATA_CURVE; break; case ID_MB: - tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_META); break; + data.icon = ICON_OUTLINER_DATA_META; break; case ID_LT: - tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_LATTICE); break; + data.icon = ICON_OUTLINER_DATA_LATTICE; break; case ID_LA: { Lamp *la = (Lamp *)tselem->id; switch (la->type) { case LA_LOCAL: - tselem_draw_icon_uibut(&arg, ICON_LIGHT_POINT); break; + data.icon = ICON_LIGHT_POINT; break; case LA_SUN: - tselem_draw_icon_uibut(&arg, ICON_LIGHT_SUN); break; + data.icon = ICON_LIGHT_SUN; break; case LA_SPOT: - tselem_draw_icon_uibut(&arg, ICON_LIGHT_SPOT); break; + data.icon = ICON_LIGHT_SPOT; break; case LA_HEMI: - tselem_draw_icon_uibut(&arg, ICON_LIGHT_HEMI); break; + data.icon = ICON_LIGHT_HEMI; break; case LA_AREA: - tselem_draw_icon_uibut(&arg, ICON_LIGHT_AREA); break; + data.icon = ICON_LIGHT_AREA; break; default: - tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_LIGHT); break; + data.icon = ICON_OUTLINER_DATA_LIGHT; break; } break; } case ID_MA: - tselem_draw_icon_uibut(&arg, ICON_MATERIAL_DATA); break; + data.icon = ICON_MATERIAL_DATA; break; case ID_TE: - tselem_draw_icon_uibut(&arg, ICON_TEXTURE_DATA); break; + data.icon = ICON_TEXTURE_DATA; break; case ID_IM: - tselem_draw_icon_uibut(&arg, ICON_IMAGE_DATA); break; + data.icon = ICON_IMAGE_DATA; break; case ID_SPK: case ID_SO: - tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_SPEAKER); break; + data.icon = ICON_OUTLINER_DATA_SPEAKER; break; case ID_AR: - tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_ARMATURE); break; + data.icon = ICON_OUTLINER_DATA_ARMATURE; break; case ID_CA: - tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_CAMERA); break; + data.icon = ICON_OUTLINER_DATA_CAMERA; break; case ID_KE: - tselem_draw_icon_uibut(&arg, ICON_SHAPEKEY_DATA); break; + data.icon = ICON_SHAPEKEY_DATA; break; case ID_WO: - tselem_draw_icon_uibut(&arg, ICON_WORLD_DATA); break; + data.icon = ICON_WORLD_DATA; break; case ID_AC: - tselem_draw_icon_uibut(&arg, ICON_ACTION); break; + data.icon = ICON_ACTION; break; case ID_NLA: - tselem_draw_icon_uibut(&arg, ICON_NLA); break; + data.icon = ICON_NLA; break; case ID_TXT: - tselem_draw_icon_uibut(&arg, ICON_SCRIPT); break; + data.icon = ICON_SCRIPT; break; case ID_GR: - tselem_draw_icon_uibut(&arg, ICON_GROUP); break; + data.icon = ICON_GROUP; break; case ID_LI: if (tselem->id->tag & LIB_TAG_MISSING) { - tselem_draw_icon_uibut(&arg, ICON_LIBRARY_DATA_BROKEN); + data.icon = ICON_LIBRARY_DATA_BROKEN; } else if (((Library *)tselem->id)->parent) { - tselem_draw_icon_uibut(&arg, ICON_LIBRARY_DATA_INDIRECT); + data.icon = ICON_LIBRARY_DATA_INDIRECT; } else { - tselem_draw_icon_uibut(&arg, ICON_LIBRARY_DATA_DIRECT); + data.icon = ICON_LIBRARY_DATA_DIRECT; } break; case ID_LS: - tselem_draw_icon_uibut(&arg, ICON_LINE_DATA); break; + data.icon = ICON_LINE_DATA; break; case ID_GD: - tselem_draw_icon_uibut(&arg, ICON_GREASEPENCIL); break; + data.icon = ICON_OUTLINER_DATA_GREASEPENCIL; break; case ID_LP: { LightProbe * lp = (LightProbe *)tselem->id; switch (lp->type) { case LIGHTPROBE_TYPE_CUBE: - tselem_draw_icon_uibut(&arg, ICON_LIGHTPROBE_CUBEMAP); break; + data.icon = ICON_LIGHTPROBE_CUBEMAP; break; case LIGHTPROBE_TYPE_PLANAR: - tselem_draw_icon_uibut(&arg, ICON_LIGHTPROBE_PLANAR); break; + data.icon = ICON_LIGHTPROBE_PLANAR; break; case LIGHTPROBE_TYPE_GRID: - tselem_draw_icon_uibut(&arg, ICON_LIGHTPROBE_GRID); break; + data.icon = ICON_LIGHTPROBE_GRID; break; default: - tselem_draw_icon_uibut(&arg, ICON_LIGHTPROBE_CUBEMAP); break; + data.icon = ICON_LIGHTPROBE_CUBEMAP; break; } break; } case ID_BR: - tselem_draw_icon_uibut(&arg, ICON_BRUSH_DATA); break; + data.icon = ICON_BRUSH_DATA; break; case ID_SCR: case ID_WS: - tselem_draw_icon_uibut(&arg, ICON_SPLITSCREEN); break; + data.icon = ICON_SPLITSCREEN; break; default: break; } } } -#undef ICON_DRAW + return data; +} + +static void tselem_draw_icon( + uiBlock *block, int xmax, float x, float y, TreeStoreElem *tselem, TreeElement *te, + float alpha, const bool is_clickable) +{ + TreeElementIcon data = tree_element_get_icon(tselem, te); + + if (data.icon == 0) { + return; + } + + if (!is_clickable || x >= xmax) { + /* placement of icons, copied from interface_widgets.c */ + float aspect = (0.8f * UI_UNIT_Y) / ICON_DEFAULT_HEIGHT; + x += 2.0f * aspect; + y += 2.0f * aspect; + + /* restrict column clip... it has been coded by simply overdrawing, + * doesnt work for buttons */ + UI_icon_draw_alpha(x, y, data.icon, alpha); + } + else { + uiDefIconBut( + block, UI_BTYPE_LABEL, 0, data.icon, x, y, UI_UNIT_X, UI_UNIT_Y, NULL, + 0.0, 0.0, 1.0, alpha, + (data.drag_id && ID_IS_LINKED(data.drag_id)) ? data.drag_id->lib->name : ""); + } } /** @@ -1344,16 +1373,9 @@ static void tselem_draw_icon( static void outliner_draw_iconrow_number( const uiFontStyle *fstyle, int offsx, int ys, - const eOLDrawState active, const int num_elements) { - float color[4] = {0.4f, 0.4f, 0.4f, 0.9f}; - copy_v3_fl(color, 0.2f); - if (active != OL_DRAWSEL_NONE) { - copy_v3_fl(color, 0.65f); - color[3] = 1.0f; - } - + float color[4] = {0.0f, 0.0f, 0.0f, 1.0f}; float ufac = 0.25f * UI_UNIT_X; float offset_x = (float) offsx + UI_UNIT_X * 0.35f; @@ -1417,13 +1439,13 @@ static void outliner_draw_iconrow_doit( } /* No inlined icon should be clickable. */ - tselem_draw_icon(block, xmax, (float)*offsx, (float)ys, tselem, te, 0.5f * alpha_fac, false); + tselem_draw_icon(block, xmax, (float)*offsx, (float)ys, tselem, te, 0.8f * alpha_fac, false); te->xs = *offsx; te->ys = ys; te->xend = (short)*offsx + UI_UNIT_X; if (num_elements > 1) { - outliner_draw_iconrow_number(fstyle, *offsx, ys, active, num_elements); + outliner_draw_iconrow_number(fstyle, *offsx, ys, num_elements); } (*offsx) += UI_UNIT_X; } @@ -1451,23 +1473,19 @@ static int tree_element_id_type_to_index(TreeElement *te) } } +typedef struct MergedIconRow { + eOLDrawState active[INDEX_ID_MAX + OB_TYPE_MAX]; + int num_elements[INDEX_ID_MAX + OB_TYPE_MAX]; + TreeElement *tree_element[INDEX_ID_MAX + OB_TYPE_MAX]; +} MergedIconRow; + static void outliner_draw_iconrow( bContext *C, uiBlock *block, const uiFontStyle *fstyle, Scene *scene, ViewLayer *view_layer, SpaceOops *soops, - ListBase *lb, int level, int xmax, int *offsx, int ys, float alpha_fac) + ListBase *lb, int level, int xmax, int *offsx, int ys, float alpha_fac, MergedIconRow *merged) { eOLDrawState active; const Object *obact = OBACT(view_layer); - struct { - eOLDrawState active[INDEX_ID_MAX + OB_TYPE_MAX]; - int num_elements[INDEX_ID_MAX + OB_TYPE_MAX]; - TreeElement *tree_element[INDEX_ID_MAX + OB_TYPE_MAX]; - } data = { - .active = {0}, - .num_elements = {0}, - .tree_element = {NULL}, - }; - for (TreeElement *te = lb->first; te; te = te->next) { /* exit drawing early */ if ((*offsx) - UI_UNIT_X > xmax) @@ -1498,13 +1516,13 @@ static void outliner_draw_iconrow( } else { const int index = tree_element_id_type_to_index(te); - data.num_elements[index]++; - if ((data.tree_element[index] == NULL) || - (active > data.active[index])) + merged->num_elements[index]++; + if ((merged->tree_element[index] == NULL) || + (active > merged->active[index])) { - data.tree_element[index] = te; + merged->tree_element[index] = te; } - data.active[index] = MAX2(active, data.active[index]); + merged->active[index] = MAX2(active, merged->active[index]); } } @@ -1512,26 +1530,28 @@ static void outliner_draw_iconrow( if (tselem->type != TSE_R_LAYER) { outliner_draw_iconrow( C, block, fstyle, scene, view_layer, soops, - &te->subtree, level + 1, xmax, offsx, ys, alpha_fac); + &te->subtree, level + 1, xmax, offsx, ys, alpha_fac, merged); } } - for (int i = 0; i < INDEX_ID_MAX; i++) { - const int num_subtypes = (i == INDEX_ID_OB) ? OB_TYPE_MAX : 1; - /* See tree_element_id_type_to_index for the index logic. */ - int index_base = i; - if (i > INDEX_ID_OB) { - index_base += OB_TYPE_MAX; - } - for (int j = 0; j < num_subtypes; j++) { - const int index = index_base + j; - if (data.num_elements[index] != 0) { - outliner_draw_iconrow_doit(block, - data.tree_element[index], - fstyle, - xmax, offsx, ys, alpha_fac, - data.active[index], - data.num_elements[index]); + if (level == 0) { + for (int i = 0; i < INDEX_ID_MAX; i++) { + const int num_subtypes = (i == INDEX_ID_OB) ? OB_TYPE_MAX : 1; + /* See tree_element_id_type_to_index for the index logic. */ + int index_base = i; + if (i > INDEX_ID_OB) { + index_base += OB_TYPE_MAX; + } + for (int j = 0; j < num_subtypes; j++) { + const int index = index_base + j; + if (merged->num_elements[index] != 0) { + outliner_draw_iconrow_doit(block, + merged->tree_element[index], + fstyle, + xmax, offsx, ys, alpha_fac, + merged->active[index], + merged->num_elements[index]); + } } } } @@ -1558,7 +1578,7 @@ static void outliner_set_coord_tree_element(TreeElement *te, int startx, int sta static void outliner_draw_tree_element( bContext *C, uiBlock *block, const uiFontStyle *fstyle, Scene *scene, ViewLayer *view_layer, ARegion *ar, SpaceOops *soops, TreeElement *te, bool draw_grayed_out, - int startx, int *starty, TreeElement **te_edit, TreeElement **te_floating) + int startx, int *starty, TreeElement **te_edit) { TreeStoreElem *tselem; float ufac = UI_UNIT_X / 20.0f; @@ -1575,9 +1595,6 @@ static void outliner_draw_tree_element( if ((tselem->flag & TSE_TEXTBUT) && (*te_edit == NULL)) { *te_edit = te; } - if ((te->drag_data != NULL) && (*te_floating == NULL)) { - *te_floating = te; - } /* icons can be ui buts, we don't want it to overlap with restrict */ if ((soops->flag & SO_HIDE_RESTRICTCOLS) == 0) @@ -1742,8 +1759,8 @@ static void outliner_draw_tree_element( /* divider */ { - Gwn_VertFormat *format = immVertexFormat(); - uint pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_I32, 2, GWN_FETCH_INT_TO_FLOAT); + GPUVertFormat *format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT); unsigned char col[4]; immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); @@ -1758,9 +1775,10 @@ static void outliner_draw_tree_element( immUnbindProgram(); } + MergedIconRow merged = {{0}}; outliner_draw_iconrow( C, block, fstyle, scene, view_layer, soops, &te->subtree, 0, xmax, &tempx, - *starty, alpha_fac); + *starty, alpha_fac, &merged); GPU_blend(false); } @@ -1778,11 +1796,11 @@ static void outliner_draw_tree_element( for (TreeElement *ten = te->subtree.first; ten; ten = ten->next) { /* check if element needs to be drawn grayed out, but also gray out * childs of a grayed out parent (pass on draw_grayed_out to childs) */ - bool draw_childs_grayed_out = draw_grayed_out || (ten->drag_data != NULL); + bool draw_childs_grayed_out = draw_grayed_out || (ten->flag & TE_DRAGGING); outliner_draw_tree_element( C, block, fstyle, scene, view_layer, ar, soops, ten, draw_childs_grayed_out, - startx + UI_UNIT_X, starty, te_edit, te_floating); + startx + UI_UNIT_X, starty, te_edit); } } else { @@ -1794,54 +1812,6 @@ static void outliner_draw_tree_element( } } -static void outliner_draw_tree_element_floating( - const ARegion *ar, const TreeElement *te_floating) -{ - const TreeElement *te_insert = te_floating->drag_data->insert_handle; - const int line_width = 2; - - uint pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); - int coord_y = te_insert->ys; - int coord_x = te_insert->xs; - float col[4]; - - if (te_insert == te_floating) { - /* don't draw anything */ - return; - } - - UI_GetThemeColorShade4fv(TH_BACK, -40, col); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - GPU_blend(true); - - if (ELEM(te_floating->drag_data->insert_type, TE_INSERT_BEFORE, TE_INSERT_AFTER)) { - if (te_floating->drag_data->insert_type == TE_INSERT_BEFORE) { - coord_y += UI_UNIT_Y; - } - immUniformColor4fv(col); - GPU_line_width(line_width); - - immBegin(GWN_PRIM_LINE_STRIP, 2); - immVertex2f(pos, coord_x, coord_y); - immVertex2f(pos, ar->v2d.cur.xmax, coord_y); - immEnd(); - } - else { - BLI_assert(te_floating->drag_data->insert_type == TE_INSERT_INTO); - immUniformColor3fvAlpha(col, col[3] * 0.5f); - - immBegin(GWN_PRIM_TRI_STRIP, 4); - immVertex2f(pos, coord_x, coord_y + UI_UNIT_Y); - immVertex2f(pos, coord_x, coord_y); - immVertex2f(pos, ar->v2d.cur.xmax, coord_y + UI_UNIT_Y); - immVertex2f(pos, ar->v2d.cur.xmax, coord_y); - immEnd(); - } - - GPU_blend(false); - immUnbindProgram(); -} - static void outliner_draw_hierarchy_lines_recursive( unsigned pos, SpaceOops *soops, ListBase *lb, int startx, const unsigned char col[4], bool draw_grayed_out, @@ -1859,7 +1829,7 @@ static void outliner_draw_hierarchy_lines_recursive( /* For vertical lines between objects. */ y1 = y2 = *starty; for (te = lb->first; te; te = te->next) { - bool draw_childs_grayed_out = draw_grayed_out || (te->drag_data != NULL); + bool draw_childs_grayed_out = draw_grayed_out || (te->flag & TE_DRAGGING); TreeStoreElem *tselem = TREESTORE(te); if (draw_childs_grayed_out) { @@ -1904,8 +1874,8 @@ static void outliner_draw_hierarchy_lines_recursive( static void outliner_draw_hierarchy_lines(SpaceOops *soops, ListBase *lb, int startx, int *starty) { - Gwn_VertFormat *format = immVertexFormat(); - uint pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_I32, 2, GWN_FETCH_INT_TO_FLOAT); + GPUVertFormat *format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT); unsigned char col[4]; immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); @@ -1927,8 +1897,8 @@ static void outliner_draw_struct_marks(ARegion *ar, SpaceOops *soops, ListBase * /* selection status */ if (TSELEM_OPEN(tselem, soops)) { if (tselem->type == TSE_RNA_STRUCT) { - Gwn_VertFormat *format = immVertexFormat(); - uint pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_I32, 2, GWN_FETCH_INT_TO_FLOAT); + GPUVertFormat *format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT); immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); immThemeColorShadeAlpha(TH_BACK, -15, -200); immRecti(pos, 0, *starty + 1, (int)ar->v2d.cur.xmax, *starty + UI_UNIT_Y - 1); @@ -1940,12 +1910,12 @@ static void outliner_draw_struct_marks(ARegion *ar, SpaceOops *soops, ListBase * if (TSELEM_OPEN(tselem, soops)) { outliner_draw_struct_marks(ar, soops, &te->subtree, starty); if (tselem->type == TSE_RNA_STRUCT) { - Gwn_VertFormat *format = immVertexFormat(); - uint pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + GPUVertFormat *format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); immThemeColorShadeAlpha(TH_BACK, -15, -200); - immBegin(GWN_PRIM_LINES, 2); + immBegin(GPU_PRIM_LINES, 2); immVertex2f(pos, 0, (float)*starty + UI_UNIT_Y); immVertex2f(pos, ar->v2d.cur.xmax, (float)*starty + UI_UNIT_Y); immEnd(); @@ -1976,18 +1946,42 @@ static void outliner_draw_highlights_recursive( immRecti(pos, 0, start_y + 1, (int)ar->v2d.cur.xmax, start_y + UI_UNIT_Y - 1); } - /* search match highlights - * we don't expand items when searching in the datablocks but we - * still want to highlight any filter matches. */ - if (is_searching && (tselem->flag & TSE_SEARCHMATCH)) { - immUniformColor4fv(col_searchmatch); - immRecti(pos, start_x, start_y + 1, ar->v2d.cur.xmax, start_y + UI_UNIT_Y - 1); - } + /* highlights */ + if (tselem->flag & (TSE_DRAG_ANY | TSE_HIGHLIGHTED | TSE_SEARCHMATCH)) { + const int end_x = (int)ar->v2d.cur.xmax; - /* mouse hover highlights */ - if ((tselem->flag & TSE_HIGHLIGHTED) || (te->drag_data != NULL)) { - immUniformColor4fv(col_highlight); - immRecti(pos, 0, start_y + 1, (int)ar->v2d.cur.xmax, start_y + UI_UNIT_Y - 1); + if (tselem->flag & TSE_DRAG_ANY) { + /* drag and drop highlight */ + float col[4]; + UI_GetThemeColorShade4fv(TH_BACK, -40, col); + + if (tselem->flag & TSE_DRAG_BEFORE) { + immUniformColor4fv(col); + immRecti(pos, start_x, start_y + UI_UNIT_Y - 1, end_x, start_y + UI_UNIT_Y + 1); + } + else if (tselem->flag & TSE_DRAG_AFTER) { + immUniformColor4fv(col); + immRecti(pos, start_x, start_y - 1, end_x, start_y + 1); + } + else { + immUniformColor3fvAlpha(col, col[3] * 0.5f); + immRecti(pos, start_x, start_y + 1, end_x, start_y + UI_UNIT_Y - 1); + } + } + else { + if (is_searching && (tselem->flag & TSE_SEARCHMATCH)) { + /* search match highlights + * we don't expand items when searching in the datablocks but we + * still want to highlight any filter matches. */ + immUniformColor4fv(col_searchmatch); + immRecti(pos, start_x, start_y + 1, end_x, start_y + UI_UNIT_Y - 1); + } + else if (tselem->flag & TSE_HIGHLIGHTED) { + /* mouse hover highlight */ + immUniformColor4fv(col_highlight); + immRecti(pos, 0, start_y + 1, end_x, start_y + UI_UNIT_Y - 1); + } + } } *io_start_y -= UI_UNIT_Y; @@ -2010,8 +2004,8 @@ static void outliner_draw_highlights(ARegion *ar, SpaceOops *soops, int startx, col_searchmatch[3] = 0.5f; GPU_blend(true); - Gwn_VertFormat *format = immVertexFormat(); - uint pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_I32, 2, GWN_FETCH_INT_TO_FLOAT); + GPUVertFormat *format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT); immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); outliner_draw_highlights_recursive( pos, ar, soops, &soops->tree, col_selection, col_highlight, col_searchmatch, @@ -2026,7 +2020,6 @@ static void outliner_draw_tree( TreeElement **te_edit) { const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; - TreeElement *te_floating = NULL; int starty, startx; GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); // only once @@ -2064,11 +2057,8 @@ static void outliner_draw_tree( for (TreeElement *te = soops->tree.first; te; te = te->next) { outliner_draw_tree_element( C, block, fstyle, scene, view_layer, - ar, soops, te, te->drag_data != NULL, - startx, &starty, te_edit, &te_floating); - } - if (te_floating && te_floating->drag_data->insert_handle) { - outliner_draw_tree_element_floating(ar, te_floating); + ar, soops, te, (te->flag & TE_DRAGGING) != 0, + startx, &starty, te_edit); } if (has_restrict_icons) { @@ -2085,8 +2075,8 @@ static void outliner_back(ARegion *ar) ystart = (int)ar->v2d.tot.ymax; ystart = UI_UNIT_Y * (ystart / (UI_UNIT_Y)) - OL_Y_OFFSET; - Gwn_VertFormat *format = immVertexFormat(); - uint pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + GPUVertFormat *format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); immUniformThemeColorShade(TH_BACK, 6); @@ -2096,7 +2086,7 @@ static void outliner_back(ARegion *ar) int tot = (int)floor(ystart - ar->v2d.cur.ymin + 2 * UI_UNIT_Y) / (2 * UI_UNIT_Y); if (tot > 0) { - immBegin(GWN_PRIM_TRIS, 6 * tot); + immBegin(GPU_PRIM_TRIS, 6 * tot); while (tot--) { y1 -= 2 * UI_UNIT_Y; y2 = y1 + UI_UNIT_Y; @@ -2117,10 +2107,10 @@ static void outliner_draw_restrictcols(ARegion *ar) { GPU_line_width(1.0f); - uint pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_I32, 2, GWN_FETCH_INT_TO_FLOAT); + uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT); immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); immUniformThemeColorShadeAlpha(TH_BACK, -15, -200); - immBegin(GWN_PRIM_LINES, 8); + immBegin(GPU_PRIM_LINES, 8); immVertex2i(pos, (int)(ar->v2d.cur.xmax - OL_TOG_HIDEX), (int)ar->v2d.cur.ymax); immVertex2i(pos, (int)(ar->v2d.cur.xmax - OL_TOG_HIDEX), (int)ar->v2d.cur.ymin); diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index d9bcf05fa29..e895ff53bc5 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -90,73 +90,17 @@ #include "outliner_intern.h" /* ************************************************************** */ -/* Unused Utilities */ -// XXX: where to place these? - -/* This is not used anywhere at the moment */ -#if 0 -static void outliner_open_reveal(SpaceOops *soops, ListBase *lb, TreeElement *teFind, int *found) -{ - TreeElement *te; - TreeStoreElem *tselem; - - for (te = lb->first; te; te = te->next) { - /* check if this tree-element was the one we're seeking */ - if (te == teFind) { - *found = 1; - return; - } - - /* try to see if sub-tree contains it then */ - outliner_open_reveal(soops, &te->subtree, teFind, found); - if (*found) { - tselem = TREESTORE(te); - if (tselem->flag & TSE_CLOSED) - tselem->flag &= ~TSE_CLOSED; - return; - } - } -} -#endif - -static TreeElement *outliner_dropzone_element(TreeElement *te, const float fmval[2], const bool children) -{ - if ((fmval[1] > te->ys) && (fmval[1] < (te->ys + UI_UNIT_Y))) { - /* name and first icon */ - if ((fmval[0] > te->xs + UI_UNIT_X) && (fmval[0] < te->xend)) - return te; - } - /* Not it. Let's look at its children. */ - if (children && (TREESTORE(te)->flag & TSE_CLOSED) == 0 && (te->subtree.first)) { - for (te = te->subtree.first; te; te = te->next) { - TreeElement *te_valid = outliner_dropzone_element(te, fmval, children); - if (te_valid) - return te_valid; - } - } - return NULL; -} - -/* Used for drag and drop parenting */ -TreeElement *outliner_dropzone_find(const SpaceOops *soops, const float fmval[2], const bool children) -{ - TreeElement *te; - - for (te = soops->tree.first; te; te = te->next) { - TreeElement *te_valid = outliner_dropzone_element(te, fmval, children); - if (te_valid) - return te_valid; - } - return NULL; -} - - -/* ************************************************************** */ /* Highlight --------------------------------------------------- */ static int outliner_highlight_update(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) { + /* Drag and drop does own highlighting. */ + wmWindowManager *wm = CTX_wm_manager(C); + if (wm->drags.first) { + return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH); + } + ARegion *ar = CTX_wm_region(C); SpaceOops *soops = CTX_wm_space_outliner(C); const float my = UI_view2d_region_to_view_y(&ar->v2d, event->mval[1]); @@ -165,7 +109,7 @@ static int outliner_highlight_update(bContext *C, wmOperator *UNUSED(op), const bool changed = false; if (!hovered_te || !(hovered_te->store_elem->flag & TSE_HIGHLIGHTED)) { - changed = outliner_flag_set(&soops->tree, TSE_HIGHLIGHTED, false); + changed = outliner_flag_set(&soops->tree, TSE_HIGHLIGHTED | TSE_DRAG_ANY, false); if (hovered_te) { hovered_te->store_elem->flag |= TSE_HIGHLIGHTED; changed = true; @@ -1951,474 +1895,3 @@ void OUTLINER_OT_orphans_purge(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } - -/* ************************************************************** */ -/* DRAG AND DROP OPERATORS */ - -/* ******************** Parent Drop Operator *********************** */ - -static int parent_drop_exec(bContext *C, wmOperator *op) -{ - Object *par = NULL, *ob = NULL; - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - int partype = -1; - char parname[MAX_ID_NAME], childname[MAX_ID_NAME]; - - partype = RNA_enum_get(op->ptr, "type"); - RNA_string_get(op->ptr, "parent", parname); - par = (Object *)BKE_libblock_find_name(bmain, ID_OB, parname); - RNA_string_get(op->ptr, "child", childname); - ob = (Object *)BKE_libblock_find_name(bmain, ID_OB, childname); - - if (ID_IS_LINKED(ob)) { - BKE_report(op->reports, RPT_INFO, "Can't edit library linked object"); - return OPERATOR_CANCELLED; - } - - ED_object_parent_set(op->reports, C, scene, ob, par, partype, false, false, NULL); - - DEG_relations_tag_update(bmain); - WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); - WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, NULL); - - return OPERATOR_FINISHED; -} - -static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event) -{ - Object *par = NULL; - Object *ob = NULL; - SpaceOops *soops = CTX_wm_space_outliner(C); - ARegion *ar = CTX_wm_region(C); - Main *bmain = CTX_data_main(C); - Scene *scene = NULL; - TreeElement *te = NULL; - char childname[MAX_ID_NAME]; - char parname[MAX_ID_NAME]; - int partype = 0; - float fmval[2]; - - UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); - - /* Find object hovered over */ - te = outliner_dropzone_find(soops, fmval, true); - - if (te) { - RNA_string_set(op->ptr, "parent", te->name); - /* Identify parent and child */ - RNA_string_get(op->ptr, "child", childname); - ob = (Object *)BKE_libblock_find_name(bmain, ID_OB, childname); - RNA_string_get(op->ptr, "parent", parname); - par = (Object *)BKE_libblock_find_name(bmain, ID_OB, parname); - - if (ELEM(NULL, ob, par)) { - if (par == NULL) printf("par==NULL\n"); - return OPERATOR_CANCELLED; - } - if (ob == par) { - return OPERATOR_CANCELLED; - } - if (ID_IS_LINKED(ob)) { - BKE_report(op->reports, RPT_INFO, "Can't edit library linked object"); - return OPERATOR_CANCELLED; - } - - scene = (Scene *)outliner_search_back(soops, te, ID_SCE); - - if (scene == NULL) { - /* currently outlier organized in a way, that if there's no parent scene - * element for object it means that all displayed objects belong to - * active scene and parenting them is allowed (sergey) - */ - - scene = CTX_data_scene(C); - } - - if ((par->type != OB_ARMATURE) && (par->type != OB_CURVE) && (par->type != OB_LATTICE)) { - if (ED_object_parent_set(op->reports, C, scene, ob, par, partype, false, false, NULL)) { - DEG_relations_tag_update(bmain); - WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); - WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, NULL); - } - } - else { - /* Menu creation */ - wmOperatorType *ot = WM_operatortype_find("OUTLINER_OT_parent_drop", false); - uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("Set Parent To"), ICON_NONE); - uiLayout *layout = UI_popup_menu_layout(pup); - PointerRNA ptr; - - /* Cannot use uiItemEnumO()... have multiple properties to set. */ - uiItemFullO_ptr(layout, ot, IFACE_("Object"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr); - RNA_string_set(&ptr, "parent", parname); - RNA_string_set(&ptr, "child", childname); - RNA_enum_set(&ptr, "type", PAR_OBJECT); - - /* par becomes parent, make the associated menus */ - if (par->type == OB_ARMATURE) { - uiItemFullO_ptr(layout, ot, IFACE_("Armature Deform"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr); - RNA_string_set(&ptr, "parent", parname); - RNA_string_set(&ptr, "child", childname); - RNA_enum_set(&ptr, "type", PAR_ARMATURE); - - uiItemFullO_ptr(layout, ot, IFACE_(" With Empty Groups"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr); - RNA_string_set(&ptr, "parent", parname); - RNA_string_set(&ptr, "child", childname); - RNA_enum_set(&ptr, "type", PAR_ARMATURE_NAME); - - uiItemFullO_ptr(layout, ot, IFACE_(" With Envelope Weights"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr); - RNA_string_set(&ptr, "parent", parname); - RNA_string_set(&ptr, "child", childname); - RNA_enum_set(&ptr, "type", PAR_ARMATURE_ENVELOPE); - - uiItemFullO_ptr(layout, ot, IFACE_(" With Automatic Weights"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr); - RNA_string_set(&ptr, "parent", parname); - RNA_string_set(&ptr, "child", childname); - RNA_enum_set(&ptr, "type", PAR_ARMATURE_AUTO); - - uiItemFullO_ptr(layout, ot, IFACE_("Bone"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr); - RNA_string_set(&ptr, "parent", parname); - RNA_string_set(&ptr, "child", childname); - RNA_enum_set(&ptr, "type", PAR_BONE); - } - else if (par->type == OB_CURVE) { - uiItemFullO_ptr(layout, ot, IFACE_("Curve Deform"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr); - RNA_string_set(&ptr, "parent", parname); - RNA_string_set(&ptr, "child", childname); - RNA_enum_set(&ptr, "type", PAR_CURVE); - - uiItemFullO_ptr(layout, ot, IFACE_("Follow Path"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr); - RNA_string_set(&ptr, "parent", parname); - RNA_string_set(&ptr, "child", childname); - RNA_enum_set(&ptr, "type", PAR_FOLLOW); - - uiItemFullO_ptr(layout, ot, IFACE_("Path Constraint"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr); - RNA_string_set(&ptr, "parent", parname); - RNA_string_set(&ptr, "child", childname); - RNA_enum_set(&ptr, "type", PAR_PATH_CONST); - } - else if (par->type == OB_LATTICE) { - uiItemFullO_ptr(layout, ot, IFACE_("Lattice Deform"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr); - RNA_string_set(&ptr, "parent", parname); - RNA_string_set(&ptr, "child", childname); - RNA_enum_set(&ptr, "type", PAR_LATTICE); - } - - UI_popup_menu_end(C, pup); - - return OPERATOR_INTERFACE; - } - } - else { - return OPERATOR_CANCELLED; - } - - return OPERATOR_FINISHED; -} - -void OUTLINER_OT_parent_drop(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Drop to Set Parent"; - ot->description = "Drag to parent in Outliner"; - ot->idname = "OUTLINER_OT_parent_drop"; - - /* api callbacks */ - ot->invoke = parent_drop_invoke; - ot->exec = parent_drop_exec; - - ot->poll = ED_operator_outliner_active; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; - - /* properties */ - RNA_def_string(ot->srna, "child", "Object", MAX_ID_NAME, "Child", "Child Object"); - RNA_def_string(ot->srna, "parent", "Object", MAX_ID_NAME, "Parent", "Parent Object"); - RNA_def_enum(ot->srna, "type", prop_make_parent_types, 0, "Type", ""); -} - -static bool outliner_parenting_poll(bContext *C) -{ - SpaceOops *soops = CTX_wm_space_outliner(C); - - if (soops) { - if (soops->outlinevis == SO_SCENES) { - return true; - } - else if ((soops->outlinevis == SO_VIEW_LAYER) && - (soops->filter & SO_FILTER_NO_COLLECTION)) - { - return true; - } - } - - return false; -} - -static int parent_clear_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) -{ - Main *bmain = CTX_data_main(C); - Object *ob = NULL; - SpaceOops *soops = CTX_wm_space_outliner(C); - char obname[MAX_ID_NAME]; - - RNA_string_get(op->ptr, "dragged_obj", obname); - ob = (Object *)BKE_libblock_find_name(bmain, ID_OB, obname); - - /* search forwards to find the object */ - outliner_find_id(soops, &soops->tree, (ID *)ob); - - ED_object_parent_clear(ob, RNA_enum_get(op->ptr, "type")); - - DEG_relations_tag_update(bmain); - WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); - WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, NULL); - return OPERATOR_FINISHED; -} - -void OUTLINER_OT_parent_clear(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Drop to Clear Parent"; - ot->description = "Drag to clear parent in Outliner"; - ot->idname = "OUTLINER_OT_parent_clear"; - - /* api callbacks */ - ot->invoke = parent_clear_invoke; - - ot->poll = outliner_parenting_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; - - /* properties */ - RNA_def_string(ot->srna, "dragged_obj", "Object", MAX_ID_NAME, "Child", "Child Object"); - RNA_def_enum(ot->srna, "type", prop_clear_parent_types, 0, "Type", ""); -} - -static int scene_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event) -{ - Scene *scene = NULL; - Object *ob = NULL; - SpaceOops *soops = CTX_wm_space_outliner(C); - ARegion *ar = CTX_wm_region(C); - Main *bmain = CTX_data_main(C); - TreeElement *te = NULL; - char obname[MAX_ID_NAME]; - float fmval[2]; - - UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); - - /* Find object hovered over */ - te = outliner_dropzone_find(soops, fmval, false); - - if (te) { - RNA_string_set(op->ptr, "scene", te->name); - scene = (Scene *)BKE_libblock_find_name(bmain, ID_SCE, te->name); - - RNA_string_get(op->ptr, "object", obname); - ob = (Object *)BKE_libblock_find_name(bmain, ID_OB, obname); - - if (ELEM(NULL, ob, scene) || ID_IS_LINKED(scene)) { - return OPERATOR_CANCELLED; - } - - if (BKE_scene_has_object(scene, ob)) { - return OPERATOR_CANCELLED; - } - - Collection *collection; - if (scene != CTX_data_scene(C)) { - /* when linking to an inactive scene link to the master collection */ - collection = BKE_collection_master(scene); - } - else { - collection = CTX_data_collection(C); - } - - BKE_collection_object_add(bmain, collection, ob); - - for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { - Base *base = BKE_view_layer_base_find(view_layer, ob); - if (base) { - ED_object_base_select(base, BA_SELECT); - } - } - - DEG_relations_tag_update(bmain); - - DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE); - WM_main_add_notifier(NC_SCENE | ND_OB_SELECT, scene); - - return OPERATOR_FINISHED; - } - - return OPERATOR_CANCELLED; -} - -void OUTLINER_OT_scene_drop(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Drop Object to Scene"; - ot->description = "Drag object to scene in Outliner"; - ot->idname = "OUTLINER_OT_scene_drop"; - - /* api callbacks */ - ot->invoke = scene_drop_invoke; - - ot->poll = ED_operator_outliner_active; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; - - /* properties */ - RNA_def_string(ot->srna, "object", "Object", MAX_ID_NAME, "Object", "Target Object"); - RNA_def_string(ot->srna, "scene", "Scene", MAX_ID_NAME, "Scene", "Target Scene"); -} - -static int material_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event) -{ - Material *ma = NULL; - Object *ob = NULL; - Main *bmain = CTX_data_main(C); - SpaceOops *soops = CTX_wm_space_outliner(C); - ARegion *ar = CTX_wm_region(C); - TreeElement *te = NULL; - char mat_name[MAX_ID_NAME - 2]; - float fmval[2]; - - UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); - - /* Find object hovered over */ - te = outliner_dropzone_find(soops, fmval, true); - - if (te) { - RNA_string_set(op->ptr, "object", te->name); - ob = (Object *)BKE_libblock_find_name(bmain, ID_OB, te->name); - - RNA_string_get(op->ptr, "material", mat_name); - ma = (Material *)BKE_libblock_find_name(bmain, ID_MA, mat_name); - - if (ELEM(NULL, ob, ma)) { - return OPERATOR_CANCELLED; - } - - assign_material(bmain, ob, ma, ob->totcol + 1, BKE_MAT_ASSIGN_USERPREF); - - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, CTX_wm_view3d(C)); - WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_LINKS, ma); - - return OPERATOR_FINISHED; - } - - return OPERATOR_CANCELLED; -} - -void OUTLINER_OT_material_drop(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Drop Material on Object"; - ot->description = "Drag material to object in Outliner"; - ot->idname = "OUTLINER_OT_material_drop"; - - /* api callbacks */ - ot->invoke = material_drop_invoke; - - ot->poll = ED_operator_outliner_active; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; - - /* properties */ - RNA_def_string(ot->srna, "object", "Object", MAX_ID_NAME, "Object", "Target Object"); - RNA_def_string(ot->srna, "material", "Material", MAX_ID_NAME, "Material", "Target Material"); -} - -/* ******************** Collection Drop Operator *********************** */ - -static int collection_drop_exec(bContext *UNUSED(C), wmOperator *UNUSED(op)) -{ - /* TODO: implement */ -#if 0 - Object *par = NULL, *ob = NULL; - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - int partype = -1; - char parname[MAX_ID_NAME], childname[MAX_ID_NAME]; - - RNA_string_get(op->ptr, "parent", parname); - par = (Object *)BKE_libblock_find_name(ID_OB, parname); - RNA_string_get(op->ptr, "child", childname); - ob = (Object *)BKE_libblock_find_name(ID_OB, childname); - - if (ID_IS_LINKED(ob)) { - BKE_report(op->reports, RPT_INFO, "Can't edit library linked object"); - return OPERATOR_CANCELLED; - } - - ED_object_parent_set(op->reports, C, scene, ob, par, partype, false, false, NULL); - - DEG_relations_tag_update(bmain); - WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); - WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, NULL); -#endif - - return OPERATOR_FINISHED; -} - -static int collection_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event) -{ - SpaceOops *soops = CTX_wm_space_outliner(C); - ARegion *ar = CTX_wm_region(C); - Main *bmain = CTX_data_main(C); - char childname[MAX_ID_NAME]; - float fmval[2]; - - UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); - - /* Find object hovered over */ - TreeElement *te = outliner_dropzone_find(soops, fmval, true); - - if (!te || !outliner_is_collection_tree_element(te)) { - return OPERATOR_CANCELLED; - } - - Collection *collection = outliner_collection_from_tree_element(te); - - // TODO: don't use scene, makes no sense anymore - // TODO: move rather than link, change hover text - Scene *scene = BKE_scene_find_from_collection(bmain, collection); - BLI_assert(scene); - RNA_string_get(op->ptr, "child", childname); - Object *ob = (Object *)BKE_libblock_find_name(bmain, ID_OB, childname); - BKE_collection_object_add(bmain, collection, ob); - - DEG_id_tag_update(&collection->id, DEG_TAG_COPY_ON_WRITE); - DEG_relations_tag_update(bmain); - WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene); - - return OPERATOR_FINISHED; -} - -void OUTLINER_OT_collection_drop(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Link to Collection"; // TODO: rename to move? - ot->description = "Drag to move to collection in Outliner"; - ot->idname = "OUTLINER_OT_collection_drop"; - - /* api callbacks */ - ot->invoke = collection_drop_invoke; - ot->exec = collection_drop_exec; - - ot->poll = ED_operator_outliner_active; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; - - /* properties */ - RNA_def_string(ot->srna, "child", "Object", MAX_ID_NAME, "Child", "Child Object"); - RNA_def_string(ot->srna, "parent", "Collection", MAX_ID_NAME, "Parent", "Parent Collection"); -} diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h index 093ad9361c2..f8dc41b8d37 100644 --- a/source/blender/editors/space_outliner/outliner_intern.h +++ b/source/blender/editors/space_outliner/outliner_intern.h @@ -67,23 +67,6 @@ typedef enum TreeTraversalAction { TRAVERSE_SKIP_CHILDS, } TreeTraversalAction; -/** - * Callback type for reinserting elements at a different position, used to allow user customizable element order. - */ -typedef void (*TreeElementReinsertFunc)(struct Main *bmain, - struct Scene *scene, - struct SpaceOops *soops, - struct TreeElement *insert_element, - struct TreeElement *insert_handle, - TreeElementInsertType action, - const struct wmEvent *event); -/** - * Executed on (almost) each mouse move while dragging. It's supposed to give info - * if reinserting insert_element before/after/into insert_handle would be allowed. - * It's allowed to change the reinsert info here for non const pointers. - */ -typedef bool (*TreeElementReinsertPollFunc)(const struct TreeElement *insert_element, - struct TreeElement **io_insert_handle, TreeElementInsertType *io_action); typedef TreeTraversalAction (*TreeTraversalFunc)(struct TreeElement *te, void *customdata); @@ -99,19 +82,13 @@ typedef struct TreeElement { const char *name; void *directdata; // Armature Bones, Base, Sequence, Strip... PointerRNA rnaptr; // RNA Pointer - - /* callbacks - TODO should be moved into a type (like TreeElementType) */ - TreeElementReinsertFunc reinsert; - TreeElementReinsertPollFunc reinsert_poll; - - struct { - TreeElementInsertType insert_type; - /* the element before/after/into which we may insert the dragged one (NULL to insert at top) */ - struct TreeElement *insert_handle; - void *tooltip_draw_handle; - } *drag_data; } TreeElement; +typedef struct TreeElementIcon { + struct ID *drag_id, *drag_parent; + int icon; +} TreeElementIcon; + #define TREESTORE_ID_TYPE(_id) \ (ELEM(GS((_id)->name), ID_SCE, ID_LI, ID_OB, ID_ME, ID_CU, ID_MB, ID_NT, ID_MA, ID_TE, ID_IM, ID_LT, ID_LA, ID_CA) || \ ELEM(GS((_id)->name), ID_KE, ID_WO, ID_SPK, ID_GR, ID_AR, ID_AC, ID_BR, ID_PA, ID_GD, ID_LS, ID_LP) || \ @@ -126,6 +103,7 @@ enum { TE_LAZY_CLOSED = (1 << 2), TE_FREE_NAME = (1 << 3), TE_DISABLED = (1 << 4), + TE_DRAGGING = (1 << 5), }; /* button events */ @@ -209,6 +187,8 @@ TreeTraversalAction outliner_find_selected_objects(struct TreeElement *te, void void draw_outliner(const struct bContext *C); void restrictbutton_gr_restrict_flag(void *poin, void *poin2, int flag); +TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te); + /* outliner_select.c -------------------------------------------- */ eOLDrawState tree_element_type_active( struct bContext *C, struct Scene *scene, struct ViewLayer *view_layer, struct SpaceOops *soops, @@ -284,10 +264,18 @@ void item_object_mode_exit_cb( struct bContext *C, struct ReportList *reports, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data); -TreeElement *outliner_dropzone_find(const struct SpaceOops *soops, const float fmval[2], const bool children); - void outliner_set_coordinates(struct ARegion *ar, struct SpaceOops *soops); +/* outliner_dragdrop.c */ +void outliner_dropboxes(void); + +void OUTLINER_OT_item_drag_drop(struct wmOperatorType *ot); +void OUTLINER_OT_parent_drop(struct wmOperatorType *ot); +void OUTLINER_OT_parent_clear(struct wmOperatorType *ot); +void OUTLINER_OT_scene_drop(struct wmOperatorType *ot); +void OUTLINER_OT_material_drop(struct wmOperatorType *ot); +void OUTLINER_OT_collection_drop(struct wmOperatorType *ot); + /* ...................................................... */ void OUTLINER_OT_highlight_update(struct wmOperatorType *ot); @@ -319,12 +307,6 @@ void OUTLINER_OT_drivers_delete_selected(struct wmOperatorType *ot); void OUTLINER_OT_orphans_purge(struct wmOperatorType *ot); -void OUTLINER_OT_parent_drop(struct wmOperatorType *ot); -void OUTLINER_OT_parent_clear(struct wmOperatorType *ot); -void OUTLINER_OT_scene_drop(struct wmOperatorType *ot); -void OUTLINER_OT_material_drop(struct wmOperatorType *ot); -void OUTLINER_OT_collection_drop(struct wmOperatorType *ot); - /* outliner_tools.c ---------------------------------------------- */ void OUTLINER_OT_operation(struct wmOperatorType *ot); @@ -358,7 +340,11 @@ void OUTLINER_OT_collection_objects_deselect(struct wmOperatorType *ot); void OUTLINER_OT_collection_link(struct wmOperatorType *ot); void OUTLINER_OT_collection_instance(struct wmOperatorType *ot); void OUTLINER_OT_collection_exclude_set(struct wmOperatorType *ot); -void OUTLINER_OT_collection_include_set(struct wmOperatorType *ot); +void OUTLINER_OT_collection_exclude_clear(struct wmOperatorType *ot); +void OUTLINER_OT_collection_holdout_set(struct wmOperatorType *ot); +void OUTLINER_OT_collection_holdout_clear(struct wmOperatorType *ot); +void OUTLINER_OT_collection_indirect_only_set(struct wmOperatorType *ot); +void OUTLINER_OT_collection_indirect_only_clear(struct wmOperatorType *ot); /* outliner_utils.c ---------------------------------------------- */ diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c index 0dd492839c9..34d79ea5a61 100644 --- a/source/blender/editors/space_outliner/outliner_ops.c +++ b/source/blender/editors/space_outliner/outliner_ops.c @@ -55,353 +55,6 @@ #include "outliner_intern.h" -typedef struct OutlinerDragDropTooltip { - TreeElement *te; - void *handle; -} OutlinerDragDropTooltip; - -enum { - OUTLINER_ITEM_DRAG_CANCEL, - OUTLINER_ITEM_DRAG_CONFIRM, -}; - -static bool outliner_item_drag_drop_poll(bContext *C) -{ - SpaceOops *soops = CTX_wm_space_outliner(C); - return ED_operator_outliner_active(C) && - /* Only collection display modes supported for now. Others need more design work */ - ELEM(soops->outlinevis, SO_VIEW_LAYER, SO_LIBRARIES); -} - -static TreeElement *outliner_item_drag_element_find(SpaceOops *soops, ARegion *ar, const wmEvent *event) -{ - /* note: using EVT_TWEAK_ events to trigger dragging is fine, - * it sends coordinates from where dragging was started */ - const float my = UI_view2d_region_to_view_y(&ar->v2d, event->mval[1]); - return outliner_find_item_at_y(soops, &soops->tree, my); -} - -static void outliner_item_drag_end(wmWindow *win, OutlinerDragDropTooltip *data) -{ - MEM_SAFE_FREE(data->te->drag_data); - - if (data->handle) { - WM_draw_cb_exit(win, data->handle); - } - - MEM_SAFE_FREE(data); -} - -static void outliner_item_drag_get_insert_data( - const SpaceOops *soops, ARegion *ar, const wmEvent *event, TreeElement *te_dragged, - TreeElement **r_te_insert_handle, TreeElementInsertType *r_insert_type) -{ - TreeElement *te_hovered; - float view_mval[2]; - - UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &view_mval[0], &view_mval[1]); - te_hovered = outliner_find_item_at_y(soops, &soops->tree, view_mval[1]); - - if (te_hovered) { - /* mouse hovers an element (ignoring x-axis), now find out how to insert the dragged item exactly */ - - if (te_hovered == te_dragged) { - *r_te_insert_handle = te_dragged; - } - else if (te_hovered != te_dragged) { - const float margin = UI_UNIT_Y * (1.0f / 4); - - *r_te_insert_handle = te_hovered; - if (view_mval[1] < (te_hovered->ys + margin)) { - if (TSELEM_OPEN(TREESTORE(te_hovered), soops)) { - /* inserting after a open item means we insert into it, but as first child */ - if (BLI_listbase_is_empty(&te_hovered->subtree)) { - *r_insert_type = TE_INSERT_INTO; - } - else { - *r_insert_type = TE_INSERT_BEFORE; - *r_te_insert_handle = te_hovered->subtree.first; - } - } - else { - *r_insert_type = TE_INSERT_AFTER; - } - } - else if (view_mval[1] > (te_hovered->ys + (3 * margin))) { - *r_insert_type = TE_INSERT_BEFORE; - } - else { - *r_insert_type = TE_INSERT_INTO; - } - } - } - else { - /* mouse doesn't hover any item (ignoring x-axis), so it's either above list bounds or below. */ - - TreeElement *first = soops->tree.first; - TreeElement *last = soops->tree.last; - - if (view_mval[1] < last->ys) { - *r_te_insert_handle = last; - *r_insert_type = TE_INSERT_AFTER; - } - else if (view_mval[1] > (first->ys + UI_UNIT_Y)) { - *r_te_insert_handle = first; - *r_insert_type = TE_INSERT_BEFORE; - } - else { - BLI_assert(0); - } - } -} - -static void outliner_item_drag_handle( - SpaceOops *soops, ARegion *ar, const wmEvent *event, TreeElement *te_dragged) -{ - TreeElement *te_insert_handle; - TreeElementInsertType insert_type; - - outliner_item_drag_get_insert_data(soops, ar, event, te_dragged, &te_insert_handle, &insert_type); - - if (!te_dragged->reinsert_poll && - /* there is no reinsert_poll, so we do some generic checks (same types and reinsert callback is available) */ - (TREESTORE(te_dragged)->type == TREESTORE(te_insert_handle)->type) && - te_dragged->reinsert) - { - /* pass */ - } - else if (te_dragged == te_insert_handle) { - /* nothing will happen anyway, no need to do poll check */ - } - else if (!te_dragged->reinsert_poll || - !te_dragged->reinsert_poll(te_dragged, &te_insert_handle, &insert_type)) - { - te_insert_handle = NULL; - } - te_dragged->drag_data->insert_type = insert_type; - te_dragged->drag_data->insert_handle = te_insert_handle; -} - -/** - * Returns true if it is a collection and empty. - */ -static bool is_empty_collection(TreeElement *te) -{ - Collection *collection = outliner_collection_from_tree_element(te); - - if (!collection) { - return false; - } - - return BLI_listbase_is_empty(&collection->gobject) && - BLI_listbase_is_empty(&collection->children); -} - -static bool outliner_item_drag_drop_apply( - Main *bmain, - Scene *scene, - SpaceOops *soops, - OutlinerDragDropTooltip *data, - const wmEvent *event) -{ - TreeElement *dragged_te = data->te; - TreeElement *insert_handle = dragged_te->drag_data->insert_handle; - TreeElementInsertType insert_type = dragged_te->drag_data->insert_type; - - if ((insert_handle == dragged_te) || !insert_handle) { - /* No need to do anything */ - } - else if (dragged_te->reinsert) { - BLI_assert(!dragged_te->reinsert_poll || dragged_te->reinsert_poll(dragged_te, &insert_handle, - &insert_type)); - /* 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 && - dragged_te->drag_data->insert_type == insert_type); - - /* 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. */ - const bool should_open_collection = (insert_type == TE_INSERT_INTO) && is_empty_collection(insert_handle); - - dragged_te->reinsert(bmain, scene, soops, dragged_te, insert_handle, insert_type, event); - - if (should_open_collection && !is_empty_collection(insert_handle)) { - TREESTORE(insert_handle)->flag &= ~TSE_CLOSED; - } - return true; - } - - return false; -} - -static int outliner_item_drag_drop_modal(bContext *C, wmOperator *op, const wmEvent *event) -{ - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - ARegion *ar = CTX_wm_region(C); - SpaceOops *soops = CTX_wm_space_outliner(C); - OutlinerDragDropTooltip *data = op->customdata; - TreeElement *te_dragged = data->te; - int retval = OPERATOR_RUNNING_MODAL; - bool redraw = false; - bool skip_rebuild = true; - - switch (event->type) { - case EVT_MODAL_MAP: - if (event->val == OUTLINER_ITEM_DRAG_CONFIRM) { - if (outliner_item_drag_drop_apply(bmain, scene, soops, data, event)) { - skip_rebuild = false; - } - retval = OPERATOR_FINISHED; - } - else if (event->val == OUTLINER_ITEM_DRAG_CANCEL) { - retval = OPERATOR_CANCELLED; - } - else { - BLI_assert(0); - } - WM_event_add_mousemove(C); /* update highlight */ - outliner_item_drag_end(CTX_wm_window(C), data); - redraw = true; - break; - case MOUSEMOVE: - outliner_item_drag_handle(soops, ar, event, te_dragged); - redraw = true; - break; - } - - if (redraw) { - if (skip_rebuild) { - ED_region_tag_redraw_no_rebuild(ar); - } - else { - ED_region_tag_redraw(ar); - } - } - - return retval; -} - -static const char *outliner_drag_drop_tooltip_get( - const TreeElement *te_float) -{ - const char *name = NULL; - - const TreeElement *te_insert = te_float->drag_data->insert_handle; - if (te_float && outliner_is_collection_tree_element(te_float)) { - if (te_insert == NULL) { - name = TIP_("Move collection"); - } - else { - switch (te_float->drag_data->insert_type) { - case TE_INSERT_BEFORE: - if (te_insert->prev && outliner_is_collection_tree_element(te_insert->prev)) { - name = TIP_("Move between collections"); - } - else { - name = TIP_("Move before collection"); - } - break; - case TE_INSERT_AFTER: - if (te_insert->next && outliner_is_collection_tree_element(te_insert->next)) { - name = TIP_("Move between collections"); - } - else { - name = TIP_("Move after collection"); - } - break; - case TE_INSERT_INTO: - name = TIP_("Move inside collection"); - break; - } - } - } - else if ((TREESTORE(te_float)->type == 0) && (te_float->idcode == ID_OB)) { - name = TIP_("Move to collection (Ctrl to link)"); - } - - return name; -} - -static void outliner_drag_drop_tooltip_cb(const wmWindow *win, void *vdata) -{ - OutlinerDragDropTooltip *data = vdata; - const char *tooltip; - - int cursorx, cursory; - int x, y; - - tooltip = outliner_drag_drop_tooltip_get(data->te); - if (tooltip == NULL) { - return; - } - - cursorx = win->eventstate->x; - cursory = win->eventstate->y; - - x = cursorx + U.widget_unit; - y = cursory - U.widget_unit; - - /* Drawing. */ - const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; - - const float col_fg[4] = {1.0f, 1.0f, 1.0f, 1.0f}; - const float col_bg[4] = {0.0f, 0.0f, 0.0f, 0.2f}; - - GPU_blend(true); - UI_fontstyle_draw_simple_backdrop(fstyle, x, y, tooltip, col_fg, col_bg); - GPU_blend(false); -} - -static int outliner_item_drag_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event) -{ - ARegion *ar = CTX_wm_region(C); - SpaceOops *soops = CTX_wm_space_outliner(C); - TreeElement *te_dragged = outliner_item_drag_element_find(soops, ar, event); - - if (!te_dragged) { - return (OPERATOR_FINISHED | OPERATOR_PASS_THROUGH); - } - - OutlinerDragDropTooltip *data = MEM_mallocN(sizeof(OutlinerDragDropTooltip), __func__); - data->te = te_dragged; - - op->customdata = data; - te_dragged->drag_data = MEM_callocN(sizeof(*te_dragged->drag_data), __func__); - /* by default we don't change the item position */ - te_dragged->drag_data->insert_handle = te_dragged; - /* unset highlighted tree element, dragged one will be highlighted instead */ - outliner_flag_set(&soops->tree, TSE_HIGHLIGHTED, false); - - ED_region_tag_redraw_no_rebuild(ar); - - WM_event_add_modal_handler(C, op); - - data->handle = WM_draw_cb_activate(CTX_wm_window(C), outliner_drag_drop_tooltip_cb, data); - - return OPERATOR_RUNNING_MODAL; -} - -/** - * Notes about Outliner Item Drag 'n Drop: - * Right now only collections display mode is supported. But ideally all/most modes would support this. There are - * just some open design questions that have to be answered: do we want to allow mixing order of different data types - * (like render-layers and objects)? Would that be a purely visual change or would that have any other effect? ... - */ -static void OUTLINER_OT_item_drag_drop(wmOperatorType *ot) -{ - ot->name = "Drag and Drop"; - ot->idname = "OUTLINER_OT_item_drag_drop"; - ot->description = "Change the hierarchical position of an item by repositioning it using drag and drop"; - - ot->invoke = outliner_item_drag_drop_invoke; - ot->modal = outliner_item_drag_drop_modal; - - ot->poll = outliner_item_drag_drop_poll; - - ot->flag = OPTYPE_UNDO; -} - - /* ************************** registration **********************************/ void outliner_operatortypes(void) @@ -457,37 +110,11 @@ void outliner_operatortypes(void) WM_operatortype_append(OUTLINER_OT_collection_link); WM_operatortype_append(OUTLINER_OT_collection_instance); WM_operatortype_append(OUTLINER_OT_collection_exclude_set); - WM_operatortype_append(OUTLINER_OT_collection_include_set); -} - -static wmKeyMap *outliner_item_drag_drop_modal_keymap(wmKeyConfig *keyconf) -{ - static EnumPropertyItem modal_items[] = { - {OUTLINER_ITEM_DRAG_CANCEL, "CANCEL", 0, "Cancel", ""}, - {OUTLINER_ITEM_DRAG_CONFIRM, "CONFIRM", 0, "Confirm/Drop", ""}, - {0, NULL, 0, NULL, NULL} - }; - const char *map_name = "Outliner Item Drag & Drop Modal Map"; - - wmKeyMap *keymap = WM_modalkeymap_get(keyconf, map_name); - - /* this function is called for each spacetype, only needs to add map once */ - if (keymap && keymap->modal_items) - return NULL; - - keymap = WM_modalkeymap_add(keyconf, map_name, modal_items); - - /* items for modal map */ - WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, OUTLINER_ITEM_DRAG_CANCEL); - WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_PRESS, KM_ANY, 0, OUTLINER_ITEM_DRAG_CANCEL); - - WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, KM_ANY, 0, OUTLINER_ITEM_DRAG_CONFIRM); - WM_modalkeymap_add_item(keymap, RETKEY, KM_RELEASE, KM_ANY, 0, OUTLINER_ITEM_DRAG_CONFIRM); - WM_modalkeymap_add_item(keymap, PADENTER, KM_RELEASE, KM_ANY, 0, OUTLINER_ITEM_DRAG_CONFIRM); - - WM_modalkeymap_assign(keymap, "OUTLINER_OT_item_drag_drop"); - - return keymap; + WM_operatortype_append(OUTLINER_OT_collection_exclude_clear); + WM_operatortype_append(OUTLINER_OT_collection_holdout_set); + WM_operatortype_append(OUTLINER_OT_collection_holdout_clear); + WM_operatortype_append(OUTLINER_OT_collection_indirect_only_set); + WM_operatortype_append(OUTLINER_OT_collection_indirect_only_clear); } void outliner_keymap(wmKeyConfig *keyconf) @@ -570,12 +197,13 @@ void outliner_keymap(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "OBJECT_OT_move_to_collection", MKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "OBJECT_OT_link_to_collection", MKEY, KM_PRESS, KM_SHIFT, 0); + WM_keymap_add_item(keymap, "OUTLINER_OT_collection_exclude_set", EKEY, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "OUTLINER_OT_collection_exclude_clear", EKEY, KM_PRESS, KM_ALT, 0); + kmi = WM_keymap_add_item(keymap, "OBJECT_OT_hide_view_clear", HKEY, KM_PRESS, KM_ALT, 0); RNA_boolean_set(kmi->ptr, "select", false); kmi = WM_keymap_add_item(keymap, "OBJECT_OT_hide_view_set", HKEY, KM_PRESS, 0, 0); RNA_boolean_set(kmi->ptr, "unselected", false); kmi = WM_keymap_add_item(keymap, "OBJECT_OT_hide_view_set", HKEY, KM_PRESS, KM_SHIFT, 0); RNA_boolean_set(kmi->ptr, "unselected", true); - - outliner_item_drag_drop_modal_keymap(keyconf); } diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c index 7ab13f36953..ec5e11520a6 100644 --- a/source/blender/editors/space_outliner/outliner_select.c +++ b/source/blender/editors/space_outliner/outliner_select.c @@ -39,6 +39,7 @@ #include "DNA_scene_types.h" #include "DNA_sequence_types.h" #include "DNA_world_types.h" +#include "DNA_gpencil_types.h" #include "BLI_utildefines.h" #include "BLI_listbase.h" @@ -46,9 +47,11 @@ #include "BKE_armature.h" #include "BKE_collection.h" #include "BKE_context.h" +#include "BKE_gpencil.h" #include "BKE_layer.h" #include "BKE_main.h" #include "BKE_object.h" +#include "BKE_paint.h" #include "BKE_scene.h" #include "BKE_sequencer.h" #include "BKE_workspace.h" @@ -60,6 +63,7 @@ #include "ED_screen.h" #include "ED_sequencer.h" #include "ED_undo.h" +#include "ED_gpencil.h" #include "WM_api.h" #include "WM_types.h" @@ -470,6 +474,28 @@ static eOLDrawState tree_element_active_defgroup( return OL_DRAWSEL_NONE; } +static eOLDrawState UNUSED_FUNCTION(tree_element_active_gplayer)( + bContext *C, Scene *UNUSED(scene), TreeElement *te, TreeStoreElem *tselem, const eOLSetState set) +{ + bGPdata *gpd = (bGPdata *)tselem->id; + bGPDlayer *gpl = te->directdata; + + /* We can only have a single "active" layer at a time + * and there must always be an active layer... + */ + if (set != OL_SETSEL_NONE) { + if (gpl) { + BKE_gpencil_layer_setactive(gpd, gpl); + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_SELECTED, gpd); + } + } + else { + return OL_DRAWSEL_NORMAL; + } + + return OL_DRAWSEL_NONE; +} + static eOLDrawState tree_element_active_posegroup( bContext *C, Scene *UNUSED(scene), ViewLayer *view_layer, TreeElement *te, TreeStoreElem *tselem, const eOLSetState set) { @@ -1006,6 +1032,10 @@ static void do_outliner_item_activate_tree_element( } } } + else if (ELEM(te->idcode, ID_GD)) { + /* set grease pencil to object mode */ + WM_operator_name_call(C, "GPENCIL_OT_editmode_toggle", WM_OP_INVOKE_REGION_WIN, NULL); + } else { // rest of types tree_element_active(C, scene, view_layer, soops, te, OL_SETSEL_NORMAL, false); } diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index 28890e42139..55a437d6ad5 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -319,112 +319,11 @@ static void outliner_add_scene_contents(SpaceOops *soops, ListBase *lb, Scene *s if (outliner_animdata_test(sce->adt)) outliner_add_element(soops, lb, sce, te, TSE_ANIM_DATA, 0); - /* Grease Pencil */ - outliner_add_element(soops, lb, sce->gpd, te, 0, 0); -} - -TreeTraversalAction outliner_find_selected_objects(TreeElement *te, void *customdata) -{ - struct ObjectsSelectedData *data = customdata; - TreeStoreElem *tselem = TREESTORE(te); - - if (outliner_is_collection_tree_element(te)) { - return TRAVERSE_CONTINUE; - } - - if (tselem->type || (tselem->id == NULL) || (GS(tselem->id->name) != ID_OB)) { - return TRAVERSE_SKIP_CHILDS; - } - - BLI_addtail(&data->objects_selected_array, BLI_genericNodeN(te)); - - return TRAVERSE_CONTINUE; -} - -/** - * Move objects from a collection to another. - * We ignore the original object being inserted, we used it for polling only. - * Instead we move all the selected objects around. - */ -static void outliner_object_reorder( - Main *bmain, Scene *scene, - SpaceOops *soops, - TreeElement *insert_element, - TreeElement *insert_handle, TreeElementInsertType action, - const wmEvent *event) -{ - Collection *collection = outliner_collection_from_tree_element(insert_handle); - Collection *collection_ob_parent = NULL; - ID *id = insert_handle->store_elem->id; - - BLI_assert(action == TE_INSERT_INTO); - UNUSED_VARS_NDEBUG(action); - - struct ObjectsSelectedData data = { - .objects_selected_array = {NULL, NULL}, - }; - - const bool is_append = event->ctrl; - - /* Make sure we include the originally inserted element as well. */ - TREESTORE(insert_element)->flag |= TSE_SELECTED; - - outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, outliner_find_selected_objects, &data); - LISTBASE_FOREACH (LinkData *, link, &data.objects_selected_array) { - TreeElement *ten_selected = (TreeElement *)link->data; - Object *ob = (Object *)TREESTORE(ten_selected)->id; - - if (is_append) { - BKE_collection_object_add(bmain, collection, ob); - continue; - } - - /* Find parent collection of object. */ - if (ten_selected->parent) { - for (TreeElement *te_ob_parent = ten_selected->parent; te_ob_parent; te_ob_parent = te_ob_parent->parent) { - if (outliner_is_collection_tree_element(te_ob_parent)) { - collection_ob_parent = outliner_collection_from_tree_element(te_ob_parent); - break; - } - } - } - else { - collection_ob_parent = BKE_collection_master(scene); - } - - BKE_collection_object_move(bmain, scene, collection, collection_ob_parent, ob); - } - - BLI_freelistN(&data.objects_selected_array); - - DEG_relations_tag_update(bmain); - - /* TODO(sergey): Use proper flag for tagging here. */ - DEG_id_tag_update(id, 0); - - WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); -} - -static bool outliner_object_reorder_poll( - const TreeElement *insert_element, - TreeElement **io_insert_handle, TreeElementInsertType *io_action) -{ - if (outliner_is_collection_tree_element(*io_insert_handle) && - (insert_element->parent != *io_insert_handle)) - { - *io_action = TE_INSERT_INTO; - return true; - } - - return false; } // can be inlined if necessary static void outliner_add_object_contents(SpaceOops *soops, TreeElement *te, TreeStoreElem *tselem, Object *ob) { - te->reinsert = outliner_object_reorder; - te->reinsert_poll = outliner_object_reorder_poll; - if (outliner_animdata_test(ob->adt)) outliner_add_element(soops, &te->subtree, ob, te, TSE_ANIM_DATA, 0); @@ -1387,80 +1286,6 @@ static void outliner_add_orphaned_datablocks(Main *mainvar, SpaceOops *soops) } } -static void outliner_collections_reorder( - Main *bmain, - Scene *UNUSED(scene), - SpaceOops *soops, - TreeElement *insert_element, - TreeElement *insert_handle, - TreeElementInsertType action, - const wmEvent *UNUSED(event)) -{ - TreeElement *from_parent_te, *to_parent_te; - Collection *from_parent, *to_parent; - - Collection *collection = outliner_collection_from_tree_element(insert_element); - Collection *relative = NULL; - bool relative_after = false; - - from_parent_te = outliner_find_parent_element(&soops->tree, NULL, insert_element); - from_parent = (from_parent_te) ? outliner_collection_from_tree_element(from_parent_te) : NULL; - - if (ELEM(action, TE_INSERT_BEFORE, TE_INSERT_AFTER)) { - to_parent_te = outliner_find_parent_element(&soops->tree, NULL, insert_handle); - to_parent = (to_parent_te) ? outliner_collection_from_tree_element(to_parent_te) : NULL; - - relative = outliner_collection_from_tree_element(insert_handle); - relative_after = (action == TE_INSERT_AFTER); - } - else if (action == TE_INSERT_INTO) { - to_parent = outliner_collection_from_tree_element(insert_handle); - } - else { - BLI_assert(0); - return; - } - - if (!to_parent) { - return; - } - - BKE_collection_move(bmain, to_parent, from_parent, relative, relative_after, collection); - - DEG_relations_tag_update(bmain); -} - -static bool outliner_collections_reorder_poll( - const TreeElement *insert_element, - TreeElement **io_insert_handle, - TreeElementInsertType *io_action) -{ - /* Can't move master collection. */ - Collection *collection = outliner_collection_from_tree_element(insert_element); - if (collection->flag & COLLECTION_IS_MASTER) { - return false; - } - - /* Can only move into collections. */ - Collection *collection_handle = outliner_collection_from_tree_element(*io_insert_handle); - if (collection_handle == NULL) { - return false; - } - - /* We can't insert/before after master collection. */ - if (collection_handle->flag & COLLECTION_IS_MASTER) { - if (*io_action == TE_INSERT_BEFORE) { - /* can't go higher than master collection, insert into it */ - *io_action = TE_INSERT_INTO; - } - else if (*io_action == TE_INSERT_AFTER) { - *io_insert_handle = (*io_insert_handle)->subtree.last; - } - } - - return true; -} - static void outliner_add_layer_collection_objects( SpaceOops *soops, ListBase *tree, ViewLayer *layer, LayerCollection *lc, TreeElement *ten) @@ -1487,8 +1312,6 @@ static void outliner_add_layer_collections_recursive( ten->name = id->name + 2; ten->directdata = lc; - ten->reinsert = outliner_collections_reorder; - ten->reinsert_poll = outliner_collections_reorder_poll; const bool exclude = (lc->flag & LAYER_COLLECTION_EXCLUDE) != 0; if (exclude || @@ -1530,8 +1353,6 @@ BLI_INLINE void outliner_add_collection_init(TreeElement *te, Collection *collec } te->directdata = collection; - te->reinsert = outliner_collections_reorder; - te->reinsert_poll = outliner_collections_reorder_poll; } BLI_INLINE void outliner_add_collection_objects( diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c index e4e99f88bf4..b0d63aee7c0 100644 --- a/source/blender/editors/space_outliner/space_outliner.c +++ b/source/blender/editors/space_outliner/space_outliner.c @@ -93,196 +93,6 @@ static void outliner_main_region_init(wmWindowManager *wm, ARegion *ar) WM_event_add_dropbox_handler(&ar->handlers, lb); } -static bool outliner_parent_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event) -{ - ARegion *ar = CTX_wm_region(C); - SpaceOops *soops = CTX_wm_space_outliner(C); - float fmval[2]; - UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); - - if (drag->type == WM_DRAG_ID) { - ID *id = drag->poin; - if (GS(id->name) == ID_OB) { - /* Ensure item under cursor is valid drop target */ - TreeElement *te = outliner_dropzone_find(soops, fmval, true); - TreeStoreElem *tselem = te ? TREESTORE(te) : NULL; - - if (!te) { - /* pass */ - } - else if (te->idcode == ID_OB && tselem->type == 0) { - Scene *scene; - ID *te_id = tselem->id; - - /* check if dropping self or parent */ - if (te_id == id || (Object *)te_id == ((Object *)id)->parent) - return 0; - - /* check that parent/child are both in the same scene */ - scene = (Scene *)outliner_search_back(soops, te, ID_SCE); - - /* currently outliner organized in a way that if there's no parent scene - * element for object it means that all displayed objects belong to - * active scene and parenting them is allowed (sergey) - */ - if (!scene) { - return 1; - } - else { - for (ViewLayer *view_layer = scene->view_layers.first; - view_layer; - view_layer = view_layer->next) - { - if (BKE_view_layer_base_find(view_layer, (Object *)id)) { - return 1; - } - } - } - } - } - } - return 0; -} - -static void outliner_parent_drop_copy(wmDrag *drag, wmDropBox *drop) -{ - ID *id = drag->poin; - - RNA_string_set(drop->ptr, "child", id->name + 2); -} - -static bool outliner_parent_clear_poll(bContext *C, wmDrag *drag, const wmEvent *event) -{ - ARegion *ar = CTX_wm_region(C); - SpaceOops *soops = CTX_wm_space_outliner(C); - TreeElement *te = NULL; - float fmval[2]; - - UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); - - if (!ELEM(soops->outlinevis, SO_VIEW_LAYER)) { - return false; - } - - if (drag->type == WM_DRAG_ID) { - ID *id = drag->poin; - if (GS(id->name) == ID_OB) { - if (((Object *)id)->parent) { - if ((te = outliner_dropzone_find(soops, fmval, true))) { - TreeStoreElem *tselem = TREESTORE(te); - - switch (te->idcode) { - case ID_SCE: - return (ELEM(tselem->type, TSE_R_LAYER_BASE, TSE_R_LAYER)); - case ID_OB: - return (ELEM(tselem->type, TSE_MODIFIER_BASE, TSE_CONSTRAINT_BASE)); - /* Other codes to ignore? */ - } - } - return (te == NULL); - } - } - } - return 0; -} - -static void outliner_parent_clear_copy(wmDrag *drag, wmDropBox *drop) -{ - ID *id = drag->poin; - RNA_string_set(drop->ptr, "dragged_obj", id->name + 2); - - /* Set to simple parent clear type. Avoid menus for drag and drop if possible. - * If desired, user can toggle the different "Clear Parent" types in the operator - * menu on tool shelf. */ - RNA_enum_set(drop->ptr, "type", 0); -} - -static bool outliner_scene_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event) -{ - ARegion *ar = CTX_wm_region(C); - SpaceOops *soops = CTX_wm_space_outliner(C); - float fmval[2]; - UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); - - if (drag->type == WM_DRAG_ID) { - ID *id = drag->poin; - if (GS(id->name) == ID_OB) { - /* Ensure item under cursor is valid drop target */ - TreeElement *te = outliner_dropzone_find(soops, fmval, false); - return (te && te->idcode == ID_SCE && TREESTORE(te)->type == 0); - } - } - return 0; -} - -static void outliner_scene_drop_copy(wmDrag *drag, wmDropBox *drop) -{ - ID *id = drag->poin; - - RNA_string_set(drop->ptr, "object", id->name + 2); -} - -static bool outliner_material_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event) -{ - ARegion *ar = CTX_wm_region(C); - SpaceOops *soops = CTX_wm_space_outliner(C); - float fmval[2]; - UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); - - if (drag->type == WM_DRAG_ID) { - ID *id = drag->poin; - if (GS(id->name) == ID_MA) { - /* Ensure item under cursor is valid drop target */ - TreeElement *te = outliner_dropzone_find(soops, fmval, true); - return (te && te->idcode == ID_OB && TREESTORE(te)->type == 0); - } - } - return 0; -} - -static void outliner_material_drop_copy(wmDrag *drag, wmDropBox *drop) -{ - ID *id = drag->poin; - - RNA_string_set(drop->ptr, "material", id->name + 2); -} - -static bool outliner_collection_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event) -{ - ARegion *ar = CTX_wm_region(C); - SpaceOops *soops = CTX_wm_space_outliner(C); - float fmval[2]; - UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); - - if (drag->type == WM_DRAG_ID) { - ID *id = drag->poin; - if (ELEM(GS(id->name), ID_OB, ID_GR)) { - /* Ensure item under cursor is valid drop target */ - TreeElement *te = outliner_dropzone_find(soops, fmval, true); - return (te && outliner_is_collection_tree_element(te)); - } - } - return 0; -} - -static void outliner_collection_drop_copy(wmDrag *drag, wmDropBox *drop) -{ - ID *id = drag->poin; - RNA_string_set(drop->ptr, "child", id->name + 2); -} - -/* region dropbox definition */ -static void outliner_dropboxes(void) -{ - ListBase *lb = WM_dropboxmap_find("Outliner", SPACE_OUTLINER, RGN_TYPE_WINDOW); - - WM_dropbox_add(lb, "OUTLINER_OT_parent_drop", outliner_parent_drop_poll, outliner_parent_drop_copy); - WM_dropbox_add(lb, "OUTLINER_OT_parent_clear", outliner_parent_clear_poll, outliner_parent_clear_copy); - WM_dropbox_add(lb, "OUTLINER_OT_scene_drop", outliner_scene_drop_poll, outliner_scene_drop_copy); - WM_dropbox_add(lb, "OUTLINER_OT_material_drop", outliner_material_drop_poll, outliner_material_drop_copy); - WM_dropbox_add(lb, "OUTLINER_OT_collection_drop", outliner_collection_drop_poll, outliner_collection_drop_copy); -} - static void outliner_main_region_draw(const bContext *C, ARegion *ar) { View2D *v2d = &ar->v2d; |