diff options
Diffstat (limited to 'source/blender/editors/space_outliner/outliner_select.c')
-rw-r--r-- | source/blender/editors/space_outliner/outliner_select.c | 368 |
1 files changed, 305 insertions, 63 deletions
diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c index 61228e24ed9..044d75b4722 100644 --- a/source/blender/editors/space_outliner/outliner_select.c +++ b/source/blender/editors/space_outliner/outliner_select.c @@ -27,12 +27,16 @@ #include "DNA_armature_types.h" #include "DNA_collection_types.h" +#include "DNA_constraint_types.h" +#include "DNA_gpencil_modifier_types.h" #include "DNA_gpencil_types.h" #include "DNA_light_types.h" #include "DNA_material_types.h" +#include "DNA_modifier_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_sequence_types.h" +#include "DNA_shader_fx_types.h" #include "DNA_world_types.h" #include "BLI_listbase.h" @@ -40,21 +44,26 @@ #include "BKE_armature.h" #include "BKE_collection.h" +#include "BKE_constraint.h" #include "BKE_context.h" #include "BKE_gpencil.h" +#include "BKE_gpencil_modifier.h" #include "BKE_layer.h" #include "BKE_main.h" +#include "BKE_modifier.h" #include "BKE_object.h" #include "BKE_paint.h" +#include "BKE_particle.h" #include "BKE_report.h" #include "BKE_scene.h" -#include "BKE_sequencer.h" +#include "BKE_shader_fx.h" #include "BKE_workspace.h" #include "DEG_depsgraph.h" #include "DEG_depsgraph_build.h" #include "ED_armature.h" +#include "ED_buttons.h" #include "ED_gpencil.h" #include "ED_object.h" #include "ED_outliner.h" @@ -63,6 +72,8 @@ #include "ED_sequencer.h" #include "ED_undo.h" +#include "SEQ_sequencer.h" + #include "WM_api.h" #include "WM_toolsystem.h" #include "WM_types.h" @@ -75,64 +86,107 @@ #include "outliner_intern.h" +/** + * \note changes to selection are by convention and not essential. + * + * \note Handles own undo push. + */ static void do_outliner_item_editmode_toggle(bContext *C, Scene *scene, Base *base) { Main *bmain = CTX_data_main(C); Object *ob = base->object; + bool changed = false; if (BKE_object_is_in_editmode(ob)) { - ED_object_editmode_exit_ex(bmain, scene, ob, EM_FREEDATA); - WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, NULL); + changed = ED_object_editmode_exit_ex(bmain, scene, ob, EM_FREEDATA); + if (changed) { + ED_object_base_select(base, BA_DESELECT); + WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, NULL); + } } else { - ED_object_editmode_enter_ex(CTX_data_main(C), scene, ob, EM_NO_CONTEXT); - WM_event_add_notifier(C, NC_SCENE | ND_MODE, NULL); + changed = ED_object_editmode_enter_ex(CTX_data_main(C), scene, ob, EM_NO_CONTEXT); + if (changed) { + ED_object_base_select(base, BA_SELECT); + WM_event_add_notifier(C, NC_SCENE | ND_MODE, NULL); + } + } + + if (changed) { + DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); + ED_outliner_select_sync_from_object_tag(C); + ED_undo_push(C, "Outliner Edit Mode Toggle"); } } -static void do_outliner_item_posemode_toggle(bContext *C, Base *base) +/** + * \note changes to selection are by convention and not essential. + * + * \note Handles own undo push. + */ +static void do_outliner_item_posemode_toggle(bContext *C, Scene *scene, Base *base) { Main *bmain = CTX_data_main(C); Object *ob = base->object; if (ID_IS_LINKED(ob)) { BKE_report(CTX_wm_reports(C), RPT_WARNING, "Cannot pose libdata"); + return; } - else if (ob->mode & OB_MODE_POSE) { - ED_object_posemode_exit_ex(bmain, ob); - WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, NULL); + + bool changed = false; + if (ob->mode & OB_MODE_POSE) { + changed = ED_object_posemode_exit_ex(bmain, ob); + if (changed) { + ED_object_base_select(base, BA_DESELECT); + WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, NULL); + } } else { - ED_object_posemode_enter_ex(bmain, ob); - WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_POSE, NULL); + changed = ED_object_posemode_enter_ex(bmain, ob); + if (changed) { + ED_object_base_select(base, BA_SELECT); + WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_POSE, NULL); + } + } + + if (changed) { + DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); + ED_outliner_select_sync_from_object_tag(C); + ED_undo_push(C, "Outliner Pose Mode Toggle"); } } -/* Swap the current active object from the interaction mode with the given base. */ +/** + * Swap the current active object from the interaction mode with the given base. + * + * \note Changes to selection _are_ needed in this case, + * since entering the object mode uses the selection. + * + * If we didn't want to touch selection we could add an option to the operators + * not to do multi-object editing. + * + * \note Handles own undo push. + */ static void do_outliner_item_mode_toggle_generic(bContext *C, TreeViewContext *tvc, Base *base) { - Main *bmain = CTX_data_main(C); - Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); const int active_mode = tvc->obact->mode; + ED_undo_group_begin(C); - /* Return all objects to object mode. */ - FOREACH_OBJECT_BEGIN (tvc->view_layer, ob_iter) { - ED_object_mode_generic_exit(bmain, depsgraph, tvc->scene, ob_iter); - } - FOREACH_OBJECT_END; - WM_toolsystem_update_from_context_view3d(C); - - Base *base_active = BKE_view_layer_base_find(tvc->view_layer, tvc->obact); - if (base_active != base) { - ED_object_base_select(base_active, BA_DESELECT); - ED_object_base_activate(C, base); - ED_object_base_select(base, BA_SELECT); + if (ED_object_mode_set(C, OB_MODE_OBJECT)) { + Base *base_active = BKE_view_layer_base_find(tvc->view_layer, tvc->obact); + if (base_active != base) { + BKE_view_layer_base_deselect_all(tvc->view_layer); + BKE_view_layer_base_select_and_set_active(tvc->view_layer, base); + DEG_id_tag_update(&tvc->scene->id, ID_RECALC_SELECT); + ED_undo_push(C, "Change Active"); - /* XXX: Must add undo step between activation and setting mode to prevent an assert. */ - ED_undo_push(C, "outliner mode toggle"); - ED_object_mode_set(C, active_mode); - ED_outliner_select_sync_from_object_tag(C); + /* Operator call does undo push. */ + ED_object_mode_set(C, active_mode); + ED_outliner_select_sync_from_object_tag(C); + } } + ED_undo_group_end(C); } /* Toggle the item's interaction mode if supported */ @@ -159,7 +213,7 @@ void outliner_item_mode_toggle(bContext *C, do_outliner_item_editmode_toggle(C, tvc->scene, base); } else if (tvc->ob_pose && ob->type == OB_ARMATURE) { - do_outliner_item_posemode_toggle(C, base); + do_outliner_item_posemode_toggle(C, tvc->scene, base); } } } @@ -671,20 +725,9 @@ static eOLDrawState tree_element_active_bone(bContext *C, static void tree_element_active_ebone__sel(bContext *C, bArmature *arm, EditBone *ebone, short sel) { if (sel) { - ebone->flag |= BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL; arm->act_edbone = ebone; - /* Flush to parent? */ - if (ebone->parent && (ebone->flag & BONE_CONNECTED)) { - ebone->parent->flag |= BONE_TIPSEL; - } - } - else { - ebone->flag &= ~(BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL); - /* Flush to parent? */ - if (ebone->parent && (ebone->flag & BONE_CONNECTED)) { - ebone->parent->flag &= ~BONE_TIPSEL; - } } + ED_armature_ebone_select_set(ebone, sel); WM_event_add_notifier(C, NC_OBJECT | ND_BONE_ACTIVE, CTX_data_edit_object(C)); } static eOLDrawState tree_element_active_ebone(bContext *C, @@ -769,15 +812,26 @@ static eOLDrawState tree_element_active_psys(bContext *C, } static int tree_element_active_constraint(bContext *C, - Scene *UNUSED(scene), - ViewLayer *UNUSED(sl), - TreeElement *UNUSED(te), + Scene *scene, + ViewLayer *view_layer, + TreeElement *te, TreeStoreElem *tselem, const eOLSetState set) { if (set != OL_SETSEL_NONE) { Object *ob = (Object *)tselem->id; + /* Activate the parent bone if this is a bone constraint. */ + te = te->parent; + while (te) { + tselem = TREESTORE(te); + if (tselem->type == TSE_POSE_CHANNEL) { + tree_element_active_posechannel(C, scene, view_layer, ob, te, tselem, set, false); + return OL_DRAWSEL_NONE; + } + te = te->parent; + } + WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob); } @@ -1009,6 +1063,7 @@ eOLDrawState tree_element_type_active(bContext *C, case TSE_POSE_CHANNEL: return tree_element_active_posechannel( C, tvc->scene, tvc->view_layer, tvc->ob_pose, te, tselem, set, recursive); + case TSE_CONSTRAINT_BASE: case TSE_CONSTRAINT: return tree_element_active_constraint(C, tvc->scene, tvc->view_layer, te, tselem, set); case TSE_R_LAYER: @@ -1032,6 +1087,186 @@ eOLDrawState tree_element_type_active(bContext *C, return OL_DRAWSEL_NONE; } +bPoseChannel *outliner_find_parent_bone(TreeElement *te, TreeElement **r_bone_te) +{ + TreeStoreElem *tselem; + + te = te->parent; + while (te) { + tselem = TREESTORE(te); + if (tselem->type == TSE_POSE_CHANNEL) { + *r_bone_te = te; + return (bPoseChannel *)te->directdata; + } + te = te->parent; + } + + return NULL; +} + +static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreElem *tselem) +{ + PointerRNA ptr = {0}; + int context = 0; + + /* ID Types */ + if (tselem->type == 0) { + RNA_id_pointer_create(tselem->id, &ptr); + + switch (te->idcode) { + case ID_SCE: + context = BCONTEXT_SCENE; + break; + case ID_OB: + context = BCONTEXT_OBJECT; + break; + case ID_ME: + case ID_CU: + case ID_MB: + case ID_IM: + case ID_LT: + case ID_LA: + case ID_CA: + case ID_KE: + case ID_SPK: + case ID_AR: + case ID_GD: + case ID_LP: + case ID_HA: + case ID_PT: + case ID_VO: + context = BCONTEXT_DATA; + break; + case ID_MA: + context = BCONTEXT_MATERIAL; + break; + case ID_WO: + context = BCONTEXT_WORLD; + break; + } + } + else { + switch (tselem->type) { + case TSE_DEFGROUP_BASE: + case TSE_DEFGROUP: + RNA_id_pointer_create(tselem->id, &ptr); + context = BCONTEXT_DATA; + break; + case TSE_CONSTRAINT_BASE: + case TSE_CONSTRAINT: { + TreeElement *bone_te = NULL; + bPoseChannel *pchan = outliner_find_parent_bone(te, &bone_te); + + if (pchan) { + RNA_pointer_create(TREESTORE(bone_te)->id, &RNA_PoseBone, pchan, &ptr); + context = BCONTEXT_BONE_CONSTRAINT; + } + else { + RNA_id_pointer_create(tselem->id, &ptr); + context = BCONTEXT_CONSTRAINT; + } + + /* Expand the selected constraint in the properties editor. */ + if (tselem->type != TSE_CONSTRAINT_BASE) { + BKE_constraint_panel_expand(te->directdata); + } + break; + } + case TSE_MODIFIER_BASE: + case TSE_MODIFIER: + RNA_id_pointer_create(tselem->id, &ptr); + context = BCONTEXT_MODIFIER; + + if (tselem->type != TSE_MODIFIER_BASE) { + Object *ob = (Object *)tselem->id; + + if (ob->type == OB_GPENCIL) { + BKE_gpencil_modifier_panel_expand(te->directdata); + } + else { + BKE_modifier_panel_expand(te->directdata); + } + } + break; + case TSE_GPENCIL_EFFECT_BASE: + case TSE_GPENCIL_EFFECT: + RNA_id_pointer_create(tselem->id, &ptr); + context = BCONTEXT_SHADERFX; + + if (tselem->type != TSE_GPENCIL_EFFECT_BASE) { + BKE_shaderfx_panel_expand(te->directdata); + } + break; + case TSE_BONE: { + bArmature *arm = (bArmature *)tselem->id; + Bone *bone = te->directdata; + + RNA_pointer_create(&arm->id, &RNA_Bone, bone, &ptr); + context = BCONTEXT_BONE; + break; + } + case TSE_EBONE: { + bArmature *arm = (bArmature *)tselem->id; + EditBone *ebone = te->directdata; + + RNA_pointer_create(&arm->id, &RNA_EditBone, ebone, &ptr); + context = BCONTEXT_BONE; + break; + } + case TSE_POSE_CHANNEL: { + Object *ob = (Object *)tselem->id; + bArmature *arm = ob->data; + bPoseChannel *pchan = te->directdata; + + RNA_pointer_create(&arm->id, &RNA_PoseBone, pchan, &ptr); + context = BCONTEXT_BONE; + break; + } + case TSE_POSE_BASE: { + Object *ob = (Object *)tselem->id; + bArmature *arm = ob->data; + + RNA_pointer_create(&arm->id, &RNA_Armature, arm, &ptr); + context = BCONTEXT_DATA; + break; + } + case TSE_R_LAYER_BASE: + case TSE_R_LAYER: { + ViewLayer *view_layer = te->directdata; + + RNA_pointer_create(tselem->id, &RNA_ViewLayer, view_layer, &ptr); + context = BCONTEXT_VIEW_LAYER; + break; + } + case TSE_POSEGRP_BASE: + case TSE_POSEGRP: { + Object *ob = (Object *)tselem->id; + bArmature *arm = ob->data; + + RNA_pointer_create(&arm->id, &RNA_Armature, arm, &ptr); + context = BCONTEXT_DATA; + break; + } + case TSE_LINKED_PSYS: { + Object *ob = (Object *)tselem->id; + ParticleSystem *psys = psys_get_current(ob); + + RNA_pointer_create(&ob->id, &RNA_ParticleSystem, psys, &ptr); + context = BCONTEXT_PARTICLE; + break; + } + case TSE_GP_LAYER: + RNA_id_pointer_create(tselem->id, &ptr); + context = BCONTEXT_DATA; + break; + } + } + + if (ptr.data) { + ED_buttons_set_context(C, &ptr, context); + } +} + /* ================================================ */ /** @@ -1056,14 +1291,8 @@ static void do_outliner_item_activate_tree_element(bContext *C, TSE_SEQUENCE_DUP, TSE_EBONE, TSE_LAYER_COLLECTION)) { - /* Note about TSE_EBONE: In case of a same ID_AR datablock shared among several objects, - * we do not want to switch out of edit mode (see T48328 for details). */ - } - else if (tselem->id && OB_DATA_SUPPORT_EDITMODE(te->idcode)) { - /* Support edit-mode toggle, keeping the active object as is. */ - } - else if (tselem->type == TSE_POSE_BASE) { - /* Support pose mode toggle, keeping the active object as is. */ + /* Note about TSE_EBONE: In case of a same ID_AR datablock shared among several + * objects, we do not want to switch out of edit mode (see T48328 for details). */ } else if (do_activate_data) { tree_element_set_active_object(C, @@ -1138,6 +1367,8 @@ static void do_outliner_item_activate_tree_element(bContext *C, extend ? OL_SETSEL_EXTEND : OL_SETSEL_NORMAL, recursive); } + + outliner_set_properties_tab(C, te, tselem); } /* Select the item using the set flags */ @@ -1193,7 +1424,7 @@ static bool do_outliner_range_select_recursive(ListBase *lb, } /* Set state for selection */ - if (te == active || te == cursor) { + if (ELEM(te, active, cursor)) { selecting = !selecting; } @@ -1263,6 +1494,17 @@ bool outliner_is_co_within_mode_column(SpaceOutliner *space_outliner, const floa return space_outliner->flag & SO_MODE_COLUMN && view_mval[0] < UI_UNIT_X; } +static bool outliner_is_co_within_active_mode_column(bContext *C, + SpaceOutliner *space_outliner, + const float view_mval[2]) +{ + ViewLayer *view_layer = CTX_data_view_layer(C); + Object *obact = OBACT(view_layer); + + return outliner_is_co_within_mode_column(space_outliner, view_mval) && obact && + obact->mode != OB_MODE_OBJECT; +} + /** * Action to run when clicking in the outliner, * @@ -1285,7 +1527,7 @@ static int outliner_item_do_activate_from_cursor(bContext *C, if (outliner_is_co_within_restrict_columns(space_outliner, region, view_mval[0])) { return OPERATOR_CANCELLED; } - if (outliner_is_co_within_mode_column(space_outliner, view_mval)) { + if (outliner_is_co_within_active_mode_column(C, space_outliner, view_mval)) { return OPERATOR_CANCELLED; } @@ -1402,8 +1644,8 @@ static void outliner_item_box_select(bContext *C, /* Look at its children. */ if (TSELEM_OPEN(tselem, space_outliner)) { - for (te = te->subtree.first; te; te = te->next) { - outliner_item_box_select(C, space_outliner, scene, rectf, te, select); + LISTBASE_FOREACH (TreeElement *, te_sub, &te->subtree) { + outliner_item_box_select(C, space_outliner, scene, rectf, te_sub, select); } } } @@ -1455,7 +1697,7 @@ static int outliner_box_select_invoke(bContext *C, wmOperator *op, const wmEvent return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH; } - if (outliner_is_co_within_mode_column(space_outliner, view_mval)) { + if (outliner_is_co_within_active_mode_column(C, space_outliner, view_mval)) { return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH; } @@ -1649,7 +1891,7 @@ static TreeElement *find_walk_select_start_element(SpaceOutliner *space_outliner } /* Scroll the outliner when the walk element reaches the top or bottom boundary */ -static void outliner_walk_scroll(ARegion *region, TreeElement *te) +static void outliner_walk_scroll(SpaceOutliner *space_outliner, ARegion *region, TreeElement *te) { /* Account for the header height */ int y_max = region->v2d.cur.ymax - UI_UNIT_Y; @@ -1657,10 +1899,10 @@ static void outliner_walk_scroll(ARegion *region, TreeElement *te) /* Scroll if walked position is beyond the border */ if (te->ys > y_max) { - outliner_scroll_view(region, te->ys - y_max); + outliner_scroll_view(space_outliner, region, te->ys - y_max); } else if (te->ys < y_min) { - outliner_scroll_view(region, -(y_min - te->ys)); + outliner_scroll_view(space_outliner, region, -(y_min - te->ys)); } } @@ -1687,7 +1929,7 @@ static int outliner_walk_select_invoke(bContext *C, wmOperator *op, const wmEven OL_ITEM_SELECT | OL_ITEM_ACTIVATE | (extend ? OL_ITEM_EXTEND : 0)); /* Scroll outliner to focus on walk element */ - outliner_walk_scroll(region, active_te); + outliner_walk_scroll(space_outliner, region, active_te); ED_outliner_select_sync_from_outliner(C, space_outliner); outliner_tag_redraw_avoid_rebuild_on_open_change(space_outliner, region); |