Merge branch 'master' into sculpt-dev

This commit is contained in:
Pablo Dobarro 2020-12-28 14:21:15 +01:00
commit a3e4f9d9a6
33 changed files with 238 additions and 130 deletions

View File

@ -174,7 +174,7 @@ class SpellChecker:
"premultiply", "premultiplied",
"prepass",
"prepend",
"preprocess", "preprocessing",
"preprocess", "preprocessing", "preprocessor",
"preseek",
"promillage",
"pushdown",
@ -549,7 +549,7 @@ class SpellChecker:
"freestyle",
"enum", "enums",
"gizmogroup",
"gons", # N-Gons
"gon", "gons", # N-Gon(s)
"gpencil",
"idcol",
"keyframe", "keyframes", "keyframing", "keyframed",

View File

@ -592,7 +592,7 @@ class GreasePencilMaterialsPanel:
if show_full_ui:
row = layout.row()
row.template_ID(ob, "active_material", new="material.new", live_icon=True)
row.template_ID(ob, "active_material", new="material.new", duplicate="material.duplicate", live_icon=True)
slot = context.material_slot
if slot:

View File

@ -93,10 +93,10 @@ class NODE_HT_header(Header):
# Show material.new when no active ID/slot exists
if not id_from and ob_type in types_that_support_material:
row.template_ID(ob, "active_material", new="material.new")
row.template_ID(ob, "active_material", new="material.new", duplicate="material.duplicate")
# Material ID, but not for Lights
if id_from and ob_type != 'LIGHT':
row.template_ID(id_from, "active_material", new="material.new")
row.template_ID(id_from, "active_material", new="material.new", duplicate="material.duplicate")
if snode.shader_type == 'WORLD':
NODE_MT_editor_menus.draw_collapsible(context, layout)
@ -109,7 +109,7 @@ class NODE_HT_header(Header):
row = layout.row()
row.enabled = not snode.pin
row.template_ID(scene, "world", new="world.new")
row.template_ID(scene, "world", new="world.new", duplicate="world.duplicate")
if snode.shader_type == 'LINESTYLE':
view_layer = context.view_layer

View File

