Compare commits
219 Commits
temp-geome
...
soc-2020-o
Author | SHA1 | Date | |
---|---|---|---|
6ae45c0874 | |||
d613d9fec2 | |||
37f9b915ac | |||
65afd36ed7 | |||
1d78720e74 | |||
538bb8002c | |||
aff36e4082 | |||
8eee0a2712 | |||
ff8255f159 | |||
093294e167 | |||
4beb3c92df | |||
1cf39ca002 | |||
347af6aa9d | |||
a336b0c3a1 | |||
1fc322125d | |||
d689dd777c | |||
6e5642afb9 | |||
282866ad94 | |||
d1a7d93ace | |||
30801617a6 | |||
550835a73b | |||
2cf264009e | |||
7900cb3b35 | |||
63cd866f55 | |||
965aadd02a | |||
bec588da8a | |||
d0cf7a3e85 | |||
2222d445ef | |||
e0d6c13a44 | |||
4fa4b2742d | |||
19525d4a11 | |||
8da9fd000b | |||
0e360a4a2d | |||
6467d34d00 | |||
d4dad94db5 | |||
44d8093f3d | |||
a11a0083b7 | |||
12bd445aab | |||
4350ea4ecd | |||
a0cd2dbcce | |||
ae09b1fdf2 | |||
cd0f918c1b | |||
4c673a6d48 | |||
d5f3ae7978 | |||
7c6b8d8db5 | |||
576028db53 | |||
be10ffb56d | |||
6d6ba343dd | |||
ecca5bbfc9 | |||
41d9e3dd68 | |||
c8eaede01d | |||
6a2c968c00 | |||
0518c9d582 | |||
bec2fad215 | |||
280404f0a1 | |||
1c5f46d293 | |||
da3cf18514 | |||
1b285bc43b | |||
698cde9344 | |||
8891cc2a1b | |||
90c60bb0ce | |||
8e483b44e7 | |||
43cc3fb17d | |||
63ba4633d1 | |||
3990b8edae | |||
fd221ce385 | |||
a6f4dbd6cb | |||
214223e864 | |||
15e59f4640 | |||
6c7d4bf72d | |||
5f8d7ad5b2 | |||
0ead199713 | |||
ba778a64b9 | |||
66a8ec44c7 | |||
247372cbe7 | |||
066f78e8f9 | |||
53452c452f | |||
aef6b5d10c | |||
ec57e6c790 | |||
5290d7e79f | |||
19557d0d82 | |||
601ce87b1a | |||
1c53386124 | |||
6eb096d80a | |||
814771e316 | |||
14f1a0ae7c | |||
96173be437 | |||
2832b37e8e | |||
cee0d1921f | |||
3815452e47 | |||
b178a1c9ca | |||
bc6bdf5b79 | |||
715f94d55b | |||
488134c80e | |||
e2febd8168 | |||
19d5d339d2 | |||
cebafc9854 | |||
a3fd574a74 | |||
04f969627d | |||
ba46eeff75 | |||
3d3ef71a39 | |||
0027319690 | |||
3ceebff60b | |||
3d197d30ec | |||
b7b2386cff | |||
7231cc5414 | |||
7faebce414 | |||
fe80f9c8d1 | |||
d00b886bfd | |||
e74b428d41 | |||
301f59a839 | |||
7a72f9b9f6 | |||
a5f4086e86 | |||
8e972bf72b | |||
c122597bf7 | |||
c4f23e1404 | |||
47a3013d68 | |||
982e795013 | |||
45d27e39e0 | |||
c3edf375c2 | |||
06928a7a4c | |||
51ce1255de | |||
5aa9a4f46a | |||
27177d84e8 | |||
7e83200003 | |||
e269f4bfca | |||
3c39c51d02 | |||
b034849e63 | |||
e59db98688 | |||
35a01f85e8 | |||
7269eba111 | |||
c4e2d23702 | |||
c4d6f0c0f2 | |||
6ac79a7dfb | |||
6140d22af3 | |||
2d2491dd81 | |||
7186d8117a | |||
263e2537c5 | |||
3155fa19c5 | |||
9d2e660643 | |||
c87f9ac840 | |||
7fdc6c5ca6 | |||
561bd0ebac | |||
4ac06b97ee | |||
f5a22d4bbd | |||
680b2a4901 | |||
cd3d261e3c | |||
abf079b64e | |||
05ddacc342 | |||
b134a0c491 | |||
3a7101f9e8 | |||
b485592901 | |||
cf97bd606e | |||
693c168c8a | |||
0f8678b536 | |||
def6f13b77 | |||
05da610ee7 | |||
1bb6d5cd75 | |||
a0931a5a70 | |||
e7123ab148 | |||
fdd643ebb6 | |||
07e11e5af2 | |||
4947aff2b9 | |||
086cad7624 | |||
95abb9967b | |||
ac24ce26b2 | |||
80bdeffac4 | |||
d99682c6ba | |||
0fcf476f04 | |||
fc08a33223 | |||
9e39bb2dbc | |||
75a9ba558e | |||
0eb4d9445a | |||
c7e5493b15 | |||
93189c4e08 | |||
e36dd0b7cf | |||
096cd76aa2 | |||
1d8a5b3772 | |||
9aa09d65c1 | |||
0bf5db9040 | |||
750d184812 | |||
13dd9eeb25 | |||
c87b8d0494 | |||
479aaccc93 | |||
a50f87d4b6 | |||
8451c5d5e0 | |||
bd1e3440fe | |||
1fb733ca74 | |||
1764f5b24d | |||
34e4dbec33 | |||
cfcba6574e | |||
bccfbc1b2d | |||
6fbf342e82 | |||
7d51351004 | |||
ed54ee3bac | |||
a36495e72d | |||
b09e0f8abe | |||
7a5ed7cc78 | |||
05861f4b59 | |||
4af045fbef | |||
64f74fc94e | |||
8113a8b0f6 | |||
b69f1ff119 | |||
53c61d2a4c | |||
78944dcadd | |||
7096d1b730 | |||
490d444097 | |||
45ee485703 | |||
cb2b5da12d | |||
ef48790804 | |||
f0caf178d0 | |||
86ce6c9280 | |||
e9d621e16e | |||
3eea51f6b5 | |||
82b1cd464e | |||
8db03500d7 | |||
fc7c19c9ab | |||
661ee21e69 | |||
f2a4dd4d27 |
BIN
release/datafiles/blender_icons16/icon16_outliner_collection.dat
Normal file
BIN
release/datafiles/blender_icons16/icon16_outliner_collection.dat
Normal file
Binary file not shown.
BIN
release/datafiles/blender_icons32/icon32_outliner_collection.dat
Normal file
BIN
release/datafiles/blender_icons32/icon32_outliner_collection.dat
Normal file
Binary file not shown.
@@ -1101,6 +1101,32 @@ const bTheme U_theme_default = {
|
||||
.active = RGBA(0x000000ff),
|
||||
},
|
||||
},
|
||||
.collection_color = {
|
||||
{
|
||||
.color = RGBA(0xe4312bff),
|
||||
},
|
||||
{
|
||||
.color = RGBA(0xef7e42ff),
|
||||
},
|
||||
{
|
||||
.color = RGBA(0xe4dd52ff),
|
||||
},
|
||||
{
|
||||
.color = RGBA(0x9ac546ff),
|
||||
},
|
||||
{
|
||||
.color = RGBA(0x46bcc2ff),
|
||||
},
|
||||
{
|
||||
.color = RGBA(0x8b65dcff),
|
||||
},
|
||||
{
|
||||
.color = RGBA(0x999999ff),
|
||||
},
|
||||
{
|
||||
.color = RGBA(0x06d4432ff),
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/* clang-format on */
|
||||
|
@@ -68,7 +68,7 @@ class OUTLINER_HT_header(Header):
|
||||
sub.prop(space, "filter_id_type", text="", icon_only=True)
|
||||
|
||||
if display_mode == 'VIEW_LAYER':
|
||||
layout.operator("outliner.collection_new", text="", icon='COLLECTION_NEW').nested = True
|
||||
layout.operator("outliner.collection_new", text="", icon='COLLECTION_NEW')
|
||||
|
||||
elif display_mode == 'ORPHAN_DATA':
|
||||
layout.operator("outliner.orphans_purge", text="Purge")
|
||||
@@ -208,7 +208,7 @@ class OUTLINER_MT_collection(Menu):
|
||||
|
||||
space = context.space_data
|
||||
|
||||
layout.operator("outliner.collection_new", text="New").nested = True
|
||||
layout.operator("outliner.collection_new", text="New")
|
||||
layout.operator("outliner.collection_duplicate", text="Duplicate Collection")
|
||||
layout.operator("outliner.collection_duplicate_linked", text="Duplicate Linked")
|
||||
layout.operator("outliner.id_copy", text="Copy", icon='COPYDOWN')
|
||||
@@ -239,6 +239,10 @@ class OUTLINER_MT_collection(Menu):
|
||||
if space.display_mode == 'VIEW_LAYER':
|
||||
layout.separator()
|
||||
layout.menu("OUTLINER_MT_collection_view_layer", icon='RENDERLAYERS')
|
||||
layout.separator()
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.operator_enum("outliner.collection_color_tag_set", "color", icon_only=True)
|
||||
|
||||
layout.separator()
|
||||
|
||||
@@ -254,7 +258,7 @@ class OUTLINER_MT_collection_new(Menu):
|
||||
|
||||
@staticmethod
|
||||
def draw_without_context_menu(context, layout):
|
||||
layout.operator("outliner.collection_new", text="New Collection").nested = True
|
||||
layout.operator_menu_enum("outliner.collection_new", "type", text="New Collection")
|
||||
layout.operator("outliner.id_paste", text="Paste Data-Blocks", icon='PASTEDOWN')
|
||||
|
||||
def draw(self, context):
|
||||
@@ -293,21 +297,11 @@ class OUTLINER_MT_object(Menu):
|
||||
|
||||
layout.separator()
|
||||
|
||||
if object_mode in {'EDIT', 'POSE'}:
|
||||
name = bpy.types.Object.bl_rna.properties["mode"].enum_items[object_mode].name
|
||||
layout.operator("outliner.object_operation",
|
||||
text=iface_("%s Set", i18n_contexts.operator_default) % name).type = 'OBJECT_MODE_ENTER'
|
||||
layout.operator("outliner.object_operation",
|
||||
text=iface_("%s Clear", i18n_contexts.operator_default) % name).type = 'OBJECT_MODE_EXIT'
|
||||
del name
|
||||
|
||||
layout.separator()
|
||||
|
||||
if not (space.display_mode == 'VIEW_LAYER' and not space.use_filter_collection):
|
||||
layout.operator("outliner.id_operation", text="Unlink").type = 'UNLINK'
|
||||
layout.separator()
|
||||
|
||||
layout.operator("outliner.collection_new", text="New Collection").nested = True
|
||||
layout.operator("outliner.collection_new", text="New Collection")
|
||||
|
||||
layout.separator()
|
||||
|
||||
@@ -351,13 +345,18 @@ class OUTLINER_PT_filter(Panel):
|
||||
|
||||
if display_mode != 'DATA_API':
|
||||
col = layout.column(align=True)
|
||||
col.prop(space, "use_sort_alpha")
|
||||
col.label(text="Sort by")
|
||||
col.prop(space, "sort_method", expand=True)
|
||||
layout.separator()
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.prop(space, "use_sync_select", text="Sync Selection")
|
||||
layout.separator()
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.prop(space, "show_mode_column", text="Show Mode Column")
|
||||
layout.separator()
|
||||
|
||||
col = layout.column(align=True)
|
||||
col.label(text="Search:")
|
||||
col.prop(space, "use_filter_complete", text="Exact Match")
|
||||
@@ -389,6 +388,9 @@ class OUTLINER_PT_filter(Panel):
|
||||
row = sub.row()
|
||||
row.label(icon='BLANK1')
|
||||
row.prop(space, "use_filter_children", text="Object Children")
|
||||
row = sub.row()
|
||||
row.label(icon='BLANK1')
|
||||
row.prop(space, "use_filter_row_children", text="Row Children")
|
||||
|
||||
if bpy.data.meshes:
|
||||
row = sub.row()
|
||||
|
@@ -1019,6 +1019,24 @@ class USERPREF_PT_theme_bone_color_sets(ThemePanel, CenterAlignMixIn, Panel):
|
||||
flow.prop(ui, "active")
|
||||
flow.prop(ui, "show_colored_constraints")
|
||||
|
||||
class USERPREF_PT_theme_collection_colors(ThemePanel, CenterAlignMixIn, Panel):
|
||||
bl_label = "Collection Colors"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
|
||||
def draw_header(self, _context):
|
||||
layout = self.layout
|
||||
|
||||
layout.label(icon='GROUP')
|
||||
|
||||
def draw_centered(self, context, layout):
|
||||
theme = context.preferences.themes[0]
|
||||
|
||||
layout.use_property_split = True
|
||||
|
||||
flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
|
||||
for i, ui in enumerate(theme.collection_color, 1):
|
||||
flow.prop(ui, "color", text=iface_(f"Color {i:d}"), translate=False)
|
||||
|
||||
|
||||
# Base class for dynamically defined theme-space panels.
|
||||
# This is not registered.
|
||||
@@ -2254,6 +2272,7 @@ classes = (
|
||||
USERPREF_PT_theme_interface_icons,
|
||||
USERPREF_PT_theme_text_style,
|
||||
USERPREF_PT_theme_bone_color_sets,
|
||||
USERPREF_PT_theme_collection_colors,
|
||||
|
||||
USERPREF_PT_file_paths_data,
|
||||
USERPREF_PT_file_paths_render,
|
||||
|
@@ -100,6 +100,10 @@ void BKE_collection_object_move(struct Main *bmain,
|
||||
struct Collection *collection_dst,
|
||||
struct Collection *collection_src,
|
||||
struct Object *ob);
|
||||
void BKE_collection_object_move_after(struct Main *bmain,
|
||||
struct Collection *collection,
|
||||
struct Object *ob_relative,
|
||||
struct Object *ob);
|
||||
|
||||
bool BKE_scene_collections_object_remove(struct Main *bmain,
|
||||
struct Scene *scene,
|
||||
|
@@ -77,6 +77,10 @@ bool BKE_object_shaderfx_use_time(struct Object *ob, struct ShaderFxData *md);
|
||||
|
||||
bool BKE_object_support_modifier_type_check(const struct Object *ob, int modifier_type);
|
||||
|
||||
bool BKE_object_link_modifier(struct Object *ob_dst,
|
||||
const struct Object *ob_src,
|
||||
struct ModifierData *md);
|
||||
bool BKE_object_link_gpencil_modifier(struct Object *ob_dst, struct GpencilModifierData *md);
|
||||
void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_src);
|
||||
void BKE_object_free_modifiers(struct Object *ob, const int flag);
|
||||
void BKE_object_free_shaderfx(struct Object *ob, const int flag);
|
||||
|
@@ -181,6 +181,7 @@ void BKE_shaderfx_copydata(struct ShaderFxData *fx, struct ShaderFxData *target)
|
||||
void BKE_shaderfx_copydata_ex(struct ShaderFxData *fx,
|
||||
struct ShaderFxData *target,
|
||||
const int flag);
|
||||
void BKE_shaderfx_copy(struct ListBase *dst, const struct ListBase *src);
|
||||
void BKE_shaderfx_foreach_ID_link(struct Object *ob, ShaderFxIDWalkFunc walk, void *userData);
|
||||
|
||||
bool BKE_shaderfx_has_gpencil(struct Object *ob);
|
||||
|
@@ -1118,6 +1118,38 @@ void BKE_collection_object_move(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Move object within a collection after specified object.
|
||||
*
|
||||
* For outliner drag & drop.
|
||||
*/
|
||||
void BKE_collection_object_move_after(Main *bmain,
|
||||
Collection *collection,
|
||||
Object *ob_relative,
|
||||
Object *ob)
|
||||
{
|
||||
if (ELEM(NULL, collection, ob_relative, ob)) {
|
||||
return;
|
||||
}
|
||||
|
||||
CollectionObject *relative = BLI_findptr(
|
||||
&collection->gobject, ob_relative, offsetof(CollectionObject, ob));
|
||||
if (!relative) {
|
||||
return;
|
||||
}
|
||||
int index_to = BLI_findindex(&collection->gobject, relative);
|
||||
|
||||
CollectionObject *object = BLI_findptr(&collection->gobject, ob, offsetof(CollectionObject, ob));
|
||||
if (!object) {
|
||||
return;
|
||||
}
|
||||
int index_from = BLI_findindex(&collection->gobject, object);
|
||||
|
||||
BLI_listbase_move_index(&collection->gobject, index_from, index_to);
|
||||
|
||||
BKE_main_collection_sync(bmain);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
@@ -689,6 +689,60 @@ bool BKE_object_support_modifier_type_check(const Object *ob, int modifier_type)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BKE_object_link_modifier(struct Object *ob_dst, const struct Object *ob_src, ModifierData *md)
|
||||
{
|
||||
ModifierData *nmd = NULL;
|
||||
|
||||
if (ELEM(md->type, eModifierType_Hook, eModifierType_Collision)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!BKE_object_support_modifier_type_check(ob_dst, md->type)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (md->type) {
|
||||
case eModifierType_Softbody:
|
||||
BKE_object_copy_softbody(ob_dst, ob_src, 0);
|
||||
break;
|
||||
case eModifierType_Skin:
|
||||
/* ensure skin-node customdata exists */
|
||||
BKE_mesh_ensure_skin_customdata(ob_dst->data);
|
||||
break;
|
||||
}
|
||||
|
||||
nmd = BKE_modifier_new(md->type);
|
||||
BLI_strncpy(nmd->name, md->name, sizeof(nmd->name));
|
||||
|
||||
if (md->type == eModifierType_Multires) {
|
||||
/* Has to be done after mod creation, but *before* we actually copy its settings! */
|
||||
multiresModifier_sync_levels_ex(
|
||||
ob_dst, (MultiresModifierData *)md, (MultiresModifierData *)nmd);
|
||||
}
|
||||
|
||||
BKE_modifier_copydata(md, nmd);
|
||||
BLI_addtail(&ob_dst->modifiers, nmd);
|
||||
BKE_modifier_unique_name(&ob_dst->modifiers, nmd);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BKE_object_link_gpencil_modifier(struct Object *ob_dst, GpencilModifierData *md)
|
||||
{
|
||||
GpencilModifierData *nmd = NULL;
|
||||
|
||||
nmd = BKE_gpencil_modifier_new(md->type);
|
||||
BLI_strncpy(nmd->name, md->name, sizeof(nmd->name));
|
||||
|
||||
const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type);
|
||||
mti->copyData(md, nmd);
|
||||
|
||||
BLI_addtail(&ob_dst->greasepencil_modifiers, nmd);
|
||||
BKE_gpencil_modifier_unique_name(&ob_dst->greasepencil_modifiers, nmd);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_src)
|
||||
{
|
||||
BKE_object_free_modifiers(ob_dst, 0);
|
||||
@@ -702,54 +756,14 @@ void BKE_object_link_modifiers(struct Object *ob_dst, const struct Object *ob_sr
|
||||
/* No grease pencil modifiers. */
|
||||
if ((ob_src->type != OB_GPENCIL) && (ob_dst->type != OB_GPENCIL)) {
|
||||
LISTBASE_FOREACH (ModifierData *, md, &ob_src->modifiers) {
|
||||
ModifierData *nmd = NULL;
|
||||
|
||||
if (ELEM(md->type, eModifierType_Hook, eModifierType_Collision)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!BKE_object_support_modifier_type_check(ob_dst, md->type)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (md->type) {
|
||||
case eModifierType_Softbody:
|
||||
BKE_object_copy_softbody(ob_dst, ob_src, 0);
|
||||
break;
|
||||
case eModifierType_Skin:
|
||||
/* ensure skin-node customdata exists */
|
||||
BKE_mesh_ensure_skin_customdata(ob_dst->data);
|
||||
break;
|
||||
}
|
||||
|
||||
nmd = BKE_modifier_new(md->type);
|
||||
BLI_strncpy(nmd->name, md->name, sizeof(nmd->name));
|
||||
|
||||
if (md->type == eModifierType_Multires) {
|
||||
/* Has to be done after mod creation, but *before* we actually copy its settings! */
|
||||
multiresModifier_sync_levels_ex(
|
||||
ob_dst, (MultiresModifierData *)md, (MultiresModifierData *)nmd);
|
||||
}
|
||||
|
||||
BKE_modifier_copydata(md, nmd);
|
||||
BLI_addtail(&ob_dst->modifiers, nmd);
|
||||
BKE_modifier_unique_name(&ob_dst->modifiers, nmd);
|
||||
BKE_object_link_modifier(ob_dst, ob_src, md);
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy grease pencil modifiers. */
|
||||
if ((ob_src->type == OB_GPENCIL) && (ob_dst->type == OB_GPENCIL)) {
|
||||
LISTBASE_FOREACH (GpencilModifierData *, md, &ob_src->greasepencil_modifiers) {
|
||||
GpencilModifierData *nmd = NULL;
|
||||
|
||||
nmd = BKE_gpencil_modifier_new(md->type);
|
||||
BLI_strncpy(nmd->name, md->name, sizeof(nmd->name));
|
||||
|
||||
const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type);
|
||||
mti->copyData(md, nmd);
|
||||
|
||||
BLI_addtail(&ob_dst->greasepencil_modifiers, nmd);
|
||||
BKE_gpencil_modifier_unique_name(&ob_dst->greasepencil_modifiers, nmd);
|
||||
BKE_object_link_gpencil_modifier(ob_dst, md);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -234,6 +234,19 @@ void BKE_shaderfx_copydata(ShaderFxData *fx, ShaderFxData *target)
|
||||
BKE_shaderfx_copydata_ex(fx, target, 0);
|
||||
}
|
||||
|
||||
void BKE_shaderfx_copy(ListBase *dst, const ListBase *src)
|
||||
{
|
||||
ShaderFxData *fx;
|
||||
ShaderFxData *srcfx;
|
||||
|
||||
BLI_listbase_clear(dst);
|
||||
BLI_duplicatelist(dst, src);
|
||||
|
||||
for (srcfx = src->first, fx = dst->first; srcfx && fx; srcfx = srcfx->next, fx = fx->next) {
|
||||
BKE_shaderfx_copydata(srcfx, fx);
|
||||
}
|
||||
}
|
||||
|
||||
ShaderFxData *BKE_shaderfx_findby_type(Object *ob, ShaderFxType type)
|
||||
{
|
||||
ShaderFxData *fx = ob->shader_fx.first;
|
||||
|
@@ -3413,7 +3413,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
|
||||
}
|
||||
case SPACE_OUTLINER: {
|
||||
SpaceOutliner *space_outliner = (SpaceOutliner *)sl;
|
||||
space_outliner->filter &= ~(SO_FILTER_UNUSED_1 | SO_FILTER_UNUSED_5 |
|
||||
space_outliner->filter &= ~(SO_FILTER_UNUSED_1 | SO_FILTER_NO_ROW_CHILDREN |
|
||||
SO_FILTER_UNUSED_12);
|
||||
space_outliner->storeflag &= ~(SO_TREESTORE_UNUSED_1);
|
||||
break;
|
||||
|
@@ -517,5 +517,17 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
|
||||
*/
|
||||
{
|
||||
/* Keep this block, even when empty. */
|
||||
|
||||
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
|
||||
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
|
||||
LISTBASE_FOREACH (SpaceLink *, space, &area->spacedata) {
|
||||
if (space->spacetype == SPACE_OUTLINER) {
|
||||
SpaceOutliner *space_outliner = (SpaceOutliner *)space;
|
||||
|
||||
space_outliner->flag |= SO_MODE_COLUMN;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -217,6 +217,15 @@ static void do_versions_theme(const UserDef *userdef, bTheme *btheme)
|
||||
btheme->tui.transparent_checker_size = U_theme_default.tui.transparent_checker_size;
|
||||
}
|
||||
|
||||
FROM_DEFAULT_V4_UCHAR(collection_color[0].color);
|
||||
FROM_DEFAULT_V4_UCHAR(collection_color[1].color);
|
||||
FROM_DEFAULT_V4_UCHAR(collection_color[2].color);
|
||||
FROM_DEFAULT_V4_UCHAR(collection_color[3].color);
|
||||
FROM_DEFAULT_V4_UCHAR(collection_color[4].color);
|
||||
FROM_DEFAULT_V4_UCHAR(collection_color[5].color);
|
||||
FROM_DEFAULT_V4_UCHAR(collection_color[6].color);
|
||||
FROM_DEFAULT_V4_UCHAR(collection_color[7].color);
|
||||
|
||||
/**
|
||||
* Versioning code until next subversion bump goes here.
|
||||
*
|
||||
|
@@ -1971,7 +1971,7 @@ static int insert_key_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UN
|
||||
/* call the menu, which will call this operator again, hence the canceled */
|
||||
pup = UI_popup_menu_begin(C, WM_operatortype_name(op->type, op->ptr), ICON_NONE);
|
||||
layout = UI_popup_menu_layout(pup);
|
||||
uiItemsEnumO(layout, "ANIM_OT_keyframe_insert_menu", "type");
|
||||
uiItemsEnumO(layout, "ANIM_OT_keyframe_insert_menu", "type", false);
|
||||
UI_popup_menu_end(C, pup);
|
||||
|
||||
return OPERATOR_INTERFACE;
|
||||
|
@@ -479,7 +479,7 @@ static int keyingset_active_menu_invoke(bContext *C, wmOperator *op, const wmEve
|
||||
/* call the menu, which will call this operator again, hence the canceled */
|
||||
pup = UI_popup_menu_begin(C, op->type->name, ICON_NONE);
|
||||
layout = UI_popup_menu_layout(pup);
|
||||
uiItemsEnumO(layout, "ANIM_OT_keying_set_active_set", "type");
|
||||
uiItemsEnumO(layout, "ANIM_OT_keying_set_active_set", "type", false);
|
||||
UI_popup_menu_end(C, pup);
|
||||
|
||||
return OPERATOR_INTERFACE;
|
||||
|
@@ -5922,7 +5922,7 @@ static int toggle_cyclic_invoke(bContext *C, wmOperator *op, const wmEvent *UNUS
|
||||
if (nu->type == CU_NURBS) {
|
||||
pup = UI_popup_menu_begin(C, IFACE_("Direction"), ICON_NONE);
|
||||
layout = UI_popup_menu_layout(pup);
|
||||
uiItemsEnumO(layout, op->type->idname, "direction");
|
||||
uiItemsEnumO(layout, op->type->idname, "direction", false);
|
||||
UI_popup_menu_end(C, pup);
|
||||
return OPERATOR_INTERFACE;
|
||||
}
|
||||
|
@@ -1403,7 +1403,7 @@ static int gpencil_layer_change_invoke(bContext *C, wmOperator *op, const wmEven
|
||||
/* call the menu, which will call this operator again, hence the canceled */
|
||||
pup = UI_popup_menu_begin(C, op->type->name, ICON_NONE);
|
||||
layout = UI_popup_menu_layout(pup);
|
||||
uiItemsEnumO(layout, "GPENCIL_OT_layer_change", "layer");
|
||||
uiItemsEnumO(layout, "GPENCIL_OT_layer_change", "layer", false);
|
||||
UI_popup_menu_end(C, pup);
|
||||
|
||||
return OPERATOR_INTERFACE;
|
||||
|
@@ -26,8 +26,11 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct bContext;
|
||||
struct SpaceProperties;
|
||||
|
||||
void ED_buttons_set_context(const struct bContext *C, PointerRNA *ptr, const short context);
|
||||
|
||||
int ED_buttons_tabs_list(struct SpaceProperties *sbuts, int *context_tabs_array);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@@ -329,6 +329,11 @@ void ED_object_constraint_dependency_tag_update(struct Main *bmain,
|
||||
struct Object *ob,
|
||||
struct bConstraint *con);
|
||||
|
||||
bool ED_object_constraint_move_to_index(struct ReportList *reports,
|
||||
struct Object *ob,
|
||||
struct bConstraint *con,
|
||||
const int index);
|
||||
|
||||
/* object_modes.c */
|
||||
bool ED_object_mode_compat_test(const struct Object *ob, eObjectMode mode);
|
||||
bool ED_object_mode_compat_set(struct bContext *C,
|
||||
|
@@ -320,7 +320,7 @@ DEF_ICON_OBJECT(OUTLINER_OB_GROUP_INSTANCE)
|
||||
DEF_ICON_OBJECT(OUTLINER_OB_GREASEPENCIL)
|
||||
DEF_ICON_OBJECT(OUTLINER_OB_LIGHTPROBE)
|
||||
DEF_ICON_OBJECT(OUTLINER_OB_IMAGE)
|
||||
DEF_ICON_BLANK(321)
|
||||
DEF_ICON(OUTLINER_COLLECTION)
|
||||
DEF_ICON(RESTRICT_COLOR_OFF)
|
||||
DEF_ICON(RESTRICT_COLOR_ON)
|
||||
DEF_ICON(HIDE_ON)
|
||||
@@ -980,6 +980,15 @@ DEF_ICON_VECTOR(COLORSET_18_VEC)
|
||||
DEF_ICON_VECTOR(COLORSET_19_VEC)
|
||||
DEF_ICON_VECTOR(COLORSET_20_VEC)
|
||||
|
||||
DEF_ICON_VECTOR(COLLECTION_COLOR_01)
|
||||
DEF_ICON_VECTOR(COLLECTION_COLOR_02)
|
||||
DEF_ICON_VECTOR(COLLECTION_COLOR_03)
|
||||
DEF_ICON_VECTOR(COLLECTION_COLOR_04)
|
||||
DEF_ICON_VECTOR(COLLECTION_COLOR_05)
|
||||
DEF_ICON_VECTOR(COLLECTION_COLOR_06)
|
||||
DEF_ICON_VECTOR(COLLECTION_COLOR_07)
|
||||
DEF_ICON_VECTOR(COLLECTION_COLOR_08)
|
||||
|
||||
/* Events */
|
||||
DEF_ICON_COLOR(EVENT_A)
|
||||
DEF_ICON_COLOR(EVENT_B)
|
||||
|
@@ -2202,7 +2202,10 @@ void uiItemEnumO_string(uiLayout *layout,
|
||||
const char *opname,
|
||||
const char *propname,
|
||||
const char *value);
|
||||
void uiItemsEnumO(uiLayout *layout, const char *opname, const char *propname);
|
||||
void uiItemsEnumO(uiLayout *layout,
|
||||
const char *opname,
|
||||
const char *propname,
|
||||
const bool icon_only);
|
||||
void uiItemBooleanO(uiLayout *layout,
|
||||
const char *name,
|
||||
int icon,
|
||||
|
@@ -32,6 +32,7 @@ struct PointerRNA;
|
||||
struct PreviewImage;
|
||||
struct Scene;
|
||||
struct bContext;
|
||||
struct Collection;
|
||||
|
||||
enum eIconSizes;
|
||||
|
||||
@@ -106,6 +107,7 @@ struct PreviewImage *UI_icon_to_preview(int icon_id);
|
||||
int UI_rnaptr_icon_get(struct bContext *C, struct PointerRNA *ptr, int rnaicon, const bool big);
|
||||
int UI_idcode_icon_get(const int idcode);
|
||||
int UI_library_icon_get(const struct ID *id);
|
||||
int UI_collection_color_icon_get(const struct Collection *collection);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@@ -383,13 +383,27 @@ static void ui_block_bounds_calc_text(uiBlock *block, float offset)
|
||||
}
|
||||
}
|
||||
|
||||
/* Keep aligned buttons in the same column. */
|
||||
if (bt->alignnr && bt->next) {
|
||||
int width = 0;
|
||||
for (col_bt = bt; col_bt->rect.xmin < col_bt->next->rect.xmin; col_bt = col_bt->next) {
|
||||
width += BLI_rctf_size_x(&col_bt->rect);
|
||||
}
|
||||
if (width > i) {
|
||||
i = width;
|
||||
}
|
||||
bt = col_bt;
|
||||
}
|
||||
|
||||
if (bt->next && bt->rect.xmin < bt->next->rect.xmin) {
|
||||
/* End of this column, and it's not the last one. */
|
||||
for (col_bt = init_col_bt; col_bt->prev != bt; col_bt = col_bt->next) {
|
||||
col_bt->rect.xmin = x1addval;
|
||||
col_bt->rect.xmax = x1addval + i + block->bounds;
|
||||
if (!col_bt->alignnr) {
|
||||
col_bt->rect.xmin = x1addval;
|
||||
col_bt->rect.xmax = x1addval + i + block->bounds;
|
||||
|
||||
ui_but_update(col_bt); /* clips text again */
|
||||
ui_but_update(col_bt); /* clips text again */
|
||||
}
|
||||
}
|
||||
|
||||
/* And we prepare next column. */
|
||||
@@ -401,8 +415,10 @@ static void ui_block_bounds_calc_text(uiBlock *block, float offset)
|
||||
|
||||
/* Last column. */
|
||||
for (col_bt = init_col_bt; col_bt; col_bt = col_bt->next) {
|
||||
col_bt->rect.xmin = x1addval;
|
||||
col_bt->rect.xmax = max_ff(x1addval + i + block->bounds, offset + block->minbounds);
|
||||
if (!col_bt->alignnr) {
|
||||
col_bt->rect.xmin = x1addval;
|
||||
col_bt->rect.xmax = max_ff(x1addval + i + block->bounds, offset + block->minbounds);
|
||||
}
|
||||
|
||||
ui_but_update(col_bt); /* clips text again */
|
||||
}
|
||||
|
@@ -40,6 +40,7 @@
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "DNA_brush_types.h"
|
||||
#include "DNA_collection_types.h"
|
||||
#include "DNA_curve_types.h"
|
||||
#include "DNA_dynamicpaint_types.h"
|
||||
#include "DNA_gpencil_types.h"
|
||||
@@ -460,6 +461,33 @@ DEF_ICON_VECTOR_COLORSET_DRAW_NTH(20, 19)
|
||||
|
||||
# undef DEF_ICON_VECTOR_COLORSET_DRAW_NTH
|
||||
|
||||
static void vicon_collection_color_draw(
|
||||
short color, int x, int y, int UNUSED(w), int UNUSED(h), float UNUSED(alpha))
|
||||
{
|
||||
bTheme *btheme = UI_GetTheme();
|
||||
const ThemeCollectionColor *collection_color = &btheme->collection_color[color - 1];
|
||||
|
||||
UI_icon_draw_ex(
|
||||
x, y, ICON_OUTLINER_COLLECTION, U.inv_dpi_fac, 1.0f, 0.0f, collection_color->color, true);
|
||||
}
|
||||
|
||||
# define DEF_ICON_COLLECTION_COLOR_DRAW(index, color) \
|
||||
static void vicon_collection_color_draw_##index(int x, int y, int w, int h, float alpha) \
|
||||
{ \
|
||||
vicon_collection_color_draw(color, x, y, w, h, alpha); \
|
||||
}
|
||||
|
||||
DEF_ICON_COLLECTION_COLOR_DRAW(01, COLLECTION_COLOR_01);
|
||||
DEF_ICON_COLLECTION_COLOR_DRAW(02, COLLECTION_COLOR_02);
|
||||
DEF_ICON_COLLECTION_COLOR_DRAW(03, COLLECTION_COLOR_03);
|
||||
DEF_ICON_COLLECTION_COLOR_DRAW(04, COLLECTION_COLOR_04);
|
||||
DEF_ICON_COLLECTION_COLOR_DRAW(05, COLLECTION_COLOR_05);
|
||||
DEF_ICON_COLLECTION_COLOR_DRAW(06, COLLECTION_COLOR_06);
|
||||
DEF_ICON_COLLECTION_COLOR_DRAW(07, COLLECTION_COLOR_07);
|
||||
DEF_ICON_COLLECTION_COLOR_DRAW(08, COLLECTION_COLOR_08);
|
||||
|
||||
# undef DEF_ICON_COLLECTION_COLOR_DRAW
|
||||
|
||||
/* Dynamically render icon instead of rendering a plain color to a texture/buffer
|
||||
* This is not strictly a "vicon", as it needs access to icon->obj to get the color info,
|
||||
* but it works in a very similar way.
|
||||
@@ -985,6 +1013,15 @@ static void init_internal_icons(void)
|
||||
def_internal_vicon(ICON_COLORSET_18_VEC, vicon_colorset_draw_18);
|
||||
def_internal_vicon(ICON_COLORSET_19_VEC, vicon_colorset_draw_19);
|
||||
def_internal_vicon(ICON_COLORSET_20_VEC, vicon_colorset_draw_20);
|
||||
|
||||
def_internal_vicon(ICON_COLLECTION_COLOR_01, vicon_collection_color_draw_01);
|
||||
def_internal_vicon(ICON_COLLECTION_COLOR_02, vicon_collection_color_draw_02);
|
||||
def_internal_vicon(ICON_COLLECTION_COLOR_03, vicon_collection_color_draw_03);
|
||||
def_internal_vicon(ICON_COLLECTION_COLOR_04, vicon_collection_color_draw_04);
|
||||
def_internal_vicon(ICON_COLLECTION_COLOR_05, vicon_collection_color_draw_05);
|
||||
def_internal_vicon(ICON_COLLECTION_COLOR_06, vicon_collection_color_draw_06);
|
||||
def_internal_vicon(ICON_COLLECTION_COLOR_07, vicon_collection_color_draw_07);
|
||||
def_internal_vicon(ICON_COLLECTION_COLOR_08, vicon_collection_color_draw_08);
|
||||
}
|
||||
# endif /* WITH_HEADLESS */
|
||||
|
||||
@@ -2148,6 +2185,9 @@ int ui_id_icon_get(const bContext *C, ID *id, const bool big)
|
||||
case ID_SCR:
|
||||
iconid = ui_id_screen_get_icon(C, id);
|
||||
break;
|
||||
case ID_GR:
|
||||
iconid = UI_collection_color_icon_get((Collection *)id);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -2309,6 +2349,17 @@ int UI_idcode_icon_get(const int idcode)
|
||||
}
|
||||
}
|
||||
|
||||
int UI_collection_color_icon_get(const Collection *collection)
|
||||
{
|
||||
int icon = ICON_OUTLINER_COLLECTION;
|
||||
|
||||
if (collection->color != COLLECTION_COLOR_NONE) {
|
||||
icon = ICON_COLLECTION_COLOR_01 + (collection->color - 1);
|
||||
}
|
||||
|
||||
return icon;
|
||||
}
|
||||
|
||||
/* draws icon with dpi scale factor */
|
||||
void UI_icon_draw(float x, float y, int icon_id)
|
||||
{
|
||||
|
@@ -1208,6 +1208,10 @@ static uiBut *uiItemFullO_ptr_ex(uiLayout *layout,
|
||||
but->flag |= UI_SELECT_DRAW;
|
||||
}
|
||||
|
||||
if (flag & UI_ITEM_R_ICON_ONLY) {
|
||||
UI_but_drawflag_disable(but, UI_BUT_ICON_LEFT);
|
||||
}
|
||||
|
||||
if (layout->redalert) {
|
||||
UI_but_flag_enable(but, UI_BUT_REDALERT);
|
||||
}
|
||||
@@ -1428,6 +1432,13 @@ void uiItemsFullEnumO_items(uiLayout *layout,
|
||||
if (radial) {
|
||||
target = uiLayoutRadial(layout);
|
||||
}
|
||||
else if (layout->item.type == ITEM_LAYOUT_ROW && flag & UI_ITEM_R_ICON_ONLY) {
|
||||
target = layout;
|
||||
|
||||
/* Add a blank button to the beginning of the row. */
|
||||
uiDefIconBut(
|
||||
block, UI_BTYPE_LABEL, 0, ICON_BLANK1, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL);
|
||||
}
|
||||
else {
|
||||
split = uiLayoutSplit(layout, 0.0f, false);
|
||||
target = uiLayoutColumn(split, layout->align);
|
||||
@@ -1475,7 +1486,14 @@ void uiItemsFullEnumO_items(uiLayout *layout,
|
||||
}
|
||||
RNA_property_enum_set(&tptr, prop, item->value);
|
||||
|
||||
uiItemFullO_ptr(target, ot, item->name, item->icon, tptr.data, context, flag, NULL);
|
||||
uiItemFullO_ptr(target,
|
||||
ot,
|
||||
(flag & UI_ITEM_R_ICON_ONLY) ? NULL : item->name,
|
||||
item->icon,
|
||||
tptr.data,
|
||||
context,
|
||||
flag,
|
||||
NULL);
|
||||
|
||||
ui_but_tip_from_enum_item(block->buttons.last, item);
|
||||
}
|
||||
@@ -1599,9 +1617,14 @@ void uiItemsFullEnumO(uiLayout *layout,
|
||||
}
|
||||
}
|
||||
|
||||
void uiItemsEnumO(uiLayout *layout, const char *opname, const char *propname)
|
||||
void uiItemsEnumO(uiLayout *layout, const char *opname, const char *propname, const bool icon_only)
|
||||
{
|
||||
uiItemsFullEnumO(layout, opname, propname, NULL, layout->root->opcontext, 0);
|
||||
uiItemsFullEnumO(layout,
|
||||
opname,
|
||||
propname,
|
||||
NULL,
|
||||
layout->root->opcontext,
|
||||
icon_only ? UI_ITEM_R_ICON_ONLY : 0);
|
||||
}
|
||||
|
||||
/* for use in cases where we have */
|
||||
@@ -3372,7 +3395,7 @@ static void menu_item_enum_opname_menu(bContext *UNUSED(C), uiLayout *layout, vo
|
||||
MenuItemLevel *lvl = (MenuItemLevel *)(((uiBut *)arg)->func_argN);
|
||||
|
||||
uiLayoutSetOperatorContext(layout, lvl->opcontext);
|
||||
uiItemsEnumO(layout, lvl->opname, lvl->propname);
|
||||
uiItemsEnumO(layout, lvl->opname, lvl->propname, false);
|
||||
|
||||
layout->root->block->flag |= UI_BLOCK_IS_FLIP;
|
||||
|
||||
@@ -3718,18 +3741,18 @@ static void ui_litem_estimate_column(uiLayout *litem, bool is_box)
|
||||
}
|
||||
}
|
||||
|
||||
static void ui_litem_layout_column(uiLayout *litem, bool is_box)
|
||||
static void ui_litem_layout_column(uiLayout *litem, bool is_box, bool is_menu)
|
||||
{
|
||||
int itemh, x, y;
|
||||
int itemw, itemh, x, y;
|
||||
|
||||
x = litem->x;
|
||||
y = litem->y;
|
||||
|
||||
LISTBASE_FOREACH (uiItem *, item, &litem->items) {
|
||||
ui_item_size(item, NULL, &itemh);
|
||||
ui_item_size(item, &itemw, &itemh);
|
||||
|
||||
y -= itemh;
|
||||
ui_item_position(item, x, y, litem->w, itemh);
|
||||
ui_item_position(item, x, y, is_menu ? itemw : litem->w, itemh);
|
||||
|
||||
if (item->next && (!is_box || item != litem->items.first)) {
|
||||
y -= litem->space;
|
||||
@@ -3890,8 +3913,11 @@ static void ui_litem_layout_root(uiLayout *litem)
|
||||
else if (litem->root->type == UI_LAYOUT_PIEMENU) {
|
||||
ui_litem_layout_root_radial(litem);
|
||||
}
|
||||
else if (litem->root->type == UI_LAYOUT_MENU) {
|
||||
ui_litem_layout_column(litem, false, true);
|
||||
}
|
||||
else {
|
||||
ui_litem_layout_column(litem, false);
|
||||
ui_litem_layout_column(litem, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3935,7 +3961,7 @@ static void ui_litem_layout_box(uiLayout *litem)
|
||||
litem->h -= 2 * boxspace;
|
||||
}
|
||||
|
||||
ui_litem_layout_column(litem, true);
|
||||
ui_litem_layout_column(litem, true, false);
|
||||
|
||||
litem->x -= boxspace;
|
||||
litem->y -= boxspace;
|
||||
@@ -5196,7 +5222,7 @@ static void ui_item_layout(uiItem *item)
|
||||
|
||||
switch (litem->item.type) {
|
||||
case ITEM_LAYOUT_COLUMN:
|
||||
ui_litem_layout_column(litem, false);
|
||||
ui_litem_layout_column(litem, false, false);
|
||||
break;
|
||||
case ITEM_LAYOUT_COLUMN_FLOW:
|
||||
ui_litem_layout_column_flow(litem);
|
||||
|
@@ -261,7 +261,7 @@ int UI_pie_menu_invoke_from_operator_enum(struct bContext *C,
|
||||
layout = UI_pie_menu_layout(pie);
|
||||
|
||||
layout = uiLayoutRadial(layout);
|
||||
uiItemsEnumO(layout, opname, propname);
|
||||
uiItemsEnumO(layout, opname, propname, false);
|
||||
|
||||
UI_pie_menu_end(C, pie);
|
||||
|
||||
|
@@ -2376,7 +2376,7 @@ static void widget_draw_text_icon(const uiFontStyle *fstyle,
|
||||
rect->xmin += 0.3f * U.widget_unit;
|
||||
}
|
||||
}
|
||||
else if (ui_block_is_menu(but->block)) {
|
||||
else if (ui_block_is_menu(but->block) && but->alignnr == 0) {
|
||||
rect->xmin += 0.2f * U.widget_unit;
|
||||
}
|
||||
|
||||
|
@@ -50,6 +50,8 @@
|
||||
#include "RNA_define.h"
|
||||
#include "RNA_enum_types.h"
|
||||
|
||||
#include "UI_interface_icons.h"
|
||||
|
||||
#include "object_intern.h"
|
||||
|
||||
/********************* 3d view operators ***********************/
|
||||
@@ -94,7 +96,7 @@ static const EnumPropertyItem *collection_object_active_itemf(bContext *C,
|
||||
collection = NULL;
|
||||
while ((collection = BKE_collection_object_find(bmain, scene, collection, ob))) {
|
||||
item_tmp.identifier = item_tmp.name = collection->id.name + 2;
|
||||
/* item_tmp.icon = ICON_ARMATURE_DATA; */
|
||||
item_tmp.icon = UI_collection_color_icon_get(collection);
|
||||
item_tmp.value = i;
|
||||
RNA_enum_item_add(&item, &totitem, &item_tmp);
|
||||
i++;
|
||||
|
@@ -1421,6 +1421,24 @@ void ED_object_constraint_dependency_tag_update(Main *bmain, Object *ob, bConstr
|
||||
DEG_relations_tag_update(bmain);
|
||||
}
|
||||
|
||||
/* TODO (Nathan): Use the reports? */
|
||||
bool ED_object_constraint_move_to_index(ReportList *reports,
|
||||
Object *ob,
|
||||
bConstraint *con,
|
||||
const int index)
|
||||
{
|
||||
BLI_assert(con != NULL);
|
||||
BLI_assert(index >= 0);
|
||||
|
||||
ListBase *conlist = ED_object_constraint_list_from_constraint(ob, con, NULL);
|
||||
int current_index = BLI_findindex(conlist, con);
|
||||
BLI_assert(current_index >= 0);
|
||||
|
||||
BLI_listbase_link_move(conlist, con, index - current_index);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* ------------------------------------------------------------------- */
|
||||
@@ -1613,11 +1631,7 @@ static int constraint_move_to_index_exec(bContext *C, wmOperator *op)
|
||||
}
|
||||
|
||||
if (con) {
|
||||
ListBase *conlist = ED_object_constraint_list_from_constraint(ob, con, NULL);
|
||||
int current_index = BLI_findindex(conlist, con);
|
||||
BLI_assert(current_index >= 0);
|
||||
|
||||
BLI_listbase_link_move(conlist, con, new_index - current_index);
|
||||
ED_object_constraint_move_to_index(op->reports, ob, con, new_index);
|
||||
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob);
|
||||
|
||||
|
@@ -100,6 +100,8 @@
|
||||
#include "RNA_define.h"
|
||||
#include "RNA_enum_types.h"
|
||||
|
||||
#include "UI_interface_icons.h"
|
||||
|
||||
#include "CLG_log.h"
|
||||
|
||||
/* for menu/popup icons etc etc*/
|
||||
@@ -1761,7 +1763,7 @@ static void move_to_collection_menus_free(MoveToCollectionData **menu)
|
||||
*menu = NULL;
|
||||
}
|
||||
|
||||
static void move_to_collection_menu_create(bContext *UNUSED(C), uiLayout *layout, void *menu_v)
|
||||
static void move_to_collection_menu_create(bContext *C, uiLayout *layout, void *menu_v)
|
||||
{
|
||||
MoveToCollectionData *menu = menu_v;
|
||||
const char *name = BKE_collection_ui_name_get(menu->collection);
|
||||
@@ -1777,7 +1779,11 @@ static void move_to_collection_menu_create(bContext *UNUSED(C), uiLayout *layout
|
||||
|
||||
uiItemS(layout);
|
||||
|
||||
uiItemIntO(layout, name, ICON_SCENE_DATA, menu->ot->idname, "collection_index", menu->index);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
const int icon = (menu->collection == scene->master_collection) ?
|
||||
ICON_SCENE_DATA :
|
||||
UI_collection_color_icon_get(menu->collection);
|
||||
uiItemIntO(layout, name, icon, menu->ot->idname, "collection_index", menu->index);
|
||||
|
||||
for (MoveToCollectionData *submenu = menu->submenus.first; submenu != NULL;
|
||||
submenu = submenu->next) {
|
||||
@@ -1787,17 +1793,18 @@ static void move_to_collection_menu_create(bContext *UNUSED(C), uiLayout *layout
|
||||
|
||||
static void move_to_collection_menus_items(uiLayout *layout, MoveToCollectionData *menu)
|
||||
{
|
||||
const int icon = UI_collection_color_icon_get(menu->collection);
|
||||
|
||||
if (BLI_listbase_is_empty(&menu->submenus)) {
|
||||
uiItemIntO(layout,
|
||||
menu->collection->id.name + 2,
|
||||
ICON_NONE,
|
||||
icon,
|
||||
menu->ot->idname,
|
||||
"collection_index",
|
||||
menu->index);
|
||||
}
|
||||
else {
|
||||
uiItemMenuF(
|
||||
layout, menu->collection->id.name + 2, ICON_NONE, move_to_collection_menu_create, menu);
|
||||
uiItemMenuF(layout, menu->collection->id.name + 2, icon, move_to_collection_menu_create, menu);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -535,11 +535,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);
|
||||
@@ -685,14 +685,14 @@ void buttons_context_compute(const bContext *C, SpaceProperties *sbuts)
|
||||
path = sbuts->path;
|
||||
|
||||
/* 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 (a = 0; a < BCONTEXT_TOT; a++) {
|
||||
if (buttons_context_path(C, path, a, pflag)) {
|
||||
if (buttons_context_path(C, sbuts, path, a, pflag)) {
|
||||
flag |= (1 << a);
|
||||
|
||||
/* setting icon for data context */
|
||||
@@ -738,7 +738,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)) {
|
||||
@@ -759,6 +759,38 @@ 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 short context)
|
||||
{
|
||||
bScreen *screen = CTX_wm_screen(C);
|
||||
|
||||
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
|
||||
/* Only update for properties editors that are visible */
|
||||
SpaceLink *sl = area->spacedata.first;
|
||||
|
||||
if (sl->spacetype == SPACE_PROPERTIES) {
|
||||
SpaceProperties *sbuts = (SpaceProperties *)sl;
|
||||
|
||||
ButsContextPath path;
|
||||
if (buttons_context_path(C, sbuts, &path, context, 0)) {
|
||||
if (is_pointer_in_path(&path, ptr)) {
|
||||
sbuts->mainbuser = context;
|
||||
sbuts->mainb = sbuts->mainbuser;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/************************* Context Callback ************************/
|
||||
|
||||
const char *buttons_context_dir[] = {
|
||||
|
@@ -256,7 +256,7 @@ static int unpack_all_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(
|
||||
layout = UI_popup_menu_layout(pup);
|
||||
|
||||
uiLayoutSetOperatorContext(layout, WM_OP_EXEC_DEFAULT);
|
||||
uiItemsEnumO(layout, "FILE_OT_unpack_all", "method");
|
||||
uiItemsEnumO(layout, "FILE_OT_unpack_all", "method", false);
|
||||
|
||||
UI_popup_menu_end(C, pup);
|
||||
|
||||
|
@@ -183,60 +183,35 @@ static bool outliner_view_layer_collections_editor_poll(bContext *C)
|
||||
/** \name New Collection
|
||||
* \{ */
|
||||
|
||||
struct CollectionNewData {
|
||||
bool error;
|
||||
Collection *collection;
|
||||
};
|
||||
typedef enum NewCollectionType {
|
||||
COLLECTION_NEW_EMPTY,
|
||||
COLLECTION_NEW_FROM_SELECTION,
|
||||
COLLECTION_NEW_FROM_SELECTION_LINKED,
|
||||
} NewCollectionType;
|
||||
|
||||
static TreeTraversalAction collection_find_selected_to_add(TreeElement *te, void *customdata)
|
||||
static Collection *find_parent_collection(TreeElement *te)
|
||||
{
|
||||
struct CollectionNewData *data = customdata;
|
||||
Collection *collection = outliner_collection_from_tree_element(te);
|
||||
|
||||
if (!collection) {
|
||||
return TRAVERSE_SKIP_CHILDS;
|
||||
while (te) {
|
||||
te = te->parent;
|
||||
if (outliner_is_collection_tree_element(te)) {
|
||||
return outliner_collection_from_tree_element(te);
|
||||
}
|
||||
}
|
||||
|
||||
if (data->collection != NULL) {
|
||||
data->error = true;
|
||||
return TRAVERSE_BREAK;
|
||||
}
|
||||
|
||||
data->collection = collection;
|
||||
return TRAVERSE_CONTINUE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int collection_new_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
|
||||
ARegion *region = CTX_wm_region(C);
|
||||
Main *bmain = CTX_data_main(C);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
ViewLayer *view_layer = CTX_data_view_layer(C);
|
||||
Collection *collection;
|
||||
const short type = RNA_enum_get(op->ptr, "type");
|
||||
|
||||
struct CollectionNewData data = {
|
||||
.error = false,
|
||||
.collection = NULL,
|
||||
};
|
||||
|
||||
if (RNA_boolean_get(op->ptr, "nested")) {
|
||||
outliner_build_tree(bmain, scene, view_layer, space_outliner, region);
|
||||
|
||||
outliner_tree_traverse(space_outliner,
|
||||
&space_outliner->tree,
|
||||
0,
|
||||
TSE_SELECTED,
|
||||
collection_find_selected_to_add,
|
||||
&data);
|
||||
|
||||
if (data.error) {
|
||||
BKE_report(op->reports, RPT_ERROR, "More than one collection is selected");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
}
|
||||
|
||||
if (data.collection == NULL || ID_IS_LINKED(data.collection)) {
|
||||
data.collection = scene->master_collection;
|
||||
/* Make new collection a child of the active collection */
|
||||
collection = CTX_data_layer_collection(C)->collection;
|
||||
if (ID_IS_LINKED(collection)) {
|
||||
collection = scene->master_collection;
|
||||
}
|
||||
|
||||
if (ID_IS_LINKED(scene)) {
|
||||
@@ -244,9 +219,35 @@ static int collection_new_exec(bContext *C, wmOperator *op)
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
BKE_collection_add(bmain, data.collection, NULL);
|
||||
Collection *collection_new = BKE_collection_add(bmain, collection, NULL);
|
||||
|
||||
DEG_id_tag_update(&data.collection->id, ID_RECALC_COPY_ON_WRITE);
|
||||
if (type != COLLECTION_NEW_EMPTY) {
|
||||
/* Move selected objects into new collection */
|
||||
struct IDsSelectedData data = {{NULL}};
|
||||
outliner_tree_traverse(space_outliner,
|
||||
&space_outliner->tree,
|
||||
0,
|
||||
TSE_SELECTED,
|
||||
outliner_find_selected_objects,
|
||||
&data);
|
||||
|
||||
LISTBASE_FOREACH (LinkData *, link, &data.selected_array) {
|
||||
TreeElement *te = (TreeElement *)link->data;
|
||||
TreeStoreElem *tselem = TREESTORE(te);
|
||||
Collection *parent = find_parent_collection(te);
|
||||
Object *ob = (Object *)tselem->id;
|
||||
|
||||
if (type == COLLECTION_NEW_FROM_SELECTION) {
|
||||
BKE_collection_object_move(bmain, scene, collection_new, parent, ob);
|
||||
}
|
||||
else {
|
||||
BKE_collection_object_add(bmain, collection_new, ob);
|
||||
}
|
||||
}
|
||||
BLI_freelistN(&data.selected_array);
|
||||
}
|
||||
|
||||
DEG_id_tag_update(&collection->id, ID_RECALC_COPY_ON_WRITE);
|
||||
DEG_relations_tag_update(bmain);
|
||||
|
||||
outliner_cleanup_tree(space_outliner);
|
||||
@@ -256,10 +257,29 @@ static int collection_new_exec(bContext *C, wmOperator *op)
|
||||
|
||||
void OUTLINER_OT_collection_new(wmOperatorType *ot)
|
||||
{
|
||||
static EnumPropertyItem type_items[] = {
|
||||
{COLLECTION_NEW_EMPTY,
|
||||
"EMPTY",
|
||||
0,
|
||||
"Empty",
|
||||
"Create a new collection inside the active collection"},
|
||||
{COLLECTION_NEW_FROM_SELECTION,
|
||||
"SELECTION",
|
||||
0,
|
||||
"Move Objects",
|
||||
"Move the selected objects to a new collection"},
|
||||
{COLLECTION_NEW_FROM_SELECTION_LINKED,
|
||||
"SELECTION_LINKED",
|
||||
0,
|
||||
"Link Objects",
|
||||
"Link the selected objects to a new collection"},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
/* identifiers */
|
||||
ot->name = "New Collection";
|
||||
ot->idname = "OUTLINER_OT_collection_new";
|
||||
ot->description = "Add a new collection inside selected collection";
|
||||
ot->description = "Create a new collection";
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec = collection_new_exec;
|
||||
@@ -269,9 +289,7 @@ void OUTLINER_OT_collection_new(wmOperatorType *ot)
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
|
||||
/* properties */
|
||||
PropertyRNA *prop = RNA_def_boolean(
|
||||
ot->srna, "nested", true, "Nested", "Add as child of selected collection");
|
||||
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
||||
ot->prop = RNA_def_enum(ot->srna, "type", type_items, COLLECTION_NEW_FROM_SELECTION, "Type", "");
|
||||
}
|
||||
|
||||
/** \} */
|
||||
@@ -563,7 +581,7 @@ static int collection_duplicate_exec(bContext *C, wmOperator *op)
|
||||
|
||||
/* Can happen when calling from a key binding. */
|
||||
if (te == NULL) {
|
||||
BKE_report(op->reports, RPT_ERROR, "No active collection");
|
||||
BKE_reportf(op->reports, RPT_WARNING, "No active collection");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
@@ -1529,3 +1547,66 @@ void OUTLINER_OT_unhide_all(wmOperatorType *ot)
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Collection Color Tags
|
||||
* \{ */
|
||||
|
||||
static int outliner_color_tag_set_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
|
||||
const short color_tag = RNA_enum_get(op->ptr, "color");
|
||||
|
||||
struct IDsSelectedData selected = {
|
||||
.selected_array = {NULL, NULL},
|
||||
};
|
||||
|
||||
outliner_tree_traverse(space_outliner,
|
||||
&space_outliner->tree,
|
||||
0,
|
||||
TSE_SELECTED,
|
||||
outliner_find_selected_collections,
|
||||
&selected);
|
||||
|
||||
LISTBASE_FOREACH (LinkData *, link, &selected.selected_array) {
|
||||
TreeElement *te_selected = (TreeElement *)link->data;
|
||||
|
||||
Collection *collection = outliner_collection_from_tree_element(te_selected);
|
||||
if (collection == scene->master_collection) {
|
||||
continue;
|
||||
}
|
||||
if (ID_IS_LINKED(collection)) {
|
||||
BKE_report(op->reports, RPT_WARNING, "Can't add a color tag to a linked collection");
|
||||
continue;
|
||||
}
|
||||
|
||||
collection->color = color_tag;
|
||||
};
|
||||
|
||||
BLI_freelistN(&selected.selected_array);
|
||||
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, NULL);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void OUTLINER_OT_collection_color_tag_set(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Set Color Tag";
|
||||
ot->idname = "OUTLINER_OT_collection_color_tag_set";
|
||||
ot->description = "Set a color tag for the selected collections";
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec = outliner_color_tag_set_exec;
|
||||
ot->poll = ED_outliner_collections_editor_poll;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
|
||||
RNA_def_enum(
|
||||
ot->srna, "color", rna_enum_collection_color_items, COLLECTION_COLOR_NONE, "Color Tag", "");
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
@@ -26,7 +26,9 @@
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "DNA_collection_types.h"
|
||||
#include "DNA_constraint_types.h"
|
||||
#include "DNA_material_types.h"
|
||||
#include "DNA_modifier_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_space_types.h"
|
||||
|
||||
@@ -36,6 +38,7 @@
|
||||
#include "BLT_translation.h"
|
||||
|
||||
#include "BKE_collection.h"
|
||||
#include "BKE_constraint.h"
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_layer.h"
|
||||
#include "BKE_lib_id.h"
|
||||
@@ -44,6 +47,7 @@
|
||||
#include "BKE_object.h"
|
||||
#include "BKE_report.h"
|
||||
#include "BKE_scene.h"
|
||||
#include "BKE_shader_fx.h"
|
||||
|
||||
#include "DEG_depsgraph.h"
|
||||
#include "DEG_depsgraph_build.h"
|
||||
@@ -65,6 +69,42 @@
|
||||
|
||||
#include "outliner_intern.h"
|
||||
|
||||
static Collection *collection_parent_from_ID(ID *id);
|
||||
|
||||
/* ******************** Drop Data Functions *********************** */
|
||||
|
||||
typedef struct OutlinerDropData {
|
||||
Object *ob_parent;
|
||||
bPoseChannel *bone_parent;
|
||||
TreeStoreElem *drag_tselem;
|
||||
void *drag_directdata;
|
||||
int drag_index;
|
||||
|
||||
int drop_action;
|
||||
TreeElement *drop_te;
|
||||
TreeElementInsertType insert_type;
|
||||
} OutlinerDropData;
|
||||
|
||||
/* */
|
||||
static void outliner_drop_data_init(wmDrag *drag,
|
||||
Object *ob,
|
||||
bPoseChannel *pchan,
|
||||
TreeElement *te,
|
||||
TreeStoreElem *tselem,
|
||||
void *directdata)
|
||||
{
|
||||
OutlinerDropData *drop_data = MEM_callocN(sizeof(OutlinerDropData), "outliner drop data");
|
||||
|
||||
drop_data->ob_parent = ob;
|
||||
drop_data->bone_parent = pchan;
|
||||
drop_data->drag_tselem = tselem;
|
||||
drop_data->drag_directdata = directdata;
|
||||
drop_data->drag_index = te->index;
|
||||
|
||||
drag->poin = drop_data;
|
||||
drag->flags |= WM_DRAG_FREE_DATA;
|
||||
}
|
||||
|
||||
/* ******************** Drop Target Find *********************** */
|
||||
|
||||
static TreeElement *outliner_dropzone_element(TreeElement *te,
|
||||
@@ -146,7 +186,8 @@ static TreeElement *outliner_drop_insert_find(bContext *C,
|
||||
const float margin = UI_UNIT_Y * (1.0f / 4);
|
||||
|
||||
if (view_mval[1] < (te_hovered->ys + margin)) {
|
||||
if (TSELEM_OPEN(TREESTORE(te_hovered), space_outliner)) {
|
||||
if (TSELEM_OPEN(TREESTORE(te_hovered), space_outliner) &&
|
||||
!BLI_listbase_is_empty(&te_hovered->subtree)) {
|
||||
/* 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;
|
||||
@@ -212,6 +253,11 @@ static TreeElement *outliner_drop_insert_collection_find(bContext *C,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
|
||||
if (space_outliner->sort_method != SO_SORT_FREE) {
|
||||
*r_insert_type = TE_INSERT_INTO;
|
||||
}
|
||||
|
||||
if (collection_te != te) {
|
||||
*r_insert_type = TE_INSERT_INTO;
|
||||
}
|
||||
@@ -224,10 +270,77 @@ static TreeElement *outliner_drop_insert_collection_find(bContext *C,
|
||||
return collection_te;
|
||||
}
|
||||
|
||||
static Object *outliner_object_from_tree_element_and_parents(TreeElement *te, TreeElement **r_te)
|
||||
{
|
||||
TreeStoreElem *tselem;
|
||||
while (te != NULL) {
|
||||
tselem = TREESTORE(te);
|
||||
if (tselem->type == 0 && te->idcode == ID_OB) {
|
||||
*r_te = te;
|
||||
return (Object *)tselem->id;
|
||||
}
|
||||
te = te->parent;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bPoseChannel *outliner_bone_from_tree_element_and_parents(TreeElement *te,
|
||||
TreeElement **r_te)
|
||||
{
|
||||
TreeStoreElem *tselem;
|
||||
while (te != NULL) {
|
||||
tselem = TREESTORE(te);
|
||||
if (tselem->type == TSE_POSE_CHANNEL) {
|
||||
*r_te = te;
|
||||
return (bPoseChannel *)te->directdata;
|
||||
}
|
||||
te = te->parent;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int outliner_get_insert_index(TreeElement *drag_te,
|
||||
TreeElement *drop_te,
|
||||
TreeElementInsertType insert_type,
|
||||
ListBase *listbase)
|
||||
{
|
||||
/* Find the element to insert after. NULL is the start of the list. */
|
||||
if (drag_te->index < drop_te->index) {
|
||||
if (insert_type == TE_INSERT_BEFORE) {
|
||||
drop_te = drop_te->prev;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (insert_type == TE_INSERT_AFTER) {
|
||||
drop_te = drop_te->next;
|
||||
}
|
||||
}
|
||||
|
||||
if (drop_te == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return BLI_findindex(listbase, drop_te->directdata);
|
||||
}
|
||||
|
||||
/* ******************** Parent Drop Operator *********************** */
|
||||
|
||||
static bool parent_drop_allowed(TreeElement *te, Object *potential_child)
|
||||
static bool parent_drop_allowed(bContext *C,
|
||||
const wmEvent *event,
|
||||
TreeElement *te,
|
||||
Object *potential_child)
|
||||
{
|
||||
ARegion *region = CTX_wm_region(C);
|
||||
float view_mval[2];
|
||||
|
||||
UI_view2d_region_to_view(
|
||||
®ion->v2d, event->mval[0], event->mval[1], &view_mval[0], &view_mval[1]);
|
||||
|
||||
/* Check if over name. */
|
||||
if ((view_mval[0] < te->xs + UI_UNIT_X) || (view_mval[0] > te->xend)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
TreeStoreElem *tselem = TREESTORE(te);
|
||||
if (te->idcode != ID_OB || tselem->type != 0) {
|
||||
return false;
|
||||
@@ -262,26 +375,14 @@ static bool parent_drop_allowed(TreeElement *te, Object *potential_child)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool allow_parenting_without_modifier_key(SpaceOutliner *space_outliner)
|
||||
{
|
||||
switch (space_outliner->outlinevis) {
|
||||
case SO_VIEW_LAYER:
|
||||
return space_outliner->filter & SO_FILTER_NO_COLLECTION;
|
||||
case SO_SCENES:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool parent_drop_poll(bContext *C,
|
||||
wmDrag *drag,
|
||||
const wmEvent *event,
|
||||
const char **UNUSED(r_tooltip))
|
||||
const char **r_tooltip)
|
||||
{
|
||||
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
|
||||
|
||||
bool changed = outliner_flag_set(&space_outliner->tree, TSE_DRAG_ANY, false);
|
||||
bool changed = outliner_flag_set(&space_outliner->tree, TSE_HIGHLIGHTED | TSE_DRAG_ANY, false);
|
||||
if (changed) {
|
||||
ED_region_tag_redraw_no_rebuild(CTX_wm_region(C));
|
||||
}
|
||||
@@ -291,24 +392,39 @@ static bool parent_drop_poll(bContext *C,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!allow_parenting_without_modifier_key(space_outliner)) {
|
||||
if (!event->shift) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
TreeElement *te = outliner_drop_find(C, event);
|
||||
TreeElementInsertType insert_type;
|
||||
TreeElement *te = outliner_drop_insert_find(C, event, &insert_type);
|
||||
if (!te) {
|
||||
return false;
|
||||
}
|
||||
TreeStoreElem *tselem = TREESTORE(te);
|
||||
|
||||
if (parent_drop_allowed(te, potential_child)) {
|
||||
TREESTORE(te)->flag |= TSE_DRAG_INTO;
|
||||
ED_region_tag_redraw_no_rebuild(CTX_wm_region(C));
|
||||
return true;
|
||||
if (space_outliner->sort_method != SO_SORT_FREE || space_outliner->outlinevis != SO_VIEW_LAYER) {
|
||||
insert_type = TE_INSERT_INTO;
|
||||
}
|
||||
|
||||
return false;
|
||||
if (!parent_drop_allowed(C, event, te, potential_child)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (insert_type) {
|
||||
case TE_INSERT_BEFORE:
|
||||
tselem->flag |= TSE_DRAG_BEFORE;
|
||||
*r_tooltip = TIP_("Reorder object");
|
||||
break;
|
||||
case TE_INSERT_AFTER:
|
||||
tselem->flag |= TSE_DRAG_AFTER;
|
||||
*r_tooltip = TIP_("Reorder object");
|
||||
break;
|
||||
case TE_INSERT_INTO:
|
||||
tselem->flag |= TSE_DRAG_INTO;
|
||||
break;
|
||||
}
|
||||
|
||||
TREESTORE(te)->flag |= TSE_DRAG_INTO;
|
||||
ED_region_tag_redraw_no_rebuild(CTX_wm_region(C));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void parent_drop_set_parents(bContext *C,
|
||||
@@ -364,9 +480,50 @@ static void parent_drop_set_parents(bContext *C,
|
||||
}
|
||||
}
|
||||
|
||||
static void parent_drop_move_objects(bContext *C, wmDragID *drag, TreeElement *te)
|
||||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
|
||||
Scene *scene = (Scene *)outliner_search_back(te, ID_SCE);
|
||||
if (scene == NULL) {
|
||||
scene = CTX_data_scene(C);
|
||||
}
|
||||
|
||||
Object *ob_drop = (Object *)TREESTORE(te)->id;
|
||||
Collection *collection_to = collection_parent_from_ID(&ob_drop->id);
|
||||
while (te) {
|
||||
te = te->parent;
|
||||
if (outliner_is_collection_tree_element(te)) {
|
||||
collection_to = outliner_collection_from_tree_element(te);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (wmDragID *drag_id = drag; drag_id; drag_id = drag_id->next) {
|
||||
if (GS(drag_id->id->name) == ID_OB) {
|
||||
Object *object = (Object *)drag_id->id;
|
||||
|
||||
/* Do nothing to linked data */
|
||||
if (ID_IS_LINKED(object)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Collection *from = collection_parent_from_ID(drag_id->from_parent);
|
||||
BKE_collection_object_move(bmain, scene, collection_to, from, object);
|
||||
BKE_collection_object_move_after(bmain, collection_to, ob_drop, object);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_LAYER, NULL);
|
||||
}
|
||||
|
||||
static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
TreeElement *te = outliner_drop_find(C, event);
|
||||
TreeElementInsertType insert_type;
|
||||
TreeElement *te = outliner_drop_insert_find(C, event, &insert_type);
|
||||
TreeStoreElem *tselem = te ? TREESTORE(te) : NULL;
|
||||
|
||||
if (!(te && te->idcode == ID_OB && tselem->type == 0)) {
|
||||
@@ -390,7 +547,17 @@ static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
ListBase *lb = event->customdata;
|
||||
wmDrag *drag = lb->first;
|
||||
|
||||
parent_drop_set_parents(C, op->reports, drag->ids.first, par, PAR_OBJECT, event->alt);
|
||||
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
|
||||
if (space_outliner->sort_method != SO_SORT_FREE || space_outliner->outlinevis != SO_VIEW_LAYER) {
|
||||
insert_type = TE_INSERT_INTO;
|
||||
}
|
||||
|
||||
if (insert_type == TE_INSERT_INTO) {
|
||||
parent_drop_set_parents(C, op->reports, drag->ids.first, par, PAR_OBJECT, event->alt);
|
||||
}
|
||||
else {
|
||||
parent_drop_move_objects(C, drag->ids.first, te);
|
||||
}
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
@@ -418,14 +585,6 @@ static bool parent_clear_poll(bContext *C,
|
||||
const wmEvent *event,
|
||||
const char **UNUSED(r_tooltip))
|
||||
{
|
||||
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
|
||||
|
||||
if (!allow_parenting_without_modifier_key(space_outliner)) {
|
||||
if (!event->shift) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Object *ob = (Object *)WM_drag_ID(drag, ID_OB);
|
||||
if (!ob) {
|
||||
return false;
|
||||
@@ -616,6 +775,318 @@ void OUTLINER_OT_material_drop(wmOperatorType *ot)
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
|
||||
}
|
||||
|
||||
/* ******************** UI Stack Drop Operator *********************** */
|
||||
|
||||
/* A generic operator to allow drag and drop for modifiers, constraints,
|
||||
* and shader effects which all share the same UI stack layout.
|
||||
*
|
||||
* The following operations are allowed:
|
||||
* - Reordering within an object.
|
||||
* - Copying a single modifier/constraint/effect to another object.
|
||||
* - Copying (linking) an object's modifiers/constraints/effects to another. */
|
||||
|
||||
enum eUIStackDropAction {
|
||||
UI_STACK_DROP_REORDER,
|
||||
UI_STACK_DROP_COPY,
|
||||
UI_STACK_DROP_LINK,
|
||||
};
|
||||
|
||||
static bool uistack_drop_poll(bContext *C,
|
||||
wmDrag *drag,
|
||||
const wmEvent *event,
|
||||
const char **r_tooltip)
|
||||
{
|
||||
OutlinerDropData *drop_data = drag->poin;
|
||||
if (!drop_data) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ELEM(drop_data->drag_tselem->type,
|
||||
TSE_MODIFIER,
|
||||
TSE_MODIFIER_BASE,
|
||||
TSE_CONSTRAINT,
|
||||
TSE_CONSTRAINT_BASE,
|
||||
TSE_EFFECT,
|
||||
TSE_EFFECT_BASE)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
|
||||
ARegion *region = CTX_wm_region(C);
|
||||
bool changed = outliner_flag_set(&space_outliner->tree, TSE_HIGHLIGHTED | TSE_DRAG_ANY, false);
|
||||
|
||||
TreeElement *te_target = outliner_drop_insert_find(C, event, &drop_data->insert_type);
|
||||
if (!te_target) {
|
||||
return false;
|
||||
}
|
||||
TreeStoreElem *tselem_target = TREESTORE(te_target);
|
||||
|
||||
if (drop_data->drag_tselem == tselem_target) {
|
||||
return false;
|
||||
}
|
||||
|
||||
TreeElement *object_te;
|
||||
TreeElement *bone_te;
|
||||
Object *ob = outliner_object_from_tree_element_and_parents(te_target, &object_te);
|
||||
bPoseChannel *pchan = outliner_bone_from_tree_element_and_parents(te_target, &bone_te);
|
||||
if (pchan) {
|
||||
ob = NULL;
|
||||
}
|
||||
|
||||
/* Drag a base for linking. */
|
||||
if (ELEM(
|
||||
drop_data->drag_tselem->type, TSE_MODIFIER_BASE, TSE_CONSTRAINT_BASE, TSE_EFFECT_BASE)) {
|
||||
drop_data->insert_type = TE_INSERT_INTO;
|
||||
drop_data->drop_action = UI_STACK_DROP_LINK;
|
||||
|
||||
if (pchan && pchan != drop_data->bone_parent) {
|
||||
*r_tooltip = TIP_("Link all to bone");
|
||||
drop_data->drop_te = bone_te;
|
||||
tselem_target = TREESTORE(bone_te);
|
||||
}
|
||||
else if (ob && ob != drop_data->ob_parent) {
|
||||
*r_tooltip = TIP_("Link all to object");
|
||||
drop_data->drop_te = object_te;
|
||||
tselem_target = TREESTORE(object_te);
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (ob || pchan) {
|
||||
/* Drag a single item. */
|
||||
if (pchan && pchan != drop_data->bone_parent) {
|
||||
*r_tooltip = TIP_("Copy to bone");
|
||||
drop_data->insert_type = TE_INSERT_INTO;
|
||||
drop_data->drop_action = UI_STACK_DROP_COPY;
|
||||
drop_data->drop_te = bone_te;
|
||||
tselem_target = TREESTORE(bone_te);
|
||||
}
|
||||
else if (ob && ob != drop_data->ob_parent) {
|
||||
*r_tooltip = TIP_("Copy to object");
|
||||
drop_data->insert_type = TE_INSERT_INTO;
|
||||
drop_data->drop_action = UI_STACK_DROP_COPY;
|
||||
drop_data->drop_te = object_te;
|
||||
tselem_target = TREESTORE(object_te);
|
||||
}
|
||||
else if (tselem_target->type == drop_data->drag_tselem->type) {
|
||||
if (drop_data->insert_type == TE_INSERT_INTO) {
|
||||
return false;
|
||||
}
|
||||
*r_tooltip = TIP_("Reorder");
|
||||
drop_data->drop_action = UI_STACK_DROP_REORDER;
|
||||
drop_data->drop_te = te_target;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (drop_data->insert_type) {
|
||||
case TE_INSERT_BEFORE:
|
||||
tselem_target->flag |= TSE_DRAG_BEFORE;
|
||||
break;
|
||||
case TE_INSERT_AFTER:
|
||||
tselem_target->flag |= TSE_DRAG_AFTER;
|
||||
break;
|
||||
case TE_INSERT_INTO:
|
||||
tselem_target->flag |= TSE_DRAG_INTO;
|
||||
break;
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
ED_region_tag_redraw_no_rebuild(region);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void uistack_drop_link(bContext *C, OutlinerDropData *drop_data)
|
||||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
TreeStoreElem *tselem = TREESTORE(drop_data->drop_te);
|
||||
Object *ob_dst = (Object *)tselem->id;
|
||||
|
||||
if (drop_data->drag_tselem->type == TSE_MODIFIER_BASE) {
|
||||
BKE_object_link_modifiers(ob_dst, drop_data->ob_parent);
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob_dst);
|
||||
DEG_id_tag_update(&ob_dst->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION);
|
||||
}
|
||||
else if (drop_data->drag_tselem->type == TSE_CONSTRAINT_BASE) {
|
||||
ListBase *src;
|
||||
|
||||
if (drop_data->bone_parent) {
|
||||
src = &drop_data->bone_parent->constraints;
|
||||
}
|
||||
else {
|
||||
src = &drop_data->ob_parent->constraints;
|
||||
}
|
||||
|
||||
ListBase *dst;
|
||||
if (tselem->type == TSE_POSE_CHANNEL) {
|
||||
bPoseChannel *pchan = (bPoseChannel *)drop_data->drop_te->directdata;
|
||||
dst = &pchan->constraints;
|
||||
}
|
||||
else {
|
||||
dst = &ob_dst->constraints;
|
||||
}
|
||||
|
||||
BKE_constraints_copy(dst, src, true);
|
||||
LISTBASE_FOREACH (bConstraint *, con, dst) {
|
||||
ED_object_constraint_dependency_tag_update(bmain, ob_dst, con);
|
||||
}
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT | NA_ADDED, NULL);
|
||||
}
|
||||
else if (drop_data->drag_tselem->type == TSE_EFFECT_BASE) {
|
||||
if (ob_dst->type != OB_GPENCIL) {
|
||||
return;
|
||||
}
|
||||
BKE_shaderfx_copy(&ob_dst->shader_fx, &drop_data->ob_parent->shader_fx);
|
||||
|
||||
DEG_id_tag_update(&ob_dst->id, ID_RECALC_GEOMETRY);
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_SHADERFX, ob_dst);
|
||||
}
|
||||
}
|
||||
|
||||
static void uistack_drop_copy(bContext *C, OutlinerDropData *drop_data)
|
||||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
|
||||
TreeStoreElem *tselem = TREESTORE(drop_data->drop_te);
|
||||
Object *ob_dst = (Object *)tselem->id;
|
||||
|
||||
if (drop_data->drag_tselem->type == TSE_MODIFIER) {
|
||||
if (drop_data->ob_parent->type == OB_GPENCIL && ob_dst->type == OB_GPENCIL) {
|
||||
BKE_object_link_gpencil_modifier(ob_dst, drop_data->drag_directdata);
|
||||
}
|
||||
else if (drop_data->ob_parent->type != OB_GPENCIL && ob_dst->type != OB_GPENCIL) {
|
||||
BKE_object_link_modifier(ob_dst, drop_data->ob_parent, drop_data->drag_directdata);
|
||||
}
|
||||
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob_dst);
|
||||
DEG_id_tag_update(&ob_dst->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION);
|
||||
}
|
||||
else if (drop_data->drag_tselem->type == TSE_CONSTRAINT) {
|
||||
if (tselem->type == TSE_POSE_CHANNEL) {
|
||||
BKE_constraint_copy_for_pose(
|
||||
ob_dst, drop_data->drop_te->directdata, drop_data->drag_directdata);
|
||||
}
|
||||
else {
|
||||
BKE_constraint_copy_for_object(ob_dst, drop_data->drag_directdata);
|
||||
}
|
||||
|
||||
ED_object_constraint_dependency_tag_update(bmain, ob_dst, drop_data->drag_directdata);
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT | NA_ADDED, ob_dst);
|
||||
}
|
||||
else if (drop_data->drag_tselem->type == TSE_EFFECT) {
|
||||
if (ob_dst->type != OB_GPENCIL) {
|
||||
return;
|
||||
}
|
||||
ShaderFxData *fx = drop_data->drag_directdata;
|
||||
ShaderFxData *nfx = BKE_shaderfx_new(fx->type);
|
||||
BLI_strncpy(nfx->name, fx->name, sizeof(nfx->name));
|
||||
BKE_shaderfx_copydata(fx, nfx);
|
||||
BLI_addtail(&ob_dst->shader_fx, nfx);
|
||||
|
||||
DEG_id_tag_update(&ob_dst->id, ID_RECALC_GEOMETRY);
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_SHADERFX, ob_dst);
|
||||
}
|
||||
}
|
||||
|
||||
static void uistack_drop_reorder(bContext *C, ReportList *reports, OutlinerDropData *drop_data)
|
||||
{
|
||||
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
|
||||
|
||||
TreeElement *drag_te = outliner_find_tree_element(&space_outliner->tree, drop_data->drag_tselem);
|
||||
if (!drag_te) {
|
||||
return;
|
||||
}
|
||||
|
||||
TreeElement *drop_te = drop_data->drop_te;
|
||||
TreeStoreElem *tselem = TREESTORE(drop_data->drop_te);
|
||||
TreeElementInsertType insert_type = drop_data->insert_type;
|
||||
|
||||
Object *ob_dst = (Object *)tselem->id;
|
||||
Object *ob = drop_data->ob_parent;
|
||||
|
||||
int index = 0;
|
||||
if (drop_data->drag_tselem->type == TSE_MODIFIER) {
|
||||
if (ob->type == OB_GPENCIL && ob_dst->type == OB_GPENCIL) {
|
||||
index = outliner_get_insert_index(
|
||||
drag_te, drop_te, insert_type, &ob->greasepencil_modifiers);
|
||||
ED_object_gpencil_modifier_move_to_index(reports, ob, drop_data->drag_directdata, index);
|
||||
}
|
||||
else if (ob->type != OB_GPENCIL && ob_dst->type != OB_GPENCIL) {
|
||||
index = outliner_get_insert_index(drag_te, drop_te, insert_type, &ob->modifiers);
|
||||
ED_object_modifier_move_to_index(reports, ob, drop_data->drag_directdata, index);
|
||||
}
|
||||
|
||||
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
|
||||
}
|
||||
else if (drop_data->drag_tselem->type == TSE_CONSTRAINT) {
|
||||
if (drop_data->bone_parent) {
|
||||
index = outliner_get_insert_index(
|
||||
drag_te, drop_te, insert_type, &drop_data->bone_parent->constraints);
|
||||
}
|
||||
else {
|
||||
index = outliner_get_insert_index(drag_te, drop_te, insert_type, &ob->constraints);
|
||||
}
|
||||
ED_object_constraint_move_to_index(reports, ob, drop_data->drag_directdata, index);
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob);
|
||||
}
|
||||
else if (drop_data->drag_tselem->type == TSE_EFFECT) {
|
||||
index = outliner_get_insert_index(drag_te, drop_te, insert_type, &ob->shader_fx);
|
||||
ED_object_shaderfx_move_to_index(reports, ob, drop_data->drag_directdata, index);
|
||||
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_SHADERFX, ob);
|
||||
}
|
||||
}
|
||||
|
||||
static int uistack_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
if (event->custom != EVT_DATA_DRAGDROP) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
ListBase *lb = event->customdata;
|
||||
wmDrag *drag = lb->first;
|
||||
OutlinerDropData *drop_data = drag->poin;
|
||||
|
||||
switch (drop_data->drop_action) {
|
||||
case UI_STACK_DROP_LINK:
|
||||
uistack_drop_link(C, drop_data);
|
||||
break;
|
||||
case UI_STACK_DROP_COPY:
|
||||
uistack_drop_copy(C, drop_data);
|
||||
break;
|
||||
case UI_STACK_DROP_REORDER:
|
||||
uistack_drop_reorder(C, op->reports, drop_data);
|
||||
break;
|
||||
}
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void OUTLINER_OT_uistack_drop(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "UI Stack Drop";
|
||||
ot->description = "Copy or reorder modifiers, constraints, and effects";
|
||||
ot->idname = "OUTLINER_OT_uistack_drop";
|
||||
|
||||
/* api callbacks */
|
||||
ot->invoke = uistack_drop_invoke;
|
||||
|
||||
ot->poll = ED_operator_outliner_active;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
|
||||
}
|
||||
|
||||
/* ******************** Collection Drop Operator *********************** */
|
||||
|
||||
typedef struct CollectionDrop {
|
||||
@@ -730,22 +1201,12 @@ static bool collection_drop_poll(bContext *C,
|
||||
case TE_INSERT_BEFORE:
|
||||
tselem->flag |= TSE_DRAG_BEFORE;
|
||||
changed = true;
|
||||
if (te->prev && outliner_is_collection_tree_element(te->prev)) {
|
||||
*r_tooltip = TIP_("Move between collections");
|
||||
}
|
||||
else {
|
||||
*r_tooltip = TIP_("Move before collection");
|
||||
}
|
||||
*r_tooltip = TIP_("Reorder collection(s)");
|
||||
break;
|
||||
case TE_INSERT_AFTER:
|
||||
tselem->flag |= TSE_DRAG_AFTER;
|
||||
changed = true;
|
||||
if (te->next && outliner_is_collection_tree_element(te->next)) {
|
||||
*r_tooltip = TIP_("Move between collections");
|
||||
}
|
||||
else {
|
||||
*r_tooltip = TIP_("Move after collection");
|
||||
}
|
||||
*r_tooltip = TIP_("Reorder collection(s)");
|
||||
break;
|
||||
case TE_INSERT_INTO:
|
||||
tselem->flag |= TSE_DRAG_INTO;
|
||||
@@ -882,7 +1343,8 @@ static int outliner_item_drag_drop_invoke(bContext *C,
|
||||
return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH);
|
||||
}
|
||||
|
||||
TreeElementIcon data = tree_element_get_icon(TREESTORE(te), te);
|
||||
TreeStoreElem *tselem = TREESTORE(te);
|
||||
TreeElementIcon data = tree_element_get_icon(tselem, te);
|
||||
if (!data.drag_id) {
|
||||
return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH);
|
||||
}
|
||||
@@ -893,6 +1355,9 @@ static int outliner_item_drag_drop_invoke(bContext *C,
|
||||
if (outliner_item_is_co_within_close_toggle(te, view_mval[0])) {
|
||||
return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH);
|
||||
}
|
||||
if (outliner_is_co_within_mode_column(space_outliner, view_mval)) {
|
||||
return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
|
||||
}
|
||||
|
||||
/* Scroll the view when dragging near edges, but not
|
||||
* when the drag goes too far outside the region. */
|
||||
@@ -907,13 +1372,25 @@ static int outliner_item_drag_drop_invoke(bContext *C,
|
||||
|
||||
wmDrag *drag = WM_event_start_drag(C, data.icon, WM_DRAG_ID, NULL, 0.0, WM_DRAG_NOP);
|
||||
|
||||
if (ELEM(GS(data.drag_id->name), ID_OB, ID_GR)) {
|
||||
if (ELEM(tselem->type,
|
||||
TSE_MODIFIER,
|
||||
TSE_MODIFIER_BASE,
|
||||
TSE_CONSTRAINT,
|
||||
TSE_CONSTRAINT_BASE,
|
||||
TSE_EFFECT,
|
||||
TSE_EFFECT_BASE)) {
|
||||
|
||||
TreeElement *te_bone = NULL;
|
||||
bPoseChannel *pchan = outliner_find_parent_bone(te, &te_bone);
|
||||
outliner_drop_data_init(drag, (Object *)tselem->id, pchan, te, tselem, te->directdata);
|
||||
}
|
||||
else if (ELEM(GS(data.drag_id->name), ID_OB, ID_GR)) {
|
||||
/* For collections and objects we cheat and drag all selected. */
|
||||
|
||||
/* Only drag element under mouse if it was not selected before. */
|
||||
if ((TREESTORE(te)->flag & TSE_SELECTED) == 0) {
|
||||
if ((tselem->flag & TSE_SELECTED) == 0) {
|
||||
outliner_flag_set(&space_outliner->tree, TSE_SELECTED, 0);
|
||||
TREESTORE(te)->flag |= TSE_SELECTED;
|
||||
tselem->flag |= TSE_SELECTED;
|
||||
}
|
||||
|
||||
/* Gather all selected elements. */
|
||||
@@ -992,7 +1469,7 @@ static int outliner_item_drag_drop_invoke(bContext *C,
|
||||
WM_drag_add_ID(drag, data.drag_id, data.drag_parent);
|
||||
}
|
||||
|
||||
ED_outliner_select_sync_from_all_tag(C);
|
||||
ED_outliner_select_sync_from_outliner(C, space_outliner);
|
||||
|
||||
return (OPERATOR_FINISHED | OPERATOR_PASS_THROUGH);
|
||||
}
|
||||
@@ -1024,5 +1501,6 @@ void outliner_dropboxes(void)
|
||||
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_uistack_drop", uistack_drop_poll, NULL);
|
||||
WM_dropbox_add(lb, "OUTLINER_OT_collection_drop", collection_drop_poll, NULL);
|
||||
}
|
||||
|
@@ -53,6 +53,7 @@
|
||||
#include "BKE_main.h"
|
||||
#include "BKE_modifier.h"
|
||||
#include "BKE_object.h"
|
||||
#include "BKE_particle.h"
|
||||
#include "BKE_report.h"
|
||||
#include "BKE_scene.h"
|
||||
|
||||
@@ -182,7 +183,7 @@ static void restrictbutton_bone_visibility_fn(bContext *C, void *poin, void *UNU
|
||||
{
|
||||
Bone *bone = (Bone *)poin;
|
||||
|
||||
if (CTX_wm_window(C)->eventstate->ctrl) {
|
||||
if (CTX_wm_window(C)->eventstate->shift) {
|
||||
restrictbutton_recursive_bone(bone, BONE_HIDDEN_P, (bone->flag & BONE_HIDDEN_P) != 0);
|
||||
}
|
||||
}
|
||||
@@ -194,7 +195,7 @@ static void restrictbutton_bone_select_fn(bContext *C, void *UNUSED(poin), void
|
||||
bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
|
||||
}
|
||||
|
||||
if (CTX_wm_window(C)->eventstate->ctrl) {
|
||||
if (CTX_wm_window(C)->eventstate->shift) {
|
||||
restrictbutton_recursive_bone(bone, BONE_UNSELECTABLE, (bone->flag & BONE_UNSELECTABLE) != 0);
|
||||
}
|
||||
|
||||
@@ -209,7 +210,7 @@ static void restrictbutton_ebone_select_fn(bContext *C, void *UNUSED(poin), void
|
||||
ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
|
||||
}
|
||||
|
||||
if (CTX_wm_window(C)->eventstate->ctrl) {
|
||||
if (CTX_wm_window(C)->eventstate->shift) {
|
||||
restrictbutton_recursive_ebone(
|
||||
C, ebone, BONE_UNSELECTABLE, (ebone->flag & BONE_UNSELECTABLE) != 0);
|
||||
}
|
||||
@@ -224,7 +225,7 @@ static void restrictbutton_ebone_visibility_fn(bContext *C, void *UNUSED(poin),
|
||||
ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
|
||||
}
|
||||
|
||||
if (CTX_wm_window(C)->eventstate->ctrl) {
|
||||
if (CTX_wm_window(C)->eventstate->shift) {
|
||||
restrictbutton_recursive_ebone(C, ebone, BONE_HIDDEN_A, (ebone->flag & BONE_HIDDEN_A) != 0);
|
||||
}
|
||||
|
||||
@@ -848,8 +849,8 @@ typedef struct RestrictProperties {
|
||||
PropertyRNA *object_hide_viewport, *object_hide_select, *object_hide_render;
|
||||
PropertyRNA *base_hide_viewport;
|
||||
PropertyRNA *collection_hide_viewport, *collection_hide_select, *collection_hide_render;
|
||||
PropertyRNA *layer_collection_holdout, *layer_collection_indirect_only,
|
||||
*layer_collection_hide_viewport;
|
||||
PropertyRNA *layer_collection_exclude, *layer_collection_holdout,
|
||||
*layer_collection_indirect_only, *layer_collection_hide_viewport;
|
||||
PropertyRNA *modifier_show_viewport, *modifier_show_render;
|
||||
PropertyRNA *constraint_enable;
|
||||
PropertyRNA *bone_hide_viewport;
|
||||
@@ -865,6 +866,7 @@ typedef struct RestrictPropertiesActive {
|
||||
bool collection_hide_viewport;
|
||||
bool collection_hide_select;
|
||||
bool collection_hide_render;
|
||||
bool layer_collection_exclude;
|
||||
bool layer_collection_holdout;
|
||||
bool layer_collection_indirect_only;
|
||||
bool layer_collection_hide_viewport;
|
||||
@@ -954,8 +956,7 @@ static bool outliner_restrict_properties_collection_set(Scene *scene,
|
||||
NULL;
|
||||
Collection *collection = outliner_collection_from_tree_element(te);
|
||||
|
||||
if ((collection->flag & COLLECTION_IS_MASTER) ||
|
||||
(layer_collection && ((layer_collection->flag & LAYER_COLLECTION_EXCLUDE) != 0))) {
|
||||
if (collection->flag & COLLECTION_IS_MASTER) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -995,6 +996,8 @@ static void outliner_draw_restrictbuts(uiBlock *block,
|
||||
"hide_viewport");
|
||||
props.collection_hide_select = RNA_struct_type_find_property(&RNA_Collection, "hide_select");
|
||||
props.collection_hide_render = RNA_struct_type_find_property(&RNA_Collection, "hide_render");
|
||||
props.layer_collection_exclude = RNA_struct_type_find_property(&RNA_LayerCollection,
|
||||
"exclude");
|
||||
props.layer_collection_holdout = RNA_struct_type_find_property(&RNA_LayerCollection,
|
||||
"holdout");
|
||||
props.layer_collection_indirect_only = RNA_struct_type_find_property(&RNA_LayerCollection,
|
||||
@@ -1012,6 +1015,7 @@ static void outliner_draw_restrictbuts(uiBlock *block,
|
||||
}
|
||||
|
||||
struct {
|
||||
int enable;
|
||||
int select;
|
||||
int hide;
|
||||
int viewport;
|
||||
@@ -1042,6 +1046,11 @@ static void outliner_draw_restrictbuts(uiBlock *block,
|
||||
if (space_outliner->show_restrict_flags & SO_RESTRICT_SELECT) {
|
||||
restrict_offsets.select = (++restrict_column_offset) * UI_UNIT_X + V2D_SCROLL_WIDTH;
|
||||
}
|
||||
if (space_outliner->outlinevis == SO_VIEW_LAYER &&
|
||||
space_outliner->show_restrict_flags & SO_RESTRICT_ENABLE) {
|
||||
restrict_offsets.enable = (++restrict_column_offset) * UI_UNIT_X + V2D_SCROLL_WIDTH;
|
||||
}
|
||||
|
||||
BLI_assert((restrict_column_offset * UI_UNIT_X + V2D_SCROLL_WIDTH) ==
|
||||
outliner_restrict_columns_width(space_outliner));
|
||||
|
||||
@@ -1430,6 +1439,26 @@ static void outliner_draw_restrictbuts(uiBlock *block,
|
||||
Collection *collection = outliner_collection_from_tree_element(te);
|
||||
|
||||
if (layer_collection != NULL) {
|
||||
if (space_outliner->show_restrict_flags & SO_RESTRICT_ENABLE) {
|
||||
bt = uiDefIconButR_prop(block,
|
||||
UI_BTYPE_ICON_TOGGLE,
|
||||
0,
|
||||
0,
|
||||
(int)(region->v2d.cur.xmax) - restrict_offsets.enable,
|
||||
te->ys,
|
||||
UI_UNIT_X,
|
||||
UI_UNIT_Y,
|
||||
&layer_collection_ptr,
|
||||
props.layer_collection_exclude,
|
||||
-1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
NULL);
|
||||
UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
|
||||
}
|
||||
|
||||
if (space_outliner->show_restrict_flags & SO_RESTRICT_HIDE) {
|
||||
bt = uiDefIconButR_prop(block,
|
||||
UI_BTYPE_ICON_TOGGLE,
|
||||
@@ -1823,7 +1852,6 @@ static void outliner_buttons(const bContext *C,
|
||||
const float restrict_column_width,
|
||||
TreeElement *te)
|
||||
{
|
||||
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
|
||||
uiBut *bt;
|
||||
TreeStoreElem *tselem;
|
||||
int spx, dx, len;
|
||||
@@ -1849,10 +1877,6 @@ static void outliner_buttons(const bContext *C,
|
||||
}
|
||||
|
||||
spx = te->xs + 1.8f * UI_UNIT_X;
|
||||
if ((tselem->type == TSE_LAYER_COLLECTION) &&
|
||||
(space_outliner->show_restrict_flags & SO_RESTRICT_ENABLE)) {
|
||||
spx += UI_UNIT_X;
|
||||
}
|
||||
dx = region->v2d.cur.xmax - (spx + restrict_column_width + 0.2f * UI_UNIT_X);
|
||||
|
||||
bt = uiDefBut(block,
|
||||
@@ -1880,6 +1904,143 @@ static void outliner_buttons(const bContext *C,
|
||||
}
|
||||
}
|
||||
|
||||
static void outliner_mode_toggle_fn(bContext *C, void *tselem_poin, void *UNUSED(arg2))
|
||||
{
|
||||
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
|
||||
TreeStoreElem *tselem = (TreeStoreElem *)tselem_poin;
|
||||
TreeViewContext tvc;
|
||||
outliner_viewcontext_init(C, &tvc);
|
||||
|
||||
TreeElement *te = outliner_find_tree_element(&space_outliner->tree, tselem);
|
||||
if (!te) {
|
||||
return;
|
||||
}
|
||||
|
||||
outliner_item_mode_toggle(C, &tvc, te);
|
||||
}
|
||||
|
||||
/* Return the icon for a given interaction mode
|
||||
* Should this be more generic (in a different file?) */
|
||||
static int outliner_get_mode_icon(const int mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case OB_MODE_OBJECT:
|
||||
return ICON_OBJECT_DATAMODE;
|
||||
case OB_MODE_EDIT:
|
||||
case OB_MODE_EDIT_GPENCIL:
|
||||
return ICON_EDITMODE_HLT;
|
||||
case OB_MODE_SCULPT:
|
||||
case OB_MODE_SCULPT_GPENCIL:
|
||||
return ICON_SCULPTMODE_HLT;
|
||||
case OB_MODE_VERTEX_PAINT:
|
||||
case OB_MODE_VERTEX_GPENCIL:
|
||||
return ICON_VPAINT_HLT;
|
||||
case OB_MODE_WEIGHT_PAINT:
|
||||
case OB_MODE_WEIGHT_GPENCIL:
|
||||
return ICON_WPAINT_HLT;
|
||||
case OB_MODE_TEXTURE_PAINT:
|
||||
return ICON_TPAINT_HLT;
|
||||
case OB_MODE_PARTICLE_EDIT:
|
||||
return ICON_PARTICLEMODE;
|
||||
case OB_MODE_POSE:
|
||||
return ICON_POSE_HLT;
|
||||
case OB_MODE_PAINT_GPENCIL:
|
||||
return ICON_GREASEPENCIL;
|
||||
default:
|
||||
return ICON_DOT;
|
||||
}
|
||||
}
|
||||
|
||||
/* Draw icons for adding and removing objects from the current interation mode */
|
||||
static void outliner_draw_mode_column_toggle(uiBlock *block,
|
||||
TreeViewContext *tvc,
|
||||
TreeElement *te,
|
||||
TreeStoreElem *tselem,
|
||||
const bool lock_object_modes)
|
||||
{
|
||||
uiBut *but;
|
||||
const int active_mode = tvc->obact->mode;
|
||||
bool draw_active_icon = true;
|
||||
|
||||
if (tselem->type == 0 && te->idcode == ID_OB) {
|
||||
Object *ob = (Object *)tselem->id;
|
||||
|
||||
/* When not locking object modes, objects can remain in non-object modes. For modes that do not
|
||||
* allow multi-object editing, these other objects should still show be viewed as not in the
|
||||
* mode. Otherwise multiple objects show the same mode icon in the outliner even though only
|
||||
* one object is actually editable in the mode. */
|
||||
if (!lock_object_modes && ob != tvc->obact && !(tvc->ob_edit || tvc->ob_pose)) {
|
||||
draw_active_icon = false;
|
||||
}
|
||||
|
||||
if (ob->type == tvc->obact->type) {
|
||||
if (draw_active_icon && ob->mode == tvc->obact->mode) {
|
||||
but = uiDefIconBut(block,
|
||||
UI_BTYPE_ICON_TOGGLE,
|
||||
0,
|
||||
outliner_get_mode_icon(active_mode),
|
||||
0,
|
||||
te->ys,
|
||||
UI_UNIT_X,
|
||||
UI_UNIT_Y,
|
||||
NULL,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
TIP_("Remove from the current mode"));
|
||||
UI_but_func_set(but, outliner_mode_toggle_fn, tselem, NULL);
|
||||
UI_but_flag_enable(but, UI_BUT_DRAG_LOCK);
|
||||
}
|
||||
else {
|
||||
/* Not all objects have particle systems */
|
||||
if (active_mode == OB_MODE_PARTICLE_EDIT && !psys_get_current(ob)) {
|
||||
return;
|
||||
}
|
||||
but = uiDefIconBut(block,
|
||||
UI_BTYPE_ICON_TOGGLE,
|
||||
0,
|
||||
tselem->flag & TSE_HIGHLIGHTED ? outliner_get_mode_icon(active_mode) :
|
||||
ICON_DOT,
|
||||
0,
|
||||
te->ys,
|
||||
UI_UNIT_X,
|
||||
UI_UNIT_Y,
|
||||
NULL,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
TIP_("Add to the current mode"));
|
||||
UI_but_func_set(but, outliner_mode_toggle_fn, tselem, NULL);
|
||||
UI_but_flag_enable(but, UI_BUT_DRAG_LOCK);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void outliner_draw_mode_column(const bContext *C,
|
||||
uiBlock *block,
|
||||
TreeViewContext *tvc,
|
||||
SpaceOutliner *space_outliner,
|
||||
ListBase *tree)
|
||||
{
|
||||
TreeStoreElem *tselem;
|
||||
const bool lock_object_modes = tvc->scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK;
|
||||
|
||||
LISTBASE_FOREACH (TreeElement *, te, tree) {
|
||||
tselem = TREESTORE(te);
|
||||
|
||||
if (tvc->obact && tvc->obact->mode != OB_MODE_OBJECT) {
|
||||
outliner_draw_mode_column_toggle(block, tvc, te, tselem, lock_object_modes);
|
||||
}
|
||||
|
||||
if (TSELEM_OPEN(tselem, space_outliner)) {
|
||||
outliner_draw_mode_column(C, block, tvc, space_outliner, &te->subtree);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ****************************************************** */
|
||||
/* Normal Drawing... */
|
||||
|
||||
@@ -1916,9 +2077,11 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
|
||||
break;
|
||||
case TSE_CONSTRAINT_BASE:
|
||||
data.icon = ICON_CONSTRAINT;
|
||||
data.drag_id = tselem->id;
|
||||
break;
|
||||
case TSE_CONSTRAINT: {
|
||||
bConstraint *con = te->directdata;
|
||||
data.drag_id = tselem->id;
|
||||
switch ((eBConstraint_Types)con->type) {
|
||||
case CONSTRAINT_TYPE_CAMERASOLVER:
|
||||
data.icon = ICON_CON_CAMERASOLVER;
|
||||
@@ -2013,6 +2176,7 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
|
||||
}
|
||||
case TSE_MODIFIER_BASE:
|
||||
data.icon = ICON_MODIFIER_DATA;
|
||||
data.drag_id = tselem->id;
|
||||
break;
|
||||
case TSE_LINKED_OB:
|
||||
data.icon = ICON_OBJECT_DATA;
|
||||
@@ -2022,6 +2186,8 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
|
||||
break;
|
||||
case TSE_MODIFIER: {
|
||||
Object *ob = (Object *)tselem->id;
|
||||
data.drag_id = tselem->id;
|
||||
|
||||
if (ob->type != OB_GPENCIL) {
|
||||
ModifierData *md = BLI_findlink(&ob->modifiers, tselem->nr);
|
||||
switch ((ModifierType)md->type) {
|
||||
@@ -2188,7 +2354,7 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
|
||||
GpencilModifierData *md = BLI_findlink(&ob->greasepencil_modifiers, tselem->nr);
|
||||
switch ((GpencilModifierType)md->type) {
|
||||
case eGpencilModifierType_Noise:
|
||||
data.icon = ICON_RNDCURVE;
|
||||
data.icon = ICON_MOD_NOISE;
|
||||
break;
|
||||
case eGpencilModifierType_Subdiv:
|
||||
data.icon = ICON_MOD_SUBSURF;
|
||||
@@ -2232,6 +2398,15 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
|
||||
case eGpencilModifierType_Armature:
|
||||
data.icon = ICON_MOD_ARMATURE;
|
||||
break;
|
||||
case eGpencilModifierType_Multiply:
|
||||
data.icon = ICON_GP_MULTIFRAME_EDITING;
|
||||
break;
|
||||
case eGpencilModifierType_Time:
|
||||
data.icon = ICON_MOD_TIME;
|
||||
break;
|
||||
case eGpencilModifierType_Texture:
|
||||
data.icon = ICON_TEXTURE;
|
||||
break;
|
||||
|
||||
/* Default */
|
||||
default:
|
||||
@@ -2347,13 +2522,18 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
|
||||
data.drag_parent = (data.drag_id && te->parent) ? TREESTORE(te->parent)->id : NULL;
|
||||
}
|
||||
|
||||
data.icon = ICON_GROUP;
|
||||
data.icon = ICON_OUTLINER_COLLECTION;
|
||||
break;
|
||||
}
|
||||
case TSE_GP_LAYER: {
|
||||
data.icon = ICON_OUTLINER_DATA_GP_LAYER;
|
||||
break;
|
||||
}
|
||||
case TSE_EFFECT_BASE:
|
||||
case TSE_EFFECT:
|
||||
data.drag_id = tselem->id;
|
||||
data.icon = ICON_SHADERFX;
|
||||
break;
|
||||
default:
|
||||
data.icon = ICON_DOT;
|
||||
break;
|
||||
@@ -2578,60 +2758,6 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
|
||||
return data;
|
||||
}
|
||||
|
||||
static void tselem_draw_layer_collection_enable_icon(
|
||||
Scene *scene, uiBlock *block, int xmax, float x, float y, TreeElement *te, float alpha)
|
||||
{
|
||||
/* Get RNA property (once for speed). */
|
||||
static PropertyRNA *exclude_prop = NULL;
|
||||
if (exclude_prop == NULL) {
|
||||
exclude_prop = RNA_struct_type_find_property(&RNA_LayerCollection, "exclude");
|
||||
}
|
||||
|
||||
if (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,
|
||||
* doesn't work for buttons */
|
||||
uchar color[4];
|
||||
int icon = RNA_property_ui_icon(exclude_prop);
|
||||
if (UI_icon_get_theme_color(icon, color)) {
|
||||
UI_icon_draw_ex(x, y, icon, U.inv_dpi_fac, alpha, 0.0f, color, true);
|
||||
}
|
||||
else {
|
||||
UI_icon_draw_ex(x, y, icon, U.inv_dpi_fac, alpha, 0.0f, NULL, false);
|
||||
}
|
||||
}
|
||||
else {
|
||||
LayerCollection *layer_collection = te->directdata;
|
||||
PointerRNA layer_collection_ptr;
|
||||
RNA_pointer_create(&scene->id, &RNA_LayerCollection, layer_collection, &layer_collection_ptr);
|
||||
|
||||
char emboss = UI_block_emboss_get(block);
|
||||
UI_block_emboss_set(block, UI_EMBOSS_NONE);
|
||||
uiBut *bt = uiDefIconButR_prop(block,
|
||||
UI_BTYPE_ICON_TOGGLE,
|
||||
0,
|
||||
0,
|
||||
x,
|
||||
y,
|
||||
UI_UNIT_X,
|
||||
UI_UNIT_Y,
|
||||
&layer_collection_ptr,
|
||||
exclude_prop,
|
||||
-1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
NULL);
|
||||
UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
|
||||
UI_block_emboss_set(block, emboss);
|
||||
}
|
||||
}
|
||||
|
||||
static void tselem_draw_icon(uiBlock *block,
|
||||
int xmax,
|
||||
float x,
|
||||
@@ -2647,8 +2773,30 @@ static void tselem_draw_icon(uiBlock *block,
|
||||
return;
|
||||
}
|
||||
|
||||
if (outliner_is_collection_tree_element(te)) {
|
||||
Collection *collection = outliner_collection_from_tree_element(te);
|
||||
|
||||
/* 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;
|
||||
if (collection->color != COLLECTION_COLOR_NONE) {
|
||||
bTheme *btheme = UI_GetTheme();
|
||||
UI_icon_draw_ex(x,
|
||||
y,
|
||||
data.icon,
|
||||
U.inv_dpi_fac,
|
||||
alpha,
|
||||
0.0f,
|
||||
btheme->collection_color[collection->color - 1].color,
|
||||
true);
|
||||
}
|
||||
else {
|
||||
UI_icon_draw_ex(x, y, data.icon, U.inv_dpi_fac, alpha, 0.0f, NULL, true);
|
||||
}
|
||||
}
|
||||
/* Icon is covered by restrict buttons */
|
||||
if (!is_clickable || x >= xmax) {
|
||||
else if (!is_clickable || x >= xmax) {
|
||||
/* Reduce alpha to match icon buttons */
|
||||
alpha *= 0.8f;
|
||||
|
||||
@@ -2732,15 +2880,21 @@ static void outliner_draw_iconrow_number(const uiFontStyle *fstyle,
|
||||
GPU_blend(GPU_BLEND_ALPHA); /* Roundbox and text drawing disables. */
|
||||
}
|
||||
|
||||
static void outliner_icon_background_colors(float icon_color[4], float icon_border[4])
|
||||
static void outliner_draw_active_highlight(const float minx,
|
||||
const float miny,
|
||||
const float maxx,
|
||||
const float maxy)
|
||||
{
|
||||
float text[4];
|
||||
UI_GetThemeColor4fv(TH_TEXT, text);
|
||||
const float ufac = U.pixelsize;
|
||||
float icon_border[4];
|
||||
UI_GetThemeColor4fv(TH_TEXT, icon_border);
|
||||
icon_border[3] = 0.6f;
|
||||
|
||||
copy_v3_v3(icon_color, text);
|
||||
icon_color[3] = 0.4f;
|
||||
copy_v3_v3(icon_border, text);
|
||||
icon_border[3] = 0.2f;
|
||||
/* border around it */
|
||||
UI_draw_roundbox_corner_set(UI_CNR_ALL);
|
||||
UI_draw_roundbox_aa(
|
||||
false, minx + ufac, miny + ufac, maxx - ufac, maxy - ufac, UI_UNIT_Y / 4.0f, icon_border);
|
||||
GPU_blend(true); /* Roundbox disables. */
|
||||
}
|
||||
|
||||
/* Draw a rounded rectangle behind icons of active elements. */
|
||||
@@ -2773,19 +2927,8 @@ static void outliner_draw_iconrow_doit(uiBlock *block,
|
||||
TreeStoreElem *tselem = TREESTORE(te);
|
||||
|
||||
if (active != OL_DRAWSEL_NONE) {
|
||||
float icon_color[4], icon_border[4];
|
||||
outliner_icon_background_colors(icon_color, icon_border);
|
||||
if (active == OL_DRAWSEL_ACTIVE) {
|
||||
UI_GetThemeColor4fv(TH_EDITED_OBJECT, icon_color);
|
||||
icon_border[3] = 0.3f;
|
||||
}
|
||||
|
||||
outliner_draw_active_indicator((float)*offsx,
|
||||
(float)ys,
|
||||
(float)*offsx + UI_UNIT_X,
|
||||
(float)ys + UI_UNIT_Y,
|
||||
icon_color,
|
||||
icon_border);
|
||||
outliner_draw_active_highlight(
|
||||
(float)*offsx, (float)ys, (float)*offsx + UI_UNIT_X, (float)ys + UI_UNIT_Y);
|
||||
}
|
||||
|
||||
if (tselem->flag & TSE_HIGHLIGHTED) {
|
||||
@@ -2967,8 +3110,6 @@ static void outliner_draw_tree_element(bContext *C,
|
||||
eOLDrawState active = OL_DRAWSEL_NONE;
|
||||
uchar text_color[4];
|
||||
UI_GetThemeColor4ubv(TH_TEXT, text_color);
|
||||
float icon_bgcolor[4], icon_border[4];
|
||||
outliner_icon_background_colors(icon_bgcolor, icon_border);
|
||||
|
||||
if (*starty + 2 * UI_UNIT_Y >= region->v2d.cur.ymin && *starty <= region->v2d.cur.ymax) {
|
||||
const float alpha_fac = ((te->flag & TE_DISABLED) || (te->flag & TE_CHILD_NOT_IN_COLLECTION) ||
|
||||
@@ -2993,7 +3134,6 @@ static void outliner_draw_tree_element(bContext *C,
|
||||
if (te->idcode == ID_SCE) {
|
||||
if (tselem->id == (ID *)tvc->scene) {
|
||||
/* active scene */
|
||||
icon_bgcolor[3] = 0.2f;
|
||||
active = OL_DRAWSEL_ACTIVE;
|
||||
}
|
||||
}
|
||||
@@ -3022,14 +3162,11 @@ static void outliner_draw_tree_element(bContext *C,
|
||||
}
|
||||
else if (is_object_data_in_editmode(tselem->id, tvc->obact)) {
|
||||
/* objects being edited */
|
||||
UI_GetThemeColor4fv(TH_EDITED_OBJECT, icon_bgcolor);
|
||||
icon_border[3] = 0.3f;
|
||||
active = OL_DRAWSEL_ACTIVE;
|
||||
}
|
||||
else {
|
||||
if (tree_element_active(C, tvc, space_outliner, te, OL_SETSEL_NONE, false)) {
|
||||
/* active items like camera or material */
|
||||
icon_bgcolor[3] = 0.2f;
|
||||
active = OL_DRAWSEL_ACTIVE;
|
||||
}
|
||||
}
|
||||
@@ -3037,32 +3174,20 @@ static void outliner_draw_tree_element(bContext *C,
|
||||
else if (tselem->type == TSE_GP_LAYER) {
|
||||
/* Active grease pencil layer. */
|
||||
if (((bGPDlayer *)te->directdata)->flag & GP_LAYER_ACTIVE) {
|
||||
icon_bgcolor[3] = 0.2f;
|
||||
active = OL_DRAWSEL_ACTIVE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
active = tree_element_type_active(C, tvc, space_outliner, te, tselem, OL_SETSEL_NONE, false);
|
||||
/* active collection*/
|
||||
icon_bgcolor[3] = 0.2f;
|
||||
}
|
||||
|
||||
/* Checkbox to enable collections. */
|
||||
if ((tselem->type == TSE_LAYER_COLLECTION) &&
|
||||
(space_outliner->show_restrict_flags & SO_RESTRICT_ENABLE)) {
|
||||
tselem_draw_layer_collection_enable_icon(
|
||||
tvc->scene, block, xmax, (float)startx + offsx + UI_UNIT_X, (float)*starty, te, 0.8f);
|
||||
offsx += UI_UNIT_X;
|
||||
}
|
||||
|
||||
/* active circle */
|
||||
if (active != OL_DRAWSEL_NONE) {
|
||||
outliner_draw_active_indicator((float)startx + offsx + UI_UNIT_X,
|
||||
outliner_draw_active_highlight((float)startx + offsx + UI_UNIT_X,
|
||||
(float)*starty,
|
||||
(float)startx + offsx + 2.0f * UI_UNIT_X,
|
||||
(float)*starty + UI_UNIT_Y,
|
||||
icon_bgcolor,
|
||||
icon_border);
|
||||
(float)*starty + UI_UNIT_Y);
|
||||
|
||||
te->flag |= TE_ACTIVE; /* For lookup in display hierarchies. */
|
||||
}
|
||||
@@ -3125,7 +3250,8 @@ static void outliner_draw_tree_element(bContext *C,
|
||||
offsx += (int)(UI_UNIT_X + UI_fontstyle_string_width(fstyle, te->name));
|
||||
|
||||
/* closed item, we draw the icons, not when it's a scene, or master-server list though */
|
||||
if (!TSELEM_OPEN(tselem, space_outliner)) {
|
||||
if (!TSELEM_OPEN(tselem, space_outliner) &&
|
||||
!(space_outliner->filter & SO_FILTER_NO_ROW_CHILDREN)) {
|
||||
if (te->subtree.first) {
|
||||
if (tselem->type == 0 && te->idcode == ID_SCE) {
|
||||
/* pass */
|
||||
@@ -3190,6 +3316,17 @@ static void outliner_draw_tree_element(bContext *C,
|
||||
}
|
||||
}
|
||||
|
||||
static bool subtree_contains_object(ListBase *lb)
|
||||
{
|
||||
LISTBASE_FOREACH (TreeElement *, te, lb) {
|
||||
TreeStoreElem *tselem = TREESTORE(te);
|
||||
if (tselem->type == 0 && te->idcode == ID_OB) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void outliner_draw_hierarchy_lines_recursive(uint pos,
|
||||
SpaceOutliner *space_outliner,
|
||||
ListBase *lb,
|
||||
@@ -3198,100 +3335,50 @@ static void outliner_draw_hierarchy_lines_recursive(uint pos,
|
||||
bool draw_grayed_out,
|
||||
int *starty)
|
||||
{
|
||||
TreeElement *te, *te_vertical_line_last = NULL, *te_vertical_line_last_dashed = NULL;
|
||||
int y1, y2, y1_dashed, y2_dashed;
|
||||
bTheme *btheme = UI_GetTheme();
|
||||
int y = *starty;
|
||||
short color = 0;
|
||||
|
||||
if (BLI_listbase_is_empty(lb)) {
|
||||
return;
|
||||
}
|
||||
/* Small vertical padding */
|
||||
const short line_padding = UI_UNIT_Y / 4.0f;
|
||||
|
||||
struct {
|
||||
int steps_num;
|
||||
int step_len;
|
||||
int gap_len;
|
||||
} dash = {
|
||||
.steps_num = 4,
|
||||
};
|
||||
|
||||
dash.step_len = UI_UNIT_X / dash.steps_num;
|
||||
dash.gap_len = dash.step_len / 2;
|
||||
|
||||
const uchar grayed_alpha = col[3] / 2;
|
||||
|
||||
/* For vertical lines between objects. */
|
||||
y1 = y2 = y1_dashed = y2_dashed = *starty;
|
||||
for (te = lb->first; te; te = te->next) {
|
||||
bool draw_children_grayed_out = draw_grayed_out || (te->flag & TE_DRAGGING);
|
||||
/* Draw vertical lines between collections */
|
||||
bool draw_hierarchy_line;
|
||||
LISTBASE_FOREACH (TreeElement *, te, lb) {
|
||||
TreeStoreElem *tselem = TREESTORE(te);
|
||||
|
||||
if (draw_children_grayed_out) {
|
||||
immUniformColor3ubvAlpha(col, grayed_alpha);
|
||||
}
|
||||
else {
|
||||
immUniformColor4ubv(col);
|
||||
}
|
||||
|
||||
if ((te->flag & TE_CHILD_NOT_IN_COLLECTION) == 0) {
|
||||
/* Horizontal Line? */
|
||||
if (tselem->type == 0 && (te->idcode == ID_OB || te->idcode == ID_SCE)) {
|
||||
immRecti(pos, startx, *starty, startx + UI_UNIT_X, *starty - U.pixelsize);
|
||||
|
||||
/* Vertical Line? */
|
||||
if (te->idcode == ID_OB) {
|
||||
te_vertical_line_last = te;
|
||||
y2 = *starty;
|
||||
}
|
||||
y1_dashed = *starty - UI_UNIT_Y;
|
||||
}
|
||||
}
|
||||
else {
|
||||
BLI_assert(te->idcode == ID_OB);
|
||||
/* Horizontal line - dashed. */
|
||||
int start = startx;
|
||||
for (int i = 0; i < dash.steps_num; i++) {
|
||||
immRecti(pos, start, *starty, start + dash.step_len - dash.gap_len, *starty - U.pixelsize);
|
||||
start += dash.step_len;
|
||||
}
|
||||
|
||||
te_vertical_line_last_dashed = te;
|
||||
y2_dashed = *starty;
|
||||
}
|
||||
|
||||
draw_hierarchy_line = false;
|
||||
*starty -= UI_UNIT_Y;
|
||||
|
||||
if (TSELEM_OPEN(tselem, space_outliner)) {
|
||||
outliner_draw_hierarchy_lines_recursive(pos,
|
||||
space_outliner,
|
||||
&te->subtree,
|
||||
startx + UI_UNIT_X,
|
||||
col,
|
||||
draw_children_grayed_out,
|
||||
starty);
|
||||
/* Only draw hierarchy lines for open collections. */
|
||||
if (TSELEM_OPEN(tselem, space_outliner) && !BLI_listbase_is_empty(&te->subtree)) {
|
||||
if (tselem->type == TSE_LAYER_COLLECTION) {
|
||||
draw_hierarchy_line = true;
|
||||
|
||||
Collection *collection = outliner_collection_from_tree_element(te);
|
||||
color = collection->color;
|
||||
|
||||
y = *starty;
|
||||
}
|
||||
else if (tselem->type == 0 && te->idcode == ID_OB) {
|
||||
if (subtree_contains_object(&te->subtree)) {
|
||||
draw_hierarchy_line = true;
|
||||
y = *starty;
|
||||
}
|
||||
}
|
||||
|
||||
outliner_draw_hierarchy_lines_recursive(
|
||||
pos, space_outliner, &te->subtree, startx + UI_UNIT_X, col, draw_grayed_out, starty);
|
||||
}
|
||||
}
|
||||
|
||||
if (draw_grayed_out) {
|
||||
immUniformColor3ubvAlpha(col, grayed_alpha);
|
||||
}
|
||||
else {
|
||||
immUniformColor4ubv(col);
|
||||
}
|
||||
if (draw_hierarchy_line) {
|
||||
if (color != COLLECTION_COLOR_NONE) {
|
||||
immUniformColor4ubv(btheme->collection_color[color - 1].color);
|
||||
}
|
||||
else {
|
||||
immUniformColor4ubv(col);
|
||||
}
|
||||
|
||||
/* Vertical line. */
|
||||
te = te_vertical_line_last;
|
||||
if ((te != NULL) && (te->parent || lb->first != lb->last)) {
|
||||
immRecti(pos, startx, y1 + UI_UNIT_Y, startx + U.pixelsize, y2);
|
||||
}
|
||||
|
||||
/* Children that are not in the collection are always in the end of the subtree.
|
||||
* This way we can draw their own dashed vertical lines. */
|
||||
te = te_vertical_line_last_dashed;
|
||||
if ((te != NULL) && (te->parent || lb->first != lb->last)) {
|
||||
const int steps_num = ((y1_dashed + UI_UNIT_Y) - y2_dashed) / dash.step_len;
|
||||
int start = y1_dashed + UI_UNIT_Y;
|
||||
for (int i = 0; i < steps_num; i++) {
|
||||
immRecti(pos, startx, start, startx + U.pixelsize, start - dash.step_len + dash.gap_len);
|
||||
start -= dash.step_len;
|
||||
immRecti(pos, startx, y - line_padding, startx + (U.pixelsize * 1), *starty + line_padding);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3356,8 +3443,20 @@ static void outliner_draw_struct_marks(ARegion *region,
|
||||
}
|
||||
}
|
||||
|
||||
static void outliner_draw_highlights_recursive(uint pos,
|
||||
const ARegion *region,
|
||||
static void draw_line_highlight(int x, int y, int maxx, int maxy, const float color[4])
|
||||
{
|
||||
const float pad = U.pixelsize;
|
||||
UI_draw_roundbox_corner_set(UI_CNR_ALL);
|
||||
UI_draw_roundbox_aa(true,
|
||||
(float)x + pad,
|
||||
(float)y + pad,
|
||||
(float)maxx - (pad * 2), /* Extra offset needed on right. */
|
||||
(float)maxy - pad,
|
||||
5.0f,
|
||||
color);
|
||||
}
|
||||
|
||||
static void outliner_draw_highlights_recursive(const ARegion *region,
|
||||
const SpaceOutliner *space_outliner,
|
||||
const ListBase *lb,
|
||||
const float col_selection[4],
|
||||
@@ -3374,20 +3473,19 @@ static void outliner_draw_highlights_recursive(uint pos,
|
||||
LISTBASE_FOREACH (TreeElement *, te, lb) {
|
||||
const TreeStoreElem *tselem = TREESTORE(te);
|
||||
const int start_y = *io_start_y;
|
||||
const int end_x = (int)region->v2d.cur.xmax;
|
||||
|
||||
/* selection status */
|
||||
if ((tselem->flag & TSE_ACTIVE) && (tselem->flag & TSE_SELECTED)) {
|
||||
immUniformColor4fv(col_active);
|
||||
immRecti(pos, 0, start_y, (int)region->v2d.cur.xmax, start_y + UI_UNIT_Y);
|
||||
draw_line_highlight(0, start_y, (int)region->v2d.cur.xmax, start_y + UI_UNIT_Y, col_active);
|
||||
}
|
||||
else if (tselem->flag & TSE_SELECTED) {
|
||||
immUniformColor4fv(col_selection);
|
||||
immRecti(pos, 0, start_y, (int)region->v2d.cur.xmax, start_y + UI_UNIT_Y);
|
||||
draw_line_highlight(
|
||||
0, start_y, (int)region->v2d.cur.xmax, start_y + UI_UNIT_Y, col_selection);
|
||||
}
|
||||
|
||||
/* highlights */
|
||||
if (tselem->flag & (TSE_DRAG_ANY | TSE_HIGHLIGHTED | TSE_SEARCHMATCH)) {
|
||||
const int end_x = (int)region->v2d.cur.xmax;
|
||||
|
||||
if (tselem->flag & TSE_DRAG_ANY) {
|
||||
/* drag and drop highlight */
|
||||
@@ -3395,20 +3493,18 @@ static void outliner_draw_highlights_recursive(uint pos,
|
||||
UI_GetThemeColorShade4fv(TH_BACK, -40, col);
|
||||
|
||||
if (tselem->flag & TSE_DRAG_BEFORE) {
|
||||
immUniformColor4fv(col);
|
||||
immRecti(pos,
|
||||
start_x,
|
||||
start_y + UI_UNIT_Y - U.pixelsize,
|
||||
end_x,
|
||||
start_y + UI_UNIT_Y + U.pixelsize);
|
||||
draw_line_highlight(start_x,
|
||||
start_y + UI_UNIT_Y - (U.pixelsize * 2),
|
||||
end_x,
|
||||
start_y + UI_UNIT_Y + (U.pixelsize * 2),
|
||||
col);
|
||||
}
|
||||
else if (tselem->flag & TSE_DRAG_AFTER) {
|
||||
immUniformColor4fv(col);
|
||||
immRecti(pos, start_x, start_y - U.pixelsize, end_x, start_y + U.pixelsize);
|
||||
draw_line_highlight(
|
||||
start_x, start_y - (U.pixelsize * 2), end_x, start_y + (U.pixelsize * 2), col);
|
||||
}
|
||||
else {
|
||||
immUniformColor3fvAlpha(col, col[3] * 0.5f);
|
||||
immRecti(pos, start_x, start_y, end_x, start_y + UI_UNIT_Y);
|
||||
draw_line_highlight(start_x, start_y, end_x, start_y + UI_UNIT_Y, col);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -3416,21 +3512,18 @@ static void outliner_draw_highlights_recursive(uint pos,
|
||||
/* search match highlights
|
||||
* we don't expand items when searching in the data-blocks but we
|
||||
* still want to highlight any filter matches. */
|
||||
immUniformColor4fv(col_searchmatch);
|
||||
immRecti(pos, start_x, start_y, end_x, start_y + UI_UNIT_Y);
|
||||
draw_line_highlight(start_x, start_y, end_x, start_y + UI_UNIT_Y, col_searchmatch);
|
||||
}
|
||||
else if (tselem->flag & TSE_HIGHLIGHTED) {
|
||||
/* mouse hover highlight */
|
||||
immUniformColor4fv(col_highlight);
|
||||
immRecti(pos, 0, start_y, end_x, start_y + UI_UNIT_Y);
|
||||
draw_line_highlight(0, start_y, end_x, start_y + UI_UNIT_Y, col_highlight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*io_start_y -= UI_UNIT_Y;
|
||||
if (TSELEM_OPEN(tselem, space_outliner)) {
|
||||
outliner_draw_highlights_recursive(pos,
|
||||
region,
|
||||
outliner_draw_highlights_recursive(region,
|
||||
space_outliner,
|
||||
&te->subtree,
|
||||
col_selection,
|
||||
@@ -3440,6 +3533,10 @@ static void outliner_draw_highlights_recursive(uint pos,
|
||||
start_x + UI_UNIT_X,
|
||||
io_start_y);
|
||||
}
|
||||
else if (outliner_find_element_with_flag(&te->subtree, TSE_ACTIVE)) {
|
||||
/* Parent highlight for active element in collapsed subtree. */
|
||||
draw_line_highlight(0, start_y, end_x, start_y + UI_UNIT_Y, col_highlight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3451,19 +3548,12 @@ static void outliner_draw_highlights(ARegion *region,
|
||||
const float col_highlight[4] = {1.0f, 1.0f, 1.0f, 0.13f};
|
||||
float col_selection[4], col_active[4], col_searchmatch[4];
|
||||
|
||||
UI_GetThemeColor3fv(TH_SELECT_HIGHLIGHT, col_selection);
|
||||
col_selection[3] = 1.0f; /* no alpha */
|
||||
UI_GetThemeColor3fv(TH_SELECT_ACTIVE, col_active);
|
||||
col_active[3] = 1.0f; /* no alpha */
|
||||
UI_GetThemeColor4fv(TH_SELECT_HIGHLIGHT, col_selection);
|
||||
UI_GetThemeColor4fv(TH_SELECT_ACTIVE, col_active);
|
||||
UI_GetThemeColor4fv(TH_MATCH, col_searchmatch);
|
||||
col_searchmatch[3] = 0.5f;
|
||||
|
||||
GPU_blend(GPU_BLEND_ALPHA);
|
||||
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,
|
||||
region,
|
||||
outliner_draw_highlights_recursive(region,
|
||||
space_outliner,
|
||||
&space_outliner->tree,
|
||||
col_selection,
|
||||
@@ -3472,8 +3562,6 @@ static void outliner_draw_highlights(ARegion *region,
|
||||
col_searchmatch,
|
||||
startx,
|
||||
starty);
|
||||
immUnbindProgram();
|
||||
GPU_blend(GPU_BLEND_NONE);
|
||||
}
|
||||
|
||||
static void outliner_draw_tree(bContext *C,
|
||||
@@ -3482,11 +3570,20 @@ static void outliner_draw_tree(bContext *C,
|
||||
ARegion *region,
|
||||
SpaceOutliner *space_outliner,
|
||||
const float restrict_column_width,
|
||||
const bool use_mode_column,
|
||||
TreeElement **te_edit)
|
||||
{
|
||||
const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
|
||||
int starty, startx;
|
||||
|
||||
/* Move the tree a unit left in view layer mode */
|
||||
short mode_column_offset = (use_mode_column && (space_outliner->outlinevis == SO_SCENES)) ?
|
||||
UI_UNIT_X :
|
||||
0;
|
||||
if (!use_mode_column && (space_outliner->outlinevis == SO_VIEW_LAYER)) {
|
||||
mode_column_offset -= UI_UNIT_X;
|
||||
}
|
||||
|
||||
GPU_blend(GPU_BLEND_ALPHA); /* Only once. */
|
||||
|
||||
if (space_outliner->outlinevis == SO_DATA_API) {
|
||||
@@ -3511,13 +3608,13 @@ static void outliner_draw_tree(bContext *C,
|
||||
}
|
||||
|
||||
/* Gray hierarchy lines. */
|
||||
starty = (int)region->v2d.tot.ymax - UI_UNIT_Y / 2 - OL_Y_OFFSET;
|
||||
startx = UI_UNIT_X / 2 - (U.pixelsize + 1) / 2;
|
||||
starty = (int)region->v2d.tot.ymax - OL_Y_OFFSET;
|
||||
startx = mode_column_offset + UI_UNIT_X / 2 - (U.pixelsize + 1) / 2;
|
||||
outliner_draw_hierarchy_lines(space_outliner, &space_outliner->tree, startx, &starty);
|
||||
|
||||
/* Items themselves. */
|
||||
starty = (int)region->v2d.tot.ymax - UI_UNIT_Y - OL_Y_OFFSET;
|
||||
startx = 0;
|
||||
startx = mode_column_offset;
|
||||
LISTBASE_FOREACH (TreeElement *, te, &space_outliner->tree) {
|
||||
outliner_draw_tree_element(C,
|
||||
block,
|
||||
@@ -3640,12 +3737,22 @@ void draw_outliner(const bContext *C)
|
||||
/* set matrix for 2d-view controls */
|
||||
UI_view2d_view_ortho(v2d);
|
||||
|
||||
/* Only show mode column in View Layers and Scenes view */
|
||||
const bool use_mode_column = (space_outliner->flag & SO_MODE_COLUMN) &&
|
||||
(ELEM(space_outliner->outlinevis, SO_VIEW_LAYER, SO_SCENES));
|
||||
|
||||
/* draw outliner stuff (background, hierarchy lines and names) */
|
||||
const float restrict_column_width = outliner_restrict_columns_width(space_outliner);
|
||||
outliner_back(region);
|
||||
block = UI_block_begin(C, region, __func__, UI_EMBOSS);
|
||||
outliner_draw_tree(
|
||||
(bContext *)C, block, &tvc, region, space_outliner, restrict_column_width, &te_edit);
|
||||
outliner_draw_tree((bContext *)C,
|
||||
block,
|
||||
&tvc,
|
||||
region,
|
||||
space_outliner,
|
||||
restrict_column_width,
|
||||
use_mode_column,
|
||||
&te_edit);
|
||||
|
||||
/* Compute outliner dimensions after it has been drawn. */
|
||||
int tree_width, tree_height;
|
||||
@@ -3680,6 +3787,11 @@ void draw_outliner(const bContext *C)
|
||||
props_active);
|
||||
}
|
||||
|
||||
/* Draw mode icons */
|
||||
if (use_mode_column) {
|
||||
outliner_draw_mode_column(C, block, &tvc, space_outliner, &space_outliner->tree);
|
||||
}
|
||||
|
||||
UI_block_emboss_set(block, UI_EMBOSS);
|
||||
|
||||
/* Draw edit buttons if necessary. */
|
||||
|
@@ -284,61 +284,6 @@ void OUTLINER_OT_item_openclose(wmOperatorType *ot)
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Object Mode Enter/Exit Utilities
|
||||
* \{ */
|
||||
|
||||
static void item_object_mode_enter_exit(bContext *C, ReportList *reports, Object *ob, bool enter)
|
||||
{
|
||||
ViewLayer *view_layer = CTX_data_view_layer(C);
|
||||
Object *obact = OBACT(view_layer);
|
||||
|
||||
if ((ob->type != obact->type) || ID_IS_LINKED(ob->data)) {
|
||||
return;
|
||||
}
|
||||
if (((ob->mode & obact->mode) != 0) == enter) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ob == obact) {
|
||||
BKE_report(reports, RPT_WARNING, "Active object mode not changed");
|
||||
return;
|
||||
}
|
||||
|
||||
Base *base = BKE_view_layer_base_find(view_layer, ob);
|
||||
if (base == NULL) {
|
||||
return;
|
||||
}
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
outliner_object_mode_toggle(C, scene, view_layer, base);
|
||||
}
|
||||
|
||||
void item_object_mode_enter_fn(bContext *C,
|
||||
ReportList *reports,
|
||||
Scene *UNUSED(scene),
|
||||
TreeElement *UNUSED(te),
|
||||
TreeStoreElem *UNUSED(tsep),
|
||||
TreeStoreElem *tselem,
|
||||
void *UNUSED(user_data))
|
||||
{
|
||||
Object *ob = (Object *)tselem->id;
|
||||
item_object_mode_enter_exit(C, reports, ob, true);
|
||||
}
|
||||
|
||||
void item_object_mode_exit_fn(bContext *C,
|
||||
ReportList *reports,
|
||||
Scene *UNUSED(scene),
|
||||
TreeElement *UNUSED(te),
|
||||
TreeStoreElem *UNUSED(tsep),
|
||||
TreeStoreElem *tselem,
|
||||
void *UNUSED(user_data))
|
||||
{
|
||||
Object *ob = (Object *)tselem->id;
|
||||
item_object_mode_enter_exit(C, reports, ob, false);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Rename Operator
|
||||
* \{ */
|
||||
|
@@ -222,7 +222,6 @@ typedef enum TreeItemSelectAction {
|
||||
OL_ITEM_ACTIVATE = (1 << 2), /* Activate the item */
|
||||
OL_ITEM_EXTEND = (1 << 3), /* Extend the current selection */
|
||||
OL_ITEM_RECURSIVE = (1 << 4), /* Select recursively */
|
||||
OL_ITEM_TOGGLE_MODE = (1 << 5) /* Temporary */
|
||||
} TreeItemSelectAction;
|
||||
|
||||
/* outliner_tree.c ----------------------------------------------- */
|
||||
@@ -277,18 +276,18 @@ eOLDrawState tree_element_active(struct bContext *C,
|
||||
const eOLSetState set,
|
||||
const bool handle_all_types);
|
||||
|
||||
struct bPoseChannel *outliner_find_parent_bone(TreeElement *te, TreeElement **r_bone_te);
|
||||
|
||||
void outliner_item_select(struct bContext *C,
|
||||
struct SpaceOutliner *space_outliner,
|
||||
struct TreeElement *te,
|
||||
const short select_flag);
|
||||
|
||||
void outliner_object_mode_toggle(struct bContext *C,
|
||||
Scene *scene,
|
||||
ViewLayer *view_layer,
|
||||
Base *base);
|
||||
|
||||
bool outliner_item_is_co_over_name_icons(const TreeElement *te, float view_co_x);
|
||||
bool outliner_item_is_co_within_close_toggle(const TreeElement *te, float view_co_x);
|
||||
bool outliner_is_co_within_mode_column(SpaceOutliner *space_outliner, const float view_mval[2]);
|
||||
|
||||
void outliner_item_mode_toggle(struct bContext *C, TreeViewContext *tvc, TreeElement *te);
|
||||
|
||||
/* outliner_edit.c ---------------------------------------------- */
|
||||
typedef void (*outliner_operation_fn)(struct bContext *C,
|
||||
@@ -384,6 +383,7 @@ 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_uistack_drop(struct wmOperatorType *ot);
|
||||
void OUTLINER_OT_collection_drop(struct wmOperatorType *ot);
|
||||
|
||||
/* ...................................................... */
|
||||
@@ -482,6 +482,8 @@ void OUTLINER_OT_collection_disable_render(struct wmOperatorType *ot);
|
||||
void OUTLINER_OT_hide(struct wmOperatorType *ot);
|
||||
void OUTLINER_OT_unhide_all(struct wmOperatorType *ot);
|
||||
|
||||
void OUTLINER_OT_collection_color_tag_set(struct wmOperatorType *ot);
|
||||
|
||||
/* outliner_utils.c ---------------------------------------------- */
|
||||
|
||||
void outliner_viewcontext_init(const struct bContext *C, TreeViewContext *tvc);
|
||||
|
@@ -88,6 +88,7 @@ void outliner_operatortypes(void)
|
||||
WM_operatortype_append(OUTLINER_OT_parent_clear);
|
||||
WM_operatortype_append(OUTLINER_OT_scene_drop);
|
||||
WM_operatortype_append(OUTLINER_OT_material_drop);
|
||||
WM_operatortype_append(OUTLINER_OT_uistack_drop);
|
||||
WM_operatortype_append(OUTLINER_OT_collection_drop);
|
||||
|
||||
/* collections */
|
||||
@@ -117,6 +118,8 @@ void outliner_operatortypes(void)
|
||||
WM_operatortype_append(OUTLINER_OT_collection_show_inside);
|
||||
WM_operatortype_append(OUTLINER_OT_hide);
|
||||
WM_operatortype_append(OUTLINER_OT_unhide_all);
|
||||
|
||||
WM_operatortype_append(OUTLINER_OT_collection_color_tag_set);
|
||||
}
|
||||
|
||||
void outliner_keymap(wmKeyConfig *keyconf)
|
||||
|
@@ -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"
|
||||
@@ -46,6 +50,7 @@
|
||||
#include "BKE_main.h"
|
||||
#include "BKE_object.h"
|
||||
#include "BKE_paint.h"
|
||||
#include "BKE_particle.h"
|
||||
#include "BKE_scene.h"
|
||||
#include "BKE_sequencer.h"
|
||||
#include "BKE_workspace.h"
|
||||
@@ -54,6 +59,7 @@
|
||||
#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"
|
||||
@@ -73,183 +79,137 @@
|
||||
|
||||
#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)
|
||||
/**
|
||||
* Find a new active object to keep the other objects in the mode.
|
||||
*
|
||||
* Identify other objects in the tree that are also in the interaction mode
|
||||
* and set the next (circular) as the active object. If none are found, then
|
||||
* the mode should be exited.
|
||||
*/
|
||||
static bool outliner_set_new_active(bContext *C, ListBase *tree, Object *ob, int mode)
|
||||
{
|
||||
bool use_all = false;
|
||||
ViewLayer *view_layer = CTX_data_view_layer(C);
|
||||
|
||||
if (do_exit) {
|
||||
FOREACH_OBJECT_BEGIN (view_layer, ob_iter) {
|
||||
ED_object_mode_generic_exit(bmain, depsgraph, scene, ob_iter);
|
||||
LISTBASE_FOREACH (TreeElement *, te, tree) {
|
||||
TreeStoreElem *tselem = TREESTORE(te);
|
||||
if (tselem->type == 0 && te->idcode == ID_OB) {
|
||||
Object *ob_te = (Object *)tselem->id;
|
||||
|
||||
/* If an object is found in the mode and not the current element. */
|
||||
if (ob_te->mode == mode && ob_te != ob) {
|
||||
Base *base = BKE_view_layer_base_find(view_layer, ob_te);
|
||||
ED_object_base_activate(C, base);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (outliner_set_new_active(C, &te->subtree, ob, mode)) {
|
||||
return true;
|
||||
}
|
||||
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);
|
||||
|
||||
if (extend) {
|
||||
use_all = true;
|
||||
}
|
||||
else {
|
||||
ED_object_base_deselect_all(view_layer, NULL, SEL_DESELECT);
|
||||
}
|
||||
|
||||
return use_all;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bring the newly selected object into edit mode.
|
||||
* Bring the newly selected object into edit mode and activate it.
|
||||
*
|
||||
* 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.
|
||||
* 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_editmode_toggle(bContext *C, Scene *scene, 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;
|
||||
bool ok = 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;
|
||||
}
|
||||
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 (BKE_object_is_in_editmode(ob)) {
|
||||
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
|
||||
outliner_set_new_active(C, &space_outliner->tree, ob, ob->mode);
|
||||
|
||||
if (use_all) {
|
||||
WM_operator_name_call(C, "OBJECT_OT_editmode_toggle", WM_OP_INVOKE_REGION_WIN, NULL);
|
||||
ok = ED_object_editmode_exit_ex(bmain, scene, ob, EM_FREEDATA);
|
||||
}
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
static void do_outliner_item_posemode_toggle(
|
||||
bContext *C, Scene *scene, ViewLayer *view_layer, Base *base, const bool extend)
|
||||
static void do_outliner_item_posemode_toggle(bContext *C, Scene *scene, 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;
|
||||
}
|
||||
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 ((!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);
|
||||
}
|
||||
bool ok = false;
|
||||
if (ob->mode & OB_MODE_POSE) {
|
||||
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
|
||||
outliner_set_new_active(C, &space_outliner->tree, ob, ob->mode);
|
||||
|
||||
if (use_all) {
|
||||
WM_operator_name_call(C, "OBJECT_OT_posemode_toggle", WM_OP_INVOKE_REGION_WIN, NULL);
|
||||
ok = ED_object_posemode_exit_ex(bmain, ob);
|
||||
}
|
||||
else {
|
||||
bool ok = false;
|
||||
if (ob->mode & OB_MODE_POSE) {
|
||||
ok = ED_object_posemode_exit_ex(bmain, ob);
|
||||
}
|
||||
else {
|
||||
ok = ED_object_posemode_enter_ex(bmain, ob);
|
||||
}
|
||||
if (ok) {
|
||||
ED_object_base_select(base, (ob->mode & OB_MODE_POSE) ? BA_SELECT : BA_DESELECT);
|
||||
|
||||
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);
|
||||
}
|
||||
ok = ED_object_posemode_enter_ex(bmain, ob);
|
||||
ED_object_base_activate(C, base);
|
||||
}
|
||||
if (ok) {
|
||||
ED_object_base_select(base, (ob->mode & OB_MODE_POSE) ? BA_SELECT : BA_DESELECT);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/* For draw callback to run mode switching */
|
||||
void outliner_object_mode_toggle(bContext *C, Scene *scene, ViewLayer *view_layer, Base *base)
|
||||
/* Toggle interaction mode for modes that do not allow multi-object editing */
|
||||
static void do_outliner_item_mode_toggle_generic(bContext *C, TreeViewContext *tvc, Base *base)
|
||||
{
|
||||
Object *obact = OBACT(view_layer);
|
||||
if (obact->mode & OB_MODE_EDIT) {
|
||||
do_outliner_item_editmode_toggle(C, scene, view_layer, base, true);
|
||||
Main *bmain = CTX_data_main(C);
|
||||
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
||||
const int active_mode = tvc->obact->mode;
|
||||
|
||||
/* Remove the active object from the mode */
|
||||
if (tvc->scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) {
|
||||
ED_object_mode_generic_exit(bmain, depsgraph, tvc->scene, tvc->obact);
|
||||
}
|
||||
else if (obact->mode & OB_MODE_POSE) {
|
||||
do_outliner_item_posemode_toggle(C, scene, view_layer, base, true);
|
||||
|
||||
Base *base_old = BKE_view_layer_base_find(tvc->view_layer, tvc->obact);
|
||||
if (base_old) {
|
||||
ED_object_base_select(base_old, BA_DESELECT);
|
||||
}
|
||||
ED_object_base_activate(C, base);
|
||||
ED_object_base_select(base, BA_SELECT);
|
||||
ED_object_mode_set(C, active_mode);
|
||||
|
||||
ED_outliner_select_sync_from_object_tag(C);
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
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);
|
||||
|
||||
if (!base || !(base->flag & BASE_VISIBLE_DEPSGRAPH)) {
|
||||
return;
|
||||
}
|
||||
|
||||
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, tvc->scene, base);
|
||||
}
|
||||
else {
|
||||
do_outliner_item_mode_toggle_generic(C, tvc, base);
|
||||
}
|
||||
|
||||
ED_outliner_select_sync_from_object_tag(C);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -499,7 +459,7 @@ static eOLDrawState tree_element_active_material(bContext *C,
|
||||
return OL_DRAWSEL_NONE;
|
||||
}
|
||||
|
||||
static eOLDrawState tree_element_active_camera(bContext *C,
|
||||
static eOLDrawState tree_element_active_camera(bContext *UNUSED(C),
|
||||
Scene *scene,
|
||||
ViewLayer *UNUSED(view_layer),
|
||||
TreeElement *te,
|
||||
@@ -508,16 +468,6 @@ static eOLDrawState tree_element_active_camera(bContext *C,
|
||||
Object *ob = (Object *)outliner_search_back(te, ID_OB);
|
||||
|
||||
if (set != OL_SETSEL_NONE) {
|
||||
scene->camera = ob;
|
||||
|
||||
Main *bmain = CTX_data_main(C);
|
||||
wmWindowManager *wm = bmain->wm.first;
|
||||
|
||||
WM_windows_scene_data_sync(&wm->windows, scene);
|
||||
DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
|
||||
DEG_relations_tag_update(bmain);
|
||||
WM_event_add_notifier(C, NC_SCENE | NA_EDITED, NULL);
|
||||
|
||||
return OL_DRAWSEL_NONE;
|
||||
}
|
||||
return scene->camera == ob;
|
||||
@@ -858,15 +808,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);
|
||||
}
|
||||
|
||||
@@ -1094,6 +1055,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:
|
||||
@@ -1117,6 +1079,188 @@ 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;
|
||||
|
||||
/* ID Types */
|
||||
if (tselem->type == 0) {
|
||||
RNA_id_pointer_create(tselem->id, &ptr);
|
||||
|
||||
switch (te->idcode) {
|
||||
case ID_SCE:
|
||||
ED_buttons_set_context(C, &ptr, BCONTEXT_SCENE);
|
||||
break;
|
||||
case ID_OB:
|
||||
ED_buttons_set_context(C, &ptr, 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:
|
||||
ED_buttons_set_context(C, &ptr, BCONTEXT_DATA);
|
||||
break;
|
||||
case ID_MA:
|
||||
ED_buttons_set_context(C, &ptr, BCONTEXT_MATERIAL);
|
||||
break;
|
||||
case ID_WO:
|
||||
ED_buttons_set_context(C, &ptr, BCONTEXT_WORLD);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
switch (tselem->type) {
|
||||
case TSE_DEFGROUP_BASE:
|
||||
case TSE_DEFGROUP:
|
||||
RNA_id_pointer_create(tselem->id, &ptr);
|
||||
ED_buttons_set_context(C, &ptr, 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);
|
||||
ED_buttons_set_context(C, &ptr, BCONTEXT_BONE_CONSTRAINT);
|
||||
}
|
||||
else {
|
||||
RNA_id_pointer_create(tselem->id, &ptr);
|
||||
ED_buttons_set_context(C, &ptr, BCONTEXT_CONSTRAINT);
|
||||
}
|
||||
|
||||
/* Expand the selected constraint in the properties editor. */
|
||||
if (tselem->type != TSE_CONSTRAINT_BASE) {
|
||||
bConstraint *con = te->directdata;
|
||||
con->ui_expand_flag |= (1 << 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TSE_MODIFIER_BASE:
|
||||
case TSE_MODIFIER:
|
||||
RNA_id_pointer_create(tselem->id, &ptr);
|
||||
ED_buttons_set_context(C, &ptr, BCONTEXT_MODIFIER);
|
||||
|
||||
if (tselem->type != TSE_MODIFIER_BASE) {
|
||||
Object *ob = (Object *)tselem->id;
|
||||
|
||||
if (ob->type == OB_GPENCIL) {
|
||||
GpencilModifierData *md = te->directdata;
|
||||
md->ui_expand_flag |= (1 << 0);
|
||||
}
|
||||
else {
|
||||
ModifierData *md = te->directdata;
|
||||
md->ui_expand_flag |= (1 << 0);
|
||||
}
|
||||
}
|
||||
|
||||
// PropertyRNA *prop = RNA_struct_type_find_property(&RNA_Modifier, "show_expanded");
|
||||
// RNA_property_boolean_set(&ptr, prop, true);
|
||||
break;
|
||||
case TSE_EFFECT_BASE:
|
||||
case TSE_EFFECT:
|
||||
RNA_id_pointer_create(tselem->id, &ptr);
|
||||
ED_buttons_set_context(C, &ptr, BCONTEXT_SHADERFX);
|
||||
|
||||
if (tselem->type != TSE_EFFECT_BASE) {
|
||||
ShaderFxData *sfx = te->directdata;
|
||||
sfx->ui_expand_flag |= (1 << 0);
|
||||
}
|
||||
break;
|
||||
case TSE_BONE: {
|
||||
bArmature *arm = (bArmature *)tselem->id;
|
||||
Bone *bone = te->directdata;
|
||||
|
||||
RNA_pointer_create(&arm->id, &RNA_Bone, bone, &ptr);
|
||||
ED_buttons_set_context(C, &ptr, BCONTEXT_BONE);
|
||||
break;
|
||||
}
|
||||
case TSE_EBONE: {
|
||||
bArmature *arm = (bArmature *)tselem->id;
|
||||
EditBone *ebone = te->directdata;
|
||||
|
||||
RNA_pointer_create(&arm->id, &RNA_EditBone, ebone, &ptr);
|
||||
ED_buttons_set_context(C, &ptr, 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);
|
||||
ED_buttons_set_context(C, &ptr, 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);
|
||||
ED_buttons_set_context(C, &ptr, 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);
|
||||
ED_buttons_set_context(C, &ptr, 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);
|
||||
ED_buttons_set_context(C, &ptr, 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);
|
||||
ED_buttons_set_context(C, &ptr, BCONTEXT_PARTICLE);
|
||||
break;
|
||||
}
|
||||
case TSE_GP_LAYER:
|
||||
RNA_id_pointer_create(tselem->id, &ptr);
|
||||
ED_buttons_set_context(C, &ptr, BCONTEXT_DATA);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================ */
|
||||
|
||||
/**
|
||||
@@ -1141,14 +1285,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,
|
||||
@@ -1165,11 +1303,6 @@ static void do_outliner_item_activate_tree_element(bContext *C,
|
||||
if (do_activate_data == false) {
|
||||
/* Only select in outliner. */
|
||||
}
|
||||
else if (te->idcode == ID_SCE) {
|
||||
if (tvc->scene != (Scene *)tselem->id) {
|
||||
WM_window_set_active_scene(CTX_data_main(C), C, CTX_wm_window(C), (Scene *)tselem->id);
|
||||
}
|
||||
}
|
||||
else if ((te->idcode == ID_GR) && (space_outliner->outlinevis != SO_VIEW_LAYER)) {
|
||||
Collection *gr = (Collection *)tselem->id;
|
||||
|
||||
@@ -1223,6 +1356,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 */
|
||||
@@ -1236,7 +1371,8 @@ void outliner_item_select(bContext *C,
|
||||
const bool extend = select_flag & OL_ITEM_EXTEND;
|
||||
const bool activate_data = select_flag & OL_ITEM_SELECT_DATA;
|
||||
|
||||
/* Clear previous active when activating and clear selection when not extending selection */
|
||||
/* Clear previous active when activating and clear selection when not extending selection
|
||||
*/
|
||||
const short clear_flag = (activate ? TSE_ACTIVE : 0) | (extend ? 0 : TSE_SELECTED);
|
||||
if (clear_flag) {
|
||||
outliner_flag_set(&space_outliner->tree, clear_flag, false);
|
||||
@@ -1262,11 +1398,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1327,7 +1458,8 @@ static void do_outliner_range_select(bContext *C,
|
||||
return;
|
||||
}
|
||||
|
||||
/* If active is not selected or visible, select and activate the element under the cursor */
|
||||
/* If active is not selected or visible, select and activate the element under the cursor
|
||||
*/
|
||||
if (!active_selected || !outliner_is_element_visible(active)) {
|
||||
outliner_item_select(C, space_outliner, cursor, OL_ITEM_SELECT | OL_ITEM_ACTIVATE);
|
||||
return;
|
||||
@@ -1343,6 +1475,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,
|
||||
*
|
||||
@@ -1365,6 +1507,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) {
|
||||
@@ -1378,7 +1523,8 @@ static int outliner_item_do_activate_from_cursor(bContext *C,
|
||||
return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
|
||||
}
|
||||
else {
|
||||
/* The row may also contain children, if one is hovered we want this instead of current te. */
|
||||
/* The row may also contain children, if one is hovered we want this instead of current
|
||||
* te. */
|
||||
bool merged_elements = false;
|
||||
TreeElement *activate_te = outliner_find_item_at_x_in_row(
|
||||
space_outliner, te, view_mval[0], &merged_elements);
|
||||
@@ -1403,7 +1549,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);
|
||||
}
|
||||
@@ -1532,6 +1678,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);
|
||||
}
|
||||
|
||||
@@ -1630,6 +1780,40 @@ static TreeElement *outliner_find_next_element(SpaceOutliner *space_outliner, Tr
|
||||
return te;
|
||||
}
|
||||
|
||||
static TreeElement *outliner_walk_left(SpaceOutliner *space_outliner,
|
||||
TreeElement *te,
|
||||
bool toggle_all)
|
||||
{
|
||||
TreeStoreElem *tselem = TREESTORE(te);
|
||||
|
||||
if (TSELEM_OPEN(tselem, space_outliner)) {
|
||||
outliner_item_openclose(te, false, toggle_all);
|
||||
}
|
||||
/* Only walk up a level if the element is closed and not toggling expand */
|
||||
else if (!toggle_all && te->parent) {
|
||||
te = te->parent;
|
||||
}
|
||||
|
||||
return te;
|
||||
}
|
||||
|
||||
static TreeElement *outliner_walk_right(SpaceOutliner *space_outliner,
|
||||
TreeElement *te,
|
||||
bool toggle_all)
|
||||
{
|
||||
TreeStoreElem *tselem = TREESTORE(te);
|
||||
|
||||
/* Only walk down a level if the element is open and not toggling expand */
|
||||
if (!toggle_all && TSELEM_OPEN(tselem, space_outliner) && te->subtree.first) {
|
||||
te = te->subtree.first;
|
||||
}
|
||||
else {
|
||||
outliner_item_openclose(te, true, toggle_all);
|
||||
}
|
||||
|
||||
return te;
|
||||
}
|
||||
|
||||
static TreeElement *do_outliner_select_walk(SpaceOutliner *space_outliner,
|
||||
TreeElement *te,
|
||||
const int direction,
|
||||
@@ -1646,10 +1830,10 @@ static TreeElement *do_outliner_select_walk(SpaceOutliner *space_outliner,
|
||||
te = outliner_find_next_element(space_outliner, te);
|
||||
break;
|
||||
case UI_SELECT_WALK_LEFT:
|
||||
outliner_item_openclose(te, false, toggle_all);
|
||||
te = outliner_walk_left(space_outliner, te, toggle_all);
|
||||
break;
|
||||
case UI_SELECT_WALK_RIGHT:
|
||||
outliner_item_openclose(te, true, toggle_all);
|
||||
te = outliner_walk_right(space_outliner, te, toggle_all);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@@ -95,110 +95,105 @@
|
||||
/** \name ID/Library/Data Set/Un-link Utilities
|
||||
* \{ */
|
||||
|
||||
static void set_operation_types(SpaceOutliner *space_outliner,
|
||||
ListBase *lb,
|
||||
int *scenelevel,
|
||||
int *objectlevel,
|
||||
int *idlevel,
|
||||
int *datalevel)
|
||||
static void get_element_operation_type(
|
||||
TreeElement *te, int *scenelevel, int *objectlevel, int *idlevel, int *datalevel)
|
||||
{
|
||||
TreeElement *te;
|
||||
TreeStoreElem *tselem;
|
||||
|
||||
for (te = lb->first; te; te = te->next) {
|
||||
tselem = TREESTORE(te);
|
||||
if (tselem->flag & TSE_SELECTED) {
|
||||
/* Layer collection points to collection ID. */
|
||||
if (!ELEM(tselem->type, 0, TSE_LAYER_COLLECTION)) {
|
||||
if (*datalevel == 0) {
|
||||
*datalevel = tselem->type;
|
||||
}
|
||||
else if (*datalevel != tselem->type) {
|
||||
*datalevel = -1;
|
||||
}
|
||||
TreeStoreElem *tselem = TREESTORE(te);
|
||||
if (tselem->flag & TSE_SELECTED) {
|
||||
/* Layer collection points to collection ID. */
|
||||
if (!ELEM(tselem->type, 0, TSE_LAYER_COLLECTION)) {
|
||||
if (*datalevel == 0) {
|
||||
*datalevel = tselem->type;
|
||||
}
|
||||
else {
|
||||
const int idcode = (int)GS(tselem->id->name);
|
||||
bool is_standard_id = false;
|
||||
switch ((ID_Type)idcode) {
|
||||
case ID_SCE:
|
||||
*scenelevel = 1;
|
||||
break;
|
||||
case ID_OB:
|
||||
*objectlevel = 1;
|
||||
break;
|
||||
|
||||
case ID_ME:
|
||||
case ID_CU:
|
||||
case ID_MB:
|
||||
case ID_LT:
|
||||
case ID_LA:
|
||||
case ID_AR:
|
||||
case ID_CA:
|
||||
case ID_SPK:
|
||||
case ID_MA:
|
||||
case ID_TE:
|
||||
case ID_IP:
|
||||
case ID_IM:
|
||||
case ID_SO:
|
||||
case ID_KE:
|
||||
case ID_WO:
|
||||
case ID_AC:
|
||||
case ID_TXT:
|
||||
case ID_GR:
|
||||
case ID_LS:
|
||||
case ID_LI:
|
||||
case ID_VF:
|
||||
case ID_NT:
|
||||
case ID_BR:
|
||||
case ID_PA:
|
||||
case ID_GD:
|
||||
case ID_MC:
|
||||
case ID_MSK:
|
||||
case ID_PAL:
|
||||
case ID_PC:
|
||||
case ID_CF:
|
||||
case ID_WS:
|
||||
case ID_LP:
|
||||
case ID_HA:
|
||||
case ID_PT:
|
||||
case ID_VO:
|
||||
case ID_SIM:
|
||||
is_standard_id = true;
|
||||
break;
|
||||
case ID_WM:
|
||||
case ID_SCR:
|
||||
/* Those are ignored here. */
|
||||
/* Note: while Screens should be manageable here, deleting a screen used by a workspace
|
||||
* will cause crashes when trying to use that workspace, so for now let's play minimal,
|
||||
* safe change. */
|
||||
break;
|
||||
}
|
||||
if (idcode == ID_NLA) {
|
||||
/* Fake one, not an actual ID type... */
|
||||
is_standard_id = true;
|
||||
}
|
||||
|
||||
if (is_standard_id) {
|
||||
if (*idlevel == 0) {
|
||||
*idlevel = idcode;
|
||||
}
|
||||
else if (*idlevel != idcode) {
|
||||
*idlevel = -1;
|
||||
}
|
||||
if (ELEM(*datalevel, TSE_VIEW_COLLECTION_BASE, TSE_SCENE_COLLECTION_BASE)) {
|
||||
*datalevel = 0;
|
||||
}
|
||||
}
|
||||
else if (*datalevel != tselem->type) {
|
||||
*datalevel = -1;
|
||||
}
|
||||
}
|
||||
if (TSELEM_OPEN(tselem, space_outliner)) {
|
||||
set_operation_types(
|
||||
space_outliner, &te->subtree, scenelevel, objectlevel, idlevel, datalevel);
|
||||
else {
|
||||
const int idcode = (int)GS(tselem->id->name);
|
||||
bool is_standard_id = false;
|
||||
switch ((ID_Type)idcode) {
|
||||
case ID_SCE:
|
||||
*scenelevel = 1;
|
||||
break;
|
||||
case ID_OB:
|
||||
*objectlevel = 1;
|
||||
break;
|
||||
|
||||
case ID_ME:
|
||||
case ID_CU:
|
||||
case ID_MB:
|
||||
case ID_LT:
|
||||
case ID_LA:
|
||||
case ID_AR:
|
||||
case ID_CA:
|
||||
case ID_SPK:
|
||||
case ID_MA:
|
||||
case ID_TE:
|
||||
case ID_IP:
|
||||
case ID_IM:
|
||||
case ID_SO:
|
||||
case ID_KE:
|
||||
case ID_WO:
|
||||
case ID_AC:
|
||||
case ID_TXT:
|
||||
case ID_GR:
|
||||
case ID_LS:
|
||||
case ID_LI:
|
||||
case ID_VF:
|
||||
case ID_NT:
|
||||
case ID_BR:
|
||||
case ID_PA:
|
||||
case ID_GD:
|
||||
case ID_MC:
|
||||
case ID_MSK:
|
||||
case ID_PAL:
|
||||
case ID_PC:
|
||||
case ID_CF:
|
||||
case ID_WS:
|
||||
case ID_LP:
|
||||
case ID_HA:
|
||||
case ID_PT:
|
||||
case ID_VO:
|
||||
case ID_SIM:
|
||||
is_standard_id = true;
|
||||
break;
|
||||
case ID_WM:
|
||||
case ID_SCR:
|
||||
/* Those are ignored here. */
|
||||
/* Note: while Screens should be manageable here, deleting a screen used by a workspace
|
||||
* will cause crashes when trying to use that workspace, so for now let's play minimal,
|
||||
* safe change. */
|
||||
break;
|
||||
}
|
||||
if (idcode == ID_NLA) {
|
||||
/* Fake one, not an actual ID type... */
|
||||
is_standard_id = true;
|
||||
}
|
||||
|
||||
if (is_standard_id) {
|
||||
if (*idlevel == 0) {
|
||||
*idlevel = idcode;
|
||||
}
|
||||
else if (*idlevel != idcode) {
|
||||
*idlevel = -1;
|
||||
}
|
||||
if (ELEM(*datalevel, TSE_VIEW_COLLECTION_BASE, TSE_SCENE_COLLECTION_BASE)) {
|
||||
*datalevel = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static TreeElement *get_target_element(SpaceOutliner *space_outliner)
|
||||
{
|
||||
TreeElement *te = outliner_find_element_with_flag(&space_outliner->tree, TSE_ACTIVE);
|
||||
BLI_assert(te);
|
||||
|
||||
return te;
|
||||
}
|
||||
|
||||
static void unlink_action_fn(bContext *C,
|
||||
ReportList *UNUSED(reports),
|
||||
Scene *UNUSED(scene),
|
||||
@@ -405,7 +400,8 @@ static void outliner_do_libdata_operation(bContext *C,
|
||||
for (te = lb->first; te; te = te->next) {
|
||||
tselem = TREESTORE(te);
|
||||
if (tselem->flag & TSE_SELECTED) {
|
||||
if (ELEM(tselem->type, 0, TSE_LAYER_COLLECTION)) {
|
||||
/* TODO (Nathan): Why is TSE_LAYER_COLLECTION an exception here? */
|
||||
if ((tselem->type == 0 && te->idcode != 0) /* || tselem->type == TSE_LAYER_COLLECTION*/) {
|
||||
TreeStoreElem *tsep = te->parent ? TREESTORE(te->parent) : NULL;
|
||||
operation_fn(C, reports, scene, te, tsep, tselem, user_data);
|
||||
}
|
||||
@@ -1407,8 +1403,6 @@ enum {
|
||||
OL_OP_TOGSEL,
|
||||
OL_OP_TOGREN,
|
||||
OL_OP_RENAME,
|
||||
OL_OP_OBJECT_MODE_ENTER,
|
||||
OL_OP_OBJECT_MODE_EXIT,
|
||||
};
|
||||
|
||||
static const EnumPropertyItem prop_object_op_types[] = {
|
||||
@@ -1421,8 +1415,6 @@ static const EnumPropertyItem prop_object_op_types[] = {
|
||||
"Remap Users",
|
||||
"Make all users of selected data-blocks to use instead a new chosen one"},
|
||||
{OL_OP_RENAME, "RENAME", 0, "Rename", ""},
|
||||
{OL_OP_OBJECT_MODE_ENTER, "OBJECT_MODE_ENTER", 0, "Enter Mode", ""},
|
||||
{OL_OP_OBJECT_MODE_EXIT, "OBJECT_MODE_EXIT", 0, "Exit Mode", ""},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
@@ -1492,16 +1484,6 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
|
||||
C, op->reports, scene, space_outliner, &space_outliner->tree, item_rename_fn);
|
||||
str = "Rename Object";
|
||||
}
|
||||
else if (event == OL_OP_OBJECT_MODE_ENTER) {
|
||||
outliner_do_object_operation(
|
||||
C, op->reports, scene, space_outliner, &space_outliner->tree, item_object_mode_enter_fn);
|
||||
str = "Enter Current Mode";
|
||||
}
|
||||
else if (event == OL_OP_OBJECT_MODE_EXIT) {
|
||||
outliner_do_object_operation(
|
||||
C, op->reports, scene, space_outliner, &space_outliner->tree, item_object_mode_exit_fn);
|
||||
str = "Exit Current Mode";
|
||||
}
|
||||
else {
|
||||
BLI_assert(0);
|
||||
return OPERATOR_CANCELLED;
|
||||
@@ -1805,18 +1787,16 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
|
||||
int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
|
||||
eOutlinerIdOpTypes event;
|
||||
|
||||
/* check for invalid states */
|
||||
if (space_outliner == NULL) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
set_operation_types(
|
||||
space_outliner, &space_outliner->tree, &scenelevel, &objectlevel, &idlevel, &datalevel);
|
||||
|
||||
event = RNA_enum_get(op->ptr, "type");
|
||||
TreeElement *te = get_target_element(space_outliner);
|
||||
get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel);
|
||||
|
||||
eOutlinerIdOpTypes event = RNA_enum_get(op->ptr, "type");
|
||||
switch (event) {
|
||||
case OUTLINER_IDOP_UNLINK: {
|
||||
/* unlink datablock from its parent */
|
||||
@@ -2137,18 +2117,16 @@ static int outliner_lib_operation_exec(bContext *C, wmOperator *op)
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
|
||||
int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
|
||||
eOutlinerLibOpTypes event;
|
||||
|
||||
/* check for invalid states */
|
||||
if (space_outliner == NULL) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
set_operation_types(
|
||||
space_outliner, &space_outliner->tree, &scenelevel, &objectlevel, &idlevel, &datalevel);
|
||||
|
||||
event = RNA_enum_get(op->ptr, "type");
|
||||
TreeElement *te = get_target_element(space_outliner);
|
||||
get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel);
|
||||
|
||||
eOutlinerLibOpTypes event = RNA_enum_get(op->ptr, "type");
|
||||
switch (event) {
|
||||
case OL_LIB_RENAME: {
|
||||
outliner_do_libdata_operation(
|
||||
@@ -2270,8 +2248,9 @@ static int outliner_action_set_exec(bContext *C, wmOperator *op)
|
||||
if (space_outliner == NULL) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
set_operation_types(
|
||||
space_outliner, &space_outliner->tree, &scenelevel, &objectlevel, &idlevel, &datalevel);
|
||||
|
||||
TreeElement *te = get_target_element(space_outliner);
|
||||
get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel);
|
||||
|
||||
/* get action to use */
|
||||
act = BLI_findlink(&bmain->actions, RNA_enum_get(op->ptr, "action"));
|
||||
@@ -2378,22 +2357,21 @@ static int outliner_animdata_operation_exec(bContext *C, wmOperator *op)
|
||||
wmWindowManager *wm = CTX_wm_manager(C);
|
||||
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
|
||||
int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
|
||||
eOutliner_AnimDataOps event;
|
||||
|
||||
/* check for invalid states */
|
||||
if (space_outliner == NULL) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
event = RNA_enum_get(op->ptr, "type");
|
||||
set_operation_types(
|
||||
space_outliner, &space_outliner->tree, &scenelevel, &objectlevel, &idlevel, &datalevel);
|
||||
TreeElement *te = get_target_element(space_outliner);
|
||||
get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel);
|
||||
|
||||
if (datalevel != TSE_ANIM_DATA) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
/* perform the core operation */
|
||||
eOutliner_AnimDataOps event = RNA_enum_get(op->ptr, "type");
|
||||
switch (event) {
|
||||
case OUTLINER_ANIMOP_CLEAR_ADT:
|
||||
/* Remove Animation Data - this may remove the active action, in some cases... */
|
||||
@@ -2483,15 +2461,10 @@ static const EnumPropertyItem prop_constraint_op_types[] = {
|
||||
static int outliner_constraint_operation_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
|
||||
int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
|
||||
eOutliner_PropConstraintOps event;
|
||||
|
||||
event = RNA_enum_get(op->ptr, "type");
|
||||
set_operation_types(
|
||||
space_outliner, &space_outliner->tree, &scenelevel, &objectlevel, &idlevel, &datalevel);
|
||||
eOutliner_PropConstraintOps event = RNA_enum_get(op->ptr, "type");
|
||||
|
||||
outliner_do_data_operation(
|
||||
space_outliner, datalevel, event, &space_outliner->tree, constraint_fn, C);
|
||||
space_outliner, TSE_CONSTRAINT, event, &space_outliner->tree, constraint_fn, C);
|
||||
|
||||
if (event == OL_CONSTRAINTOP_DELETE) {
|
||||
outliner_cleanup_tree(space_outliner);
|
||||
@@ -2535,15 +2508,10 @@ static const EnumPropertyItem prop_modifier_op_types[] = {
|
||||
static int outliner_modifier_operation_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
|
||||
int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
|
||||
eOutliner_PropModifierOps event;
|
||||
|
||||
event = RNA_enum_get(op->ptr, "type");
|
||||
set_operation_types(
|
||||
space_outliner, &space_outliner->tree, &scenelevel, &objectlevel, &idlevel, &datalevel);
|
||||
eOutliner_PropModifierOps event = RNA_enum_get(op->ptr, "type");
|
||||
|
||||
outliner_do_data_operation(
|
||||
space_outliner, datalevel, event, &space_outliner->tree, modifier_fn, C);
|
||||
space_outliner, TSE_MODIFIER, event, &space_outliner->tree, modifier_fn, C);
|
||||
|
||||
if (event == OL_MODIFIER_OP_DELETE) {
|
||||
outliner_cleanup_tree(space_outliner);
|
||||
@@ -2590,17 +2558,16 @@ static int outliner_data_operation_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
|
||||
int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
|
||||
eOutliner_PropDataOps event;
|
||||
|
||||
/* check for invalid states */
|
||||
if (space_outliner == NULL) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
event = RNA_enum_get(op->ptr, "type");
|
||||
set_operation_types(
|
||||
space_outliner, &space_outliner->tree, &scenelevel, &objectlevel, &idlevel, &datalevel);
|
||||
TreeElement *te = get_target_element(space_outliner);
|
||||
get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel);
|
||||
|
||||
eOutliner_PropDataOps event = RNA_enum_get(op->ptr, "type");
|
||||
switch (datalevel) {
|
||||
case TSE_POSE_CHANNEL: {
|
||||
outliner_do_data_operation(
|
||||
@@ -2687,7 +2654,7 @@ static int outliner_operator_menu(bContext *C, const char *opname)
|
||||
|
||||
/* set this so the default execution context is the same as submenus */
|
||||
uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_REGION_WIN);
|
||||
uiItemsEnumO(layout, ot->idname, RNA_property_identifier(ot->prop));
|
||||
uiItemsEnumO(layout, ot->idname, RNA_property_identifier(ot->prop), false);
|
||||
|
||||
uiItemS(layout);
|
||||
|
||||
@@ -2699,134 +2666,117 @@ static int outliner_operator_menu(bContext *C, const char *opname)
|
||||
}
|
||||
|
||||
static int do_outliner_operation_event(bContext *C,
|
||||
ReportList *reports,
|
||||
ARegion *region,
|
||||
SpaceOutliner *space_outliner,
|
||||
TreeElement *te,
|
||||
const float mval[2])
|
||||
TreeElement *te)
|
||||
{
|
||||
ReportList *reports = CTX_wm_reports(C); /* XXX... */
|
||||
int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
|
||||
TreeStoreElem *tselem = TREESTORE(te);
|
||||
|
||||
if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) {
|
||||
int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
|
||||
TreeStoreElem *tselem = TREESTORE(te);
|
||||
|
||||
/* select object that's clicked on and popup context menu */
|
||||
if (!(tselem->flag & TSE_SELECTED)) {
|
||||
|
||||
if (outliner_flag_is_any_test(&space_outliner->tree, TSE_SELECTED, 1)) {
|
||||
outliner_flag_set(&space_outliner->tree, TSE_SELECTED, 0);
|
||||
}
|
||||
|
||||
tselem->flag |= TSE_SELECTED;
|
||||
|
||||
/* Only redraw, don't rebuild here because TreeElement pointers will
|
||||
* become invalid and operations will crash. */
|
||||
ED_region_tag_redraw_no_rebuild(region);
|
||||
ED_outliner_select_sync_from_outliner(C, space_outliner);
|
||||
}
|
||||
|
||||
set_operation_types(
|
||||
space_outliner, &space_outliner->tree, &scenelevel, &objectlevel, &idlevel, &datalevel);
|
||||
|
||||
if (scenelevel) {
|
||||
if (objectlevel || datalevel || idlevel) {
|
||||
BKE_report(reports, RPT_WARNING, "Mixed selection");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
return outliner_operator_menu(C, "OUTLINER_OT_scene_operation");
|
||||
}
|
||||
if (objectlevel) {
|
||||
WM_menu_name_call(C, "OUTLINER_MT_object", WM_OP_INVOKE_REGION_WIN);
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
if (idlevel) {
|
||||
if (idlevel == -1 || datalevel) {
|
||||
BKE_report(reports, RPT_WARNING, "Mixed selection");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
switch (idlevel) {
|
||||
case ID_GR:
|
||||
WM_menu_name_call(C, "OUTLINER_MT_collection", WM_OP_INVOKE_REGION_WIN);
|
||||
return OPERATOR_FINISHED;
|
||||
break;
|
||||
case ID_LI:
|
||||
return outliner_operator_menu(C, "OUTLINER_OT_lib_operation");
|
||||
break;
|
||||
default:
|
||||
return outliner_operator_menu(C, "OUTLINER_OT_id_operation");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (datalevel) {
|
||||
if (datalevel == -1) {
|
||||
BKE_report(reports, RPT_WARNING, "Mixed selection");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
if (datalevel == TSE_ANIM_DATA) {
|
||||
return outliner_operator_menu(C, "OUTLINER_OT_animdata_operation");
|
||||
}
|
||||
if (datalevel == TSE_DRIVER_BASE) {
|
||||
/* do nothing... no special ops needed yet */
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
if (datalevel == TSE_LAYER_COLLECTION) {
|
||||
WM_menu_name_call(C, "OUTLINER_MT_collection", WM_OP_INVOKE_REGION_WIN);
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
if (ELEM(datalevel, TSE_SCENE_COLLECTION_BASE, TSE_VIEW_COLLECTION_BASE)) {
|
||||
WM_menu_name_call(C, "OUTLINER_MT_collection_new", WM_OP_INVOKE_REGION_WIN);
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
if (datalevel == TSE_ID_BASE) {
|
||||
/* do nothing... there are no ops needed here yet */
|
||||
return 0;
|
||||
}
|
||||
if (datalevel == TSE_CONSTRAINT) {
|
||||
return outliner_operator_menu(C, "OUTLINER_OT_constraint_operation");
|
||||
}
|
||||
if (datalevel == TSE_MODIFIER) {
|
||||
return outliner_operator_menu(C, "OUTLINER_OT_modifier_operation");
|
||||
}
|
||||
return outliner_operator_menu(C, "OUTLINER_OT_data_operation");
|
||||
}
|
||||
|
||||
return 0;
|
||||
int clear_flag = TSE_ACTIVE;
|
||||
if (!(tselem->flag & TSE_SELECTED)) {
|
||||
clear_flag |= TSE_SELECTED;
|
||||
}
|
||||
|
||||
for (te = te->subtree.first; te; te = te->next) {
|
||||
int retval = do_outliner_operation_event(C, region, space_outliner, te, mval);
|
||||
if (retval) {
|
||||
return retval;
|
||||
outliner_flag_set(&space_outliner->tree, clear_flag, false);
|
||||
tselem->flag |= TSE_SELECTED | TSE_ACTIVE;
|
||||
|
||||
/* Only redraw, don't rebuild here because TreeElement pointers will
|
||||
* become invalid and operations will crash. */
|
||||
ED_region_tag_redraw_no_rebuild(region);
|
||||
ED_outliner_select_sync_from_outliner(C, space_outliner);
|
||||
|
||||
get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel);
|
||||
|
||||
if (scenelevel) {
|
||||
if (objectlevel || datalevel || idlevel) {
|
||||
BKE_report(reports, RPT_WARNING, "Mixed selection");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
return outliner_operator_menu(C, "OUTLINER_OT_scene_operation");
|
||||
}
|
||||
if (objectlevel) {
|
||||
WM_menu_name_call(C, "OUTLINER_MT_object", WM_OP_INVOKE_REGION_WIN);
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
if (idlevel) {
|
||||
if (idlevel == -1 || datalevel) {
|
||||
BKE_report(reports, RPT_WARNING, "Mixed selection");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
switch (idlevel) {
|
||||
case ID_GR:
|
||||
WM_menu_name_call(C, "OUTLINER_MT_collection", WM_OP_INVOKE_REGION_WIN);
|
||||
return OPERATOR_FINISHED;
|
||||
break;
|
||||
case ID_LI:
|
||||
return outliner_operator_menu(C, "OUTLINER_OT_lib_operation");
|
||||
break;
|
||||
default:
|
||||
return outliner_operator_menu(C, "OUTLINER_OT_id_operation");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (datalevel) {
|
||||
if (datalevel == -1) {
|
||||
BKE_report(reports, RPT_WARNING, "Mixed selection");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
if (datalevel == TSE_ANIM_DATA) {
|
||||
return outliner_operator_menu(C, "OUTLINER_OT_animdata_operation");
|
||||
}
|
||||
if (datalevel == TSE_DRIVER_BASE) {
|
||||
/* do nothing... no special ops needed yet */
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
if (datalevel == TSE_LAYER_COLLECTION) {
|
||||
WM_menu_name_call(C, "OUTLINER_MT_collection", WM_OP_INVOKE_REGION_WIN);
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
if (ELEM(datalevel, TSE_SCENE_COLLECTION_BASE, TSE_VIEW_COLLECTION_BASE)) {
|
||||
WM_menu_name_call(C, "OUTLINER_MT_collection_new", WM_OP_INVOKE_REGION_WIN);
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
if (datalevel == TSE_ID_BASE) {
|
||||
/* do nothing... there are no ops needed here yet */
|
||||
return 0;
|
||||
}
|
||||
if (datalevel == TSE_CONSTRAINT) {
|
||||
return outliner_operator_menu(C, "OUTLINER_OT_constraint_operation");
|
||||
}
|
||||
if (datalevel == TSE_MODIFIER) {
|
||||
return outliner_operator_menu(C, "OUTLINER_OT_modifier_operation");
|
||||
}
|
||||
return outliner_operator_menu(C, "OUTLINER_OT_data_operation");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int outliner_operation(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
|
||||
static int outliner_operation(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
ARegion *region = CTX_wm_region(C);
|
||||
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
|
||||
uiBut *but = UI_context_active_but_get(C);
|
||||
TreeElement *te;
|
||||
float fmval[2];
|
||||
float view_mval[2];
|
||||
|
||||
if (but) {
|
||||
UI_but_tooltip_timer_remove(C, but);
|
||||
}
|
||||
|
||||
UI_view2d_region_to_view(®ion->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
|
||||
UI_view2d_region_to_view(
|
||||
®ion->v2d, event->mval[0], event->mval[1], &view_mval[0], &view_mval[1]);
|
||||
|
||||
for (te = space_outliner->tree.first; te; te = te->next) {
|
||||
int retval = do_outliner_operation_event(C, region, space_outliner, te, fmval);
|
||||
if (retval) {
|
||||
return retval;
|
||||
}
|
||||
TreeElement *hovered_te = outliner_find_item_at_y(
|
||||
space_outliner, &space_outliner->tree, view_mval[1]);
|
||||
if (!hovered_te) {
|
||||
/* Let this fall through to 'OUTLINER_MT_context_menu'. */
|
||||
return OPERATOR_PASS_THROUGH;
|
||||
}
|
||||
|
||||
/* Let this fall through to 'OUTLINER_MT_context_menu'. */
|
||||
return OPERATOR_PASS_THROUGH;
|
||||
return do_outliner_operation_event(C, op->reports, region, space_outliner, hovered_te);
|
||||
}
|
||||
|
||||
/* Menu only! Calls other operators */
|
||||
|
@@ -32,6 +32,7 @@
|
||||
#include "DNA_camera_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_hair_types.h"
|
||||
#include "DNA_key_types.h"
|
||||
@@ -46,6 +47,7 @@
|
||||
#include "DNA_pointcloud_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
#include "DNA_sequence_types.h"
|
||||
#include "DNA_shader_fx_types.h"
|
||||
#include "DNA_simulation_types.h"
|
||||
#include "DNA_speaker_types.h"
|
||||
#include "DNA_volume_types.h"
|
||||
@@ -552,6 +554,72 @@ static void outliner_add_object_contents(SpaceOutliner *space_outliner,
|
||||
}
|
||||
}
|
||||
|
||||
/* Grease Pencil modifiers. */
|
||||
if (!BLI_listbase_is_empty(&ob->greasepencil_modifiers)) {
|
||||
GpencilModifierData *md;
|
||||
TreeElement *ten_mod = outliner_add_element(
|
||||
space_outliner, &te->subtree, ob, te, TSE_MODIFIER_BASE, 0);
|
||||
int index;
|
||||
|
||||
ten_mod->name = IFACE_("Modifiers");
|
||||
for (index = 0, md = ob->greasepencil_modifiers.first; md; index++, md = md->next) {
|
||||
TreeElement *ten = outliner_add_element(
|
||||
space_outliner, &ten_mod->subtree, ob, ten_mod, TSE_MODIFIER, index);
|
||||
ten->name = md->name;
|
||||
ten->directdata = md;
|
||||
|
||||
if (md->type == eGpencilModifierType_Armature) {
|
||||
outliner_add_element(space_outliner,
|
||||
&ten->subtree,
|
||||
((ArmatureGpencilModifierData *)md)->object,
|
||||
ten,
|
||||
TSE_LINKED_OB,
|
||||
0);
|
||||
}
|
||||
else if (md->type == eGpencilModifierType_Hook) {
|
||||
outliner_add_element(space_outliner,
|
||||
&ten->subtree,
|
||||
((HookGpencilModifierData *)md)->object,
|
||||
ten,
|
||||
TSE_LINKED_OB,
|
||||
0);
|
||||
}
|
||||
else if (md->type == eGpencilModifierType_Lattice) {
|
||||
outliner_add_element(space_outliner,
|
||||
&ten->subtree,
|
||||
((LatticeGpencilModifierData *)md)->object,
|
||||
ten,
|
||||
TSE_LINKED_OB,
|
||||
0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Grease Pencil effects. */
|
||||
if (!BLI_listbase_is_empty(&ob->shader_fx)) {
|
||||
ShaderFxData *fx;
|
||||
TreeElement *ten_fx = outliner_add_element(
|
||||
space_outliner, &te->subtree, ob, te, TSE_EFFECT_BASE, 0);
|
||||
int index;
|
||||
|
||||
ten_fx->name = IFACE_("Effects");
|
||||
for (index = 0, fx = ob->shader_fx.first; fx; index++, fx = fx->next) {
|
||||
TreeElement *ten = outliner_add_element(
|
||||
space_outliner, &ten_fx->subtree, ob, ten_fx, TSE_EFFECT, index);
|
||||
ten->name = fx->name;
|
||||
ten->directdata = fx;
|
||||
|
||||
if (fx->type == eShaderFxType_Swirl) {
|
||||
outliner_add_element(space_outliner,
|
||||
&ten->subtree,
|
||||
((SwirlShaderFxData *)fx)->object,
|
||||
ten,
|
||||
TSE_LINKED_OB,
|
||||
0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* vertex groups */
|
||||
if (ob->defbase.first) {
|
||||
bDeformGroup *defgroup;
|
||||
@@ -1787,117 +1855,24 @@ static int treesort_alpha(const void *v1, const void *v2)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* this is nice option for later? doesn't look too useful... */
|
||||
#if 0
|
||||
static int treesort_obtype_alpha(const void *v1, const void *v2)
|
||||
static int treesort_type(const void *v1, const void *v2)
|
||||
{
|
||||
const tTreeSort *x1 = v1, *x2 = v2;
|
||||
const tTreeSort *x1 = v1;
|
||||
const tTreeSort *x2 = v2;
|
||||
|
||||
/* first put objects last (hierarchy) */
|
||||
if (x1->idcode == ID_OB && x2->idcode != ID_OB) {
|
||||
if (((Object *)x1->id)->type > ((Object *)x2->id)->type) {
|
||||
return 1;
|
||||
}
|
||||
else if (x2->idcode == ID_OB && x1->idcode != ID_OB) {
|
||||
else if (((Object *)x2->id)->type > ((Object *)x1->id)->type) {
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
/* 2nd we check ob type */
|
||||
if (x1->idcode == ID_OB && x2->idcode == ID_OB) {
|
||||
if (((Object *)x1->id)->type > ((Object *)x2->id)->type) {
|
||||
return 1;
|
||||
}
|
||||
else if (((Object *)x1->id)->type > ((Object *)x2->id)->type) {
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
int comp = BLI_strcasecmp_natural(x1->name, x2->name);
|
||||
|
||||
if (comp > 0) {
|
||||
return 1;
|
||||
}
|
||||
else if (comp < 0) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* sort happens on each subtree individual */
|
||||
static void outliner_sort(ListBase *lb)
|
||||
{
|
||||
TreeElement *te;
|
||||
TreeStoreElem *tselem;
|
||||
|
||||
te = lb->last;
|
||||
if (te == NULL) {
|
||||
return;
|
||||
}
|
||||
tselem = TREESTORE(te);
|
||||
|
||||
/* sorting rules; only object lists, ID lists, or deformgroups */
|
||||
if (ELEM(tselem->type, TSE_DEFGROUP, TSE_ID_BASE) ||
|
||||
(tselem->type == 0 && te->idcode == ID_OB)) {
|
||||
int totelem = BLI_listbase_count(lb);
|
||||
|
||||
if (totelem > 1) {
|
||||
tTreeSort *tear = MEM_mallocN(totelem * sizeof(tTreeSort), "tree sort array");
|
||||
tTreeSort *tp = tear;
|
||||
int skip = 0;
|
||||
|
||||
for (te = lb->first; te; te = te->next, tp++) {
|
||||
tselem = TREESTORE(te);
|
||||
tp->te = te;
|
||||
tp->name = te->name;
|
||||
tp->idcode = te->idcode;
|
||||
|
||||
if (tselem->type && tselem->type != TSE_DEFGROUP) {
|
||||
tp->idcode = 0; /* Don't sort this. */
|
||||
}
|
||||
if (tselem->type == TSE_ID_BASE) {
|
||||
tp->idcode = 1; /* Do sort this. */
|
||||
}
|
||||
|
||||
tp->id = tselem->id;
|
||||
}
|
||||
|
||||
/* just sort alphabetically */
|
||||
if (tear->idcode == 1) {
|
||||
qsort(tear, totelem, sizeof(tTreeSort), treesort_alpha);
|
||||
}
|
||||
else {
|
||||
/* keep beginning of list */
|
||||
for (tp = tear, skip = 0; skip < totelem; skip++, tp++) {
|
||||
if (tp->idcode) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (skip < totelem) {
|
||||
qsort(tear + skip, totelem - skip, sizeof(tTreeSort), treesort_alpha_ob);
|
||||
}
|
||||
}
|
||||
|
||||
BLI_listbase_clear(lb);
|
||||
tp = tear;
|
||||
while (totelem--) {
|
||||
BLI_addtail(lb, tp->te);
|
||||
tp++;
|
||||
}
|
||||
MEM_freeN(tear);
|
||||
}
|
||||
}
|
||||
|
||||
for (te = lb->first; te; te = te->next) {
|
||||
outliner_sort(&te->subtree);
|
||||
/* Compare by name */
|
||||
return treesort_alpha(v1, v2);
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO (Nathan): Should children still be sorted? */
|
||||
static void outliner_collections_children_sort(ListBase *lb)
|
||||
{
|
||||
TreeElement *te;
|
||||
@@ -1942,6 +1917,126 @@ static void outliner_collections_children_sort(ListBase *lb)
|
||||
}
|
||||
}
|
||||
|
||||
static bool outliner_is_sort_item(TreeElement *te)
|
||||
{
|
||||
TreeStoreElem *tselem = TREESTORE(te);
|
||||
return (tselem->type == 0 && te->idcode == ID_OB) || outliner_is_collection_tree_element(te) ||
|
||||
(ELEM(tselem->type, TSE_BONE, TSE_EBONE, TSE_POSE_CHANNEL));
|
||||
}
|
||||
|
||||
/* Sort collections and objects separately on each outliner subtree. */
|
||||
static void outliner_tree_sort(SpaceOutliner *space_outliner, ListBase *tree)
|
||||
{
|
||||
if (BLI_listbase_is_empty(tree)) {
|
||||
return;
|
||||
}
|
||||
|
||||
TreeElement *te_last = tree->last;
|
||||
TreeStoreElem *tselem;
|
||||
|
||||
/* Only sort collections and objects */
|
||||
if (outliner_is_sort_item(te_last)) {
|
||||
int num_elems = BLI_listbase_count(tree);
|
||||
|
||||
if (num_elems > 1) {
|
||||
tTreeSort *tree_sort = MEM_mallocN(num_elems * sizeof(tTreeSort), "tree sort array");
|
||||
tTreeSort *tree_sort_p = tree_sort;
|
||||
int num_collections = 0;
|
||||
|
||||
for (TreeElement *te = tree->first; te; te = te->next, tree_sort_p++) {
|
||||
tselem = TREESTORE(te);
|
||||
tree_sort_p->te = te;
|
||||
tree_sort_p->name = te->name;
|
||||
tree_sort_p->idcode = te->idcode;
|
||||
|
||||
if (tselem->type && tselem->type != TSE_DEFGROUP) {
|
||||
tree_sort_p->idcode = 0; /* Don't sort this. */
|
||||
}
|
||||
if (tselem->type == TSE_ID_BASE) {
|
||||
tree_sort_p->idcode = 1; /* Do sort this. */
|
||||
}
|
||||
|
||||
if (outliner_is_collection_tree_element(te)) {
|
||||
num_collections++;
|
||||
}
|
||||
|
||||
tree_sort_p->id = tselem->id;
|
||||
}
|
||||
|
||||
/* Skip beginning of list */
|
||||
int skip = 0;
|
||||
if (!outliner_is_sort_item(tree_sort->te)) {
|
||||
for (tree_sort_p = tree_sort, skip = 0; skip < num_elems; skip++, tree_sort_p++) {
|
||||
if (outliner_is_sort_item(tree_sort_p->te)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Sort collections. */
|
||||
if (num_collections > 0) {
|
||||
switch (space_outliner->sort_method) {
|
||||
case SO_SORT_ALPHA:
|
||||
qsort(tree_sort + skip, num_collections - skip, sizeof(tTreeSort), treesort_alpha);
|
||||
break;
|
||||
case SO_SORT_TYPE:
|
||||
qsort(tree_sort + skip, num_collections - skip, sizeof(tTreeSort), treesort_alpha);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Sort objects. */
|
||||
if (num_elems - num_collections - skip > 0) {
|
||||
switch (space_outliner->sort_method) {
|
||||
case SO_SORT_ALPHA:
|
||||
qsort(tree_sort + skip + num_collections,
|
||||
num_elems - num_collections - skip,
|
||||
sizeof(tTreeSort),
|
||||
treesort_alpha);
|
||||
break;
|
||||
case SO_SORT_TYPE:
|
||||
qsort(tree_sort + skip + num_collections,
|
||||
num_elems - num_collections - skip,
|
||||
sizeof(tTreeSort),
|
||||
treesort_type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy sorted list back into tree */
|
||||
BLI_listbase_clear(tree);
|
||||
tree_sort_p = tree_sort;
|
||||
while (num_elems--) {
|
||||
BLI_addtail(tree, tree_sort_p->te);
|
||||
tree_sort_p++;
|
||||
}
|
||||
MEM_freeN(tree_sort);
|
||||
}
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (TreeElement *, te, tree) {
|
||||
outliner_tree_sort(space_outliner, &te->subtree);
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
void f(SpaceOutliner *space_outliner)
|
||||
{
|
||||
if (space_outliner->sort_method == SO_SORT_ALPHA) {
|
||||
outliner_sort(tree);
|
||||
}
|
||||
else if (space_outliner->sort_method == SO_SORT_TYPE) {
|
||||
}
|
||||
else if ((space_outliner->filter & SO_FILTER_NO_CHILDREN) == 0) {
|
||||
/* We group the children that are in the collection before the ones that are not.
|
||||
* This way we can try to draw them in a different style altogether.
|
||||
* We also have to respect the original order of the elements in case alphabetical
|
||||
* sorting is not enabled. This keep object data and modifiers before its children. */
|
||||
outliner_collections_children_sort(tree);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Filtering ----------------------------------------------- */
|
||||
|
||||
typedef struct OutlinerTreeElementFocus {
|
||||
@@ -2564,15 +2659,8 @@ void outliner_build_tree(Main *mainvar,
|
||||
}
|
||||
}
|
||||
|
||||
if ((space_outliner->flag & SO_SKIP_SORT_ALPHA) == 0) {
|
||||
outliner_sort(&space_outliner->tree);
|
||||
}
|
||||
else if ((space_outliner->filter & SO_FILTER_NO_CHILDREN) == 0) {
|
||||
/* We group the children that are in the collection before the ones that are not.
|
||||
* This way we can try to draw them in a different style altogether.
|
||||
* We also have to respect the original order of the elements in case alphabetical
|
||||
* sorting is not enabled. This keep object data and modifiers before its children. */
|
||||
outliner_collections_children_sort(&space_outliner->tree);
|
||||
if (space_outliner->sort_method != SO_SORT_FREE) {
|
||||
outliner_tree_sort(space_outliner, &space_outliner->tree);
|
||||
}
|
||||
|
||||
outliner_filter_tree(space_outliner, view_layer);
|
||||
|
@@ -359,6 +359,9 @@ float outliner_restrict_columns_width(const SpaceOutliner *space_outliner)
|
||||
num_columns = 3;
|
||||
break;
|
||||
case SO_VIEW_LAYER:
|
||||
if (space_outliner->show_restrict_flags & SO_RESTRICT_ENABLE) {
|
||||
num_columns++;
|
||||
}
|
||||
if (space_outliner->show_restrict_flags & SO_RESTRICT_HOLDOUT) {
|
||||
num_columns++;
|
||||
}
|
||||
|
@@ -305,7 +305,7 @@ static SpaceLink *outliner_create(const ScrArea *UNUSED(area), const Scene *UNUS
|
||||
space_outliner->show_restrict_flags = SO_RESTRICT_ENABLE | SO_RESTRICT_HIDE;
|
||||
space_outliner->outlinevis = SO_VIEW_LAYER;
|
||||
space_outliner->sync_select_dirty |= WM_OUTLINER_SYNC_SELECT_FROM_ALL;
|
||||
space_outliner->flag |= SO_SYNC_SELECT;
|
||||
space_outliner->flag = SO_SYNC_SELECT | SO_MODE_COLUMN;
|
||||
|
||||
/* header */
|
||||
region = MEM_callocN(sizeof(ARegion), "header for outliner");
|
||||
|
@@ -187,7 +187,7 @@ static int select_orientation_invoke(bContext *C,
|
||||
|
||||
pup = UI_popup_menu_begin(C, IFACE_("Orientation"), ICON_NONE);
|
||||
layout = UI_popup_menu_layout(pup);
|
||||
uiItemsEnumO(layout, "TRANSFORM_OT_select_orientation", "orientation");
|
||||
uiItemsEnumO(layout, "TRANSFORM_OT_select_orientation", "orientation", false);
|
||||
UI_popup_menu_end(C, pup);
|
||||
|
||||
return OPERATOR_INTERFACE;
|
||||
|
@@ -58,7 +58,9 @@ typedef struct Collection {
|
||||
short flag;
|
||||
/* Runtime-only, always cleared on file load. */
|
||||
short tag;
|
||||
char _pad[4];
|
||||
|
||||
short color;
|
||||
char _pad[2];
|
||||
|
||||
/* Runtime. Cache of objects in this collection and all its
|
||||
* children. This is created on demand when e.g. some physics
|
||||
@@ -92,3 +94,16 @@ enum {
|
||||
* Using a generic tag like LIB_TAG_DOIT for this is just impossible, we need our very own. */
|
||||
COLLECTION_TAG_RELATION_REBUILD = (1 << 0),
|
||||
};
|
||||
|
||||
/* Collection->color */
|
||||
enum {
|
||||
COLLECTION_COLOR_NONE = 0,
|
||||
COLLECTION_COLOR_01 = 1,
|
||||
COLLECTION_COLOR_02 = 2,
|
||||
COLLECTION_COLOR_03 = 3,
|
||||
COLLECTION_COLOR_04 = 4,
|
||||
COLLECTION_COLOR_05 = 5,
|
||||
COLLECTION_COLOR_06 = 6,
|
||||
COLLECTION_COLOR_07 = 7,
|
||||
COLLECTION_COLOR_08 = 8,
|
||||
};
|
||||
|
@@ -109,6 +109,8 @@ enum {
|
||||
#define TSE_SCENE_COLLECTION_BASE 39
|
||||
#define TSE_VIEW_COLLECTION_BASE 40
|
||||
#define TSE_SCENE_OBJECTS_BASE 41
|
||||
#define TSE_EFFECT_BASE 42
|
||||
#define TSE_EFFECT 43
|
||||
|
||||
/* Check whether given TreeStoreElem should have a real ID in its ->id member. */
|
||||
#define TSE_IS_REAL_ID(_tse) \
|
||||
|
@@ -274,6 +274,9 @@ typedef struct SpaceOutliner {
|
||||
* Pointers to treestore elements, grouped by (id, type, nr)
|
||||
* in hashtable for faster searching */
|
||||
void *treehash;
|
||||
|
||||
char sort_method;
|
||||
char _pad[7];
|
||||
} SpaceOutliner;
|
||||
|
||||
/* SpaceOutliner.flag */
|
||||
@@ -282,8 +285,9 @@ typedef enum eSpaceOutliner_Flag {
|
||||
/* SO_NEWSELECTED = (1 << 1), */ /* UNUSED */
|
||||
SO_FLAG_UNUSED_1 = (1 << 2), /* cleared */
|
||||
/* SO_HIDE_KEYINGSETINFO = (1 << 3), */ /* UNUSED */
|
||||
SO_SKIP_SORT_ALPHA = (1 << 4),
|
||||
/* SO_SKIP_SORT_ALPHA = (1 << 4), */ /* UNUSED */
|
||||
SO_SYNC_SELECT = (1 << 5),
|
||||
SO_MODE_COLUMN = (1 << 6),
|
||||
} eSpaceOutliner_Flag;
|
||||
|
||||
/* SpaceOutliner.filter */
|
||||
@@ -294,7 +298,7 @@ typedef enum eSpaceOutliner_Filter {
|
||||
SO_FILTER_NO_OB_CONTENT = (1 << 3), /* Not only mesh, but modifiers, constraints, ... */
|
||||
SO_FILTER_NO_CHILDREN = (1 << 4),
|
||||
|
||||
SO_FILTER_UNUSED_5 = (1 << 5), /* cleared */
|
||||
SO_FILTER_NO_ROW_CHILDREN = (1 << 5),
|
||||
SO_FILTER_NO_OB_MESH = (1 << 6),
|
||||
SO_FILTER_NO_OB_ARMATURE = (1 << 7),
|
||||
SO_FILTER_NO_OB_EMPTY = (1 << 8),
|
||||
@@ -321,8 +325,8 @@ typedef enum eSpaceOutliner_Filter {
|
||||
SO_FILTER_OB_STATE_ACTIVE)
|
||||
|
||||
#define SO_FILTER_ANY \
|
||||
(SO_FILTER_NO_OB_CONTENT | SO_FILTER_NO_CHILDREN | SO_FILTER_OB_TYPE | SO_FILTER_OB_STATE | \
|
||||
SO_FILTER_NO_COLLECTION)
|
||||
(SO_FILTER_NO_OB_CONTENT | SO_FILTER_NO_CHILDREN | SO_FILTER_NO_ROW_CHILDREN | \
|
||||
SO_FILTER_OB_TYPE | SO_FILTER_OB_STATE | SO_FILTER_NO_COLLECTION)
|
||||
|
||||
/* SpaceOutliner.filter_state */
|
||||
typedef enum eSpaceOutliner_StateFilter {
|
||||
@@ -381,6 +385,13 @@ typedef enum eSpaceOutliner_Search_Flags {
|
||||
SO_SEARCH_RECURSIVE = (1 << 2),
|
||||
} eSpaceOutliner_Search_Flags;
|
||||
|
||||
/* SpaceOutliner.sort_method */
|
||||
typedef enum eSpaceOutliner_Sort_Types {
|
||||
SO_SORT_FREE,
|
||||
SO_SORT_ALPHA,
|
||||
SO_SORT_TYPE,
|
||||
} eSpaceOutliner_Sort_Types;
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
@@ -455,6 +455,10 @@ typedef enum eWireColor_Flags {
|
||||
/* TH_WIRECOLOR_TEXTCOLS = (1 << 1), */ /* UNUSED */
|
||||
} eWireColor_Flags;
|
||||
|
||||
typedef struct ThemeCollectionColor {
|
||||
unsigned char color[4];
|
||||
} ThemeCollectionColor;
|
||||
|
||||
/**
|
||||
* A theme.
|
||||
*
|
||||
@@ -493,6 +497,8 @@ typedef struct bTheme {
|
||||
ThemeWireColor tarm[20];
|
||||
/*ThemeWireColor tobj[20];*/
|
||||
|
||||
ThemeCollectionColor collection_color[8];
|
||||
|
||||
int active_theme_area;
|
||||
char _pad0[4];
|
||||
} bTheme;
|
||||
|
@@ -633,6 +633,7 @@ extern StructRNA RNA_TextureNodeViewer;
|
||||
extern StructRNA RNA_TextureSlot;
|
||||
extern StructRNA RNA_Theme;
|
||||
extern StructRNA RNA_ThemeBoneColorSet;
|
||||
extern StructRNA RNA_ThemeCollectionColor;
|
||||
extern StructRNA RNA_ThemeConsole;
|
||||
extern StructRNA RNA_ThemeDopeSheet;
|
||||
extern StructRNA RNA_ThemeFileBrowser;
|
||||
|
@@ -229,6 +229,8 @@ extern const EnumPropertyItem rna_enum_context_mode_items[];
|
||||
extern const EnumPropertyItem rna_enum_curveprofile_preset_items[];
|
||||
extern const EnumPropertyItem rna_enum_preference_section_items[];
|
||||
|
||||
extern const EnumPropertyItem rna_enum_collection_color_items[];
|
||||
|
||||
/* API calls */
|
||||
int rna_node_tree_type_to_enum(struct bNodeTreeType *typeinfo);
|
||||
int rna_node_tree_idname_to_enum(const char *idname);
|
||||
|
@@ -30,6 +30,19 @@
|
||||
|
||||
#include "WM_types.h"
|
||||
|
||||
const EnumPropertyItem rna_enum_collection_color_items[] = {
|
||||
{COLLECTION_COLOR_NONE, "NONE", ICON_X, "None", "Assign no color tag to the collection"},
|
||||
{COLLECTION_COLOR_01, "COLOR_01", ICON_COLLECTION_COLOR_01, "Color 01", ""},
|
||||
{COLLECTION_COLOR_02, "COLOR_02", ICON_COLLECTION_COLOR_02, "Color 02", ""},
|
||||
{COLLECTION_COLOR_03, "COLOR_03", ICON_COLLECTION_COLOR_03, "Color 03", ""},
|
||||
{COLLECTION_COLOR_04, "COLOR_04", ICON_COLLECTION_COLOR_04, "Color 04", ""},
|
||||
{COLLECTION_COLOR_05, "COLOR_05", ICON_COLLECTION_COLOR_05, "Color 05", ""},
|
||||
{COLLECTION_COLOR_06, "COLOR_06", ICON_COLLECTION_COLOR_06, "Color 06", ""},
|
||||
{COLLECTION_COLOR_07, "COLOR_07", ICON_COLLECTION_COLOR_07, "Color 07", ""},
|
||||
{COLLECTION_COLOR_08, "COLOR_08", ICON_COLLECTION_COLOR_08, "Color 08", ""},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
#ifdef RNA_RUNTIME
|
||||
|
||||
# include "DNA_object_types.h"
|
||||
@@ -474,6 +487,12 @@ void RNA_def_collections(BlenderRNA *brna)
|
||||
RNA_def_property_ui_text(prop, "Disable in Renders", "Globally disable in renders");
|
||||
RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_Collection_flag_update");
|
||||
|
||||
prop = RNA_def_property(srna, "color", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, NULL, "color");
|
||||
RNA_def_property_enum_items(prop, rna_enum_collection_color_items);
|
||||
RNA_def_property_ui_text(prop, "Collection Color", "Color tag for a collection");
|
||||
RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, NULL);
|
||||
|
||||
RNA_define_lib_overridable(false);
|
||||
}
|
||||
|
||||
|
@@ -2984,6 +2984,13 @@ static void rna_def_space_outliner(BlenderRNA *brna)
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
static const EnumPropertyItem sort_method_items[] = {
|
||||
{SO_SORT_FREE, "FREE", 0, "Manual", "Sort objects and collections manually"},
|
||||
{SO_SORT_ALPHA, "ALPHA", 0, "Name", "Sort objects and collections by name alphabetically"},
|
||||
{SO_SORT_TYPE, "TYPE", 0, "Type", "Sort objects by type"},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
static const EnumPropertyItem filter_state_items[] = {
|
||||
{SO_FILTER_OB_ALL, "ALL", 0, "All", "Show all objects in the view layer"},
|
||||
{SO_FILTER_OB_VISIBLE, "VISIBLE", 0, "Visible", "Show visible objects"},
|
||||
@@ -3021,9 +3028,10 @@ static void rna_def_space_outliner(BlenderRNA *brna)
|
||||
prop, "Complete Matches Only", "Only use complete matches of search string");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "use_sort_alpha", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SO_SKIP_SORT_ALPHA);
|
||||
RNA_def_property_ui_text(prop, "Sort Alphabetically", "");
|
||||
prop = RNA_def_property(srna, "sort_method", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, NULL, "sort_method");
|
||||
RNA_def_property_enum_items(prop, sort_method_items);
|
||||
RNA_def_property_ui_text(prop, "Sort Type", "Outliner sort method");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "use_sync_select", PROP_BOOLEAN, PROP_NONE);
|
||||
@@ -3032,6 +3040,12 @@ static void rna_def_space_outliner(BlenderRNA *brna)
|
||||
prop, "Sync Outliner Selection", "Sync outliner selection with other editors");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "show_mode_column", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", SO_MODE_COLUMN);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Show Mode Column", "Show the mode column for mode toggle and activation");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
|
||||
|
||||
/* Granular restriction column option. */
|
||||
prop = RNA_def_property(srna, "show_restrict_column_enable", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "show_restrict_flags", SO_RESTRICT_ENABLE);
|
||||
@@ -3092,6 +3106,11 @@ static void rna_def_space_outliner(BlenderRNA *brna)
|
||||
RNA_def_property_ui_text(prop, "Show Object Children", "Show children");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "use_filter_row_children", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_negative_sdna(prop, NULL, "filter", SO_FILTER_NO_ROW_CHILDREN);
|
||||
RNA_def_property_ui_text(prop, "Show Row Children", "Show children on collapsed rows");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "use_filter_collection", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_negative_sdna(prop, NULL, "filter", SO_FILTER_NO_COLLECTION);
|
||||
RNA_def_property_ui_text(prop, "Show Collections", "Show collections");
|
||||
|
@@ -977,6 +977,7 @@ void RNA_api_ui_layout(StructRNA *srna)
|
||||
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
|
||||
parm = RNA_def_string(func, "property", NULL, 0, "", "Identifier of property in operator");
|
||||
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
|
||||
RNA_def_boolean(func, "icon_only", false, "", "Draw only icons in buttons, no text");
|
||||
|
||||
func = RNA_def_function(srna, "operator_menu_enum", "rna_uiItemMenuEnumO");
|
||||
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
|
||||
|
@@ -3615,6 +3615,23 @@ static void rna_def_userdef_theme_colorset(BlenderRNA *brna)
|
||||
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
|
||||
}
|
||||
|
||||
static void rna_def_userdef_theme_collection_color(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
srna = RNA_def_struct(brna, "ThemeCollectionColor", NULL);
|
||||
RNA_def_struct_sdna(srna, "ThemeCollectionColor");
|
||||
RNA_def_struct_clear_flag(srna, STRUCT_UNDO);
|
||||
RNA_def_struct_ui_text(srna, "Theme Collection Color", "Theme settings for collection colors");
|
||||
|
||||
prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA);
|
||||
RNA_def_property_float_sdna(prop, NULL, "color");
|
||||
RNA_def_property_array(prop, 3);
|
||||
RNA_def_property_ui_text(prop, "Color", "Collection Color Tag");
|
||||
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
|
||||
}
|
||||
|
||||
static void rna_def_userdef_theme_space_clip(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
@@ -3931,6 +3948,12 @@ static void rna_def_userdef_themes(BlenderRNA *brna)
|
||||
RNA_def_property_collection_sdna(prop, NULL, "tarm", "");
|
||||
RNA_def_property_struct_type(prop, "ThemeBoneColorSet");
|
||||
RNA_def_property_ui_text(prop, "Bone Color Sets", "");
|
||||
|
||||
prop = RNA_def_property(srna, "collection_color", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_flag(prop, PROP_NEVER_NULL);
|
||||
RNA_def_property_collection_sdna(prop, NULL, "collection_color", "");
|
||||
RNA_def_property_struct_type(prop, "ThemeCollectionColor");
|
||||
RNA_def_property_ui_text(prop, "Collection Color", "");
|
||||
}
|
||||
|
||||
static void rna_def_userdef_addon(BlenderRNA *brna)
|
||||
@@ -4172,6 +4195,7 @@ static void rna_def_userdef_dothemes(BlenderRNA *brna)
|
||||
rna_def_userdef_theme_space_topbar(brna);
|
||||
rna_def_userdef_theme_space_statusbar(brna);
|
||||
rna_def_userdef_theme_colorset(brna);
|
||||
rna_def_userdef_theme_collection_color(brna);
|
||||
rna_def_userdef_themes(brna);
|
||||
}
|
||||
|
||||
|
@@ -3991,6 +3991,12 @@ static const EnumPropertyItem *rna_id_itemf(bContext *UNUSED(C),
|
||||
if (local == false || !ID_IS_LINKED(id)) {
|
||||
item_tmp.identifier = item_tmp.name = id->name + 2;
|
||||
item_tmp.value = i++;
|
||||
|
||||
/* Show collection color tag icons in menus. */
|
||||
if (GS(id->name) == ID_GR) {
|
||||
item_tmp.icon = UI_collection_color_icon_get((Collection *)id);
|
||||
}
|
||||
|
||||
RNA_enum_item_add(&item, &totitem, &item_tmp);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user