Пример #1
0
/* Adds a new bone-group */
void BKE_pose_add_group(Object *ob)
{
	bPose *pose = (ob) ? ob->pose : NULL;
	bActionGroup *grp;
	
	if (ELEM(NULL, ob, ob->pose))
		return;
	
	grp = MEM_callocN(sizeof(bActionGroup), "PoseGroup");
	BLI_strncpy(grp->name, DATA_("Group"), sizeof(grp->name));
	BLI_addtail(&pose->agroups, grp);
	BLI_uniquename(&pose->agroups, grp, DATA_("Group"), '.', offsetof(bActionGroup, name), sizeof(grp->name));
	
	pose->active_group = BLI_countlist(&pose->agroups);
}
Пример #2
0
static int poselib_rename_exec(bContext *C, wmOperator *op)
{
	Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
	bAction *act = (ob) ? ob->poselib : NULL;
	TimeMarker *marker;
	char newname[64];
	
	/* check if valid poselib */
	if (act == NULL) {
		BKE_report(op->reports, RPT_ERROR, "Object does not have pose lib data");
		return OPERATOR_CANCELLED;
	}
	
	/* get index (and pointer) of pose to remove */
	marker = BLI_findlink(&act->markers, RNA_enum_get(op->ptr, "pose"));
	if (marker == NULL) {
		BKE_report(op->reports, RPT_ERROR, "Invalid index for pose");
		return OPERATOR_CANCELLED;
	}
	
	/* get new name */
	RNA_string_get(op->ptr, "name", newname);
	
	/* copy name and validate it */
	BLI_strncpy(marker->name, newname, sizeof(marker->name));
	BLI_uniquename(&act->markers, marker, DATA_("Pose"), '.', offsetof(TimeMarker, name), sizeof(marker->name));
	
	/* send notifiers for this - using keyframe editing notifiers, since action 
	 * may be being shown in anim editors as active action 
	 */
	WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
	
	/* done */
	return OPERATOR_FINISHED;
}
Пример #3
0
/* add a new gp-layer and make it the active layer */
bGPDlayer *gpencil_layer_addnew(bGPdata *gpd, const char *name, int setactive)
{
	bGPDlayer *gpl;
	
	/* check that list is ok */
	if (gpd == NULL)
		return NULL;
		
	/* allocate memory for frame and add to end of list */
	gpl = MEM_callocN(sizeof(bGPDlayer), "bGPDlayer");
	
	/* add to datablock */
	BLI_addtail(&gpd->layers, gpl);
	
	/* set basic settings */
	copy_v4_v4(gpl->color, U.gpencil_new_layer_col);
	gpl->thickness = 3;
	
	/* auto-name */
	BLI_strncpy(gpl->info, name, sizeof(gpl->info));
	BLI_uniquename(&gpd->layers, gpl, DATA_("GP_Layer"), '.', offsetof(bGPDlayer, info), sizeof(gpl->info));
	
	/* make this one the active one */
	if (setactive)
		gpencil_layer_setactive(gpd, gpl);
	
	/* return layer */
	return gpl;
}
Пример #4
0
static void rna_Sensor_name_set(PointerRNA *ptr, const char *value)
{
	Object *ob = ptr->id.data;
	bSensor *sens = ptr->data;
	BLI_strncpy_utf8(sens->name, value, sizeof(sens->name));
	BLI_uniquename(&ob->sensors, sens, DATA_("Sensor"), '.', offsetof(bSensor, name), sizeof(sens->name));
}
Пример #5
0
void defgroup_unique_name(bDeformGroup *dg, Object *ob)
{
	struct {Object *ob; void *dg; } data;
	data.ob = ob;
	data.dg = dg;

	BLI_uniquename_cb(defgroup_unique_check, &data, DATA_("Group"), '.', dg->name, sizeof(dg->name));
}
Пример #6
0
static void rna_GameProperty_name_set(PointerRNA *ptr, const char *value)
{
	Object *ob = ptr->id.data;
	bProperty *prop = ptr->data;
	BLI_strncpy_utf8(prop->name, value, sizeof(prop->name));

	BLI_uniquename(&ob->prop, prop, DATA_("Property"), '.', offsetof(bProperty, name), sizeof(prop->name));
}
Пример #7
0
void modifier_unique_name(ListBase *modifiers, ModifierData *md)
{
	if (modifiers && md) {
		ModifierTypeInfo *mti = modifierType_getInfo(md->type);

		BLI_uniquename(modifiers, md, DATA_(mti->name), '.', offsetof(ModifierData, name), sizeof(md->name));
	}
}
Пример #8
0
void unique_editbone_name(ListBase *edbo, char *name, EditBone *bone)
{
	struct {ListBase *lb; void *bone; } data;
	data.lb = edbo;
	data.bone = bone;

	BLI_uniquename_cb(editbone_unique_check, &data, DATA_("Bone"), '.', name, sizeof(bone->name));
}
Пример #9
0
bool modifier_unique_name(ListBase *modifiers, ModifierData *md)
{
	if (modifiers && md) {
		const ModifierTypeInfo *mti = modifierType_getInfo(md->type);

		return BLI_uniquename(modifiers, md, DATA_(mti->name), '.', offsetof(ModifierData, name), sizeof(md->name));
	}
	return false;
}
Пример #10
0
static void rna_GPencilLayer_info_set(PointerRNA *ptr, const char *value)
{
	bGPdata *gpd = ptr->id.data;
	bGPDlayer *gpl = ptr->data;

	/* copy the new name into the name slot */
	BLI_strncpy_utf8(gpl->info, value, sizeof(gpl->info));

	BLI_uniquename(&gpd->layers, gpl, DATA_("GP_Layer"), '.', offsetof(bGPDlayer, info), sizeof(gpl->info));
}
Пример #11
0
/* return default layer, also used to patch old files */
SceneRenderLayer *BKE_scene_add_render_layer(Scene *sce, const char *name)
{
	SceneRenderLayer *srl;

	if (!name)
		name = DATA_("RenderLayer");

	srl = MEM_callocN(sizeof(SceneRenderLayer), "new render layer");
	BLI_strncpy(srl->name, name, sizeof(srl->name));
	BLI_uniquename(&sce->r.layers, srl, DATA_("RenderLayer"), '.', offsetof(SceneRenderLayer, name), sizeof(srl->name));
	BLI_addtail(&sce->r.layers, srl);

	/* note, this is also in render, pipeline.c, to make layer when scenedata doesnt have it */
	srl->lay = (1 << 20) - 1;
	srl->layflag = 0x7FFF;   /* solid ztra halo edge strand */
	srl->passflag = SCE_PASS_COMBINED | SCE_PASS_Z;
	BKE_freestyle_config_init(&srl->freestyleConfig);

	return srl;
}
Пример #12
0
/* add new layer - wrapper around API */
static int gp_layer_add_exec(bContext *C, wmOperator *op)
{
	bGPdata **gpd_ptr = gpencil_data_get_pointers(C, NULL);
	
	/* if there's no existing Grease-Pencil data there, add some */
	if (gpd_ptr == NULL) {
		BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
		return OPERATOR_CANCELLED;
	}
	if (*gpd_ptr == NULL)
		*gpd_ptr = gpencil_data_addnew(DATA_("GPencil"));
	
	/* add new layer now */
	gpencil_layer_addnew(*gpd_ptr, DATA_("GP_Layer"), 1);
	
	/* notifiers */
	WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
	
	return OPERATOR_FINISHED;
}
Пример #13
0
static void rna_Constroller_name_set(PointerRNA *ptr, const char *value)
{
	bController *cont = (bController *)ptr->data;

	BLI_strncpy_utf8(cont->name, value, sizeof(cont->name));

	if (ptr->id.data) {
		Object *ob = (Object *)ptr->id.data;
		BLI_uniquename(&ob->controllers, cont, DATA_("Controller"), '.', offsetof(bController, name),
		               sizeof(cont->name));
	}
}
Пример #14
0
static int controller_add_exec(bContext *C, wmOperator *op)
{
	Object *ob;
	bController *cont;
	PointerRNA cont_ptr;
	PropertyRNA *prop;
	const char *cont_name;
	int bit;
	char name[MAX_NAME];
	int type = RNA_enum_get(op->ptr, "type");

	ob = edit_object_property_get(C, op);
	if (!ob)
		return OPERATOR_CANCELLED;
	
	cont = new_controller(type);
	BLI_addtail(&(ob->controllers), cont);
	
	/* set the controller name based on rna type enum */
	RNA_pointer_create((ID *)ob, &RNA_Controller, cont, &cont_ptr);
	prop = RNA_struct_find_property(&cont_ptr, "type");

	RNA_string_get(op->ptr, "name", name);
	if (*name) {
		BLI_strncpy(cont->name, name, sizeof(cont->name));
	}
	else {
		RNA_property_enum_name(C, &cont_ptr, prop, RNA_property_enum_get(&cont_ptr, prop), &cont_name);
		BLI_strncpy(cont->name, cont_name, sizeof(cont->name));
	}

	BLI_uniquename(&ob->controllers, cont, DATA_("Controller"), '.', offsetof(bController, name), sizeof(cont->name));

	/* set the controller state mask from the current object state.
	 * A controller is always in a single state, so select the lowest bit set
	 * from the object state */
	for (bit = 0; bit < OB_MAX_STATES; bit++) {
		if (ob->state & (1 << bit))
			break;
	}
	cont->state_mask = (1 << bit);
	if (cont->state_mask == 0) {
		/* shouldn't happen, object state is never 0 */
		cont->state_mask = 1;
	}
	
	ob->scaflag |= OB_SHOWCONT;
	
	WM_event_add_notifier(C, NC_LOGIC, NULL);
	
	return OPERATOR_FINISHED;
}
Пример #15
0
/* Add a new action group with the given name to the action */
bActionGroup *action_groups_add_new(bAction *act, const char name[])
{
	bActionGroup *agrp;
	
	/* sanity check: must have action and name */
	if (ELEM(NULL, act, name))
		return NULL;
	
	/* allocate a new one */
	agrp = MEM_callocN(sizeof(bActionGroup), "bActionGroup");
	
	/* make it selected, with default name */
	agrp->flag = AGRP_SELECTED;
	BLI_strncpy(agrp->name, name[0] ? name : DATA_("Group"), sizeof(agrp->name));
	
	/* add to action, and validate */
	BLI_addtail(&act->groups, agrp);
	BLI_uniquename(&act->groups, agrp, DATA_("Group"), '.', offsetof(bActionGroup, name), sizeof(agrp->name));
	
	/* return the new group */
	return agrp;
}
Пример #16
0
static int poselib_add_exec(bContext *C, wmOperator *op)
{
	Object *ob = get_poselib_object(C);
	bAction *act = poselib_validate(ob);
	bPose *pose = (ob) ? ob->pose : NULL;
	TimeMarker *marker;
	KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_WHOLE_CHARACTER_ID); /* this includes custom props :)*/
	int frame = RNA_int_get(op->ptr, "frame");
	char name[64];
	
	/* sanity check (invoke should have checked this anyway) */
	if (ELEM(NULL, ob, pose)) 
		return OPERATOR_CANCELLED;
	
	/* get name to give to pose */
	RNA_string_get(op->ptr, "name", name);
	
	/* add pose to poselib - replaces any existing pose there
	 *	- for the 'replace' option, this should end up finding the appropriate marker,
	 *	  so no new one will be added
	 */
	for (marker = act->markers.first; marker; marker = marker->next) {
		if (marker->frame == frame) {
			BLI_strncpy(marker->name, name, sizeof(marker->name));
			break;
		}
	}
	if (marker == NULL) {
		marker = MEM_callocN(sizeof(TimeMarker), "ActionMarker");
		
		BLI_strncpy(marker->name, name, sizeof(marker->name));
		marker->frame = frame;
		
		BLI_addtail(&act->markers, marker);
	}
	
	/* validate name */
	BLI_uniquename(&act->markers, marker, DATA_("Pose"), '.', offsetof(TimeMarker, name), sizeof(marker->name));
	
	/* use Keying Set to determine what to store for the pose */
	/* FIXME: in the past, the Keying Set respected selections (LocRotScale), but the current one doesn't
	 * (WholeCharacter) so perhaps we need either a new Keying Set, or just to add overrides here... */
	ANIM_apply_keyingset(C, NULL, act, ks, MODIFYKEY_MODE_INSERT, (float)frame);
	
	/* store new 'active' pose number */
	act->active_marker = BLI_countlist(&act->markers);
	
	/* done */
	return OPERATOR_FINISHED;
}
Пример #17
0
/* Get palette color or create a new one */
bGPDpalettecolor *ED_gpencil_stroke_getcolor(bGPdata *gpd, bGPDstroke *gps)
{
	bGPDpalette *palette;
	bGPDpalettecolor *palcolor;

	if ((gps->palcolor != NULL) && ((gps->flag & GP_STROKE_RECALC_COLOR) == 0))
		return gps->palcolor;

	/* get palette */
	palette = BKE_gpencil_palette_getactive(gpd);
	if (palette == NULL) {
		palette = BKE_gpencil_palette_addnew(gpd, DATA_("GP_Palette"), true);
	}
	/* get color */
	palcolor = BKE_gpencil_palettecolor_getbyname(palette, gps->colorname);
	if (palcolor == NULL) {
		if (gps->palcolor == NULL) {
			palcolor = BKE_gpencil_palettecolor_addnew(palette, DATA_("Color"), true);
			/* set to a different color */
			ARRAY_SET_ITEMS(palcolor->color, 1.0f, 0.0f, 1.0f, 0.9f);
		}
		else {
			palcolor = BKE_gpencil_palettecolor_addnew(palette, gps->colorname, true);
			/* set old color and attributes */
			bGPDpalettecolor *gpscolor = gps->palcolor;
			copy_v4_v4(palcolor->color, gpscolor->color);
			copy_v4_v4(palcolor->fill, gpscolor->fill);
			palcolor->flag = gpscolor->flag;
		}
	}

	/* clear flag and set pointer */
	gps->flag &= ~GP_STROKE_RECALC_COLOR;
	gps->palcolor = palcolor;

	return palcolor;
}
Пример #18
0
/* /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// */
static void get_material_cb(bContext *C, void *poin, void *poin2)
{
    Scene       *scene  = CTX_data_scene(C);
    Main        *bmain  = CTX_data_main(C);
    bool        not_set = true;
    Object      *cur_object;
    Object      *ob;
    Material    *ma;

    cur_object = scene->basact ? scene->basact->object : 0;
    if(cur_object->actcol > 0) {
        ob = (Object*)cur_object;
        if(cur_object->totcol >= cur_object->actcol && ob->mat[cur_object->actcol - 1]) {
            bNodeTree *ntree = ob->mat[cur_object->actcol - 1]->nodetree;
            if(!ob->mat[cur_object->actcol - 1]->use_nodes) ob->mat[cur_object->actcol - 1]->use_nodes = true;
            if (ntree) {
                get_material(bmain, C, scene, ntree, (char*)poin, (int)poin2);
                not_set = false;
            }
        }
        if(not_set) {
            ID *id_me = cur_object->data;
            if (GS(id_me->name) == ID_ME) {
                Mesh *me = (Mesh*)id_me;
                if(me->totcol >= cur_object->actcol && me->mat[cur_object->actcol - 1]) {
                    bNodeTree *ntree = me->mat[cur_object->actcol - 1]->nodetree;
                    if(!me->mat[cur_object->actcol - 1]->use_nodes) me->mat[cur_object->actcol - 1]->use_nodes = true;
                    if (ntree) {
                        get_material(bmain, C, scene, ntree, (char*)poin, (int)poin2);
                        not_set = false;
                    }
                }
            }
        }
    }
    if(not_set) {
        ob = (Object*)cur_object;
        ma = BKE_material_add(bmain, DATA_("LDB Material"));

        ma->use_nodes = true;
        ma->nodetree  = ntreeAddTree(NULL, "Shader Nodetree", ntreeType_Shader->idname);
        assign_material(ob, ma, ob->totcol + 1, BKE_MAT_ASSIGN_USERPREF);
        WM_event_add_notifier(C, NC_MATERIAL | NA_ADDED, ma);

        get_material(bmain, C, scene, ma->nodetree, (char*)poin, (int)poin2);
    }
} /* get_material_cb() */
Пример #19
0
/* Adds a new bone-group (name may be NULL) */
bActionGroup *BKE_pose_add_group(bPose *pose, const char *name)
{
	bActionGroup *grp;
	
	if (!name) {
		name = DATA_("Group");
	}
	
	grp = MEM_callocN(sizeof(bActionGroup), "PoseGroup");
	BLI_strncpy(grp->name, name, sizeof(grp->name));
	BLI_addtail(&pose->agroups, grp);
	BLI_uniquename(&pose->agroups, grp, name, '.', offsetof(bActionGroup, name), sizeof(grp->name));
	
	pose->active_group = BLI_listbase_count(&pose->agroups);
	
	return grp;
}
Пример #20
0
bool new_id(ListBase *lb, ID *id, const char *tname)
{
	bool result;
	char name[MAX_ID_NAME - 2];

	/* if library, don't rename */
	if (id->lib)
		return false;

	/* if no libdata given, look up based on ID */
	if (lb == NULL)
		lb = which_libbase(G.main, GS(id->name));

	/* if no name given, use name of current ID
	 * else make a copy (tname args can be const) */
	if (tname == NULL)
		tname = id->name + 2;

	BLI_strncpy(name, tname, sizeof(name));

	if (name[0] == '\0') {
		/* disallow empty names */
		BLI_strncpy(name, DATA_(ID_FALLBACK_NAME), sizeof(name));
	}
	else {
		/* disallow non utf8 chars,
		 * the interface checks for this but new ID's based on file names don't */
		BLI_utf8_invalid_strip(name, strlen(name));
	}

	result = check_for_dupid(lb, id, name);
	strcpy(id->name + 2, name);

	/* This was in 2.43 and previous releases
	 * however all data in blender should be sorted, not just duplicate names
	 * sorting should not hurt, but noting just incase it alters the way other
	 * functions work, so sort every time */
#if 0
	if (result)
		id_sort_by_name(lb, id);
#endif

	id_sort_by_name(lb, id);
	
	return result;
}
Пример #21
0
ModifierData *modifier_new(int type)
{
	ModifierTypeInfo *mti = modifierType_getInfo(type);
	ModifierData *md = MEM_callocN(mti->structSize, mti->structName);
	
	/* note, this name must be made unique later */
	BLI_strncpy(md->name, DATA_(mti->name), sizeof(md->name));

	md->type = type;
	md->mode = eModifierMode_Realtime | eModifierMode_Render | eModifierMode_Expanded;

	if (mti->flags & eModifierTypeFlag_EnableInEditmode)
		md->mode |= eModifierMode_Editmode;

	if (mti->initData) mti->initData(md);

	return md;
}
Пример #22
0
/**
 * Add a new view layer
 * by default, a view layer has the master collection
 */
