Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/editors/space_outliner/outliner_select.c')
-rw-r--r--source/blender/editors/space_outliner/outliner_select.c368
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);