Compare commits
236 Commits
temp-cpp-g
...
soc-2019-o
Author | SHA1 | Date | |
---|---|---|---|
723d05070a | |||
0e2b56ed71 | |||
d156139cbc | |||
28ee7e60c5 | |||
8c3b3a982b | |||
90e07364ac | |||
6e11d5f6fc | |||
5d52524b96 | |||
99bf3d275c | |||
705b4f2ef0 | |||
d934a78d10 | |||
9494c3df53 | |||
e088ee55f7 | |||
16c18c5bfb | |||
ec3cd8d400 | |||
919d1b53ae | |||
dbed7dba22 | |||
7e7b073712 | |||
340fc634ad | |||
1ed65f1cbd | |||
f4373aa3a7 | |||
0683b716a0 | |||
dd9dbc05ee | |||
aaf3ed3db0 | |||
dae8db68e9 | |||
d030770449 | |||
48679697e5 | |||
22fea4852f | |||
fd89431861 | |||
c08ac7562c | |||
367a944541 | |||
6c52eb2183 | |||
1760a6e8cd | |||
67f9c22f54 | |||
c2b752b268 | |||
3da5106dac | |||
2a4ab7ed9a | |||
2608109308 | |||
6bf5959fa2 | |||
47b478eb68 | |||
52acbc43f0 | |||
e4516299a0 | |||
5a93b1a51c | |||
63074fc889 | |||
fccf729f09 | |||
6f208b9024 | |||
364e7e0849 | |||
e4f23f7e17 | |||
e55e23a9d5 | |||
7eb5f9501a | |||
ed35d00fc2 | |||
9a9924894c | |||
c8c85907b4 | |||
5283f90bd0 | |||
091736088e | |||
2120a65391 | |||
ca8086663c | |||
1e037295d8 | |||
6fdad0afbc | |||
bb795b2119 | |||
7213f1775c | |||
5dcbc32067 | |||
eb33e0369f | |||
389abca671 | |||
98af6c8ce3 | |||
673323251c | |||
18ac5447ad | |||
3cbf9956e4 | |||
c4a4ba004a | |||
6267d647ae | |||
fe03e52227 | |||
c47018f603 | |||
65bad61cee | |||
598a4104a6 | |||
bdea5d6e01 | |||
e257f3c75e | |||
badb172cc3 | |||
f2cc499a04 | |||
499c47a974 | |||
6334ff86cb | |||
d50b8c0bfb | |||
955c9dd98b | |||
ec9dfb21d7 | |||
4b786c0a0c | |||
504542da09 | |||
d3c083f5be | |||
88a2c57827 | |||
f38c8b84b7 | |||
e1af790d2d | |||
e2174037c6 | |||
421b0bc443 | |||
70dd380d72 | |||
27da9edb1d | |||
006c8add7b | |||
8f37592666 | |||
6ac50f4bea | |||
b6405d001a | |||
b22c84d780 | |||
927ffd4a52 | |||
3958c90871 | |||
229578c9e5 | |||
3997ccdb73 | |||
807f95bf7a | |||
3d99c71837 | |||
8184c39ca7 | |||
6513d55636 | |||
8637d8dcb3 | |||
8f2c296e22 | |||
cd0e42c065 | |||
cd00f29061 | |||
eed6d1dcf1 | |||
1becd16042 | |||
1986efe44d | |||
f7310fae94 | |||
dbcce31ad3 | |||
e664a324f1 | |||
9d28b8ae3f | |||
b4118991e7 | |||
e4c17ee9d1 | |||
dda15a3e69 | |||
e63b87fb4d | |||
93c4e1e369 | |||
5bb9fce0cd | |||
5962ff5da4 | |||
185e8183fa | |||
f8ca71e66a | |||
d75d2860fd | |||
de5589f0ff | |||
aa6c8f609c | |||
210600e7f6 | |||
a78b73ac6f | |||
d2ea9f7bed | |||
b73fc56dfa | |||
e0bd7e67c1 | |||
137397836a | |||
c90bc0175c | |||
a284ca9d39 | |||
fd917935d1 | |||
f04988e357 | |||
ddcb635ceb | |||
8e25a19a05 | |||
c40ec17fd3 | |||
63076a7d7f | |||
92f2d8b86b | |||
6c3564bff9 | |||
89c156d888 | |||
12283cdec8 | |||
7a78c32b58 | |||
064c4396c7 | |||
1f37ee140b | |||
a9ee8d49b4 | |||
65c3f3e520 | |||
f4948d2ce7 | |||
c8aed23a1c | |||
9605cebdd2 | |||
35b5395f2a | |||
5992e6c3e6 | |||
7b7772e180 | |||
ff6c1027bd | |||
c91148c966 | |||
3f52689590 | |||
cc3f7abbb0 | |||
d5ad3d6fc8 | |||
6ee77a28a8 | |||
7b440e5796 | |||
c68dff9ff7 | |||
e191fb3bda | |||
3de1bd9b38 | |||
30e48c6c6a | |||
e4ed727f43 | |||
a4b99522f0 | |||
55e95e84d7 | |||
89c0a27651 | |||
883399072f | |||
99ceaf2ecc | |||
3906d6d500 | |||
20ae943bf4 | |||
801e973aa8 | |||
64c5417017 | |||
56314980ac | |||
6c82357176 | |||
fb439d5a87 | |||
a3688f0924 | |||
6864873372 | |||
0bc6448746 | |||
d1227026aa | |||
26b55532ba | |||
7979534279 | |||
33f237d04c | |||
516cfd2250 | |||
93de8cf127 | |||
2edb0f10c5 | |||
bb89b6788d | |||
e96f32a0ee | |||
248060c884 | |||
d2493bdd77 | |||
1840fd4fa8 | |||
ad1ff2b601 | |||
213d0d6f70 | |||
8ee6fd8866 | |||
e680755ad7 | |||
cae3c781e7 | |||
0be0559fd1 | |||
c042f82b89 | |||
f5ccf5f035 | |||
59955efb07 | |||
886670fb63 | |||
5d7a7dd7a0 | |||
b5d22f77e7 | |||
43dedae029 | |||
0f998b27fc | |||
c68ffd3394 | |||
07f938be38 | |||
729c81d947 | |||
3627e5b8d3 | |||
a3acc8296c | |||
33502f6d2b | |||
73392fc29b | |||
9f4d65e488 | |||
b1a88dab43 | |||
aeba4958e5 | |||
c5ff3aecc3 | |||
cac85a4ecb | |||
333aa010bb | |||
155cb8505c | |||
94be4ea6cf | |||
558679a19e | |||
cdbd48b310 | |||
593aa62bce | |||
fda3351c88 | |||
6cc800d845 | |||
3bedf72319 | |||
b2a716e033 | |||
4ccf9a5b75 | |||
ed299c0f9d | |||
a3448a9eef |
@@ -748,7 +748,8 @@ const bTheme U_theme_default = {
|
||||
.outline_width = 1,
|
||||
.facedot_size = 4,
|
||||
.match = RGBA(0x337f334c),
|
||||
.selected_highlight = RGBA(0x314e784c),
|
||||
.selected_highlight = RGBA(0x223a5bff),
|
||||
.active = RGBA(0x3b5689ff),
|
||||
.selected_object = RGBA(0xe96a00ff),
|
||||
.active_object = RGBA(0xffaf29ff),
|
||||
.edited_object = RGBA(0x00806266),
|
||||
|
@@ -974,6 +974,7 @@
|
||||
<ThemeOutliner
|
||||
match="#337f33"
|
||||
selected_highlight="#7a8e99"
|
||||
active="#92aab7"
|
||||
selected_object="#ffddb3"
|
||||
active_object="#ffffff"
|
||||
edited_object="#0080624d"
|
||||
|
@@ -700,20 +700,37 @@ def km_outliner(params):
|
||||
items.extend([
|
||||
("outliner.highlight_update", {"type": 'MOUSEMOVE', "value": 'ANY', "any": True}, None),
|
||||
("outliner.item_rename", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK'}, None),
|
||||
("outliner.item_rename", {"type": 'F2', "value": 'PRESS'}, None),
|
||||
("outliner.item_activate", {"type": 'LEFTMOUSE', "value": 'CLICK'},
|
||||
{"properties": [("extend", False), ("recursive", False), ("deselect_all", not params.legacy)]}),
|
||||
("outliner.item_activate", {"type": 'LEFTMOUSE', "value": 'CLICK', "shift": True},
|
||||
{"properties": [("extend", True), ("recursive", False)]}),
|
||||
{"properties": [("extend", False), ("deselect_all", not params.legacy)]}),
|
||||
("outliner.item_activate", {"type": 'LEFTMOUSE', "value": 'CLICK', "ctrl": True},
|
||||
{"properties": [("extend", False), ("recursive", True)]}),
|
||||
("outliner.item_activate", {"type": 'LEFTMOUSE', "value": 'CLICK', "shift": True, "ctrl": True},
|
||||
{"properties": [("extend", True), ("recursive", True)]}),
|
||||
{"properties": [("extend", True), ("deselect_all", not params.legacy)]}),
|
||||
("outliner.item_activate", {"type": 'LEFTMOUSE', "value": 'CLICK', "shift": True},
|
||||
{"properties": [("extend", False), ("extend_range", True), ("deselect_all", not params.legacy)]}),
|
||||
("outliner.select_box", {"type": 'B', "value": 'PRESS'}, None),
|
||||
("outliner.item_openclose", {"type": 'RET', "value": 'PRESS'},
|
||||
("outliner.select_box", {"type": 'EVT_TWEAK_L', "value": 'ANY'}, {"properties": [("tweak", True)]}),
|
||||
("outliner.select_box", {"type": 'EVT_TWEAK_L', "value": 'ANY', "shift": True},
|
||||
{"properties": [("tweak", True), ("mode", "ADD")]}),
|
||||
("outliner.select_box", {"type": 'EVT_TWEAK_L', "value": 'ANY', "ctrl": True},
|
||||
{"properties": [("tweak", True), ("mode", "SUB")]}),
|
||||
("outliner.select_walk", {"type": 'UP_ARROW', "value": 'PRESS'}, {"properties": [("direction", 'UP')]}),
|
||||
("outliner.select_walk", {"type": 'UP_ARROW', "value": 'PRESS', "shift": True},
|
||||
{"properties": [("direction", 'UP'), ("extend", True)]}),
|
||||
("outliner.select_walk", {"type": 'DOWN_ARROW', "value": 'PRESS'}, {"properties": [("direction", 'DOWN')]}),
|
||||
("outliner.select_walk", {"type": 'DOWN_ARROW', "value": 'PRESS', "shift": True},
|
||||
{"properties": [("direction", 'DOWN'), ("extend", True)]}),
|
||||
("outliner.select_walk", {"type": 'LEFT_ARROW', "value": 'PRESS'}, {"properties": [("direction", 'LEFT')]}),
|
||||
("outliner.select_walk", {"type": 'LEFT_ARROW', "value": 'PRESS', "shift": True},
|
||||
{"properties": [("direction", 'LEFT'), ("toggle_all", True)]}),
|
||||
("outliner.select_walk", {"type": 'RIGHT_ARROW', "value": 'PRESS'}, {"properties": [("direction", 'RIGHT')]}),
|
||||
("outliner.select_walk", {"type": 'RIGHT_ARROW', "value": 'PRESS', "shift": True},
|
||||
{"properties": [("direction", 'RIGHT'), ("toggle_all", True)]}),
|
||||
("outliner.item_openclose", {"type": 'LEFTMOUSE', "value": 'CLICK'},
|
||||
{"properties": [("all", False)]}),
|
||||
("outliner.item_openclose", {"type": 'RET', "value": 'PRESS', "shift": True},
|
||||
("outliner.item_openclose", {"type": 'LEFTMOUSE', "value": 'CLICK', "shift": True},
|
||||
{"properties": [("all", True)]}),
|
||||
("outliner.item_rename", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True}, None),
|
||||
("outliner.item_openclose", {"type": 'EVT_TWEAK_L', "value": 'ANY'},
|
||||
{"properties": [("all", False)]}),
|
||||
("outliner.operation", {"type": 'RIGHTMOUSE', "value": 'PRESS'}, None),
|
||||
("outliner.item_drag_drop", {"type": 'EVT_TWEAK_L', "value": 'ANY'}, None),
|
||||
("outliner.item_drag_drop", {"type": 'EVT_TWEAK_L', "value": 'ANY', "shift": True}, None),
|
||||
|
@@ -46,6 +46,10 @@ class OUTLINER_HT_header(Header):
|
||||
|
||||
layout.separator_spacer()
|
||||
|
||||
if display_mode == 'SEQUENCE':
|
||||
row = layout.row(align=True)
|
||||
row.prop(space, "use_sync_select", icon="UV_SYNC_SELECT", text="")
|
||||
|
||||
row = layout.row(align=True)
|
||||
if display_mode in {'SCENES', 'VIEW_LAYER'}:
|
||||
row.popover(
|
||||
@@ -328,6 +332,10 @@ class OUTLINER_PT_filter(Panel):
|
||||
col.prop(space, "use_sort_alpha")
|
||||
layout.separator()
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.prop(space, "use_sync_select", text="Sync Selection")
|
||||
layout.separator()
|
||||
|
||||
col = layout.column(align=True)
|
||||
col.label(text="Search:")
|
||||
col.prop(space, "use_filter_complete", text="Exact Match")
|
||||
|
@@ -493,6 +493,36 @@ static LayerCollection *collection_from_index(ListBase *lb, const int number, in
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a collection is hidden, viewport visibility restricted, or excluded
|
||||
*/
|
||||
static bool layer_collection_hidden(ViewLayer *view_layer, LayerCollection *lc)
|
||||
{
|
||||
if (lc->flag & LAYER_COLLECTION_EXCLUDE) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Check visiblilty restriction flags */
|
||||
if (lc->flag & LAYER_COLLECTION_HIDE || lc->collection->flag & COLLECTION_RESTRICT_VIEWPORT) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
/* Restriction flags stay set, so we need to check parents */
|
||||
CollectionParent *parent = lc->collection->parents.first;
|
||||
|
||||
if (parent) {
|
||||
lc = BKE_layer_collection_first_from_scene_collection(view_layer, parent->collection);
|
||||
|
||||
return lc && layer_collection_hidden(view_layer, lc);
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the collection for a given index
|
||||
*/
|
||||
@@ -537,8 +567,9 @@ LayerCollection *BKE_layer_collection_activate_parent(ViewLayer *view_layer, Lay
|
||||
lc = NULL;
|
||||
}
|
||||
|
||||
if (lc && (lc->flag & LAYER_COLLECTION_EXCLUDE)) {
|
||||
/* Don't activate excluded collections. */
|
||||
/* Don't activate excluded or hidden collections to prevent creating objects in a hidden
|
||||
* collection from the UI */
|
||||
if (lc && layer_collection_hidden(view_layer, lc)) {
|
||||
return BKE_layer_collection_activate_parent(view_layer, lc);
|
||||
}
|
||||
|
||||
@@ -817,8 +848,7 @@ void BKE_layer_collection_sync(const Scene *scene, ViewLayer *view_layer)
|
||||
|
||||
/* Always set a valid active collection. */
|
||||
LayerCollection *active = view_layer->active_collection;
|
||||
|
||||
if (active && (active->flag & LAYER_COLLECTION_EXCLUDE)) {
|
||||
if (active && layer_collection_hidden(view_layer, active)) {
|
||||
BKE_layer_collection_activate_parent(view_layer, active);
|
||||
}
|
||||
else if (active == NULL) {
|
||||
|
@@ -3644,6 +3644,19 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
|
||||
LISTBASE_FOREACH (bArmature *, arm, &bmain->armatures) {
|
||||
arm->flag &= ~(ARM_FLAG_UNUSED_6);
|
||||
}
|
||||
|
||||
/* Marks each outliner as dirty so a sync will occur as an outliner draws. */
|
||||
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
|
||||
for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
|
||||
for (SpaceLink *space = sa->spacedata.first; space; space = space->next) {
|
||||
if (space->spacetype == SPACE_OUTLINER) {
|
||||
SpaceOutliner *soutliner = (SpaceOutliner *)space;
|
||||
soutliner->sync_select_dirty |= WM_OUTLINER_SYNC_SELECT_FROM_ALL;
|
||||
soutliner->flag |= SO_SYNC_SELECT;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!MAIN_VERSION_ATLEAST(bmain, 281, 1)) {
|
||||
|
@@ -141,6 +141,9 @@ static void do_versions_theme(const UserDef *userdef, bTheme *btheme)
|
||||
FROM_DEFAULT_V4_UCHAR(space_outliner.row_alternate);
|
||||
}
|
||||
|
||||
FROM_DEFAULT_V4_UCHAR(space_outliner.selected_highlight);
|
||||
FROM_DEFAULT_V4_UCHAR(space_outliner.active);
|
||||
|
||||
/**
|
||||
* Include next version bump.
|
||||
*/
|
||||
|
@@ -46,6 +46,7 @@
|
||||
|
||||
#include "ED_armature.h"
|
||||
#include "ED_object.h"
|
||||
#include "ED_outliner.h"
|
||||
#include "ED_screen.h"
|
||||
#include "ED_select_utils.h"
|
||||
#include "ED_view3d.h"
|
||||
@@ -356,6 +357,8 @@ static int armature_select_linked_invoke(bContext *C, wmOperator *op, const wmEv
|
||||
}
|
||||
}
|
||||
|
||||
ED_outliner_select_sync_from_edit_bone_tag(C);
|
||||
|
||||
ED_armature_edit_sync_selection(arm->edbo);
|
||||
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, base->object);
|
||||
@@ -1027,6 +1030,8 @@ static int armature_de_select_all_exec(bContext *C, wmOperator *op)
|
||||
}
|
||||
CTX_DATA_END;
|
||||
|
||||
ED_outliner_select_sync_from_edit_bone_tag(C);
|
||||
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, NULL);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
@@ -1148,6 +1153,8 @@ static int armature_de_select_more_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
|
||||
}
|
||||
MEM_freeN(objects);
|
||||
|
||||
ED_outliner_select_sync_from_edit_bone_tag(C);
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
@@ -1178,6 +1185,8 @@ static int armature_de_select_less_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
|
||||
}
|
||||
MEM_freeN(objects);
|
||||
|
||||
ED_outliner_select_sync_from_edit_bone_tag(C);
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
@@ -1569,6 +1578,8 @@ static int armature_select_similar_exec(bContext *C, wmOperator *op)
|
||||
|
||||
#undef STRUCT_SIZE_AND_OFFSET
|
||||
|
||||
ED_outliner_select_sync_from_edit_bone_tag(C);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
@@ -1663,6 +1674,8 @@ static int armature_select_hierarchy_exec(bContext *C, wmOperator *op)
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
ED_outliner_select_sync_from_edit_bone_tag(C);
|
||||
|
||||
ED_armature_edit_sync_selection(arm->edbo);
|
||||
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
|
||||
@@ -1748,6 +1761,8 @@ static int armature_select_mirror_exec(bContext *C, wmOperator *op)
|
||||
arm->act_edbone = ebone_mirror_act;
|
||||
}
|
||||
|
||||
ED_outliner_select_sync_from_edit_bone_tag(C);
|
||||
|
||||
ED_armature_edit_sync_selection(arm->edbo);
|
||||
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
|
||||
@@ -1876,6 +1891,7 @@ static int armature_shortest_path_pick_invoke(bContext *C, wmOperator *op, const
|
||||
|
||||
if (changed) {
|
||||
arm->act_edbone = ebone_dst;
|
||||
ED_outliner_select_sync_from_edit_bone_tag(C);
|
||||
ED_armature_edit_sync_selection(arm->edbo);
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
|
||||
|
||||
|
@@ -54,6 +54,7 @@
|
||||
#include "ED_keyframing.h"
|
||||
#include "ED_mesh.h"
|
||||
#include "ED_object.h"
|
||||
#include "ED_outliner.h"
|
||||
#include "ED_screen.h"
|
||||
#include "ED_select_utils.h"
|
||||
#include "ED_view3d.h"
|
||||
@@ -449,6 +450,8 @@ static int pose_select_connected_invoke(bContext *C, wmOperator *op, const wmEve
|
||||
selectconnected_posebonechildren(base->object, curBone, extend);
|
||||
}
|
||||
|
||||
ED_outliner_select_sync_from_pose_bone_tag(C);
|
||||
|
||||
ED_pose_bone_select_tag_update(base->object);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
@@ -514,6 +517,8 @@ static int pose_de_select_all_exec(bContext *C, wmOperator *op)
|
||||
}
|
||||
CTX_DATA_END;
|
||||
|
||||
ED_outliner_select_sync_from_pose_bone_tag(C);
|
||||
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, NULL);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
@@ -560,6 +565,8 @@ static int pose_select_parent_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
ED_outliner_select_sync_from_pose_bone_tag(C);
|
||||
|
||||
ED_pose_bone_select_tag_update(ob);
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
@@ -624,6 +631,8 @@ static int pose_select_constraint_target_exec(bContext *C, wmOperator *UNUSED(op
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
ED_outliner_select_sync_from_pose_bone_tag(C);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
@@ -712,6 +721,8 @@ static int pose_select_hierarchy_exec(bContext *C, wmOperator *op)
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
ED_outliner_select_sync_from_pose_bone_tag(C);
|
||||
|
||||
ED_pose_bone_select_tag_update(ob);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
@@ -1061,6 +1072,8 @@ static int pose_select_grouped_exec(bContext *C, wmOperator *op)
|
||||
|
||||
/* report done status */
|
||||
if (changed) {
|
||||
ED_outliner_select_sync_from_pose_bone_tag(C);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
else {
|
||||
@@ -1172,6 +1185,8 @@ static int pose_select_mirror_exec(bContext *C, wmOperator *op)
|
||||
}
|
||||
MEM_freeN(objects);
|
||||
|
||||
ED_outliner_select_sync_from_pose_bone_tag(C);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
|
@@ -30,4 +30,17 @@ bool ED_outliner_collections_editor_poll(struct bContext *C);
|
||||
|
||||
void ED_outliner_selected_objects_get(const struct bContext *C, struct ListBase *objects);
|
||||
|
||||
Base *ED_outliner_give_base_under_cursor(struct bContext *C, const int mval[2]);
|
||||
|
||||
void ED_outliner_select_sync_from_object_tag(struct bContext *C);
|
||||
void ED_outliner_select_sync_from_edit_bone_tag(struct bContext *C);
|
||||
void ED_outliner_select_sync_from_pose_bone_tag(struct bContext *C);
|
||||
void ED_outliner_select_sync_from_sequence_tag(struct bContext *C);
|
||||
|
||||
bool ED_outliner_select_sync_is_dirty(const struct bContext *C);
|
||||
|
||||
void ED_outliner_select_sync_from_outliner(struct bContext *C, struct SpaceOutliner *soops);
|
||||
|
||||
void ED_outliner_select_sync_flag_outliners(const struct bContext *C);
|
||||
|
||||
#endif /* __ED_OUTLINER_H__ */
|
||||
|
@@ -255,6 +255,7 @@ typedef enum ThemeColorID {
|
||||
|
||||
TH_MATCH, /* highlight color for search matches */
|
||||
TH_SELECT_HIGHLIGHT, /* highlight color for selected outliner item */
|
||||
TH_SELECT_ACTIVE, /* highlight color for active outliner item */
|
||||
TH_SELECTED_OBJECT, /* selected object color for outliner */
|
||||
TH_ACTIVE_OBJECT, /* active object color for outliner */
|
||||
TH_EDITED_OBJECT, /* edited object color for outliner */
|
||||
|
@@ -51,6 +51,7 @@
|
||||
#include "ED_space_api.h"
|
||||
#include "ED_screen.h"
|
||||
#include "ED_view3d.h"
|
||||
#include "ED_outliner.h"
|
||||
|
||||
#include "interface_intern.h"
|
||||
#include "interface_eyedropper_intern.h"
|
||||
@@ -67,6 +68,7 @@ typedef struct DataDropper {
|
||||
|
||||
ID *init_id; /* for resetting on cancel */
|
||||
|
||||
ScrArea *cursor_area; /* Area under the cursor */
|
||||
ARegionType *art;
|
||||
void *draw_handle_pixel;
|
||||
char name[200];
|
||||
@@ -103,6 +105,7 @@ static int datadropper_init(bContext *C, wmOperator *op)
|
||||
|
||||
ddr->is_undo = UI_but_flag_is_set(but, UI_BUT_UNDO);
|
||||
|
||||
ddr->cursor_area = CTX_wm_area(C);
|
||||
ddr->art = art;
|
||||
ddr->draw_handle_pixel = ED_region_draw_cb_activate(
|
||||
art, datadropper_draw_cb, ddr, REGION_DRAW_POST_PIXEL);
|
||||
@@ -141,7 +144,7 @@ static void datadropper_exit(bContext *C, wmOperator *op)
|
||||
|
||||
/* *** datadropper id helper functions *** */
|
||||
/**
|
||||
* \brief get the ID from the screen.
|
||||
* \brief get the ID from the 3D view or outliner.
|
||||
*/
|
||||
static void datadropper_id_sample_pt(bContext *C, DataDropper *ddr, int mx, int my, ID **r_id)
|
||||
{
|
||||
@@ -155,7 +158,7 @@ static void datadropper_id_sample_pt(bContext *C, DataDropper *ddr, int mx, int
|
||||
ddr->name[0] = '\0';
|
||||
|
||||
if (sa) {
|
||||
if (sa->spacetype == SPACE_VIEW3D) {
|
||||
if (ELEM(sa->spacetype, SPACE_VIEW3D, SPACE_OUTLINER)) {
|
||||
ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
|
||||
if (ar) {
|
||||
const int mval[2] = {mx - ar->winrct.xmin, my - ar->winrct.ymin};
|
||||
@@ -167,7 +170,13 @@ static void datadropper_id_sample_pt(bContext *C, DataDropper *ddr, int mx, int
|
||||
/* grr, always draw else we leave stale text */
|
||||
ED_region_tag_redraw(ar);
|
||||
|
||||
base = ED_view3d_give_base_under_cursor(C, mval);
|
||||
if (sa->spacetype == SPACE_VIEW3D) {
|
||||
base = ED_view3d_give_base_under_cursor(C, mval);
|
||||
}
|
||||
else {
|
||||
base = ED_outliner_give_base_under_cursor(C, mval);
|
||||
}
|
||||
|
||||
if (base) {
|
||||
Object *ob = base->object;
|
||||
ID *id = NULL;
|
||||
@@ -232,6 +241,36 @@ static void datadropper_cancel(bContext *C, wmOperator *op)
|
||||
datadropper_exit(C, op);
|
||||
}
|
||||
|
||||
/* To switch the draw callback when region under mouse event changes */
|
||||
static void datadropper_set_draw_callback_region(bContext *C,
|
||||
DataDropper *ddr,
|
||||
const int mx,
|
||||
const int my)
|
||||
{
|
||||
bScreen *screen = CTX_wm_screen(C);
|
||||
ScrArea *sa = BKE_screen_find_area_xy(screen, -1, mx, my);
|
||||
|
||||
if (sa) {
|
||||
/* If spacetype changed */
|
||||
if (sa->spacetype != ddr->cursor_area->spacetype) {
|
||||
/* Remove old callback */
|
||||
ED_region_draw_cb_exit(ddr->art, ddr->draw_handle_pixel);
|
||||
|
||||
/* Redraw old area */
|
||||
ARegion *ar = BKE_area_find_region_type(ddr->cursor_area, RGN_TYPE_WINDOW);
|
||||
ED_region_tag_redraw(ar);
|
||||
|
||||
/* Set draw callback in new region */
|
||||
ARegionType *art = BKE_regiontype_from_id(sa->type, RGN_TYPE_WINDOW);
|
||||
|
||||
ddr->cursor_area = sa;
|
||||
ddr->art = art;
|
||||
ddr->draw_handle_pixel = ED_region_draw_cb_activate(
|
||||
art, datadropper_draw_cb, ddr, REGION_DRAW_POST_PIXEL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* main modal status check */
|
||||
static int datadropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
@@ -260,6 +299,10 @@ static int datadropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
}
|
||||
else if (event->type == MOUSEMOVE) {
|
||||
ID *id = NULL;
|
||||
|
||||
/* Set the region for eyedropper cursor text drawing */
|
||||
datadropper_set_draw_callback_region(C, ddr, event->x, event->y);
|
||||
|
||||
datadropper_id_sample_pt(C, ddr, event->x, event->y, &id);
|
||||
}
|
||||
|
||||
|
@@ -2523,7 +2523,7 @@ static uiLayout *draw_constraint(uiLayout *layout, Object *ob, bConstraint *con)
|
||||
|
||||
/* enabled */
|
||||
UI_block_emboss_set(block, UI_EMBOSS_NONE);
|
||||
uiItemR(row, &ptr, "mute", 0, "", (con->flag & CONSTRAINT_OFF) ? ICON_HIDE_ON : ICON_HIDE_OFF);
|
||||
uiItemR(row, &ptr, "mute", 0, "", 0);
|
||||
UI_block_emboss_set(block, UI_EMBOSS);
|
||||
|
||||
uiLayoutSetOperatorContext(row, WM_OP_INVOKE_DEFAULT);
|
||||
|
@@ -794,6 +794,10 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid)
|
||||
cp = ts->selected_highlight;
|
||||
break;
|
||||
|
||||
case TH_SELECT_ACTIVE:
|
||||
cp = ts->active;
|
||||
break;
|
||||
|
||||
case TH_SELECTED_OBJECT:
|
||||
cp = ts->selected_object;
|
||||
break;
|
||||
|
@@ -103,6 +103,7 @@
|
||||
#include "ED_mesh.h"
|
||||
#include "ED_node.h"
|
||||
#include "ED_object.h"
|
||||
#include "ED_outliner.h"
|
||||
#include "ED_physics.h"
|
||||
#include "ED_render.h"
|
||||
#include "ED_screen.h"
|
||||
@@ -502,6 +503,8 @@ Object *ED_object_add_type(bContext *C,
|
||||
/* TODO(sergey): Use proper flag for tagging here. */
|
||||
DEG_id_tag_update(&scene->id, 0);
|
||||
|
||||
ED_outliner_select_sync_from_object_tag(C);
|
||||
|
||||
return ob;
|
||||
}
|
||||
|
||||
|
@@ -69,6 +69,7 @@
|
||||
|
||||
#include "ED_armature.h"
|
||||
#include "ED_object.h"
|
||||
#include "ED_outliner.h"
|
||||
#include "ED_screen.h"
|
||||
#include "ED_select_utils.h"
|
||||
#include "ED_keyframing.h"
|
||||
@@ -436,6 +437,8 @@ static int object_select_by_type_exec(bContext *C, wmOperator *op)
|
||||
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
|
||||
|
||||
ED_outliner_select_sync_from_object_tag(C);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
@@ -717,6 +720,7 @@ static int object_select_linked_exec(bContext *C, wmOperator *op)
|
||||
if (changed) {
|
||||
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
|
||||
ED_outliner_select_sync_from_object_tag(C);
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
@@ -1100,6 +1104,7 @@ static int object_select_grouped_exec(bContext *C, wmOperator *op)
|
||||
if (changed) {
|
||||
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
|
||||
ED_outliner_select_sync_from_object_tag(C);
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
@@ -1150,6 +1155,8 @@ static int object_select_all_exec(bContext *C, wmOperator *op)
|
||||
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
|
||||
|
||||
ED_outliner_select_sync_from_object_tag(C);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
else if (any_visible == false) {
|
||||
@@ -1218,6 +1225,8 @@ static int object_select_same_collection_exec(bContext *C, wmOperator *op)
|
||||
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
|
||||
|
||||
ED_outliner_select_sync_from_object_tag(C);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
@@ -1281,6 +1290,8 @@ static int object_select_mirror_exec(bContext *C, wmOperator *op)
|
||||
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
|
||||
|
||||
ED_outliner_select_sync_from_object_tag(C);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
@@ -1369,6 +1380,9 @@ static int object_select_more_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
|
||||
|
||||
ED_outliner_select_sync_from_object_tag(C);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
else {
|
||||
@@ -1399,6 +1413,9 @@ static int object_select_less_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
|
||||
|
||||
ED_outliner_select_sync_from_object_tag(C);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
else {
|
||||
@@ -1448,6 +1465,8 @@ static int object_select_random_exec(bContext *C, wmOperator *op)
|
||||
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
|
||||
|
||||
ED_outliner_select_sync_from_object_tag(C);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
|
@@ -41,6 +41,7 @@ set(SRC
|
||||
outliner_edit.c
|
||||
outliner_ops.c
|
||||
outliner_select.c
|
||||
outliner_sync.c
|
||||
outliner_tools.c
|
||||
outliner_tree.c
|
||||
outliner_utils.c
|
||||
|
@@ -326,38 +326,57 @@ static bool parent_drop_poll(bContext *C,
|
||||
return false;
|
||||
}
|
||||
|
||||
static int parent_drop_exec(bContext *C, wmOperator *op)
|
||||
static void parent_drop_set_parents(
|
||||
bContext *C, ReportList *reports, wmDragID *drag, Object *parent, short parent_type)
|
||||
{
|
||||
Object *par = NULL, *ob = NULL;
|
||||
Main *bmain = CTX_data_main(C);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
int partype = -1;
|
||||
char parname[MAX_NAME], childname[MAX_NAME];
|
||||
SpaceOutliner *soops = CTX_wm_space_outliner(C);
|
||||
|
||||
partype = RNA_enum_get(op->ptr, "type");
|
||||
RNA_string_get(op->ptr, "parent", parname);
|
||||
par = (Object *)BKE_libblock_find_name(bmain, ID_OB, parname);
|
||||
RNA_string_get(op->ptr, "child", childname);
|
||||
ob = (Object *)BKE_libblock_find_name(bmain, ID_OB, childname);
|
||||
TreeElement *te = outliner_find_id(soops, &soops->tree, &parent->id);
|
||||
Scene *scene = (Scene *)outliner_search_back(soops, te, ID_SCE);
|
||||
|
||||
if (ID_IS_LINKED(ob)) {
|
||||
BKE_report(op->reports, RPT_INFO, "Can't edit library linked object");
|
||||
return OPERATOR_CANCELLED;
|
||||
if (scene == NULL) {
|
||||
/* currently outliner organized in a way, that if there's no parent scene
|
||||
* element for object it means that all displayed objects belong to
|
||||
* active scene and parenting them is allowed (sergey)
|
||||
*/
|
||||
|
||||
scene = CTX_data_scene(C);
|
||||
}
|
||||
|
||||
ED_object_parent_set(op->reports, C, scene, ob, par, partype, false, false, NULL);
|
||||
bool parent_set = false;
|
||||
bool linked_objects = false;
|
||||
|
||||
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);
|
||||
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;
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
/* Do nothing to linked data */
|
||||
if (ID_IS_LINKED(object)) {
|
||||
linked_objects = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ED_object_parent_set(
|
||||
reports, C, scene, object, parent, parent_type, false, false, NULL)) {
|
||||
parent_set = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (linked_objects) {
|
||||
BKE_report(reports, RPT_INFO, "Can't edit library linked object(s)");
|
||||
}
|
||||
|
||||
if (parent_set) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
SpaceOutliner *soops = CTX_wm_space_outliner(C);
|
||||
TreeElement *te = outliner_drop_find(C, event);
|
||||
TreeStoreElem *tselem = te ? TREESTORE(te) : NULL;
|
||||
|
||||
@@ -374,107 +393,15 @@ static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
if (ob == par) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
if (ID_IS_LINKED(ob)) {
|
||||
BKE_report(op->reports, RPT_INFO, "Can't edit library linked object");
|
||||
|
||||
if (event->custom != EVT_DATA_DRAGDROP) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
char childname[MAX_NAME];
|
||||
char parname[MAX_NAME];
|
||||
STRNCPY(childname, ob->id.name + 2);
|
||||
STRNCPY(parname, par->id.name + 2);
|
||||
RNA_string_set(op->ptr, "child", childname);
|
||||
RNA_string_set(op->ptr, "parent", parname);
|
||||
ListBase *lb = event->customdata;
|
||||
wmDrag *drag = lb->first;
|
||||
|
||||
Scene *scene = (Scene *)outliner_search_back(soops, te, ID_SCE);
|
||||
|
||||
if (scene == NULL) {
|
||||
/* currently outlier organized in a way, that if there's no parent scene
|
||||
* element for object it means that all displayed objects belong to
|
||||
* active scene and parenting them is allowed (sergey)
|
||||
*/
|
||||
|
||||
scene = CTX_data_scene(C);
|
||||
}
|
||||
|
||||
if ((par->type != OB_ARMATURE) && (par->type != OB_CURVE) && (par->type != OB_LATTICE)) {
|
||||
int partype = 0;
|
||||
if (ED_object_parent_set(op->reports, C, scene, ob, par, partype, false, false, NULL)) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Menu creation */
|
||||
wmOperatorType *ot = WM_operatortype_find("OUTLINER_OT_parent_drop", false);
|
||||
uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("Set Parent To"), ICON_NONE);
|
||||
uiLayout *layout = UI_popup_menu_layout(pup);
|
||||
PointerRNA ptr;
|
||||
|
||||
/* Cannot use uiItemEnumO()... have multiple properties to set. */
|
||||
uiItemFullO_ptr(layout, ot, IFACE_("Object"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr);
|
||||
RNA_string_set(&ptr, "parent", parname);
|
||||
RNA_string_set(&ptr, "child", childname);
|
||||
RNA_enum_set(&ptr, "type", PAR_OBJECT);
|
||||
|
||||
/* par becomes parent, make the associated menus */
|
||||
if (par->type == OB_ARMATURE) {
|
||||
uiItemFullO_ptr(layout, ot, IFACE_("Armature Deform"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr);
|
||||
RNA_string_set(&ptr, "parent", parname);
|
||||
RNA_string_set(&ptr, "child", childname);
|
||||
RNA_enum_set(&ptr, "type", PAR_ARMATURE);
|
||||
|
||||
uiItemFullO_ptr(
|
||||
layout, ot, IFACE_(" With Empty Groups"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr);
|
||||
RNA_string_set(&ptr, "parent", parname);
|
||||
RNA_string_set(&ptr, "child", childname);
|
||||
RNA_enum_set(&ptr, "type", PAR_ARMATURE_NAME);
|
||||
|
||||
uiItemFullO_ptr(
|
||||
layout, ot, IFACE_(" With Envelope Weights"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr);
|
||||
RNA_string_set(&ptr, "parent", parname);
|
||||
RNA_string_set(&ptr, "child", childname);
|
||||
RNA_enum_set(&ptr, "type", PAR_ARMATURE_ENVELOPE);
|
||||
|
||||
uiItemFullO_ptr(
|
||||
layout, ot, IFACE_(" With Automatic Weights"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr);
|
||||
RNA_string_set(&ptr, "parent", parname);
|
||||
RNA_string_set(&ptr, "child", childname);
|
||||
RNA_enum_set(&ptr, "type", PAR_ARMATURE_AUTO);
|
||||
|
||||
uiItemFullO_ptr(layout, ot, IFACE_("Bone"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr);
|
||||
RNA_string_set(&ptr, "parent", parname);
|
||||
RNA_string_set(&ptr, "child", childname);
|
||||
RNA_enum_set(&ptr, "type", PAR_BONE);
|
||||
}
|
||||
else if (par->type == OB_CURVE) {
|
||||
uiItemFullO_ptr(layout, ot, IFACE_("Curve Deform"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr);
|
||||
RNA_string_set(&ptr, "parent", parname);
|
||||
RNA_string_set(&ptr, "child", childname);
|
||||
RNA_enum_set(&ptr, "type", PAR_CURVE);
|
||||
|
||||
uiItemFullO_ptr(layout, ot, IFACE_("Follow Path"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr);
|
||||
RNA_string_set(&ptr, "parent", parname);
|
||||
RNA_string_set(&ptr, "child", childname);
|
||||
RNA_enum_set(&ptr, "type", PAR_FOLLOW);
|
||||
|
||||
uiItemFullO_ptr(layout, ot, IFACE_("Path Constraint"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr);
|
||||
RNA_string_set(&ptr, "parent", parname);
|
||||
RNA_string_set(&ptr, "child", childname);
|
||||
RNA_enum_set(&ptr, "type", PAR_PATH_CONST);
|
||||
}
|
||||
else if (par->type == OB_LATTICE) {
|
||||
uiItemFullO_ptr(layout, ot, IFACE_("Lattice Deform"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr);
|
||||
RNA_string_set(&ptr, "parent", parname);
|
||||
RNA_string_set(&ptr, "child", childname);
|
||||
RNA_enum_set(&ptr, "type", PAR_LATTICE);
|
||||
}
|
||||
|
||||
UI_popup_menu_end(C, pup);
|
||||
|
||||
return OPERATOR_INTERFACE;
|
||||
}
|
||||
parent_drop_set_parents(C, op->reports, drag->ids.first, par, PAR_OBJECT);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
@@ -488,17 +415,11 @@ void OUTLINER_OT_parent_drop(wmOperatorType *ot)
|
||||
|
||||
/* api callbacks */
|
||||
ot->invoke = parent_drop_invoke;
|
||||
ot->exec = parent_drop_exec;
|
||||
|
||||
ot->poll = ED_operator_outliner_active;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
|
||||
|
||||
/* properties */
|
||||
RNA_def_string(ot->srna, "child", "Object", MAX_NAME, "Child", "Child Object");
|
||||
RNA_def_string(ot->srna, "parent", "Object", MAX_NAME, "Parent", "Parent Object");
|
||||
RNA_def_enum(ot->srna, "type", prop_make_parent_types, 0, "Type", "");
|
||||
}
|
||||
|
||||
/* ******************** Parent Clear Operator *********************** */
|
||||
@@ -549,13 +470,21 @@ static bool parent_clear_poll(bContext *C,
|
||||
static int parent_clear_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
|
||||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
Object *ob = (Object *)WM_drag_ID_from_event(event, ID_OB);
|
||||
|
||||
if (ob == NULL) {
|
||||
if (event->custom != EVT_DATA_DRAGDROP) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
ED_object_parent_clear(ob, 0);
|
||||
ListBase *lb = event->customdata;
|
||||
wmDrag *drag = lb->first;
|
||||
|
||||
for (wmDragID *drag_id = drag->ids.first; drag_id; drag_id = drag_id->next) {
|
||||
if (GS(drag_id->id->name) == ID_OB) {
|
||||
Object *object = (Object *)drag_id->id;
|
||||
|
||||
ED_object_parent_clear(object, 0);
|
||||
}
|
||||
}
|
||||
|
||||
DEG_relations_tag_update(bmain);
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
|
||||
@@ -966,6 +895,12 @@ static int outliner_item_drag_drop_invoke(bContext *C,
|
||||
return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH);
|
||||
}
|
||||
|
||||
float view_mval[2];
|
||||
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &view_mval[0], &view_mval[1]);
|
||||
if (outliner_item_is_co_within_close_toggle(te, view_mval[0])) {
|
||||
return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH);
|
||||
}
|
||||
|
||||
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)) {
|
||||
|
@@ -31,6 +31,7 @@
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
#include "DNA_sequence_types.h"
|
||||
#include "DNA_constraint_types.h"
|
||||
#include "DNA_object_force_types.h"
|
||||
|
||||
#include "BLI_math.h"
|
||||
@@ -60,6 +61,7 @@
|
||||
#include "ED_armature.h"
|
||||
#include "ED_keyframing.h"
|
||||
#include "ED_object.h"
|
||||
#include "ED_outliner.h"
|
||||
#include "ED_screen.h"
|
||||
|
||||
#include "WM_api.h"
|
||||
@@ -848,6 +850,7 @@ typedef struct RestrictProperties {
|
||||
PropertyRNA *layer_collection_holdout, *layer_collection_indirect_only,
|
||||
*layer_collection_hide_viewport;
|
||||
PropertyRNA *modifier_show_viewport, *modifier_show_render;
|
||||
PropertyRNA *constraint_enable;
|
||||
} RestrictProperties;
|
||||
|
||||
/* We don't care about the value of the property
|
||||
@@ -865,6 +868,7 @@ typedef struct RestrictPropertiesActive {
|
||||
bool layer_collection_hide_viewport;
|
||||
bool modifier_show_viewport;
|
||||
bool modifier_show_render;
|
||||
bool constraint_enable;
|
||||
} RestrictPropertiesActive;
|
||||
|
||||
static void outliner_restrict_properties_enable_collection_set(
|
||||
@@ -878,6 +882,7 @@ static void outliner_restrict_properties_enable_collection_set(
|
||||
props_active->layer_collection_indirect_only = false;
|
||||
props_active->object_hide_render = false;
|
||||
props_active->modifier_show_render = false;
|
||||
props_active->constraint_enable = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -891,6 +896,7 @@ static void outliner_restrict_properties_enable_collection_set(
|
||||
props_active->object_hide_viewport = false;
|
||||
props_active->base_hide_viewport = false;
|
||||
props_active->modifier_show_viewport = false;
|
||||
props_active->constraint_enable = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -995,6 +1001,8 @@ static void outliner_draw_restrictbuts(uiBlock *block,
|
||||
props.modifier_show_viewport = RNA_struct_type_find_property(&RNA_Modifier, "show_viewport");
|
||||
props.modifier_show_render = RNA_struct_type_find_property(&RNA_Modifier, "show_render");
|
||||
|
||||
props.constraint_enable = RNA_struct_type_find_property(&RNA_Constraint, "mute");
|
||||
|
||||
props.initialized = true;
|
||||
}
|
||||
|
||||
@@ -1181,6 +1189,35 @@ static void outliner_draw_restrictbuts(uiBlock *block,
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (tselem->type == TSE_CONSTRAINT) {
|
||||
bConstraint *con = (bConstraint *)te->directdata;
|
||||
|
||||
PointerRNA ptr;
|
||||
RNA_pointer_create(tselem->id, &RNA_Constraint, con, &ptr);
|
||||
|
||||
if (soops->show_restrict_flags & SO_RESTRICT_HIDE) {
|
||||
bt = uiDefIconButR_prop(block,
|
||||
UI_BTYPE_ICON_TOGGLE,
|
||||
0,
|
||||
0,
|
||||
(int)(ar->v2d.cur.xmax - restrict_offsets.hide),
|
||||
te->ys,
|
||||
UI_UNIT_X,
|
||||
UI_UNIT_Y,
|
||||
&ptr,
|
||||
props.constraint_enable,
|
||||
-1,
|
||||
0,
|
||||
0,
|
||||
-1,
|
||||
-1,
|
||||
NULL);
|
||||
UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
|
||||
if (!props_active.constraint_enable) {
|
||||
UI_but_flag_enable(bt, UI_BUT_INACTIVE);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (tselem->type == TSE_MODIFIER) {
|
||||
ModifierData *md = (ModifierData *)te->directdata;
|
||||
|
||||
@@ -1878,6 +1915,9 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
|
||||
case TSE_DEFGROUP_BASE:
|
||||
data.icon = ICON_GROUP_VERTEX;
|
||||
break;
|
||||
case TSE_DEFGROUP:
|
||||
data.icon = ICON_GROUP_VERTEX;
|
||||
break;
|
||||
case TSE_BONE:
|
||||
case TSE_EBONE:
|
||||
data.icon = ICON_BONE_DATA;
|
||||
@@ -1885,6 +1925,100 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
|
||||
case TSE_CONSTRAINT_BASE:
|
||||
data.icon = ICON_CONSTRAINT;
|
||||
break;
|
||||
case TSE_CONSTRAINT: {
|
||||
bConstraint *con = te->directdata;
|
||||
switch ((eBConstraint_Types)con->type) {
|
||||
case CONSTRAINT_TYPE_CAMERASOLVER:
|
||||
data.icon = ICON_CON_CAMERASOLVER;
|
||||
break;
|
||||
case CONSTRAINT_TYPE_FOLLOWTRACK:
|
||||
data.icon = ICON_CON_FOLLOWTRACK;
|
||||
break;
|
||||
case CONSTRAINT_TYPE_OBJECTSOLVER:
|
||||
data.icon = ICON_CON_OBJECTSOLVER;
|
||||
break;
|
||||
case CONSTRAINT_TYPE_LOCLIKE:
|
||||
data.icon = ICON_CON_LOCLIKE;
|
||||
break;
|
||||
case CONSTRAINT_TYPE_ROTLIKE:
|
||||
data.icon = ICON_CON_ROTLIKE;
|
||||
break;
|
||||
case CONSTRAINT_TYPE_SIZELIKE:
|
||||
data.icon = ICON_CON_SIZELIKE;
|
||||
break;
|
||||
case CONSTRAINT_TYPE_TRANSLIKE:
|
||||
data.icon = ICON_CON_TRANSLIKE;
|
||||
break;
|
||||
case CONSTRAINT_TYPE_DISTLIMIT:
|
||||
data.icon = ICON_CON_DISTLIMIT;
|
||||
break;
|
||||
case CONSTRAINT_TYPE_LOCLIMIT:
|
||||
data.icon = ICON_CON_LOCLIMIT;
|
||||
break;
|
||||
case CONSTRAINT_TYPE_ROTLIMIT:
|
||||
data.icon = ICON_CON_ROTLIMIT;
|
||||
break;
|
||||
case CONSTRAINT_TYPE_SIZELIMIT:
|
||||
data.icon = ICON_CON_SIZELIMIT;
|
||||
break;
|
||||
case CONSTRAINT_TYPE_SAMEVOL:
|
||||
data.icon = ICON_CON_SAMEVOL;
|
||||
break;
|
||||
case CONSTRAINT_TYPE_TRANSFORM:
|
||||
data.icon = ICON_CON_TRANSFORM;
|
||||
break;
|
||||
case CONSTRAINT_TYPE_TRANSFORM_CACHE:
|
||||
data.icon = ICON_CON_TRANSFORM_CACHE;
|
||||
break;
|
||||
case CONSTRAINT_TYPE_CLAMPTO:
|
||||
data.icon = ICON_CON_CLAMPTO;
|
||||
break;
|
||||
case CONSTRAINT_TYPE_DAMPTRACK:
|
||||
data.icon = ICON_CON_TRACKTO;
|
||||
break;
|
||||
case CONSTRAINT_TYPE_KINEMATIC:
|
||||
data.icon = ICON_CON_KINEMATIC;
|
||||
break;
|
||||
case CONSTRAINT_TYPE_LOCKTRACK:
|
||||
data.icon = ICON_CON_LOCKTRACK;
|
||||
break;
|
||||
case CONSTRAINT_TYPE_SPLINEIK:
|
||||
data.icon = ICON_CON_SPLINEIK;
|
||||
break;
|
||||
case CONSTRAINT_TYPE_STRETCHTO:
|
||||
data.icon = ICON_CON_STRETCHTO;
|
||||
break;
|
||||
case CONSTRAINT_TYPE_TRACKTO:
|
||||
data.icon = ICON_CON_TRACKTO;
|
||||
break;
|
||||
case CONSTRAINT_TYPE_ACTION:
|
||||
data.icon = ICON_ACTION;
|
||||
break;
|
||||
case CONSTRAINT_TYPE_ARMATURE:
|
||||
data.icon = ICON_CON_ARMATURE;
|
||||
break;
|
||||
case CONSTRAINT_TYPE_CHILDOF:
|
||||
data.icon = ICON_CON_CHILDOF;
|
||||
break;
|
||||
case CONSTRAINT_TYPE_MINMAX:
|
||||
data.icon = ICON_CON_FLOOR;
|
||||
break;
|
||||
case CONSTRAINT_TYPE_FOLLOWPATH:
|
||||
data.icon = ICON_CON_FOLLOWPATH;
|
||||
break;
|
||||
case CONSTRAINT_TYPE_PIVOT:
|
||||
data.icon = ICON_CON_PIVOT;
|
||||
break;
|
||||
case CONSTRAINT_TYPE_SHRINKWRAP:
|
||||
data.icon = ICON_CON_SHRINKWRAP;
|
||||
break;
|
||||
|
||||
default:
|
||||
data.icon = ICON_DOT;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TSE_MODIFIER_BASE:
|
||||
data.icon = ICON_MODIFIER_DATA;
|
||||
break;
|
||||
@@ -2137,23 +2271,57 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
|
||||
data.icon = ICON_GROUP_BONE;
|
||||
break;
|
||||
case TSE_SEQUENCE:
|
||||
if (te->idcode == SEQ_TYPE_MOVIE) {
|
||||
data.icon = ICON_SEQUENCE;
|
||||
}
|
||||
else if (te->idcode == SEQ_TYPE_META) {
|
||||
data.icon = ICON_DOT;
|
||||
}
|
||||
else if (te->idcode == SEQ_TYPE_SCENE) {
|
||||
data.icon = ICON_SCENE;
|
||||
}
|
||||
else if (te->idcode == SEQ_TYPE_SOUND_RAM) {
|
||||
data.icon = ICON_SOUND;
|
||||
}
|
||||
else if (te->idcode == SEQ_TYPE_IMAGE) {
|
||||
data.icon = ICON_IMAGE;
|
||||
}
|
||||
else {
|
||||
data.icon = ICON_PARTICLES;
|
||||
switch (te->idcode) {
|
||||
case SEQ_TYPE_SCENE:
|
||||
data.icon = ICON_SCENE_DATA;
|
||||
break;
|
||||
case SEQ_TYPE_MOVIECLIP:
|
||||
data.icon = ICON_TRACKER;
|
||||
break;
|
||||
case SEQ_TYPE_MASK:
|
||||
data.icon = ICON_MOD_MASK;
|
||||
break;
|
||||
case SEQ_TYPE_MOVIE:
|
||||
data.icon = ICON_FILE_MOVIE;
|
||||
break;
|
||||
case SEQ_TYPE_SOUND_RAM:
|
||||
data.icon = ICON_SOUND;
|
||||
break;
|
||||
case SEQ_TYPE_IMAGE:
|
||||
data.icon = ICON_FILE_IMAGE;
|
||||
break;
|
||||
case SEQ_TYPE_COLOR:
|
||||
case SEQ_TYPE_ADJUSTMENT:
|
||||
data.icon = ICON_COLOR;
|
||||
break;
|
||||
case SEQ_TYPE_TEXT:
|
||||
data.icon = ICON_FONT_DATA;
|
||||
break;
|
||||
case SEQ_TYPE_ADD:
|
||||
case SEQ_TYPE_SUB:
|
||||
case SEQ_TYPE_MUL:
|
||||
case SEQ_TYPE_OVERDROP:
|
||||
case SEQ_TYPE_ALPHAOVER:
|
||||
case SEQ_TYPE_ALPHAUNDER:
|
||||
case SEQ_TYPE_COLORMIX:
|
||||
case SEQ_TYPE_MULTICAM:
|
||||
case SEQ_TYPE_TRANSFORM:
|
||||
case SEQ_TYPE_SPEED:
|
||||
case SEQ_TYPE_GLOW:
|
||||
case SEQ_TYPE_GAUSSIAN_BLUR:
|
||||
data.icon = ICON_SHADERFX;
|
||||
break;
|
||||
case SEQ_TYPE_CROSS:
|
||||
case SEQ_TYPE_GAMCROSS:
|
||||
case SEQ_TYPE_WIPE:
|
||||
data.icon = ICON_ARROW_LEFTRIGHT;
|
||||
break;
|
||||
case SEQ_TYPE_META:
|
||||
data.icon = ICON_DOT;
|
||||
break;
|
||||
default:
|
||||
data.icon = ICON_DOT;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case TSE_SEQ_STRIP:
|
||||
@@ -2459,7 +2627,11 @@ static void tselem_draw_icon(uiBlock *block,
|
||||
return;
|
||||
}
|
||||
|
||||
/* Icon is covered by restrict buttons */
|
||||
if (!is_clickable || x >= xmax) {
|
||||
/* Reduce alpha to match icon buttons */
|
||||
alpha *= 0.8f;
|
||||
|
||||
/* placement of icons, copied from interface_widgets.c */
|
||||
float aspect = (0.8f * UI_UNIT_Y) / ICON_DEFAULT_HEIGHT;
|
||||
x += 2.0f * aspect;
|
||||
@@ -2567,7 +2739,6 @@ static void outliner_draw_iconrow_doit(uiBlock *block,
|
||||
float ufac = UI_UNIT_X / 20.0f;
|
||||
float icon_color[4], icon_border[4];
|
||||
outliner_icon_background_colors(icon_color, icon_border);
|
||||
icon_color[3] *= alpha_fac;
|
||||
if (active == OL_DRAWSEL_ACTIVE) {
|
||||
UI_GetThemeColor4fv(TH_EDITED_OBJECT, icon_color);
|
||||
icon_border[3] = 0.3f;
|
||||
@@ -2592,6 +2763,9 @@ static void outliner_draw_iconrow_doit(uiBlock *block,
|
||||
GPU_blend(true); /* Roundbox disables. */
|
||||
}
|
||||
|
||||
if (tselem->flag & TSE_HIGHLIGHTED) {
|
||||
alpha_fac += 0.5;
|
||||
}
|
||||
tselem_draw_icon(block, xmax, (float)*offsx, (float)ys, tselem, te, alpha_fac, false);
|
||||
te->xs = *offsx;
|
||||
te->ys = ys;
|
||||
@@ -2599,7 +2773,12 @@ static void outliner_draw_iconrow_doit(uiBlock *block,
|
||||
|
||||
if (num_elements > 1) {
|
||||
outliner_draw_iconrow_number(fstyle, *offsx, ys, num_elements);
|
||||
te->flag |= TE_ICONROW_MERGED;
|
||||
}
|
||||
else {
|
||||
te->flag |= TE_ICONROW;
|
||||
}
|
||||
|
||||
(*offsx) += UI_UNIT_X;
|
||||
}
|
||||
|
||||
@@ -2609,7 +2788,7 @@ static void outliner_draw_iconrow_doit(uiBlock *block,
|
||||
* We use a continuum of indices until we get to the object data-blocks
|
||||
* and we then make room for the object types.
|
||||
*/
|
||||
static int tree_element_id_type_to_index(TreeElement *te)
|
||||
int tree_element_id_type_to_index(TreeElement *te)
|
||||
{
|
||||
TreeStoreElem *tselem = TREESTORE(te);
|
||||
|
||||
@@ -2739,7 +2918,7 @@ static void outliner_set_coord_tree_element(TreeElement *te, int startx, int sta
|
||||
TreeElement *ten;
|
||||
|
||||
/* closed items may be displayed in row of parent, don't change their coordinate! */
|
||||
if ((te->flag & TE_ICONROW) == 0) {
|
||||
if ((te->flag & TE_ICONROW) == 0 && (te->flag & TE_ICONROW_MERGED) == 0) {
|
||||
/* store coord and continue, we need coordinates for elements outside view too */
|
||||
te->xs = startx;
|
||||
te->ys = starty;
|
||||
@@ -3193,6 +3372,7 @@ static void outliner_draw_highlights_recursive(unsigned pos,
|
||||
const SpaceOutliner *soops,
|
||||
const ListBase *lb,
|
||||
const float col_selection[4],
|
||||
const float col_active[4],
|
||||
const float col_highlight[4],
|
||||
const float col_searchmatch[4],
|
||||
int start_x,
|
||||
@@ -3206,7 +3386,11 @@ static void outliner_draw_highlights_recursive(unsigned pos,
|
||||
const int start_y = *io_start_y;
|
||||
|
||||
/* selection status */
|
||||
if (tselem->flag & TSE_SELECTED) {
|
||||
if ((tselem->flag & TSE_ACTIVE) && (tselem->flag & TSE_SELECTED)) {
|
||||
immUniformColor4fv(col_active);
|
||||
immRecti(pos, 0, start_y, (int)ar->v2d.cur.xmax, start_y + UI_UNIT_Y);
|
||||
}
|
||||
else if (tselem->flag & TSE_SELECTED) {
|
||||
immUniformColor4fv(col_selection);
|
||||
immRecti(pos, 0, start_y, (int)ar->v2d.cur.xmax, start_y + UI_UNIT_Y);
|
||||
}
|
||||
@@ -3260,6 +3444,7 @@ static void outliner_draw_highlights_recursive(unsigned pos,
|
||||
soops,
|
||||
&te->subtree,
|
||||
col_selection,
|
||||
col_active,
|
||||
col_highlight,
|
||||
col_searchmatch,
|
||||
start_x + UI_UNIT_X,
|
||||
@@ -3271,10 +3456,12 @@ static void outliner_draw_highlights_recursive(unsigned pos,
|
||||
static void outliner_draw_highlights(ARegion *ar, SpaceOutliner *soops, int startx, int *starty)
|
||||
{
|
||||
const float col_highlight[4] = {1.0f, 1.0f, 1.0f, 0.13f};
|
||||
float col_selection[4], col_searchmatch[4];
|
||||
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_MATCH, col_searchmatch);
|
||||
col_searchmatch[3] = 0.5f;
|
||||
|
||||
@@ -3282,8 +3469,16 @@ static void outliner_draw_highlights(ARegion *ar, SpaceOutliner *soops, int star
|
||||
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, ar, soops, &soops->tree, col_selection, col_highlight, col_searchmatch, startx, starty);
|
||||
outliner_draw_highlights_recursive(pos,
|
||||
ar,
|
||||
soops,
|
||||
&soops->tree,
|
||||
col_selection,
|
||||
col_active,
|
||||
col_highlight,
|
||||
col_searchmatch,
|
||||
startx,
|
||||
starty);
|
||||
immUnbindProgram();
|
||||
GPU_blend(false);
|
||||
}
|
||||
@@ -3439,6 +3634,17 @@ void draw_outliner(const bContext *C)
|
||||
|
||||
outliner_build_tree(mainvar, scene, view_layer, soops, ar); // always
|
||||
|
||||
/* If global sync select is dirty, flag other outliners */
|
||||
if (ED_outliner_select_sync_is_dirty(C)) {
|
||||
ED_outliner_select_sync_flag_outliners(C);
|
||||
}
|
||||
|
||||
/* Sync selection state from view layer */
|
||||
if (!ELEM(soops->outlinevis, SO_LIBRARIES, SO_DATA_API, SO_ID_ORPHANS) &&
|
||||
soops->flag & SO_SYNC_SELECT) {
|
||||
outliner_sync_selection(C, soops);
|
||||
}
|
||||
|
||||
/* force display to pixel coords */
|
||||
v2d->flag |= (V2D_PIXELOFS_X | V2D_PIXELOFS_Y);
|
||||
/* set matrix for 2d-view controls */
|
||||
|
@@ -101,9 +101,15 @@ static int outliner_highlight_update(bContext *C, wmOperator *UNUSED(op), const
|
||||
|
||||
ARegion *ar = CTX_wm_region(C);
|
||||
SpaceOutliner *soops = CTX_wm_space_outliner(C);
|
||||
const float my = UI_view2d_region_to_view_y(&ar->v2d, event->mval[1]);
|
||||
|
||||
TreeElement *hovered_te = outliner_find_item_at_y(soops, &soops->tree, my);
|
||||
float view_mval[2];
|
||||
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &view_mval[0], &view_mval[1]);
|
||||
|
||||
TreeElement *hovered_te = outliner_find_item_at_y(soops, &soops->tree, view_mval[1]);
|
||||
|
||||
if (hovered_te) {
|
||||
hovered_te = outliner_find_item_at_x_in_row(soops, hovered_te, view_mval[0], NULL);
|
||||
}
|
||||
bool changed = false;
|
||||
|
||||
if (!hovered_te || !(hovered_te->store_elem->flag & TSE_HIGHLIGHTED)) {
|
||||
@@ -134,59 +140,108 @@ void OUTLINER_OT_highlight_update(wmOperatorType *ot)
|
||||
|
||||
/* Toggle Open/Closed ------------------------------------------- */
|
||||
|
||||
static int do_outliner_item_openclose(
|
||||
bContext *C, SpaceOutliner *soops, TreeElement *te, const bool all, const float mval[2])
|
||||
/* Open or close a tree element, optionally toggling all children recursively */
|
||||
void outliner_item_openclose(TreeElement *te, bool open, bool toggle_all)
|
||||
{
|
||||
TreeStoreElem *tselem = TREESTORE(te);
|
||||
|
||||
if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) {
|
||||
TreeStoreElem *tselem = TREESTORE(te);
|
||||
|
||||
/* all below close/open? */
|
||||
if (all) {
|
||||
tselem->flag &= ~TSE_CLOSED;
|
||||
outliner_flag_set(
|
||||
&te->subtree, TSE_CLOSED, !outliner_flag_is_any_test(&te->subtree, TSE_CLOSED, 1));
|
||||
}
|
||||
else {
|
||||
if (tselem->flag & TSE_CLOSED) {
|
||||
tselem->flag &= ~TSE_CLOSED;
|
||||
}
|
||||
else {
|
||||
tselem->flag |= TSE_CLOSED;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
if (open) {
|
||||
tselem->flag &= ~TSE_CLOSED;
|
||||
}
|
||||
else {
|
||||
tselem->flag |= TSE_CLOSED;
|
||||
}
|
||||
|
||||
for (te = te->subtree.first; te; te = te->next) {
|
||||
if (do_outliner_item_openclose(C, soops, te, all, mval)) {
|
||||
return 1;
|
||||
}
|
||||
if (toggle_all) {
|
||||
outliner_flag_set(&te->subtree, TSE_CLOSED, !open);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* event can enterkey, then it opens/closes */
|
||||
static int outliner_item_openclose(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
typedef struct OpenCloseData {
|
||||
TreeStoreElem *prev_tselem;
|
||||
bool open;
|
||||
int x_location;
|
||||
} OpenCloseData;
|
||||
|
||||
static int outliner_item_openclose_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
ARegion *ar = CTX_wm_region(C);
|
||||
SpaceOutliner *soops = CTX_wm_space_outliner(C);
|
||||
TreeElement *te;
|
||||
float fmval[2];
|
||||
const bool all = RNA_boolean_get(op->ptr, "all");
|
||||
|
||||
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
|
||||
float view_mval[2];
|
||||
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &view_mval[0], &view_mval[1]);
|
||||
|
||||
for (te = soops->tree.first; te; te = te->next) {
|
||||
if (do_outliner_item_openclose(C, soops, te, all, fmval)) {
|
||||
break;
|
||||
if (event->type == MOUSEMOVE) {
|
||||
TreeElement *te = outliner_find_item_at_y(soops, &soops->tree, view_mval[1]);
|
||||
|
||||
OpenCloseData *data = (OpenCloseData *)op->customdata;
|
||||
|
||||
/* Only openclose if mouse is not over the previously toggled element */
|
||||
if (te && TREESTORE(te) != data->prev_tselem) {
|
||||
|
||||
/* Only toggle openclose on the same level as the first clicked element */
|
||||
if (te->xs == data->x_location) {
|
||||
outliner_item_openclose(te, data->open, false);
|
||||
ED_region_tag_redraw(ar);
|
||||
}
|
||||
}
|
||||
|
||||
if (te) {
|
||||
data->prev_tselem = TREESTORE(te);
|
||||
}
|
||||
else {
|
||||
data->prev_tselem = NULL;
|
||||
}
|
||||
}
|
||||
else if (event->val == KM_RELEASE) {
|
||||
MEM_freeN(op->customdata);
|
||||
|
||||
ED_region_tag_redraw(ar);
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
|
||||
static int outliner_item_openclose_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
ARegion *ar = CTX_wm_region(C);
|
||||
SpaceOutliner *soops = CTX_wm_space_outliner(C);
|
||||
|
||||
const bool toggle_all = RNA_boolean_get(op->ptr, "all");
|
||||
|
||||
float view_mval[2];
|
||||
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &view_mval[0], &view_mval[1]);
|
||||
|
||||
TreeElement *te = outliner_find_item_at_y(soops, &soops->tree, view_mval[1]);
|
||||
|
||||
if (te && outliner_item_is_co_within_close_toggle(te, view_mval[0])) {
|
||||
TreeStoreElem *tselem = TREESTORE(te);
|
||||
|
||||
const bool open = (tselem->flag & TSE_CLOSED) ||
|
||||
(toggle_all && (outliner_flag_is_any_test(&te->subtree, TSE_CLOSED, 1)));
|
||||
|
||||
outliner_item_openclose(te, open, toggle_all);
|
||||
ED_region_tag_redraw(ar);
|
||||
|
||||
/* Only toggle once for single click toggling */
|
||||
if (event->type == LEFTMOUSE) {
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
/* Store last expanded tselem and x coordinate of disclosure triangle */
|
||||
OpenCloseData *toggle_data = MEM_callocN(sizeof(OpenCloseData), "open_close_data");
|
||||
toggle_data->prev_tselem = tselem;
|
||||
toggle_data->open = open;
|
||||
toggle_data->x_location = te->xs;
|
||||
|
||||
/* Store the first clicked on element */
|
||||
op->customdata = toggle_data;
|
||||
|
||||
WM_event_add_modal_handler(C, op);
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
|
||||
return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
|
||||
}
|
||||
|
||||
void OUTLINER_OT_item_openclose(wmOperatorType *ot)
|
||||
@@ -195,11 +250,12 @@ void OUTLINER_OT_item_openclose(wmOperatorType *ot)
|
||||
ot->idname = "OUTLINER_OT_item_openclose";
|
||||
ot->description = "Toggle whether item under cursor is enabled or closed";
|
||||
|
||||
ot->invoke = outliner_item_openclose;
|
||||
ot->invoke = outliner_item_openclose_invoke;
|
||||
ot->modal = outliner_item_openclose_modal;
|
||||
|
||||
ot->poll = ED_operator_outliner_active;
|
||||
|
||||
RNA_def_boolean(ot->srna, "all", 1, "All", "Close or open all items");
|
||||
RNA_def_boolean(ot->srna, "all", false, "All", "Close or open all items");
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
@@ -330,10 +386,10 @@ void item_rename_cb(bContext *C,
|
||||
do_item_rename(ar, te, tselem, reports);
|
||||
}
|
||||
|
||||
static int do_outliner_item_rename(ReportList *reports,
|
||||
ARegion *ar,
|
||||
TreeElement *te,
|
||||
const float mval[2])
|
||||
static void do_outliner_item_rename(ReportList *reports,
|
||||
ARegion *ar,
|
||||
TreeElement *te,
|
||||
const float mval[2])
|
||||
{
|
||||
if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) {
|
||||
TreeStoreElem *tselem = TREESTORE(te);
|
||||
@@ -341,17 +397,12 @@ static int do_outliner_item_rename(ReportList *reports,
|
||||
/* click on name */
|
||||
if (mval[0] > te->xs + UI_UNIT_X * 2 && mval[0] < te->xend) {
|
||||
do_item_rename(ar, te, tselem, reports);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (te = te->subtree.first; te; te = te->next) {
|
||||
if (do_outliner_item_rename(reports, ar, te, mval)) {
|
||||
return 1;
|
||||
}
|
||||
do_outliner_item_rename(reports, ar, te, mval);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int outliner_item_rename(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
@@ -360,25 +411,34 @@ static int outliner_item_rename(bContext *C, wmOperator *op, const wmEvent *even
|
||||
SpaceOutliner *soops = CTX_wm_space_outliner(C);
|
||||
TreeElement *te;
|
||||
float fmval[2];
|
||||
bool changed = false;
|
||||
|
||||
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
|
||||
/* Rename active element if key pressed, otherwise rename element at cursor coordinates */
|
||||
if (event->val == KM_PRESS) {
|
||||
TreeElement *active_element = outliner_find_element_with_flag(&soops->tree, TSE_ACTIVE);
|
||||
|
||||
for (te = soops->tree.first; te; te = te->next) {
|
||||
if (do_outliner_item_rename(op->reports, ar, te, fmval)) {
|
||||
changed = true;
|
||||
break;
|
||||
if (active_element) {
|
||||
do_item_rename(ar, active_element, TREESTORE(active_element), op->reports);
|
||||
}
|
||||
else {
|
||||
BKE_report(op->reports, RPT_WARNING, "No active item to rename");
|
||||
}
|
||||
}
|
||||
else {
|
||||
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
|
||||
|
||||
for (te = soops->tree.first; te; te = te->next) {
|
||||
do_outliner_item_rename(op->reports, ar, te, fmval);
|
||||
}
|
||||
}
|
||||
|
||||
return changed ? OPERATOR_FINISHED : OPERATOR_PASS_THROUGH;
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void OUTLINER_OT_item_rename(wmOperatorType *ot)
|
||||
{
|
||||
ot->name = "Rename";
|
||||
ot->idname = "OUTLINER_OT_item_rename";
|
||||
ot->description = "Rename item under cursor";
|
||||
ot->description = "Rename the active element";
|
||||
|
||||
ot->invoke = outliner_item_rename;
|
||||
|
||||
@@ -1103,6 +1163,10 @@ static int outliner_select_all_exec(bContext *C, wmOperator *op)
|
||||
break;
|
||||
}
|
||||
|
||||
if (soops->flag & SO_SYNC_SELECT) {
|
||||
ED_outliner_select_sync_from_outliner(C, soops);
|
||||
}
|
||||
|
||||
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
|
||||
ED_region_tag_redraw_no_rebuild(ar);
|
||||
@@ -1179,20 +1243,17 @@ static int outliner_open_back(TreeElement *te)
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int outliner_show_active_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
/* Return element representing the active base or bone in the outliner, or NULL if none exists */
|
||||
static TreeElement *outliner_show_active_get_element(bContext *C,
|
||||
SpaceOutliner *so,
|
||||
ViewLayer *view_layer)
|
||||
{
|
||||
SpaceOutliner *so = CTX_wm_space_outliner(C);
|
||||
ViewLayer *view_layer = CTX_data_view_layer(C);
|
||||
ARegion *ar = CTX_wm_region(C);
|
||||
View2D *v2d = &ar->v2d;
|
||||
|
||||
TreeElement *te;
|
||||
int xdelta, ytop;
|
||||
|
||||
Object *obact = OBACT(view_layer);
|
||||
|
||||
if (!obact) {
|
||||
return OPERATOR_CANCELLED;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
te = outliner_find_id(so, &so->tree, &obact->id);
|
||||
@@ -1215,25 +1276,50 @@ static int outliner_show_active_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
}
|
||||
}
|
||||
|
||||
if (te) {
|
||||
/* open up tree to active object/bone */
|
||||
return te;
|
||||
}
|
||||
|
||||
static void outliner_show_active(SpaceOutliner *so, ARegion *ar, TreeElement *te, ID *id)
|
||||
{
|
||||
/* open up tree to active object/bone */
|
||||
if (TREESTORE(te)->id == id) {
|
||||
if (outliner_open_back(te)) {
|
||||
outliner_set_coordinates(ar, so);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* make te->ys center of view */
|
||||
ytop = te->ys + BLI_rcti_size_y(&v2d->mask) / 2;
|
||||
if (ytop > 0) {
|
||||
ytop = 0;
|
||||
for (TreeElement *ten = te->subtree.first; ten; ten = ten->next) {
|
||||
outliner_show_active(so, ar, ten, id);
|
||||
}
|
||||
}
|
||||
|
||||
static int outliner_show_active_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
{
|
||||
SpaceOutliner *so = CTX_wm_space_outliner(C);
|
||||
ViewLayer *view_layer = CTX_data_view_layer(C);
|
||||
ARegion *ar = CTX_wm_region(C);
|
||||
View2D *v2d = &ar->v2d;
|
||||
|
||||
TreeElement *active_element = outliner_show_active_get_element(C, so, view_layer);
|
||||
|
||||
if (active_element) {
|
||||
ID *id = TREESTORE(active_element)->id;
|
||||
|
||||
/* Expand all elements in the outliner with matching ID */
|
||||
for (TreeElement *te = so->tree.first; te; te = te->next) {
|
||||
outliner_show_active(so, ar, te, id);
|
||||
}
|
||||
|
||||
v2d->cur.ymax = (float)ytop;
|
||||
v2d->cur.ymin = (float)(ytop - BLI_rcti_size_y(&v2d->mask));
|
||||
/* Center view on first element found */
|
||||
int size_y = BLI_rcti_size_y(&v2d->mask) + 1;
|
||||
int ytop = (active_element->ys + (size_y / 2));
|
||||
int delta_y = ytop - v2d->cur.ymax;
|
||||
|
||||
/* make te->xs ==> te->xend center of view */
|
||||
xdelta = (int)(te->xs - v2d->cur.xmin);
|
||||
v2d->cur.xmin += xdelta;
|
||||
v2d->cur.xmax += xdelta;
|
||||
outliner_scroll_view(ar, delta_y);
|
||||
}
|
||||
else {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
ED_region_tag_redraw_no_rebuild(ar);
|
||||
@@ -1259,18 +1345,15 @@ void OUTLINER_OT_show_active(wmOperatorType *ot)
|
||||
static int outliner_scroll_page_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
ARegion *ar = CTX_wm_region(C);
|
||||
int dy = BLI_rcti_size_y(&ar->v2d.mask);
|
||||
int up = 0;
|
||||
int size_y = BLI_rcti_size_y(&ar->v2d.mask) + 1;
|
||||
|
||||
if (RNA_boolean_get(op->ptr, "up")) {
|
||||
up = 1;
|
||||
bool up = RNA_boolean_get(op->ptr, "up");
|
||||
|
||||
if (!up) {
|
||||
size_y = -size_y;
|
||||
}
|
||||
|
||||
if (up == 0) {
|
||||
dy = -dy;
|
||||
}
|
||||
ar->v2d.cur.ymin += dy;
|
||||
ar->v2d.cur.ymax += dy;
|
||||
outliner_scroll_view(ar, size_y);
|
||||
|
||||
ED_region_tag_redraw_no_rebuild(ar);
|
||||
|
||||
|
@@ -50,6 +50,14 @@ typedef enum TreeElementInsertType {
|
||||
TE_INSERT_INTO,
|
||||
} TreeElementInsertType;
|
||||
|
||||
/* Use generic walk select after D4771 is committed */
|
||||
typedef enum WalkSelectDirection {
|
||||
OUTLINER_SELECT_WALK_UP,
|
||||
OUTLINER_SELECT_WALK_DOWN,
|
||||
OUTLINER_SELECT_WALK_LEFT,
|
||||
OUTLINER_SELECT_WALK_RIGHT,
|
||||
} WalkSelectDirection;
|
||||
|
||||
typedef enum TreeTraversalAction {
|
||||
/* Continue traversal regularly, don't skip children. */
|
||||
TRAVERSE_CONTINUE = 0,
|
||||
@@ -131,6 +139,9 @@ enum {
|
||||
TE_DISABLED = (1 << 4),
|
||||
TE_DRAGGING = (1 << 5),
|
||||
TE_CHILD_NOT_IN_COLLECTION = (1 << 6),
|
||||
/* Child elements of the same type in the iconrow are drawn merged as one icon.
|
||||
* TE_ICONROW_MERGED is set for an element that is part of these merged child icons. */
|
||||
TE_ICONROW_MERGED = (1 << 7),
|
||||
};
|
||||
|
||||
/* button events */
|
||||
@@ -223,6 +234,8 @@ void outliner_collection_isolate_flag(struct Scene *scene,
|
||||
const char *propname,
|
||||
const bool value);
|
||||
|
||||
int tree_element_id_type_to_index(TreeElement *te);
|
||||
|
||||
/* outliner_select.c -------------------------------------------- */
|
||||
eOLDrawState tree_element_type_active(struct bContext *C,
|
||||
struct Scene *scene,
|
||||
@@ -253,6 +266,10 @@ void outliner_object_mode_toggle(struct bContext *C,
|
||||
ViewLayer *view_layer,
|
||||
Base *base);
|
||||
|
||||
void outliner_element_activate(struct SpaceOutliner *soops, struct TreeStoreElem *tselem);
|
||||
|
||||
bool outliner_item_is_co_within_close_toggle(TreeElement *te, float view_co_x);
|
||||
|
||||
/* outliner_edit.c ---------------------------------------------- */
|
||||
typedef void (*outliner_operation_cb)(struct bContext *C,
|
||||
struct ReportList *,
|
||||
@@ -337,6 +354,8 @@ void item_object_mode_exit_cb(struct bContext *C,
|
||||
|
||||
void outliner_set_coordinates(struct ARegion *ar, struct SpaceOutliner *soops);
|
||||
|
||||
void outliner_item_openclose(TreeElement *te, bool open, bool toggle_all);
|
||||
|
||||
/* outliner_dragdrop.c */
|
||||
void outliner_dropboxes(void);
|
||||
|
||||
@@ -364,6 +383,7 @@ void OUTLINER_OT_show_active(struct wmOperatorType *ot);
|
||||
void OUTLINER_OT_show_hierarchy(struct wmOperatorType *ot);
|
||||
|
||||
void OUTLINER_OT_select_box(struct wmOperatorType *ot);
|
||||
void OUTLINER_OT_select_walk(struct wmOperatorType *ot);
|
||||
|
||||
void OUTLINER_OT_select_all(struct wmOperatorType *ot);
|
||||
void OUTLINER_OT_expanded_toggle(struct wmOperatorType *ot);
|
||||
@@ -380,6 +400,10 @@ void OUTLINER_OT_orphans_purge(struct wmOperatorType *ot);
|
||||
|
||||
/* outliner_tools.c ---------------------------------------------- */
|
||||
|
||||
void merged_element_search_menu_invoke(struct bContext *C,
|
||||
TreeElement *parent_te,
|
||||
TreeElement *activate_te);
|
||||
|
||||
void OUTLINER_OT_operation(struct wmOperatorType *ot);
|
||||
void OUTLINER_OT_scene_operation(struct wmOperatorType *ot);
|
||||
void OUTLINER_OT_object_operation(struct wmOperatorType *ot);
|
||||
@@ -439,7 +463,8 @@ TreeElement *outliner_find_item_at_y(const SpaceOutliner *soops,
|
||||
float view_co_y);
|
||||
TreeElement *outliner_find_item_at_x_in_row(const SpaceOutliner *soops,
|
||||
const TreeElement *parent_te,
|
||||
float view_co_x);
|
||||
float view_co_x,
|
||||
bool *multiple_objects);
|
||||
TreeElement *outliner_find_tse(struct SpaceOutliner *soops, const TreeStoreElem *tse);
|
||||
TreeElement *outliner_find_tree_element(ListBase *lb, const TreeStoreElem *store_elem);
|
||||
TreeElement *outliner_find_parent_element(ListBase *lb,
|
||||
@@ -456,5 +481,12 @@ bool outliner_tree_traverse(const SpaceOutliner *soops,
|
||||
TreeTraversalFunc func,
|
||||
void *customdata);
|
||||
float outliner_restrict_columns_width(const struct SpaceOutliner *soops);
|
||||
TreeElement *outliner_find_element_with_flag(const ListBase *lb, short flag);
|
||||
bool outliner_is_element_visible(const TreeElement *te);
|
||||
void outliner_scroll_view(struct ARegion *ar, int delta_y);
|
||||
|
||||
/* outliner_sync.c ---------------------------------------------- */
|
||||
|
||||
void outliner_sync_selection(const struct bContext *C, struct SpaceOutliner *soops);
|
||||
|
||||
#endif /* __OUTLINER_INTERN_H__ */
|
||||
|
@@ -50,6 +50,7 @@ void outliner_operatortypes(void)
|
||||
WM_operatortype_append(OUTLINER_OT_highlight_update);
|
||||
WM_operatortype_append(OUTLINER_OT_item_activate);
|
||||
WM_operatortype_append(OUTLINER_OT_select_box);
|
||||
WM_operatortype_append(OUTLINER_OT_select_walk);
|
||||
WM_operatortype_append(OUTLINER_OT_item_openclose);
|
||||
WM_operatortype_append(OUTLINER_OT_item_rename);
|
||||
WM_operatortype_append(OUTLINER_OT_item_drag_drop);
|
||||
|
@@ -51,14 +51,16 @@
|
||||
#include "BKE_workspace.h"
|
||||
|
||||
#include "DEG_depsgraph.h"
|
||||
#include "DEG_depsgraph_build.h"
|
||||
|
||||
#include "ED_armature.h"
|
||||
#include "ED_gpencil.h"
|
||||
#include "ED_object.h"
|
||||
#include "ED_outliner.h"
|
||||
#include "ED_screen.h"
|
||||
#include "ED_select_utils.h"
|
||||
#include "ED_sequencer.h"
|
||||
#include "ED_undo.h"
|
||||
#include "ED_gpencil.h"
|
||||
|
||||
#include "WM_api.h"
|
||||
#include "WM_types.h"
|
||||
@@ -251,9 +253,7 @@ static eOLDrawState active_viewlayer(bContext *C,
|
||||
}
|
||||
|
||||
/**
|
||||
* Select object tree:
|
||||
* CTRL+LMB: Select/Deselect object and all children.
|
||||
* CTRL+SHIFT+LMB: Add/Remove object and all children.
|
||||
* Select object tree
|
||||
*/
|
||||
static void do_outliner_object_select_recursive(ViewLayer *view_layer,
|
||||
Object *ob_parent,
|
||||
@@ -450,9 +450,9 @@ static eOLDrawState tree_element_active_material(bContext *C,
|
||||
return OL_DRAWSEL_NONE;
|
||||
}
|
||||
|
||||
static eOLDrawState tree_element_active_camera(bContext *UNUSED(C),
|
||||
static eOLDrawState tree_element_active_camera(bContext *C,
|
||||
Scene *scene,
|
||||
ViewLayer *UNUSED(sl),
|
||||
ViewLayer *UNUSED(view_layer),
|
||||
SpaceOutliner *soops,
|
||||
TreeElement *te,
|
||||
const eOLSetState set)
|
||||
@@ -460,10 +460,21 @@ static eOLDrawState tree_element_active_camera(bContext *UNUSED(C),
|
||||
Object *ob = (Object *)outliner_search_back(soops, 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;
|
||||
else {
|
||||
return scene->camera == ob;
|
||||
}
|
||||
}
|
||||
|
||||
static eOLDrawState tree_element_active_world(bContext *C,
|
||||
@@ -1083,6 +1094,13 @@ eOLDrawState tree_element_type_active(bContext *C,
|
||||
|
||||
/* ================================================ */
|
||||
|
||||
/* Activate a tree store element and set the walk navigation start element */
|
||||
void outliner_element_activate(SpaceOutliner *soops, TreeStoreElem *tselem)
|
||||
{
|
||||
outliner_flag_set(&soops->tree, TSE_ACTIVE | TSE_ACTIVE_WALK, false);
|
||||
tselem->flag |= TSE_ACTIVE | TSE_ACTIVE_WALK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Action when clicking to activate an item (typically under the mouse cursor),
|
||||
* but don't do any cursor intersection checks.
|
||||
@@ -1114,7 +1132,8 @@ static void do_outliner_item_activate_tree_element(bContext *C,
|
||||
else if (tselem->type == TSE_POSE_BASE) {
|
||||
/* Support pose mode toggle, keeping the active object as is. */
|
||||
}
|
||||
else {
|
||||
else if (soops->flag & SO_SYNC_SELECT) {
|
||||
/* Only activate when synced selection is enabled */
|
||||
tree_element_set_active_object(C,
|
||||
scene,
|
||||
view_layer,
|
||||
@@ -1125,6 +1144,9 @@ static void do_outliner_item_activate_tree_element(bContext *C,
|
||||
recursive && tselem->type == 0);
|
||||
}
|
||||
|
||||
/* Mark as active in the outliner */
|
||||
outliner_element_activate(soops, tselem);
|
||||
|
||||
if (tselem->type == 0) { // the lib blocks
|
||||
/* editmode? */
|
||||
if (te->idcode == ID_SCE) {
|
||||
@@ -1189,7 +1211,7 @@ static void do_outliner_item_activate_tree_element(bContext *C,
|
||||
tree_element_active(C, scene, view_layer, soops, te, OL_SETSEL_NORMAL, false);
|
||||
}
|
||||
}
|
||||
else {
|
||||
else if (soops->flag & SO_SYNC_SELECT) {
|
||||
tree_element_type_active(C,
|
||||
scene,
|
||||
view_layer,
|
||||
@@ -1211,7 +1233,8 @@ void outliner_item_select(SpaceOutliner *soops,
|
||||
const bool toggle)
|
||||
{
|
||||
TreeStoreElem *tselem = TREESTORE(te);
|
||||
const short new_flag = toggle ? (tselem->flag ^ TSE_SELECTED) : (tselem->flag | TSE_SELECTED);
|
||||
const short new_flag = (toggle && (tselem->flag & TSE_ACTIVE)) ? (tselem->flag ^ TSE_SELECTED) :
|
||||
(tselem->flag | TSE_SELECTED);
|
||||
|
||||
if (extend == false) {
|
||||
outliner_flag_set(&soops->tree, TSE_SELECTED, false);
|
||||
@@ -1219,24 +1242,66 @@ void outliner_item_select(SpaceOutliner *soops,
|
||||
tselem->flag = new_flag;
|
||||
}
|
||||
|
||||
static void outliner_item_toggle_closed(TreeElement *te, const bool toggle_children)
|
||||
static void do_outliner_range_select_recursive(ListBase *lb,
|
||||
TreeElement *active,
|
||||
TreeElement *cursor,
|
||||
bool *selecting)
|
||||
{
|
||||
TreeStoreElem *tselem = TREESTORE(te);
|
||||
if (toggle_children) {
|
||||
tselem->flag &= ~TSE_CLOSED;
|
||||
for (TreeElement *te = lb->first; te; te = te->next) {
|
||||
if (*selecting) {
|
||||
TREESTORE(te)->flag |= TSE_SELECTED;
|
||||
}
|
||||
|
||||
const bool all_opened = !outliner_flag_is_any_test(&te->subtree, TSE_CLOSED, 1);
|
||||
outliner_flag_set(&te->subtree, TSE_CLOSED, all_opened);
|
||||
}
|
||||
else {
|
||||
tselem->flag ^= TSE_CLOSED;
|
||||
/* Set state for selection */
|
||||
if (te == active || te == cursor) {
|
||||
*selecting = !*selecting;
|
||||
}
|
||||
|
||||
if (*selecting) {
|
||||
TREESTORE(te)->flag |= TSE_SELECTED;
|
||||
}
|
||||
|
||||
/* Don't look inside closed elements */
|
||||
if (!(TREESTORE(te)->flag & TSE_CLOSED)) {
|
||||
do_outliner_range_select_recursive(&te->subtree, active, cursor, selecting);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool outliner_item_is_co_within_close_toggle(TreeElement *te, float view_co_x)
|
||||
/* Select a range of items between cursor and active element */
|
||||
static void do_outliner_range_select(bContext *C, SpaceOutliner *soops, TreeElement *cursor)
|
||||
{
|
||||
return ((te->flag & TE_ICONROW) == 0) && (view_co_x > te->xs) &&
|
||||
(view_co_x < te->xs + UI_UNIT_X);
|
||||
TreeElement *active = outliner_find_element_with_flag(&soops->tree, TSE_ACTIVE);
|
||||
outliner_flag_set(&soops->tree, TSE_ACTIVE_WALK, false);
|
||||
|
||||
if (!active) {
|
||||
outliner_item_select(soops, cursor, false, false);
|
||||
outliner_item_do_activate_from_tree_element(C, cursor, TREESTORE(cursor), false, false);
|
||||
return;
|
||||
}
|
||||
|
||||
TreeStoreElem *tselem = TREESTORE(active);
|
||||
const bool active_selected = (tselem->flag & TSE_SELECTED);
|
||||
|
||||
outliner_flag_set(&soops->tree, TSE_SELECTED | TSE_ACTIVE_WALK, false);
|
||||
|
||||
/* Select active if under cursor */
|
||||
if (active == cursor) {
|
||||
TREESTORE(cursor)->flag |= TSE_SELECTED;
|
||||
return;
|
||||
}
|
||||
|
||||
/* If active is not selected, just select the element under the cursor */
|
||||
if (!active_selected || !outliner_is_element_visible(active)) {
|
||||
outliner_item_select(soops, cursor, false, false);
|
||||
outliner_item_do_activate_from_tree_element(C, cursor, TREESTORE(cursor), false, false);
|
||||
return;
|
||||
}
|
||||
|
||||
outliner_flag_set(&soops->tree, TSE_SELECTED, false);
|
||||
|
||||
bool selecting = false;
|
||||
do_outliner_range_select_recursive(&soops->tree, active, cursor, &selecting);
|
||||
}
|
||||
|
||||
static bool outliner_is_co_within_restrict_columns(const SpaceOutliner *soops,
|
||||
@@ -1247,7 +1312,7 @@ static bool outliner_is_co_within_restrict_columns(const SpaceOutliner *soops,
|
||||
}
|
||||
|
||||
/**
|
||||
* A version of #outliner_item_do_acticate_from_cursor that takes the tree element directly.
|
||||
* A version of #outliner_item_do_activate_from_cursor that takes the tree element directly.
|
||||
* and doesn't depend on the pointer position.
|
||||
*
|
||||
* This allows us to simulate clicking on an item without dealing with the mouse cursor.
|
||||
@@ -1271,10 +1336,11 @@ void outliner_item_do_activate_from_tree_element(
|
||||
static int outliner_item_do_activate_from_cursor(bContext *C,
|
||||
const int mval[2],
|
||||
const bool extend,
|
||||
const bool recursive,
|
||||
const bool use_range,
|
||||
const bool deselect_all)
|
||||
{
|
||||
ARegion *ar = CTX_wm_region(C);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
SpaceOutliner *soops = CTX_wm_space_outliner(C);
|
||||
TreeElement *te;
|
||||
float view_mval[2];
|
||||
@@ -1292,21 +1358,36 @@ static int outliner_item_do_activate_from_cursor(bContext *C,
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
else if (outliner_item_is_co_within_close_toggle(te, view_mval[0])) {
|
||||
outliner_item_toggle_closed(te, extend);
|
||||
changed = true;
|
||||
rebuild_tree = true;
|
||||
/* Don't allow toggle on scene collection */
|
||||
else if ((TREESTORE(te)->type != TSE_VIEW_COLLECTION_BASE) &&
|
||||
outliner_item_is_co_within_close_toggle(te, view_mval[0])) {
|
||||
return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
|
||||
}
|
||||
else {
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
ViewLayer *view_layer = CTX_data_view_layer(C);
|
||||
/* the row may also contain children, if one is hovered we want this instead of current te */
|
||||
TreeElement *activate_te = outliner_find_item_at_x_in_row(soops, te, view_mval[0]);
|
||||
|
||||
/* 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(
|
||||
soops, te, view_mval[0], &merged_elements);
|
||||
|
||||
/* If the selected icon was an aggregate of multiple elements, run the search popup */
|
||||
if (merged_elements) {
|
||||
merged_element_search_menu_invoke(C, te, activate_te);
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
TreeStoreElem *activate_tselem = TREESTORE(activate_te);
|
||||
|
||||
outliner_item_select(soops, activate_te, extend, extend);
|
||||
do_outliner_item_activate_tree_element(
|
||||
C, scene, view_layer, soops, activate_te, activate_tselem, extend, recursive);
|
||||
if (use_range) {
|
||||
do_outliner_range_select(C, soops, activate_te);
|
||||
}
|
||||
else {
|
||||
outliner_item_select(soops, activate_te, extend, extend);
|
||||
do_outliner_item_activate_tree_element(
|
||||
C, scene, view_layer, soops, activate_te, activate_tselem, extend, false);
|
||||
}
|
||||
|
||||
changed = true;
|
||||
}
|
||||
|
||||
@@ -1318,6 +1399,10 @@ static int outliner_item_do_activate_from_cursor(bContext *C,
|
||||
ED_region_tag_redraw_no_rebuild(ar);
|
||||
}
|
||||
ED_undo_push(C, "Outliner selection change");
|
||||
|
||||
if (soops->flag & SO_SYNC_SELECT) {
|
||||
ED_outliner_select_sync_from_outliner(C, soops);
|
||||
}
|
||||
}
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
@@ -1327,9 +1412,9 @@ static int outliner_item_do_activate_from_cursor(bContext *C,
|
||||
static int outliner_item_activate_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
const bool extend = RNA_boolean_get(op->ptr, "extend");
|
||||
const bool recursive = RNA_boolean_get(op->ptr, "recursive");
|
||||
const bool use_range = RNA_boolean_get(op->ptr, "extend_range");
|
||||
const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
|
||||
return outliner_item_do_activate_from_cursor(C, event->mval, extend, recursive, deselect_all);
|
||||
return outliner_item_do_activate_from_cursor(C, event->mval, extend, use_range, deselect_all);
|
||||
}
|
||||
|
||||
void OUTLINER_OT_item_activate(wmOperatorType *ot)
|
||||
@@ -1344,7 +1429,10 @@ void OUTLINER_OT_item_activate(wmOperatorType *ot)
|
||||
|
||||
PropertyRNA *prop;
|
||||
RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend selection for activation");
|
||||
RNA_def_boolean(ot->srna, "recursive", false, "Recursive", "Select Objects and their children");
|
||||
prop = RNA_def_boolean(
|
||||
ot->srna, "extend_range", false, "Extend Range", "Select a range from active element");
|
||||
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
||||
|
||||
prop = RNA_def_boolean(ot->srna,
|
||||
"deselect_all",
|
||||
false,
|
||||
@@ -1402,9 +1490,44 @@ static int outliner_box_select_exec(bContext *C, wmOperator *op)
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
|
||||
ED_region_tag_redraw(ar);
|
||||
|
||||
if (soops->flag & SO_SYNC_SELECT) {
|
||||
ED_outliner_select_sync_from_outliner(C, soops);
|
||||
}
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
/* Find if x coordinate is over an icon or name */
|
||||
static bool outliner_item_is_co_over_name_icons(TreeElement *te, float view_co_x)
|
||||
{
|
||||
/* Special case: count area left of Scene Collection as empty space */
|
||||
bool outside_left = (TREESTORE(te)->type == TSE_VIEW_COLLECTION_BASE) ?
|
||||
(view_co_x > te->xs + UI_UNIT_X) :
|
||||
(view_co_x > te->xs);
|
||||
|
||||
return outside_left && (view_co_x < te->xend);
|
||||
}
|
||||
|
||||
static int outliner_box_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
SpaceOutliner *soops = CTX_wm_space_outliner(C);
|
||||
ARegion *ar = CTX_wm_region(C);
|
||||
float view_mval[2];
|
||||
const bool tweak = RNA_boolean_get(op->ptr, "tweak");
|
||||
|
||||
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &view_mval[0], &view_mval[1]);
|
||||
|
||||
/* Find element clicked on */
|
||||
TreeElement *te = outliner_find_item_at_y(soops, &soops->tree, view_mval[1]);
|
||||
|
||||
/* Pass through if click is over name or icons, or not tweak event */
|
||||
if (te && tweak && outliner_item_is_co_over_name_icons(te, view_mval[0])) {
|
||||
return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
|
||||
}
|
||||
|
||||
return WM_gesture_box_invoke(C, op, event);
|
||||
}
|
||||
|
||||
void OUTLINER_OT_select_box(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
@@ -1413,7 +1536,7 @@ void OUTLINER_OT_select_box(wmOperatorType *ot)
|
||||
ot->description = "Use box selection to select tree elements";
|
||||
|
||||
/* api callbacks */
|
||||
ot->invoke = WM_gesture_box_invoke;
|
||||
ot->invoke = outliner_box_select_invoke;
|
||||
ot->exec = outliner_box_select_exec;
|
||||
ot->modal = WM_gesture_box_modal;
|
||||
ot->cancel = WM_gesture_box_cancel;
|
||||
@@ -1424,8 +1547,240 @@ void OUTLINER_OT_select_box(wmOperatorType *ot)
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
|
||||
/* properties */
|
||||
PropertyRNA *prop;
|
||||
|
||||
prop = RNA_def_boolean(
|
||||
ot->srna, "tweak", false, "Tweak", "Tweak gesture from empty space for box selection");
|
||||
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
||||
|
||||
WM_operator_properties_gesture_box(ot);
|
||||
WM_operator_properties_select_operation_simple(ot);
|
||||
}
|
||||
|
||||
/* ****************************************************** */
|
||||
|
||||
/* **************** Walk Select Tool ****************** */
|
||||
|
||||
/* Given a tree element return the rightmost child that is visible in the outliner */
|
||||
static TreeElement *outliner_find_rightmost_visible_child(SpaceOutliner *soops, TreeElement *te)
|
||||
{
|
||||
while (te->subtree.last) {
|
||||
if (TSELEM_OPEN(TREESTORE(te), soops)) {
|
||||
te = te->subtree.last;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return te;
|
||||
}
|
||||
|
||||
/* Find previous visible element in the tree */
|
||||
static TreeElement *outliner_find_previous_element(SpaceOutliner *soops, TreeElement *walk_element)
|
||||
{
|
||||
if (walk_element->prev) {
|
||||
walk_element = outliner_find_rightmost_visible_child(soops, walk_element->prev);
|
||||
}
|
||||
else if (walk_element->parent) {
|
||||
/* Use parent if at beginning of list */
|
||||
walk_element = walk_element->parent;
|
||||
}
|
||||
|
||||
return walk_element;
|
||||
}
|
||||
|
||||
/* Recursively search up the tree until a successor to a given element is found */
|
||||
static TreeElement *outliner_element_find_successor_in_parents(TreeElement *te)
|
||||
{
|
||||
TreeElement *successor = te;
|
||||
while (successor->parent) {
|
||||
if (successor->parent->next) {
|
||||
te = successor->parent->next;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
successor = successor->parent;
|
||||
}
|
||||
}
|
||||
|
||||
return te;
|
||||
}
|
||||
|
||||
/* Find next visible element in the tree */
|
||||
static TreeElement *outliner_find_next_element(SpaceOutliner *soops, TreeElement *walk_element)
|
||||
{
|
||||
TreeStoreElem *tselem = TREESTORE(walk_element);
|
||||
|
||||
if (TSELEM_OPEN(tselem, soops) && walk_element->subtree.first) {
|
||||
walk_element = walk_element->subtree.first;
|
||||
}
|
||||
else if (walk_element->next) {
|
||||
walk_element = walk_element->next;
|
||||
}
|
||||
else {
|
||||
walk_element = outliner_element_find_successor_in_parents(walk_element);
|
||||
}
|
||||
|
||||
return walk_element;
|
||||
}
|
||||
|
||||
static TreeElement *do_outliner_select_walk(SpaceOutliner *soops,
|
||||
TreeElement *walk_element,
|
||||
const int direction,
|
||||
const bool extend,
|
||||
const bool toggle_all)
|
||||
{
|
||||
TreeStoreElem *tselem = TREESTORE(walk_element);
|
||||
|
||||
if (!extend) {
|
||||
outliner_flag_set(&soops->tree, TSE_SELECTED, false);
|
||||
}
|
||||
tselem->flag &= ~TSE_ACTIVE_WALK;
|
||||
|
||||
switch (direction) {
|
||||
case OUTLINER_SELECT_WALK_UP:
|
||||
walk_element = outliner_find_previous_element(soops, walk_element);
|
||||
break;
|
||||
case OUTLINER_SELECT_WALK_DOWN:
|
||||
walk_element = outliner_find_next_element(soops, walk_element);
|
||||
break;
|
||||
case OUTLINER_SELECT_WALK_LEFT:
|
||||
outliner_item_openclose(walk_element, false, toggle_all);
|
||||
break;
|
||||
case OUTLINER_SELECT_WALK_RIGHT:
|
||||
outliner_item_openclose(walk_element, true, toggle_all);
|
||||
break;
|
||||
}
|
||||
|
||||
TreeStoreElem *tselem_new = TREESTORE(walk_element);
|
||||
|
||||
/* If new element is already selected, deselect the previous element */
|
||||
if (extend) {
|
||||
tselem->flag = (tselem_new->flag & TSE_SELECTED) ? (tselem->flag & ~TSE_SELECTED) :
|
||||
(tselem->flag | TSE_SELECTED);
|
||||
}
|
||||
|
||||
tselem_new->flag |= TSE_SELECTED | TSE_ACTIVE_WALK;
|
||||
|
||||
return walk_element;
|
||||
}
|
||||
|
||||
/* Find walk select element, or set it if it does not exist.
|
||||
* Changed is set to true if walk element is found, false if it was set */
|
||||
static TreeElement *find_walk_select_start_element(SpaceOutliner *soops, bool *changed)
|
||||
{
|
||||
TreeElement *walk_element = outliner_find_element_with_flag(&soops->tree, TSE_ACTIVE_WALK);
|
||||
|
||||
*changed = false;
|
||||
|
||||
/* If no walk element exists, start from active */
|
||||
if (!walk_element) {
|
||||
TreeElement *active_element = outliner_find_element_with_flag(&soops->tree, TSE_ACTIVE);
|
||||
|
||||
/* If no active element exists, use the first element in the tree */
|
||||
if (!active_element) {
|
||||
walk_element = soops->tree.first;
|
||||
}
|
||||
else {
|
||||
walk_element = active_element;
|
||||
}
|
||||
|
||||
*changed = true;
|
||||
}
|
||||
|
||||
/* If walk element is not visible, set that element's first visible parent as walk element */
|
||||
if (!outliner_is_element_visible(walk_element)) {
|
||||
TREESTORE(walk_element)->flag &= ~TSE_ACTIVE_WALK;
|
||||
|
||||
while (!outliner_is_element_visible(walk_element)) {
|
||||
walk_element = walk_element->parent;
|
||||
}
|
||||
*changed = true;
|
||||
}
|
||||
|
||||
return walk_element;
|
||||
}
|
||||
|
||||
/* Scroll the outliner when the walk element reaches the top or bottom boundary */
|
||||
static void outliner_walk_scroll(ARegion *ar, TreeElement *te)
|
||||
{
|
||||
/* Account for the header height */
|
||||
int y_max = ar->v2d.cur.ymax - UI_UNIT_Y;
|
||||
int y_min = ar->v2d.cur.ymin;
|
||||
|
||||
/* Scroll if walked position is beyond the border */
|
||||
if (te->ys > y_max) {
|
||||
outliner_scroll_view(ar, te->ys - y_max);
|
||||
}
|
||||
else if (te->ys < y_min) {
|
||||
outliner_scroll_view(ar, -(y_min - te->ys));
|
||||
}
|
||||
}
|
||||
|
||||
static int outliner_walk_select_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
|
||||
{
|
||||
SpaceOutliner *soops = CTX_wm_space_outliner(C);
|
||||
ARegion *ar = CTX_wm_region(C);
|
||||
|
||||
const short direction = RNA_enum_get(op->ptr, "direction");
|
||||
const bool extend = RNA_boolean_get(op->ptr, "extend");
|
||||
const bool toggle_all = RNA_boolean_get(op->ptr, "toggle_all");
|
||||
|
||||
bool changed;
|
||||
TreeElement *walk_element = find_walk_select_start_element(soops, &changed);
|
||||
|
||||
/* If finding the starting walk select element did not move the element, proceed to walk */
|
||||
if (!changed) {
|
||||
walk_element = do_outliner_select_walk(soops, walk_element, direction, extend, toggle_all);
|
||||
}
|
||||
else {
|
||||
TREESTORE(walk_element)->flag |= TSE_SELECTED | TSE_ACTIVE_WALK;
|
||||
}
|
||||
|
||||
/* Scroll outliner to focus on walk element */
|
||||
outliner_walk_scroll(ar, walk_element);
|
||||
|
||||
if (soops->flag & SO_SYNC_SELECT) {
|
||||
ED_outliner_select_sync_from_outliner(C, soops);
|
||||
}
|
||||
ED_region_tag_redraw(ar);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void OUTLINER_OT_select_walk(wmOperatorType *ot)
|
||||
{
|
||||
static const EnumPropertyItem direction_items[] = {
|
||||
{OUTLINER_SELECT_WALK_UP, "UP", 0, "Up", ""},
|
||||
{OUTLINER_SELECT_WALK_DOWN, "DOWN", 0, "Down", ""},
|
||||
{OUTLINER_SELECT_WALK_LEFT, "LEFT", 0, "Left", ""},
|
||||
{OUTLINER_SELECT_WALK_RIGHT, "RIGHT", 0, "Right", ""},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
/* identifiers */
|
||||
ot->name = "Walk Select";
|
||||
ot->idname = "OUTLINER_OT_select_walk";
|
||||
ot->description = "Use walk navigation to select tree elements";
|
||||
|
||||
/* api callbacks */
|
||||
ot->invoke = outliner_walk_select_invoke;
|
||||
ot->poll = ED_operator_outliner_active;
|
||||
|
||||
/* properties */
|
||||
PropertyRNA *prop;
|
||||
prop = RNA_def_enum(ot->srna,
|
||||
"direction",
|
||||
direction_items,
|
||||
0,
|
||||
"Walk Direction",
|
||||
"Select element in this direction");
|
||||
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
||||
prop = RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection on walk");
|
||||
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
||||
prop = RNA_def_boolean(
|
||||
ot->srna, "toggle_all", false, "Toggle All", "Toggle open/close hierarchy");
|
||||
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
||||
}
|
||||
|
||||
/* ****************************************************** */
|
||||
|
548
source/blender/editors/space_outliner/outliner_sync.c
Normal file
548
source/blender/editors/space_outliner/outliner_sync.c
Normal file
@@ -0,0 +1,548 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2004 Blender Foundation.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup spoutliner
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "DNA_armature_types.h"
|
||||
#include "DNA_layer_types.h"
|
||||
#include "DNA_outliner_types.h"
|
||||
#include "DNA_screen_types.h"
|
||||
#include "DNA_sequence_types.h"
|
||||
#include "DNA_space_types.h"
|
||||
|
||||
#include "BLI_compiler_compat.h"
|
||||
#include "BLI_ghash.h"
|
||||
|
||||
#include "BKE_armature.h"
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_layer.h"
|
||||
#include "BKE_main.h"
|
||||
#include "BKE_sequencer.h"
|
||||
|
||||
#include "DEG_depsgraph.h"
|
||||
|
||||
#include "ED_armature.h"
|
||||
#include "ED_object.h"
|
||||
#include "ED_outliner.h"
|
||||
|
||||
#include "WM_api.h"
|
||||
#include "WM_types.h"
|
||||
|
||||
#include "outliner_intern.h"
|
||||
|
||||
/* Functions for tagging outliner selection syncing is dirty from operators */
|
||||
void ED_outliner_select_sync_from_object_tag(bContext *C)
|
||||
{
|
||||
wmWindowManager *wm = CTX_wm_manager(C);
|
||||
wm->outliner_sync_select_dirty |= WM_OUTLINER_SYNC_SELECT_FROM_OBJECT;
|
||||
}
|
||||
|
||||
void ED_outliner_select_sync_from_edit_bone_tag(bContext *C)
|
||||
{
|
||||
wmWindowManager *wm = CTX_wm_manager(C);
|
||||
wm->outliner_sync_select_dirty |= WM_OUTLINER_SYNC_SELECT_FROM_EDIT_BONE;
|
||||
}
|
||||
|
||||
void ED_outliner_select_sync_from_pose_bone_tag(bContext *C)
|
||||
{
|
||||
wmWindowManager *wm = CTX_wm_manager(C);
|
||||
wm->outliner_sync_select_dirty |= WM_OUTLINER_SYNC_SELECT_FROM_POSE_BONE;
|
||||
}
|
||||
|
||||
void ED_outliner_select_sync_from_sequence_tag(bContext *C)
|
||||
{
|
||||
wmWindowManager *wm = CTX_wm_manager(C);
|
||||
wm->outliner_sync_select_dirty |= WM_OUTLINER_SYNC_SELECT_FROM_SEQUENCE;
|
||||
}
|
||||
|
||||
bool ED_outliner_select_sync_is_dirty(const bContext *C)
|
||||
{
|
||||
wmWindowManager *wm = CTX_wm_manager(C);
|
||||
return wm->outliner_sync_select_dirty & WM_OUTLINER_SYNC_SELECT_FROM_ALL;
|
||||
}
|
||||
|
||||
/* Copy sync select dirty flag from window manager to all outliners to be synced lazily on draw */
|
||||
void ED_outliner_select_sync_flag_outliners(const bContext *C)
|
||||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
wmWindowManager *wm = CTX_wm_manager(C);
|
||||
|
||||
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
|
||||
for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
|
||||
for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
|
||||
if (sl->spacetype == SPACE_OUTLINER) {
|
||||
SpaceOutliner *soutliner = (SpaceOutliner *)sl;
|
||||
|
||||
soutliner->sync_select_dirty |= wm->outliner_sync_select_dirty;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear global sync flag */
|
||||
wm->outliner_sync_select_dirty = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outliner sync select dirty flags are not enough to determine which types to sync,
|
||||
* outliner display mode also needs to be considered. This stores the types of data
|
||||
* to sync to increase code clarity.
|
||||
*/
|
||||
typedef struct SyncSelectTypes {
|
||||
bool object;
|
||||
bool edit_bone;
|
||||
bool pose_bone;
|
||||
bool sequence;
|
||||
} SyncSelectTypes;
|
||||
|
||||
/**
|
||||
* Set which types of data to sync when syncing selection from the outliner based on object
|
||||
* interaction mode and outliner display mode
|
||||
*/
|
||||
static void outliner_sync_select_from_outliner_set_types(bContext *C,
|
||||
SpaceOutliner *soops,
|
||||
SyncSelectTypes *sync_types)
|
||||
{
|
||||
Object *obact = CTX_data_active_object(C);
|
||||
Object *obedit = CTX_data_edit_object(C);
|
||||
|
||||
const bool sequence_view = soops->outlinevis == SO_SEQUENCE;
|
||||
|
||||
sync_types->object = !sequence_view && (obact && obact->mode == OB_MODE_OBJECT);
|
||||
sync_types->edit_bone = !sequence_view && (obedit && obedit->type == OB_ARMATURE);
|
||||
sync_types->pose_bone = !sequence_view && (obact && obact->mode == OB_MODE_POSE);
|
||||
sync_types->sequence = sequence_view;
|
||||
}
|
||||
|
||||
/**
|
||||
* Current dirty flags and outliner display mode determine which type of syncing should occur.
|
||||
* This is to ensure sync flag data is not lost on sync in the wrong display mode.
|
||||
*/
|
||||
static void outliner_sync_select_to_outliner_set_types(const bContext *C,
|
||||
SpaceOutliner *soops,
|
||||
SyncSelectTypes *sync_types)
|
||||
{
|
||||
Object *obact = CTX_data_active_object(C);
|
||||
Object *obedit = CTX_data_edit_object(C);
|
||||
|
||||
const bool sequence_view = soops->outlinevis == SO_SEQUENCE;
|
||||
|
||||
sync_types->object = !sequence_view && (obact && obact->mode == OB_MODE_OBJECT) &&
|
||||
(soops->sync_select_dirty & WM_OUTLINER_SYNC_SELECT_FROM_OBJECT);
|
||||
sync_types->edit_bone = !sequence_view && (obedit && obedit->type == OB_ARMATURE) &&
|
||||
(soops->sync_select_dirty & WM_OUTLINER_SYNC_SELECT_FROM_EDIT_BONE);
|
||||
sync_types->pose_bone = !sequence_view && (obact && obact->mode == OB_MODE_POSE) &&
|
||||
(soops->sync_select_dirty & WM_OUTLINER_SYNC_SELECT_FROM_POSE_BONE);
|
||||
sync_types->sequence = sequence_view &&
|
||||
(soops->sync_select_dirty & WM_OUTLINER_SYNC_SELECT_FROM_SEQUENCE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores items selected from a sync from the outliner. Prevents syncing the selection
|
||||
* state of the last instance of an object linked in multiple collections.
|
||||
*/
|
||||
typedef struct SelectedItems {
|
||||
GSet *objects;
|
||||
GSet *edit_bones;
|
||||
GSet *pose_bones;
|
||||
} SelectedItems;
|
||||
|
||||
static void selected_items_init(SelectedItems *selected_items)
|
||||
{
|
||||
selected_items->objects = BLI_gset_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
|
||||
selected_items->edit_bones = BLI_gset_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
|
||||
selected_items->pose_bones = BLI_gset_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
|
||||
}
|
||||
|
||||
static void selected_items_free(SelectedItems *selected_items)
|
||||
{
|
||||
BLI_gset_free(selected_items->objects, NULL);
|
||||
BLI_gset_free(selected_items->edit_bones, NULL);
|
||||
BLI_gset_free(selected_items->pose_bones, NULL);
|
||||
}
|
||||
|
||||
/* Check if an instance of this object been selected by the sync */
|
||||
static bool is_object_selected(GSet *selected_objects, Base *base)
|
||||
{
|
||||
return BLI_gset_haskey(selected_objects, base);
|
||||
}
|
||||
|
||||
/* Check if an instance of this edit bone been selected by the sync */
|
||||
static bool is_edit_bone_selected(GSet *selected_ebones, EditBone *ebone)
|
||||
{
|
||||
return BLI_gset_haskey(selected_ebones, ebone);
|
||||
}
|
||||
|
||||
/* Check if an instance of this pose bone been selected by the sync */
|
||||
static bool is_pose_bone_selected(GSet *selected_pbones, bPoseChannel *pchan)
|
||||
{
|
||||
return BLI_gset_haskey(selected_pbones, pchan);
|
||||
}
|
||||
|
||||
/* Add element's data to selected item set */
|
||||
static void add_selected_item(GSet *selected, void *data)
|
||||
{
|
||||
BLI_gset_add(selected, data);
|
||||
}
|
||||
|
||||
static void outliner_select_sync_to_object(ViewLayer *view_layer,
|
||||
TreeElement *te,
|
||||
TreeStoreElem *tselem,
|
||||
GSet *selected_objects)
|
||||
{
|
||||
Object *ob = (Object *)tselem->id;
|
||||
Base *base = (te->directdata) ? (Base *)te->directdata :
|
||||
BKE_view_layer_base_find(view_layer, ob);
|
||||
|
||||
if (base && (base->flag & BASE_SELECTABLE)) {
|
||||
if (tselem->flag & TSE_SELECTED) {
|
||||
ED_object_base_select(base, BA_SELECT);
|
||||
|
||||
add_selected_item(selected_objects, base);
|
||||
}
|
||||
else if (!is_object_selected(selected_objects, base)) {
|
||||
ED_object_base_select(base, BA_DESELECT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void outliner_select_sync_to_edit_bone(ViewLayer *view_layer,
|
||||
TreeElement *te,
|
||||
TreeStoreElem *tselem,
|
||||
GSet *selected_ebones)
|
||||
{
|
||||
bArmature *arm = (bArmature *)tselem->id;
|
||||
EditBone *ebone = (EditBone *)te->directdata;
|
||||
|
||||
short bone_flag = ebone->flag;
|
||||
|
||||
if (EBONE_SELECTABLE(arm, ebone)) {
|
||||
if (tselem->flag & TSE_SELECTED) {
|
||||
ebone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
|
||||
|
||||
add_selected_item(selected_ebones, ebone);
|
||||
}
|
||||
else if (!is_edit_bone_selected(selected_ebones, ebone)) {
|
||||
ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
|
||||
}
|
||||
}
|
||||
|
||||
/* Tag if selection changed */
|
||||
if (bone_flag != ebone->flag) {
|
||||
Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
|
||||
DEG_id_tag_update(&arm->id, ID_RECALC_SELECT);
|
||||
WM_main_add_notifier(NC_OBJECT | ND_BONE_SELECT, obedit);
|
||||
}
|
||||
}
|
||||
|
||||
static void outliner_select_sync_to_pose_bone(TreeElement *te,
|
||||
TreeStoreElem *tselem,
|
||||
GSet *selected_pbones)
|
||||
{
|
||||
Object *ob = (Object *)tselem->id;
|
||||
bArmature *arm = ob->data;
|
||||
bPoseChannel *pchan = (bPoseChannel *)te->directdata;
|
||||
|
||||
short bone_flag = pchan->bone->flag;
|
||||
|
||||
if (PBONE_SELECTABLE(arm, pchan->bone)) {
|
||||
if (tselem->flag & TSE_SELECTED) {
|
||||
pchan->bone->flag |= BONE_SELECTED;
|
||||
|
||||
add_selected_item(selected_pbones, pchan);
|
||||
}
|
||||
else if (!is_pose_bone_selected(selected_pbones, pchan)) {
|
||||
pchan->bone->flag &= ~BONE_SELECTED;
|
||||
}
|
||||
}
|
||||
|
||||
/* Tag if selection changed */
|
||||
if (bone_flag != pchan->bone->flag) {
|
||||
DEG_id_tag_update(&arm->id, ID_RECALC_SELECT);
|
||||
WM_main_add_notifier(NC_OBJECT | ND_BONE_SELECT, ob);
|
||||
}
|
||||
}
|
||||
|
||||
static void outliner_select_sync_to_sequence(Scene *scene, TreeStoreElem *tselem)
|
||||
{
|
||||
Sequence *seq = (Sequence *)tselem->id;
|
||||
|
||||
if (tselem->flag & TSE_ACTIVE) {
|
||||
BKE_sequencer_active_set(scene, seq);
|
||||
}
|
||||
|
||||
if (tselem->flag & TSE_SELECTED) {
|
||||
seq->flag |= SELECT;
|
||||
}
|
||||
else {
|
||||
seq->flag &= ~SELECT;
|
||||
}
|
||||
}
|
||||
|
||||
/** Sync select and active flags from outliner to active view layer, bones, and sequencer. */
|
||||
static void outliner_sync_selection_from_outliner(Scene *scene,
|
||||
ViewLayer *view_layer,
|
||||
ListBase *tree,
|
||||
const SyncSelectTypes *sync_types,
|
||||
SelectedItems *selected_items)
|
||||
{
|
||||
|
||||
for (TreeElement *te = tree->first; te; te = te->next) {
|
||||
TreeStoreElem *tselem = TREESTORE(te);
|
||||
|
||||
if (tselem->type == 0 && te->idcode == ID_OB) {
|
||||
if (sync_types->object) {
|
||||
outliner_select_sync_to_object(view_layer, te, tselem, selected_items->objects);
|
||||
}
|
||||
}
|
||||
else if (tselem->type == TSE_EBONE) {
|
||||
if (sync_types->edit_bone) {
|
||||
outliner_select_sync_to_edit_bone(view_layer, te, tselem, selected_items->edit_bones);
|
||||
}
|
||||
}
|
||||
else if (tselem->type == TSE_POSE_CHANNEL) {
|
||||
if (sync_types->pose_bone) {
|
||||
outliner_select_sync_to_pose_bone(te, tselem, selected_items->pose_bones);
|
||||
}
|
||||
}
|
||||
else if (tselem->type == TSE_SEQUENCE) {
|
||||
if (sync_types->sequence) {
|
||||
outliner_select_sync_to_sequence(scene, tselem);
|
||||
}
|
||||
}
|
||||
|
||||
outliner_sync_selection_from_outliner(
|
||||
scene, view_layer, &te->subtree, sync_types, selected_items);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set clean outliner and mark other outliners for syncing */
|
||||
void ED_outliner_select_sync_from_outliner(bContext *C, SpaceOutliner *soops)
|
||||
{
|
||||
/* Don't sync in certain outliner display modes */
|
||||
if (ELEM(soops->outlinevis, SO_LIBRARIES, SO_DATA_API, SO_ID_ORPHANS)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
ViewLayer *view_layer = CTX_data_view_layer(C);
|
||||
|
||||
SyncSelectTypes sync_types;
|
||||
outliner_sync_select_from_outliner_set_types(C, soops, &sync_types);
|
||||
|
||||
/* To store elements that have been selected to prevent linked object sync errors */
|
||||
SelectedItems selected_items;
|
||||
|
||||
selected_items_init(&selected_items);
|
||||
|
||||
outliner_sync_selection_from_outliner(
|
||||
scene, view_layer, &soops->tree, &sync_types, &selected_items);
|
||||
|
||||
selected_items_free(&selected_items);
|
||||
|
||||
/* Tag for updates */
|
||||
if (sync_types.object) {
|
||||
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
|
||||
}
|
||||
if (sync_types.sequence) {
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
|
||||
}
|
||||
|
||||
/* Clear outliner sync select dirty flag to prevent a sync to the outliner on draw */
|
||||
soops->sync_select_dirty &= ~WM_OUTLINER_SYNC_SELECT_FROM_ALL;
|
||||
}
|
||||
|
||||
static void outliner_select_sync_from_object(ViewLayer *view_layer,
|
||||
SpaceOutliner *soops,
|
||||
Object *obact,
|
||||
TreeElement *te,
|
||||
TreeStoreElem *tselem)
|
||||
{
|
||||
Object *ob = (Object *)tselem->id;
|
||||
Base *base = (te->directdata) ? (Base *)te->directdata :
|
||||
BKE_view_layer_base_find(view_layer, ob);
|
||||
const bool is_selected = (base != NULL) && ((base->flag & BASE_SELECTED) != 0);
|
||||
|
||||
if (base && (ob == obact)) {
|
||||
outliner_element_activate(soops, tselem);
|
||||
}
|
||||
|
||||
if (is_selected) {
|
||||
tselem->flag |= TSE_SELECTED;
|
||||
}
|
||||
else {
|
||||
tselem->flag &= ~TSE_SELECTED;
|
||||
}
|
||||
}
|
||||
|
||||
static void outliner_select_sync_from_edit_bone(SpaceOutliner *soops,
|
||||
EditBone *ebone_active,
|
||||
TreeElement *te,
|
||||
TreeStoreElem *tselem)
|
||||
{
|
||||
EditBone *ebone = (EditBone *)te->directdata;
|
||||
|
||||
if (ebone == ebone_active) {
|
||||
outliner_element_activate(soops, tselem);
|
||||
}
|
||||
|
||||
if (ebone->flag & BONE_SELECTED) {
|
||||
tselem->flag |= TSE_SELECTED;
|
||||
}
|
||||
else {
|
||||
tselem->flag &= ~TSE_SELECTED;
|
||||
}
|
||||
}
|
||||
|
||||
static void outliner_select_sync_from_pose_bone(SpaceOutliner *soops,
|
||||
bPoseChannel *pchan_active,
|
||||
TreeElement *te,
|
||||
TreeStoreElem *tselem)
|
||||
{
|
||||
bPoseChannel *pchan = (bPoseChannel *)te->directdata;
|
||||
Bone *bone = pchan->bone;
|
||||
|
||||
if (pchan == pchan_active) {
|
||||
outliner_element_activate(soops, tselem);
|
||||
}
|
||||
|
||||
if (bone->flag & BONE_SELECTED) {
|
||||
tselem->flag |= TSE_SELECTED;
|
||||
}
|
||||
else {
|
||||
tselem->flag &= ~TSE_SELECTED;
|
||||
}
|
||||
}
|
||||
|
||||
static void outliner_select_sync_from_sequence(SpaceOutliner *soops,
|
||||
Sequence *sequence_active,
|
||||
TreeStoreElem *tselem)
|
||||
{
|
||||
Sequence *seq = (Sequence *)tselem->id;
|
||||
|
||||
if (seq == sequence_active) {
|
||||
outliner_element_activate(soops, tselem);
|
||||
}
|
||||
|
||||
if (seq->flag & SELECT) {
|
||||
tselem->flag |= TSE_SELECTED;
|
||||
}
|
||||
else {
|
||||
tselem->flag &= ~TSE_SELECTED;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Contains active object, bones, and sequence for syncing to prevent getting active data
|
||||
* repeatedly throughout syncing to the outliner.
|
||||
*/
|
||||
typedef struct SyncSelectActiveData {
|
||||
Object *object;
|
||||
EditBone *edit_bone;
|
||||
bPoseChannel *pose_channel;
|
||||
Sequence *sequence;
|
||||
} SyncSelectActiveData;
|
||||
|
||||
/** Sync select and active flags from active view layer, bones, and sequences to the outliner. */
|
||||
static void outliner_sync_selection_to_outliner(ViewLayer *view_layer,
|
||||
SpaceOutliner *soops,
|
||||
ListBase *tree,
|
||||
SyncSelectActiveData *active_data,
|
||||
const SyncSelectTypes *sync_types)
|
||||
{
|
||||
for (TreeElement *te = tree->first; te; te = te->next) {
|
||||
TreeStoreElem *tselem = TREESTORE(te);
|
||||
|
||||
if (tselem->type == 0 && te->idcode == ID_OB) {
|
||||
if (sync_types->object) {
|
||||
outliner_select_sync_from_object(view_layer, soops, active_data->object, te, tselem);
|
||||
}
|
||||
}
|
||||
else if (tselem->type == TSE_EBONE) {
|
||||
if (sync_types->edit_bone) {
|
||||
outliner_select_sync_from_edit_bone(soops, active_data->edit_bone, te, tselem);
|
||||
}
|
||||
}
|
||||
else if (tselem->type == TSE_POSE_CHANNEL) {
|
||||
if (sync_types->pose_bone) {
|
||||
outliner_select_sync_from_pose_bone(soops, active_data->pose_channel, te, tselem);
|
||||
}
|
||||
}
|
||||
else if (tselem->type == TSE_SEQUENCE) {
|
||||
if (sync_types->sequence) {
|
||||
outliner_select_sync_from_sequence(soops, active_data->sequence, tselem);
|
||||
}
|
||||
}
|
||||
else {
|
||||
tselem->flag &= ~TSE_SELECTED;
|
||||
}
|
||||
|
||||
/* Sync subtree elements */
|
||||
outliner_sync_selection_to_outliner(view_layer, soops, &te->subtree, active_data, sync_types);
|
||||
}
|
||||
}
|
||||
|
||||
/* Get active data from context */
|
||||
static void get_sync_select_active_data(const bContext *C, SyncSelectActiveData *active_data)
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
ViewLayer *view_layer = CTX_data_view_layer(C);
|
||||
active_data->object = OBACT(view_layer);
|
||||
active_data->edit_bone = CTX_data_active_bone(C);
|
||||
active_data->pose_channel = CTX_data_active_pose_bone(C);
|
||||
active_data->sequence = BKE_sequencer_active_get(scene);
|
||||
}
|
||||
|
||||
/* If outliner is dirty sync selection from view layer and sequwncer */
|
||||
void outliner_sync_selection(const bContext *C, SpaceOutliner *soops)
|
||||
{
|
||||
if (soops->sync_select_dirty & WM_OUTLINER_SYNC_SELECT_FROM_ALL) {
|
||||
ViewLayer *view_layer = CTX_data_view_layer(C);
|
||||
|
||||
/* Set which types of data to sync from sync dirty flag and outliner display mode */
|
||||
SyncSelectTypes sync_types;
|
||||
outliner_sync_select_to_outliner_set_types(C, soops, &sync_types);
|
||||
|
||||
/* Store active object, bones, and sequence */
|
||||
SyncSelectActiveData active_data;
|
||||
get_sync_select_active_data(C, &active_data);
|
||||
|
||||
outliner_sync_selection_to_outliner(
|
||||
view_layer, soops, &soops->tree, &active_data, &sync_types);
|
||||
|
||||
/* Keep any unsynced data in the dirty flag */
|
||||
if (sync_types.object) {
|
||||
soops->sync_select_dirty &= ~WM_OUTLINER_SYNC_SELECT_FROM_OBJECT;
|
||||
}
|
||||
if (sync_types.edit_bone) {
|
||||
soops->sync_select_dirty &= ~WM_OUTLINER_SYNC_SELECT_FROM_EDIT_BONE;
|
||||
}
|
||||
if (sync_types.pose_bone) {
|
||||
soops->sync_select_dirty &= ~WM_OUTLINER_SYNC_SELECT_FROM_POSE_BONE;
|
||||
}
|
||||
if (sync_types.sequence) {
|
||||
soops->sync_select_dirty &= ~WM_OUTLINER_SYNC_SELECT_FROM_SEQUENCE;
|
||||
}
|
||||
}
|
||||
}
|
@@ -63,6 +63,7 @@
|
||||
|
||||
#include "ED_armature.h"
|
||||
#include "ED_object.h"
|
||||
#include "ED_outliner.h"
|
||||
#include "ED_scene.h"
|
||||
#include "ED_screen.h"
|
||||
#include "ED_sequencer.h"
|
||||
@@ -478,6 +479,127 @@ void OUTLINER_OT_scene_operation(wmOperatorType *ot)
|
||||
}
|
||||
/* ******************************************** */
|
||||
|
||||
/* Stores the parent and a child element of a merged iconrow icon for
|
||||
* the merged select popup menu. The subtree of the parent is searched and
|
||||
* the child is needed to only show elements of the same type in the popup. */
|
||||
typedef struct MergedSearchData {
|
||||
TreeElement *parent_element;
|
||||
TreeElement *select_element;
|
||||
} MergedSearchData;
|
||||
|
||||
static void merged_element_search_cb_recursive(
|
||||
const ListBase *tree, short tselem_type, short type, const char *str, uiSearchItems *items)
|
||||
{
|
||||
char name[64];
|
||||
int iconid;
|
||||
|
||||
for (TreeElement *te = tree->first; te; te = te->next) {
|
||||
TreeStoreElem *tselem = TREESTORE(te);
|
||||
|
||||
if (tree_element_id_type_to_index(te) == type && tselem_type == tselem->type) {
|
||||
if (BLI_strcasestr(te->name, str)) {
|
||||
BLI_strncpy(name, te->name, 64);
|
||||
|
||||
iconid = tree_element_get_icon(tselem, te).icon;
|
||||
|
||||
/* Don't allow duplicate named items */
|
||||
if (UI_search_items_find_index(items, name) == -1) {
|
||||
if (!UI_search_item_add(items, name, te, iconid)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
merged_element_search_cb_recursive(&te->subtree, tselem_type, type, str, items);
|
||||
}
|
||||
}
|
||||
|
||||
/* Get a list of elements that match the search string */
|
||||
static void merged_element_search_cb(const bContext *UNUSED(C),
|
||||
void *data,
|
||||
const char *str,
|
||||
uiSearchItems *items)
|
||||
{
|
||||
MergedSearchData *search_data = (MergedSearchData *)data;
|
||||
TreeElement *parent = search_data->parent_element;
|
||||
TreeElement *te = search_data->select_element;
|
||||
|
||||
int type = tree_element_id_type_to_index(te);
|
||||
|
||||
merged_element_search_cb_recursive(&parent->subtree, TREESTORE(te)->type, type, str, items);
|
||||
}
|
||||
|
||||
/* Activate an element from the merged element search menu */
|
||||
static void merged_element_search_call_cb(struct bContext *C, void *UNUSED(arg1), void *element)
|
||||
{
|
||||
SpaceOutliner *soops = CTX_wm_space_outliner(C);
|
||||
TreeElement *te = (TreeElement *)element;
|
||||
|
||||
outliner_item_select(soops, te, false, false);
|
||||
outliner_item_do_activate_from_tree_element(C, te, te->store_elem, false, false);
|
||||
|
||||
if (soops->flag & SO_SYNC_SELECT) {
|
||||
ED_outliner_select_sync_from_outliner(C, soops);
|
||||
}
|
||||
}
|
||||
|
||||
/** Merged element search menu
|
||||
* Created on activation of a merged or aggregated iconrow icon.
|
||||
*/
|
||||
static uiBlock *merged_element_search_menu(bContext *C, ARegion *ar, void *data)
|
||||
{
|
||||
static char search[64] = "";
|
||||
uiBlock *block;
|
||||
uiBut *but;
|
||||
|
||||
/* Clear search on each menu creation */
|
||||
*search = '\0';
|
||||
|
||||
block = UI_block_begin(C, ar, __func__, UI_EMBOSS);
|
||||
UI_block_flag_enable(block, UI_BLOCK_LOOP | UI_BLOCK_MOVEMOUSE_QUIT | UI_BLOCK_SEARCH_MENU);
|
||||
UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP);
|
||||
|
||||
short menu_width = 10 * UI_UNIT_X;
|
||||
but = uiDefSearchBut(
|
||||
block, search, 0, ICON_VIEWZOOM, sizeof(search), 10, 10, menu_width, UI_UNIT_Y, 0, 0, "");
|
||||
UI_but_func_search_set(
|
||||
but, NULL, merged_element_search_cb, data, false, merged_element_search_call_cb, NULL);
|
||||
UI_but_flag_enable(but, UI_BUT_ACTIVATE_ON_INIT);
|
||||
|
||||
/* Fake button to hold space for search items */
|
||||
uiDefBut(block,
|
||||
UI_BTYPE_LABEL,
|
||||
0,
|
||||
"",
|
||||
10,
|
||||
10 - UI_searchbox_size_y(),
|
||||
menu_width,
|
||||
UI_searchbox_size_y(),
|
||||
NULL,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
NULL);
|
||||
|
||||
/* Center the menu on the cursor */
|
||||
UI_block_bounds_set_popup(block, 6, (const int[2]){-(menu_width / 2), 0});
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
void merged_element_search_menu_invoke(bContext *C,
|
||||
TreeElement *parent_te,
|
||||
TreeElement *activate_te)
|
||||
{
|
||||
MergedSearchData *select_data = MEM_callocN(sizeof(MergedSearchData), "merge_search_data");
|
||||
select_data->parent_element = parent_te;
|
||||
select_data->select_element = activate_te;
|
||||
|
||||
UI_popup_block_invoke(C, merged_element_search_menu, select_data, MEM_freeN);
|
||||
}
|
||||
|
||||
static void object_select_cb(bContext *C,
|
||||
ReportList *UNUSED(reports),
|
||||
Scene *UNUSED(scene),
|
||||
|
@@ -297,7 +297,7 @@ static void outliner_add_scene_contents(SpaceOutliner *soops,
|
||||
|
||||
ViewLayer *view_layer;
|
||||
for (view_layer = sce->view_layers.first; view_layer; view_layer = view_layer->next) {
|
||||
TreeElement *tenlay = outliner_add_element(soops, &ten->subtree, sce, te, TSE_R_LAYER, 0);
|
||||
TreeElement *tenlay = outliner_add_element(soops, &ten->subtree, sce, ten, TSE_R_LAYER, 0);
|
||||
tenlay->name = view_layer->name;
|
||||
tenlay->directdata = view_layer;
|
||||
}
|
||||
@@ -314,7 +314,7 @@ static void outliner_add_scene_contents(SpaceOutliner *soops,
|
||||
ten = outliner_add_element(soops, lb, sce, te, TSE_SCENE_OBJECTS_BASE, 0);
|
||||
ten->name = IFACE_("Objects");
|
||||
FOREACH_SCENE_OBJECT_BEGIN (sce, ob) {
|
||||
outliner_add_element(soops, &ten->subtree, ob, NULL, 0, 0);
|
||||
outliner_add_element(soops, &ten->subtree, ob, ten, 0, 0);
|
||||
}
|
||||
FOREACH_SCENE_OBJECT_END;
|
||||
outliner_make_object_parent_hierarchy(&ten->subtree);
|
||||
@@ -2008,6 +2008,9 @@ static int outliner_exclude_filter_get(SpaceOutliner *soops)
|
||||
case SO_FILTER_OB_VISIBLE:
|
||||
exclude_filter |= SO_FILTER_OB_STATE_VISIBLE;
|
||||
break;
|
||||
case SO_FILTER_OB_INVISIBLE:
|
||||
exclude_filter |= SO_FILTER_OB_STATE_INVISIBLE;
|
||||
break;
|
||||
case SO_FILTER_OB_SELECTED:
|
||||
exclude_filter |= SO_FILTER_OB_STATE_SELECTED;
|
||||
break;
|
||||
@@ -2086,6 +2089,11 @@ static bool outliner_element_visible_get(ViewLayer *view_layer,
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (exclude_filter & SO_FILTER_OB_STATE_INVISIBLE) {
|
||||
if ((base->flag & BASE_VISIBLE) != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (exclude_filter & SO_FILTER_OB_STATE_SELECTED) {
|
||||
if ((base->flag & BASE_SELECTED) == 0) {
|
||||
return false;
|
||||
@@ -2339,7 +2347,8 @@ void outliner_build_tree(
|
||||
te = outliner_add_element(soops, &soops->tree, sce, NULL, 0, 0);
|
||||
tselem = TREESTORE(te);
|
||||
|
||||
if (sce == scene && show_opened) {
|
||||
/* New scene elements open by default */
|
||||
if ((sce == scene && show_opened) || !tselem->used) {
|
||||
tselem->flag &= ~TSE_CLOSED;
|
||||
}
|
||||
|
||||
|
@@ -24,11 +24,15 @@
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "DNA_action_types.h"
|
||||
#include "DNA_screen_types.h"
|
||||
#include "DNA_space_types.h"
|
||||
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_outliner_treehash.h"
|
||||
#include "BKE_layer.h"
|
||||
|
||||
#include "ED_armature.h"
|
||||
#include "ED_outliner.h"
|
||||
|
||||
#include "UI_interface.h"
|
||||
#include "UI_view2d.h"
|
||||
@@ -62,6 +66,38 @@ TreeElement *outliner_find_item_at_y(const SpaceOutliner *soops,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static TreeElement *outliner_find_item_at_x_in_row_recursive(const TreeElement *parent_te,
|
||||
float view_co_x,
|
||||
bool *r_merged)
|
||||
{
|
||||
TreeElement *child_te = parent_te->subtree.first;
|
||||
|
||||
bool over_element = false;
|
||||
|
||||
while (child_te) {
|
||||
over_element = (view_co_x > child_te->xs) && (view_co_x < child_te->xend);
|
||||
if ((child_te->flag & TE_ICONROW) && over_element) {
|
||||
return child_te;
|
||||
}
|
||||
else if ((child_te->flag & TE_ICONROW_MERGED) && over_element) {
|
||||
if (r_merged) {
|
||||
*r_merged = true;
|
||||
}
|
||||
return child_te;
|
||||
}
|
||||
|
||||
TreeElement *te = outliner_find_item_at_x_in_row_recursive(child_te, view_co_x, r_merged);
|
||||
if (te != child_te) {
|
||||
return te;
|
||||
}
|
||||
|
||||
child_te = child_te->next;
|
||||
}
|
||||
|
||||
/* return parent if no child is hovered */
|
||||
return (TreeElement *)parent_te;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collapsed items can show their children as click-able icons. This function tries to find
|
||||
* such an icon that represents the child item at x-coordinate \a view_co_x (view-space).
|
||||
@@ -70,24 +106,14 @@ TreeElement *outliner_find_item_at_y(const SpaceOutliner *soops,
|
||||
*/
|
||||
TreeElement *outliner_find_item_at_x_in_row(const SpaceOutliner *soops,
|
||||
const TreeElement *parent_te,
|
||||
float view_co_x)
|
||||
float view_co_x,
|
||||
bool *r_merged)
|
||||
{
|
||||
/* if parent_te is opened, it doesn't show childs in row */
|
||||
/* if parent_te is opened, it doesn't show children in row */
|
||||
if (!TSELEM_OPEN(TREESTORE(parent_te), soops)) {
|
||||
/* no recursion, items can only display their direct children in the row */
|
||||
for (TreeElement *child_te = parent_te->subtree.first;
|
||||
/* don't look further if co_x is smaller than child position*/
|
||||
child_te && view_co_x >= child_te->xs;
|
||||
|
||||
child_te = child_te->next) {
|
||||
if ((child_te->flag & TE_ICONROW) && (view_co_x > child_te->xs) &&
|
||||
(view_co_x < child_te->xend)) {
|
||||
return child_te;
|
||||
}
|
||||
}
|
||||
return outliner_find_item_at_x_in_row_recursive(parent_te, view_co_x, r_merged);
|
||||
}
|
||||
|
||||
/* return parent if no child is hovered */
|
||||
return (TreeElement *)parent_te;
|
||||
}
|
||||
|
||||
@@ -300,3 +326,89 @@ float outliner_restrict_columns_width(const SpaceOutliner *soops)
|
||||
}
|
||||
return (num_columns * UI_UNIT_X + V2D_SCROLL_WIDTH);
|
||||
}
|
||||
|
||||
/* Find first tree element in tree with matching treestore flag */
|
||||
TreeElement *outliner_find_element_with_flag(const ListBase *lb, short flag)
|
||||
{
|
||||
for (TreeElement *te = lb->first; te; te = te->next) {
|
||||
if ((TREESTORE(te)->flag & flag) == flag) {
|
||||
return te;
|
||||
}
|
||||
TreeElement *active_element = outliner_find_element_with_flag(&te->subtree, flag);
|
||||
if (active_element) {
|
||||
return active_element;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Find if element is visible in the outliner tree */
|
||||
bool outliner_is_element_visible(const TreeElement *te)
|
||||
{
|
||||
TreeStoreElem *tselem;
|
||||
|
||||
while (te->parent) {
|
||||
tselem = TREESTORE(te->parent);
|
||||
|
||||
if (tselem->flag & TSE_CLOSED) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
te = te->parent;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Find if x coordinate is over element disclosure toggle */
|
||||
bool outliner_item_is_co_within_close_toggle(TreeElement *te, float view_co_x)
|
||||
{
|
||||
return (view_co_x > te->xs) && (view_co_x < te->xs + UI_UNIT_X);
|
||||
}
|
||||
|
||||
/* Scroll view vertically while keeping within total bounds */
|
||||
void outliner_scroll_view(ARegion *ar, int delta_y)
|
||||
{
|
||||
int y_min = MIN2(ar->v2d.cur.ymin, ar->v2d.tot.ymin);
|
||||
|
||||
ar->v2d.cur.ymax += delta_y;
|
||||
ar->v2d.cur.ymin += delta_y;
|
||||
|
||||
/* Adjust view if delta placed view outside total area */
|
||||
int offset;
|
||||
if (ar->v2d.cur.ymax > -UI_UNIT_Y) {
|
||||
offset = ar->v2d.cur.ymax;
|
||||
ar->v2d.cur.ymax -= offset;
|
||||
ar->v2d.cur.ymin -= offset;
|
||||
}
|
||||
else if (ar->v2d.cur.ymin < y_min) {
|
||||
offset = y_min - ar->v2d.cur.ymin;
|
||||
ar->v2d.cur.ymax += offset;
|
||||
ar->v2d.cur.ymin += offset;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get base of object under cursor. Used for eyedropper tool */
|
||||
Base *ED_outliner_give_base_under_cursor(bContext *C, const int mval[2])
|
||||
{
|
||||
ARegion *ar = CTX_wm_region(C);
|
||||
ViewLayer *view_layer = CTX_data_view_layer(C);
|
||||
SpaceOutliner *soops = CTX_wm_space_outliner(C);
|
||||
TreeElement *te;
|
||||
Base *base = NULL;
|
||||
float view_mval[2];
|
||||
|
||||
UI_view2d_region_to_view(&ar->v2d, mval[0], mval[1], &view_mval[0], &view_mval[1]);
|
||||
|
||||
te = outliner_find_item_at_y(soops, &soops->tree, view_mval[1]);
|
||||
if (te) {
|
||||
TreeStoreElem *tselem = TREESTORE(te);
|
||||
if (tselem->type == 0) {
|
||||
Object *ob = (Object *)tselem->id;
|
||||
base = (te->directdata) ? (Base *)te->directdata : BKE_view_layer_base_find(view_layer, ob);
|
||||
}
|
||||
}
|
||||
|
||||
return base;
|
||||
}
|
||||
|
@@ -131,6 +131,9 @@ static void outliner_main_region_listener(wmWindow *UNUSED(win),
|
||||
ED_region_tag_redraw(ar);
|
||||
break;
|
||||
}
|
||||
if (wmn->action & NA_EDITED) {
|
||||
ED_region_tag_redraw(ar);
|
||||
}
|
||||
break;
|
||||
case NC_OBJECT:
|
||||
switch (wmn->data) {
|
||||
@@ -145,13 +148,8 @@ static void outliner_main_region_listener(wmWindow *UNUSED(win),
|
||||
ED_region_tag_redraw(ar);
|
||||
break;
|
||||
case ND_CONSTRAINT:
|
||||
switch (wmn->action) {
|
||||
case NA_ADDED:
|
||||
case NA_REMOVED:
|
||||
case NA_RENAME:
|
||||
ED_region_tag_redraw(ar);
|
||||
break;
|
||||
}
|
||||
/* all constraint actions now, for reordering */
|
||||
ED_region_tag_redraw(ar);
|
||||
break;
|
||||
case ND_MODIFIER:
|
||||
/* all modifier actions now */
|
||||
@@ -304,6 +302,8 @@ static SpaceLink *outliner_new(const ScrArea *UNUSED(area), const Scene *UNUSED(
|
||||
soutliner->filter_id_type = ID_GR;
|
||||
soutliner->show_restrict_flags = SO_RESTRICT_ENABLE | SO_RESTRICT_HIDE;
|
||||
soutliner->outlinevis = SO_VIEW_LAYER;
|
||||
soutliner->sync_select_dirty |= WM_OUTLINER_SYNC_SELECT_FROM_ALL;
|
||||
soutliner->flag |= SO_SYNC_SELECT;
|
||||
|
||||
/* header */
|
||||
ar = MEM_callocN(sizeof(ARegion), "header for outliner");
|
||||
@@ -349,6 +349,9 @@ static SpaceLink *outliner_duplicate(SpaceLink *sl)
|
||||
soutlinern->treestore = NULL;
|
||||
soutlinern->treehash = NULL;
|
||||
|
||||
soutlinern->flag |= (soutliner->flag & SO_SYNC_SELECT);
|
||||
soutlinern->sync_select_dirty = WM_OUTLINER_SYNC_SELECT_FROM_ALL;
|
||||
|
||||
return (SpaceLink *)soutlinern;
|
||||
}
|
||||
|
||||
@@ -415,7 +418,7 @@ void ED_spacetype_outliner(void)
|
||||
/* regions: main window */
|
||||
art = MEM_callocN(sizeof(ARegionType), "spacetype outliner region");
|
||||
art->regionid = RGN_TYPE_WINDOW;
|
||||
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES;
|
||||
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D;
|
||||
|
||||
art->init = outliner_main_region_init;
|
||||
art->draw = outliner_main_region_draw;
|
||||
@@ -428,7 +431,7 @@ void ED_spacetype_outliner(void)
|
||||
art = MEM_callocN(sizeof(ARegionType), "spacetype outliner header region");
|
||||
art->regionid = RGN_TYPE_HEADER;
|
||||
art->prefsizey = HEADERY;
|
||||
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER;
|
||||
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_HEADER;
|
||||
|
||||
art->init = outliner_header_region_init;
|
||||
art->draw = outliner_header_region_draw;
|
||||
|
@@ -41,6 +41,7 @@
|
||||
|
||||
/* for menu/popup icons etc etc*/
|
||||
|
||||
#include "ED_outliner.h"
|
||||
#include "ED_screen.h"
|
||||
#include "ED_sequencer.h"
|
||||
#include "ED_select_utils.h"
|
||||
@@ -49,6 +50,7 @@
|
||||
|
||||
/* own include */
|
||||
#include "sequencer_intern.h"
|
||||
|
||||
static void *find_nearest_marker(int UNUSED(d1), int UNUSED(d2))
|
||||
{
|
||||
return NULL;
|
||||
@@ -254,6 +256,8 @@ static int sequencer_de_select_all_exec(bContext *C, wmOperator *op)
|
||||
}
|
||||
}
|
||||
|
||||
ED_outliner_select_sync_from_sequence_tag(C);
|
||||
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
@@ -293,6 +297,8 @@ static int sequencer_select_inverse_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
}
|
||||
}
|
||||
|
||||
ED_outliner_select_sync_from_sequence_tag(C);
|
||||
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
@@ -542,6 +548,8 @@ static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *e
|
||||
}
|
||||
}
|
||||
|
||||
ED_outliner_select_sync_from_sequence_tag(C);
|
||||
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
|
||||
|
||||
/* allowing tweaks */
|
||||
@@ -668,6 +676,8 @@ static int sequencer_select_more_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
ED_outliner_select_sync_from_sequence_tag(C);
|
||||
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
@@ -699,6 +709,8 @@ static int sequencer_select_less_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
ED_outliner_select_sync_from_sequence_tag(C);
|
||||
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
@@ -750,6 +762,8 @@ static int sequencer_select_linked_pick_invoke(bContext *C, wmOperator *op, cons
|
||||
selected = select_more_less_seq__internal(scene, 1, 1);
|
||||
}
|
||||
|
||||
ED_outliner_select_sync_from_sequence_tag(C);
|
||||
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
@@ -784,6 +798,8 @@ static int sequencer_select_linked_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
selected = select_more_less_seq__internal(scene, true, true);
|
||||
}
|
||||
|
||||
ED_outliner_select_sync_from_sequence_tag(C);
|
||||
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
@@ -832,6 +848,8 @@ static int sequencer_select_handles_exec(bContext *C, wmOperator *op)
|
||||
}
|
||||
}
|
||||
|
||||
ED_outliner_select_sync_from_sequence_tag(C);
|
||||
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
@@ -876,6 +894,8 @@ static int sequencer_select_active_side_exec(bContext *C, wmOperator *op)
|
||||
select_active_side(
|
||||
ed->seqbasep, RNA_enum_get(op->ptr, "side"), seq_act->machine, seq_act->startdisp);
|
||||
|
||||
ED_outliner_select_sync_from_sequence_tag(C);
|
||||
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
@@ -934,6 +954,8 @@ static int sequencer_box_select_exec(bContext *C, wmOperator *op)
|
||||
}
|
||||
}
|
||||
|
||||
ED_outliner_select_sync_from_sequence_tag(C);
|
||||
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
@@ -1311,6 +1333,7 @@ static int sequencer_select_grouped_exec(bContext *C, wmOperator *op)
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
ED_outliner_select_sync_from_sequence_tag(C);
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
@@ -88,6 +88,7 @@
|
||||
#include "ED_particle.h"
|
||||
#include "ED_mesh.h"
|
||||
#include "ED_object.h"
|
||||
#include "ED_outliner.h"
|
||||
#include "ED_screen.h"
|
||||
#include "ED_select_utils.h"
|
||||
#include "ED_sculpt.h"
|
||||
@@ -1280,9 +1281,15 @@ static bool view3d_lasso_select(
|
||||
}
|
||||
else if (ob && (ob->mode & OB_MODE_POSE)) {
|
||||
changed_multi |= do_lasso_select_pose(vc, mcords, moves, sel_op);
|
||||
if (changed_multi) {
|
||||
ED_outliner_select_sync_from_pose_bone_tag(C);
|
||||
}
|
||||
}
|
||||
else {
|
||||
changed_multi |= do_lasso_select_objects(vc, mcords, moves, sel_op);
|
||||
if (changed_multi) {
|
||||
ED_outliner_select_sync_from_object_tag(C);
|
||||
}
|
||||
}
|
||||
}
|
||||
else { /* Edit Mode */
|
||||
@@ -1303,6 +1310,9 @@ static bool view3d_lasso_select(
|
||||
break;
|
||||
case OB_ARMATURE:
|
||||
changed = do_lasso_select_armature(vc, mcords, moves, sel_op);
|
||||
if (changed) {
|
||||
ED_outliner_select_sync_from_edit_bone_tag(C);
|
||||
}
|
||||
break;
|
||||
case OB_MBALL:
|
||||
changed = do_lasso_select_meta(vc, mcords, moves, sel_op);
|
||||
@@ -1488,6 +1498,9 @@ static int object_select_menu_exec(bContext *C, wmOperator *op)
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
|
||||
|
||||
ED_outliner_select_sync_from_object_tag(C);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
else {
|
||||
@@ -2350,6 +2363,9 @@ static int view3d_select_exec(bContext *C, wmOperator *op)
|
||||
if (!retval && deselect_all) {
|
||||
retval = ED_armature_edit_deselect_all_visible_multi(C);
|
||||
}
|
||||
if (retval) {
|
||||
ED_outliner_select_sync_from_edit_bone_tag(C);
|
||||
}
|
||||
}
|
||||
else if (obedit->type == OB_LATTICE) {
|
||||
retval = ED_lattice_select_pick(C, location, extend, deselect, toggle);
|
||||
@@ -2410,6 +2426,15 @@ static int view3d_select_exec(bContext *C, wmOperator *op)
|
||||
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
|
||||
}
|
||||
}
|
||||
|
||||
if (retval) {
|
||||
if (obact && obact->mode & OB_MODE_POSE) {
|
||||
ED_outliner_select_sync_from_pose_bone_tag(C);
|
||||
}
|
||||
else {
|
||||
ED_outliner_select_sync_from_object_tag(C);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Pass-through allows tweaks
|
||||
@@ -3230,6 +3255,7 @@ static int view3d_box_select_exec(bContext *C, wmOperator *op)
|
||||
if (changed) {
|
||||
DEG_id_tag_update(&vc.obedit->id, ID_RECALC_SELECT);
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, vc.obedit);
|
||||
ED_outliner_select_sync_from_edit_bone_tag(C);
|
||||
}
|
||||
break;
|
||||
case OB_LATTICE:
|
||||
@@ -3264,9 +3290,15 @@ static int view3d_box_select_exec(bContext *C, wmOperator *op)
|
||||
}
|
||||
else if (vc.obact && vc.obact->mode & OB_MODE_POSE) {
|
||||
changed_multi = do_pose_box_select(C, &vc, &rect, sel_op);
|
||||
if (changed_multi) {
|
||||
ED_outliner_select_sync_from_pose_bone_tag(C);
|
||||
}
|
||||
}
|
||||
else { /* object mode with none active */
|
||||
changed_multi = do_object_box_select(C, &vc, &rect, sel_op);
|
||||
if (changed_multi) {
|
||||
ED_outliner_select_sync_from_object_tag(C);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3890,7 +3922,8 @@ static bool mball_circle_select(ViewContext *vc,
|
||||
|
||||
/** Callbacks for circle selection in Editmode */
|
||||
|
||||
static bool obedit_circle_select(ViewContext *vc,
|
||||
static bool obedit_circle_select(bContext *C,
|
||||
ViewContext *vc,
|
||||
wmGenericUserData *wm_userdata,
|
||||
const eSelectOp sel_op,
|
||||
const int mval[2],
|
||||
@@ -3911,6 +3944,9 @@ static bool obedit_circle_select(ViewContext *vc,
|
||||
break;
|
||||
case OB_ARMATURE:
|
||||
changed = armature_circle_select(vc, sel_op, mval, rad);
|
||||
if (changed) {
|
||||
ED_outliner_select_sync_from_edit_bone_tag(C);
|
||||
}
|
||||
break;
|
||||
case OB_MBALL:
|
||||
changed = mball_circle_select(vc, sel_op, mval, rad);
|
||||
@@ -3999,7 +4035,7 @@ static int view3d_circle_select_exec(bContext *C, wmOperator *op)
|
||||
obedit = vc.obedit;
|
||||
|
||||
if (obedit) {
|
||||
obedit_circle_select(&vc, wm_userdata, sel_op, mval, (float)radius);
|
||||
obedit_circle_select(C, &vc, wm_userdata, sel_op, mval, (float)radius);
|
||||
}
|
||||
else if (BKE_paint_select_face_test(obact)) {
|
||||
paint_facesel_circle_select(&vc, wm_userdata, sel_op, mval, (float)radius);
|
||||
@@ -4009,6 +4045,7 @@ static int view3d_circle_select_exec(bContext *C, wmOperator *op)
|
||||
}
|
||||
else if (obact->mode & OB_MODE_POSE) {
|
||||
pose_circle_select(&vc, sel_op, mval, (float)radius);
|
||||
ED_outliner_select_sync_from_pose_bone_tag(C);
|
||||
}
|
||||
else {
|
||||
BLI_assert(0);
|
||||
@@ -4029,6 +4066,8 @@ static int view3d_circle_select_exec(bContext *C, wmOperator *op)
|
||||
if (object_circle_select(&vc, sel_op, mval, (float)radius)) {
|
||||
DEG_id_tag_update(&vc.scene->id, ID_RECALC_SELECT);
|
||||
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, vc.scene);
|
||||
|
||||
ED_outliner_select_sync_from_object_tag(C);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -60,6 +60,10 @@ enum {
|
||||
TSE_DRAG_INTO = (1 << 6),
|
||||
TSE_DRAG_BEFORE = (1 << 7),
|
||||
TSE_DRAG_AFTER = (1 << 8),
|
||||
/* Needed because outliner-only elements can be active */
|
||||
TSE_ACTIVE = (1 << 9),
|
||||
/* Needed because walk selection should not activate */
|
||||
TSE_ACTIVE_WALK = (1 << 10),
|
||||
TSE_DRAG_ANY = (TSE_DRAG_INTO | TSE_DRAG_BEFORE | TSE_DRAG_AFTER),
|
||||
};
|
||||
|
||||
|
@@ -244,7 +244,12 @@ typedef struct SpaceOutliner {
|
||||
char search_string[64];
|
||||
struct TreeStoreElem search_tse;
|
||||
|
||||
short flag, outlinevis, storeflag, search_flags;
|
||||
short flag, outlinevis, storeflag;
|
||||
char search_flags;
|
||||
|
||||
/** Selection syncing flag (#WM_OUTLINER_SYNC_SELECT_FROM_OBJECT and similar flags). */
|
||||
char sync_select_dirty;
|
||||
|
||||
int filter;
|
||||
char filter_state;
|
||||
char show_restrict_flags;
|
||||
@@ -263,6 +268,7 @@ typedef enum eSpaceOutliner_Flag {
|
||||
SO_FLAG_UNUSED_1 = (1 << 2), /* cleared */
|
||||
SO_HIDE_KEYINGSETINFO = (1 << 3),
|
||||
SO_SKIP_SORT_ALPHA = (1 << 4),
|
||||
SO_SYNC_SELECT = (1 << 5),
|
||||
} eSpaceOutliner_Flag;
|
||||
|
||||
/* SpaceOutliner.filter */
|
||||
@@ -281,13 +287,14 @@ typedef enum eSpaceOutliner_Filter {
|
||||
SO_FILTER_NO_OB_CAMERA = (1 << 10),
|
||||
SO_FILTER_NO_OB_OTHERS = (1 << 11),
|
||||
|
||||
SO_FILTER_UNUSED_12 = (1 << 12), /* cleared */
|
||||
SO_FILTER_OB_STATE_VISIBLE = (1 << 13), /* Not set via DNA. */
|
||||
SO_FILTER_OB_STATE_SELECTED = (1 << 14), /* Not set via DNA. */
|
||||
SO_FILTER_OB_STATE_ACTIVE = (1 << 15), /* Not set via DNA. */
|
||||
SO_FILTER_NO_COLLECTION = (1 << 16),
|
||||
SO_FILTER_UNUSED_12 = (1 << 12), /* cleared */
|
||||
SO_FILTER_OB_STATE_VISIBLE = (1 << 13), /* Not set via DNA. */
|
||||
SO_FILTER_OB_STATE_INVISIBLE = (1 << 14), /* Not set via DNA. */
|
||||
SO_FILTER_OB_STATE_SELECTED = (1 << 15), /* Not set via DNA. */
|
||||
SO_FILTER_OB_STATE_ACTIVE = (1 << 16), /* Not set via DNA. */
|
||||
SO_FILTER_NO_COLLECTION = (1 << 17),
|
||||
|
||||
SO_FILTER_ID_TYPE = (1 << 17),
|
||||
SO_FILTER_ID_TYPE = (1 << 18),
|
||||
} eSpaceOutliner_Filter;
|
||||
|
||||
#define SO_FILTER_OB_TYPE \
|
||||
@@ -295,7 +302,8 @@ typedef enum eSpaceOutliner_Filter {
|
||||
SO_FILTER_NO_OB_LAMP | SO_FILTER_NO_OB_CAMERA | SO_FILTER_NO_OB_OTHERS)
|
||||
|
||||
#define SO_FILTER_OB_STATE \
|
||||
(SO_FILTER_OB_STATE_VISIBLE | SO_FILTER_OB_STATE_SELECTED | SO_FILTER_OB_STATE_ACTIVE)
|
||||
(SO_FILTER_OB_STATE_VISIBLE | SO_FILTER_OB_STATE_INVISIBLE | SO_FILTER_OB_STATE_SELECTED | \
|
||||
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 | \
|
||||
@@ -305,8 +313,9 @@ typedef enum eSpaceOutliner_Filter {
|
||||
typedef enum eSpaceOutliner_StateFilter {
|
||||
SO_FILTER_OB_ALL = 0,
|
||||
SO_FILTER_OB_VISIBLE = 1,
|
||||
SO_FILTER_OB_SELECTED = 2,
|
||||
SO_FILTER_OB_ACTIVE = 3,
|
||||
SO_FILTER_OB_INVISIBLE = 2,
|
||||
SO_FILTER_OB_SELECTED = 3,
|
||||
SO_FILTER_OB_ACTIVE = 4,
|
||||
} eSpaceOutliner_StateFilter;
|
||||
|
||||
/* SpaceOutliner.show_restrict_flags */
|
||||
|
@@ -131,12 +131,15 @@ typedef struct wmWindowManager {
|
||||
ListBase windows;
|
||||
|
||||
/** Set on file read. */
|
||||
int initialized;
|
||||
short initialized;
|
||||
/** Indicator whether data was saved. */
|
||||
short file_saved;
|
||||
/** Operator stack depth to avoid nested undo pushes. */
|
||||
short op_undo_depth;
|
||||
|
||||
/** Set after selection to notify outliner to sync. Stores type of selection */
|
||||
short outliner_sync_select_dirty;
|
||||
|
||||
/** Operator registry. */
|
||||
ListBase operators;
|
||||
|
||||
@@ -186,6 +189,18 @@ enum {
|
||||
WM_KEYCONFIG_IS_INITIALIZED = (1 << 1),
|
||||
};
|
||||
|
||||
/* wmWindowManager.outliner_sync_select_dirty */
|
||||
enum {
|
||||
WM_OUTLINER_SYNC_SELECT_FROM_OBJECT = (1 << 0),
|
||||
WM_OUTLINER_SYNC_SELECT_FROM_EDIT_BONE = (1 << 1),
|
||||
WM_OUTLINER_SYNC_SELECT_FROM_POSE_BONE = (1 << 2),
|
||||
WM_OUTLINER_SYNC_SELECT_FROM_SEQUENCE = (1 << 3),
|
||||
};
|
||||
|
||||
#define WM_OUTLINER_SYNC_SELECT_FROM_ALL \
|
||||
(WM_OUTLINER_SYNC_SELECT_FROM_OBJECT | WM_OUTLINER_SYNC_SELECT_FROM_EDIT_BONE | \
|
||||
WM_OUTLINER_SYNC_SELECT_FROM_POSE_BONE | WM_OUTLINER_SYNC_SELECT_FROM_SEQUENCE)
|
||||
|
||||
#define WM_KEYCONFIG_STR_DEFAULT "blender"
|
||||
|
||||
/* IME is win32 only! */
|
||||
|
@@ -1009,7 +1009,7 @@ static void rna_def_constraint_armature_deform(BlenderRNA *brna)
|
||||
RNA_def_struct_ui_text(
|
||||
srna, "Armature Constraint", "Applies transformations done by the Armature modifier");
|
||||
RNA_def_struct_sdna_from(srna, "bArmatureConstraint", "data");
|
||||
RNA_def_struct_ui_icon(srna, ICON_MOD_ARMATURE);
|
||||
RNA_def_struct_ui_icon(srna, ICON_CON_ARMATURE);
|
||||
|
||||
prop = RNA_def_property(srna, "targets", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_collection_sdna(prop, NULL, "targets", NULL);
|
||||
@@ -3026,6 +3026,7 @@ void RNA_def_constraint(BlenderRNA *brna)
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
|
||||
RNA_def_property_ui_text(prop, "Disable", "Enable/Disable Constraint");
|
||||
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
|
||||
RNA_def_property_ui_icon(prop, ICON_HIDE_OFF, -1);
|
||||
|
||||
prop = RNA_def_property(srna, "show_expanded", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_flag(prop, PROP_NO_DEG_UPDATE);
|
||||
|
@@ -2777,6 +2777,7 @@ static void rna_def_space_outliner(BlenderRNA *brna)
|
||||
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"},
|
||||
{SO_FILTER_OB_INVISIBLE, "INVISIBLE", 0, "Invisible", "Show invisible objects"},
|
||||
{SO_FILTER_OB_SELECTED, "SELECTED", 0, "Selected", "Show selected objects"},
|
||||
{SO_FILTER_OB_ACTIVE, "ACTIVE", 0, "Active", "Show only the active object"},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
@@ -2815,6 +2816,12 @@ static void rna_def_space_outliner(BlenderRNA *brna)
|
||||
RNA_def_property_ui_text(prop, "Sort Alphabetically", "");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "use_sync_select", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", SO_SYNC_SELECT);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Sync Outliner Selection", "Sync outliner selection with other editors");
|
||||
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);
|
||||
|
@@ -2297,6 +2297,11 @@ static void rna_def_userdef_theme_space_outliner(BlenderRNA *brna)
|
||||
RNA_def_property_ui_text(prop, "Selected Highlight", "");
|
||||
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
|
||||
|
||||
prop = RNA_def_property(srna, "active", PROP_FLOAT, PROP_COLOR_GAMMA);
|
||||
RNA_def_property_array(prop, 3);
|
||||
RNA_def_property_ui_text(prop, "Active Highlight", "");
|
||||
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
|
||||
|
||||
prop = RNA_def_property(srna, "selected_object", PROP_FLOAT, PROP_COLOR_GAMMA);
|
||||
RNA_def_property_array(prop, 3);
|
||||
RNA_def_property_ui_text(prop, "Selected Objects", "");
|
||||
|
Reference in New Issue
Block a user