Example #1
0
static int add_driver_button_exec(bContext *C, wmOperator *op)
{
	PointerRNA ptr = {{NULL}};
	PropertyRNA *prop = NULL;
	int success = 0;
	int index;
	const bool all = RNA_boolean_get(op->ptr, "all");
	
	/* try to create driver using property retrieved from UI */
	uiContextActiveProperty(C, &ptr, &prop, &index);
	
	if (all)
		index = -1;
	
	if (ptr.id.data && ptr.data && prop && RNA_property_animateable(&ptr, prop)) {
		char *path = get_driver_path_hack(C, &ptr, prop);
		short flags = CREATEDRIVER_WITH_DEFAULT_DVAR;
		
		if (path) {
			success += ANIM_add_driver(op->reports, ptr.id.data, path, index, flags, DRIVER_TYPE_PYTHON);
			
			MEM_freeN(path);
		}
	}
	
	if (success) {
		/* send updates */
		uiContextAnimUpdate(C);
		
		WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, NULL); // XXX
	}
	
	return (success) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
Example #2
0
/* Wrapper for creating a driver without knowing what the targets will be yet
 * (i.e. "manual/add later"). */
static int add_driver_button_none(bContext *C, wmOperator *op, short mapping_type)
{
  PointerRNA ptr = {{NULL}};
  PropertyRNA *prop = NULL;
  int index;
  int success = 0;

  UI_context_active_but_prop_get(C, &ptr, &prop, &index);

  if (mapping_type == CREATEDRIVER_MAPPING_NONE_ALL) {
    index = -1;
  }

  if (ptr.id.data && ptr.data && prop && RNA_property_animateable(&ptr, prop)) {
    char *path = BKE_animdata_driver_path_hack(C, &ptr, prop, NULL);
    short flags = CREATEDRIVER_WITH_DEFAULT_DVAR;

    if (path) {
      success += ANIM_add_driver(op->reports, ptr.id.data, path, index, flags, DRIVER_TYPE_PYTHON);
      MEM_freeN(path);
    }
  }

  if (success) {
    /* send updates */
    UI_context_update_anim_flag(C);
    DEG_relations_tag_update(CTX_data_main(C));
    WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, NULL);  // XXX

    return OPERATOR_FINISHED;
  }
  else {
    return OPERATOR_CANCELLED;
  }
}
Example #3
0
static int add_driver_button_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
  PointerRNA ptr = {{NULL}};
  PropertyRNA *prop = NULL;
  int index;

  /* try to find driver using property retrieved from UI */
  UI_context_active_but_prop_get(C, &ptr, &prop, &index);

  if (ptr.id.data && ptr.data && prop && RNA_property_animateable(&ptr, prop)) {
    /* 1) Create a new "empty" driver for this property */
    char *path = BKE_animdata_driver_path_hack(C, &ptr, prop, NULL);
    short flags = CREATEDRIVER_WITH_DEFAULT_DVAR;
    short success = 0;

    if (path) {
      success += ANIM_add_driver(op->reports, ptr.id.data, path, index, flags, DRIVER_TYPE_PYTHON);
      MEM_freeN(path);
    }

    if (success) {
      /* send updates */
      UI_context_update_anim_flag(C);
      DEG_id_tag_update(ptr.id.data, ID_RECALC_COPY_ON_WRITE);
      DEG_relations_tag_update(CTX_data_main(C));
      WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, NULL);
    }

    /* 2) Show editing panel for setting up this driver */
    /* TODO: Use a different one from the editing popever, so we can have the single/all toggle? */
    UI_popover_panel_invoke(C, "GRAPH_PT_drivers_popover", true, op->reports);
  }

  return OPERATOR_INTERFACE;
}
Example #4
0
PyObject *pyrna_struct_driver_add(BPy_StructRNA *self, PyObject *args)
{
	const char *path, *path_full;
	int index = -1;

	PYRNA_STRUCT_CHECK_OBJ(self);

	if (!PyArg_ParseTuple(args, "s|i:driver_add", &path, &index))
		return NULL;

	if (pyrna_struct_anim_args_parse(&self->ptr, "bpy_struct.driver_add():", path, &path_full, &index) == -1) {
		return NULL;
	}
	else {
		PyObject *ret = NULL;
		ReportList reports;
		int result;

		BKE_reports_init(&reports, RPT_STORE);

		result = ANIM_add_driver(&reports, (ID *)self->ptr.id.data, path_full, index, 
		                         CREATEDRIVER_WITH_FMODIFIER, DRIVER_TYPE_PYTHON);

		if (BPy_reports_to_error(&reports, PyExc_RuntimeError, true) == -1)
			return NULL;

		if (result) {
			ID *id = self->ptr.id.data;
			AnimData *adt = BKE_animdata_from_id(id);
			FCurve *fcu;

			PointerRNA tptr;

			if (index == -1) { /* all, use a list */
				int i = 0;
				ret = PyList_New(0);
				while ((fcu = list_find_fcurve(&adt->drivers, path_full, i++))) {
					RNA_pointer_create(id, &RNA_FCurve, fcu, &tptr);
					PyList_APPEND(ret, pyrna_struct_CreatePyObject(&tptr));
				}
			}
			else {
				fcu = list_find_fcurve(&adt->drivers, path_full, index);
				RNA_pointer_create(id, &RNA_FCurve, fcu, &tptr);
				ret = pyrna_struct_CreatePyObject(&tptr);
			}
			
			WM_event_add_notifier(BPy_GetContext(), NC_ANIMATION | ND_FCURVES_ORDER, NULL);
		}
		else {
			/* XXX, should be handled by reports, */
			PyErr_SetString(PyExc_TypeError, "bpy_struct.driver_add(): failed because of an internal error");
			return NULL;
		}

		MEM_freeN((void *)path_full);

		return ret;
	}
}
Example #5
0
/* Main Driver Management API calls:
 * Add a new driver for the specified property on the given ID block,
 * and make it be driven by the specified target.
 *
 * This is intended to be used in conjunction with a modal "eyedropper"
 * for picking the variable that is going to be used to drive this one.
 *
 * - flag: eCreateDriverFlags
 * - driver_type: eDriver_Types
 * - mapping_type: eCreateDriver_MappingTypes
 */
