diff --git a/scripts/startup/bl_ui/space_view3d.py b/scripts/startup/bl_ui/space_view3d.py index b60988353fc..5d26059384c 100644 --- a/scripts/startup/bl_ui/space_view3d.py +++ b/scripts/startup/bl_ui/space_view3d.py @@ -7854,42 +7854,63 @@ class VIEW3D_PT_sculpt_automasking(Panel): layout = self.layout tool_settings = context.tool_settings + brush = tool_settings.sculpt.brush sculpt = tool_settings.sculpt layout.label(text="Auto-Masking") col = layout.column(align=True) - col.prop(sculpt, "use_automasking_topology", text="Topology") - col.prop(sculpt, "use_automasking_face_sets", text="Face Sets") + sub = col.column() + sub.active = not brush.use_automasking_topology + sub.prop(sculpt, "use_automasking_topology", text="Topology") + + sub = col.column() + sub.active = not brush.use_automasking_face_sets + sub.prop(sculpt, "use_automasking_face_sets", text="Face Sets") col.separator() col = layout.column(align=True) - col.prop(sculpt, "use_automasking_boundary_edges", text="Mesh Boundary") - col.prop(sculpt, "use_automasking_boundary_face_sets", text="Face Sets Boundary") + sub = col.column() + sub.active = not brush.use_automasking_boundary_edges + sub.prop(sculpt, "use_automasking_boundary_edges", text="Mesh Boundary") + + sub = col.column() + sub.active = not brush.use_automasking_boundary_face_sets + sub.prop(sculpt, "use_automasking_boundary_face_sets", text="Face Sets Boundary") if sculpt.use_automasking_boundary_edges or sculpt.use_automasking_boundary_face_sets: - col.prop(sculpt.brush, "automasking_boundary_edges_propagation_steps") + sub = col.column() + sub.active = not brush.use_automasking_boundary_edges or not brush.use_automasking_boundary_face_sets + sub.prop(sculpt.brush, "automasking_boundary_edges_propagation_steps") col.separator() col = layout.column(align=True) row = col.row() - row.prop(sculpt, "use_automasking_cavity", text="Cavity") + subrow = row.column(align=True) + subrow.active = not brush.use_automasking_cavity and not brush.use_automasking_cavity_inverted + subrow.prop(sculpt, "use_automasking_cavity", text="Cavity") is_cavity_active = sculpt.use_automasking_cavity or sculpt.use_automasking_cavity_inverted if is_cavity_active: - props = row.operator("sculpt.mask_from_cavity", text="Create Mask") + subrow = row.column(align=True) + subrow.enabled = not brush.use_automasking_cavity and not brush.use_automasking_cavity_inverted + props = subrow.operator("sculpt.scene_mask_from_cavity", text="Create Mask") props.settings_source = "SCENE" - col.prop(sculpt, "use_automasking_cavity_inverted", text="Cavity (inverted)") + subcol = col.column(align=True) + subcol.active = not brush.use_automasking_cavity and not brush.use_automasking_cavity_inverted + subcol.prop(sculpt, "use_automasking_cavity_inverted", text="Cavity (inverted)") if is_cavity_active: col = layout.column(align=True) + col.active = not brush.use_automasking_cavity_inverted and not brush.use_automasking_cavity col.prop(sculpt, "automasking_cavity_factor", text="Factor") col.prop(sculpt, "automasking_cavity_blur_steps", text="Blur") col = layout.column() + col.active = not brush.use_automasking_cavity_inverted and not brush.use_automasking_cavity col.prop(sculpt, "use_automasking_custom_cavity_curve", text="Custom Curve") if sculpt.use_automasking_custom_cavity_curve: @@ -7898,20 +7919,23 @@ class VIEW3D_PT_sculpt_automasking(Panel): col.separator() col = layout.column(align=True) + col.active = not brush.use_automasking_view_normal col.prop(sculpt, "use_automasking_view_normal", text="View Normal") if sculpt.use_automasking_view_normal: col.prop(sculpt, "use_automasking_view_occlusion", text="Occlusion") subcol = col.column(align=True) subcol.active = not sculpt.use_automasking_view_occlusion - subcol.prop(sculpt, "automasking_view_normal_limit", text="Limit") - subcol.prop(sculpt, "automasking_view_normal_falloff", text="Falloff") + subcol.prop(sculpt, "automasking_scene_view_normal_limit", text="Limit") + subcol.prop(sculpt, "automasking_scene_view_normal_falloff", text="Falloff") col = layout.column() + col.active = not brush.use_automasking_start_normal col.prop(sculpt, "use_automasking_start_normal", text="Area Normal") if sculpt.use_automasking_start_normal: col = layout.column(align=True) + col.active = not brush.use_automasking_start_normal col.prop(sculpt, "automasking_start_normal_limit", text="Limit") col.prop(sculpt, "automasking_start_normal_falloff", text="Falloff") diff --git a/source/blender/blenkernel/intern/paint.cc b/source/blender/blenkernel/intern/paint.cc index 943f6902868..dcced0e6f9b 100644 --- a/source/blender/blenkernel/intern/paint.cc +++ b/source/blender/blenkernel/intern/paint.cc @@ -2078,6 +2078,8 @@ void BKE_sculpt_toolsettings_data_ensure(Scene *scene) sd->automasking_start_normal_limit = 20.0f / 180.0f * M_PI; sd->automasking_start_normal_falloff = 0.25f; + sd->automasking_scene_view_normal_limit = 90.0f / 180.0f * M_PI; + sd->automasking_scene_view_normal_falloff = 0.25f; sd->automasking_view_normal_limit = 90.0f / 180.0f * M_PI; sd->automasking_view_normal_falloff = 0.25f; } diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index de3169d045b..0842d8432c0 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -896,6 +896,7 @@ void UI_but_dragflag_enable(uiBut *but, int flag); void UI_but_dragflag_disable(uiBut *but, int flag); void UI_but_disable(uiBut *but, const char *disabled_hint); +void UI_but_set_disabled_hint(uiBut *but, const char *disabled_hint); void UI_but_type_set_menu_from_pulldown(uiBut *but); diff --git a/source/blender/editors/interface/interface.cc b/source/blender/editors/interface/interface.cc index 94eeab27159..9ea07d1ae13 100644 --- a/source/blender/editors/interface/interface.cc +++ b/source/blender/editors/interface/interface.cc @@ -4715,6 +4715,10 @@ static uiBut *ui_def_but_rna(uiBlock *block, UI_but_disable(but, info); } + if (but->rnapoin.data && RNA_property_is_inactive_info(&but->rnapoin, prop, &info)) { + UI_but_set_disabled_hint(but, info); + } + if (proptype == PROP_POINTER) { /* If the button shows an ID, automatically set it as focused in context so operators can * access it. */ @@ -5904,10 +5908,8 @@ void UI_but_dragflag_disable(uiBut *but, int flag) but->dragflag &= ~flag; } -void UI_but_disable(uiBut *but, const char *disabled_hint) +void UI_but_set_disabled_hint(uiBut *but, const char *disabled_hint) { - UI_but_flag_enable(but, UI_BUT_DISABLED); - /* Only one disabled hint at a time currently. Don't override the previous one here. */ if (but->disabled_info && but->disabled_info[0]) { return; @@ -5916,6 +5918,13 @@ void UI_but_disable(uiBut *but, const char *disabled_hint) but->disabled_info = disabled_hint; } +void UI_but_disable(uiBut *but, const char *disabled_hint) +{ + UI_but_flag_enable(but, UI_BUT_DISABLED); + + UI_but_set_disabled_hint(but, disabled_hint); +} + void UI_but_type_set_menu_from_pulldown(uiBut *but) { BLI_assert(but->type == UI_BTYPE_PULLDOWN); diff --git a/source/blender/editors/interface/interface_region_tooltip.cc b/source/blender/editors/interface/interface_region_tooltip.cc index fb87d940506..f67bd1b405b 100644 --- a/source/blender/editors/interface/interface_region_tooltip.cc +++ b/source/blender/editors/interface/interface_region_tooltip.cc @@ -897,8 +897,8 @@ static uiTooltipData *ui_tooltip_data_from_button_or_extra_icon(bContext *C, MEM_freeN(str); } - /* Button is disabled, we may be able to tell user why. */ - if ((but->flag & UI_BUT_DISABLED) || extra_icon) { + /* Button is disabled or set to inactive, we may be able to tell user why. */ + if ((but->flag & UI_BUT_DISABLED) || (but->flag & UI_BUT_INACTIVE) || extra_icon) { const char *disabled_msg = nullptr; bool disabled_msg_free = false; diff --git a/source/blender/editors/sculpt_paint/sculpt.cc b/source/blender/editors/sculpt_paint/sculpt.cc index 077a16cf4df..cbe212c5074 100644 --- a/source/blender/editors/sculpt_paint/sculpt.cc +++ b/source/blender/editors/sculpt_paint/sculpt.cc @@ -4273,6 +4273,19 @@ bool SCULPT_mode_poll(bContext *C) return ob && ob->mode & OB_MODE_SCULPT; } +bool SCULPT_mode_poll_cavity_automask(bContext *C) +{ + ToolSettings *tool_settings = CTX_data_tool_settings(C); + int automasking_flags = tool_settings->sculpt->paint.brush->automasking_flags; + + if (SCULPT_mode_poll(C) && !(automasking_flags & BRUSH_AUTOMASKING_CAVITY_ALL)) { + return true; + } else { + CTX_wm_operator_poll_msg_set(C, "The active brush already has the same auto-masking enabled."); + return false; + } +} + bool SCULPT_mode_poll_view3d(bContext *C) { return (SCULPT_mode_poll(C) && CTX_wm_region_view3d(C)); diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.hh b/source/blender/editors/sculpt_paint/sculpt_intern.hh index fae073233a6..3659eb010de 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.hh +++ b/source/blender/editors/sculpt_paint/sculpt_intern.hh @@ -843,6 +843,7 @@ struct ExpandCache { * \{ */ bool SCULPT_mode_poll(bContext *C); +bool SCULPT_mode_poll_cavity_automask(bContext *C); bool SCULPT_mode_poll_view3d(bContext *C); /** * Checks for a brush, not just sculpt mode. diff --git a/source/blender/editors/sculpt_paint/sculpt_ops.cc b/source/blender/editors/sculpt_paint/sculpt_ops.cc index 9a975fb5ced..20c4b9c5e34 100644 --- a/source/blender/editors/sculpt_paint/sculpt_ops.cc +++ b/source/blender/editors/sculpt_paint/sculpt_ops.cc @@ -1290,6 +1290,13 @@ static void SCULPT_OT_mask_from_cavity(wmOperatorType *ot) RNA_def_boolean(ot->srna, "invert", false, "Cavity (Inverted)", ""); } +static void SCULPT_OT_scene_mask_from_cavity(wmOperatorType *ot) +{ + SCULPT_OT_mask_from_cavity(ot); + ot->idname = "SCULPT_OT_scene_mask_from_cavity"; + ot->poll = SCULPT_mode_poll_cavity_automask; +} + static int sculpt_reveal_all_exec(bContext *C, wmOperator *op) { Object *ob = CTX_data_active_object(C); @@ -1424,6 +1431,7 @@ void ED_operatortypes_sculpt(void) WM_operatortype_append(SCULPT_OT_mask_init); WM_operatortype_append(SCULPT_OT_expand); + WM_operatortype_append(SCULPT_OT_scene_mask_from_cavity); WM_operatortype_append(SCULPT_OT_mask_from_cavity); WM_operatortype_append(SCULPT_OT_reveal_all); } diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index ca1d878110f..0305696bb8e 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -1089,6 +1089,7 @@ typedef struct Sculpt { float automasking_start_normal_limit, automasking_start_normal_falloff; float automasking_view_normal_limit, automasking_view_normal_falloff; + float automasking_scene_view_normal_limit, automasking_scene_view_normal_falloff; struct CurveMapping *automasking_cavity_curve; /** For use by operators. */ diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index 14d7c6691f6..4e05d9f56be 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -274,6 +274,7 @@ bool RNA_property_editable(PointerRNA *ptr, PropertyRNA *prop); * that can be exposed in UI. */ bool RNA_property_editable_info(PointerRNA *ptr, PropertyRNA *prop, const char **r_info); +bool RNA_property_is_inactive_info(PointerRNA *ptr, PropertyRNA *prop, const char **r_info); /** * Same as RNA_property_editable(), except this checks individual items in an array. */ diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h index 568eea48ec1..4a10af9bf32 100644 --- a/source/blender/makesrna/RNA_types.h +++ b/source/blender/makesrna/RNA_types.h @@ -187,6 +187,15 @@ typedef enum PropertyFlag { * for pointers and collections. */ PROP_EDITABLE = (1 << 0), + /** + * Inactive specifically only refers to the front end + * where UI elements are grayed out but can still be + * toggled. It is specifically used to add Disabled + * message for when UI is set to inactive through Python + * script. It is completely unrelated to anything that + * is performed in the backend. + */ + PROP_INACTIVE = (1 << 9), /** * This property is editable even if it is lib linked, * meaning it will get lost on reload, but it's useful diff --git a/source/blender/makesrna/intern/rna_access.cc b/source/blender/makesrna/intern/rna_access.cc index c1030d80196..85b89f4c93a 100644 --- a/source/blender/makesrna/intern/rna_access.cc +++ b/source/blender/makesrna/intern/rna_access.cc @@ -1935,6 +1935,32 @@ int RNA_property_ui_icon(const PropertyRNA *prop) return rna_ensure_property((PropertyRNA *)prop)->icon; } +static bool rna_property_is_inactive_do(PointerRNA *ptr, + PropertyRNA *prop_orig, + const int index, + const char **r_info) +{ + PropertyRNA *prop = rna_ensure_property(prop_orig); + + const char *info = ""; + const int flag = (prop->itemeditable != nullptr && index >= 0) ? + prop->itemeditable(ptr, index) : + (prop->editable != nullptr ? prop->editable(ptr, &info) : prop->flag); + if (r_info != nullptr) { + *r_info = info; + } + + /* Return true if the property itself is inative. */ + if ((flag & PROP_INACTIVE) != 0) { + if (r_info != nullptr && (*r_info)[0] == '\0') { + *r_info = N_("This property is for internal use only and can't be edited"); + } + return true; + } + + return false; +} + static bool rna_property_editable_do(PointerRNA *ptr, PropertyRNA *prop_orig, const int index, @@ -2001,6 +2027,11 @@ bool RNA_property_editable(PointerRNA *ptr, PropertyRNA *prop) return rna_property_editable_do(ptr, prop, -1, nullptr); } +bool RNA_property_is_inactive_info(PointerRNA *ptr, PropertyRNA *prop, const char **r_info) +{ + return rna_property_is_inactive_do(ptr, prop, -1, r_info); +} + bool RNA_property_editable_info(PointerRNA *ptr, PropertyRNA *prop, const char **r_info) { return rna_property_editable_do(ptr, prop, -1, r_info); diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c index 033090f2f5b..6e9c8de6de6 100644 --- a/source/blender/makesrna/intern/rna_brush.c +++ b/source/blender/makesrna/intern/rna_brush.c @@ -3078,6 +3078,7 @@ static void rna_def_brush(BlenderRNA *brna) "Propagation Steps", "Distance where boundary edge automasking is going to protect vertices " "from the fully masked edge"); + RNA_def_property_editable_func(prop, "rna_Scene_automasking_mesh_and_face_sets_boundary_editable"); RNA_def_property_update(prop, 0, "rna_Brush_update"); prop = RNA_def_property(srna, "auto_smooth_factor", PROP_FLOAT, PROP_FACTOR); @@ -3839,3 +3840,13 @@ void RNA_def_brush(BlenderRNA *brna) } #endif + +static int rna_Scene_automasking_mesh_and_face_sets_boundary_editable(struct PointerRNA *ptr, const char **r_info) { + Brush *br = (Brush*)ptr->data; + if (br && (br->automasking_flags & BRUSH_AUTOMASKING_BOUNDARY_EDGES) && (br->automasking_flags & BRUSH_AUTOMASKING_BOUNDARY_FACE_SETS)) { + *r_info = "The active brush already has the same auto-masking enabled."; + return PROP_INACTIVE | PROP_EDITABLE; + } + + return br ? PROP_EDITABLE: 0; +} diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c index aa60339b7b8..592936000df 100644 --- a/source/blender/makesrna/intern/rna_sculpt_paint.c +++ b/source/blender/makesrna/intern/rna_sculpt_paint.c @@ -862,25 +862,54 @@ static void rna_def_sculpt(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Sculpt_update"); - const EnumPropertyItem *entry = rna_enum_brush_automasking_flag_items; - do { - prop = RNA_def_property(srna, entry->identifier, PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "automasking_flags", entry->value); - RNA_def_property_ui_text(prop, entry->name, entry->description); + prop = RNA_def_property(srna, "use_automasking_topology", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "automasking_flags", BRUSH_AUTOMASKING_TOPOLOGY); + RNA_def_property_ui_text(prop, "Topology", "Affect only vertices connected to the active vertex under the brush"); + RNA_def_property_editable_func(prop, "rna_Scene_automasking_topology_editable"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); - if (entry->value == BRUSH_AUTOMASKING_CAVITY_NORMAL) { - RNA_def_property_boolean_funcs(prop, NULL, "rna_Sculpt_automasking_cavity_set"); - } - else if (entry->value == BRUSH_AUTOMASKING_CAVITY_INVERTED) { - RNA_def_property_boolean_funcs(prop, NULL, "rna_Sculpt_automasking_invert_cavity_set"); - } + prop = RNA_def_property(srna, "use_automasking_face_sets", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "automasking_flags", BRUSH_AUTOMASKING_FACE_SETS); + RNA_def_property_ui_text(prop, "Face Sets", "Affect only vertices that share Face Sets with the active vertex"); + RNA_def_property_editable_func(prop, "rna_Scene_automasking_face_sets_editable"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); - RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); - } while ((++entry)->identifier); + prop = RNA_def_property(srna, "use_automasking_boundary_edges", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "automasking_flags", BRUSH_AUTOMASKING_BOUNDARY_EDGES); + RNA_def_property_ui_text(prop, "Mesh Boundary Auto-Masking", "Do not affect non manifold boundary edges"); + RNA_def_property_editable_func(prop, "rna_Scene_automasking_mesh_boundary_editable"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + + prop = RNA_def_property(srna, "use_automasking_boundary_face_sets", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "automasking_flags", BRUSH_AUTOMASKING_BOUNDARY_FACE_SETS); + RNA_def_property_ui_text(prop, "Face Sets Boundary Automasking", "Do not affect vertices that belong to a Face Set boundary"); + RNA_def_property_editable_func(prop, "rna_Scene_automasking_face_sets_boundary_editable"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + + prop = RNA_def_property(srna, "use_automasking_cavity", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "automasking_flags", BRUSH_AUTOMASKING_CAVITY_NORMAL); + RNA_def_property_ui_text(prop, "Cavity Mask", "Do not affect vertices on peaks, based on the surface curvature"); + RNA_def_property_editable_func(prop, "rna_Scene_automasking_cavity_editable"); + RNA_def_property_boolean_funcs(prop, NULL, "rna_Sculpt_automasking_cavity_set"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + + prop = RNA_def_property(srna, "use_automasking_cavity_inverted", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "automasking_flags", BRUSH_AUTOMASKING_CAVITY_INVERTED); + RNA_def_property_ui_text(prop, "Inverted Cavity Mask", "Do not affect vertices within crevices, based on the surface curvature"); + RNA_def_property_editable_func(prop, "rna_Scene_automasking_cavity_editable"); + RNA_def_property_boolean_funcs(prop, NULL, "rna_Sculpt_automasking_invert_cavity_set"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + + prop = RNA_def_property(srna, "use_automasking_custom_cavity_curve", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "automasking_flags", BRUSH_AUTOMASKING_CAVITY_USE_CURVE); + RNA_def_property_ui_text(prop, "Custom Cavity Curve", "Use custom curve"); + RNA_def_property_editable_func(prop, "rna_Scene_automasking_cavity_editable"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); prop = RNA_def_property(srna, "automasking_cavity_factor", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "automasking_cavity_factor"); RNA_def_property_ui_text(prop, "Cavity Factor", "The contrast of the cavity mask"); + RNA_def_property_editable_func(prop, "rna_Scene_automasking_cavity_editable"); RNA_def_property_float_default(prop, 1.0f); RNA_def_property_range(prop, 0.0f, 5.0f); RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.1, 3); @@ -889,6 +918,7 @@ static void rna_def_sculpt(BlenderRNA *brna) prop = RNA_def_property(srna, "automasking_cavity_blur_steps", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "automasking_cavity_blur_steps"); RNA_def_property_ui_text(prop, "Blur Steps", "The number of times the cavity mask is blurred"); + RNA_def_property_editable_func(prop, "rna_Scene_automasking_cavity_editable"); RNA_def_property_int_default(prop, 0); RNA_def_property_range(prop, 0, 25); RNA_def_property_ui_range(prop, 0, 10, 1, 1); @@ -898,6 +928,7 @@ static void rna_def_sculpt(BlenderRNA *brna) RNA_def_property_pointer_sdna(prop, NULL, "automasking_cavity_curve"); RNA_def_property_struct_type(prop, "CurveMapping"); RNA_def_property_ui_text(prop, "Cavity Curve", "Curve used for the sensitivity"); + RNA_def_property_editable_func(prop, "rna_Scene_automasking_cavity_editable"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); @@ -905,6 +936,7 @@ static void rna_def_sculpt(BlenderRNA *brna) RNA_def_property_pointer_sdna(prop, NULL, "automasking_cavity_curve_op"); RNA_def_property_struct_type(prop, "CurveMapping"); RNA_def_property_ui_text(prop, "Cavity Curve", "Curve used for the sensitivity"); + RNA_def_property_editable_func(prop, "rna_Scene_automasking_cavity_editable"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); @@ -914,12 +946,14 @@ static void rna_def_sculpt(BlenderRNA *brna) prop, "Area Normal", "Affect only vertices with a similar normal to where the stroke starts"); + RNA_def_property_editable_func(prop, "rna_Scene_automasking_area_normal_editable"); RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); prop = RNA_def_property(srna, "use_automasking_view_normal", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "automasking_flags", BRUSH_AUTOMASKING_VIEW_NORMAL); RNA_def_property_ui_text( prop, "View Normal", "Affect only vertices with a normal that faces the viewer"); + RNA_def_property_editable_func(prop, "rna_Scene_automasking_view_normal_editable"); RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); prop = RNA_def_property(srna, "use_automasking_view_occlusion", PROP_BOOLEAN, PROP_NONE); @@ -928,12 +962,14 @@ static void rna_def_sculpt(BlenderRNA *brna) prop, "Occlusion", "Only affect vertices that are not occluded by other faces. (Slower performance)"); + RNA_def_property_editable_func(prop, "rna_Scene_automasking_view_normal_editable"); RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); prop = RNA_def_property(srna, "automasking_start_normal_limit", PROP_FLOAT, PROP_ANGLE); RNA_def_property_float_sdna(prop, NULL, "automasking_start_normal_limit"); RNA_def_property_range(prop, 0.0001f, M_PI); RNA_def_property_ui_text(prop, "Area Normal Limit", "The range of angles that will be affected"); + RNA_def_property_editable_func(prop, "rna_Scene_automasking_area_normal_editable"); RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); prop = RNA_def_property(srna, "automasking_start_normal_falloff", PROP_FLOAT, PROP_FACTOR); @@ -941,6 +977,7 @@ static void rna_def_sculpt(BlenderRNA *brna) RNA_def_property_range(prop, 0.0001f, 1.0f); RNA_def_property_ui_text( prop, "Area Normal Falloff", "Extend the angular range with a falloff gradient"); + RNA_def_property_editable_func(prop, "rna_Scene_automasking_area_normal_editable"); RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); prop = RNA_def_property(srna, "automasking_view_normal_limit", PROP_FLOAT, PROP_ANGLE); @@ -956,6 +993,21 @@ static void rna_def_sculpt(BlenderRNA *brna) prop, "View Normal Falloff", "Extend the angular range with a falloff gradient"); RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + prop = RNA_def_property(srna, "automasking_scene_view_normal_limit", PROP_FLOAT, PROP_ANGLE); + RNA_def_property_float_sdna(prop, NULL, "automasking_scene_view_normal_limit"); + RNA_def_property_range(prop, 0.0001f, M_PI); + RNA_def_property_ui_text(prop, "View Normal Limit", "The range of angles that will be affected"); + RNA_def_property_editable_func(prop, "rna_Scene_automasking_view_normal_editable"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + + prop = RNA_def_property(srna, "automasking_scene_view_normal_falloff", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "automasking_scene_view_normal_falloff"); + RNA_def_property_range(prop, 0.0001f, 1.0f); + RNA_def_property_ui_text( + prop, "View Normal Falloff", "Extend the angular range with a falloff gradient"); + RNA_def_property_editable_func(prop, "rna_Scene_automasking_view_normal_editable"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + prop = RNA_def_property(srna, "symmetrize_direction", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, rna_enum_symmetrize_direction_items); RNA_def_property_ui_text(prop, "Direction", "Source and destination for symmetrize operator"); @@ -1701,3 +1753,80 @@ void RNA_def_sculpt_paint(BlenderRNA *brna) } #endif + +static int rna_Scene_automasking_topology_editable(struct PointerRNA *ptr, const char **r_info) { + Sculpt *sd = (Sculpt*)ptr->data; + if (sd && (sd->paint.brush->automasking_flags & BRUSH_AUTOMASKING_TOPOLOGY)) { + *r_info = "The active brush already has the same auto-masking enabled."; + return PROP_INACTIVE | PROP_EDITABLE; + } + + return sd ? PROP_EDITABLE: 0; +} + +static int rna_Scene_automasking_face_sets_editable(struct PointerRNA *ptr, const char **r_info) { + Sculpt *sd = (Sculpt*)ptr->data; + if (sd && (sd->paint.brush->automasking_flags & BRUSH_AUTOMASKING_FACE_SETS)) { + *r_info = "The active brush already has the same auto-masking enabled."; + return PROP_INACTIVE | PROP_EDITABLE; + } + + return sd ? PROP_EDITABLE: 0; +} + +static int rna_Scene_automasking_mesh_boundary_editable(struct PointerRNA *ptr, const char **r_info) { + Sculpt *sd = (Sculpt*)ptr->data; + if (sd && (sd->paint.brush->automasking_flags & BRUSH_AUTOMASKING_BOUNDARY_EDGES)) { + *r_info = "The active brush already has the same auto-masking enabled."; + return PROP_INACTIVE | PROP_EDITABLE; + } + + return sd ? PROP_EDITABLE: 0; +} + +static int rna_Scene_automasking_face_sets_boundary_editable(struct PointerRNA *ptr, const char **r_info) { + Sculpt *sd = (Sculpt*)ptr->data; + if (sd && (sd->paint.brush->automasking_flags & BRUSH_AUTOMASKING_BOUNDARY_FACE_SETS)) { + *r_info = "The active brush already has the same auto-masking enabled."; + return PROP_INACTIVE | PROP_EDITABLE; + } + + return sd ? PROP_EDITABLE: 0; +} + +static int rna_Scene_automasking_cavity_editable(struct PointerRNA *ptr, const char **r_info) { + Sculpt *sd = (Sculpt*)ptr->data; + if (sd && (sd->paint.brush->automasking_flags & BRUSH_AUTOMASKING_CAVITY_ALL)) { + *r_info = "The active brush already has the same auto-masking enabled."; + return PROP_INACTIVE | PROP_EDITABLE; + } + + return sd ? PROP_EDITABLE: 0; +} + +static int rna_Scene_automasking_view_normal_editable(struct PointerRNA *ptr, const char **r_info) { + Sculpt *sd = (Sculpt*)ptr->data; + + if (sd && (sd->paint.brush->automasking_flags & BRUSH_AUTOMASKING_VIEW_NORMAL)) { + *r_info = "The active brush already has the same auto-masking enabled."; + // TODO should probably utilize RNA_def_property_float_funcs to sync values between automasking_view and automasking_scene_view + sd->automasking_scene_view_normal_limit = sd->automasking_view_normal_limit; + sd->automasking_scene_view_normal_falloff = sd->automasking_view_normal_falloff; + return PROP_INACTIVE | PROP_EDITABLE; + } else { + sd->automasking_view_normal_limit = sd->automasking_scene_view_normal_limit; + sd->automasking_view_normal_falloff = sd->automasking_scene_view_normal_falloff; + } + + return sd ? PROP_EDITABLE: 0; +} + +static int rna_Scene_automasking_area_normal_editable(struct PointerRNA *ptr, const char **r_info) { + Sculpt *sd = (Sculpt*)ptr->data; + if (sd && (sd->paint.brush->automasking_flags & BRUSH_AUTOMASKING_BRUSH_NORMAL)) { + *r_info = "The active brush already has the same auto-masking enabled."; + return PROP_INACTIVE | PROP_EDITABLE; + } + + return sd ? PROP_EDITABLE: 0; +}