@ -410,6 +410,10 @@ class OUTLINER_PT_filter(Panel):
row = sub.row()
row.label(icon='EMPTY_DATA')
row.prop(space, "use_filter_object_empty", text="Empties")
row = sub.row()
if bpy.data.libraries:
row.label(icon='LIBRARY_DATA_OVERRIDE')
row.prop(space, "use_filter_lib_override", text="Library Overrides")
if (
bpy.data.curves or

View File

@ -95,6 +95,10 @@ struct IDOverrideLibraryProperty *BKE_lib_override_library_property_get(
struct IDOverrideLibrary *override, const char *rna_path, bool *r_created);
void BKE_lib_override_library_property_delete(struct IDOverrideLibrary *override,
struct IDOverrideLibraryProperty *override_property);
bool BKE_lib_override_rna_property_find(struct PointerRNA *idpoin,
const struct IDOverrideLibraryProperty *library_prop,
struct PointerRNA *r_override_poin,
struct PropertyRNA **r_override_prop);
struct IDOverrideLibraryPropertyOperation *BKE_lib_override_library_property_operation_find(
struct IDOverrideLibraryProperty *override_property,
@ -131,7 +135,7 @@ bool BKE_lib_override_library_status_check_local(struct Main *bmain, struct ID *
bool BKE_lib_override_library_status_check_reference(struct Main *bmain, struct ID *local);
bool BKE_lib_override_library_operations_create(struct Main *bmain, struct ID *local);
void BKE_lib_override_library_main_operations_create(struct Main *bmain, const bool force_auto);
bool BKE_lib_override_library_main_operations_create(struct Main *bmain, const bool force_auto);
void BKE_lib_override_library_id_reset(struct Main *bmain, struct ID *id_root);
void BKE_lib_override_library_id_hierarchy_reset(struct Main *bmain, struct ID *id_root);

View File

@ -96,6 +96,12 @@ typedef struct UndoStep {
/* Over alloc 'type->struct_size'. */
} UndoStep;
typedef enum UndoPushReturn {
UNDO_PUSH_RET_FAILURE = 0,
UNDO_PUSH_RET_SUCCESS = (1 << 0),
UNDO_PUSH_RET_OVERRIDE_CHANGED = (1 << 1),
} UndoPushReturn;
typedef void (*UndoTypeForEachIDRefFn)(void *user_data, struct UndoRefID *id_ref);
typedef struct UndoType {
@ -172,11 +178,11 @@ UndoStep *BKE_undosys_step_push_init_with_type(UndoStack *ustack,
const UndoType *ut);
UndoStep *BKE_undosys_step_push_init(UndoStack *ustack, struct bContext *C, const char *name);
bool BKE_undosys_step_push_with_type(UndoStack *ustack,
struct bContext *C,
const char *name,
const UndoType *ut);
bool BKE_undosys_step_push(UndoStack *ustack, struct bContext *C, const char *name);
UndoPushReturn BKE_undosys_step_push_with_type(UndoStack *ustack,
struct bContext *C,
const char *name,
const UndoType *ut);
UndoPushReturn BKE_undosys_step_push(UndoStack *ustack, struct bContext *C, const char *name);
UndoStep *BKE_undosys_step_find_by_name_with_type(UndoStack *ustack,
const char *name,

View File

@ -57,6 +57,8 @@
#include "RNA_access.h"
#include "RNA_types.h"
#include "atomic_ops.h"
#define OVERRIDE_AUTO_CHECK_DELAY 0.2 /* 200ms between auto-override checks. */
//#define DEBUG_OVERRIDE_TIMEIT
@ -982,6 +984,23 @@ IDOverrideLibraryProperty *BKE_lib_override_library_property_get(IDOverrideLibra
return op;
}
/**
* Get the RNA-property matching the \a library_prop override property. Used for UI to query
* additional data about the overridden property (e.g. UI name).
*
* \param idpoin: Pointer to the override ID.
* \param library_prop: The library override property to find the matching RNA property for.
*/
bool BKE_lib_override_rna_property_find(PointerRNA *idpoin,
const IDOverrideLibraryProperty *library_prop,
PointerRNA *r_override_poin,
PropertyRNA **r_override_prop)
{
BLI_assert(RNA_struct_is_ID(idpoin->type) && ID_IS_OVERRIDE_LIBRARY(idpoin->data));
return RNA_path_resolve_property(
idpoin, library_prop->rna_path, r_override_poin, r_override_prop);
}
void lib_override_library_property_copy(IDOverrideLibraryProperty *op_dst,
IDOverrideLibraryProperty *op_src)
{
@ -1370,19 +1389,20 @@ bool BKE_lib_override_library_status_check_reference(Main *bmain, ID *local)
* since it has to go over all properties in depth (all overridable ones at least).
* Generating differential values and applying overrides are much cheaper.
*
* \return true if a new overriding op was created, or some local data was reset. */
* \return true if any library operation was created.
*/
bool BKE_lib_override_library_operations_create(Main *bmain, ID *local)
{
BLI_assert(local->override_library != NULL);
const bool is_template = (local->override_library->reference == NULL);
bool ret = false;
bool created = false;
if (!is_template) {
/* Do not attempt to generate overriding rules from an empty place-holder generated by link
* code when it cannot find the actual library/ID. Much better to keep the local data-block as
* is in the file in that case, until broken lib is fixed. */
if (ID_MISSING(local->override_library->reference)) {
return ret;
return created;
}
if (GS(local->name) == ID_OB) {
@ -1412,14 +1432,16 @@ bool BKE_lib_override_library_operations_create(Main *bmain, ID *local)
local->override_library,
RNA_OVERRIDE_COMPARE_CREATE | RNA_OVERRIDE_COMPARE_RESTORE,
&report_flags);
if (report_flags & RNA_OVERRIDE_MATCH_RESULT_CREATED) {
ret = true;
created = true;
}
#ifndef NDEBUG
if (report_flags & RNA_OVERRIDE_MATCH_RESULT_RESTORED) {
printf("We did restore some properties of %s from its reference.\n", local->name);
}
if (ret) {
if (report_flags & RNA_OVERRIDE_MATCH_RESULT_CREATED) {
printf("We did generate library override rules for %s\n", local->name);
}
else {
@ -1427,19 +1449,28 @@ bool BKE_lib_override_library_operations_create(Main *bmain, ID *local)
}
#endif
}
return ret;
return created;
}
struct LibOverrideOpCreateData {
Main *bmain;
bool changed;
};
static void lib_override_library_operations_create_cb(TaskPool *__restrict pool, void *taskdata)
{
Main *bmain = BLI_task_pool_user_data(pool);
struct LibOverrideOpCreateData *create_data = BLI_task_pool_user_data(pool);
ID *id = taskdata;
BKE_lib_override_library_operations_create(bmain, id);
if (BKE_lib_override_library_operations_create(create_data->bmain, id)) {
/* Technically no need for atomic, all jobs write the same value and we only care if one did
* it. But play safe and avoid implicit assumptions. */
atomic_fetch_and_or_uint8((uint8_t *)&create_data->changed, true);
}
}
/** Check all overrides from given \a bmain and create/update overriding operations as needed. */
void BKE_lib_override_library_main_operations_create(Main *bmain, const bool force_auto)
bool BKE_lib_override_library_main_operations_create(Main *bmain, const bool force_auto)
{
ID *id;
@ -1464,7 +1495,8 @@ void BKE_lib_override_library_main_operations_create(Main *bmain, const bool for
}
}
TaskPool *task_pool = BLI_task_pool_create(bmain, TASK_PRIORITY_HIGH);
struct LibOverrideOpCreateData create_pool_data = {.bmain = bmain, .changed = false};
TaskPool *task_pool = BLI_task_pool_create(&create_pool_data, TASK_PRIORITY_HIGH);
FOREACH_MAIN_ID_BEGIN (bmain, id) {
if (ID_IS_OVERRIDE_LIBRARY_REAL(id) &&
@ -1503,6 +1535,8 @@ void BKE_lib_override_library_main_operations_create(Main *bmain, const bool for
#ifdef DEBUG_OVERRIDE_TIMEIT
TIMEIT_END_AVERAGED(BKE_lib_override_library_main_operations_create);
#endif
return create_pool_data.changed;
}
static bool lib_override_library_id_reset_do(Main *bmain, ID *id_root)

View File

@ -845,9 +845,7 @@ static void mesh_tessface_clear_intern(Mesh *mesh, int free_customdata)
Mesh *BKE_mesh_add(Main *bmain, const char *name)
{
Mesh *me;
me = BKE_id_new(bmain, ID_ME, name);
Mesh *me = BKE_id_new(bmain, ID_ME, name);
return me;
}
@ -1007,10 +1005,9 @@ BMesh *BKE_mesh_to_bmesh_ex(const Mesh *me,
const struct BMeshCreateParams *create_params,
const struct BMeshFromMeshParams *convert_params)
{
BMesh *bm;
const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(me);
bm = BM_mesh_create(&allocsize, create_params);
BMesh *bm = BM_mesh_create(&allocsize, create_params);
BM_mesh_bm_from_me(bm, me, convert_params);
return bm;
@ -1162,17 +1159,14 @@ void BKE_mesh_texspace_copy_from_object(Mesh *me, Object *ob)
float (*BKE_mesh_orco_verts_get(Object *ob))[3]
{
Mesh *me = ob->data;
MVert *mvert = NULL;
Mesh *tme = me->texcomesh ? me->texcomesh : me;
int a, totvert;
float(*vcos)[3] = NULL;
/* Get appropriate vertex coordinates */
vcos = MEM_calloc_arrayN(me->totvert, sizeof(*vcos), "orco mesh");
mvert = tme->mvert;
totvert = min_ii(tme->totvert, me->totvert);
float(*vcos)[3] = MEM_calloc_arrayN(me->totvert, sizeof(*vcos), "orco mesh");
MVert *mvert = tme->mvert;
int totvert = min_ii(tme->totvert, me->totvert);
for (a = 0; a < totvert; a++, mvert++) {
for (int a = 0; a < totvert; a++, mvert++) {
copy_v3_v3(vcos[a], mvert->co);
}
@ -1182,18 +1176,17 @@ float (*BKE_mesh_orco_verts_get(Object *ob))[3]
void BKE_mesh_orco_verts_transform(Mesh *me, float (*orco)[3], int totvert, int invert)
{
float loc[3], size[3];
int a;
BKE_mesh_texspace_get(me->texcomesh ? me->texcomesh : me, loc, size);
if (invert) {
for (a = 0; a < totvert; a++) {
for (int a = 0; a < totvert; a++) {
float *co = orco[a];
madd_v3_v3v3v3(co, loc, co, size);
}
}
else {
for (a = 0; a < totvert; a++) {
for (int a = 0; a < totvert; a++) {
float *co = orco[a];
co[0] = (co[0] - loc[0]) / size[0];
co[1] = (co[1] - loc[1]) / size[1];
@ -1274,7 +1267,6 @@ int test_index_face(MFace *mface, CustomData *fdata, int mfindex, int nr)
Mesh *BKE_mesh_from_object(Object *ob)
{
if (ob == NULL) {
return NULL;
}
@ -1414,8 +1406,7 @@ void BKE_mesh_smooth_flag_set(Mesh *me, const bool use_smooth)
*/
int poly_find_loop_from_vert(const MPoly *poly, const MLoop *loopstart, uint vert)
{
int j;
for (j = 0; j < poly->totloop; j++, loopstart++) {
for (int j = 0; j < poly->totloop; j++, loopstart++) {
if (loopstart->v == vert) {
return j;
}
@ -1682,11 +1673,9 @@ void BKE_mesh_mselect_validate(Mesh *me)
*/
int BKE_mesh_mselect_find(Mesh *me, int index, int type)
{
int i;
BLI_assert(ELEM(type, ME_VSEL, ME_ESEL, ME_FSEL));
for (i = 0; i < me->totselect; i++) {
for (int i = 0; i < me->totselect; i++) {
if ((me->mselect[i].index == index) && (me->mselect[i].type == type)) {
return i;
}

View File

@ -154,12 +154,10 @@ int BKE_mesh_runtime_looptri_len(const Mesh *mesh)
/* This is a ported copy of dm_getLoopTriArray(dm). */
const MLoopTri *BKE_mesh_runtime_looptri_ensure(Mesh *mesh)
{
MLoopTri *looptri;
ThreadMutex *mesh_eval_mutex = (ThreadMutex *)mesh->runtime.eval_mutex;
BLI_mutex_lock(mesh_eval_mutex);
looptri = mesh->runtime.looptris.array;
MLoopTri *looptri = mesh->runtime.looptris.array;
if (looptri != NULL) {
BLI_assert(BKE_mesh_runtime_looptri_len(mesh) == mesh->runtime.looptris.len);
@ -180,8 +178,7 @@ void BKE_mesh_runtime_verttri_from_looptri(MVertTri *r_verttri,
const MLoopTri *looptri,
int looptri_num)
{
int i;
for (i = 0; i < looptri_num; i++) {
for (int i = 0; i < looptri_num; i++) {
r_verttri[i].tri[0] = mloop[looptri[i].tri[0]].v;
r_verttri[i].tri[1] = mloop[looptri[i].tri[1]].v;
r_verttri[i].tri[2] = mloop[looptri[i].tri[2]].v;

View File

@ -60,25 +60,30 @@ bool multires_reshape_assign_final_coords_from_ccg(const MultiresReshapeContext
CCG_grid_elem_co(&reshape_level_key, ccg_grid, x, y),
sizeof(float[3]));
if (reshape_level_key.has_mask) {
/* Assert about a non-NULL `grid_element.mask` may fail here, this code may be called
* from cleanup code during COW evaluation phase by depsgraph (e.g.
* `object_update_from_subsurf_ccg` call in `BKE_object_free_derived_caches`).
*
* `reshape_level_key.has_mask` is ultimately set from MultiRes modifier apply code
* (through `multires_as_ccg` -> `multires_ccg_settings_init`), when object is in sculpt
* mode only, and there is matching loop cdlayer.
*
* `grid_element.mask` is directly set from existing matching loop cdlayer during
* initialization of `MultiresReshapeContext` struct.
*
* Since ccg data is preserved during undos, we may end up with a state where there is no
* mask data in mesh loops' cdlayer, while ccg's `has_mask` is still set to true.
*/
// BLI_assert(grid_element.mask != NULL);
if (grid_element.mask != NULL) {
*grid_element.mask = *CCG_grid_elem_mask(&reshape_level_key, ccg_grid, x, y);
}
/* NOTE: The sculpt mode might have SubdivCCG's data out of sync from what is stored in
* the original object. This happens upon the following scenario:
*
* - User enters sculpt mode of the default cube object.
* - Sculpt mode creates new `layer`
* - User does some strokes.
* - User used undo until sculpt mode is exited.
*
* In an ideal world the sculpt mode will take care of keeping CustomData and CCG layers in
* sync by doing proper pushes to a local sculpt undo stack.
*
* Since the proper solution needs time to be implemented, consider the target object
* the source of truth of which data layers are to be updated during reshape. This means,
* for example, that if the undo system says object does not have paint mask layer, it is
* not to be updated.
*
* This is a fragile logic, and is only working correctly because the code path is only
* used by sculpt changes. In other usecases the code might not catch inconsistency and
* silently do wrong decision. */
/* NOTE: There is a known bug in Undo code that results in first Sculpt step
* after a Memfile one to never be undone (see T83806). This might be the root cause of
* this inconsistency. */
if (reshape_level_key.has_mask && grid_element.mask != NULL) {
*grid_element.mask = *CCG_grid_elem_mask(&reshape_level_key, ccg_grid, x, y);
}
}
}

View File

@ -342,9 +342,10 @@ static bool undosys_stack_push_main(UndoStack *ustack, const char *name, struct
CLOG_INFO(&LOG, 1, "'%s'", name);
bContext *C_temp = CTX_create();
CTX_data_main_set(C_temp, bmain);
bool ok = BKE_undosys_step_push_with_type(ustack, C_temp, name, BKE_UNDOSYS_TYPE_MEMFILE);
UndoPushReturn ret = BKE_undosys_step_push_with_type(
ustack, C_temp, name, BKE_UNDOSYS_TYPE_MEMFILE);
CTX_free(C_temp);
return ok;
return (ret & UNDO_PUSH_RET_SUCCESS);
}
void BKE_undosys_stack_init_from_main(UndoStack *ustack, struct Main *bmain)
@ -495,18 +496,21 @@ UndoStep *BKE_undosys_step_push_init(UndoStack *ustack, bContext *C, const char
/**
* \param C: Can be NULL from some callers if their encoding function doesn't need it
*/
bool BKE_undosys_step_push_with_type(UndoStack *ustack,
bContext *C,
const char *name,
const UndoType *ut)
UndoPushReturn BKE_undosys_step_push_with_type(UndoStack *ustack,
bContext *C,
const char *name,
const UndoType *ut)
{
UNDO_NESTED_ASSERT(false);
undosys_stack_validate(ustack, false);
bool is_not_empty = ustack->step_active != NULL;
UndoPushReturn retval = UNDO_PUSH_RET_FAILURE;
/* Might not be final place for this to be called - probably only want to call it from some
* undo handlers, not all of them? */
BKE_lib_override_library_main_operations_create(G_MAIN, false);
if (BKE_lib_override_library_main_operations_create(G_MAIN, false)) {
retval |= UNDO_PUSH_RET_OVERRIDE_CHANGED;
}
/* Remove all undos after (also when 'ustack->step_active == NULL'). */
while (ustack->steps.last != ustack->step_active) {
@ -558,7 +562,7 @@ bool BKE_undosys_step_push_with_type(UndoStack *ustack,
if (!undosys_step_encode(C, G_MAIN, ustack, us)) {
MEM_freeN(us);
undosys_stack_validate(ustack, true);
return false;
return retval;
}
ustack->step_active = us;
BLI_addtail(&ustack->steps, us);
@ -589,10 +593,10 @@ bool BKE_undosys_step_push_with_type(UndoStack *ustack,
}
undosys_stack_validate(ustack, true);
return true;
return (retval | UNDO_PUSH_RET_SUCCESS);
}
bool BKE_undosys_step_push(UndoStack *ustack, bContext *C, const char *name)
UndoPushReturn BKE_undosys_step_push(UndoStack *ustack, bContext *C, const char *name)
{
UNDO_NESTED_ASSERT(false);
const UndoType *ut = ustack->step_init ? ustack->step_init->type :

View File

@ -3421,7 +3421,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
case SPACE_OUTLINER: {
SpaceOutliner *space_outliner = (SpaceOutliner *)sl;
space_outliner->filter &= ~(SO_FILTER_UNUSED_1 | SO_FILTER_UNUSED_5 |
space_outliner->filter &= ~(SO_FILTER_CLEARED_1 | SO_FILTER_UNUSED_5 |
SO_FILTER_OB_STATE_SELECTABLE);
space_outliner->storeflag &= ~(SO_TREESTORE_UNUSED_1);
break;

View File

@ -229,7 +229,7 @@ enum {
UI_BUT_VALUE_CLEAR = 1 << 30,
/** RNA property of the button is overridden from linked reference data. */
UI_BUT_OVERRIDEN = 1u << 31u,
UI_BUT_OVERRIDDEN = 1u << 31u,
};
/* Default font size for normal text. */

View File

@ -1592,10 +1592,10 @@ void ui_but_override_flag(Main *bmain, uiBut *but)
bmain, &but->rnapoin, but->rnaprop, but->rnaindex);
if (override_status & RNA_OVERRIDE_STATUS_OVERRIDDEN) {
but->flag |= UI_BUT_OVERRIDEN;
but->flag |= UI_BUT_OVERRIDDEN;
}
else {
but->flag &= ~UI_BUT_OVERRIDEN;
but->flag &= ~UI_BUT_OVERRIDDEN;
}
}
@ -4537,7 +4537,7 @@ static uiBut *ui_def_but_rna(uiBlock *block,
block, type, retval, str, x, y, width, height, NULL, min, max, a1, a2, tip);
if (but->type == UI_BTYPE_NUM) {
/* Set default values, can be overriden later. */
/* Set default values, can be overridden later. */
UI_but_number_step_size_set(but, a1);
UI_but_number_precision_set(but, a2);
}

View File

@ -169,7 +169,7 @@ void ui_but_anim_decorate_update_from_flag(uiButDecorator *decorator_but)
else if (flag & UI_BUT_ANIMATED) {
but->icon = ICON_DECORATE_ANIMATE;
}
else if (flag & UI_BUT_OVERRIDEN) {
else if (flag & UI_BUT_OVERRIDDEN) {
but->icon = ICON_DECORATE_OVERRIDE;
}
else {

View File

@ -784,7 +784,7 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but)
/* Override Operators */
uiItemS(layout);
if (but->flag & UI_BUT_OVERRIDEN) {
if (but->flag & UI_BUT_OVERRIDDEN) {
if (is_array_component) {
#if 0 /* Disabled for now. */
ot = WM_operatortype_find("UI_OT_override_type_set_button", false);

View File

@ -2540,7 +2540,7 @@ static const uchar *widget_color_blend_from_flags(const uiWidgetStateColors *wco
if (state & UI_BUT_DRIVEN) {
return wcol_state->inner_driven_sel;
}
if (state & UI_BUT_OVERRIDEN) {
if (state & UI_BUT_OVERRIDDEN) {
return wcol_state->inner_overridden_sel;
}
return NULL;
@ -3824,7 +3824,7 @@ static void widget_swatch(
ui_but_v3_get(but, col);
if ((state & (UI_BUT_ANIMATED | UI_BUT_ANIMATED_KEY | UI_BUT_DRIVEN | UI_BUT_OVERRIDEN |
if ((state & (UI_BUT_ANIMATED | UI_BUT_ANIMATED_KEY | UI_BUT_DRIVEN | UI_BUT_OVERRIDDEN |
UI_BUT_REDALERT)) ||
(but->drawflag & UI_BUT_ANIMATED_CHANGED)) {
/* draw based on state - color for keyed etc */

View File

@ -3611,7 +3611,7 @@ static int spacedata_cleanup_exec(bContext *C, wmOperator *op)
static void SCREEN_OT_spacedata_cleanup(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Cleanup Space Data";
ot->name = "Clean Up Space Data";
ot->description = "Remove unused settings for invisible editors";
ot->idname = "SCREEN_OT_spacedata_cleanup";

View File

@ -493,7 +493,7 @@ static bool parent_clear_poll(bContext *C,
case ID_OB:
return ELEM(tselem->type, TSE_MODIFIER_BASE, TSE_CONSTRAINT_BASE);
case ID_GR:
return event->shift;
return event->shift || ELEM(tselem->type, TSE_LIBRARY_OVERRIDE_BASE);
default:
return true;
}

View File

@ -2180,6 +2180,10 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
data.icon = ICON_MODIFIER_DATA;
data.drag_id = tselem->id;
break;
case TSE_LIBRARY_OVERRIDE_BASE:
case TSE_LIBRARY_OVERRIDE:
data.icon = ICON_LIBRARY_DATA_OVERRIDE;
break;
case TSE_LINKED_OB:
data.icon = ICON_OBJECT_DATA;
break;

View File

@ -331,7 +331,8 @@ static void do_item_rename(ARegion *region,
TSE_POSEGRP_BASE,
TSE_R_LAYER_BASE,
TSE_SCENE_COLLECTION_BASE,
TSE_VIEW_COLLECTION_BASE)) {
TSE_VIEW_COLLECTION_BASE,
TSE_LIBRARY_OVERRIDE_BASE)) {
BKE_report(reports, RPT_WARNING, "Cannot edit builtin name");
}
else if (ELEM(tselem->type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP)) {

View File

@ -66,6 +66,7 @@
#include "BKE_idtype.h"
#include "BKE_layer.h"
#include "BKE_lib_id.h"
#include "BKE_lib_override.h"
#include "BKE_main.h"
#include "BKE_modifier.h"
#include "BKE_outliner_treehash.h"
@ -640,6 +641,30 @@ static void outliner_add_object_contents(SpaceOutliner *space_outliner,
}
}
static void outliner_add_library_override_contents(SpaceOutliner *soops, TreeElement *te, ID *id)
{
if (!id->override_library) {
return;
}
PointerRNA idpoin;
RNA_id_pointer_create(id, &idpoin);
PointerRNA override_ptr;
PropertyRNA *override_prop;
int index = 0;
LISTBASE_FOREACH (IDOverrideLibraryProperty *, op, &id->override_library->properties) {
if (!BKE_lib_override_rna_property_find(&idpoin, op, &override_ptr, &override_prop)) {
BLI_assert(false);
continue;
}
TreeElement *ten = outliner_add_element(
soops, &te->subtree, id, te, TSE_LIBRARY_OVERRIDE, index++);
ten->name = RNA_property_ui_name(override_prop);
}
}
/* Can be inlined if necessary. */
static void outliner_add_id_contents(SpaceOutliner *space_outliner,
TreeElement *te,
@ -903,6 +928,17 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner,
default:
break;
}
const bool lib_overrides_visible = !SUPPORT_FILTER_OUTLINER(space_outliner) ||
((space_outliner->filter & SO_FILTER_NO_LIB_OVERRIDE) == 0);
if (lib_overrides_visible && ID_IS_OVERRIDE_LIBRARY(id)) {
TreeElement *ten = outliner_add_element(
space_outliner, &te->subtree, id, te, TSE_LIBRARY_OVERRIDE_BASE, 0);
ten->name = IFACE_("Library Overrides");
outliner_add_library_override_contents(space_outliner, ten, id);
}
}
/**

View File

@ -112,6 +112,13 @@ static void outliner_main_region_listener(wmWindow *UNUSED(win),
/* context changes */
switch (wmn->category) {
case NC_WM:
switch (wmn->data) {
case ND_LIB_OVERRIDE_CHANGED:
ED_region_tag_redraw(region);
break;
}
break;
case NC_SCENE:
switch (wmn->data) {
case ND_OB_ACTIVE:
@ -152,8 +159,6 @@ static void outliner_main_region_listener(wmWindow *UNUSED(win),
case NC_OBJECT:
switch (wmn->data) {
case ND_TRANSFORM:
/* transform doesn't change outliner data */
break;
case ND_BONE_ACTIVE:
case ND_BONE_SELECT:
case ND_DRAW:

View File

@ -145,12 +145,14 @@ void ED_undo_push(bContext *C, const char *str)
}
}
UndoPushReturn push_retval;
/* Only apply limit if this is the last undo step. */
if (wm->undo_stack->step_active && (wm->undo_stack->step_active->next == NULL)) {
BKE_undosys_stack_limit_steps_and_memory(wm->undo_stack, steps - 1, 0);
}
BKE_undosys_step_push(wm->undo_stack, C, str);
push_retval = BKE_undosys_step_push(wm->undo_stack, C, str);
if (U.undomemory != 0) {
const size_t memory_limit = (size_t)U.undomemory * 1024 * 1024;
@ -160,6 +162,10 @@ void ED_undo_push(bContext *C, const char *str)
if (CLOG_CHECK(&LOG, 1)) {
BKE_undosys_print(wm->undo_stack);
}
if (push_retval & UNDO_PUSH_RET_OVERRIDE_CHANGED) {
WM_main_add_notifier(NC_WM | ND_LIB_OVERRIDE_CHANGED, NULL);
}
}
/**

View File

@ -117,6 +117,8 @@ enum {
#define TSE_SCENE_OBJECTS_BASE 41
#define TSE_GPENCIL_EFFECT_BASE 42
#define TSE_GPENCIL_EFFECT 43
#define TSE_LIBRARY_OVERRIDE_BASE 44
#define TSE_LIBRARY_OVERRIDE 45
/* Check whether given TreeStoreElem should have a real ID in its ->id member. */
#define TSE_IS_REAL_ID(_tse) \

View File

@ -305,8 +305,9 @@ typedef enum eSpaceOutliner_Flag {
/* SpaceOutliner.filter */
typedef enum eSpaceOutliner_Filter {
SO_FILTER_SEARCH = (1 << 0), /* Run-time flag. */
SO_FILTER_UNUSED_1 = (1 << 1), /* cleared */
SO_FILTER_SEARCH = (1 << 0), /* Run-time flag. */
SO_FILTER_CLEARED_1 = (1 << 1),
SO_FILTER_NO_LIB_OVERRIDE = SO_FILTER_CLEARED_1, /* re-use */
SO_FILTER_NO_OBJECT = (1 << 2),
SO_FILTER_NO_OB_CONTENT = (1 << 3), /* Not only mesh, but modifiers, constraints, ... */
SO_FILTER_NO_CHILDREN = (1 << 4),
@ -339,7 +340,7 @@ typedef enum eSpaceOutliner_Filter {
#define SO_FILTER_ANY \
(SO_FILTER_NO_OB_CONTENT | SO_FILTER_NO_CHILDREN | SO_FILTER_OB_TYPE | SO_FILTER_OB_STATE | \
SO_FILTER_NO_COLLECTION)
SO_FILTER_NO_COLLECTION | SO_FILTER_NO_LIB_OVERRIDE)
/* SpaceOutliner.filter_state */
typedef enum eSpaceOutliner_StateFilter {

View File

@ -60,7 +60,7 @@ const EnumPropertyItem rna_enum_fmodifier_type_items[] = {
"Envelope",
"Reshape F-Curve values, e.g. change amplitude of movements"},
{FMODIFIER_TYPE_CYCLES, "CYCLES", 0, "Cycles", "Cyclic extend/repeat keyframe sequence"},
{FMODIFIER_TYPE_NOISE, "NOISE", 0, "Noise", "Add pseudorandom noise on top of F-Curves"},
{FMODIFIER_TYPE_NOISE, "NOISE", 0, "Noise", "Add pseudo-random noise on top of F-Curves"},
/*{FMODIFIER_TYPE_FILTER, "FILTER", 0, "Filter", ""},*/ /* FIXME: not implemented yet! */
/*{FMODIFIER_TYPE_PYTHON, "PYTHON", 0, "Python", ""},*/ /* FIXME: not implemented yet! */
{FMODIFIER_TYPE_LIMITS,

View File

@ -3442,6 +3442,13 @@ static void rna_def_space_outliner(BlenderRNA *brna)
RNA_def_property_enum_items(prop, rna_enum_id_type_items);
RNA_def_property_ui_text(prop, "Filter by Type", "Data-block type to show");
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_ID);
prop = RNA_def_property(srna, "use_filter_lib_override", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "filter", SO_FILTER_NO_LIB_OVERRIDE);
RNA_def_property_ui_text(prop,
"Show Library Overrides",
"For libraries with overrides created, show the overridden values");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
}
static void rna_def_space_view3d_shading(BlenderRNA *brna)

View File

@ -1448,7 +1448,7 @@ static void rna_def_panel(BlenderRNA *brna)
RNA_def_property_string_sdna(prop, NULL, "type->parent_id");
RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
RNA_def_property_ui_text(
prop, "Parent ID Name", "If this is set, the panel becomes a subpanel");
prop, "Parent ID Name", "If this is set, the panel becomes a sub-panel");
prop = RNA_def_property(srna, "bl_ui_units_x", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "type->ui_units_x");

View File

@ -2455,7 +2455,7 @@ static void rna_def_userdef_theme_space_graph(BlenderRNA *brna)
prop = RNA_def_property(srna, "dopesheet_subchannel", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "ds_subchannel");
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Dope Sheet Subchannel", "");
RNA_def_property_ui_text(prop, "Dope Sheet Sub-channel", "");
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
prop = RNA_def_property(srna, "channel_group", PROP_FLOAT, PROP_COLOR_GAMMA);
@ -3334,7 +3334,7 @@ static void rna_def_userdef_theme_space_action(BlenderRNA *brna)
prop = RNA_def_property(srna, "dopesheet_subchannel", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "ds_subchannel");
RNA_def_property_array(prop, 4);
RNA_def_property_ui_text(prop, "Dope Sheet Subchannel", "");
RNA_def_property_ui_text(prop, "Dope Sheet Sub-channel", "");
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
prop = RNA_def_property(srna, "channels", PROP_FLOAT, PROP_COLOR_GAMMA);

View File

@ -82,40 +82,42 @@ static void get_instanced_data__collection(
bke::PersistentCollectionHandle collection_handle =
params.get_input<bke::PersistentCollectionHandle>("Collection");
Collection *collection = params.handle_map().lookup(collection_handle);
if (collection != nullptr) {
const bool use_whole_collection = node.custom2 == 0;
if (use_whole_collection) {
if (collection == nullptr) {
return;
}
const bool use_whole_collection = node.custom2 == 0;
if (use_whole_collection) {
InstancedData instance;
instance.type = INSTANCE_DATA_TYPE_COLLECTION;
instance.data.collection = collection;
r_instances_data.fill(instance);
}
else {
Vector<InstancedData> possible_instances;
/* Direct child objects are instanced as objects. */
LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) {
Object *object = cob->ob;
InstancedData instance;
instance.type = INSTANCE_DATA_TYPE_OBJECT;
instance.data.object = object;
possible_instances.append(instance);
}
/* Direct child collections are instanced as collections. */
LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
Collection *child_collection = child->collection;
InstancedData instance;
instance.type = INSTANCE_DATA_TYPE_COLLECTION;
instance.data.collection = collection;
r_instances_data.fill(instance);
instance.data.collection = child_collection;
possible_instances.append(instance);
}
else {
Vector<InstancedData> possible_instances;
/* Direct child objects are instanced as objects. */
LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) {
Object *object = cob->ob;
InstancedData instance;
instance.type = INSTANCE_DATA_TYPE_OBJECT;
instance.data.object = object;
possible_instances.append(instance);
}
/* Direct child collections are instanced as collections. */
LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
Collection *child_collection = child->collection;
InstancedData instance;
instance.type = INSTANCE_DATA_TYPE_COLLECTION;
instance.data.collection = child_collection;
possible_instances.append(instance);
}
if (!possible_instances.is_empty()) {
const int seed = params.get_input<int>("Seed");
Array<uint32_t> ids = get_geometry_element_ids_as_uints(component, ATTR_DOMAIN_POINT);
for (const int i : r_instances_data.index_range()) {
const int index = BLI_hash_int_2d(ids[i], seed) % possible_instances.size();
r_instances_data[i] = possible_instances[index];
}
if (!possible_instances.is_empty()) {
const int seed = params.get_input<int>("Seed");
Array<uint32_t> ids = get_geometry_element_ids_as_uints(component, ATTR_DOMAIN_POINT);
for (const int i : r_instances_data.index_range()) {
const int index = BLI_hash_int_2d(ids[i], seed) % possible_instances.size();
r_instances_data[i] = possible_instances[index];
}
}
}

View File

@ -312,6 +312,7 @@ typedef struct wmNotifier {
#define ND_JOB (5 << 16)
#define ND_UNDO (6 << 16)
#define ND_XR_DATA_CHANGED (7 << 16)
#define ND_LIB_OVERRIDE_CHANGED (8 << 16)
/* NC_SCREEN */
#define ND_LAYOUTBROWSE (1 << 16)

View File

@ -2263,7 +2263,7 @@ static int wm_handler_fileselect_do(bContext *C,
continue;
}
if (ctx_area->full) {
if (file_area->full) {
/* Users should not be able to maximize/fullscreen an area in a temporary screen. So if
* there's a maximized file browser in a temporary screen, it was likely opened by
* #EVT_FILESELECT_FULL_OPEN. */