From e79d9048f34b0b213780db5dadc472d4d04a8b56 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Wed, 29 Nov 2017 17:03:52 +0100 Subject: ID Static Override: add basic generic UI tools to control override of properties. --- .../blender/editors/interface/interface_handlers.c | 58 +++++- source/blender/editors/interface/interface_ops.c | 212 +++++++++++++++++++++ 2 files changed, 265 insertions(+), 5 deletions(-) diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 2e9dae36d96..a4ce0e2f4a8 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -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 */ diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c index 5913f1c48f5..1866cebcbb8 100644 --- a/source/blender/editors/interface/interface_ops.c +++ b/source/blender/editors/interface/interface_ops.c @@ -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); -- cgit v1.2.3