ID Static Override: add basic generic UI tools to control override of properties.

This commit is contained in:
Bastien Montagne 2017-11-29 17:03:52 +01:00
parent e36b5f004d
commit 0007873645
2 changed files with 265 additions and 5 deletions

View File

@ -6759,6 +6759,8 @@ static bool ui_but_menu(bContext *C, uiBut *but)
MenuType *mt = WM_menutype_find("WM_MT_button_context", true);
bool is_array, is_array_component;
uiStringInfo label = {BUT_GET_LABEL, NULL};
wmOperatorType *ot;
PointerRNA op_ptr;
/* if ((but->rnapoin.data && but->rnaprop) == 0 && but->optype == NULL)*/
/* return 0;*/
@ -6785,11 +6787,11 @@ static bool ui_but_menu(bContext *C, uiBut *but)
const PropertySubType subtype = RNA_property_subtype(prop);
bool is_anim = RNA_property_animateable(ptr, prop);
bool is_editable = RNA_property_editable(ptr, prop);
bool is_overridable;
/*bool is_idprop = RNA_property_is_idprop(prop);*/ /* XXX does not work as expected, not strictly needed */
bool is_set = RNA_property_is_set(ptr, prop);
/* Set the (button_pointer, button_prop) and pointer data for Python access to the hovered ui element. */
uiLayoutSetContextFromBut(layout, but);
RNA_property_override_status(ptr, prop, -1, &is_overridable, NULL, NULL, NULL);
/* second slower test, saved people finding keyframe items in menus when its not possible */
if (is_anim)
@ -6918,11 +6920,57 @@ static bool ui_but_menu(bContext *C, uiBut *but)
ICON_NONE, "ANIM_OT_keyingset_button_remove");
}
}
if (is_overridable) {
/* Override Operators */
uiItemS(layout);
if (but->flag & UI_BUT_OVERRIDEN) {
if (is_array_component) {
ot = WM_operatortype_find("UI_OT_override_type_set_button", false);
uiItemFullO_ptr(layout, ot, "Overrides Type", ICON_NONE,
NULL, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
RNA_boolean_set(&op_ptr, "all", true);
uiItemFullO_ptr(layout, ot, "Single Override Type", ICON_NONE,
NULL, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
RNA_boolean_set(&op_ptr, "all", false);
uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Remove Overrides"),
ICON_X, "UI_OT_override_remove_button", "all", true);
uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Remove Single Override"),
ICON_X, "UI_OT_override_remove_button", "all", false);
}
else {
uiItemFullO(layout, "UI_OT_override_type_set_button", "Override Type", ICON_NONE,
NULL, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
RNA_boolean_set(&op_ptr, "all", false);
uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Remove Override"),
ICON_X, "UI_OT_override_remove_button", "all", true);
}
}
else {
if (is_array_component) {
ot = WM_operatortype_find("UI_OT_override_type_set_button", false);
uiItemFullO_ptr(layout, ot, "Define Overrides", ICON_NONE,
NULL, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
RNA_boolean_set(&op_ptr, "all", true);
uiItemFullO_ptr(layout, ot, "Define Single Override", ICON_NONE,
NULL, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
RNA_boolean_set(&op_ptr, "all", false);
}
else {
uiItemFullO(layout, "UI_OT_override_type_set_button", "Define Override", ICON_NONE,
NULL, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
RNA_boolean_set(&op_ptr, "all", false);
}
}
}
uiItemS(layout);
/* Property Operators */
/* Copy Property Value
* Paste Property Value */

View File

@ -46,6 +46,7 @@
#include "BKE_layer.h"
#include "BKE_screen.h"
#include "BKE_global.h"
#include "BKE_library_override.h"
#include "BKE_node.h"
#include "BKE_text.h" /* for UI_OT_reports_to_text */
#include "BKE_report.h"
@ -452,6 +453,215 @@ static void UI_OT_unuse_property_button(wmOperatorType *ot)
ot->flag = OPTYPE_UNDO;
}
/* Note that we use different values for UI/UX than 'real' override operations, user does not care
* whether it's added or removed for the differential operation e.g. */
enum {
UIOverride_Type_NOOP = 0,
UIOverride_Type_Replace = 1,
UIOverride_Type_Difference = 2, /* Add/subtract */
UIOverride_Type_Factor = 3, /* Multiply */
/* TODO: should/can we expose insert/remove ones for collections? Doubt it... */
};
static EnumPropertyItem override_type_items[] = {
{UIOverride_Type_NOOP, "NOOP", 0, "NoOp",
"'No-Operation', place holder preventing automatic override to ever affect the property"},
{UIOverride_Type_Replace, "REPLACE", 0, "Replace", "Completely replace value from linked data by local one"},
{UIOverride_Type_Difference, "DIFFERENCE", 0, "Difference", "Store difference to linked data value"},
{UIOverride_Type_Factor, "FACTOR", 0, "Factor", "Store factor to linked data value (useful e.g. for scale)"},
{0, NULL, 0, NULL, NULL}
};
static int override_type_set_button_poll(bContext *C)
{
PointerRNA ptr;
PropertyRNA *prop;
int index;
bool is_overridable;
UI_context_active_but_prop_get(C, &ptr, &prop, &index);
RNA_property_override_status(&ptr, prop, index, &is_overridable, NULL, NULL, NULL);
return (ptr.data && prop && is_overridable);
}
static int override_type_set_button_exec(bContext *C, wmOperator *op)
{
PointerRNA ptr;
PropertyRNA *prop;
int index;
bool created;
const bool all = RNA_boolean_get(op->ptr, "all");
const int op_type = RNA_enum_get(op->ptr, "type");
short operation;
switch(op_type) {
case UIOverride_Type_NOOP:
operation = IDOVERRIDESTATIC_OP_NOOP;
break;
case UIOverride_Type_Replace:
operation = IDOVERRIDESTATIC_OP_REPLACE;
break;
case UIOverride_Type_Difference:
operation = IDOVERRIDESTATIC_OP_ADD; /* override code will automatically switch to subtract if needed. */
break;
case UIOverride_Type_Factor:
operation = IDOVERRIDESTATIC_OP_MULTIPLY;
break;
default:
operation = IDOVERRIDESTATIC_OP_REPLACE;
BLI_assert(0);
break;
}
/* try to reset the nominated setting to its default value */
UI_context_active_but_prop_get(C, &ptr, &prop, &index);
BLI_assert(ptr.id.data != NULL);
if (all) {
index = -1;
}
IDOverrideStaticPropertyOperation *opop = RNA_property_override_property_operation_get(
&ptr, prop, operation, index, true, NULL, &created);
if (!created) {
opop->operation = operation;
}
return operator_button_property_finish(C, &ptr, prop);
}
static int override_type_set_button_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
return WM_menu_invoke_ex(C, op, WM_OP_INVOKE_DEFAULT);
}
static void UI_OT_override_type_set_button(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Define Override Type";
ot->idname = "UI_OT_override_type_set_button";
ot->description = "Create an override operation, or set the type of an existing one";
/* callbacks */
ot->poll = override_type_set_button_poll;
ot->exec = override_type_set_button_exec;
ot->invoke = override_type_set_button_invoke;
/* flags */
ot->flag = OPTYPE_UNDO;
/* properties */
RNA_def_boolean(ot->srna, "all", 1, "All", "Reset to default values all elements of the array");
ot->prop = RNA_def_enum(ot->srna, "type", override_type_items, UIOverride_Type_Replace,
"Type", "Type of override operation");
/* TODO: add itemf callback, not all aoptions are available for all data types... */
}
static int override_remove_button_poll(bContext *C)
{
PointerRNA ptr;
PropertyRNA *prop;
int index;
bool is_overridden;
UI_context_active_but_prop_get(C, &ptr, &prop, &index);
RNA_property_override_status(&ptr, prop, index, NULL, &is_overridden, NULL, NULL);
return (ptr.data && ptr.id.data && prop && is_overridden);
}
static int override_remove_button_exec(bContext *C, wmOperator *op)
{
PointerRNA ptr, id_refptr, src;
PropertyRNA *prop;
int index;
const bool all = RNA_boolean_get(op->ptr, "all");
/* try to reset the nominated setting to its default value */
UI_context_active_but_prop_get(C, &ptr, &prop, &index);
ID *id = ptr.id.data;
IDOverrideStaticProperty *oprop = RNA_property_override_property_find(&ptr, prop);
BLI_assert(oprop != NULL);
BLI_assert(id != NULL && id->override_static != NULL);
const bool is_template = (id->override_static->reference == NULL);
/* We need source (i.e. linked data) to restore values of deleted overrides...
* If this is an override template, we obviously do not need to restore anything. */
if (!is_template) {
RNA_id_pointer_create(id->override_static->reference, &id_refptr);
if (!RNA_path_resolve(&id_refptr, oprop->rna_path, &src, NULL)) {
BLI_assert(0 && "Failed to create matching source (linked data) RNA pointer");
}
}
if (!all && index != -1) {
bool is_strict_find;
/* Remove override operation for given item, add singular operations for the other items as needed. */
IDOverrideStaticPropertyOperation *opop = BKE_override_static_property_operation_find(
oprop, NULL, NULL, index, index, false, &is_strict_find);
BLI_assert(opop != NULL);
if (!is_strict_find) {
/* No specific override operation, we have to get generic one,
* and create item-specific override operations for all but given index, before removing generic one. */
for (int idx = RNA_property_array_length(&ptr, prop); idx--; ) {
if (idx != index) {
BKE_override_static_property_operation_get(oprop, opop->operation, NULL, NULL, idx, idx, true, NULL, NULL);
}
}
}
BKE_override_static_property_operation_delete(oprop, opop);
if (!is_template) {
RNA_property_copy(&ptr, &src, prop, index);
}
if (BLI_listbase_is_empty(&oprop->operations)) {
BKE_override_static_property_delete(id->override_static, oprop);
}
}
else {
/* Just remove whole generic override operation of this property. */
BKE_override_static_property_delete(id->override_static, oprop);
if (!is_template) {
RNA_property_copy(&ptr, &src, prop, -1);
}
}
return operator_button_property_finish(C, &ptr, prop);
}
static void UI_OT_override_remove_button(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Remove Override";
ot->idname = "UI_OT_override_remove_button";
ot->description = "Remove an override operation";
/* callbacks */
ot->poll = override_remove_button_poll;
ot->exec = override_remove_button_exec;
/* flags */
ot->flag = OPTYPE_UNDO;
/* properties */
RNA_def_boolean(ot->srna, "all", 1, "All", "Reset to default values all elements of the array");
}
/* Copy To Selected Operator ------------------------ */
bool UI_context_copy_to_selected_list(
@ -1243,6 +1453,8 @@ void ED_operatortypes_ui(void)
WM_operatortype_append(UI_OT_unset_property_button);
WM_operatortype_append(UI_OT_use_property_button);
WM_operatortype_append(UI_OT_unuse_property_button);
WM_operatortype_append(UI_OT_override_type_set_button);
WM_operatortype_append(UI_OT_override_remove_button);
WM_operatortype_append(UI_OT_copy_to_selected_button);
WM_operatortype_append(UI_OT_reports_to_textblock); /* XXX: temp? */
WM_operatortype_append(UI_OT_drop_color);