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:
authorNathan Craddock <nzcraddock@gmail.com>2020-09-10 17:35:58 +0300
committerNathan Craddock <nzcraddock@gmail.com>2020-09-10 18:01:27 +0300
commit2110af20f5e636cd4481152e8cbe920dfa1efa8c (patch)
treee8b005723d97306876d23e17ab7048960bc11b81 /source/blender/editors/space_outliner/outliner_select.c
parent0649e6371629507c201310f7ece628a926d846d5 (diff)
Outliner: Move mode toggling to left column
Add a column of icons in the left gutter of the outliner for controlling the interaction modes of objects. When an object is in a mode other than object mode, the mode icon will draw to the left of that object. Any other objects that are valid to be added or swapped into the mode are drawn with a dot to the left of the object. Clicking the dot to the left of an object will swap that object with the current active object in the interaction mode. For edit and pose modes, ctrl clicking the dot will add that object to the current mode. Clicking the mode icon next to the active object removes it and all other objects from the current mode. The behavior is nearly identical to the previous edit/pose mode toggling by selecting the mesh and armature datablocks, with additional support for all interaction modes. Currently two undo steps are pushed to prevent an assert. Part of T77408 Manifest Task: https://developer.blender.org/T68498 Differential Revision: https://developer.blender.org/D8641
Diffstat (limited to 'source/blender/editors/space_outliner/outliner_select.c')
-rw-r--r--source/blender/editors/space_outliner/outliner_select.c225
1 files changed, 75 insertions, 150 deletions
diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c
index 266ea293d43..fe40d4cfd36 100644
--- a/source/blender/editors/space_outliner/outliner_select.c
+++ b/source/blender/editors/space_outliner/outliner_select.c
@@ -64,6 +64,7 @@
#include "ED_undo.h"
#include "WM_api.h"
+#include "WM_toolsystem.h"
#include "WM_types.h"
#include "UI_interface.h"
@@ -74,187 +75,99 @@
#include "outliner_intern.h"
-static bool do_outliner_activate_common(bContext *C,
- Main *bmain,
- Depsgraph *depsgraph,
- Scene *scene,
- ViewLayer *view_layer,
- Base *base,
- const bool extend,
- const bool do_exit)
+static void do_outliner_item_editmode_toggle(bContext *C, Scene *scene, Base *base)
{
- bool use_all = false;
-
- if (do_exit) {
- FOREACH_OBJECT_BEGIN (view_layer, ob_iter) {
- ED_object_mode_generic_exit(bmain, depsgraph, scene, ob_iter);
- }
- FOREACH_OBJECT_END;
- }
-
- /* Just like clicking in the object changes the active object,
- * clicking on the object data should change it as well. */
- ED_object_base_activate(C, base);
+ Main *bmain = CTX_data_main(C);
+ Object *ob = base->object;
- if (extend) {
- use_all = true;
+ 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);
}
else {
- ED_object_base_deselect_all(view_layer, NULL, SEL_DESELECT);
+ ED_object_editmode_enter_ex(CTX_data_main(C), scene, ob, EM_NO_CONTEXT);
+ WM_event_add_notifier(C, NC_SCENE | ND_MODE, NULL);
}
-
- return use_all;
}
-/**
- * Bring the newly selected object into edit mode.
- *
- * If extend is used, we try to have the other compatible selected objects in the new mode as well.
- * Otherwise only the new object will be active, selected and in the edit mode.
- */
-static void do_outliner_item_editmode_toggle(
- bContext *C, Scene *scene, ViewLayer *view_layer, Base *base, const bool extend)
+static void do_outliner_item_posemode_toggle(bContext *C, Base *base)
{
Main *bmain = CTX_data_main(C);
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- Object *obact = OBACT(view_layer);
Object *ob = base->object;
- bool use_all = false;
- if (obact == NULL) {
- ED_object_base_activate(C, base);
- DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
- WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
- obact = ob;
- use_all = true;
+ if (ID_IS_LINKED(ob)) {
+ BKE_report(CTX_wm_reports(C), RPT_WARNING, "Cannot pose libdata");
}
- else if (obact->data == ob->data) {
- use_all = true;
- }
- else if (obact->mode == OB_MODE_OBJECT) {
- use_all = do_outliner_activate_common(
- C, bmain, depsgraph, scene, view_layer, base, extend, false);
- }
- else if ((ob->type != obact->type) || ((obact->mode & OB_MODE_EDIT) == 0) ||
- ((obact->mode & OB_MODE_POSE) && ELEM(OB_ARMATURE, ob->type, obact->type)) || !extend) {
- use_all = do_outliner_activate_common(
- C, bmain, depsgraph, scene, view_layer, base, extend, true);
- }
-
- if (use_all) {
- WM_operator_name_call(C, "OBJECT_OT_editmode_toggle", WM_OP_INVOKE_REGION_WIN, NULL);
+ 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);
}
else {
- bool ok;
- if (BKE_object_is_in_editmode(ob)) {
- ok = ED_object_editmode_exit_ex(bmain, scene, ob, EM_FREEDATA);
- }
- else {
- ok = ED_object_editmode_enter_ex(CTX_data_main(C), scene, ob, EM_NO_CONTEXT);
- }
- if (ok) {
- ED_object_base_select(base, (ob->mode & OB_MODE_EDIT) ? BA_SELECT : BA_DESELECT);
- DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
- WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
- }
+ ED_object_posemode_enter_ex(bmain, ob);
+ WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_POSE, NULL);
}
}
-static void do_outliner_item_posemode_toggle(
- bContext *C, Scene *scene, ViewLayer *view_layer, Base *base, const bool extend)
+/* Swap the current active object from the interaction mode with the given base. */
+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);
- Object *obact = OBACT(view_layer);
- Object *ob = base->object;
- bool use_all = false;
+ const int active_mode = tvc->obact->mode;
- if (obact == NULL) {
- ED_object_base_activate(C, base);
- DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
- WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
- obact = ob;
- use_all = true;
- }
- else if (obact->data == ob->data) {
- use_all = true;
+ /* 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);
}
- else if (obact->mode == OB_MODE_OBJECT) {
- use_all = do_outliner_activate_common(
- C, bmain, depsgraph, scene, view_layer, base, extend, false);
- }
- else if ((!ELEM(ob->type, obact->type)) ||
- ((obact->mode & OB_MODE_EDIT) && ELEM(OB_ARMATURE, ob->type, obact->type))) {
- use_all = do_outliner_activate_common(
- C, bmain, depsgraph, scene, view_layer, base, extend, true);
- }
-
- if (use_all) {
- WM_operator_name_call(C, "OBJECT_OT_posemode_toggle", WM_OP_INVOKE_REGION_WIN, NULL);
- }
- else {
- bool ok = false;
-
- if (ID_IS_LINKED(ob)) {
- BKE_report(CTX_wm_reports(C), RPT_WARNING, "Cannot pose libdata");
- }
- else if (ob->mode & OB_MODE_POSE) {
- ok = ED_object_posemode_exit_ex(bmain, ob);
- }
- else {
- ok = ED_object_posemode_enter_ex(bmain, ob);
- }
+ FOREACH_OBJECT_END;
+ WM_toolsystem_update_from_context_view3d(C);
- if (ok) {
- ED_object_base_select(base, (ob->mode & OB_MODE_POSE) ? BA_SELECT : BA_DESELECT);
+ 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);
- DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
- WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, NULL);
- WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
- }
+ /* 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);
}
}
/* For draw callback to run mode switching */
-void outliner_object_mode_toggle(bContext *C, Scene *scene, ViewLayer *view_layer, Base *base)
+void outliner_object_mode_toggle(bContext *UNUSED(C),
+ Scene *UNUSED(scene),
+ ViewLayer *UNUSED(view_layer),
+ Base *UNUSED(base))
{
- Object *obact = OBACT(view_layer);
- if (obact->mode & OB_MODE_EDIT) {
- do_outliner_item_editmode_toggle(C, scene, view_layer, base, true);
- }
- else if (obact->mode & OB_MODE_POSE) {
- do_outliner_item_posemode_toggle(C, scene, view_layer, base, true);
- }
}
/* Toggle the item's interaction mode if supported */
-static void outliner_item_mode_toggle(bContext *C,
- TreeViewContext *tvc,
- TreeElement *te,
- const bool extend)
+void outliner_item_mode_toggle(bContext *C,
+ TreeViewContext *tvc,
+ TreeElement *te,
+ const bool do_extend)
{
TreeStoreElem *tselem = TREESTORE(te);
- if (tselem->type == 0) {
- if (OB_DATA_SUPPORT_EDITMODE(te->idcode)) {
- Object *ob = (Object *)outliner_search_back(te, ID_OB);
- if ((ob != NULL) && (ob->data == tselem->id)) {
- Base *base = BKE_view_layer_base_find(tvc->view_layer, ob);
- if ((base != NULL) && (base->flag & BASE_VISIBLE_DEPSGRAPH)) {
- do_outliner_item_editmode_toggle(C, tvc->scene, tvc->view_layer, base, extend);
- }
- }
- }
- 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 if (tselem->type == TSE_POSE_BASE) {
+ if (tselem->type == 0 && te->idcode == ID_OB) {
Object *ob = (Object *)tselem->id;
Base *base = BKE_view_layer_base_find(tvc->view_layer, ob);
- if (base != NULL) {
- do_outliner_item_posemode_toggle(C, tvc->scene, tvc->view_layer, base, extend);
+
+ /* Hidden objects can be removed from the mode. */
+ if (!base || (!(base->flag & BASE_VISIBLE_DEPSGRAPH) && (ob->mode != tvc->obact->mode))) {
+ return;
+ }
+
+ if (!do_extend) {
+ do_outliner_item_mode_toggle_generic(C, tvc, base);
+ }
+ else if (tvc->ob_edit && OB_TYPE_SUPPORT_EDITMODE(ob->type)) {
+ 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);
}
}
}
@@ -1272,11 +1185,6 @@ void outliner_item_select(bContext *C,
extend,
select_flag & OL_ITEM_RECURSIVE,
activate_data || space_outliner->flag & SO_SYNC_SELECT);
-
- /* Mode toggle on data activate for now, but move later */
- if (select_flag & OL_ITEM_TOGGLE_MODE) {
- outliner_item_mode_toggle(C, &tvc, te, extend);
- }
}
}
@@ -1353,6 +1261,16 @@ static bool outliner_is_co_within_restrict_columns(const SpaceOutliner *space_ou
return (view_co_x > region->v2d.cur.xmax - outliner_restrict_columns_width(space_outliner));
}
+bool outliner_is_co_within_mode_column(SpaceOutliner *space_outliner, const float view_mval[2])
+{
+ /* Mode toggles only show in View Layer and Scenes modes. */
+ if (!ELEM(space_outliner->outlinevis, SO_VIEW_LAYER, SO_SCENES)) {
+ return false;
+ }
+
+ return space_outliner->flag & SO_MODE_COLUMN && view_mval[0] < UI_UNIT_X;
+}
+
/**
* Action to run when clicking in the outliner,
*
@@ -1375,6 +1293,9 @@ 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;
}
+ else if (outliner_is_co_within_mode_column(space_outliner, view_mval)) {
+ return OPERATOR_CANCELLED;
+ }
if (!(te = outliner_find_item_at_y(space_outliner, &space_outliner->tree, view_mval[1]))) {
if (deselect_all) {
@@ -1413,7 +1334,7 @@ static int outliner_item_do_activate_from_cursor(bContext *C,
const short select_flag = OL_ITEM_ACTIVATE | (select ? OL_ITEM_SELECT : OL_ITEM_DESELECT) |
(is_over_name_icons ? OL_ITEM_SELECT_DATA : 0) |
- (extend ? OL_ITEM_EXTEND : 0) | OL_ITEM_TOGGLE_MODE;
+ (extend ? OL_ITEM_EXTEND : 0);
outliner_item_select(C, space_outliner, activate_te, select_flag);
}
@@ -1542,6 +1463,10 @@ 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)) {
+ return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
+ }
+
return WM_gesture_box_invoke(C, op, event);
}