ViewLayer *BKE_view_layer_add(Scene *scene, const char *name)
{
  ViewLayer *view_layer = view_layer_add(name);

  BLI_addtail(&scene->view_layers, view_layer);

  /* unique name */
  BLI_uniquename(&scene->view_layers,
                 view_layer,
                 DATA_("ViewLayer"),
                 '.',
                 offsetof(ViewLayer, name),
                 sizeof(view_layer->name));

  BKE_layer_collection_sync(scene, view_layer);

  return view_layer;
}
Пример #23
0
void BKE_view_layer_rename(Main *bmain, Scene *scene, ViewLayer *view_layer, const char *newname)
{
  char oldname[sizeof(view_layer->name)];

  BLI_strncpy(oldname, view_layer->name, sizeof(view_layer->name));

  BLI_strncpy_utf8(view_layer->name, newname, sizeof(view_layer->name));
  BLI_uniquename(&scene->view_layers,
                 view_layer,
                 DATA_("ViewLayer"),
                 '.',
                 offsetof(ViewLayer, name),
                 sizeof(view_layer->name));

  if (scene->nodetree) {
    bNode *node;
    int index = BLI_findindex(&scene->view_layers, view_layer);

    for (node = scene->nodetree->nodes.first; node; node = node->next) {
      if (node->type == CMP_NODE_R_LAYERS && node->id == NULL) {
        if (node->custom1 == index) {
          BLI_strncpy(node->name, view_layer->name, NODE_MAXSTR);
        }
      }
    }
  }

  /* Fix all the animation data and windows which may link to this. */
  BKE_animdata_fix_paths_rename_all(NULL, "view_layers", oldname, view_layer->name);

  /* WM can be missing on startup. */
  wmWindowManager *wm = bmain->wm.first;
  if (wm) {
    for (wmWindow *win = wm->windows.first; win; win = win->next) {
      if (win->scene == scene && STREQ(win->view_layer_name, oldname)) {
        STRNCPY(win->view_layer_name, view_layer->name);
      }
    }
  }

  /* Dependency graph uses view layer name based lookups. */
  DEG_id_tag_update(&scene->id, 0);
}
Пример #24
0
static ViewLayer *view_layer_add(const char *name)
{
  if (!name) {
    name = DATA_("View Layer");
  }

  ViewLayer *view_layer = MEM_callocN(sizeof(ViewLayer), "View Layer");
  view_layer->flag = VIEW_LAYER_RENDER | VIEW_LAYER_FREESTYLE;

  BLI_strncpy_utf8(view_layer->name, name, sizeof(view_layer->name));

  /* Pure rendering pipeline settings. */
  view_layer->layflag = 0x7FFF; /* solid ztra halo edge strand */
  view_layer->passflag = SCE_PASS_COMBINED | SCE_PASS_Z;
  view_layer->pass_alpha_threshold = 0.5f;
  BKE_freestyle_config_init(&view_layer->freestyle_config);

  return view_layer;
}
Пример #25
0
/* add new datablock - wrapper around API */
static int gp_data_add_exec(bContext *C, wmOperator *op)
{
	bGPdata **gpd_ptr = gpencil_data_get_pointers(C, NULL);
	
	if (gpd_ptr == NULL) {
		BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go");
		return OPERATOR_CANCELLED;
	}
	else {
		/* decrement user count and add new datablock */
		bGPdata *gpd = (*gpd_ptr);
		
		id_us_min(&gpd->id);
		*gpd_ptr = gpencil_data_addnew(DATA_("GPencil"));
	}
	
	/* notifiers */
	WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
	
	return OPERATOR_FINISHED;
}
Пример #26
0
static int actuator_add_exec(bContext *C, wmOperator *op)
{
	Object *ob;
	bActuator *act;
	PointerRNA act_ptr;
	PropertyRNA *prop;
	const char *act_name;
	char name[MAX_NAME];
	int type = RNA_enum_get(op->ptr, "type");
		
	ob = edit_object_property_get(C, op);
	if (!ob)
		return OPERATOR_CANCELLED;

	act = new_actuator(type);
	BLI_addtail(&(ob->actuators), act);
	
	/* set the actuator name based on rna type enum */
	RNA_pointer_create((ID *)ob, &RNA_Actuator, act, &act_ptr);
	prop = RNA_struct_find_property(&act_ptr, "type");

	RNA_string_get(op->ptr, "name", name);
	if (*name) {
		BLI_strncpy(act->name, name, sizeof(act->name));
	}
	else {
		RNA_property_enum_name(C, &act_ptr, prop, RNA_property_enum_get(&act_ptr, prop), &act_name);
		BLI_strncpy(act->name, act_name, sizeof(act->name));
	}

	BLI_uniquename(&ob->actuators, act, DATA_("Actuator"), '.', offsetof(bActuator, name), sizeof(act->name));
	ob->scaflag |= OB_SHOWACT;
	
	WM_event_add_notifier(C, NC_LOGIC, NULL);
	
	return OPERATOR_FINISHED;
}
Пример #27
0
static void unique_bone_name(bArmature *arm, char *name)
{
	BLI_uniquename_cb(bone_unique_check, (void *)arm, DATA_("Bone"), '.', name, sizeof(((Bone *)NULL)->name));
}
Пример #28
0
void ED_animedit_unlink_action(bContext *C, ID *id, AnimData *adt, bAction *act, ReportList *reports, bool force_delete)
{
	ScrArea *sa = CTX_wm_area(C);
	
	/* If the old action only has a single user (that it's about to lose),
	 * warn user about it
	 *
	 * TODO: Maybe we should just save it for them? But then, there's the problem of
	 *       trying to get rid of stuff that's actually unwanted!
	 */
	if (act->id.us == 1) {
		BKE_reportf(reports, RPT_WARNING,
		            "Action '%s' will not be saved, create Fake User or Stash in NLA Stack to retain",
		            act->id.name + 2);
	}
	
	/* Clear Fake User and remove action stashing strip (if present) */
	if (force_delete) {
		/* Remove stashed strip binding this action to this datablock */
		/* XXX: we cannot unlink it from *OTHER* datablocks that may also be stashing it,
		 * but GE users only seem to use/care about single-object binding for now so this
		 * should be fine
		 */
		if (adt) {
			NlaTrack *nlt, *nlt_next;
			NlaStrip *strip, *nstrip;
			
			for (nlt = adt->nla_tracks.first; nlt; nlt = nlt_next) {
				nlt_next = nlt->next;
				
				if (strstr(nlt->name, DATA_("[Action Stash]"))) {
					for (strip = nlt->strips.first; strip; strip = nstrip) {
						nstrip = strip->next;
						
						if (strip->act == act) {
							/* Remove this strip, and the track too if it doesn't have anything else */
							free_nlastrip(&nlt->strips, strip);
							
							if (nlt->strips.first == NULL) {
								BLI_assert(nstrip == NULL);
								free_nlatrack(&adt->nla_tracks, nlt);
							}
						}
					}
				}
			}
		}
		
		/* Clear Fake User */
		id_fake_user_clear(&act->id);
	}
	
	/* If in Tweak Mode, don't unlink. Instead, this 
	 * becomes a shortcut to exit Tweak Mode instead
	 */
	if ((adt) && (adt->flag & ADT_NLA_EDIT_ON)) {
		/* Exit Tweak Mode */
		BKE_nla_tweakmode_exit(adt);
		
		/* Flush this to the Action Editor (if that's where this change was initiated) */
		if (sa->spacetype == SPACE_ACTION) {
			actedit_change_action(C, NULL);
		}
	}
	else {
		/* Unlink normally - Setting it to NULL should be enough to get the old one unlinked */
		if (sa->spacetype == SPACE_ACTION) {
			/* clear action editor -> action */
			actedit_change_action(C, NULL);
		}
		else {
			/* clear AnimData -> action */
			PointerRNA ptr;
			PropertyRNA *prop;
			
			/* create AnimData RNA pointers */
			RNA_pointer_create(id, &RNA_AnimData, adt, &ptr);
			prop = RNA_struct_find_property(&ptr, "action");
			
			/* clear... */
			RNA_property_pointer_set(&ptr, prop, PointerRNA_NULL);
			RNA_property_update(C, &ptr, prop);
		}
	}
}