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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/editors/space_outliner')
-rw-r--r--source/blender/editors/space_outliner/CMakeLists.txt6
-rw-r--r--source/blender/editors/space_outliner/SConscript8
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c413
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.c284
-rw-r--r--source/blender/editors/space_outliner/outliner_intern.h57
-rw-r--r--source/blender/editors/space_outliner/outliner_ops.c7
-rw-r--r--source/blender/editors/space_outliner/outliner_select.c21
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.c506
-rw-r--r--source/blender/editors/space_outliner/outliner_tree.c268
-rw-r--r--source/blender/editors/space_outliner/space_outliner.c57
10 files changed, 1237 insertions, 390 deletions
diff --git a/source/blender/editors/space_outliner/CMakeLists.txt b/source/blender/editors/space_outliner/CMakeLists.txt
index 4db47b75502..289d6e715e1 100644
--- a/source/blender/editors/space_outliner/CMakeLists.txt
+++ b/source/blender/editors/space_outliner/CMakeLists.txt
@@ -22,12 +22,14 @@ set(INC
../include
../../blenkernel
../../blenlib
- ../../blenfont
+ ../../blentranslation
../../imbuf
+ ../../gpu
../../makesdna
../../makesrna
../../windowmanager
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -50,4 +52,6 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
+add_definitions(${GL_DEFINITIONS})
+
blender_add_lib(bf_editor_space_outliner "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/space_outliner/SConscript b/source/blender/editors/space_outliner/SConscript
index db8041f0235..dce559a21df 100644
--- a/source/blender/editors/space_outliner/SConscript
+++ b/source/blender/editors/space_outliner/SConscript
@@ -28,15 +28,19 @@
Import ('env')
sources = env.Glob('*.c')
+
defs = []
+defs == env['BF_GL_DEFINITIONS']
incs = [
'#/intern/guardedalloc',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'../include',
- '../../blenfont',
'../../blenkernel',
'../../blenlib',
+ '../../blentranslation',
+ '../../gpu',
'../../imbuf',
'../../makesdna',
'../../makesrna',
diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c
index 7eb90953df4..ac9e2e36ded 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.c
@@ -29,7 +29,9 @@
* \ingroup spoutliner
*/
+#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
+#include "DNA_gpencil_types.h"
#include "DNA_group_types.h"
#include "DNA_lamp_types.h"
#include "DNA_object_types.h"
@@ -41,11 +43,12 @@
#include "BLI_utildefines.h"
#include "BLI_mempool.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "BKE_context.h"
#include "BKE_deform.h"
#include "BKE_depsgraph.h"
+#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_main.h"
@@ -55,6 +58,7 @@
#include "BKE_object.h"
#include "ED_armature.h"
+#include "ED_keyframing.h"
#include "ED_object.h"
#include "ED_screen.h"
@@ -168,20 +172,51 @@ static void restrictbutton_recursive_bone(bContext *C, bArmature *arm, Bone *bon
}
static void restrictbutton_recursive_child(bContext *C, Scene *scene, Object *ob_parent, char flag,
- bool state, bool deselect)
+ bool state, bool deselect, const char *rnapropname)
{
Main *bmain = CTX_data_main(C);
Object *ob;
+
for (ob = bmain->object.first; ob; ob = ob->id.next) {
if (BKE_object_is_child_recursive(ob_parent, ob)) {
- if (state) {
- ob->restrictflag |= flag;
- if (deselect) {
- ED_base_object_select(BKE_scene_base_find(scene, ob), BA_DESELECT);
+ /* only do if child object is selectable */
+ if ((flag == OB_RESTRICT_SELECT) || (ob->restrictflag & OB_RESTRICT_SELECT) == 0) {
+ if (state) {
+ ob->restrictflag |= flag;
+ if (deselect) {
+ ED_base_object_select(BKE_scene_base_find(scene, ob), BA_DESELECT);
+ }
+ }
+ else {
+ ob->restrictflag &= ~flag;
}
}
- else {
- ob->restrictflag &= ~flag;
+
+ if (rnapropname) {
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ ID *id;
+ bAction *action;
+ FCurve *fcu;
+ bool driven, special;
+
+ RNA_id_pointer_create(&ob->id, &ptr);
+ prop = RNA_struct_find_property(&ptr, rnapropname);
+ fcu = rna_get_fcurve_context_ui(C, &ptr, prop, 0, NULL, &action, &driven, &special);
+
+ if (fcu && !driven) {
+ id = ptr.id.data;
+ if (autokeyframe_cfra_can_key(scene, id)) {
+ ReportList *reports = CTX_wm_reports(C);
+ short flag = ANIM_get_keyframing_flags(scene, 1);
+
+ fcu->flag &= ~FCURVE_SELECTED;
+ insert_keyframe(reports, id, action, ((fcu->grp) ? (fcu->grp->name) : (NULL)),
+ fcu->rna_path, fcu->array_index, CFRA, flag);
+ /* Assuming this is not necessary here, since 'ancestor' object button will do it anyway. */
+ /* WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); */
+ }
+ }
}
}
}
@@ -203,7 +238,7 @@ static void restrictbutton_view_cb(bContext *C, void *poin, void *poin2)
if (CTX_wm_window(C)->eventstate->ctrl) {
restrictbutton_recursive_child(C, scene, ob, OB_RESTRICT_VIEW,
- (ob->restrictflag & OB_RESTRICT_VIEW) != 0, true);
+ (ob->restrictflag & OB_RESTRICT_VIEW) != 0, true, "hide");
}
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
@@ -226,7 +261,7 @@ static void restrictbutton_sel_cb(bContext *C, void *poin, void *poin2)
if (CTX_wm_window(C)->eventstate->ctrl) {
restrictbutton_recursive_child(C, scene, ob, OB_RESTRICT_SELECT,
- (ob->restrictflag & OB_RESTRICT_SELECT) != 0, true);
+ (ob->restrictflag & OB_RESTRICT_SELECT) != 0, true, NULL);
}
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
@@ -239,7 +274,7 @@ static void restrictbutton_rend_cb(bContext *C, void *poin, void *poin2)
if (CTX_wm_window(C)->eventstate->ctrl) {
restrictbutton_recursive_child(C, (Scene *)poin, ob, OB_RESTRICT_RENDER,
- (ob->restrictflag & OB_RESTRICT_RENDER) != 0, false);
+ (ob->restrictflag & OB_RESTRICT_RENDER) != 0, false, "hide_render");
}
WM_event_add_notifier(C, NC_SCENE | ND_OB_RENDER, poin);
@@ -255,8 +290,7 @@ static void restrictbutton_modifier_cb(bContext *C, void *UNUSED(poin), void *po
Object *ob = (Object *)poin2;
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
-
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
}
static void restrictbutton_bone_visibility_cb(bContext *C, void *poin, void *poin2)
@@ -316,6 +350,11 @@ static void restrictbutton_ebone_visibility_cb(bContext *C, void *UNUSED(poin),
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
}
+static void restrictbutton_gp_layer_flag_cb(bContext *C, void *UNUSED(poin), void *UNUSED(poin2))
+{
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+}
+
static int group_restrict_flag(Group *gr, int flag)
{
GroupObject *gob;
@@ -407,6 +446,20 @@ static void restrictbutton_gr_restrict_render(bContext *C, void *poin, void *poi
WM_event_add_notifier(C, NC_GROUP, NULL);
}
+static void restrictbutton_id_user_toggle(bContext *UNUSED(C), void *poin, void *UNUSED(poin2))
+{
+ ID *id = (ID *)poin;
+
+ BLI_assert(id != NULL);
+
+ if (id->flag & LIB_FAKEUSER) {
+ id_us_plus(id);
+ }
+ else {
+ id_us_min(id);
+ }
+}
+
static void namebutton_cb(bContext *C, void *tsep, char *oldname)
{
@@ -417,7 +470,7 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname)
TreeStoreElem *tselem = tsep;
if (ts && tselem) {
- TreeElement *te = outliner_find_tse(soops, tselem);
+ TreeElement *te = outliner_find_tree_element(&soops->tree, tselem);
if (tselem->type == 0) {
test_idbutton(tselem->id->name); // library.c, unique name and alpha sort
@@ -514,11 +567,22 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname)
Object *ob = (Object *)tselem->id; // id = object
bActionGroup *grp = te->directdata;
- BLI_uniquename(&ob->pose->agroups, grp, CTX_DATA_(BLF_I18NCONTEXT_ID_ACTION, "Group"), '.',
+ BLI_uniquename(&ob->pose->agroups, grp, CTX_DATA_(BLT_I18NCONTEXT_ID_ACTION, "Group"), '.',
offsetof(bActionGroup, name), sizeof(grp->name));
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
break;
}
+ case TSE_GP_LAYER:
+ {
+ bGPdata *gpd = (bGPdata *)tselem->id; // id = GP Datablock
+ bGPDlayer *gpl = te->directdata;
+
+ // XXX: name needs translation stuff
+ BLI_uniquename(&gpd->layers, gpl, "GP Layer", '.',
+ offsetof(bGPDlayer, info), sizeof(gpl->info));
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, gpd);
+ break;
+ }
case TSE_R_LAYER:
break;
}
@@ -554,29 +618,29 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar
ob = (Object *)tselem->id;
RNA_pointer_create((ID *)ob, &RNA_Object, ob, &ptr);
- uiBlockSetEmboss(block, UI_EMBOSSN);
- bt = uiDefIconButR_prop(block, ICONTOG, 0, ICON_RESTRICT_VIEW_OFF,
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
+ bt = uiDefIconButR_prop(block, UI_BTYPE_ICON_TOGGLE, 0, ICON_RESTRICT_VIEW_OFF,
(int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X, UI_UNIT_Y,
&ptr, object_prop_hide, -1, 0, 0, -1, -1,
TIP_("Restrict viewport visibility (Ctrl - Recursive)"));
- uiButSetFunc(bt, restrictbutton_view_cb, scene, ob);
- uiButSetFlag(bt, UI_BUT_DRAG_LOCK);
+ UI_but_func_set(bt, restrictbutton_view_cb, scene, ob);
+ UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
- bt = uiDefIconButR_prop(block, ICONTOG, 0, ICON_RESTRICT_SELECT_OFF,
+ bt = uiDefIconButR_prop(block, UI_BTYPE_ICON_TOGGLE, 0, ICON_RESTRICT_SELECT_OFF,
(int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys, UI_UNIT_X, UI_UNIT_Y,
&ptr, object_prop_hide_select, -1, 0, 0, -1, -1,
TIP_("Restrict viewport selection (Ctrl - Recursive)"));
- uiButSetFunc(bt, restrictbutton_sel_cb, scene, ob);
- uiButSetFlag(bt, UI_BUT_DRAG_LOCK);
+ UI_but_func_set(bt, restrictbutton_sel_cb, scene, ob);
+ UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
- bt = uiDefIconButR_prop(block, ICONTOG, 0, ICON_RESTRICT_RENDER_OFF,
+ bt = uiDefIconButR_prop(block, UI_BTYPE_ICON_TOGGLE, 0, ICON_RESTRICT_RENDER_OFF,
(int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), te->ys, UI_UNIT_X, UI_UNIT_Y,
&ptr, object_prop_hide_render, -1, 0, 0, -1, -1,
TIP_("Restrict rendering (Ctrl - Recursive)"));
- uiButSetFunc(bt, restrictbutton_rend_cb, scene, ob);
- uiButSetFlag(bt, UI_BUT_DRAG_LOCK);
+ UI_but_func_set(bt, restrictbutton_rend_cb, scene, ob);
+ UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
- uiBlockSetEmboss(block, UI_EMBOSS);
+ UI_block_emboss_set(block, UI_EMBOSS);
}
if (tselem->type == 0 && te->idcode == ID_GR) {
@@ -587,130 +651,153 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar
if (gr->id.lib)
but_flag |= UI_BUT_DISABLED;
- uiBlockSetEmboss(block, UI_EMBOSSN);
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
restrict_bool = group_restrict_flag(gr, OB_RESTRICT_VIEW);
- bt = uiDefIconBut(block, ICONTOG, 0, restrict_bool ? ICON_RESTRICT_VIEW_ON : ICON_RESTRICT_VIEW_OFF,
+ bt = uiDefIconBut(block, UI_BTYPE_ICON_TOGGLE, 0, restrict_bool ? ICON_RESTRICT_VIEW_ON : ICON_RESTRICT_VIEW_OFF,
(int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X, UI_UNIT_Y,
NULL, 0, 0, 0, 0, TIP_("Restrict/Allow visibility in the 3D View"));
- uiButSetFunc(bt, restrictbutton_gr_restrict_view, scene, gr);
- uiButSetFlag(bt, but_flag);
+ UI_but_func_set(bt, restrictbutton_gr_restrict_view, scene, gr);
+ UI_but_flag_enable(bt, but_flag);
restrict_bool = group_restrict_flag(gr, OB_RESTRICT_SELECT);
- bt = uiDefIconBut(block, ICONTOG, 0, restrict_bool ? ICON_RESTRICT_SELECT_ON : ICON_RESTRICT_SELECT_OFF,
+ bt = uiDefIconBut(block, UI_BTYPE_ICON_TOGGLE, 0, restrict_bool ? ICON_RESTRICT_SELECT_ON : ICON_RESTRICT_SELECT_OFF,
(int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys, UI_UNIT_X, UI_UNIT_Y,
NULL, 0, 0, 0, 0, TIP_("Restrict/Allow selection in the 3D View"));
- uiButSetFunc(bt, restrictbutton_gr_restrict_select, scene, gr);
- uiButSetFlag(bt, but_flag);
+ UI_but_func_set(bt, restrictbutton_gr_restrict_select, scene, gr);
+ UI_but_flag_enable(bt, but_flag);
restrict_bool = group_restrict_flag(gr, OB_RESTRICT_RENDER);
- bt = uiDefIconBut(block, ICONTOG, 0, restrict_bool ? ICON_RESTRICT_RENDER_ON : ICON_RESTRICT_RENDER_OFF,
+ bt = uiDefIconBut(block, UI_BTYPE_ICON_TOGGLE, 0, restrict_bool ? ICON_RESTRICT_RENDER_ON : ICON_RESTRICT_RENDER_OFF,
(int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), te->ys, UI_UNIT_X, UI_UNIT_Y,
NULL, 0, 0, 0, 0, TIP_("Restrict/Allow renderability"));
- uiButSetFunc(bt, restrictbutton_gr_restrict_render, scene, gr);
- uiButSetFlag(bt, but_flag);
+ UI_but_func_set(bt, restrictbutton_gr_restrict_render, scene, gr);
+ UI_but_flag_enable(bt, but_flag);
- uiBlockSetEmboss(block, UI_EMBOSS);
+ UI_block_emboss_set(block, UI_EMBOSS);
}
/* scene render layers and passes have toggle-able flags too! */
else if (tselem->type == TSE_R_LAYER) {
- uiBlockSetEmboss(block, UI_EMBOSSN);
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
- bt = uiDefIconButBitI(block, ICONTOGN, SCE_LAY_DISABLE, 0, ICON_CHECKBOX_HLT - 1,
+ bt = uiDefIconButBitI(block, UI_BTYPE_ICON_TOGGLE_N, SCE_LAY_DISABLE, 0, ICON_CHECKBOX_HLT - 1,
(int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X,
UI_UNIT_Y, te->directdata, 0, 0, 0, 0, TIP_("Render this RenderLayer"));
- uiButSetFunc(bt, restrictbutton_r_lay_cb, tselem->id, NULL);
- uiButSetFlag(bt, UI_BUT_DRAG_LOCK);
+ UI_but_func_set(bt, restrictbutton_r_lay_cb, tselem->id, NULL);
+ UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
- uiBlockSetEmboss(block, UI_EMBOSS);
+ UI_block_emboss_set(block, UI_EMBOSS);
}
else if (tselem->type == TSE_R_PASS) {
int *layflag = te->directdata;
int passflag = 1 << tselem->nr;
- uiBlockSetEmboss(block, UI_EMBOSSN);
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
- bt = uiDefIconButBitI(block, ICONTOG, passflag, 0, ICON_CHECKBOX_HLT - 1,
+ bt = uiDefIconButBitI(block, UI_BTYPE_ICON_TOGGLE, passflag, 0, ICON_CHECKBOX_HLT - 1,
(int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X,
UI_UNIT_Y, layflag, 0, 0, 0, 0, TIP_("Render this Pass"));
- uiButSetFunc(bt, restrictbutton_r_lay_cb, tselem->id, NULL);
- uiButSetFlag(bt, UI_BUT_DRAG_LOCK);
+ UI_but_func_set(bt, restrictbutton_r_lay_cb, tselem->id, NULL);
+ UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
layflag++; /* is lay_xor */
if (ELEM(passflag, SCE_PASS_SPEC, SCE_PASS_SHADOW, SCE_PASS_AO, SCE_PASS_REFLECT, SCE_PASS_REFRACT,
SCE_PASS_INDIRECT, SCE_PASS_EMIT, SCE_PASS_ENVIRONMENT))
{
- bt = uiDefIconButBitI(block, TOG, passflag, 0, (*layflag & passflag) ? ICON_DOT : ICON_BLANK1,
+ bt = uiDefIconButBitI(block, UI_BTYPE_TOGGLE, passflag, 0, (*layflag & passflag) ? ICON_DOT : ICON_BLANK1,
(int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys, UI_UNIT_X,
UI_UNIT_Y, layflag, 0, 0, 0, 0, TIP_("Exclude this Pass from Combined"));
- uiButSetFunc(bt, restrictbutton_r_lay_cb, tselem->id, NULL);
- uiButSetFlag(bt, UI_BUT_DRAG_LOCK);
+ UI_but_func_set(bt, restrictbutton_r_lay_cb, tselem->id, NULL);
+ UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
}
- uiBlockSetEmboss(block, UI_EMBOSS);
+ UI_block_emboss_set(block, UI_EMBOSS);
}
else if (tselem->type == TSE_MODIFIER) {
ModifierData *md = (ModifierData *)te->directdata;
ob = (Object *)tselem->id;
- uiBlockSetEmboss(block, UI_EMBOSSN);
- bt = uiDefIconButBitI(block, ICONTOGN, eModifierMode_Realtime, 0, ICON_RESTRICT_VIEW_OFF,
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
+ bt = uiDefIconButBitI(block, UI_BTYPE_ICON_TOGGLE_N, eModifierMode_Realtime, 0, ICON_RESTRICT_VIEW_OFF,
(int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X,
UI_UNIT_Y, &(md->mode), 0, 0, 0, 0,
TIP_("Restrict/Allow visibility in the 3D View"));
- uiButSetFunc(bt, restrictbutton_modifier_cb, scene, ob);
- uiButSetFlag(bt, UI_BUT_DRAG_LOCK);
+ UI_but_func_set(bt, restrictbutton_modifier_cb, scene, ob);
+ UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
- bt = uiDefIconButBitI(block, ICONTOGN, eModifierMode_Render, 0, ICON_RESTRICT_RENDER_OFF,
+ bt = uiDefIconButBitI(block, UI_BTYPE_ICON_TOGGLE_N, eModifierMode_Render, 0, ICON_RESTRICT_RENDER_OFF,
(int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), te->ys, UI_UNIT_X,
UI_UNIT_Y, &(md->mode), 0, 0, 0, 0, TIP_("Restrict/Allow renderability"));
- uiButSetFunc(bt, restrictbutton_modifier_cb, scene, ob);
- uiButSetFlag(bt, UI_BUT_DRAG_LOCK);
+ UI_but_func_set(bt, restrictbutton_modifier_cb, scene, ob);
+ UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
- uiBlockSetEmboss(block, UI_EMBOSS);
+ UI_block_emboss_set(block, UI_EMBOSS);
}
else if (tselem->type == TSE_POSE_CHANNEL) {
bPoseChannel *pchan = (bPoseChannel *)te->directdata;
Bone *bone = pchan->bone;
ob = (Object *)tselem->id;
- uiBlockSetEmboss(block, UI_EMBOSSN);
- bt = uiDefIconButBitI(block, ICONTOG, BONE_HIDDEN_P, 0, ICON_RESTRICT_VIEW_OFF,
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
+ bt = uiDefIconButBitI(block, UI_BTYPE_ICON_TOGGLE, BONE_HIDDEN_P, 0, ICON_RESTRICT_VIEW_OFF,
(int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X,
UI_UNIT_Y, &(bone->flag), 0, 0, 0, 0,
TIP_("Restrict/Allow visibility in the 3D View"));
- uiButSetFunc(bt, restrictbutton_bone_visibility_cb, ob->data, bone);
- uiButSetFlag(bt, UI_BUT_DRAG_LOCK);
+ UI_but_func_set(bt, restrictbutton_bone_visibility_cb, ob->data, bone);
+ UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
- bt = uiDefIconButBitI(block, ICONTOG, BONE_UNSELECTABLE, 0, ICON_RESTRICT_SELECT_OFF,
+ bt = uiDefIconButBitI(block, UI_BTYPE_ICON_TOGGLE, BONE_UNSELECTABLE, 0, ICON_RESTRICT_SELECT_OFF,
(int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys, UI_UNIT_X,
UI_UNIT_Y, &(bone->flag), 0, 0, 0, 0,
TIP_("Restrict/Allow selection in the 3D View"));
- uiButSetFunc(bt, restrictbutton_bone_select_cb, ob->data, bone);
- uiButSetFlag(bt, UI_BUT_DRAG_LOCK);
+ UI_but_func_set(bt, restrictbutton_bone_select_cb, ob->data, bone);
+ UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
- uiBlockSetEmboss(block, UI_EMBOSS);
+ UI_block_emboss_set(block, UI_EMBOSS);
}
else if (tselem->type == TSE_EBONE) {
EditBone *ebone = (EditBone *)te->directdata;
- uiBlockSetEmboss(block, UI_EMBOSSN);
- bt = uiDefIconButBitI(block, ICONTOG, BONE_HIDDEN_A, 0, ICON_RESTRICT_VIEW_OFF,
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
+ bt = uiDefIconButBitI(block, UI_BTYPE_ICON_TOGGLE, BONE_HIDDEN_A, 0, ICON_RESTRICT_VIEW_OFF,
(int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X,
UI_UNIT_Y, &(ebone->flag), 0, 0, 0, 0,
TIP_("Restrict/Allow visibility in the 3D View"));
- uiButSetFunc(bt, restrictbutton_ebone_visibility_cb, NULL, ebone);
- uiButSetFlag(bt, UI_BUT_DRAG_LOCK);
+ UI_but_func_set(bt, restrictbutton_ebone_visibility_cb, NULL, ebone);
+ UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
- bt = uiDefIconButBitI(block, ICONTOG, BONE_UNSELECTABLE, 0, ICON_RESTRICT_SELECT_OFF,
+ bt = uiDefIconButBitI(block, UI_BTYPE_ICON_TOGGLE, BONE_UNSELECTABLE, 0, ICON_RESTRICT_SELECT_OFF,
(int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys, UI_UNIT_X,
UI_UNIT_Y, &(ebone->flag), 0, 0, 0, 0,
TIP_("Restrict/Allow selection in the 3D View"));
- uiButSetFunc(bt, restrictbutton_ebone_select_cb, NULL, ebone);
- uiButSetFlag(bt, UI_BUT_DRAG_LOCK);
+ UI_but_func_set(bt, restrictbutton_ebone_select_cb, NULL, ebone);
+ UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
- uiBlockSetEmboss(block, UI_EMBOSS);
+ UI_block_emboss_set(block, UI_EMBOSS);
+ }
+ else if (tselem->type == TSE_GP_LAYER) {
+ bGPDlayer *gpl = (bGPDlayer *)te->directdata;
+
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
+
+ bt = uiDefIconButBitS(block, UI_BTYPE_ICON_TOGGLE, GP_LAYER_HIDE, 0, ICON_RESTRICT_VIEW_OFF,
+ (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X,
+ UI_UNIT_Y, &gpl->flag, 0, 0, 0, 0,
+ TIP_("Restrict/Allow visibility in the 3D View"));
+ UI_but_func_set(bt, restrictbutton_gp_layer_flag_cb, NULL, gpl);
+ UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
+
+ bt = uiDefIconButBitS(block, UI_BTYPE_ICON_TOGGLE, GP_LAYER_LOCKED, 0, ICON_UNLOCKED,
+ (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys, UI_UNIT_X,
+ UI_UNIT_Y, &gpl->flag, 0, 0, 0, 0,
+ TIP_("Restrict/Allow editing of strokes and keyframes in this layer"));
+ UI_but_func_set(bt, restrictbutton_gp_layer_flag_cb, NULL, gpl);
+ UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
+
+ /* TODO: visibility in renders */
+
+ UI_block_emboss_set(block, UI_EMBOSS);
}
}
@@ -718,6 +805,66 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar
}
}
+static void outliner_draw_userbuts(uiBlock *block, ARegion *ar, SpaceOops *soops, ListBase *lb)
+{
+ uiBut *bt;
+ TreeElement *te;
+ TreeStoreElem *tselem;
+
+ for (te = lb->first; te; te = te->next) {
+ tselem = TREESTORE(te);
+ if (te->ys + 2 * UI_UNIT_Y >= ar->v2d.cur.ymin && te->ys <= ar->v2d.cur.ymax) {
+ if (tselem->type == 0) {
+ ID *id = tselem->id;
+ const char *tip = NULL;
+ int icon = ICON_NONE;
+ char buf[16] = "";
+ int but_flag = UI_BUT_DRAG_LOCK;
+
+ if (id->lib)
+ but_flag |= UI_BUT_DISABLED;
+
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
+
+ if (id->flag & LIB_FAKEUSER) {
+ icon = ICON_FILE_TICK;
+ tip = TIP_("Datablock will be retained using a fake user");
+ }
+ else {
+ icon = ICON_X;
+ tip = TIP_("Datablock has no users and will be deleted");
+ }
+ bt = uiDefIconButBitS(block, UI_BTYPE_TOGGLE, LIB_FAKEUSER, 1, icon,
+ (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X, UI_UNIT_Y,
+ &id->flag, 0, 0, 0, 0, tip);
+ UI_but_func_set(bt, restrictbutton_id_user_toggle, id, NULL);
+ UI_but_flag_enable(bt, but_flag);
+
+
+ BLI_str_format_int_grouped(buf, id->us);
+ bt = uiDefBut(block, UI_BTYPE_BUT, 1, buf,
+ (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys,
+ UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0,
+ TIP_("Number of users of this datablock"));
+ UI_but_flag_enable(bt, but_flag);
+
+
+ bt = uiDefButBitS(block, UI_BTYPE_TOGGLE, LIB_FAKEUSER, 1, (id->flag & LIB_FAKEUSER) ? "F" : " ",
+ (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), te->ys, UI_UNIT_X, UI_UNIT_Y,
+ &id->flag, 0, 0, 0, 0,
+ TIP_("Datablock has a 'fake' user which will keep it in the file "
+ "even if nothing else uses it"));
+ UI_but_func_set(bt, restrictbutton_id_user_toggle, id, NULL);
+ UI_but_flag_enable(bt, but_flag);
+
+ UI_block_emboss_set(block, UI_EMBOSS);
+ }
+ }
+
+ if (TSELEM_OPEN(tselem, soops)) outliner_draw_userbuts(block, ar, soops, &te->subtree);
+ }
+}
+
static void outliner_draw_rnacols(ARegion *ar, int sizex)
{
View2D *v2d = &ar->v2d;
@@ -745,8 +892,6 @@ static void outliner_draw_rnabuts(uiBlock *block, Scene *scene, ARegion *ar, Spa
TreeStoreElem *tselem;
PointerRNA *ptr;
PropertyRNA *prop;
-
- uiBlockSetEmboss(block, UI_EMBOSST);
for (te = lb->first; te; te = te->next) {
tselem = TREESTORE(te);
@@ -759,7 +904,7 @@ static void outliner_draw_rnabuts(uiBlock *block, Scene *scene, ARegion *ar, Spa
if (RNA_property_type(prop) == PROP_POINTER) {
uiBut *but = uiDefAutoButR(block, ptr, prop, -1, "", ICON_NONE, sizex, te->ys,
OL_RNA_COL_SIZEX, UI_UNIT_Y - 1);
- uiButSetFlag(but, UI_BUT_DISABLED);
+ UI_but_flag_enable(but, UI_BUT_DISABLED);
}
else if (RNA_property_type(prop) == PROP_ENUM) {
uiDefAutoButR(block, ptr, prop, -1, NULL, ICON_NONE, sizex, te->ys, OL_RNA_COL_SIZEX,
@@ -783,7 +928,7 @@ static void outliner_draw_rnabuts(uiBlock *block, Scene *scene, ARegion *ar, Spa
if (TSELEM_OPEN(tselem, soops)) outliner_draw_rnabuts(block, scene, ar, soops, sizex, &te->subtree);
}
- uiBlockSetEmboss(block, UI_EMBOSS);
+ UI_block_emboss_set(block, UI_EMBOSS);
}
static void outliner_buttons(const bContext *C, uiBlock *block, ARegion *ar, TreeElement *te)
@@ -807,12 +952,12 @@ static void outliner_buttons(const bContext *C, uiBlock *block, ARegion *ar, Tre
spx = te->xs + 1.8f * UI_UNIT_X;
dx = ar->v2d.cur.xmax - (spx + 3.2f * UI_UNIT_X);
- bt = uiDefBut(block, TEX, OL_NAMEBUTTON, "", spx, te->ys, dx, UI_UNIT_Y - 1, (void *)te->name,
+ bt = uiDefBut(block, UI_BTYPE_TEXT, OL_NAMEBUTTON, "", spx, te->ys, dx, UI_UNIT_Y - 1, (void *)te->name,
1.0, (float)len, 0, 0, "");
- uiButSetRenameFunc(bt, namebutton_cb, tselem);
+ UI_but_func_rename_set(bt, namebutton_cb, tselem);
/* returns false if button got removed */
- if (false == uiButActiveOnly(C, ar, block, bt)) {
+ if (false == UI_but_active_only(C, ar, block, bt)) {
tselem->flag &= ~TSE_TEXTBUT;
/* bad! (notifier within draw) without this, we don't get a refesh */
@@ -840,13 +985,46 @@ static void tselem_draw_icon_uibut(struct DrawIconArg *arg, int icon)
glDisable(GL_BLEND);
}
else {
- uiBut *but = uiDefIconBut(arg->block, LABEL, 0, icon, arg->xb, arg->yb, UI_UNIT_X, UI_UNIT_Y, NULL,
+ uiBut *but = uiDefIconBut(arg->block, UI_BTYPE_LABEL, 0, icon, arg->xb, arg->yb, UI_UNIT_X, UI_UNIT_Y, NULL,
0.0, 0.0, 1.0, arg->alpha, (arg->id && arg->id->lib) ? arg->id->lib->name : "");
if (arg->id)
- uiButSetDragID(but, arg->id);
+ UI_but_drag_set_id(but, arg->id);
+ }
+
+}
+
+static void tselem_draw_gp_icon_uibut(struct DrawIconArg *arg, ID *id, bGPDlayer *gpl)
+{
+ /* restrict column clip - skip it for now... */
+ if (arg->x >= arg->xmax) {
+ /* pass */
}
+ else {
+ PointerRNA ptr;
+ const float eps = 0.001f;
+ const bool is_stroke_visible = (gpl->color[3] > eps);
+ const bool is_fill_visible = (gpl->fill[3] > eps);
+ float w = 0.5f * UI_UNIT_X;
+ float h = 0.85f * UI_UNIT_Y;
+ RNA_pointer_create(id, &RNA_GPencilLayer, gpl, &ptr);
+
+ UI_block_align_begin(arg->block);
+
+ UI_block_emboss_set(arg->block, is_stroke_visible ? UI_EMBOSS : UI_EMBOSS_NONE);
+ uiDefButR(arg->block, UI_BTYPE_COLOR, 1, "", arg->xb, arg->yb, w, h,
+ &ptr, "color", -1,
+ 0, 0, 0, 0, NULL);
+
+ UI_block_emboss_set(arg->block, is_fill_visible ? UI_EMBOSS : UI_EMBOSS_NONE);
+ uiDefButR(arg->block, UI_BTYPE_COLOR, 1, "", arg->xb + w, arg->yb, w, h,
+ &ptr, "fill_color", -1,
+ 0, 0, 0, 0, NULL);
+
+ UI_block_emboss_set(arg->block, UI_EMBOSS_NONE);
+ UI_block_align_end(arg->block);
+ }
}
static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeStoreElem *tselem, TreeElement *te,
@@ -946,6 +1124,7 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto
UI_icon_draw(x, y, ICON_MOD_BEVEL); break;
case eModifierType_Smooth:
case eModifierType_LaplacianSmooth:
+ case eModifierType_CorrectiveSmooth:
UI_icon_draw(x, y, ICON_MOD_SMOOTH); break;
case eModifierType_SimpleDeform:
UI_icon_draw(x, y, ICON_MOD_SIMPLEDEFORM); break;
@@ -990,6 +1169,10 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto
UI_icon_draw(x, y, ICON_MOD_WIREFRAME); break;
case eModifierType_LaplacianDeform:
UI_icon_draw(x, y, ICON_MOD_MESHDEFORM); break; /* XXX, needs own icon */
+ case eModifierType_DataTransfer:
+ UI_icon_draw(x, y, ICON_MOD_DATA_TRANSFER); break;
+ case eModifierType_NormalEdit:
+ UI_icon_draw(x, y, ICON_MOD_NORMALEDIT); break;
/* Default */
case eModifierType_None:
case eModifierType_ShapeKey:
@@ -1042,6 +1225,9 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto
else
UI_icon_draw(x, y, RNA_struct_ui_icon(te->rnaptr.type));
break;
+ case TSE_GP_LAYER:
+ tselem_draw_gp_icon_uibut(&arg, tselem->id, te->directdata);
+ break;
default:
UI_icon_draw(x, y, ICON_DOT); break;
}
@@ -1135,6 +1321,8 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto
tselem_draw_icon_uibut(&arg, ICON_LIBRARY_DATA_DIRECT); break;
case ID_LS:
tselem_draw_icon_uibut(&arg, ICON_LINE_DATA); break;
+ case ID_GD:
+ tselem_draw_icon_uibut(&arg, ICON_GREASEPENCIL); break;
}
}
}
@@ -1176,13 +1364,14 @@ static void outliner_draw_iconrow(bContext *C, uiBlock *block, Scene *scene, Spa
if (active != OL_DRAWSEL_NONE) {
float ufac = UI_UNIT_X / 20.0f;
- uiSetRoundBox(UI_CNR_ALL);
+ UI_draw_roundbox_corner_set(UI_CNR_ALL);
glColor4ub(255, 255, 255, 100);
- uiRoundBox((float) *offsx - 1.0f * ufac,
- (float)ys + 1.0f * ufac,
- (float)*offsx + UI_UNIT_X - 2.0f * ufac,
- (float)ys + UI_UNIT_Y - ufac,
- (float)UI_UNIT_Y / 2.0f - ufac);
+ UI_draw_roundbox(
+ (float) *offsx - 1.0f * ufac,
+ (float)ys + 1.0f * ufac,
+ (float)*offsx + UI_UNIT_X - 2.0f * ufac,
+ (float)ys + UI_UNIT_Y - ufac,
+ (float)UI_UNIT_Y / 2.0f - ufac);
glEnable(GL_BLEND); /* roundbox disables */
}
@@ -1217,8 +1406,9 @@ static void outliner_set_coord_tree_element(SpaceOops *soops, TreeElement *te, i
}
-static void outliner_draw_tree_element(bContext *C, uiBlock *block, Scene *scene, ARegion *ar, SpaceOops *soops,
- TreeElement *te, int startx, int *starty, TreeElement **te_edit)
+static void outliner_draw_tree_element(
+ bContext *C, uiBlock *block, const uiFontStyle *fstyle, Scene *scene, ARegion *ar, SpaceOops *soops,
+ TreeElement *te, int startx, int *starty, TreeElement **te_edit)
{
TreeElement *ten;
TreeStoreElem *tselem;
@@ -1322,12 +1512,13 @@ static void outliner_draw_tree_element(bContext *C, uiBlock *block, Scene *scene
/* active circle */
if (active != OL_DRAWSEL_NONE) {
- uiSetRoundBox(UI_CNR_ALL);
- uiRoundBox((float)startx + UI_UNIT_X,
- (float)*starty + 1.0f * ufac,
- (float)startx + 2.0f * UI_UNIT_X - 2.0f * ufac,
- (float)*starty + UI_UNIT_Y - 1.0f * ufac,
- UI_UNIT_Y / 2.0f - 1.0f * ufac);
+ UI_draw_roundbox_corner_set(UI_CNR_ALL);
+ UI_draw_roundbox(
+ (float)startx + UI_UNIT_X,
+ (float)*starty + 1.0f * ufac,
+ (float)startx + 2.0f * UI_UNIT_X - 2.0f * ufac,
+ (float)*starty + UI_UNIT_Y - 1.0f * ufac,
+ UI_UNIT_Y / 2.0f - 1.0f * ufac);
glEnable(GL_BLEND); /* roundbox disables it */
te->flag |= TE_ACTIVE; // for lookup in display hierarchies
@@ -1376,9 +1567,9 @@ static void outliner_draw_tree_element(bContext *C, uiBlock *block, Scene *scene
else if (ELEM(tselem->type, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) UI_ThemeColorBlend(TH_BACK, TH_TEXT, 0.75f);
else UI_ThemeColor(TH_TEXT);
- UI_DrawString(startx + offsx, *starty + 5 * ufac, te->name);
+ UI_fontstyle_draw_simple(fstyle, startx + offsx, *starty + 5 * ufac, te->name);
- offsx += (int)(UI_UNIT_X + UI_GetStringWidth(te->name));
+ offsx += (int)(UI_UNIT_X + UI_fontstyle_string_width(fstyle, te->name));
/* closed item, we draw the icons, not when it's a scene, or master-server list though */
if (!TSELEM_OPEN(tselem, soops)) {
@@ -1416,13 +1607,15 @@ static void outliner_draw_tree_element(bContext *C, uiBlock *block, Scene *scene
if (TSELEM_OPEN(tselem, soops)) {
*starty -= UI_UNIT_Y;
-
- for (ten = te->subtree.first; ten; ten = ten->next)
- outliner_draw_tree_element(C, block, scene, ar, soops, ten, startx + UI_UNIT_X, starty, te_edit);
+
+ for (ten = te->subtree.first; ten; ten = ten->next) {
+ outliner_draw_tree_element(C, block, fstyle, scene, ar, soops, ten, startx + UI_UNIT_X, starty, te_edit);
+ }
}
else {
- for (ten = te->subtree.first; ten; ten = ten->next)
+ for (ten = te->subtree.first; ten; ten = ten->next) {
outliner_set_coord_tree_element(soops, ten, startx, *starty);
+ }
*starty -= UI_UNIT_Y;
}
@@ -1505,6 +1698,7 @@ static void outliner_draw_selection(ARegion *ar, SpaceOops *soops, ListBase *lb,
static void outliner_draw_tree(bContext *C, uiBlock *block, Scene *scene, ARegion *ar,
SpaceOops *soops, TreeElement **te_edit)
{
+ const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
TreeElement *te;
int starty, startx;
float col[3];
@@ -1535,7 +1729,7 @@ static void outliner_draw_tree(bContext *C, uiBlock *block, Scene *scene, ARegio
starty = (int)ar->v2d.tot.ymax - UI_UNIT_Y - OL_Y_OFFSET;
startx = 0;
for (te = soops->tree.first; te; te = te->next) {
- outliner_draw_tree_element(C, block, scene, ar, soops, te, startx, &starty, te_edit);
+ outliner_draw_tree_element(C, block, fstyle, scene, ar, soops, te, startx, &starty, te_edit);
}
}
@@ -1654,7 +1848,7 @@ void draw_outliner(const bContext *C)
/* draw outliner stuff (background, hierarchy lines and names) */
outliner_back(ar);
- block = uiBeginBlock(C, ar, __func__, UI_EMBOSS);
+ block = UI_block_begin(C, ar, __func__, UI_EMBOSS);
outliner_draw_tree((bContext *)C, block, scene, ar, soops, &te_edit);
if (ELEM(soops->outlinevis, SO_DATABLOCKS, SO_USERDEF)) {
@@ -1662,6 +1856,11 @@ void draw_outliner(const bContext *C)
outliner_draw_rnacols(ar, sizex_rna);
outliner_draw_rnabuts(block, scene, ar, soops, sizex_rna, &soops->tree);
}
+ else if ((soops->outlinevis == SO_ID_ORPHANS) && !(soops->flag & SO_HIDE_RESTRICTCOLS)) {
+ /* draw user toggle columns */
+ outliner_draw_restrictcols(ar);
+ outliner_draw_userbuts(block, ar, soops, &soops->tree);
+ }
else if (!(soops->flag & SO_HIDE_RESTRICTCOLS)) {
/* draw restriction columns */
outliner_draw_restrictcols(ar);
@@ -1673,8 +1872,8 @@ void draw_outliner(const bContext *C)
outliner_buttons(C, block, ar, te_edit);
}
- uiEndBlock(C, block);
- uiDrawBlock(C, block);
+ UI_block_end(C, block);
+ UI_block_draw(C, block);
/* clear flag that allows quick redraws */
soops->storeflag &= ~SO_TREESTORE_REDRAW;
diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c
index ef621407abd..6d420674f3e 100644
--- a/source/blender/editors/space_outliner/outliner_edit.c
+++ b/source/blender/editors/space_outliner/outliner_edit.c
@@ -39,19 +39,24 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "BLI_mempool.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "BKE_animsys.h"
#include "BKE_context.h"
#include "BKE_depsgraph.h"
+#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_main.h"
+#include "BKE_outliner_treehash.h"
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_material.h"
+#include "BKE_group.h"
#include "ED_object.h"
+#include "ED_outliner.h"
#include "ED_screen.h"
#include "ED_keyframing.h"
@@ -73,22 +78,6 @@
/* This is not used anywhere at the moment */
#if 0
-/* return 1 when levels were opened */
-static int outliner_open_back(SpaceOops *soops, TreeElement *te)
-{
- TreeStoreElem *tselem;
- int retval = 0;
-
- for (te = te->parent; te; te = te->parent) {
- tselem = TREESTORE(te);
- if (tselem->flag & TSE_CLOSED) {
- tselem->flag &= ~TSE_CLOSED;
- retval = 1;
- }
- }
- return retval;
-}
-
static void outliner_open_reveal(SpaceOops *soops, ListBase *lb, TreeElement *teFind, int *found)
{
TreeElement *te;
@@ -113,7 +102,9 @@ static void outliner_open_reveal(SpaceOops *soops, ListBase *lb, TreeElement *te
}
#endif
-static TreeElement *outliner_dropzone_element(const SpaceOops *soops, TreeElement *te, const float fmval[2], const int children)
+static TreeElement *outliner_dropzone_element(
+ const SpaceOops *soops, TreeElement *te,
+ const float fmval[2], const bool children)
{
if ((fmval[1] > te->ys) && (fmval[1] < (te->ys + UI_UNIT_Y))) {
/* name and first icon */
@@ -132,7 +123,7 @@ static TreeElement *outliner_dropzone_element(const SpaceOops *soops, TreeElemen
}
/* Used for drag and drop parenting */
-TreeElement *outliner_dropzone_find(const SpaceOops *soops, const float fmval[2], const int children)
+TreeElement *outliner_dropzone_find(const SpaceOops *soops, const float fmval[2], const bool children)
{
TreeElement *te;
@@ -229,7 +220,7 @@ static void do_item_rename(ARegion *ar, TreeElement *te, TreeStoreElem *tselem,
else if (tselem->id->lib) {
BKE_report(reports, RPT_WARNING, "Cannot edit external libdata");
}
- else if (te->idcode == ID_LI && te->parent) {
+ else if (te->idcode == ID_LI && ((Library *)tselem->id)->parent) {
BKE_report(reports, RPT_WARNING, "Cannot edit the path of an indirectly linked library");
}
else {
@@ -601,6 +592,50 @@ void OUTLINER_OT_selected_toggle(wmOperatorType *ot)
/* Show Active --------------------------------------------------- */
+static void outliner_set_coordinates_element_recursive(SpaceOops *soops, TreeElement *te, int startx, int *starty)
+{
+ TreeStoreElem *tselem = TREESTORE(te);
+
+ /* store coord and continue, we need coordinates for elements outside view too */
+ te->xs = (float)startx;
+ te->ys = (float)(*starty);
+ *starty -= UI_UNIT_Y;
+
+ if (TSELEM_OPEN(tselem, soops)) {
+ TreeElement *ten;
+ for (ten = te->subtree.first; ten; ten = ten->next) {
+ outliner_set_coordinates_element_recursive(soops, ten, startx + UI_UNIT_X, starty);
+ }
+ }
+}
+
+/* to retrieve coordinates with redrawing the entire tree */
+static void outliner_set_coordinates(ARegion *ar, SpaceOops *soops)
+{
+ TreeElement *te;
+ int starty = (int)(ar->v2d.tot.ymax) - UI_UNIT_Y;
+
+ for (te = soops->tree.first; te; te = te->next) {
+ outliner_set_coordinates_element_recursive(soops, te, 0, &starty);
+ }
+}
+
+/* return 1 when levels were opened */
+static int outliner_open_back(TreeElement *te)
+{
+ TreeStoreElem *tselem;
+ int retval = 0;
+
+ for (te = te->parent; te; te = te->parent) {
+ tselem = TREESTORE(te);
+ if (tselem->flag & TSE_CLOSED) {
+ tselem->flag &= ~TSE_CLOSED;
+ retval = 1;
+ }
+ }
+ return retval;
+}
+
static int outliner_show_active_exec(bContext *C, wmOperator *UNUSED(op))
{
SpaceOops *so = CTX_wm_space_outliner(C);
@@ -617,6 +652,11 @@ static int outliner_show_active_exec(bContext *C, wmOperator *UNUSED(op))
te = outliner_find_id(so, &so->tree, (ID *)OBACT);
if (te) {
+ /* open up tree to active object */
+ if (outliner_open_back(te)) {
+ outliner_set_coordinates(ar, so);
+ }
+
/* make te->ys center of view */
ytop = te->ys + BLI_rcti_size_y(&v2d->mask) / 2;
if (ytop > 0) ytop = 0;
@@ -642,7 +682,7 @@ void OUTLINER_OT_show_active(wmOperatorType *ot)
/* identifiers */
ot->name = "Show Active";
ot->idname = "OUTLINER_OT_show_active";
- ot->description = "Adjust the view so that the active Object is shown centered";
+ ot->description = "Open up the tree and adjust the view so that the active Object is shown centered";
/* callbacks */
ot->exec = outliner_show_active_exec;
@@ -690,37 +730,6 @@ void OUTLINER_OT_scroll_page(wmOperatorType *ot)
#if 0
-/* recursive helper for function below */
-static void outliner_set_coordinates_element(SpaceOops *soops, TreeElement *te, int startx, int *starty)
-{
- TreeStoreElem *tselem = TREESTORE(te);
-
- /* store coord and continue, we need coordinates for elements outside view too */
- te->xs = (float)startx;
- te->ys = (float)(*starty);
- *starty -= UI_UNIT_Y;
-
- if (TSELEM_OPEN(tselem, soops)) {
- TreeElement *ten;
- for (ten = te->subtree.first; ten; ten = ten->next) {
- outliner_set_coordinates_element(soops, ten, startx + UI_UNIT_X, starty);
- }
- }
-
-}
-
-/* to retrieve coordinates with redrawing the entire tree */
-static void outliner_set_coordinates(ARegion *ar, SpaceOops *soops)
-{
- TreeElement *te;
- int starty = (int)(ar->v2d.tot.ymax) - UI_UNIT_Y;
- int startx = 0;
-
- for (te = soops->tree.first; te; te = te->next) {
- outliner_set_coordinates_element(soops, te, startx, &starty);
- }
-}
-
/* find next element that has this name */
static TreeElement *outliner_find_name(SpaceOops *soops, ListBase *lb, char *name, int flags,
TreeElement *prev, int *prevFound)
@@ -780,7 +789,7 @@ static void outliner_find_panel(Scene *UNUSED(scene), ARegion *ar, SpaceOops *so
else {
/* pop up panel - no previous, or user didn't want search after previous */
name[0] = '\0';
-// XXX if (sbutton(name, 0, sizeof(name)-1, "Find: ") && name[0]) {
+// XXX if (sbutton(name, 0, sizeof(name) - 1, "Find: ") && name[0]) {
// te = outliner_find_name(soops, &soops->tree, name, flags, NULL, &prevFound);
// }
// else return; /* XXX RETURN! XXX */
@@ -1305,7 +1314,7 @@ static KeyingSet *verify_active_keyingset(Scene *scene, short add)
// XXX the default settings have yet to evolve
if ((add) && (ks == NULL)) {
ks = BKE_keyingset_add(&scene->keyingsets, NULL, NULL, KEYINGSET_ABSOLUTE, 0);
- scene->active_keyingset = BLI_countlist(&scene->keyingsets);
+ scene->active_keyingset = BLI_listbase_count(&scene->keyingsets);
}
return ks;
@@ -1347,7 +1356,7 @@ static void do_outliner_keyingset_editop(SpaceOops *soops, KeyingSet *ks, ListBa
/* TODO: what do we do with group name?
* for now, we don't supply one, and just let this use the KeyingSet name */
BKE_keyingset_add_path(ks, id, NULL, path, array_index, flag, groupmode);
- ks->active_path = BLI_countlist(&ks->paths);
+ ks->active_path = BLI_listbase_count(&ks->paths);
break;
}
case KEYINGSET_EDITMODE_REMOVE:
@@ -1453,6 +1462,62 @@ void OUTLINER_OT_keyingset_remove_selected(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+
+/* ************************************************************** */
+/* ORPHANED DATABLOCKS */
+
+static int ed_operator_outliner_id_orphans_active(bContext *C)
+{
+ ScrArea *sa = CTX_wm_area(C);
+ if ((sa) && (sa->spacetype == SPACE_OUTLINER)) {
+ SpaceOops *so = CTX_wm_space_outliner(C);
+ return (so->outlinevis == SO_ID_ORPHANS);
+ }
+ return 0;
+}
+
+/* Purge Orphans Operator --------------------------------------- */
+
+static int outliner_orphans_purge_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(evt))
+{
+ /* present a prompt to informing users that this change is irreversible */
+ return WM_operator_confirm_message(C, op,
+ "Purging unused datablocks cannot be undone. "
+ "Click here to proceed...");
+}
+
+static int outliner_orphans_purge_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ /* Firstly, ensure that the file has been saved,
+ * so that the latest changes since the last save
+ * are retained...
+ */
+ WM_operator_name_call(C, "WM_OT_save_mainfile", WM_OP_EXEC_DEFAULT, NULL);
+
+ /* Now, reload the file to get rid of the orphans... */
+ WM_operator_name_call(C, "WM_OT_revert_mainfile", WM_OP_EXEC_DEFAULT, NULL);
+ return OPERATOR_FINISHED;
+}
+
+void OUTLINER_OT_orphans_purge(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->idname = "OUTLINER_OT_orphans_purge";
+ ot->name = "Purge All";
+ ot->description = "Clear all orphaned datablocks without any users from the file (cannot be undone)";
+
+ /* callbacks */
+ ot->invoke = outliner_orphans_purge_invoke;
+ ot->exec = outliner_orphans_purge_exec;
+ ot->poll = ed_operator_outliner_id_orphans_active;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ************************************************************** */
+/* DRAG AND DROP OPERATORS */
+
/* ******************** Parent Drop Operator *********************** */
static int parent_drop_exec(bContext *C, wmOperator *op)
@@ -1500,7 +1565,7 @@ static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
/* Find object hovered over */
- te = outliner_dropzone_find(soops, fmval, 1);
+ te = outliner_dropzone_find(soops, fmval, true);
if (te) {
RNA_string_set(op->ptr, "parent", te->name);
@@ -1543,8 +1608,8 @@ static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
else {
/* Menu creation */
wmOperatorType *ot = WM_operatortype_find("OUTLINER_OT_parent_drop", false);
- uiPopupMenu *pup = uiPupMenuBegin(C, IFACE_("Set Parent To"), ICON_NONE);
- uiLayout *layout = uiPupMenuLayout(pup);
+ uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("Set Parent To"), ICON_NONE);
+ uiLayout *layout = UI_popup_menu_layout(pup);
PointerRNA ptr;
@@ -1615,9 +1680,9 @@ static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
uiItemFullO_ptr(layout, ot, IFACE_("Lattice Deform"), 0, ptr.data, WM_OP_EXEC_DEFAULT, 0);
}
- uiPupMenuEnd(C, pup);
+ UI_popup_menu_end(C, pup);
- return OPERATOR_CANCELLED;
+ return OPERATOR_INTERFACE;
}
}
else {
@@ -1715,7 +1780,7 @@ static int scene_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
/* Find object hovered over */
- te = outliner_dropzone_find(soops, fmval, 0);
+ te = outliner_dropzone_find(soops, fmval, false);
if (te) {
Base *base;
@@ -1785,7 +1850,7 @@ static int material_drop_invoke(bContext *C, wmOperator *op, const wmEvent *even
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
/* Find object hovered over */
- te = outliner_dropzone_find(soops, fmval, 1);
+ te = outliner_dropzone_find(soops, fmval, true);
if (te) {
RNA_string_set(op->ptr, "object", te->name);
@@ -1829,3 +1894,98 @@ void OUTLINER_OT_material_drop(wmOperatorType *ot)
RNA_def_string(ot->srna, "material", "Material", MAX_ID_NAME, "Material", "Target Material");
}
+static int group_link_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Main *bmain = CTX_data_main(C);
+ Group *group = NULL;
+ Object *ob = NULL;
+ Scene *scene = CTX_data_scene(C);
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+ ARegion *ar = CTX_wm_region(C);
+ TreeElement *te = NULL;
+ char ob_name[MAX_ID_NAME - 2];
+ float fmval[2];
+
+ UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
+
+ /* Find object hovered over */
+ te = outliner_dropzone_find(soops, fmval, true);
+
+ if (te) {
+ group = (Group *)BKE_libblock_find_name(ID_GR, te->name);
+
+ RNA_string_get(op->ptr, "object", ob_name);
+ ob = (Object *)BKE_libblock_find_name(ID_OB, ob_name);
+
+ if (ELEM(NULL, group, ob)) {
+ return OPERATOR_CANCELLED;
+ }
+ if (BKE_group_object_exists(group, ob)) {
+ return OPERATOR_FINISHED;
+ }
+
+ if (BKE_group_object_cyclic_check(bmain, ob, group)) {
+ BKE_report(op->reports, RPT_ERROR, "Could not add the group because of dependency cycle detected");
+ return OPERATOR_CANCELLED;
+ }
+
+ BKE_group_object_add(group, ob, scene, NULL);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+
+ return OPERATOR_FINISHED;
+ }
+
+ return OPERATOR_CANCELLED;
+}
+
+void OUTLINER_OT_group_link(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Link Object to Group";
+ ot->description = "Link Object to Group in Outliner";
+ ot->idname = "OUTLINER_OT_group_link";
+
+ /* api callbacks */
+ ot->invoke = group_link_invoke;
+
+ ot->poll = ED_operator_outliner_active;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
+
+ /* properties */
+ RNA_def_string(ot->srna, "object", "Object", MAX_ID_NAME, "Object", "Target Object");
+}
+
+/******** Utils to clear any ref to freed ID... **********/
+
+void ED_outliner_id_unref(SpaceOops *so, const ID *id)
+{
+ /* Some early out checks. */
+ if (!TREESTORE_ID_TYPE(id)) {
+ return; /* ID type is not used by outilner... */
+ }
+
+ if (so->search_tse.id == id) {
+ so->search_tse.id = NULL;
+ }
+
+ if (so->treestore) {
+ TreeStoreElem *tselem;
+ BLI_mempool_iter iter;
+ bool changed = false;
+
+ BLI_mempool_iternew(so->treestore, &iter);
+ while ((tselem = BLI_mempool_iterstep(&iter))) {
+ if (tselem->id == id) {
+ tselem->id = NULL;
+ changed = true;
+ }
+ }
+ if (so->treehash && changed) {
+ /* rebuild hash table, because it depends on ids too */
+ /* postpone a full rebuild because this can be called many times on-free */
+ so->storeflag |= SO_TREESTORE_REBUILD;
+ }
+ }
+}
diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h
index 317d33dd3e2..c89a1bb1b9f 100644
--- a/source/blender/editors/space_outliner/outliner_intern.h
+++ b/source/blender/editors/space_outliner/outliner_intern.h
@@ -36,12 +36,10 @@
/* internal exports only */
-struct wmWindowManager;
struct wmOperatorType;
struct TreeStoreElem;
struct bContext;
struct Scene;
-struct ARegion;
struct ID;
struct Object;
@@ -59,52 +57,17 @@ typedef struct TreeElement {
PointerRNA rnaptr; // RNA Pointer
} TreeElement;
+#define TREESTORE_ID_TYPE(_id) \
+ (ELEM(GS((_id)->name), ID_SCE, ID_LI, ID_OB, ID_ME, ID_CU, ID_MB, ID_NT, ID_MA, ID_TE, ID_IM, ID_LT, ID_LA, ID_CA) || \
+ ELEM(GS((_id)->name), ID_KE, ID_WO, ID_SPK, ID_GR, ID_AR, ID_AC, ID_BR, ID_PA, ID_GD, ID_LS) || \
+ ELEM(GS((_id)->name), ID_SCR, ID_WM, ID_TXT, ID_VF)) /* Only in 'blendfile' mode ... :/ */
+
/* TreeElement->flag */
#define TE_ACTIVE 1
#define TE_ICONROW 2
#define TE_LAZY_CLOSED 4
#define TE_FREE_NAME 8
-/* TreeStoreElem types */
-#define TSE_NLA 1
-#define TSE_NLA_ACTION 2
-#define TSE_DEFGROUP_BASE 3
-#define TSE_DEFGROUP 4
-#define TSE_BONE 5
-#define TSE_EBONE 6
-#define TSE_CONSTRAINT_BASE 7
-#define TSE_CONSTRAINT 8
-#define TSE_MODIFIER_BASE 9
-#define TSE_MODIFIER 10
-#define TSE_LINKED_OB 11
-// #define TSE_SCRIPT_BASE 12 // UNUSED
-#define TSE_POSE_BASE 13
-#define TSE_POSE_CHANNEL 14
-#define TSE_ANIM_DATA 15
-#define TSE_DRIVER_BASE 16
-#define TSE_DRIVER 17
-
-#define TSE_PROXY 18
-#define TSE_R_LAYER_BASE 19
-#define TSE_R_LAYER 20
-#define TSE_R_PASS 21
-#define TSE_LINKED_MAT 22
-/* NOTE, is used for light group */
-#define TSE_LINKED_LAMP 23
-#define TSE_POSEGRP_BASE 24
-#define TSE_POSEGRP 25
-#define TSE_SEQUENCE 26
-#define TSE_SEQ_STRIP 27
-#define TSE_SEQUENCE_DUP 28
-#define TSE_LINKED_PSYS 29
-#define TSE_RNA_STRUCT 30
-#define TSE_RNA_PROPERTY 31
-#define TSE_RNA_ARRAY_ELEM 32
-#define TSE_NLA_TRACK 33
-#define TSE_KEYMAP 34
-#define TSE_KEYMAP_ITEM 35
-#define TSE_ID_BASE 36
-
/* button events */
#define OL_NAMEBUTTON 1
@@ -166,6 +129,7 @@ void outliner_free_tree(ListBase *lb);
void outliner_cleanup_tree(struct SpaceOops *soops);
TreeElement *outliner_find_tse(struct SpaceOops *soops, TreeStoreElem *tse);
+TreeElement *outliner_find_tree_element(ListBase *lb, TreeStoreElem *store_elem);
TreeElement *outliner_find_id(struct SpaceOops *soops, ListBase *lb, struct ID *id);
struct ID *outliner_search_back(SpaceOops *soops, TreeElement *te, short idcode);
@@ -205,7 +169,7 @@ void group_toggle_renderability_cb(struct bContext *C, struct Scene *scene, Tree
void item_rename_cb(struct bContext *C, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem);
-TreeElement *outliner_dropzone_find(const struct SpaceOops *soops, const float fmval[2], const int children);
+TreeElement *outliner_dropzone_find(const struct SpaceOops *soops, const float fmval[2], const bool children);
/* ...................................................... */
void OUTLINER_OT_item_activate(struct wmOperatorType *ot);
@@ -233,21 +197,26 @@ void OUTLINER_OT_keyingset_remove_selected(struct wmOperatorType *ot);
void OUTLINER_OT_drivers_add_selected(struct wmOperatorType *ot);
void OUTLINER_OT_drivers_delete_selected(struct wmOperatorType *ot);
+void OUTLINER_OT_orphans_purge(struct wmOperatorType *ot);
+
void OUTLINER_OT_parent_drop(struct wmOperatorType *ot);
void OUTLINER_OT_parent_clear(struct wmOperatorType *ot);
void OUTLINER_OT_scene_drop(struct wmOperatorType *ot);
void OUTLINER_OT_material_drop(struct wmOperatorType *ot);
+void OUTLINER_OT_group_link(struct wmOperatorType *ot);
/* outliner_tools.c ---------------------------------------------- */
void OUTLINER_OT_operation(struct wmOperatorType *ot);
+void OUTLINER_OT_scene_operation(struct wmOperatorType *ot);
void OUTLINER_OT_object_operation(struct wmOperatorType *ot);
void OUTLINER_OT_group_operation(struct wmOperatorType *ot);
void OUTLINER_OT_id_operation(struct wmOperatorType *ot);
void OUTLINER_OT_data_operation(struct wmOperatorType *ot);
void OUTLINER_OT_animdata_operation(struct wmOperatorType *ot);
void OUTLINER_OT_action_set(struct wmOperatorType *ot);
-
+void OUTLINER_OT_constraint_operation(struct wmOperatorType *ot);
+void OUTLINER_OT_modifier_operation(struct wmOperatorType *ot);
/* ---------------------------------------------------------------- */
/* outliner_ops.c */
diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c
index d735b5e75cf..839d44df25d 100644
--- a/source/blender/editors/space_outliner/outliner_ops.c
+++ b/source/blender/editors/space_outliner/outliner_ops.c
@@ -30,7 +30,6 @@
#include "DNA_space_types.h"
-#include "BLI_utildefines.h"
#include "RNA_access.h"
@@ -49,12 +48,15 @@ void outliner_operatortypes(void)
WM_operatortype_append(OUTLINER_OT_item_openclose);
WM_operatortype_append(OUTLINER_OT_item_rename);
WM_operatortype_append(OUTLINER_OT_operation);
+ WM_operatortype_append(OUTLINER_OT_scene_operation);
WM_operatortype_append(OUTLINER_OT_object_operation);
WM_operatortype_append(OUTLINER_OT_group_operation);
WM_operatortype_append(OUTLINER_OT_id_operation);
WM_operatortype_append(OUTLINER_OT_data_operation);
WM_operatortype_append(OUTLINER_OT_animdata_operation);
WM_operatortype_append(OUTLINER_OT_action_set);
+ WM_operatortype_append(OUTLINER_OT_constraint_operation);
+ WM_operatortype_append(OUTLINER_OT_modifier_operation);
WM_operatortype_append(OUTLINER_OT_show_one_level);
WM_operatortype_append(OUTLINER_OT_show_active);
@@ -73,11 +75,14 @@ void outliner_operatortypes(void)
WM_operatortype_append(OUTLINER_OT_drivers_add_selected);
WM_operatortype_append(OUTLINER_OT_drivers_delete_selected);
+
+ WM_operatortype_append(OUTLINER_OT_orphans_purge);
WM_operatortype_append(OUTLINER_OT_parent_drop);
WM_operatortype_append(OUTLINER_OT_parent_clear);
WM_operatortype_append(OUTLINER_OT_scene_drop);
WM_operatortype_append(OUTLINER_OT_material_drop);
+ WM_operatortype_append(OUTLINER_OT_group_link);
}
void outliner_keymap(wmKeyConfig *keyconf)
diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c
index 6f5bf712d55..e52c68b57e9 100644
--- a/source/blender/editors/space_outliner/outliner_select.c
+++ b/source/blender/editors/space_outliner/outliner_select.c
@@ -290,6 +290,10 @@ static eOLDrawState tree_element_active_material(
}
}
if (set != OL_SETSEL_NONE) {
+ /* Tagging object for update seems a bit stupid here, but looks like we have to do it
+ * for render views to update. See T42973.
+ * Note that RNA material update does it too, see e.g. rna_MaterialSlot_update(). */
+ DAG_id_tag_update((ID *)ob, OB_RECALC_OB);
WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_LINKS, NULL);
}
return OL_DRAWSEL_NONE;
@@ -550,10 +554,12 @@ static eOLDrawState tree_element_active_bone(
Object *ob = OBACT;
if (ob) {
if (set != OL_SETSEL_EXTEND) {
- bPoseChannel *pchannel;
/* single select forces all other bones to get unselected */
- for (pchannel = ob->pose->chanbase.first; pchannel; pchannel = pchannel->next)
- pchannel->bone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
+ Bone *bone;
+ for (bone = arm->bonebase.first; bone != NULL; bone = bone->next) {
+ bone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
+ do_outliner_bone_select_recursive(arm, bone, false);
+ }
}
}
@@ -614,7 +620,7 @@ static eOLDrawState tree_element_active_ebone(
if (set != OL_SETSEL_NONE) {
if (set == OL_SETSEL_NORMAL) {
if (!(ebone->flag & BONE_HIDDEN_A)) {
- ED_armature_deselect_all(scene->obedit, 0); // deselect
+ ED_armature_deselect_all(scene->obedit);
tree_element_active_ebone__sel(C, scene, arm, ebone, true);
status = OL_DRAWSEL_NORMAL;
}
@@ -771,7 +777,7 @@ static eOLDrawState tree_element_active_sequence_dup(
continue;
}
-// if (!strcmp(p->strip->stripdata->name, seq->strip->stripdata->name))
+// if (STREQ(p->strip->stripdata->name, seq->strip->stripdata->name))
// XXX select_single_seq(p, 0);
p = p->next;
}
@@ -869,6 +875,9 @@ eOLDrawState tree_element_type_active(
return tree_element_active_sequence_dup(scene, te, tselem, set);
case TSE_KEYMAP_ITEM:
return tree_element_active_keymap_item(C, te, tselem, set);
+ case TSE_GP_LAYER:
+ //return tree_element_active_gplayer(C, scene, te, tselem, set);
+ break;
}
return OL_DRAWSEL_NONE;
@@ -911,7 +920,7 @@ static bool do_outliner_item_activate(bContext *C, Scene *scene, ARegion *ar, Sp
if (tselem->type != TSE_SEQUENCE && tselem->type != TSE_SEQ_STRIP && tselem->type != TSE_SEQUENCE_DUP)
tree_element_set_active_object(C, scene, soops, te,
(extend && tselem->type == 0) ? OL_SETSEL_EXTEND : OL_SETSEL_NORMAL,
- recursive && tselem->type == 0 );
+ recursive && tselem->type == 0);
if (tselem->type == 0) { // the lib blocks
/* editmode? */
diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c
index d09ed1a100e..50171d7f032 100644
--- a/source/blender/editors/space_outliner/outliner_tools.c
+++ b/source/blender/editors/space_outliner/outliner_tools.c
@@ -33,6 +33,7 @@
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
+#include "DNA_gpencil_types.h"
#include "DNA_group_types.h"
#include "DNA_lamp_types.h"
#include "DNA_linestyle_types.h"
@@ -43,12 +44,15 @@
#include "DNA_sequence_types.h"
#include "DNA_world_types.h"
#include "DNA_object_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_modifier_types.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BKE_animsys.h"
#include "BKE_context.h"
+#include "BKE_constraint.h"
#include "BKE_depsgraph.h"
#include "BKE_fcurve.h"
#include "BKE_group.h"
@@ -69,6 +73,7 @@
#include "UI_interface.h"
#include "UI_view2d.h"
+#include "UI_resources.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -258,7 +263,90 @@ static void outliner_do_libdata_operation(bContext *C, Scene *scene, SpaceOops *
}
}
-/* */
+/* ******************************************** */
+typedef enum eOutliner_PropSceneOps {
+ OL_SCENE_OP_DELETE = 1
+} eOutliner_PropSceneOps;
+
+static EnumPropertyItem prop_scene_op_types[] = {
+ {OL_SCENE_OP_DELETE, "DELETE", ICON_X, "Delete", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
+static bool outliner_do_scene_operation(
+ bContext *C, eOutliner_PropSceneOps event, ListBase *lb,
+ bool (*operation_cb)(bContext *, eOutliner_PropSceneOps, TreeElement *, TreeStoreElem *))
+{
+ TreeElement *te;
+ TreeStoreElem *tselem;
+ bool success = false;
+
+ for (te = lb->first; te; te = te->next) {
+ tselem = TREESTORE(te);
+ if (tselem->flag & TSE_SELECTED) {
+ if (operation_cb(C, event, te, tselem)) {
+ success = true;
+ }
+ }
+ }
+
+ return success;
+}
+
+static bool scene_cb(bContext *C, eOutliner_PropSceneOps event, TreeElement *UNUSED(te), TreeStoreElem *tselem)
+{
+ Scene *scene = (Scene *)tselem->id;
+
+ if (event == OL_SCENE_OP_DELETE) {
+ if (ED_screen_delete_scene(C, scene)) {
+ WM_event_add_notifier(C, NC_SCENE | NA_REMOVED, scene);
+ }
+ else {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static int outliner_scene_operation_exec(bContext *C, wmOperator *op)
+{
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+ const eOutliner_PropSceneOps event = RNA_enum_get(op->ptr, "type");
+
+ if (outliner_do_scene_operation(C, event, &soops->tree, scene_cb) == false) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (event == OL_SCENE_OP_DELETE) {
+ outliner_cleanup_tree(soops);
+ ED_undo_push(C, "Delete Scene(s)");
+ }
+ else {
+ BLI_assert(0);
+ return OPERATOR_CANCELLED;
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void OUTLINER_OT_scene_operation(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Outliner Scene Operation";
+ ot->idname = "OUTLINER_OT_scene_operation";
+ ot->description = "Context menu for scene operations";
+
+ /* callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = outliner_scene_operation_exec;
+ ot->poll = ED_operator_outliner_active;
+
+ ot->flag = 0;
+
+ ot->prop = RNA_def_enum(ot->srna, "type", prop_scene_op_types, 0, "Scene Operation", "");
+}
+/* ******************************************** */
static void object_select_cb(bContext *UNUSED(C), Scene *scene, TreeElement *te,
TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem)
@@ -422,8 +510,7 @@ static void group_instance_cb(bContext *C, Scene *scene, TreeElement *UNUSED(te)
{
Group *group = (Group *)tselem->id;
- Object *ob = ED_object_add_type(C, OB_EMPTY, scene->cursor, NULL, false, scene->layact);
- rename_id(&ob->id, group->id.name + 2);
+ Object *ob = ED_object_add_type(C, OB_EMPTY, group->id.name + 2, scene->cursor, NULL, false, scene->layact);
ob->dup_group = group;
ob->transflag |= OB_DUPLIGROUP;
id_lib_extern(&group->id);
@@ -462,7 +549,7 @@ void outliner_do_object_operation(bContext *C, Scene *scene_act, SpaceOops *soop
static void clear_animdata_cb(int UNUSED(event), TreeElement *UNUSED(te),
TreeStoreElem *tselem, void *UNUSED(arg))
{
- BKE_free_animdata(tselem->id);
+ BKE_animdata_free(tselem->id);
}
@@ -499,19 +586,39 @@ static void refreshdrivers_animdata_cb(int UNUSED(event), TreeElement *UNUSED(te
/* --------------------------------- */
+typedef enum eOutliner_PropDataOps {
+ OL_DOP_SELECT = 1,
+ OL_DOP_DESELECT,
+ OL_DOP_HIDE,
+ OL_DOP_UNHIDE,
+ OL_DOP_SELECT_LINKED,
+} eOutliner_PropDataOps;
+
+typedef enum eOutliner_PropConstraintOps {
+ OL_CONSTRAINTOP_ENABLE = 1,
+ OL_CONSTRAINTOP_DISABLE,
+ OL_CONSTRAINTOP_DELETE
+} eOutliner_PropConstraintOps;
+
+typedef enum eOutliner_PropModifierOps {
+ OL_MODIFIER_OP_TOGVIS = 1,
+ OL_MODIFIER_OP_TOGREN,
+ OL_MODIFIER_OP_DELETE
+} eOutliner_PropModifierOps;
+
static void pchan_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *UNUSED(arg))
{
bPoseChannel *pchan = (bPoseChannel *)te->directdata;
- if (event == 1)
+ if (event == OL_DOP_SELECT)
pchan->bone->flag |= BONE_SELECTED;
- else if (event == 2)
+ else if (event == OL_DOP_DESELECT)
pchan->bone->flag &= ~BONE_SELECTED;
- else if (event == 3) {
+ else if (event == OL_DOP_HIDE) {
pchan->bone->flag |= BONE_HIDDEN_P;
pchan->bone->flag &= ~BONE_SELECTED;
}
- else if (event == 4)
+ else if (event == OL_DOP_UNHIDE)
pchan->bone->flag &= ~BONE_HIDDEN_P;
}
@@ -519,15 +626,15 @@ static void bone_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), v
{
Bone *bone = (Bone *)te->directdata;
- if (event == 1)
+ if (event == OL_DOP_SELECT)
bone->flag |= BONE_SELECTED;
- else if (event == 2)
+ else if (event == OL_DOP_DESELECT)
bone->flag &= ~BONE_SELECTED;
- else if (event == 3) {
+ else if (event == OL_DOP_HIDE) {
bone->flag |= BONE_HIDDEN_P;
bone->flag &= ~BONE_SELECTED;
}
- else if (event == 4)
+ else if (event == OL_DOP_UNHIDE)
bone->flag &= ~BONE_HIDDEN_P;
}
@@ -535,22 +642,22 @@ static void ebone_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem),
{
EditBone *ebone = (EditBone *)te->directdata;
- if (event == 1)
+ if (event == OL_DOP_SELECT)
ebone->flag |= BONE_SELECTED;
- else if (event == 2)
+ else if (event == OL_DOP_DESELECT)
ebone->flag &= ~BONE_SELECTED;
- else if (event == 3) {
+ else if (event == OL_DOP_HIDE) {
ebone->flag |= BONE_HIDDEN_A;
ebone->flag &= ~BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL;
}
- else if (event == 4)
+ else if (event == OL_DOP_UNHIDE)
ebone->flag &= ~BONE_HIDDEN_A;
}
static void sequence_cb(int event, TreeElement *te, TreeStoreElem *tselem, void *scene_ptr)
{
Sequence *seq = (Sequence *)te->directdata;
- if (event == 1) {
+ if (event == OL_DOP_SELECT) {
Scene *scene = (Scene *)scene_ptr;
Editing *ed = BKE_sequencer_editing_get(scene, false);
if (BLI_findindex(ed->seqbasep, seq) != -1) {
@@ -561,9 +668,23 @@ static void sequence_cb(int event, TreeElement *te, TreeStoreElem *tselem, void
(void)tselem;
}
+static void gp_layer_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *UNUSED(arg))
+{
+ bGPDlayer *gpl = (bGPDlayer *)te->directdata;
+
+ if (event == OL_DOP_SELECT)
+ gpl->flag |= GP_LAYER_SELECT;
+ else if (event == OL_DOP_DESELECT)
+ gpl->flag &= ~GP_LAYER_SELECT;
+ else if (event == OL_DOP_HIDE)
+ gpl->flag |= GP_LAYER_HIDE;
+ else if (event == OL_DOP_UNHIDE)
+ gpl->flag &= ~GP_LAYER_HIDE;
+}
+
static void data_select_linked_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *C_v)
{
- if (event == 5) {
+ if (event == OL_DOP_SELECT_LINKED) {
if (RNA_struct_is_ID(te->rnaptr.type)) {
bContext *C = (bContext *) C_v;
ID *id = te->rnaptr.data;
@@ -573,6 +694,68 @@ static void data_select_linked_cb(int event, TreeElement *te, TreeStoreElem *UNU
}
}
+static void constraint_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *C_v)
+{
+ bContext *C = C_v;
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+ bConstraint *constraint = (bConstraint *)te->directdata;
+ Object *ob = (Object *)outliner_search_back(soops, te, ID_OB);
+
+ if (event == OL_CONSTRAINTOP_ENABLE) {
+ constraint->flag &= ~CONSTRAINT_OFF;
+ ED_object_constraint_update(ob);
+ WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob);
+ }
+ else if (event == OL_CONSTRAINTOP_DISABLE) {
+ constraint->flag = CONSTRAINT_OFF;
+ ED_object_constraint_update(ob);
+ WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob);
+ }
+ else if (event == OL_CONSTRAINTOP_DELETE) {
+ ListBase *lb = NULL;
+
+ if (TREESTORE(te->parent->parent)->type == TSE_POSE_CHANNEL) {
+ lb = &((bPoseChannel *)te->parent->parent->directdata)->constraints;
+ }
+ else {
+ lb = &ob->constraints;
+ }
+
+ if (BKE_constraint_remove_ex(lb, ob, constraint, true)) {
+ /* there's no active constraint now, so make sure this is the case */
+ BKE_constraints_active_set(&ob->constraints, NULL);
+ ED_object_constraint_update(ob); /* needed to set the flags on posebones correctly */
+ WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT | NA_REMOVED, ob);
+ te->store_elem->flag &= ~TSE_SELECTED;
+ }
+ }
+}
+
+static void modifier_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *Carg)
+{
+ bContext *C = (bContext *)Carg;
+ Main *bmain = CTX_data_main(C);
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+ ModifierData *md = (ModifierData *)te->directdata;
+ Object *ob = (Object *)outliner_search_back(soops, te, ID_OB);
+
+ if (event == OL_MODIFIER_OP_TOGVIS) {
+ md->mode ^= eModifierMode_Realtime;
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
+ }
+ else if (event == OL_MODIFIER_OP_TOGREN) {
+ md->mode ^= eModifierMode_Render;
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
+ }
+ else if (event == OL_MODIFIER_OP_DELETE) {
+ ED_object_modifier_remove(NULL, bmain, ob, md);
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER | NA_REMOVED, ob);
+ te->store_elem->flag &= ~TSE_SELECTED;
+ }
+}
+
static void outliner_do_data_operation(SpaceOops *soops, int type, int event, ListBase *lb,
void (*operation_cb)(int, TreeElement *, TreeStoreElem *, void *),
void *arg)
@@ -593,14 +776,60 @@ static void outliner_do_data_operation(SpaceOops *soops, int type, int event, Li
}
}
+static Base *outline_delete_hierarchy(bContext *C, Scene *scene, Base *base)
+{
+ Base *child_base, *base_next;
+ Object *parent;
+
+ if (!base) {
+ return NULL;
+ }
+
+ for (child_base = scene->base.first; child_base; child_base = base_next) {
+ base_next = child_base->next;
+ for (parent = child_base->object->parent; parent && (parent != base->object); parent = parent->parent);
+ if (parent) {
+ base_next = outline_delete_hierarchy(C, scene, child_base);
+ }
+ }
+
+ base_next = base->next;
+ ED_base_object_free_and_unlink(CTX_data_main(C), scene, base);
+ return base_next;
+}
+
+static void object_delete_hierarchy_cb(
+ bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem)
+{
+ Base *base = (Base *)te->directdata;
+ Object *obedit = scene->obedit;
+
+ if (!base) {
+ base = BKE_scene_base_find(scene, (Object *)tselem->id);
+ }
+ if (base) {
+ /* Check also library later. */
+ for (; obedit && (obedit != base->object); obedit = obedit->parent);
+ if (obedit == base->object) {
+ ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO);
+ }
+
+ outline_delete_hierarchy(C, scene, base);
+ te->directdata = NULL;
+ tselem->id = NULL;
+ }
+
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
+}
+
/* **************************************** */
enum {
- OL_OP_ENDMARKER = 0,
- OL_OP_SELECT,
+ OL_OP_SELECT = 1,
OL_OP_DESELECT,
OL_OP_SELECT_HIERARCHY,
OL_OP_DELETE,
+ OL_OP_DELETE_HIERARCHY,
OL_OP_LOCALIZED, /* disabled, see below */
OL_OP_TOGVIS,
OL_OP_TOGSEL,
@@ -613,11 +842,12 @@ static EnumPropertyItem prop_object_op_types[] = {
{OL_OP_DESELECT, "DESELECT", 0, "Deselect", ""},
{OL_OP_SELECT_HIERARCHY, "SELECT_HIERARCHY", 0, "Select Hierarchy", ""},
{OL_OP_DELETE, "DELETE", 0, "Delete", ""},
+ {OL_OP_DELETE_HIERARCHY, "DELETE_HIERARCHY", 0, "Delete Hierarchy", ""},
{OL_OP_TOGVIS, "TOGVIS", 0, "Toggle Visible", ""},
{OL_OP_TOGSEL, "TOGSEL", 0, "Toggle Selectable", ""},
{OL_OP_TOGREN, "TOGREN", 0, "Toggle Renderable", ""},
{OL_OP_RENAME, "RENAME", 0, "Rename", ""},
- {OL_OP_ENDMARKER, NULL, 0, NULL, NULL}
+ {0, NULL, 0, NULL, NULL}
};
static int outliner_object_operation_exec(bContext *C, wmOperator *op)
@@ -672,6 +902,16 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
str = "Delete Objects";
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
}
+ else if (event == OL_OP_DELETE_HIERARCHY) {
+ outliner_do_object_operation(C, scene, soops, &soops->tree, object_delete_hierarchy_cb);
+
+ /* XXX: See OL_OP_DELETE comment above. */
+ outliner_cleanup_tree(soops);
+
+ DAG_relations_tag_update(bmain);
+ str = "Delete Object Hierarchy";
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
+ }
else if (event == OL_OP_LOCALIZED) { /* disabled, see above enum (ton) */
outliner_do_object_operation(C, scene, soops, &soops->tree, id_local_cb);
str = "Localized Objects";
@@ -725,15 +965,26 @@ void OUTLINER_OT_object_operation(wmOperatorType *ot)
/* **************************************** */
+typedef enum eOutliner_PropGroupOps {
+ OL_GROUPOP_UNLINK = 1,
+ OL_GROUPOP_LOCAL,
+ OL_GROUPOP_LINK,
+ OL_GROUPOP_INSTANCE,
+ OL_GROUPOP_TOGVIS,
+ OL_GROUPOP_TOGSEL,
+ OL_GROUPOP_TOGREN,
+ OL_GROUPOP_RENAME,
+} eOutliner_PropGroupOps;
+
static EnumPropertyItem prop_group_op_types[] = {
- {0, "UNLINK", 0, "Unlink Group", ""},
- {1, "LOCAL", 0, "Make Local Group", ""},
- {2, "LINK", 0, "Link Group Objects to Scene", ""},
- {3, "INSTANCE", 0, "Instance Groups in Scene", ""},
- {4, "TOGVIS", 0, "Toggle Visible Group", ""},
- {5, "TOGSEL", 0, "Toggle Selectable", ""},
- {6, "TOGREN", 0, "Toggle Renderable", ""},
- {7, "RENAME", 0, "Rename", ""},
+ {OL_GROUPOP_UNLINK, "UNLINK", 0, "Unlink Group", ""},
+ {OL_GROUPOP_LOCAL, "LOCAL", 0, "Make Local Group", ""},
+ {OL_GROUPOP_LINK, "LINK", 0, "Link Group Objects to Scene", ""},
+ {OL_GROUPOP_INSTANCE, "INSTANCE", 0, "Instance Groups in Scene", ""},
+ {OL_GROUPOP_TOGVIS, "TOGVIS", 0, "Toggle Visible Group", ""},
+ {OL_GROUPOP_TOGSEL, "TOGSEL", 0, "Toggle Selectable", ""},
+ {OL_GROUPOP_TOGREN, "TOGREN", 0, "Toggle Renderable", ""},
+ {OL_GROUPOP_RENAME, "RENAME", 0, "Rename", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -750,28 +1001,42 @@ static int outliner_group_operation_exec(bContext *C, wmOperator *op)
event = RNA_enum_get(op->ptr, "type");
switch (event) {
- case 0: outliner_do_libdata_operation(C, scene, soops, &soops->tree, unlink_group_cb); break;
- case 1: outliner_do_libdata_operation(C, scene, soops, &soops->tree, id_local_cb); break;
- case 2: outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_linkobs2scene_cb); break;
- case 3: outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_instance_cb); break;
- case 4: outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_toggle_visibility_cb); break;
- case 5: outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_toggle_selectability_cb); break;
- case 6: outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_toggle_renderability_cb); break;
- case 7: outliner_do_libdata_operation(C, scene, soops, &soops->tree, item_rename_cb); break;
+ case OL_GROUPOP_UNLINK:
+ outliner_do_libdata_operation(C, scene, soops, &soops->tree, unlink_group_cb);
+ break;
+ case OL_GROUPOP_LOCAL:
+ outliner_do_libdata_operation(C, scene, soops, &soops->tree, id_local_cb);
+ break;
+ case OL_GROUPOP_LINK:
+ outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_linkobs2scene_cb);
+ break;
+ case OL_GROUPOP_INSTANCE:
+ outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_instance_cb);
+ break;
+ case OL_GROUPOP_TOGVIS:
+ outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_toggle_visibility_cb);
+ break;
+ case OL_GROUPOP_TOGSEL:
+ outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_toggle_selectability_cb);
+ break;
+ case OL_GROUPOP_TOGREN:
+ outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_toggle_renderability_cb);
+ break;
+ case OL_GROUPOP_RENAME:
+ outliner_do_libdata_operation(C, scene, soops, &soops->tree, item_rename_cb);
+ break;
default:
BLI_assert(0);
- return OPERATOR_CANCELLED;
}
-
if (event == 3) { /* instance */
/* works without this except if you try render right after, see: 22027 */
DAG_relations_tag_update(CTX_data_main(C));
}
-
- ED_undo_push(C, prop_group_op_types[event].name);
+
+ ED_undo_push(C, prop_group_op_types[event - 1].name);
WM_event_add_notifier(C, NC_GROUP, NULL);
-
+
return OPERATOR_FINISHED;
}
@@ -1195,12 +1460,105 @@ void OUTLINER_OT_animdata_operation(wmOperatorType *ot)
/* **************************************** */
+static EnumPropertyItem prop_constraint_op_types[] = {
+ {OL_CONSTRAINTOP_ENABLE, "ENABLE", ICON_RESTRICT_VIEW_OFF, "Enable", ""},
+ {OL_CONSTRAINTOP_DISABLE, "DISABLE", ICON_RESTRICT_VIEW_ON, "Disable", ""},
+ {OL_CONSTRAINTOP_DELETE, "DELETE", ICON_X, "Delete", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
+static int outliner_constraint_operation_exec(bContext *C, wmOperator *op)
+{
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+ int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
+ eOutliner_PropConstraintOps event;
+
+ event = RNA_enum_get(op->ptr, "type");
+ set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel);
+
+ outliner_do_data_operation(soops, datalevel, event, &soops->tree, constraint_cb, C);
+
+ if (event == OL_CONSTRAINTOP_DELETE) {
+ outliner_cleanup_tree(soops);
+ }
+
+ ED_undo_push(C, "Constraint operation");
+
+ return OPERATOR_FINISHED;
+}
+
+void OUTLINER_OT_constraint_operation(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Outliner Constraint Operation";
+ ot->idname = "OUTLINER_OT_constraint_operation";
+ ot->description = "";
+
+ /* callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = outliner_constraint_operation_exec;
+ ot->poll = ED_operator_outliner_active;
+
+ ot->flag = 0;
+
+ ot->prop = RNA_def_enum(ot->srna, "type", prop_constraint_op_types, 0, "Constraint Operation", "");
+}
+
+/* ******************** */
+
+static EnumPropertyItem prop_modifier_op_types[] = {
+ {OL_MODIFIER_OP_TOGVIS, "TOGVIS", ICON_RESTRICT_VIEW_OFF, "Toggle viewport use", ""},
+ {OL_MODIFIER_OP_TOGREN, "TOGREN", ICON_RESTRICT_RENDER_OFF, "Toggle render use", ""},
+ {OL_MODIFIER_OP_DELETE, "DELETE", ICON_X, "Delete", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
+static int outliner_modifier_operation_exec(bContext *C, wmOperator *op)
+{
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+ int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
+ eOutliner_PropModifierOps event;
+
+ event = RNA_enum_get(op->ptr, "type");
+ set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel);
+
+ outliner_do_data_operation(soops, datalevel, event, &soops->tree, modifier_cb, C);
+
+ if (event == OL_MODIFIER_OP_DELETE) {
+ outliner_cleanup_tree(soops);
+ }
+
+ ED_undo_push(C, "Modifier operation");
+
+ return OPERATOR_FINISHED;
+}
+
+void OUTLINER_OT_modifier_operation(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Outliner Modifier Operation";
+ ot->idname = "OUTLINER_OT_modifier_operation";
+ ot->description = "";
+
+ /* callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = outliner_modifier_operation_exec;
+ ot->poll = ED_operator_outliner_active;
+
+ ot->flag = 0;
+
+ ot->prop = RNA_def_enum(ot->srna, "type", prop_modifier_op_types, 0, "Modifier Operation", "");
+}
+
+/* ******************** */
+
+// XXX: select linked is for RNA structs only
static EnumPropertyItem prop_data_op_types[] = {
- {1, "SELECT", 0, "Select", ""},
- {2, "DESELECT", 0, "Deselect", ""},
- {3, "HIDE", 0, "Hide", ""},
- {4, "UNHIDE", 0, "Unhide", ""},
- {5, "SELECT_LINKED", 0, "Select Linked", ""},
+ {OL_DOP_SELECT, "SELECT", 0, "Select", ""},
+ {OL_DOP_DESELECT, "DESELECT", 0, "Deselect", ""},
+ {OL_DOP_HIDE, "HIDE", 0, "Hide", ""},
+ {OL_DOP_UNHIDE, "UNHIDE", 0, "Unhide", ""},
+ {OL_DOP_SELECT_LINKED, "SELECT_LINKED", 0, "Select Linked", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -1208,7 +1566,7 @@ static int outliner_data_operation_exec(bContext *C, wmOperator *op)
{
SpaceOops *soops = CTX_wm_space_outliner(C);
int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
- int event;
+ eOutliner_PropDataOps event;
/* check for invalid states */
if (soops == NULL)
@@ -1217,47 +1575,53 @@ static int outliner_data_operation_exec(bContext *C, wmOperator *op)
event = RNA_enum_get(op->ptr, "type");
set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel);
- if (event <= 0)
- return OPERATOR_CANCELLED;
-
switch (datalevel) {
case TSE_POSE_CHANNEL:
{
outliner_do_data_operation(soops, datalevel, event, &soops->tree, pchan_cb, NULL);
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
ED_undo_push(C, "PoseChannel operation");
- }
+
break;
-
+ }
case TSE_BONE:
{
outliner_do_data_operation(soops, datalevel, event, &soops->tree, bone_cb, NULL);
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
ED_undo_push(C, "Bone operation");
- }
+
break;
-
+ }
case TSE_EBONE:
{
outliner_do_data_operation(soops, datalevel, event, &soops->tree, ebone_cb, NULL);
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
ED_undo_push(C, "EditBone operation");
- }
+
break;
-
+ }
case TSE_SEQUENCE:
{
Scene *scene = CTX_data_scene(C);
outliner_do_data_operation(soops, datalevel, event, &soops->tree, sequence_cb, scene);
+
+ break;
}
+ case TSE_GP_LAYER:
+ {
+ outliner_do_data_operation(soops, datalevel, event, &soops->tree, gp_layer_cb, NULL);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, NULL);
+ ED_undo_push(C, "Grease Pencil Layer operation");
+
break;
-
+ }
case TSE_RNA_STRUCT:
- if (event == 5) {
+ if (event == OL_DOP_SELECT_LINKED) {
outliner_do_data_operation(soops, datalevel, event, &soops->tree, data_select_linked_cb, C);
}
+
break;
-
+
default:
BKE_report(op->reports, RPT_WARNING, "Not yet implemented");
break;
@@ -1312,8 +1676,12 @@ static int do_outliner_operation_event(bContext *C, Scene *scene, ARegion *ar, S
set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel);
if (scenelevel) {
- //if (objectlevel || datalevel || idlevel) error("Mixed selection");
- //else pupmenu("Scene Operations%t|Delete");
+ if (objectlevel || datalevel || idlevel) {
+ BKE_report(reports, RPT_WARNING, "Mixed selection");
+ }
+ else {
+ WM_operator_name_call(C, "OUTLINER_OT_scene_operation", WM_OP_INVOKE_REGION_WIN, NULL);
+ }
}
else if (objectlevel) {
WM_operator_name_call(C, "OUTLINER_OT_object_operation", WM_OP_INVOKE_REGION_WIN, NULL);
@@ -1342,6 +1710,15 @@ static int do_outliner_operation_event(bContext *C, Scene *scene, ARegion *ar, S
else if (ELEM(datalevel, TSE_R_LAYER_BASE, TSE_R_LAYER, TSE_R_PASS)) {
/*WM_operator_name_call(C, "OUTLINER_OT_renderdata_operation", WM_OP_INVOKE_REGION_WIN, NULL)*/
}
+ else if (datalevel == TSE_ID_BASE) {
+ /* do nothing... there are no ops needed here yet */
+ }
+ else if (datalevel == TSE_CONSTRAINT) {
+ WM_operator_name_call(C, "OUTLINER_OT_constraint_operation", WM_OP_INVOKE_REGION_WIN, NULL);
+ }
+ else if (datalevel == TSE_MODIFIER) {
+ WM_operator_name_call(C, "OUTLINER_OT_modifier_operation", WM_OP_INVOKE_REGION_WIN, NULL);
+ }
else {
WM_operator_name_call(C, "OUTLINER_OT_data_operation", WM_OP_INVOKE_REGION_WIN, NULL);
}
@@ -1364,9 +1741,14 @@ static int outliner_operation(bContext *C, wmOperator *UNUSED(op), const wmEvent
Scene *scene = CTX_data_scene(C);
ARegion *ar = CTX_wm_region(C);
SpaceOops *soops = CTX_wm_space_outliner(C);
+ uiBut *but = UI_context_active_but_get(C);
TreeElement *te;
float fmval[2];
+ if (but) {
+ UI_but_tooltip_timer_remove(C, but);
+ }
+
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) {
diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c
index 5801dd126e3..aaca61ed5cf 100644
--- a/source/blender/editors/space_outliner/outliner_tree.c
+++ b/source/blender/editors/space_outliner/outliner_tree.c
@@ -38,6 +38,7 @@
#include "DNA_armature_types.h"
#include "DNA_constraint_types.h"
#include "DNA_camera_types.h"
+#include "DNA_gpencil_types.h"
#include "DNA_group_types.h"
#include "DNA_key_types.h"
#include "DNA_lamp_types.h"
@@ -57,7 +58,7 @@
#include "BLI_mempool.h"
#include "BLI_fnmatch.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "BKE_fcurve.h"
#include "BKE_main.h"
@@ -65,7 +66,7 @@
#include "BKE_modifier.h"
#include "BKE_sequencer.h"
#include "BKE_idcode.h"
-#include "BKE_treehash.h"
+#include "BKE_outliner_treehash.h"
#include "ED_armature.h"
#include "ED_screen.h"
@@ -103,6 +104,8 @@ static void outliner_storage_cleanup(SpaceOops *soops)
/* cleanup only after reading file or undo step, and always for
* RNA datablocks view in order to save memory */
if (soops->storeflag & SO_TREESTORE_CLEANUP) {
+ soops->storeflag &= ~SO_TREESTORE_CLEANUP;
+
BLI_mempool_iternew(ts, &iter);
while ((tselem = BLI_mempool_iterstep(&iter))) {
if (tselem->id == NULL) unused++;
@@ -113,7 +116,7 @@ static void outliner_storage_cleanup(SpaceOops *soops)
BLI_mempool_destroy(ts);
soops->treestore = NULL;
if (soops->treehash) {
- BKE_treehash_free(soops->treehash);
+ BKE_outliner_treehash_free(soops->treehash);
soops->treehash = NULL;
}
}
@@ -132,7 +135,7 @@ static void outliner_storage_cleanup(SpaceOops *soops)
soops->treestore = new_ts;
if (soops->treehash) {
/* update hash table to fix broken pointers */
- BKE_treehash_rebuild_from_treestore(soops->treehash, soops->treestore);
+ BKE_outliner_treehash_rebuild_from_treestore(soops->treehash, soops->treestore);
}
}
}
@@ -150,12 +153,12 @@ static void check_persistent(SpaceOops *soops, TreeElement *te, ID *id, short ty
}
if (soops->treehash == NULL) {
- soops->treehash = BKE_treehash_create_from_treestore(soops->treestore);
+ soops->treehash = BKE_outliner_treehash_create_from_treestore(soops->treestore);
}
/* find any unused tree element in treestore and mark it as used
* (note that there may be multiple unused elements in case of linked objects) */
- tselem = BKE_treehash_lookup_unused(soops->treehash, type, nr, id);
+ tselem = BKE_outliner_treehash_lookup_unused(soops->treehash, type, nr, id);
if (tselem) {
te->store_elem = tselem;
tselem->used = 1;
@@ -170,7 +173,7 @@ static void check_persistent(SpaceOops *soops, TreeElement *te, ID *id, short ty
tselem->used = 0;
tselem->flag = TSE_CLOSED;
te->store_elem = tselem;
- BKE_treehash_add_element(soops->treehash, tselem);
+ BKE_outliner_treehash_add_element(soops->treehash, tselem);
}
/* ********************************************************* */
@@ -196,7 +199,7 @@ void outliner_cleanup_tree(SpaceOops *soops)
}
/* Find specific item from the treestore */
-static TreeElement *outliner_find_tree_element(ListBase *lb, TreeStoreElem *store_elem)
+TreeElement *outliner_find_tree_element(ListBase *lb, TreeStoreElem *store_elem)
{
TreeElement *te, *tes;
for (te = lb->first; te; te = te->next) {
@@ -215,7 +218,7 @@ TreeElement *outliner_find_tse(SpaceOops *soops, TreeStoreElem *tse)
if (tse->id == NULL) return NULL;
/* check if 'tse' is in treestore */
- tselem = BKE_treehash_lookup_any(soops->treehash, tse->type, tse->nr, tse->id);
+ tselem = BKE_outliner_treehash_lookup_any(soops->treehash, tse->type, tse->nr, tse->id);
if (tselem)
return outliner_find_tree_element(&soops->tree, tselem);
@@ -430,11 +433,13 @@ static void outliner_add_scene_contents(SpaceOops *soops, ListBase *lb, Scene *s
// TODO: move this to the front?
if (outliner_animdata_test(sce->adt))
outliner_add_element(soops, lb, sce, te, TSE_ANIM_DATA, 0);
+
+ outliner_add_element(soops, lb, sce->gpd, te, 0, 0);
outliner_add_element(soops, lb, sce->world, te, 0, 0);
#ifdef WITH_FREESTYLE
- if (STREQ(sce->r.engine, "BLENDER_RENDER") && (sce->r.mode & R_EDGE_FRS))
+ if (STREQ(sce->r.engine, RE_engine_id_BLENDER_RENDER) && (sce->r.mode & R_EDGE_FRS))
outliner_add_line_styles(soops, lb, sce, te);
#endif
}
@@ -451,6 +456,8 @@ static void outliner_add_object_contents(SpaceOops *soops, TreeElement *te, Tree
if (ob->proxy && ob->id.lib == NULL)
outliner_add_element(soops, &te->subtree, ob->proxy, te, TSE_PROXY, 0);
+
+ outliner_add_element(soops, &te->subtree, ob->gpd, te, 0, 0);
outliner_add_element(soops, &te->subtree, ob->data, te, 0, 0);
@@ -764,16 +771,16 @@ static void outliner_add_id_contents(SpaceOops *soops, TreeElement *te, TreeStor
ten = outliner_add_element(soops, &te->subtree, id, te, TSE_EBONE, a);
ten->directdata = ebone;
ten->name = ebone->name;
- ebone->temp = ten;
+ ebone->temp.p = ten;
}
/* make hierarchy */
- ten = arm->edbo->first ? ((EditBone *)arm->edbo->first)->temp : NULL;
+ ten = arm->edbo->first ? ((EditBone *)arm->edbo->first)->temp.p : NULL;
while (ten) {
TreeElement *nten = ten->next, *par;
ebone = (EditBone *)ten->directdata;
if (ebone->parent) {
BLI_remlink(&te->subtree, ten);
- par = ebone->parent->temp;
+ par = ebone->parent->temp.p;
BLI_addtail(&par->subtree, ten);
ten->parent = par;
}
@@ -809,6 +816,22 @@ static void outliner_add_id_contents(SpaceOops *soops, TreeElement *te, TreeStor
}
break;
}
+ case ID_GD:
+ {
+ bGPdata *gpd = (bGPdata *)id;
+ bGPDlayer *gpl;
+ int a = 0;
+
+ if (outliner_animdata_test(gpd->adt))
+ outliner_add_element(soops, &te->subtree, gpd, te, TSE_ANIM_DATA, 0);
+
+ // TODO: base element for layers?
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ outliner_add_element(soops, &te->subtree, gpl, te, TSE_GP_LAYER, a);
+ a++;
+ }
+ break;
+ }
}
}
@@ -825,6 +848,10 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
id = ((PointerRNA *)idv)->id.data;
if (!id) id = ((PointerRNA *)idv)->data;
}
+ else if (type == TSE_GP_LAYER) {
+ /* idv is the layer its self */
+ id = TREESTORE(parent)->id;
+ }
/* One exception */
if (type == TSE_ID_BASE) {
@@ -834,6 +861,11 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
return NULL;
}
+ if (type == 0) {
+ /* Zero type means real ID, ensure we do not get non-outliner ID types here... */
+ BLI_assert(TREESTORE_ID_TYPE(id));
+ }
+
te = MEM_callocN(sizeof(TreeElement), "tree elem");
/* add to the visual tree */
BLI_addtail(lb, te);
@@ -856,6 +888,9 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
else if (type == TSE_ANIM_DATA) {
/* pass */
}
+ else if (type == TSE_GP_LAYER) {
+ /* pass */
+ }
else if (type == TSE_ID_BASE) {
/* pass */
}
@@ -938,6 +973,12 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
}
}
}
+ else if (type == TSE_GP_LAYER) {
+ bGPDlayer *gpl = (bGPDlayer *)idv;
+
+ te->name = gpl->info;
+ te->directdata = gpl;
+ }
else if (type == TSE_SEQUENCE) {
Sequence *seq = (Sequence *) idv;
Sequence *p;
@@ -951,7 +992,7 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
te->directdata = seq;
te->name = seq->name + 2;
- if (seq->type < SEQ_TYPE_EFFECT) {
+ if (!(seq->type & SEQ_TYPE_EFFECT)) {
/*
* This work like the sequence.
* If the sequence have a name (not default name)
@@ -1102,7 +1143,7 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
int a = 0;
for (kmi = km->items.first; kmi; kmi = kmi->next, a++) {
- const char *key = WM_key_event_string(kmi->type);
+ const char *key = WM_key_event_string(kmi->type, false);
if (key[0]) {
wmOperatorType *ot = NULL;
@@ -1160,7 +1201,7 @@ static int need_add_seq_dup(Sequence *seq)
continue;
}
- if (!strcmp(p->strip->stripdata->name, seq->strip->stripdata->name))
+ if (STREQ(p->strip->stripdata->name, seq->strip->stripdata->name))
return(2);
p = p->prev;
}
@@ -1172,7 +1213,7 @@ static int need_add_seq_dup(Sequence *seq)
continue;
}
- if (!strcmp(p->strip->stripdata->name, seq->strip->stripdata->name))
+ if (STREQ(p->strip->stripdata->name, seq->strip->stripdata->name))
return(0);
p = p->next;
}
@@ -1191,12 +1232,90 @@ static void outliner_add_seq_dup(SpaceOops *soops, Sequence *seq, TreeElement *t
continue;
}
- if (!strcmp(p->strip->stripdata->name, seq->strip->stripdata->name))
+ if (STREQ(p->strip->stripdata->name, seq->strip->stripdata->name))
/* ch = */ /* UNUSED */ outliner_add_element(soops, &te->subtree, (void *)p, te, TSE_SEQUENCE, index);
p = p->next;
}
}
+
+/* ----------------------------------------------- */
+
+
+static void outliner_add_library_contents(Main *mainvar, SpaceOops *soops, TreeElement *te, Library *lib)
+{
+ TreeElement *ten;
+ ListBase *lbarray[MAX_LIBARRAY];
+ int a, tot;
+
+ tot = set_listbasepointers(mainvar, lbarray);
+ for (a = 0; a < tot; a++) {
+ if (lbarray[a]->first) {
+ ID *id = lbarray[a]->first;
+
+ /* check if there's data in current lib */
+ for (; id; id = id->next)
+ if (id->lib == lib)
+ break;
+
+ if (id) {
+ ten = outliner_add_element(soops, &te->subtree, lbarray[a], NULL, TSE_ID_BASE, 0);
+ ten->directdata = lbarray[a];
+
+ ten->name = (char *)BKE_idcode_to_name_plural(GS(id->name));
+ if (ten->name == NULL)
+ ten->name = "UNKNOWN";
+
+ for (id = lbarray[a]->first; id; id = id->next) {
+ if (id->lib == lib)
+ outliner_add_element(soops, &ten->subtree, id, ten, 0, 0);
+ }
+ }
+ }
+ }
+
+}
+
+static void outliner_add_orphaned_datablocks(Main *mainvar, SpaceOops *soops)
+{
+ TreeElement *ten;
+ ListBase *lbarray[MAX_LIBARRAY];
+ int a, tot;
+
+ tot = set_listbasepointers(mainvar, lbarray);
+ for (a = 0; a < tot; a++) {
+ if (lbarray[a]->first) {
+ ID *id = lbarray[a]->first;
+
+ /* check if there are any datablocks of this type which are orphans */
+ for (; id; id = id->next) {
+ if (ID_REAL_USERS(id) <= 0)
+ break;
+ }
+
+ if (id) {
+ /* header for this type of datablock */
+ /* TODO's:
+ * - Add a parameter to BKE_idcode_to_name_plural to get a sane "user-visible" name instead?
+ * - Ensure that this uses nice icons for the datablock type involved instead of the dot?
+ */
+ ten = outliner_add_element(soops, &soops->tree, lbarray[a], NULL, TSE_ID_BASE, 0);
+ ten->directdata = lbarray[a];
+
+ ten->name = (char *)BKE_idcode_to_name_plural(GS(id->name));
+ if (ten->name == NULL)
+ ten->name = "UNKNOWN";
+
+ /* add the orphaned datablocks - these will not be added with any subtrees attached */
+ for (id = lbarray[a]->first; id; id = id->next) {
+ if (ID_REAL_USERS(id) <= 0)
+ outliner_add_element(soops, &ten->subtree, id, ten, 0, 0);
+ }
+ }
+ }
+ }
+}
+
/* ======================================================= */
/* Generic Tree Building helpers - order these are called is top to bottom */
@@ -1311,7 +1430,10 @@ static void outliner_sort(SpaceOops *soops, ListBase *lb)
TreeElement *te;
TreeStoreElem *tselem;
int totelem = 0;
-
+
+ if (soops->flag & SO_SKIP_SORT_ALPHA)
+ return;
+
te = lb->last;
if (te == NULL) return;
tselem = TREESTORE(te);
@@ -1371,59 +1493,42 @@ static void outliner_sort(SpaceOops *soops, ListBase *lb)
/* Filtering ----------------------------------------------- */
-static int outliner_filter_has_name(TreeElement *te, const char *name, int flags)
+static bool outliner_filter_has_name(TreeElement *te, const char *name, int flags)
{
-#if 0
- int found = 0;
-
- /* determine if match */
- if (flags & SO_FIND_CASE_SENSITIVE) {
- if (flags & SO_FIND_COMPLETE)
- found = strcmp(te->name, name) == 0;
- else
- found = strstr(te->name, name) != NULL;
- }
- else {
- if (flags & SO_FIND_COMPLETE)
- found = BLI_strcasecmp(te->name, name) == 0;
- else
- found = BLI_strcasestr(te->name, name) != NULL;
- }
-#else
-
int fn_flag = 0;
- int found = 0;
-
+
if ((flags & SO_FIND_CASE_SENSITIVE) == 0)
fn_flag |= FNM_CASEFOLD;
- if (flags & SO_FIND_COMPLETE) {
- found = fnmatch(name, te->name, fn_flag) == 0;
- }
- else {
- char fn_name[sizeof(((struct SpaceOops *)NULL)->search_string) + 2];
- BLI_snprintf(fn_name, sizeof(fn_name), "*%s*", name);
- found = fnmatch(fn_name, te->name, fn_flag) == 0;
- }
- return found;
-#endif
+ return fnmatch(name, te->name, fn_flag) == 0;
}
static int outliner_filter_tree(SpaceOops *soops, ListBase *lb)
{
TreeElement *te, *ten;
TreeStoreElem *tselem;
-
+ char search_buff[sizeof(((struct SpaceOops *)NULL)->search_string) + 2];
+ char *search_string;
+
/* although we don't have any search string, we return true
* since the entire tree is ok then...
*/
if (soops->search_string[0] == 0)
return 1;
+ if (soops->search_flags & SO_FIND_COMPLETE) {
+ search_string = soops->search_string;
+ }
+ else {
+ /* Implicitly add heading/trailing wildcards if needed. */
+ BLI_strncpy_ensure_pad(search_buff, soops->search_string, '*', sizeof(search_buff));
+ search_string = search_buff;
+ }
+
for (te = lb->first; te; te = ten) {
ten = te->next;
- if (0 == outliner_filter_has_name(te, soops->search_string, soops->search_flags)) {
+ if (!outliner_filter_has_name(te, search_string, soops->search_flags)) {
/* item isn't something we're looking for, but...
* - if the subtree is expanded, check if there are any matches that can be easily found
* so that searching for "cu" in the default scene will still match the Cube
@@ -1458,42 +1563,6 @@ static int outliner_filter_tree(SpaceOops *soops, ListBase *lb)
return (BLI_listbase_is_empty(lb) == false);
}
-static void outliner_add_library_contents(Main *mainvar, SpaceOops *soops, TreeElement *te, Library *lib)
-{
- TreeElement *ten;
- ListBase *lbarray[MAX_LIBARRAY];
- int a, tot;
-
- tot = set_listbasepointers(mainvar, lbarray);
- for (a = 0; a < tot; a++) {
- if (lbarray[a]->first) {
- ID *id = lbarray[a]->first;
-
- /* check if there's data in current lib */
- for (; id; id = id->next)
- if (id->lib == lib)
- break;
-
- if (id) {
-
- ten = outliner_add_element(soops, &te->subtree, (void *)lbarray[a], NULL, TSE_ID_BASE, 0);
- ten->directdata = lbarray[a];
-
- ten->name = (char *)BKE_idcode_to_name_plural(GS(id->name));
- if (ten->name == NULL)
- ten->name = "UNKNOWN";
-
- for (id = lbarray[a]->first; id; id = id->next) {
- if (id->lib == lib)
- outliner_add_element(soops, &ten->subtree, id, ten, 0, 0);
- }
- }
- }
- }
-
-}
-
-
/* ======================================================= */
/* Main Tree Building API */
@@ -1515,6 +1584,11 @@ void outliner_build_tree(Main *mainvar, Scene *scene, SpaceOops *soops)
else
soops->search_flags &= ~SO_SEARCH_RECURSIVE;
+ if (soops->treehash && (soops->storeflag & SO_TREESTORE_REBUILD)) {
+ soops->storeflag &= ~SO_TREESTORE_REBUILD;
+ BKE_outliner_treehash_rebuild_from_treestore(soops->treehash, soops->treestore);
+ }
+
if (soops->tree.first && (soops->storeflag & SO_TREESTORE_REDRAW))
return;
@@ -1553,10 +1627,19 @@ void outliner_build_tree(Main *mainvar, Scene *scene, SpaceOops *soops)
tselem = TREESTORE(ten);
lib = (Library *)tselem->id;
if (lib && lib->parent) {
- BLI_remlink(&soops->tree, ten);
par = (TreeElement *)lib->parent->id.newid;
- BLI_addtail(&par->subtree, ten);
- ten->parent = par;
+ if (tselem->id->flag & LIB_INDIRECT) {
+ /* Only remove from 'first level' if lib is not also directly used. */
+ BLI_remlink(&soops->tree, ten);
+ BLI_addtail(&par->subtree, ten);
+ ten->parent = par;
+ }
+ else {
+ /* Else, make a new copy of the libtree for our parent. */
+ TreeElement *dupten = outliner_add_element(soops, &par->subtree, lib, NULL, 0, 0);
+ outliner_add_library_contents(mainvar, soops, dupten, lib);
+ dupten->parent = par;
+ }
}
ten = nten;
}
@@ -1688,6 +1771,9 @@ void outliner_build_tree(Main *mainvar, Scene *scene, SpaceOops *soops)
tselem->flag &= ~TSE_CLOSED;
}
}
+ else if (soops->outlinevis == SO_ID_ORPHANS) {
+ outliner_add_orphaned_datablocks(mainvar, soops);
+ }
else {
ten = outliner_add_element(soops, &soops->tree, OBACT, NULL, 0, 0);
if (ten) ten->directdata = BASACT;
diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c
index 504d9628d98..7b1ec174a6b 100644
--- a/source/blender/editors/space_outliner/space_outliner.c
+++ b/source/blender/editors/space_outliner/space_outliner.c
@@ -41,7 +41,7 @@
#include "BKE_context.h"
#include "BKE_screen.h"
#include "BKE_scene.h"
-#include "BKE_treehash.h"
+#include "BKE_outliner_treehash.h"
#include "ED_space_api.h"
#include "ED_screen.h"
@@ -98,10 +98,10 @@ static int outliner_parent_drop_poll(bContext *C, wmDrag *drag, const wmEvent *e
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
if (drag->type == WM_DRAG_ID) {
- ID *id = (ID *)drag->poin;
+ ID *id = drag->poin;
if (GS(id->name) == ID_OB) {
/* Ensure item under cursor is valid drop target */
- TreeElement *te = outliner_dropzone_find(soops, fmval, 1);
+ TreeElement *te = outliner_dropzone_find(soops, fmval, true);
if (te && te->idcode == ID_OB && TREESTORE(te)->type == 0) {
Scene *scene;
@@ -129,7 +129,7 @@ static int outliner_parent_drop_poll(bContext *C, wmDrag *drag, const wmEvent *e
static void outliner_parent_drop_copy(wmDrag *drag, wmDropBox *drop)
{
- ID *id = (ID *)drag->poin;
+ ID *id = drag->poin;
RNA_string_set(drop->ptr, "child", id->name + 2);
}
@@ -148,10 +148,10 @@ static int outliner_parent_clear_poll(bContext *C, wmDrag *drag, const wmEvent *
}
if (drag->type == WM_DRAG_ID) {
- ID *id = (ID *)drag->poin;
+ ID *id = drag->poin;
if (GS(id->name) == ID_OB) {
if (((Object *)id)->parent) {
- if ((te = outliner_dropzone_find(soops, fmval, 1))) {
+ if ((te = outliner_dropzone_find(soops, fmval, true))) {
TreeStoreElem *tselem = TREESTORE(te);
switch (te->idcode) {
@@ -171,7 +171,7 @@ static int outliner_parent_clear_poll(bContext *C, wmDrag *drag, const wmEvent *
static void outliner_parent_clear_copy(wmDrag *drag, wmDropBox *drop)
{
- ID *id = (ID *)drag->poin;
+ ID *id = drag->poin;
RNA_string_set(drop->ptr, "dragged_obj", id->name + 2);
/* Set to simple parent clear type. Avoid menus for drag and drop if possible.
@@ -188,10 +188,10 @@ static int outliner_scene_drop_poll(bContext *C, wmDrag *drag, const wmEvent *ev
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
if (drag->type == WM_DRAG_ID) {
- ID *id = (ID *)drag->poin;
+ ID *id = drag->poin;
if (GS(id->name) == ID_OB) {
/* Ensure item under cursor is valid drop target */
- TreeElement *te = outliner_dropzone_find(soops, fmval, 0);
+ TreeElement *te = outliner_dropzone_find(soops, fmval, false);
return (te && te->idcode == ID_SCE && TREESTORE(te)->type == 0);
}
}
@@ -200,7 +200,7 @@ static int outliner_scene_drop_poll(bContext *C, wmDrag *drag, const wmEvent *ev
static void outliner_scene_drop_copy(wmDrag *drag, wmDropBox *drop)
{
- ID *id = (ID *)drag->poin;
+ ID *id = drag->poin;
RNA_string_set(drop->ptr, "object", id->name + 2);
}
@@ -213,10 +213,10 @@ static int outliner_material_drop_poll(bContext *C, wmDrag *drag, const wmEvent
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
if (drag->type == WM_DRAG_ID) {
- ID *id = (ID *)drag->poin;
+ ID *id = drag->poin;
if (GS(id->name) == ID_MA) {
/* Ensure item under cursor is valid drop target */
- TreeElement *te = outliner_dropzone_find(soops, fmval, 1);
+ TreeElement *te = outliner_dropzone_find(soops, fmval, true);
return (te && te->idcode == ID_OB && TREESTORE(te)->type == 0);
}
}
@@ -225,11 +225,35 @@ static int outliner_material_drop_poll(bContext *C, wmDrag *drag, const wmEvent
static void outliner_material_drop_copy(wmDrag *drag, wmDropBox *drop)
{
- ID *id = (ID *)drag->poin;
+ ID *id = drag->poin;
RNA_string_set(drop->ptr, "material", id->name + 2);
}
+static int outliner_group_link_poll(bContext *C, wmDrag *drag, const wmEvent *event)
+{
+ ARegion *ar = CTX_wm_region(C);
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+ float fmval[2];
+ UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
+
+ if (drag->type == WM_DRAG_ID) {
+ ID *id = drag->poin;
+ if (GS(id->name) == ID_OB) {
+ /* Ensure item under cursor is valid drop target */
+ TreeElement *te = outliner_dropzone_find(soops, fmval, true);
+ return (te && te->idcode == ID_GR && TREESTORE(te)->type == 0);
+ }
+ }
+ return 0;
+}
+
+static void outliner_group_link_copy(wmDrag *drag, wmDropBox *drop)
+{
+ ID *id = drag->poin;
+ RNA_string_set(drop->ptr, "object", id->name + 2);
+}
+
/* region dropbox definition */
static void outliner_dropboxes(void)
{
@@ -239,6 +263,7 @@ static void outliner_dropboxes(void)
WM_dropbox_add(lb, "OUTLINER_OT_parent_clear", outliner_parent_clear_poll, outliner_parent_clear_copy);
WM_dropbox_add(lb, "OUTLINER_OT_scene_drop", outliner_scene_drop_poll, outliner_scene_drop_copy);
WM_dropbox_add(lb, "OUTLINER_OT_material_drop", outliner_material_drop_poll, outliner_material_drop_copy);
+ WM_dropbox_add(lb, "OUTLINER_OT_group_link", outliner_group_link_poll, outliner_group_link_copy);
}
static void outliner_main_area_draw(const bContext *C, ARegion *ar)
@@ -362,6 +387,10 @@ static void outliner_main_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa)
break;
}
break;
+ case NC_GPENCIL:
+ if (ELEM(wmn->action, NA_EDITED, NA_SELECTED))
+ ED_region_tag_redraw(ar);
+ break;
}
}
@@ -435,7 +464,7 @@ static void outliner_free(SpaceLink *sl)
BLI_mempool_destroy(soutliner->treestore);
}
if (soutliner->treehash) {
- BKE_treehash_free(soutliner->treehash);
+ BKE_outliner_treehash_free(soutliner->treehash);
}
}