diff options
Diffstat (limited to 'source/blender/editors/space_outliner')
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); } } |