Outliner: Properties editor sync on selection
When outliner datablocks are selected, switch to the corresponding tab for that datablock in properties editors. Only properties editors that share an edge with the outliner will change tabs. Additionally, when modifiers, constraints, and shader effects are selected from the outliner, the panel will be expanded in all properties editors. Part of T77408 Manifest Task: https://developer.blender.org/T63991 Differential Revision: https://developer.blender.org/D8638
This commit is contained in:
parent
5af8fc8192
commit
0e47e57eb7
Notes:
blender-bot
2023-02-14 02:52:35 +01:00
Referenced by issue #94079, Outliner: Object selected/deselected when clicking with RMB on it's object data [`Sync Selection` option causes this] Referenced by issue #93799, Outliner: Remap Users crash (for `ID Type` `Object`) Referenced by issue #82668, Properties editor "forgets" selected tab and always resets to Object properties tab when switching between objects or editors Referenced by issue #77408, Continued Outliner Improvements Design Referenced by issue #63991, Outliner/Properties syncing
|
@ -183,6 +183,8 @@ bool BKE_constraint_remove_ex(ListBase *list,
|
|||
bool clear_dep);
|
||||
bool BKE_constraint_remove(ListBase *list, struct bConstraint *con);
|
||||
|
||||
void BKE_constraint_panel_expand(struct bConstraint *con);
|
||||
|
||||
/* Constraints + Proxies function prototypes */
|
||||
void BKE_constraints_proxylocal_extract(struct ListBase *dst, struct ListBase *src);
|
||||
bool BKE_constraints_proxylocked_owner(struct Object *ob, struct bPoseChannel *pchan);
|
||||
|
|
|
@ -249,6 +249,7 @@ typedef struct GpencilModifierTypeInfo {
|
|||
void BKE_gpencil_modifier_init(void);
|
||||
|
||||
void BKE_gpencil_modifierType_panel_id(GpencilModifierType type, char *r_idname);
|
||||
void BKE_gpencil_modifier_panel_expand(struct GpencilModifierData *md);
|
||||
const GpencilModifierTypeInfo *BKE_gpencil_modifier_get_info(GpencilModifierType type);
|
||||
struct GpencilModifierData *BKE_gpencil_modifier_new(int type);
|
||||
void BKE_gpencil_modifier_free_ex(struct GpencilModifierData *md, const int flag);
|
||||
|
|
|
@ -396,6 +396,7 @@ const ModifierTypeInfo *BKE_modifier_get_info(ModifierType type);
|
|||
|
||||
/* For modifier UI panels. */
|
||||
void BKE_modifier_type_panel_id(ModifierType type, char *r_idname);
|
||||
void BKE_modifier_panel_expand(struct ModifierData *md);
|
||||
|
||||
/* Modifier utility calls, do call through type pointer and return
|
||||
* default values if pointer is optional.
|
||||
|
|
|
@ -151,6 +151,7 @@ typedef struct ShaderFxTypeInfo {
|
|||
void BKE_shaderfx_init(void);
|
||||
|
||||
void BKE_shaderfxType_panel_id(ShaderFxType type, char *r_idname);
|
||||
void BKE_shaderfx_panel_expand(struct ShaderFxData *fx);
|
||||
const ShaderFxTypeInfo *BKE_shaderfx_get_info(ShaderFxType type);
|
||||
struct ShaderFxData *BKE_shaderfx_new(int type);
|
||||
void BKE_shaderfx_free_ex(struct ShaderFxData *fx, const int flag);
|
||||
|
|
|
@ -5406,6 +5406,11 @@ bool BKE_constraint_remove_ex(ListBase *list, Object *ob, bConstraint *con, bool
|
|||
return false;
|
||||
}
|
||||
|
||||
void BKE_constraint_panel_expand(bConstraint *con)
|
||||
{
|
||||
con->ui_expand_flag |= (1 << 0);
|
||||
}
|
||||
|
||||
/* ......... */
|
||||
|
||||
/* Creates a new constraint, initializes its data, and returns it */
|
||||
|
|
|
@ -411,6 +411,11 @@ void BKE_gpencil_modifierType_panel_id(GpencilModifierType type, char *r_idname)
|
|||
strcat(r_idname, mti->name);
|
||||
}
|
||||
|
||||
void BKE_gpencil_modifier_panel_expand(GpencilModifierData *md)
|
||||
{
|
||||
md->ui_expand_flag |= (1 << 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic grease pencil modifier copy data.
|
||||
* \param md_src: Source modifier data
|
||||
|
|
|
@ -130,6 +130,11 @@ void BKE_modifier_type_panel_id(ModifierType type, char *r_idname)
|
|||
strcat(r_idname, mti->name);
|
||||
}
|
||||
|
||||
void BKE_modifier_panel_expand(ModifierData *md)
|
||||
{
|
||||
md->ui_expand_flag |= (1 << 0);
|
||||
}
|
||||
|
||||
/***/
|
||||
|
||||
ModifierData *BKE_modifier_new(int type)
|
||||
|
|
|
@ -175,6 +175,11 @@ void BKE_shaderfxType_panel_id(ShaderFxType type, char *r_idname)
|
|||
strcat(r_idname, fxi->name);
|
||||
}
|
||||
|
||||
void BKE_shaderfx_panel_expand(ShaderFxData *fx)
|
||||
{
|
||||
fx->ui_expand_flag |= (1 << 0);
|
||||
}
|
||||
|
||||
void BKE_shaderfx_copydata_generic(const ShaderFxData *fx_src, ShaderFxData *fx_dst)
|
||||
{
|
||||
const ShaderFxTypeInfo *fxi = BKE_shaderfx_get_info(fx_src->type);
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct bContext;
|
||||
struct SpaceProperties;
|
||||
|
||||
int ED_buttons_tabs_list(struct SpaceProperties *sbuts, short *context_tabs_array);
|
||||
|
@ -35,6 +36,8 @@ void ED_buttons_search_string_set(struct SpaceProperties *sbuts, const char *val
|
|||
int ED_buttons_search_string_length(struct SpaceProperties *sbuts);
|
||||
const char *ED_buttons_search_string_get(struct SpaceProperties *sbuts);
|
||||
|
||||
void ED_buttons_set_context(const struct bContext *C, PointerRNA *ptr, const int context);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -199,6 +199,7 @@ int ED_region_global_size_y(void);
|
|||
void ED_area_update_region_sizes(struct wmWindowManager *wm,
|
||||
struct wmWindow *win,
|
||||
struct ScrArea *area);
|
||||
bool ED_area_has_shared_border(struct ScrArea *a, struct ScrArea *b);
|
||||
|
||||
ScrArea *ED_screen_areas_iter_first(const struct wmWindow *win, const bScreen *screen);
|
||||
ScrArea *ED_screen_areas_iter_next(const bScreen *screen, const ScrArea *area);
|
||||
|
|
|
@ -1871,6 +1871,11 @@ void ED_area_update_region_sizes(wmWindowManager *wm, wmWindow *win, ScrArea *ar
|
|||
area->flag &= ~AREA_FLAG_REGION_SIZE_UPDATE;
|
||||
}
|
||||
|
||||
bool ED_area_has_shared_border(struct ScrArea *a, struct ScrArea *b)
|
||||
{
|
||||
return area_getorientation(a, b) != -1;
|
||||
}
|
||||
|
||||
/* called in screen_refresh, or screens_init, also area size changes */
|
||||
void ED_area_init(wmWindowManager *wm, wmWindow *win, ScrArea *area)
|
||||
{
|
||||
|
|
|
@ -56,6 +56,7 @@
|
|||
|
||||
#include "RNA_access.h"
|
||||
|
||||
#include "ED_buttons.h"
|
||||
#include "ED_physics.h"
|
||||
#include "ED_screen.h"
|
||||
|
||||
|
@ -512,11 +513,11 @@ static bool buttons_context_linestyle_pinnable(const bContext *C, ViewLayer *vie
|
|||
}
|
||||
#endif
|
||||
|
||||
static bool buttons_context_path(const bContext *C, ButsContextPath *path, int mainb, int flag)
|
||||
static bool buttons_context_path(
|
||||
const bContext *C, SpaceProperties *sbuts, ButsContextPath *path, int mainb, int flag)
|
||||
{
|
||||
/* Note we don't use CTX_data here, instead we get it from the window.
|
||||
* Otherwise there is a loop reading the context that we are setting. */
|
||||
SpaceProperties *sbuts = CTX_wm_space_properties(C);
|
||||
wmWindow *window = CTX_wm_window(C);
|
||||
Scene *scene = WM_window_get_active_scene(window);
|
||||
ViewLayer *view_layer = WM_window_get_active_view_layer(window);
|
||||
|
@ -660,14 +661,14 @@ void buttons_context_compute(const bContext *C, SpaceProperties *sbuts)
|
|||
int flag = 0;
|
||||
|
||||
/* Set scene path. */
|
||||
buttons_context_path(C, path, BCONTEXT_SCENE, pflag);
|
||||
buttons_context_path(C, sbuts, path, BCONTEXT_SCENE, pflag);
|
||||
|
||||
buttons_texture_context_compute(C, sbuts);
|
||||
|
||||
/* for each context, see if we can compute a valid path to it, if
|
||||
* this is the case, we know we have to display the button */
|
||||
for (int i = 0; i < BCONTEXT_TOT; i++) {
|
||||
if (buttons_context_path(C, path, i, pflag)) {
|
||||
if (buttons_context_path(C, sbuts, path, i, pflag)) {
|
||||
flag |= (1 << i);
|
||||
|
||||
/* setting icon for data context */
|
||||
|
@ -713,7 +714,7 @@ void buttons_context_compute(const bContext *C, SpaceProperties *sbuts)
|
|||
}
|
||||
}
|
||||
|
||||
buttons_context_path(C, path, sbuts->mainb, pflag);
|
||||
buttons_context_path(C, sbuts, path, sbuts->mainb, pflag);
|
||||
|
||||
if (!(flag & (1 << sbuts->mainb))) {
|
||||
if (flag & (1 << BCONTEXT_OBJECT)) {
|
||||
|
@ -734,6 +735,39 @@ void buttons_context_compute(const bContext *C, SpaceProperties *sbuts)
|
|||
sbuts->pathflag = flag;
|
||||
}
|
||||
|
||||
static bool is_pointer_in_path(ButsContextPath *path, PointerRNA *ptr)
|
||||
{
|
||||
for (int i = 0; i < path->len; ++i) {
|
||||
if (ptr->owner_id == path->ptr[i].owner_id) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ED_buttons_set_context(const bContext *C, PointerRNA *ptr, const int context)
|
||||
{
|
||||
ScrArea *active_area = CTX_wm_area(C);
|
||||
bScreen *screen = CTX_wm_screen(C);
|
||||
|
||||
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
|
||||
/* Only update for properties editors that are visible and share a border. */
|
||||
if (area->spacetype != SPACE_PROPERTIES) {
|
||||
continue;
|
||||
}
|
||||
if (!ED_area_has_shared_border(active_area, area)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
SpaceProperties *sbuts = (SpaceProperties *)area->spacedata.first;
|
||||
ButsContextPath path;
|
||||
if (buttons_context_path(C, sbuts, &path, context, 0) && is_pointer_in_path(&path, ptr)) {
|
||||
sbuts->mainbuser = context;
|
||||
sbuts->mainb = sbuts->mainbuser;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/************************* Context Callback ************************/
|
||||
|
||||
const char *buttons_context_dir[] = {
|
||||
|
|
|
@ -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,27 @@
|
|||
|
||||
#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"
|
||||
|
@ -769,15 +779,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 +1030,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:
|
||||
|
@ -1049,6 +1071,169 @@ bPoseChannel *outliner_find_parent_bone(TreeElement *te, TreeElement **r_bone_te
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================ */
|
||||
|
||||
/**
|
||||
|
@ -1073,14 +1258,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,
|
||||
|
@ -1155,6 +1334,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 */
|
||||
|
|
Loading…
Reference in New Issue