2011-07-11 10:59:53 +00:00
|
|
|
/*
|
|
|
|
* ***** BEGIN GPL LICENSE BLOCK *****
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*
|
|
|
|
* The Original Code is Copyright (C) 2004 Blender Foundation.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* The Original Code is: all of this file.
|
|
|
|
*
|
|
|
|
* Contributor(s): Joshua Leung
|
|
|
|
*
|
|
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
|
|
*/
|
|
|
|
|
|
|
|
/** \file blender/editors/space_outliner/outliner_edit.c
|
|
|
|
* \ingroup spoutliner
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
|
|
|
|
#include "DNA_anim_types.h"
|
|
|
|
#include "DNA_group_types.h"
|
|
|
|
#include "DNA_scene_types.h"
|
|
|
|
#include "DNA_object_types.h"
|
2012-06-10 22:22:26 +00:00
|
|
|
#include "DNA_material_types.h"
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
#include "BLI_blenlib.h"
|
|
|
|
#include "BLI_utildefines.h"
|
|
|
|
|
Fixed another bunch of i18n bugs (thx to Leon Cheung for spotting them), among which:
* Drag'n'drop translation in Outliner
* "Execute" button in file window
* "Labels" of spacing elements, in multi-column enums
* A glitch with nodes "Value to RGB", they where called "ColorRamp" in node_type_base() call. This is not definitive, though, as it appears that UI node names are determined by this call, while it should be by "defines" in rna_nodetrre_types.h, I guess... Anyway, not good to have such things in two different places!
Also moved default context name under BLF_translation.h, much better to have those all in one place, accessible from whole Blender code!
2012-04-14 15:06:41 +00:00
|
|
|
#include "BLF_translation.h"
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
#include "BKE_animsys.h"
|
|
|
|
#include "BKE_context.h"
|
|
|
|
#include "BKE_depsgraph.h"
|
|
|
|
#include "BKE_library.h"
|
|
|
|
#include "BKE_main.h"
|
|
|
|
#include "BKE_report.h"
|
|
|
|
#include "BKE_scene.h"
|
2012-06-10 22:22:26 +00:00
|
|
|
#include "BKE_material.h"
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
#include "ED_object.h"
|
|
|
|
#include "ED_screen.h"
|
2012-04-26 05:17:54 +00:00
|
|
|
#include "ED_keyframing.h"
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
#include "WM_api.h"
|
|
|
|
#include "WM_types.h"
|
|
|
|
|
|
|
|
#include "UI_interface.h"
|
|
|
|
#include "UI_resources.h"
|
|
|
|
#include "UI_view2d.h"
|
|
|
|
|
|
|
|
#include "RNA_access.h"
|
|
|
|
#include "RNA_define.h"
|
|
|
|
|
|
|
|
#include "outliner_intern.h"
|
|
|
|
|
|
|
|
/* ************************************************************** */
|
|
|
|
/* Unused Utilities */
|
|
|
|
// XXX: where to place these?
|
|
|
|
|
|
|
|
/* 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;
|
2012-05-07 17:56:30 +00:00
|
|
|
int retval = 0;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
for (te = te->parent; te; te = te->parent) {
|
|
|
|
tselem = TREESTORE(te);
|
2012-10-21 05:46:41 +00:00
|
|
|
if (tselem->flag & TSE_CLOSED) {
|
2011-07-11 10:59:53 +00:00
|
|
|
tselem->flag &= ~TSE_CLOSED;
|
2012-05-07 17:56:30 +00:00
|
|
|
retval = 1;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void outliner_open_reveal(SpaceOops *soops, ListBase *lb, TreeElement *teFind, int *found)
|
|
|
|
{
|
|
|
|
TreeElement *te;
|
|
|
|
TreeStoreElem *tselem;
|
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
for (te = lb->first; te; te = te->next) {
|
2011-07-11 10:59:53 +00:00
|
|
|
/* check if this tree-element was the one we're seeking */
|
|
|
|
if (te == teFind) {
|
2012-05-07 17:56:30 +00:00
|
|
|
*found = 1;
|
2011-07-11 10:59:53 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* try to see if sub-tree contains it then */
|
|
|
|
outliner_open_reveal(soops, &te->subtree, teFind, found);
|
|
|
|
if (*found) {
|
2012-05-07 17:56:30 +00:00
|
|
|
tselem = TREESTORE(te);
|
2011-07-11 10:59:53 +00:00
|
|
|
if (tselem->flag & TSE_CLOSED)
|
|
|
|
tselem->flag &= ~TSE_CLOSED;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-04-03 07:42:56 +00:00
|
|
|
static TreeElement *outliner_dropzone_element(const SpaceOops *soops, TreeElement *te, const float fmval[2], const int children)
|
|
|
|
{
|
|
|
|
if ((fmval[1] > te->ys) && (fmval[1] < (te->ys + UI_UNIT_Y))) {
|
|
|
|
/* name and first icon */
|
|
|
|
if ((fmval[0] > te->xs + UI_UNIT_X) && (fmval[0] < te->xend))
|
|
|
|
return te;
|
|
|
|
}
|
|
|
|
/* Not it. Let's look at its children. */
|
|
|
|
if (children && (TREESTORE(te)->flag & TSE_CLOSED) == 0 && (te->subtree.first)) {
|
|
|
|
for (te = te->subtree.first; te; te = te->next) {
|
|
|
|
TreeElement *te_valid = outliner_dropzone_element(soops, te, fmval, children);
|
|
|
|
if (te_valid)
|
|
|
|
return te_valid;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Used for drag and drop parenting */
|
|
|
|
TreeElement *outliner_dropzone_find(const SpaceOops *soops, const float fmval[2], const int children)
|
|
|
|
{
|
|
|
|
TreeElement *te;
|
|
|
|
|
|
|
|
for (te = soops->tree.first; te; te = te->next) {
|
|
|
|
TreeElement *te_valid = outliner_dropzone_element(soops, te, fmval, children);
|
|
|
|
if (te_valid)
|
|
|
|
return te_valid;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2011-07-11 10:59:53 +00:00
|
|
|
/* ************************************************************** */
|
|
|
|
/* Click Activated */
|
|
|
|
|
|
|
|
/* Toggle Open/Closed ------------------------------------------- */
|
|
|
|
|
2014-02-03 18:55:59 +11:00
|
|
|
static int do_outliner_item_openclose(bContext *C, SpaceOops *soops, TreeElement *te, const bool all, const float mval[2])
|
2011-07-11 10:59:53 +00:00
|
|
|
{
|
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) {
|
|
|
|
TreeStoreElem *tselem = TREESTORE(te);
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
/* all below close/open? */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (all) {
|
2011-07-11 10:59:53 +00:00
|
|
|
tselem->flag &= ~TSE_CLOSED;
|
|
|
|
outliner_set_flag(soops, &te->subtree, TSE_CLOSED, !outliner_has_one_flag(soops, &te->subtree, TSE_CLOSED, 1));
|
|
|
|
}
|
|
|
|
else {
|
2012-03-24 06:38:07 +00:00
|
|
|
if (tselem->flag & TSE_CLOSED) tselem->flag &= ~TSE_CLOSED;
|
2011-07-11 10:59:53 +00:00
|
|
|
else tselem->flag |= TSE_CLOSED;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
for (te = te->subtree.first; te; te = te->next) {
|
2012-03-24 06:38:07 +00:00
|
|
|
if (do_outliner_item_openclose(C, soops, te, all, mval))
|
2011-07-11 10:59:53 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/* event can enterkey, then it opens/closes */
|
2013-03-13 09:03:46 +00:00
|
|
|
static int outliner_item_openclose(bContext *C, wmOperator *op, const wmEvent *event)
|
2011-07-11 10:59:53 +00:00
|
|
|
{
|
2012-05-07 17:56:30 +00:00
|
|
|
ARegion *ar = CTX_wm_region(C);
|
|
|
|
SpaceOops *soops = CTX_wm_space_outliner(C);
|
2011-07-11 10:59:53 +00:00
|
|
|
TreeElement *te;
|
|
|
|
float fmval[2];
|
2014-02-03 18:55:59 +11:00
|
|
|
const bool all = RNA_boolean_get(op->ptr, "all");
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2014-04-21 16:47:16 +10:00
|
|
|
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
for (te = soops->tree.first; te; te = te->next) {
|
2012-03-24 06:38:07 +00:00
|
|
|
if (do_outliner_item_openclose(C, soops, te, all, fmval))
|
2011-07-11 10:59:53 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
ED_region_tag_redraw(ar);
|
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void OUTLINER_OT_item_openclose(wmOperatorType *ot)
|
|
|
|
{
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "Open/Close Item";
|
|
|
|
ot->idname = "OUTLINER_OT_item_openclose";
|
|
|
|
ot->description = "Toggle whether item under cursor is enabled or closed";
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->invoke = outliner_item_openclose;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->poll = ED_operator_outliner_active;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2011-09-19 12:26:20 +00:00
|
|
|
RNA_def_boolean(ot->srna, "all", 1, "All", "Close or open all items");
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Rename --------------------------------------------------- */
|
|
|
|
|
2011-09-16 08:20:21 +00:00
|
|
|
static void do_item_rename(ARegion *ar, TreeElement *te, TreeStoreElem *tselem, ReportList *reports)
|
2011-09-02 08:35:46 +00:00
|
|
|
{
|
2012-12-22 16:49:50 +00:00
|
|
|
/* can't rename rna datablocks entries or listbases */
|
2014-07-20 01:30:29 +10:00
|
|
|
if (ELEM(tselem->type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM, TSE_ID_BASE)) {
|
2012-05-07 17:56:30 +00:00
|
|
|
/* do nothing */;
|
2011-12-22 00:03:20 +00:00
|
|
|
}
|
2014-07-20 01:30:29 +10:00
|
|
|
else if (ELEM(tselem->type, TSE_ANIM_DATA, TSE_NLA, TSE_DEFGROUP_BASE, TSE_CONSTRAINT_BASE, TSE_MODIFIER_BASE,
|
|
|
|
TSE_DRIVER_BASE, TSE_POSE_BASE, TSE_POSEGRP_BASE, TSE_R_LAYER_BASE, TSE_R_PASS))
|
2011-12-22 00:03:20 +00:00
|
|
|
{
|
2012-05-07 17:56:30 +00:00
|
|
|
BKE_report(reports, RPT_WARNING, "Cannot edit builtin name");
|
2011-12-22 00:03:20 +00:00
|
|
|
}
|
2014-07-20 01:30:29 +10:00
|
|
|
else if (ELEM(tselem->type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP)) {
|
2011-09-02 08:35:46 +00:00
|
|
|
BKE_report(reports, RPT_WARNING, "Cannot edit sequence name");
|
2011-12-22 00:03:20 +00:00
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
else if (tselem->id->lib) {
|
2013-09-12 22:08:56 +00:00
|
|
|
BKE_report(reports, RPT_WARNING, "Cannot edit external libdata");
|
2012-10-21 05:46:41 +00:00
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
else if (te->idcode == ID_LI && te->parent) {
|
2011-09-02 08:35:46 +00:00
|
|
|
BKE_report(reports, RPT_WARNING, "Cannot edit the path of an indirectly linked library");
|
2012-10-21 05:46:41 +00:00
|
|
|
}
|
2011-09-02 08:35:46 +00:00
|
|
|
else {
|
|
|
|
tselem->flag |= TSE_TEXTBUT;
|
|
|
|
ED_region_tag_redraw(ar);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-31 18:40:06 +00:00
|
|
|
void item_rename_cb(bContext *C, Scene *UNUSED(scene), TreeElement *te,
|
|
|
|
TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem)
|
2011-09-02 08:35:46 +00:00
|
|
|
{
|
2012-05-07 17:56:30 +00:00
|
|
|
ARegion *ar = CTX_wm_region(C);
|
|
|
|
ReportList *reports = CTX_wm_reports(C); // XXX
|
2012-02-27 10:35:39 +00:00
|
|
|
do_item_rename(ar, te, tselem, reports);
|
2011-09-02 08:35:46 +00:00
|
|
|
}
|
|
|
|
|
2011-07-11 10:59:53 +00:00
|
|
|
static int do_outliner_item_rename(bContext *C, ARegion *ar, SpaceOops *soops, TreeElement *te, const float mval[2])
|
|
|
|
{
|
2012-05-07 17:56:30 +00:00
|
|
|
ReportList *reports = CTX_wm_reports(C); // XXX
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) {
|
|
|
|
TreeStoreElem *tselem = TREESTORE(te);
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2013-03-09 13:13:04 +00:00
|
|
|
/* click on name */
|
|
|
|
if (mval[0] > te->xs + UI_UNIT_X * 2 && mval[0] < te->xend) {
|
2012-02-27 10:35:39 +00:00
|
|
|
do_item_rename(ar, te, tselem, reports);
|
2013-03-09 13:13:04 +00:00
|
|
|
return 1;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
2013-03-09 13:13:04 +00:00
|
|
|
return 0;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
for (te = te->subtree.first; te; te = te->next) {
|
2012-03-24 06:38:07 +00:00
|
|
|
if (do_outliner_item_rename(C, ar, soops, te, mval)) return 1;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-03-13 09:03:46 +00:00
|
|
|
static int outliner_item_rename(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
|
2011-07-11 10:59:53 +00:00
|
|
|
{
|
2012-05-07 17:56:30 +00:00
|
|
|
ARegion *ar = CTX_wm_region(C);
|
|
|
|
SpaceOops *soops = CTX_wm_space_outliner(C);
|
2011-07-11 10:59:53 +00:00
|
|
|
TreeElement *te;
|
|
|
|
float fmval[2];
|
2013-11-26 06:39:14 +11:00
|
|
|
bool changed = false;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2014-04-21 16:47:16 +10:00
|
|
|
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
for (te = soops->tree.first; te; te = te->next) {
|
2013-03-09 13:13:04 +00:00
|
|
|
if (do_outliner_item_rename(C, ar, soops, te, fmval)) {
|
2013-11-26 06:39:14 +11:00
|
|
|
changed = true;
|
2013-03-09 13:13:04 +00:00
|
|
|
break;
|
|
|
|
}
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
|
2013-11-26 06:39:14 +11:00
|
|
|
return changed ? OPERATOR_FINISHED : OPERATOR_PASS_THROUGH;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void OUTLINER_OT_item_rename(wmOperatorType *ot)
|
|
|
|
{
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "Rename Item";
|
|
|
|
ot->idname = "OUTLINER_OT_item_rename";
|
|
|
|
ot->description = "Rename item under cursor";
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->invoke = outliner_item_rename;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->poll = ED_operator_outliner_active;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ************************************************************** */
|
|
|
|
/* Setting Toggling Operators */
|
|
|
|
|
|
|
|
/* =============================================== */
|
|
|
|
/* Toggling Utilities (Exported) */
|
|
|
|
|
|
|
|
/* Apply Settings ------------------------------- */
|
|
|
|
|
2014-01-16 19:15:53 +11:00
|
|
|
static int outliner_count_levels(SpaceOops *soops, ListBase *lb, const int curlevel)
|
2011-07-11 10:59:53 +00:00
|
|
|
{
|
|
|
|
TreeElement *te;
|
2012-05-07 17:56:30 +00:00
|
|
|
int level = curlevel, lev;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
for (te = lb->first; te; te = te->next) {
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
lev = outliner_count_levels(soops, &te->subtree, curlevel + 1);
|
|
|
|
if (lev > level) level = lev;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
return level;
|
|
|
|
}
|
|
|
|
|
2014-01-16 20:52:30 +11:00
|
|
|
int outliner_has_one_flag(SpaceOops *soops, ListBase *lb, short flag, const int curlevel)
|
2011-07-11 10:59:53 +00:00
|
|
|
{
|
|
|
|
TreeElement *te;
|
|
|
|
TreeStoreElem *tselem;
|
|
|
|
int level;
|
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
for (te = lb->first; te; te = te->next) {
|
|
|
|
tselem = TREESTORE(te);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (tselem->flag & flag) return curlevel;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
level = outliner_has_one_flag(soops, &te->subtree, flag, curlevel + 1);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (level) return level;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void outliner_set_flag(SpaceOops *soops, ListBase *lb, short flag, short set)
|
|
|
|
{
|
|
|
|
TreeElement *te;
|
|
|
|
TreeStoreElem *tselem;
|
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
for (te = lb->first; te; te = te->next) {
|
|
|
|
tselem = TREESTORE(te);
|
|
|
|
if (set == 0) tselem->flag &= ~flag;
|
2011-07-11 10:59:53 +00:00
|
|
|
else tselem->flag |= flag;
|
|
|
|
outliner_set_flag(soops, &te->subtree, flag, set);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Restriction Columns ------------------------------- */
|
|
|
|
|
|
|
|
/* same check needed for both object operation and restrict column button func
|
|
|
|
* return 0 when in edit mode (cannot restrict view or select)
|
|
|
|
* otherwise return 1 */
|
|
|
|
int common_restrict_check(bContext *C, Object *ob)
|
|
|
|
{
|
|
|
|
/* Don't allow hide an object in edit mode,
|
|
|
|
* check the bug #22153 and #21609, #23977
|
|
|
|
*/
|
2012-05-07 17:56:30 +00:00
|
|
|
Object *obedit = CTX_data_edit_object(C);
|
2011-07-11 10:59:53 +00:00
|
|
|
if (obedit && obedit == ob) {
|
|
|
|
/* found object is hidden, reset */
|
|
|
|
if (ob->restrictflag & OB_RESTRICT_VIEW)
|
|
|
|
ob->restrictflag &= ~OB_RESTRICT_VIEW;
|
|
|
|
/* found object is unselectable, reset */
|
|
|
|
if (ob->restrictflag & OB_RESTRICT_SELECT)
|
|
|
|
ob->restrictflag &= ~OB_RESTRICT_SELECT;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* =============================================== */
|
|
|
|
/* Restriction toggles */
|
|
|
|
|
|
|
|
/* Toggle Visibility ---------------------------------------- */
|
|
|
|
|
2012-05-31 18:40:06 +00:00
|
|
|
void object_toggle_visibility_cb(bContext *C, Scene *scene, TreeElement *te,
|
|
|
|
TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem)
|
2011-07-11 10:59:53 +00:00
|
|
|
{
|
2012-05-07 17:56:30 +00:00
|
|
|
Base *base = (Base *)te->directdata;
|
2011-07-11 10:59:53 +00:00
|
|
|
Object *ob = (Object *)tselem->id;
|
|
|
|
|
|
|
|
/* add check for edit mode */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (!common_restrict_check(C, ob)) return;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
if (base || (base = BKE_scene_base_find(scene, ob))) {
|
2012-03-24 06:38:07 +00:00
|
|
|
if ((base->object->restrictflag ^= OB_RESTRICT_VIEW)) {
|
2011-07-11 10:59:53 +00:00
|
|
|
ED_base_object_select(base, BA_DESELECT);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-31 18:40:06 +00:00
|
|
|
void group_toggle_visibility_cb(bContext *UNUSED(C), Scene *scene, TreeElement *UNUSED(te),
|
|
|
|
TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem)
|
2011-09-02 08:35:46 +00:00
|
|
|
{
|
2012-05-07 17:56:30 +00:00
|
|
|
Group *group = (Group *)tselem->id;
|
2011-09-02 08:35:46 +00:00
|
|
|
restrictbutton_gr_restrict_flag(scene, group, OB_RESTRICT_VIEW);
|
|
|
|
}
|
|
|
|
|
2011-07-11 10:59:53 +00:00
|
|
|
static int outliner_toggle_visibility_exec(bContext *C, wmOperator *UNUSED(op))
|
|
|
|
{
|
2012-10-18 11:58:54 +00:00
|
|
|
Main *bmain = CTX_data_main(C);
|
2012-05-07 17:56:30 +00:00
|
|
|
SpaceOops *soops = CTX_wm_space_outliner(C);
|
|
|
|
Scene *scene = CTX_data_scene(C);
|
|
|
|
ARegion *ar = CTX_wm_region(C);
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
outliner_do_object_operation(C, scene, soops, &soops->tree, object_toggle_visibility_cb);
|
|
|
|
|
2012-10-18 11:58:54 +00:00
|
|
|
DAG_id_type_tag(bmain, ID_OB);
|
2012-05-07 17:56:30 +00:00
|
|
|
WM_event_add_notifier(C, NC_SCENE | ND_OB_VISIBLE, scene);
|
2011-07-11 10:59:53 +00:00
|
|
|
ED_region_tag_redraw(ar);
|
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void OUTLINER_OT_visibility_toggle(wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
/* identifiers */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "Toggle Visibility";
|
|
|
|
ot->idname = "OUTLINER_OT_visibility_toggle";
|
|
|
|
ot->description = "Toggle the visibility of selected items";
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
/* callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->exec = outliner_toggle_visibility_exec;
|
|
|
|
ot->poll = ED_operator_outliner_active_no_editobject;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Toggle Selectability ---------------------------------------- */
|
|
|
|
|
2012-05-31 18:40:06 +00:00
|
|
|
void object_toggle_selectability_cb(bContext *UNUSED(C), Scene *scene, TreeElement *te,
|
|
|
|
TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem)
|
2011-07-11 10:59:53 +00:00
|
|
|
{
|
2012-05-07 17:56:30 +00:00
|
|
|
Base *base = (Base *)te->directdata;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
if (base == NULL) base = BKE_scene_base_find(scene, (Object *)tselem->id);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (base) {
|
2012-05-07 17:56:30 +00:00
|
|
|
base->object->restrictflag ^= OB_RESTRICT_SELECT;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-31 18:40:06 +00:00
|
|
|
void group_toggle_selectability_cb(bContext *UNUSED(C), Scene *scene, TreeElement *UNUSED(te),
|
|
|
|
TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem)
|
2011-09-02 08:35:46 +00:00
|
|
|
{
|
2012-05-07 17:56:30 +00:00
|
|
|
Group *group = (Group *)tselem->id;
|
2011-09-02 08:35:46 +00:00
|
|
|
restrictbutton_gr_restrict_flag(scene, group, OB_RESTRICT_SELECT);
|
|
|
|
}
|
|
|
|
|
2011-07-11 10:59:53 +00:00
|
|
|
static int outliner_toggle_selectability_exec(bContext *C, wmOperator *UNUSED(op))
|
|
|
|
{
|
2012-05-07 17:56:30 +00:00
|
|
|
SpaceOops *soops = CTX_wm_space_outliner(C);
|
|
|
|
Scene *scene = CTX_data_scene(C);
|
|
|
|
ARegion *ar = CTX_wm_region(C);
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
outliner_do_object_operation(C, scene, soops, &soops->tree, object_toggle_selectability_cb);
|
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
|
2011-07-11 10:59:53 +00:00
|
|
|
ED_region_tag_redraw(ar);
|
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void OUTLINER_OT_selectability_toggle(wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
/* identifiers */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "Toggle Selectability";
|
|
|
|
ot->idname = "OUTLINER_OT_selectability_toggle";
|
|
|
|
ot->description = "Toggle the selectability";
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
/* callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->exec = outliner_toggle_selectability_exec;
|
|
|
|
ot->poll = ED_operator_outliner_active_no_editobject;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Toggle Renderability ---------------------------------------- */
|
|
|
|
|
2012-05-31 18:40:06 +00:00
|
|
|
void object_toggle_renderability_cb(bContext *UNUSED(C), Scene *scene, TreeElement *te,
|
|
|
|
TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem)
|
2011-07-11 10:59:53 +00:00
|
|
|
{
|
2012-05-07 17:56:30 +00:00
|
|
|
Base *base = (Base *)te->directdata;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
if (base == NULL) base = BKE_scene_base_find(scene, (Object *)tselem->id);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (base) {
|
2012-05-07 17:56:30 +00:00
|
|
|
base->object->restrictflag ^= OB_RESTRICT_RENDER;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-31 18:40:06 +00:00
|
|
|
void group_toggle_renderability_cb(bContext *UNUSED(C), Scene *scene, TreeElement *UNUSED(te),
|
|
|
|
TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem)
|
2011-09-02 08:35:46 +00:00
|
|
|
{
|
2012-05-07 17:56:30 +00:00
|
|
|
Group *group = (Group *)tselem->id;
|
2011-09-02 08:35:46 +00:00
|
|
|
restrictbutton_gr_restrict_flag(scene, group, OB_RESTRICT_RENDER);
|
|
|
|
}
|
|
|
|
|
2011-07-11 10:59:53 +00:00
|
|
|
static int outliner_toggle_renderability_exec(bContext *C, wmOperator *UNUSED(op))
|
|
|
|
{
|
2012-10-18 11:58:54 +00:00
|
|
|
Main *bmain = CTX_data_main(C);
|
2012-05-07 17:56:30 +00:00
|
|
|
SpaceOops *soops = CTX_wm_space_outliner(C);
|
|
|
|
Scene *scene = CTX_data_scene(C);
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
outliner_do_object_operation(C, scene, soops, &soops->tree, object_toggle_renderability_cb);
|
|
|
|
|
2012-10-18 11:58:54 +00:00
|
|
|
DAG_id_type_tag(bmain, ID_OB);
|
2012-05-07 17:56:30 +00:00
|
|
|
WM_event_add_notifier(C, NC_SCENE | ND_OB_RENDER, scene);
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void OUTLINER_OT_renderability_toggle(wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
/* identifiers */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "Toggle Renderability";
|
|
|
|
ot->idname = "OUTLINER_OT_renderability_toggle";
|
|
|
|
ot->description = "Toggle the renderability of selected items";
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
/* callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->exec = outliner_toggle_renderability_exec;
|
|
|
|
ot->poll = ED_operator_outliner_active;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* =============================================== */
|
|
|
|
/* Outliner setting toggles */
|
|
|
|
|
|
|
|
/* Toggle Expanded (Outliner) ---------------------------------------- */
|
|
|
|
|
|
|
|
static int outliner_toggle_expanded_exec(bContext *C, wmOperator *UNUSED(op))
|
|
|
|
{
|
2012-05-07 17:56:30 +00:00
|
|
|
SpaceOops *soops = CTX_wm_space_outliner(C);
|
|
|
|
ARegion *ar = CTX_wm_region(C);
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
if (outliner_has_one_flag(soops, &soops->tree, TSE_CLOSED, 1))
|
|
|
|
outliner_set_flag(soops, &soops->tree, TSE_CLOSED, 0);
|
|
|
|
else
|
|
|
|
outliner_set_flag(soops, &soops->tree, TSE_CLOSED, 1);
|
|
|
|
|
|
|
|
ED_region_tag_redraw(ar);
|
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void OUTLINER_OT_expanded_toggle(wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
/* identifiers */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "Expand/Collapse All";
|
|
|
|
ot->idname = "OUTLINER_OT_expanded_toggle";
|
|
|
|
ot->description = "Expand/Collapse all items";
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
/* callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->exec = outliner_toggle_expanded_exec;
|
|
|
|
ot->poll = ED_operator_outliner_active;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
/* no undo or registry, UI option */
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Toggle Selected (Outliner) ---------------------------------------- */
|
|
|
|
|
|
|
|
static int outliner_toggle_selected_exec(bContext *C, wmOperator *UNUSED(op))
|
|
|
|
{
|
2012-05-07 17:56:30 +00:00
|
|
|
SpaceOops *soops = CTX_wm_space_outliner(C);
|
|
|
|
ARegion *ar = CTX_wm_region(C);
|
|
|
|
Scene *scene = CTX_data_scene(C);
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
if (outliner_has_one_flag(soops, &soops->tree, TSE_SELECTED, 1))
|
|
|
|
outliner_set_flag(soops, &soops->tree, TSE_SELECTED, 0);
|
|
|
|
else
|
|
|
|
outliner_set_flag(soops, &soops->tree, TSE_SELECTED, 1);
|
|
|
|
|
|
|
|
soops->storeflag |= SO_TREESTORE_REDRAW;
|
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
|
2011-07-11 10:59:53 +00:00
|
|
|
ED_region_tag_redraw(ar);
|
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void OUTLINER_OT_selected_toggle(wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
/* identifiers */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "Toggle Selected";
|
|
|
|
ot->idname = "OUTLINER_OT_selected_toggle";
|
|
|
|
ot->description = "Toggle the Outliner selection of items";
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
/* callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->exec = outliner_toggle_selected_exec;
|
|
|
|
ot->poll = ED_operator_outliner_active;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
/* no undo or registry, UI option */
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ************************************************************** */
|
|
|
|
/* Hotkey Only Operators */
|
|
|
|
|
|
|
|
/* Show Active --------------------------------------------------- */
|
|
|
|
|
|
|
|
static int outliner_show_active_exec(bContext *C, wmOperator *UNUSED(op))
|
|
|
|
{
|
2012-05-07 17:56:30 +00:00
|
|
|
SpaceOops *so = CTX_wm_space_outliner(C);
|
|
|
|
Scene *scene = CTX_data_scene(C);
|
|
|
|
ARegion *ar = CTX_wm_region(C);
|
|
|
|
View2D *v2d = &ar->v2d;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
TreeElement *te;
|
|
|
|
int xdelta, ytop;
|
|
|
|
|
|
|
|
// TODO: make this get this info from context instead...
|
|
|
|
if (OBACT == NULL)
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
te = outliner_find_id(so, &so->tree, (ID *)OBACT);
|
2011-07-11 10:59:53 +00:00
|
|
|
if (te) {
|
|
|
|
/* make te->ys center of view */
|
2013-07-30 08:45:45 +00:00
|
|
|
ytop = te->ys + BLI_rcti_size_y(&v2d->mask) / 2;
|
2012-05-07 17:56:30 +00:00
|
|
|
if (ytop > 0) ytop = 0;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-03-24 02:51:46 +00:00
|
|
|
v2d->cur.ymax = (float)ytop;
|
2012-09-15 11:48:20 +00:00
|
|
|
v2d->cur.ymin = (float)(ytop - BLI_rcti_size_y(&v2d->mask));
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
/* make te->xs ==> te->xend center of view */
|
|
|
|
xdelta = (int)(te->xs - v2d->cur.xmin);
|
|
|
|
v2d->cur.xmin += xdelta;
|
|
|
|
v2d->cur.xmax += xdelta;
|
|
|
|
|
|
|
|
so->storeflag |= SO_TREESTORE_REDRAW;
|
|
|
|
}
|
|
|
|
|
|
|
|
ED_region_tag_redraw(ar);
|
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void OUTLINER_OT_show_active(wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
/* identifiers */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "Show Active";
|
|
|
|
ot->idname = "OUTLINER_OT_show_active";
|
|
|
|
ot->description = "Adjust the view so that the active Object is shown centered";
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
/* callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->exec = outliner_show_active_exec;
|
|
|
|
ot->poll = ED_operator_outliner_active;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* View Panning --------------------------------------------------- */
|
|
|
|
|
|
|
|
static int outliner_scroll_page_exec(bContext *C, wmOperator *op)
|
|
|
|
{
|
2012-05-07 17:56:30 +00:00
|
|
|
ARegion *ar = CTX_wm_region(C);
|
2012-09-15 11:48:20 +00:00
|
|
|
int dy = BLI_rcti_size_y(&ar->v2d.mask);
|
2012-05-07 17:56:30 +00:00
|
|
|
int up = 0;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (RNA_boolean_get(op->ptr, "up"))
|
2012-05-07 17:56:30 +00:00
|
|
|
up = 1;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
if (up == 0) dy = -dy;
|
|
|
|
ar->v2d.cur.ymin += dy;
|
|
|
|
ar->v2d.cur.ymax += dy;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
ED_region_tag_redraw(ar);
|
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void OUTLINER_OT_scroll_page(wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
/* identifiers */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "Scroll Page";
|
|
|
|
ot->idname = "OUTLINER_OT_scroll_page";
|
|
|
|
ot->description = "Scroll page up or down";
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
/* callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->exec = outliner_scroll_page_exec;
|
|
|
|
ot->poll = ED_operator_outliner_active;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
/* properties */
|
2011-09-19 12:26:20 +00:00
|
|
|
RNA_def_boolean(ot->srna, "up", 0, "Up", "Scroll up one page");
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Search ------------------------------------------------------- */
|
|
|
|
// TODO: probably obsolete now with filtering?
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
|
|
|
/* recursive helper for function below */
|
|
|
|
static void outliner_set_coordinates_element(SpaceOops *soops, TreeElement *te, int startx, int *starty)
|
|
|
|
{
|
2012-05-07 17:56:30 +00:00
|
|
|
TreeStoreElem *tselem = TREESTORE(te);
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
/* store coord and continue, we need coordinates for elements outside view too */
|
2012-05-07 17:56:30 +00:00
|
|
|
te->xs = (float)startx;
|
|
|
|
te->ys = (float)(*starty);
|
|
|
|
*starty -= UI_UNIT_Y;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-04-29 15:47:02 +00:00
|
|
|
if (TSELEM_OPEN(tselem, soops)) {
|
2011-07-11 10:59:53 +00:00
|
|
|
TreeElement *ten;
|
2012-05-07 17:56:30 +00:00
|
|
|
for (ten = te->subtree.first; ten; ten = ten->next) {
|
|
|
|
outliner_set_coordinates_element(soops, ten, startx + UI_UNIT_X, starty);
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/* to retrieve coordinates with redrawing the entire tree */
|
|
|
|
static void outliner_set_coordinates(ARegion *ar, SpaceOops *soops)
|
|
|
|
{
|
|
|
|
TreeElement *te;
|
2012-05-07 17:56:30 +00:00
|
|
|
int starty = (int)(ar->v2d.tot.ymax) - UI_UNIT_Y;
|
|
|
|
int startx = 0;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
for (te = soops->tree.first; te; te = te->next) {
|
2011-07-11 10:59:53 +00:00
|
|
|
outliner_set_coordinates_element(soops, te, startx, &starty);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* find next element that has this name */
|
2012-05-31 18:40:06 +00:00
|
|
|
static TreeElement *outliner_find_name(SpaceOops *soops, ListBase *lb, char *name, int flags,
|
|
|
|
TreeElement *prev, int *prevFound)
|
2011-07-11 10:59:53 +00:00
|
|
|
{
|
|
|
|
TreeElement *te, *tes;
|
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
for (te = lb->first; te; te = te->next) {
|
2011-07-11 10:59:53 +00:00
|
|
|
int found = outliner_filter_has_name(te, name, flags);
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (found) {
|
2011-07-11 10:59:53 +00:00
|
|
|
/* name is right, but is element the previous one? */
|
|
|
|
if (prev) {
|
|
|
|
if ((te != prev) && (*prevFound))
|
|
|
|
return te;
|
|
|
|
if (te == prev) {
|
|
|
|
*prevFound = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return te;
|
|
|
|
}
|
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
tes = outliner_find_name(soops, &te->subtree, name, flags, prev, prevFound);
|
2012-03-24 06:38:07 +00:00
|
|
|
if (tes) return tes;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* nothing valid found */
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void outliner_find_panel(Scene *UNUSED(scene), ARegion *ar, SpaceOops *soops, int again, int flags)
|
|
|
|
{
|
|
|
|
ReportList *reports = NULL; // CTX_wm_reports(C);
|
2012-05-07 17:56:30 +00:00
|
|
|
TreeElement *te = NULL;
|
2011-07-11 10:59:53 +00:00
|
|
|
TreeElement *last_find;
|
|
|
|
TreeStoreElem *tselem;
|
2012-05-07 17:56:30 +00:00
|
|
|
int ytop, xdelta, prevFound = 0;
|
2012-01-11 12:33:51 +00:00
|
|
|
char name[sizeof(soops->search_string)];
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
/* get last found tree-element based on stored search_tse */
|
2012-05-07 17:56:30 +00:00
|
|
|
last_find = outliner_find_tse(soops, &soops->search_tse);
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
/* determine which type of search to do */
|
|
|
|
if (again && last_find) {
|
2012-10-21 05:46:41 +00:00
|
|
|
/* no popup panel - previous + user wanted to search for next after previous */
|
2011-07-11 10:59:53 +00:00
|
|
|
BLI_strncpy(name, soops->search_string, sizeof(name));
|
2012-05-07 17:56:30 +00:00
|
|
|
flags = soops->search_flags;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
/* try to find matching element */
|
2012-05-07 17:56:30 +00:00
|
|
|
te = outliner_find_name(soops, &soops->tree, name, flags, last_find, &prevFound);
|
|
|
|
if (te == NULL) {
|
2011-07-11 10:59:53 +00:00
|
|
|
/* no more matches after previous, start from beginning again */
|
2012-05-07 17:56:30 +00:00
|
|
|
prevFound = 1;
|
|
|
|
te = outliner_find_name(soops, &soops->tree, name, flags, last_find, &prevFound);
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* pop up panel - no previous, or user didn't want search after previous */
|
2012-05-07 17:56:30 +00:00
|
|
|
name[0] = '\0';
|
2011-07-11 10:59:53 +00:00
|
|
|
// XXX if (sbutton(name, 0, sizeof(name)-1, "Find: ") && name[0]) {
|
2012-10-26 04:14:10 +00:00
|
|
|
// te = outliner_find_name(soops, &soops->tree, name, flags, NULL, &prevFound);
|
2011-07-11 10:59:53 +00:00
|
|
|
// }
|
|
|
|
// else return; /* XXX RETURN! XXX */
|
|
|
|
}
|
|
|
|
|
|
|
|
/* do selection and reveal */
|
|
|
|
if (te) {
|
2012-05-07 17:56:30 +00:00
|
|
|
tselem = TREESTORE(te);
|
2011-07-11 10:59:53 +00:00
|
|
|
if (tselem) {
|
|
|
|
/* expand branches so that it will be visible, we need to get correct coordinates */
|
2012-05-07 17:56:30 +00:00
|
|
|
if (outliner_open_back(soops, te))
|
2011-07-11 10:59:53 +00:00
|
|
|
outliner_set_coordinates(ar, soops);
|
|
|
|
|
|
|
|
/* deselect all visible, and select found element */
|
|
|
|
outliner_set_flag(soops, &soops->tree, TSE_SELECTED, 0);
|
|
|
|
tselem->flag |= TSE_SELECTED;
|
|
|
|
|
|
|
|
/* make te->ys center of view */
|
2012-09-15 11:48:20 +00:00
|
|
|
ytop = (int)(te->ys + BLI_rctf_size_y(&ar->v2d.mask) / 2);
|
2012-05-07 17:56:30 +00:00
|
|
|
if (ytop > 0) ytop = 0;
|
2012-03-24 02:51:46 +00:00
|
|
|
ar->v2d.cur.ymax = (float)ytop;
|
2012-09-15 11:48:20 +00:00
|
|
|
ar->v2d.cur.ymin = (float)(ytop - BLI_rctf_size_y(&ar->v2d.mask));
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
/* make te->xs ==> te->xend center of view */
|
|
|
|
xdelta = (int)(te->xs - ar->v2d.cur.xmin);
|
|
|
|
ar->v2d.cur.xmin += xdelta;
|
|
|
|
ar->v2d.cur.xmax += xdelta;
|
|
|
|
|
|
|
|
/* store selection */
|
2012-05-07 17:56:30 +00:00
|
|
|
soops->search_tse = *tselem;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-01-11 12:33:51 +00:00
|
|
|
BLI_strncpy(soops->search_string, name, sizeof(soops->search_string));
|
2012-05-07 17:56:30 +00:00
|
|
|
soops->search_flags = flags;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
/* redraw */
|
|
|
|
soops->storeflag |= SO_TREESTORE_REDRAW;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* no tree-element found */
|
2012-10-26 17:32:50 +00:00
|
|
|
BKE_reportf(reports, RPT_WARNING, "Not found: %s", name);
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Show One Level ----------------------------------------------- */
|
|
|
|
|
|
|
|
/* helper function for Show/Hide one level operator */
|
|
|
|
static void outliner_openclose_level(SpaceOops *soops, ListBase *lb, int curlevel, int level, int open)
|
|
|
|
{
|
|
|
|
TreeElement *te;
|
|
|
|
TreeStoreElem *tselem;
|
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
for (te = lb->first; te; te = te->next) {
|
|
|
|
tselem = TREESTORE(te);
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (open) {
|
2012-05-07 17:56:30 +00:00
|
|
|
if (curlevel <= level) tselem->flag &= ~TSE_CLOSED;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
else {
|
2012-05-07 17:56:30 +00:00
|
|
|
if (curlevel >= level) tselem->flag |= TSE_CLOSED;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
outliner_openclose_level(soops, &te->subtree, curlevel + 1, level, open);
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int outliner_one_level_exec(bContext *C, wmOperator *op)
|
|
|
|
{
|
2012-05-07 17:56:30 +00:00
|
|
|
SpaceOops *soops = CTX_wm_space_outliner(C);
|
|
|
|
ARegion *ar = CTX_wm_region(C);
|
2014-02-03 18:55:59 +11:00
|
|
|
const bool add = RNA_boolean_get(op->ptr, "open");
|
2011-07-11 10:59:53 +00:00
|
|
|
int level;
|
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
level = outliner_has_one_flag(soops, &soops->tree, TSE_CLOSED, 1);
|
|
|
|
if (add == 1) {
|
2012-03-24 06:38:07 +00:00
|
|
|
if (level) outliner_openclose_level(soops, &soops->tree, 1, level, 1);
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
else {
|
2012-05-07 17:56:30 +00:00
|
|
|
if (level == 0) level = outliner_count_levels(soops, &soops->tree, 0);
|
|
|
|
if (level) outliner_openclose_level(soops, &soops->tree, 1, level - 1, 0);
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ED_region_tag_redraw(ar);
|
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void OUTLINER_OT_show_one_level(wmOperatorType *ot)
|
|
|
|
{
|
2012-11-27 20:12:00 +00:00
|
|
|
PropertyRNA *prop;
|
|
|
|
|
2011-07-11 10:59:53 +00:00
|
|
|
/* identifiers */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "Show/Hide One Level";
|
|
|
|
ot->idname = "OUTLINER_OT_show_one_level";
|
|
|
|
ot->description = "Expand/collapse all entries by one level";
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
/* callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->exec = outliner_one_level_exec;
|
|
|
|
ot->poll = ED_operator_outliner_active;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
/* no undo or registry, UI option */
|
|
|
|
|
|
|
|
/* properties */
|
2012-11-27 20:12:00 +00:00
|
|
|
prop = RNA_def_boolean(ot->srna, "open", 1, "Open", "Expand all entries one level deep");
|
|
|
|
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Show Hierarchy ----------------------------------------------- */
|
|
|
|
|
|
|
|
/* helper function for tree_element_shwo_hierarchy() - recursively checks whether subtrees have any objects*/
|
|
|
|
static int subtree_has_objects(SpaceOops *soops, ListBase *lb)
|
|
|
|
{
|
|
|
|
TreeElement *te;
|
|
|
|
TreeStoreElem *tselem;
|
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
for (te = lb->first; te; te = te->next) {
|
|
|
|
tselem = TREESTORE(te);
|
|
|
|
if (tselem->type == 0 && te->idcode == ID_OB) return 1;
|
|
|
|
if (subtree_has_objects(soops, &te->subtree)) return 1;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* recursive helper function for Show Hierarchy operator */
|
|
|
|
static void tree_element_show_hierarchy(Scene *scene, SpaceOops *soops, ListBase *lb)
|
|
|
|
{
|
|
|
|
TreeElement *te;
|
|
|
|
TreeStoreElem *tselem;
|
|
|
|
|
|
|
|
/* open all object elems, close others */
|
2012-05-07 17:56:30 +00:00
|
|
|
for (te = lb->first; te; te = te->next) {
|
|
|
|
tselem = TREESTORE(te);
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
if (tselem->type == 0) {
|
|
|
|
if (te->idcode == ID_SCE) {
|
|
|
|
if (tselem->id != (ID *)scene) tselem->flag |= TSE_CLOSED;
|
|
|
|
else tselem->flag &= ~TSE_CLOSED;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
2012-05-07 17:56:30 +00:00
|
|
|
else if (te->idcode == ID_OB) {
|
2012-03-24 06:38:07 +00:00
|
|
|
if (subtree_has_objects(soops, &te->subtree)) tselem->flag &= ~TSE_CLOSED;
|
2011-07-11 10:59:53 +00:00
|
|
|
else tselem->flag |= TSE_CLOSED;
|
|
|
|
}
|
|
|
|
}
|
2013-03-09 03:46:30 +00:00
|
|
|
else {
|
|
|
|
tselem->flag |= TSE_CLOSED;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (TSELEM_OPEN(tselem, soops)) {
|
|
|
|
tree_element_show_hierarchy(scene, soops, &te->subtree);
|
|
|
|
}
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* show entire object level hierarchy */
|
|
|
|
static int outliner_show_hierarchy_exec(bContext *C, wmOperator *UNUSED(op))
|
|
|
|
{
|
2012-05-07 17:56:30 +00:00
|
|
|
SpaceOops *soops = CTX_wm_space_outliner(C);
|
|
|
|
ARegion *ar = CTX_wm_region(C);
|
|
|
|
Scene *scene = CTX_data_scene(C);
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
/* recursively open/close levels */
|
|
|
|
tree_element_show_hierarchy(scene, soops, &soops->tree);
|
|
|
|
|
|
|
|
ED_region_tag_redraw(ar);
|
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void OUTLINER_OT_show_hierarchy(wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
/* identifiers */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "Show Hierarchy";
|
|
|
|
ot->idname = "OUTLINER_OT_show_hierarchy";
|
|
|
|
ot->description = "Open all object entries and close all others";
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
/* callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->exec = outliner_show_hierarchy_exec;
|
|
|
|
ot->poll = ED_operator_outliner_active; // TODO: shouldn't be allowed in RNA views...
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
/* no undo or registry, UI option */
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ************************************************************** */
|
|
|
|
/* ANIMATO OPERATIONS */
|
|
|
|
/* KeyingSet and Driver Creation - Helper functions */
|
|
|
|
|
2011-10-17 06:39:13 +00:00
|
|
|
/* specialized poll callback for these operators to work in Datablocks view only */
|
2011-07-11 10:59:53 +00:00
|
|
|
static int ed_operator_outliner_datablocks_active(bContext *C)
|
|
|
|
{
|
2012-05-07 17:56:30 +00:00
|
|
|
ScrArea *sa = CTX_wm_area(C);
|
|
|
|
if ((sa) && (sa->spacetype == SPACE_OUTLINER)) {
|
|
|
|
SpaceOops *so = CTX_wm_space_outliner(C);
|
2011-07-11 10:59:53 +00:00
|
|
|
return (so->outlinevis == SO_DATABLOCKS);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Helper func to extract an RNA path from selected tree element
|
|
|
|
* NOTE: the caller must zero-out all values of the pointers that it passes here first, as
|
|
|
|
* this function does not do that yet
|
|
|
|
*/
|
2013-08-03 11:35:09 +00:00
|
|
|
static void tree_element_to_path(TreeElement *te, TreeStoreElem *tselem,
|
2012-05-07 17:56:30 +00:00
|
|
|
ID **id, char **path, int *array_index, short *flag, short *UNUSED(groupmode))
|
2011-07-11 10:59:53 +00:00
|
|
|
{
|
|
|
|
ListBase hierarchy = {NULL, NULL};
|
|
|
|
LinkData *ld;
|
|
|
|
TreeElement *tem, *temnext, *temsub;
|
2011-09-20 08:48:48 +00:00
|
|
|
TreeStoreElem *tse /* , *tsenext */ /* UNUSED */;
|
2011-07-11 10:59:53 +00:00
|
|
|
PointerRNA *ptr, *nextptr;
|
|
|
|
PropertyRNA *prop;
|
2012-05-07 17:56:30 +00:00
|
|
|
char *newpath = NULL;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-03-02 16:05:54 +00:00
|
|
|
/* optimize tricks:
|
2011-07-11 10:59:53 +00:00
|
|
|
* - Don't do anything if the selected item is a 'struct', but arrays are allowed
|
|
|
|
*/
|
|
|
|
if (tselem->type == TSE_RNA_STRUCT)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Overview of Algorithm:
|
2012-05-07 17:56:30 +00:00
|
|
|
* 1. Go up the chain of parents until we find the 'root', taking note of the
|
2011-07-11 10:59:53 +00:00
|
|
|
* levels encountered in reverse-order (i.e. items are added to the start of the list
|
|
|
|
* for more convenient looping later)
|
2012-05-07 17:56:30 +00:00
|
|
|
* 2. Walk down the chain, adding from the first ID encountered
|
2011-07-11 10:59:53 +00:00
|
|
|
* (which will become the 'ID' for the KeyingSet Path), and build a
|
2012-05-07 17:56:30 +00:00
|
|
|
* path as we step through the chain
|
2011-07-11 10:59:53 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
/* step 1: flatten out hierarchy of parents into a flat chain */
|
2012-05-07 17:56:30 +00:00
|
|
|
for (tem = te->parent; tem; tem = tem->parent) {
|
|
|
|
ld = MEM_callocN(sizeof(LinkData), "LinkData for tree_element_to_path()");
|
|
|
|
ld->data = tem;
|
2011-07-11 10:59:53 +00:00
|
|
|
BLI_addhead(&hierarchy, ld);
|
|
|
|
}
|
|
|
|
|
2012-05-31 18:40:06 +00:00
|
|
|
/* step 2: step down hierarchy building the path
|
|
|
|
* (NOTE: addhead in previous loop was needed so that we can loop like this) */
|
2012-05-07 17:56:30 +00:00
|
|
|
for (ld = hierarchy.first; ld; ld = ld->next) {
|
2011-07-11 10:59:53 +00:00
|
|
|
/* get data */
|
2012-05-07 17:56:30 +00:00
|
|
|
tem = (TreeElement *)ld->data;
|
|
|
|
tse = TREESTORE(tem);
|
|
|
|
ptr = &tem->rnaptr;
|
|
|
|
prop = tem->directdata;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
/* check if we're looking for first ID, or appending to path */
|
|
|
|
if (*id) {
|
|
|
|
/* just 'append' property to path
|
2012-05-31 18:40:06 +00:00
|
|
|
* - to prevent memory leaks, we must write to newpath not path, then free old path + swap them
|
2011-07-11 10:59:53 +00:00
|
|
|
*/
|
2012-03-24 06:38:07 +00:00
|
|
|
if (tse->type == TSE_RNA_PROPERTY) {
|
|
|
|
if (RNA_property_type(prop) == PROP_POINTER) {
|
2011-07-11 10:59:53 +00:00
|
|
|
/* for pointer we just append property name */
|
2012-05-07 17:56:30 +00:00
|
|
|
newpath = RNA_path_append(*path, ptr, prop, 0, NULL);
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
else if (RNA_property_type(prop) == PROP_COLLECTION) {
|
2011-07-11 10:59:53 +00:00
|
|
|
char buf[128], *name;
|
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
temnext = (TreeElement *)(ld->next->data);
|
2012-10-26 04:14:10 +00:00
|
|
|
/* tsenext = TREESTORE(temnext); */ /* UNUSED */
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
nextptr = &temnext->rnaptr;
|
|
|
|
name = RNA_struct_name_get_alloc(nextptr, buf, sizeof(buf), NULL);
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (name) {
|
2011-07-11 10:59:53 +00:00
|
|
|
/* if possible, use name as a key in the path */
|
2012-05-07 17:56:30 +00:00
|
|
|
newpath = RNA_path_append(*path, NULL, prop, 0, name);
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (name != buf)
|
2011-07-11 10:59:53 +00:00
|
|
|
MEM_freeN(name);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* otherwise use index */
|
2012-05-07 17:56:30 +00:00
|
|
|
int index = 0;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
for (temsub = tem->subtree.first; temsub; temsub = temsub->next, index++)
|
2012-03-24 06:38:07 +00:00
|
|
|
if (temsub == temnext)
|
2011-07-11 10:59:53 +00:00
|
|
|
break;
|
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
newpath = RNA_path_append(*path, NULL, prop, index, NULL);
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
ld = ld->next;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (newpath) {
|
2011-07-11 10:59:53 +00:00
|
|
|
if (*path) MEM_freeN(*path);
|
2012-05-07 17:56:30 +00:00
|
|
|
*path = newpath;
|
|
|
|
newpath = NULL;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* no ID, so check if entry is RNA-struct, and if that RNA-struct is an ID datablock to extract info from */
|
|
|
|
if (tse->type == TSE_RNA_STRUCT) {
|
2012-05-31 18:40:06 +00:00
|
|
|
/* ptr->data not ptr->id.data seems to be the one we want,
|
|
|
|
* since ptr->data is sometimes the owner of this ID? */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (RNA_struct_is_ID(ptr->type)) {
|
2012-05-07 17:56:30 +00:00
|
|
|
*id = (ID *)ptr->data;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
/* clear path */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (*path) {
|
2011-07-11 10:59:53 +00:00
|
|
|
MEM_freeN(*path);
|
2012-05-07 17:56:30 +00:00
|
|
|
path = NULL;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* step 3: if we've got an ID, add the current item to the path */
|
|
|
|
if (*id) {
|
|
|
|
/* add the active property to the path */
|
2012-05-07 17:56:30 +00:00
|
|
|
ptr = &te->rnaptr;
|
|
|
|
prop = te->directdata;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
/* array checks */
|
|
|
|
if (tselem->type == TSE_RNA_ARRAY_ELEM) {
|
|
|
|
/* item is part of an array, so must set the array_index */
|
2012-05-07 17:56:30 +00:00
|
|
|
*array_index = te->index;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
2013-09-16 01:35:52 +00:00
|
|
|
else if (RNA_property_array_check(prop)) {
|
2011-07-11 10:59:53 +00:00
|
|
|
/* entire array was selected, so keyframe all */
|
|
|
|
*flag |= KSP_FLAG_WHOLE_ARRAY;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* path */
|
2012-05-07 17:56:30 +00:00
|
|
|
newpath = RNA_path_append(*path, NULL, prop, 0, NULL);
|
2011-07-11 10:59:53 +00:00
|
|
|
if (*path) MEM_freeN(*path);
|
2012-05-07 17:56:30 +00:00
|
|
|
*path = newpath;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* free temp data */
|
|
|
|
BLI_freelistN(&hierarchy);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* =============================================== */
|
|
|
|
/* Driver Operations */
|
|
|
|
|
|
|
|
/* These operators are only available in databrowser mode for now, as
|
|
|
|
* they depend on having RNA paths and/or hierarchies available.
|
|
|
|
*/
|
|
|
|
enum {
|
2012-05-07 17:56:30 +00:00
|
|
|
DRIVERS_EDITMODE_ADD = 0,
|
2011-07-11 10:59:53 +00:00
|
|
|
DRIVERS_EDITMODE_REMOVE,
|
|
|
|
} /*eDrivers_EditModes*/;
|
|
|
|
|
|
|
|
/* Utilities ---------------------------------- */
|
|
|
|
|
|
|
|
/* Recursively iterate over tree, finding and working on selected items */
|
|
|
|
static void do_outliner_drivers_editop(SpaceOops *soops, ListBase *tree, ReportList *reports, short mode)
|
|
|
|
{
|
|
|
|
TreeElement *te;
|
|
|
|
TreeStoreElem *tselem;
|
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
for (te = tree->first; te; te = te->next) {
|
|
|
|
tselem = TREESTORE(te);
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
/* if item is selected, perform operation */
|
|
|
|
if (tselem->flag & TSE_SELECTED) {
|
2012-05-07 17:56:30 +00:00
|
|
|
ID *id = NULL;
|
|
|
|
char *path = NULL;
|
|
|
|
int array_index = 0;
|
|
|
|
short flag = 0;
|
|
|
|
short groupmode = KSP_GROUP_KSNAME;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-03-03 11:45:08 +00:00
|
|
|
/* check if RNA-property described by this selected element is an animatable prop */
|
2012-05-31 18:40:06 +00:00
|
|
|
if (ELEM(tselem->type, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM) &&
|
|
|
|
RNA_property_animateable(&te->rnaptr, te->directdata))
|
|
|
|
{
|
2011-07-11 10:59:53 +00:00
|
|
|
/* get id + path + index info from the selected element */
|
2013-08-03 11:35:09 +00:00
|
|
|
tree_element_to_path(te, tselem,
|
2012-05-07 17:56:30 +00:00
|
|
|
&id, &path, &array_index, &flag, &groupmode);
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* only if ID and path were set, should we perform any actions */
|
|
|
|
if (id && path) {
|
|
|
|
short dflags = CREATEDRIVER_WITH_DEFAULT_DVAR;
|
|
|
|
int arraylen = 1;
|
|
|
|
|
|
|
|
/* array checks */
|
|
|
|
if (flag & KSP_FLAG_WHOLE_ARRAY) {
|
|
|
|
/* entire array was selected, so add drivers for all */
|
2012-05-07 17:56:30 +00:00
|
|
|
arraylen = RNA_property_array_length(&te->rnaptr, te->directdata);
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
else
|
2012-05-07 17:56:30 +00:00
|
|
|
arraylen = array_index;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
/* we should do at least one step */
|
|
|
|
if (arraylen == array_index)
|
|
|
|
arraylen++;
|
|
|
|
|
|
|
|
/* for each array element we should affect, add driver */
|
|
|
|
for (; array_index < arraylen; array_index++) {
|
|
|
|
/* action depends on mode */
|
|
|
|
switch (mode) {
|
|
|
|
case DRIVERS_EDITMODE_ADD:
|
|
|
|
{
|
|
|
|
/* add a new driver with the information obtained (only if valid) */
|
|
|
|
ANIM_add_driver(reports, id, path, array_index, dflags, DRIVER_TYPE_PYTHON);
|
2013-07-19 15:23:42 +00:00
|
|
|
break;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
case DRIVERS_EDITMODE_REMOVE:
|
|
|
|
{
|
|
|
|
/* remove driver matching the information obtained (only if valid) */
|
|
|
|
ANIM_remove_driver(reports, id, path, array_index, dflags);
|
2013-07-19 15:23:42 +00:00
|
|
|
break;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* free path, since it had to be generated */
|
|
|
|
MEM_freeN(path);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/* go over sub-tree */
|
2012-04-29 15:47:02 +00:00
|
|
|
if (TSELEM_OPEN(tselem, soops))
|
2011-07-11 10:59:53 +00:00
|
|
|
do_outliner_drivers_editop(soops, &te->subtree, reports, mode);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Add Operator ---------------------------------- */
|
|
|
|
|
|
|
|
static int outliner_drivers_addsel_exec(bContext *C, wmOperator *op)
|
|
|
|
{
|
2012-05-07 17:56:30 +00:00
|
|
|
SpaceOops *soutliner = CTX_wm_space_outliner(C);
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
/* check for invalid states */
|
|
|
|
if (soutliner == NULL)
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
|
|
|
|
/* recursively go into tree, adding selected items */
|
|
|
|
do_outliner_drivers_editop(soutliner, &soutliner->tree, op->reports, DRIVERS_EDITMODE_ADD);
|
|
|
|
|
|
|
|
/* send notifiers */
|
2012-05-07 17:56:30 +00:00
|
|
|
WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, NULL); // XXX
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void OUTLINER_OT_drivers_add_selected(wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
/* api callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->idname = "OUTLINER_OT_drivers_add_selected";
|
|
|
|
ot->name = "Add Drivers for Selected";
|
|
|
|
ot->description = "Add drivers to selected items";
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
/* api callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->exec = outliner_drivers_addsel_exec;
|
|
|
|
ot->poll = ed_operator_outliner_datablocks_active;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
/* flags */
|
2012-05-07 17:56:30 +00:00
|
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Remove Operator ---------------------------------- */
|
|
|
|
|
|
|
|
static int outliner_drivers_deletesel_exec(bContext *C, wmOperator *op)
|
|
|
|
{
|
2012-05-07 17:56:30 +00:00
|
|
|
SpaceOops *soutliner = CTX_wm_space_outliner(C);
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
/* check for invalid states */
|
|
|
|
if (soutliner == NULL)
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
|
|
|
|
/* recursively go into tree, adding selected items */
|
|
|
|
do_outliner_drivers_editop(soutliner, &soutliner->tree, op->reports, DRIVERS_EDITMODE_REMOVE);
|
|
|
|
|
|
|
|
/* send notifiers */
|
|
|
|
WM_event_add_notifier(C, ND_KEYS, NULL); // XXX
|
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void OUTLINER_OT_drivers_delete_selected(wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
/* identifiers */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->idname = "OUTLINER_OT_drivers_delete_selected";
|
|
|
|
ot->name = "Delete Drivers for Selected";
|
|
|
|
ot->description = "Delete drivers assigned to selected items";
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
/* api callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->exec = outliner_drivers_deletesel_exec;
|
|
|
|
ot->poll = ed_operator_outliner_datablocks_active;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
/* flags */
|
2012-05-07 17:56:30 +00:00
|
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* =============================================== */
|
|
|
|
/* Keying Set Operations */
|
|
|
|
|
|
|
|
/* These operators are only available in databrowser mode for now, as
|
|
|
|
* they depend on having RNA paths and/or hierarchies available.
|
|
|
|
*/
|
|
|
|
enum {
|
2012-05-07 17:56:30 +00:00
|
|
|
KEYINGSET_EDITMODE_ADD = 0,
|
2011-07-11 10:59:53 +00:00
|
|
|
KEYINGSET_EDITMODE_REMOVE,
|
|
|
|
} /*eKeyingSet_EditModes*/;
|
|
|
|
|
|
|
|
/* Utilities ---------------------------------- */
|
|
|
|
|
|
|
|
/* find the 'active' KeyingSet, and add if not found (if adding is allowed) */
|
|
|
|
// TODO: should this be an API func?
|
|
|
|
static KeyingSet *verify_active_keyingset(Scene *scene, short add)
|
|
|
|
{
|
2012-05-07 17:56:30 +00:00
|
|
|
KeyingSet *ks = NULL;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
/* sanity check */
|
|
|
|
if (scene == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/* try to find one from scene */
|
|
|
|
if (scene->active_keyingset > 0)
|
2012-05-07 17:56:30 +00:00
|
|
|
ks = BLI_findlink(&scene->keyingsets, scene->active_keyingset - 1);
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
/* add if none found */
|
|
|
|
// XXX the default settings have yet to evolve
|
2012-05-07 17:56:30 +00:00
|
|
|
if ((add) && (ks == NULL)) {
|
|
|
|
ks = BKE_keyingset_add(&scene->keyingsets, NULL, NULL, KEYINGSET_ABSOLUTE, 0);
|
|
|
|
scene->active_keyingset = BLI_countlist(&scene->keyingsets);
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return ks;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Recursively iterate over tree, finding and working on selected items */
|
|
|
|
static void do_outliner_keyingset_editop(SpaceOops *soops, KeyingSet *ks, ListBase *tree, short mode)
|
|
|
|
{
|
|
|
|
TreeElement *te;
|
|
|
|
TreeStoreElem *tselem;
|
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
for (te = tree->first; te; te = te->next) {
|
|
|
|
tselem = TREESTORE(te);
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
/* if item is selected, perform operation */
|
|
|
|
if (tselem->flag & TSE_SELECTED) {
|
2012-05-07 17:56:30 +00:00
|
|
|
ID *id = NULL;
|
|
|
|
char *path = NULL;
|
|
|
|
int array_index = 0;
|
|
|
|
short flag = 0;
|
|
|
|
short groupmode = KSP_GROUP_KSNAME;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
2012-03-03 11:45:08 +00:00
|
|
|
/* check if RNA-property described by this selected element is an animatable prop */
|
2012-05-31 18:40:06 +00:00
|
|
|
if (ELEM(tselem->type, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM) &&
|
|
|
|
RNA_property_animateable(&te->rnaptr, te->directdata))
|
|
|
|
{
|
2011-07-11 10:59:53 +00:00
|
|
|
/* get id + path + index info from the selected element */
|
2013-08-03 11:35:09 +00:00
|
|
|
tree_element_to_path(te, tselem,
|
2012-05-07 17:56:30 +00:00
|
|
|
&id, &path, &array_index, &flag, &groupmode);
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* only if ID and path were set, should we perform any actions */
|
|
|
|
if (id && path) {
|
|
|
|
/* action depends on mode */
|
|
|
|
switch (mode) {
|
|
|
|
case KEYINGSET_EDITMODE_ADD:
|
|
|
|
{
|
|
|
|
/* add a new path with the information obtained (only if valid) */
|
2012-05-31 18:40:06 +00:00
|
|
|
/* TODO: what do we do with group name?
|
|
|
|
* for now, we don't supply one, and just let this use the KeyingSet name */
|
2011-07-11 10:59:53 +00:00
|
|
|
BKE_keyingset_add_path(ks, id, NULL, path, array_index, flag, groupmode);
|
2012-05-07 17:56:30 +00:00
|
|
|
ks->active_path = BLI_countlist(&ks->paths);
|
2013-02-02 04:58:03 +00:00
|
|
|
break;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
case KEYINGSET_EDITMODE_REMOVE:
|
|
|
|
{
|
|
|
|
/* find the relevant path, then remove it from the KeyingSet */
|
2012-05-07 17:56:30 +00:00
|
|
|
KS_Path *ksp = BKE_keyingset_find_path(ks, id, NULL, path, array_index, groupmode);
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
if (ksp) {
|
|
|
|
/* free path's data */
|
|
|
|
BKE_keyingset_free_path(ks, ksp);
|
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
ks->active_path = 0;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
2013-02-02 04:58:03 +00:00
|
|
|
break;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* free path, since it had to be generated */
|
|
|
|
MEM_freeN(path);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* go over sub-tree */
|
2012-04-29 15:47:02 +00:00
|
|
|
if (TSELEM_OPEN(tselem, soops))
|
2011-07-11 10:59:53 +00:00
|
|
|
do_outliner_keyingset_editop(soops, ks, &te->subtree, mode);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Add Operator ---------------------------------- */
|
|
|
|
|
|
|
|
static int outliner_keyingset_additems_exec(bContext *C, wmOperator *op)
|
|
|
|
{
|
2012-05-07 17:56:30 +00:00
|
|
|
SpaceOops *soutliner = CTX_wm_space_outliner(C);
|
|
|
|
Scene *scene = CTX_data_scene(C);
|
|
|
|
KeyingSet *ks = verify_active_keyingset(scene, 1);
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
/* check for invalid states */
|
|
|
|
if (ks == NULL) {
|
2012-10-18 16:25:58 +00:00
|
|
|
BKE_report(op->reports, RPT_ERROR, "Operation requires an active keying set");
|
2011-07-11 10:59:53 +00:00
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
}
|
|
|
|
if (soutliner == NULL)
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
|
|
|
|
/* recursively go into tree, adding selected items */
|
|
|
|
do_outliner_keyingset_editop(soutliner, ks, &soutliner->tree, KEYINGSET_EDITMODE_ADD);
|
|
|
|
|
|
|
|
/* send notifiers */
|
2012-05-07 17:56:30 +00:00
|
|
|
WM_event_add_notifier(C, NC_SCENE | ND_KEYINGSET, NULL);
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void OUTLINER_OT_keyingset_add_selected(wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
/* identifiers */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->idname = "OUTLINER_OT_keyingset_add_selected";
|
|
|
|
ot->name = "Keying Set Add Selected";
|
2012-07-03 19:09:07 +00:00
|
|
|
ot->description = "Add selected items (blue-gray rows) to active Keying Set";
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
/* api callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->exec = outliner_keyingset_additems_exec;
|
|
|
|
ot->poll = ed_operator_outliner_datablocks_active;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
/* flags */
|
2012-05-07 17:56:30 +00:00
|
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Remove Operator ---------------------------------- */
|
|
|
|
|
|
|
|
static int outliner_keyingset_removeitems_exec(bContext *C, wmOperator *UNUSED(op))
|
|
|
|
{
|
2012-05-07 17:56:30 +00:00
|
|
|
SpaceOops *soutliner = CTX_wm_space_outliner(C);
|
|
|
|
Scene *scene = CTX_data_scene(C);
|
|
|
|
KeyingSet *ks = verify_active_keyingset(scene, 1);
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
/* check for invalid states */
|
|
|
|
if (soutliner == NULL)
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
|
|
|
|
/* recursively go into tree, adding selected items */
|
|
|
|
do_outliner_keyingset_editop(soutliner, ks, &soutliner->tree, KEYINGSET_EDITMODE_REMOVE);
|
|
|
|
|
|
|
|
/* send notifiers */
|
2012-05-07 17:56:30 +00:00
|
|
|
WM_event_add_notifier(C, NC_SCENE | ND_KEYINGSET, NULL);
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void OUTLINER_OT_keyingset_remove_selected(wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
/* identifiers */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->idname = "OUTLINER_OT_keyingset_remove_selected";
|
|
|
|
ot->name = "Keying Set Remove Selected";
|
2012-07-03 19:09:07 +00:00
|
|
|
ot->description = "Remove selected items (blue-gray rows) from active Keying Set";
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
/* api callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->exec = outliner_keyingset_removeitems_exec;
|
|
|
|
ot->poll = ed_operator_outliner_datablocks_active;
|
2011-07-11 10:59:53 +00:00
|
|
|
|
|
|
|
/* flags */
|
2012-05-07 17:56:30 +00:00
|
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
2011-07-11 10:59:53 +00:00
|
|
|
}
|
2012-01-22 10:20:30 +00:00
|
|
|
|
|
|
|
/* ******************** Parent Drop Operator *********************** */
|
|
|
|
|
|
|
|
static int parent_drop_exec(bContext *C, wmOperator *op)
|
|
|
|
{
|
2012-02-22 07:56:15 +00:00
|
|
|
Object *par = NULL, *ob = NULL;
|
2012-05-07 17:56:30 +00:00
|
|
|
Main *bmain = CTX_data_main(C);
|
|
|
|
Scene *scene = CTX_data_scene(C);
|
2012-01-22 10:20:30 +00:00
|
|
|
int partype = -1;
|
2012-02-22 07:56:15 +00:00
|
|
|
char parname[MAX_ID_NAME], childname[MAX_ID_NAME];
|
2012-01-22 10:20:30 +00:00
|
|
|
|
2012-05-07 17:56:30 +00:00
|
|
|
partype = RNA_enum_get(op->ptr, "type");
|
2012-01-22 10:20:30 +00:00
|
|
|
RNA_string_get(op->ptr, "parent", parname);
|
2012-05-07 17:56:30 +00:00
|
|
|
par = (Object *)BKE_libblock_find_name(ID_OB, parname);
|
2012-02-22 07:56:15 +00:00
|
|
|
RNA_string_get(op->ptr, "child", childname);
|
2012-05-07 17:56:30 +00:00
|
|
|
ob = (Object *)BKE_libblock_find_name(ID_OB, childname);
|
2012-02-22 07:56:15 +00:00
|
|
|
|
2014-02-05 13:16:15 +01:00
|
|
|
if (ob->id.lib) {
|
|
|
|
BKE_report(op->reports, RPT_INFO, "Can't edit library linked object");
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
}
|
|
|
|
|
2013-09-01 22:01:21 +00:00
|
|
|
ED_object_parent_set(op->reports, bmain, scene, ob, par, partype, false, false, NULL);
|
2012-01-22 10:20:30 +00:00
|
|
|
|
2013-02-21 19:33:04 +00:00
|
|
|
DAG_relations_tag_update(bmain);
|
2012-05-07 17:56:30 +00:00
|
|
|
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
|
|
|
|
WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, NULL);
|
2012-01-22 10:20:30 +00:00
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
2013-03-13 09:03:46 +00:00
|
|
|
static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
2012-01-22 10:20:30 +00:00
|
|
|
{
|
2012-05-07 17:56:30 +00:00
|
|
|
Object *par = NULL;
|
|
|
|
Object *ob = NULL;
|
|
|
|
SpaceOops *soops = CTX_wm_space_outliner(C);
|
|
|
|
ARegion *ar = CTX_wm_region(C);
|
|
|
|
Main *bmain = CTX_data_main(C);
|
2012-05-29 18:12:13 +00:00
|
|
|
Scene *scene = NULL;
|
2012-05-07 17:56:30 +00:00
|
|
|
TreeElement *te = NULL;
|
2012-01-22 10:20:30 +00:00
|
|
|
char childname[MAX_ID_NAME];
|
|
|
|
char parname[MAX_ID_NAME];
|
2012-05-07 17:56:30 +00:00
|
|
|
int partype = 0;
|
2012-01-22 10:20:30 +00:00
|
|
|
float fmval[2];
|
|
|
|
|
|
|
|
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
|
|
|
|
|
|
|
|
/* Find object hovered over */
|
2013-04-03 07:42:56 +00:00
|
|
|
te = outliner_dropzone_find(soops, fmval, 1);
|
2012-01-22 10:20:30 +00:00
|
|
|
|
2013-04-03 07:42:56 +00:00
|
|
|
if (te) {
|
|
|
|
RNA_string_set(op->ptr, "parent", te->name);
|
2012-01-22 10:20:30 +00:00
|
|
|
/* Identify parent and child */
|
|
|
|
RNA_string_get(op->ptr, "child", childname);
|
2012-05-07 17:56:30 +00:00
|
|
|
ob = (Object *)BKE_libblock_find_name(ID_OB, childname);
|
2012-01-22 10:20:30 +00:00
|
|
|
RNA_string_get(op->ptr, "parent", parname);
|
2012-05-07 17:56:30 +00:00
|
|
|
par = (Object *)BKE_libblock_find_name(ID_OB, parname);
|
2012-01-22 10:20:30 +00:00
|
|
|
|
|
|
|
if (ELEM(NULL, ob, par)) {
|
|
|
|
if (par == NULL) printf("par==NULL\n");
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
}
|
|
|
|
if (ob == par) {
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
}
|
2014-02-05 13:16:15 +01:00
|
|
|
if (ob->id.lib) {
|
|
|
|
BKE_report(op->reports, RPT_INFO, "Can't edit library linked object");
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
}
|
2012-01-22 10:20:30 +00:00
|
|
|
|
2013-04-03 07:42:56 +00:00
|
|
|
scene = (Scene *)outliner_search_back(soops, te, ID_SCE);
|
2012-05-29 18:12:13 +00:00
|
|
|
|
2012-05-31 18:40:06 +00:00
|
|
|
if (scene == NULL) {
|
2012-06-05 09:57:19 +00:00
|
|
|
/* currently outlier organized in a way, that if there's no parent scene
|
|
|
|
* element for object it means that all displayed objects belong to
|
|
|
|
* active scene and parenting them is allowed (sergey)
|
|
|
|
*/
|
|
|
|
|
|
|
|
scene = CTX_data_scene(C);
|
2012-05-29 18:12:13 +00:00
|
|
|
}
|
|
|
|
|
2012-01-22 10:20:30 +00:00
|
|
|
if ((par->type != OB_ARMATURE) && (par->type != OB_CURVE) && (par->type != OB_LATTICE)) {
|
2013-09-01 22:01:21 +00:00
|
|
|
if (ED_object_parent_set(op->reports, bmain, scene, ob, par, partype, false, false, NULL)) {
|
2013-02-21 19:33:04 +00:00
|
|
|
DAG_relations_tag_update(bmain);
|
2012-05-07 17:56:30 +00:00
|
|
|
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
|
|
|
|
WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, NULL);
|
2012-02-22 07:56:15 +00:00
|
|
|
}
|
2012-01-22 10:20:30 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* Menu creation */
|
2014-01-23 22:05:51 +11:00
|
|
|
wmOperatorType *ot = WM_operatortype_find("OUTLINER_OT_parent_drop", false);
|
2012-05-07 17:56:30 +00:00
|
|
|
uiPopupMenu *pup = uiPupMenuBegin(C, IFACE_("Set Parent To"), ICON_NONE);
|
|
|
|
uiLayout *layout = uiPupMenuLayout(pup);
|
2012-01-22 10:20:30 +00:00
|
|
|
|
|
|
|
PointerRNA ptr;
|
|
|
|
|
2014-01-23 22:05:51 +11:00
|
|
|
WM_operator_properties_create_ptr(&ptr, ot);
|
2012-01-22 10:20:30 +00:00
|
|
|
RNA_string_set(&ptr, "parent", parname);
|
|
|
|
RNA_string_set(&ptr, "child", childname);
|
|
|
|
RNA_enum_set(&ptr, "type", PAR_OBJECT);
|
|
|
|
/* Cannot use uiItemEnumO()... have multiple properties to set. */
|
2014-01-23 22:05:51 +11:00
|
|
|
uiItemFullO_ptr(layout, ot, IFACE_("Object"), 0, ptr.data, WM_OP_EXEC_DEFAULT, 0);
|
2012-01-22 10:20:30 +00:00
|
|
|
|
|
|
|
/* par becomes parent, make the associated menus */
|
2012-05-07 17:56:30 +00:00
|
|
|
if (par->type == OB_ARMATURE) {
|
2014-01-23 22:05:51 +11:00
|
|
|
WM_operator_properties_create_ptr(&ptr, ot);
|
2012-01-22 10:20:30 +00:00
|
|
|
RNA_string_set(&ptr, "parent", parname);
|
|
|
|
RNA_string_set(&ptr, "child", childname);
|
|
|
|
RNA_enum_set(&ptr, "type", PAR_ARMATURE);
|
2014-01-23 22:05:51 +11:00
|
|
|
uiItemFullO_ptr(layout, ot, IFACE_("Armature Deform"), 0, ptr.data, WM_OP_EXEC_DEFAULT, 0);
|
2012-01-22 10:20:30 +00:00
|
|
|
|
2014-01-23 22:05:51 +11:00
|
|
|
WM_operator_properties_create_ptr(&ptr, ot);
|
2012-01-22 10:20:30 +00:00
|
|
|
RNA_string_set(&ptr, "parent", parname);
|
|
|
|
RNA_string_set(&ptr, "child", childname);
|
|
|
|
RNA_enum_set(&ptr, "type", PAR_ARMATURE_NAME);
|
2014-01-23 22:05:51 +11:00
|
|
|
uiItemFullO_ptr(layout, ot, IFACE_(" With Empty Groups"), 0, ptr.data, WM_OP_EXEC_DEFAULT, 0);
|
2012-01-22 10:20:30 +00:00
|
|
|
|
2014-01-23 22:05:51 +11:00
|
|
|
WM_operator_properties_create_ptr(&ptr, ot);
|
2012-01-22 10:20:30 +00:00
|
|
|
RNA_string_set(&ptr, "parent", parname);
|
|
|
|
RNA_string_set(&ptr, "child", childname);
|
|
|
|
RNA_enum_set(&ptr, "type", PAR_ARMATURE_ENVELOPE);
|
2014-01-23 22:05:51 +11:00
|
|
|
uiItemFullO_ptr(layout, ot, IFACE_(" With Envelope Weights"), 0, ptr.data, WM_OP_EXEC_DEFAULT, 0);
|
2012-01-22 10:20:30 +00:00
|
|
|
|
2014-01-23 22:05:51 +11:00
|
|
|
WM_operator_properties_create_ptr(&ptr, ot);
|
2012-01-22 10:20:30 +00:00
|
|
|
RNA_string_set(&ptr, "parent", parname);
|
|
|
|
RNA_string_set(&ptr, "child", childname);
|
|
|
|
RNA_enum_set(&ptr, "type", PAR_ARMATURE_AUTO);
|
2014-01-23 22:05:51 +11:00
|
|
|
uiItemFullO_ptr(layout, ot, IFACE_(" With Automatic Weights"), 0, ptr.data, WM_OP_EXEC_DEFAULT, 0);
|
2012-01-22 10:20:30 +00:00
|
|
|
|
2014-01-23 22:05:51 +11:00
|
|
|
WM_operator_properties_create_ptr(&ptr, ot);
|
2012-01-22 10:20:30 +00:00
|
|
|
RNA_string_set(&ptr, "parent", parname);
|
|
|
|
RNA_string_set(&ptr, "child", childname);
|
|
|
|
RNA_enum_set(&ptr, "type", PAR_BONE);
|
2014-01-23 22:05:51 +11:00
|
|
|
uiItemFullO_ptr(layout, ot, IFACE_("Bone"),
|
Fixed another bunch of i18n bugs (thx to Leon Cheung for spotting them), among which:
* Drag'n'drop translation in Outliner
* "Execute" button in file window
* "Labels" of spacing elements, in multi-column enums
* A glitch with nodes "Value to RGB", they where called "ColorRamp" in node_type_base() call. This is not definitive, though, as it appears that UI node names are determined by this call, while it should be by "defines" in rna_nodetrre_types.h, I guess... Anyway, not good to have such things in two different places!
Also moved default context name under BLF_translation.h, much better to have those all in one place, accessible from whole Blender code!
2012-04-14 15:06:41 +00:00
|
|
|
0, ptr.data, WM_OP_EXEC_DEFAULT, 0);
|
2012-01-22 10:20:30 +00:00
|
|
|
}
|
2012-05-07 17:56:30 +00:00
|
|
|
else if (par->type == OB_CURVE) {
|
2014-01-23 22:05:51 +11:00
|
|
|
WM_operator_properties_create_ptr(&ptr, ot);
|
2012-01-22 10:20:30 +00:00
|
|
|
RNA_string_set(&ptr, "parent", parname);
|
|
|
|
RNA_string_set(&ptr, "child", childname);
|
|
|
|
RNA_enum_set(&ptr, "type", PAR_CURVE);
|
2014-01-23 22:05:51 +11:00
|
|
|
uiItemFullO_ptr(layout, ot, IFACE_("Curve Deform"), 0, ptr.data, WM_OP_EXEC_DEFAULT, 0);
|
2012-01-22 10:20:30 +00:00
|
|
|
|
2014-01-23 22:05:51 +11:00
|
|
|
WM_operator_properties_create_ptr(&ptr, ot);
|
2012-01-22 10:20:30 +00:00
|
|
|
RNA_string_set(&ptr, "parent", parname);
|
|
|
|
RNA_string_set(&ptr, "child", childname);
|
|
|
|
RNA_enum_set(&ptr, "type", PAR_FOLLOW);
|
2014-01-23 22:05:51 +11:00
|
|
|
uiItemFullO_ptr(layout, ot, IFACE_("Follow Path"), 0, ptr.data, WM_OP_EXEC_DEFAULT, 0);
|
2012-01-22 10:20:30 +00:00
|
|
|
|
2014-01-23 22:05:51 +11:00
|
|
|
WM_operator_properties_create_ptr(&ptr, ot);
|
2012-01-22 10:20:30 +00:00
|
|
|
RNA_string_set(&ptr, "parent", parname);
|
|
|
|
RNA_string_set(&ptr, "child", childname);
|
|
|
|
RNA_enum_set(&ptr, "type", PAR_PATH_CONST);
|
2014-01-23 22:05:51 +11:00
|
|
|
uiItemFullO_ptr(layout, ot, IFACE_("Path Constraint"), 0, ptr.data, WM_OP_EXEC_DEFAULT, 0);
|
2012-01-22 10:20:30 +00:00
|
|
|
}
|
|
|
|
else if (par->type == OB_LATTICE) {
|
2014-01-23 22:05:51 +11:00
|
|
|
WM_operator_properties_create_ptr(&ptr, ot);
|
2012-01-22 10:20:30 +00:00
|
|
|
RNA_string_set(&ptr, "parent", parname);
|
|
|
|
RNA_string_set(&ptr, "child", childname);
|
|
|
|
RNA_enum_set(&ptr, "type", PAR_LATTICE);
|
2014-01-23 22:05:51 +11:00
|
|
|
uiItemFullO_ptr(layout, ot, IFACE_("Lattice Deform"), 0, ptr.data, WM_OP_EXEC_DEFAULT, 0);
|
2012-01-22 10:20:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
uiPupMenuEnd(C, pup);
|
|
|
|
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
}
|
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void OUTLINER_OT_parent_drop(wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
/* identifiers */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "Drop to Set Parent";
|
2012-01-22 10:20:30 +00:00
|
|
|
ot->description = "Drag to parent in Outliner";
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->idname = "OUTLINER_OT_parent_drop";
|
2012-01-22 10:20:30 +00:00
|
|
|
|
|
|
|
/* api callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->invoke = parent_drop_invoke;
|
|
|
|
ot->exec = parent_drop_exec;
|
2012-01-22 10:20:30 +00:00
|
|
|
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->poll = ED_operator_outliner_active;
|
2012-01-22 10:20:30 +00:00
|
|
|
|
|
|
|
/* flags */
|
2013-02-05 14:38:19 +00:00
|
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
|
2012-01-22 10:20:30 +00:00
|
|
|
|
|
|
|
/* properties */
|
|
|
|
RNA_def_string(ot->srna, "child", "Object", MAX_ID_NAME, "Child", "Child Object");
|
|
|
|
RNA_def_string(ot->srna, "parent", "Object", MAX_ID_NAME, "Parent", "Parent Object");
|
|
|
|
RNA_def_enum(ot->srna, "type", prop_make_parent_types, 0, "Type", "");
|
|
|
|
}
|
|
|
|
|
2013-08-13 14:46:39 +00:00
|
|
|
static int outliner_parenting_poll(bContext *C)
|
|
|
|
{
|
|
|
|
SpaceOops *soops = CTX_wm_space_outliner(C);
|
|
|
|
|
|
|
|
if (soops) {
|
2014-07-20 01:30:29 +10:00
|
|
|
return ELEM(soops->outlinevis, SO_ALL_SCENES, SO_CUR_SCENE, SO_VISIBLE, SO_GROUPS);
|
2013-08-13 14:46:39 +00:00
|
|
|
}
|
|
|
|
|
2014-04-01 11:34:00 +11:00
|
|
|
return false;
|
2013-08-13 14:46:39 +00:00
|
|
|
}
|
|
|
|
|
2013-03-13 09:03:46 +00:00
|
|
|
static int parent_clear_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
|
2012-01-22 10:20:30 +00:00
|
|
|
{
|
2012-05-29 18:12:13 +00:00
|
|
|
Main *bmain = CTX_data_main(C);
|
2012-05-07 17:56:30 +00:00
|
|
|
Object *ob = NULL;
|
2012-05-29 18:12:13 +00:00
|
|
|
SpaceOops *soops = CTX_wm_space_outliner(C);
|
2012-01-22 10:20:30 +00:00
|
|
|
char obname[MAX_ID_NAME];
|
|
|
|
|
|
|
|
RNA_string_get(op->ptr, "dragged_obj", obname);
|
2012-05-07 17:56:30 +00:00
|
|
|
ob = (Object *)BKE_libblock_find_name(ID_OB, obname);
|
2012-01-22 10:20:30 +00:00
|
|
|
|
2012-05-29 18:12:13 +00:00
|
|
|
/* search forwards to find the object */
|
2013-08-14 11:29:22 +00:00
|
|
|
outliner_find_id(soops, &soops->tree, (ID *)ob);
|
2012-05-29 18:12:13 +00:00
|
|
|
|
|
|
|
ED_object_parent_clear(ob, RNA_enum_get(op->ptr, "type"));
|
2012-01-22 10:20:30 +00:00
|
|
|
|
2013-02-21 19:33:04 +00:00
|
|
|
DAG_relations_tag_update(bmain);
|
2012-05-29 18:12:13 +00:00
|
|
|
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
|
|
|
|
WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, NULL);
|
2012-01-22 10:20:30 +00:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void OUTLINER_OT_parent_clear(wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
/* identifiers */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "Drop to Clear Parent";
|
2012-01-23 22:57:46 +00:00
|
|
|
ot->description = "Drag to clear parent in Outliner";
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->idname = "OUTLINER_OT_parent_clear";
|
2012-01-22 10:20:30 +00:00
|
|
|
|
|
|
|
/* api callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->invoke = parent_clear_invoke;
|
2012-01-22 10:20:30 +00:00
|
|
|
|
2013-08-13 14:46:39 +00:00
|
|
|
ot->poll = outliner_parenting_poll;
|
2012-01-22 10:20:30 +00:00
|
|
|
|
|
|
|
/* flags */
|
2013-02-05 14:38:19 +00:00
|
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
|
2012-01-22 10:20:30 +00:00
|
|
|
|
|
|
|
/* properties */
|
|
|
|
RNA_def_string(ot->srna, "dragged_obj", "Object", MAX_ID_NAME, "Child", "Child Object");
|
|
|
|
RNA_def_enum(ot->srna, "type", prop_clear_parent_types, 0, "Type", "");
|
|
|
|
}
|
2012-05-29 08:20:11 +00:00
|
|
|
|
2013-03-13 09:03:46 +00:00
|
|
|
static int scene_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
2012-05-29 08:20:11 +00:00
|
|
|
{
|
|
|
|
Scene *scene = NULL;
|
|
|
|
Object *ob = NULL;
|
|
|
|
SpaceOops *soops = CTX_wm_space_outliner(C);
|
|
|
|
ARegion *ar = CTX_wm_region(C);
|
|
|
|
Main *bmain = CTX_data_main(C);
|
|
|
|
TreeElement *te = NULL;
|
|
|
|
char obname[MAX_ID_NAME];
|
|
|
|
float fmval[2];
|
|
|
|
|
|
|
|
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
|
|
|
|
|
|
|
|
/* Find object hovered over */
|
2013-04-03 07:42:56 +00:00
|
|
|
te = outliner_dropzone_find(soops, fmval, 0);
|
2012-05-29 08:20:11 +00:00
|
|
|
|
2013-04-03 07:42:56 +00:00
|
|
|
if (te) {
|
2012-05-29 08:20:11 +00:00
|
|
|
Base *base;
|
|
|
|
|
2013-04-03 07:42:56 +00:00
|
|
|
RNA_string_set(op->ptr, "scene", te->name);
|
|
|
|
scene = (Scene *)BKE_libblock_find_name(ID_SCE, te->name);
|
2012-05-29 08:20:11 +00:00
|
|
|
|
|
|
|
RNA_string_get(op->ptr, "object", obname);
|
|
|
|
ob = (Object *)BKE_libblock_find_name(ID_OB, obname);
|
2012-05-29 18:12:13 +00:00
|
|
|
|
|
|
|
if (ELEM(NULL, ob, scene) || scene->id.lib != NULL) {
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
}
|
|
|
|
|
|
|
|
base = ED_object_scene_link(scene, ob);
|
2012-05-29 08:20:11 +00:00
|
|
|
|
|
|
|
if (base == NULL) {
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (scene == CTX_data_scene(C)) {
|
|
|
|
/* when linking to an inactive scene don't touch the layer */
|
|
|
|
ob->lay = base->lay;
|
|
|
|
ED_base_object_select(base, BA_SELECT);
|
|
|
|
}
|
|
|
|
|
2013-02-21 19:33:04 +00:00
|
|
|
DAG_relations_tag_update(bmain);
|
2012-05-29 08:20:11 +00:00
|
|
|
|
|
|
|
WM_main_add_notifier(NC_SCENE | ND_OB_SELECT, scene);
|
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void OUTLINER_OT_scene_drop(wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
/* identifiers */
|
|
|
|
ot->name = "Drop Object to Scene";
|
|
|
|
ot->description = "Drag object to scene in Outliner";
|
|
|
|
ot->idname = "OUTLINER_OT_scene_drop";
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
ot->invoke = scene_drop_invoke;
|
|
|
|
|
|
|
|
ot->poll = ED_operator_outliner_active;
|
|
|
|
|
|
|
|
/* flags */
|
2013-02-05 14:38:19 +00:00
|
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
|
2012-05-29 08:20:11 +00:00
|
|
|
|
|
|
|
/* properties */
|
|
|
|
RNA_def_string(ot->srna, "object", "Object", MAX_ID_NAME, "Object", "Target Object");
|
|
|
|
RNA_def_string(ot->srna, "scene", "Scene", MAX_ID_NAME, "Scene", "Target Scene");
|
|
|
|
}
|
2012-06-10 22:22:26 +00:00
|
|
|
|
2013-03-13 09:03:46 +00:00
|
|
|
static int material_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
2012-06-10 22:22:26 +00:00
|
|
|
{
|
|
|
|
Material *ma = NULL;
|
|
|
|
Object *ob = NULL;
|
|
|
|
SpaceOops *soops = CTX_wm_space_outliner(C);
|
|
|
|
ARegion *ar = CTX_wm_region(C);
|
|
|
|
TreeElement *te = NULL;
|
|
|
|
char mat_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 */
|
2013-04-03 07:42:56 +00:00
|
|
|
te = outliner_dropzone_find(soops, fmval, 1);
|
2012-06-10 22:22:26 +00:00
|
|
|
|
2013-04-03 07:42:56 +00:00
|
|
|
if (te) {
|
|
|
|
RNA_string_set(op->ptr, "object", te->name);
|
|
|
|
ob = (Object *)BKE_libblock_find_name(ID_OB, te->name);
|
2012-06-10 22:22:26 +00:00
|
|
|
|
|
|
|
RNA_string_get(op->ptr, "material", mat_name);
|
|
|
|
ma = (Material *)BKE_libblock_find_name(ID_MA, mat_name);
|
|
|
|
|
|
|
|
if (ELEM(NULL, ob, ma)) {
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
}
|
|
|
|
|
2012-08-12 17:12:07 +00:00
|
|
|
assign_material(ob, ma, ob->totcol + 1, BKE_MAT_ASSIGN_USERPREF);
|
2012-06-10 22:22:26 +00:00
|
|
|
|
2012-10-21 05:46:41 +00:00
|
|
|
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, CTX_wm_view3d(C));
|
2012-11-26 08:52:07 +00:00
|
|
|
WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_LINKS, ma);
|
2012-06-10 22:22:26 +00:00
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void OUTLINER_OT_material_drop(wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
/* identifiers */
|
|
|
|
ot->name = "Drop Material on Object";
|
|
|
|
ot->description = "Drag material to object in Outliner";
|
|
|
|
ot->idname = "OUTLINER_OT_material_drop";
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
ot->invoke = material_drop_invoke;
|
|
|
|
|
|
|
|
ot->poll = ED_operator_outliner_active;
|
|
|
|
|
|
|
|
/* flags */
|
2013-02-05 14:38:19 +00:00
|
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
|
2012-06-10 22:22:26 +00:00
|
|
|
|
|
|
|
/* properties */
|
|
|
|
RNA_def_string(ot->srna, "object", "Object", MAX_ID_NAME, "Object", "Target Object");
|
|
|
|
RNA_def_string(ot->srna, "material", "Material", MAX_ID_NAME, "Material", "Target Material");
|
|
|
|
}
|
|
|
|
|