int ANIM_add_driver_with_target(ReportList *reports,
                                ID *dst_id,
                                const char dst_path[],
                                int dst_index,
                                ID *src_id,
                                const char src_path[],
                                int src_index,
                                short flag,
                                int driver_type,
                                short mapping_type)
{
  PointerRNA id_ptr, ptr;
  PropertyRNA *prop;

  PointerRNA id_ptr2, ptr2;
  PropertyRNA *prop2;
  int done_tot = 0;

  /* validate pointers first - exit if failure */
  RNA_id_pointer_create(dst_id, &id_ptr);
  if (RNA_path_resolve_property(&id_ptr, dst_path, &ptr, &prop) == false) {
    BKE_reportf(
        reports,
        RPT_ERROR,
        "Could not add driver, as RNA path is invalid for the given ID (ID = %s, path = %s)",
        dst_id->name,
        dst_path);
    return 0;
  }

  RNA_id_pointer_create(src_id, &id_ptr2);
  if ((RNA_path_resolve_property(&id_ptr2, src_path, &ptr2, &prop2) == false) ||
      (mapping_type == CREATEDRIVER_MAPPING_NONE)) {
    /* No target - So, fall back to default method for adding a "simple" driver normally */
    return ANIM_add_driver(
        reports, dst_id, dst_path, dst_index, flag | CREATEDRIVER_WITH_DEFAULT_DVAR, driver_type);
  }

  /* handle curve-property mappings based on mapping_type */
  switch (mapping_type) {
    case CREATEDRIVER_MAPPING_N_N: /* N-N - Try to match as much as possible,
                                    * then use the first one */
    {
      /* Use the shorter of the two (to avoid out of bounds access) */
      int dst_len = (RNA_property_array_check(prop)) ? RNA_property_array_length(&ptr, prop) : 1;
      int src_len = (RNA_property_array_check(prop)) ? RNA_property_array_length(&ptr2, prop2) : 1;

      int len = MIN2(dst_len, src_len);
      int i;

      for (i = 0; i < len; i++) {
        done_tot += add_driver_with_target(reports,
                                           dst_id,
                                           dst_path,
                                           i,
                                           src_id,
                                           src_path,
                                           i,
                                           &ptr,
                                           prop,
                                           &ptr2,
                                           prop2,
                                           flag,
                                           driver_type);
      }
      break;
    }

    case CREATEDRIVER_MAPPING_1_N: /* 1-N - Specified target index for all */
    default: {
      int len = (RNA_property_array_check(prop)) ? RNA_property_array_length(&ptr, prop) : 1;
      int i;

      for (i = 0; i < len; i++) {
        done_tot += add_driver_with_target(reports,
                                           dst_id,
                                           dst_path,
                                           i,
                                           src_id,
                                           src_path,
                                           src_index,
                                           &ptr,
                                           prop,
                                           &ptr2,
                                           prop2,
                                           flag,
                                           driver_type);
      }
      break;
    }

    case CREATEDRIVER_MAPPING_1_1: /* 1-1 - Use the specified index (unless -1) */
    {
      done_tot = add_driver_with_target(reports,
                                        dst_id,
                                        dst_path,
                                        dst_index,
                                        src_id,
                                        src_path,
                                        src_index,
                                        &ptr,
                                        prop,
                                        &ptr2,
                                        prop2,
                                        flag,
                                        driver_type);
      break;
    }
  }

  /* done */
  return done_tot;
}
Example #6
0
/* 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;
	
	for (te= tree->first; te; te=te->next) {
		tselem= TREESTORE(te);
		
		/* if item is selected, perform operation */
		if (tselem->flag & TSE_SELECTED) {
			ID *id= NULL;
			char *path= NULL;
			int array_index= 0;
			short flag= 0;
			short groupmode= KSP_GROUP_KSNAME;
			
			/* check if RNA-property described by this selected element is an animateable prop */
			if (ELEM(tselem->type, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM) && RNA_property_animateable(&te->rnaptr, te->directdata)) {
				/* get id + path + index info from the selected element */
				tree_element_to_path(soops, te, tselem, 
						&id, &path, &array_index, &flag, &groupmode);
			}
			
			/* 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 */
					arraylen= RNA_property_array_length(&te->rnaptr, te->directdata);
				}
				else
					arraylen= array_index;
				
				/* 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);
						}
							break;
						case DRIVERS_EDITMODE_REMOVE:
						{
							/* remove driver matching the information obtained (only if valid) */
							ANIM_remove_driver(reports, id, path, array_index, dflags);
						}
							break;
					}
				}
				
				/* free path, since it had to be generated */
				MEM_freeN(path);
			}
			
			
		}
		
		/* go over sub-tree */
		if ((tselem->flag & TSE_CLOSED)==0)
			do_outliner_drivers_editop(soops, &te->subtree, reports, mode);
	}
}