Changeset View
Changeset View
Standalone View
Standalone View
release/scripts/startup/bl_ui/properties_paint_common.py
| Context not available. | |||||
| # <pep8 compliant> | # <pep8 compliant> | ||||
| from bpy.types import Menu | from bpy.types import Menu | ||||
| class UnifiedPaintPanel: | class UnifiedPaintPanel: | ||||
| # subclass must set | # subclass must set | ||||
| # bl_space_type = 'IMAGE_EDITOR' | # bl_space_type = 'IMAGE_EDITOR' | ||||
| Context not available. | |||||
| return None | return None | ||||
| @staticmethod | @staticmethod | ||||
| def unified_paint_settings(parent, context): | def prop_unified(layout, context, brush, prop_name, unified_name=None, pressure_name=None, icon='NONE', text=None, slider=False, display_unified_toggle=True): | ||||
| """ Generalized way of adding brush options to the UI, along with their pen pressure setting and global toggle, if they exist """ | |||||
| row = layout.row(align=True) | |||||
| ups = context.tool_settings.unified_paint_settings | ups = context.tool_settings.unified_paint_settings | ||||
| ptr = brush | |||||
| if(unified_name and getattr(ups, unified_name) and display_unified_toggle): | |||||
| ptr = ups | |||||
| flow = parent.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False) | row.prop(ptr, prop_name, icon=icon, text=text, slider=slider) | ||||
| col = flow.column() | if(pressure_name): | ||||
| col.prop(ups, "use_unified_size", text="Size") | # We know that the Brush and the UnifiedPaintSettings classes have identical variable names for their brush settings, eg. Brush.use_pressure_size, UnifiedPaintSettings.use_pressure_size. | ||||
| col = flow.column() | row.prop(ptr, pressure_name, text="") | ||||
| col.prop(ups, "use_unified_strength", text="Strength") | |||||
| if context.weight_paint_object: | |||||
| col = flow.column() | |||||
| col.prop(ups, "use_unified_weight", text="Weight") | |||||
| elif context.vertex_paint_object or context.image_paint_object: | |||||
| col = flow.column() | |||||
| col.prop(ups, "use_unified_color", text="Color") | |||||
| else: | |||||
| col = flow.column() | |||||
| col.prop(ups, "use_unified_color", text="Color") | |||||
| @staticmethod | if(unified_name and display_unified_toggle): | ||||
| def prop_unified_size(parent, context, brush, prop_name, *, icon='NONE', text=None, slider=False): | row.prop(ups, unified_name, text="", icon="WORLD") | ||||
| ups = context.tool_settings.unified_paint_settings | |||||
| ptr = ups if ups.use_unified_size else brush | return row | ||||
| parent.prop(ptr, prop_name, icon=icon, text=text, slider=slider) | |||||
| @staticmethod | |||||
| def prop_unified_strength(parent, context, brush, prop_name, *, icon='NONE', text=None, slider=False): | |||||
| ups = context.tool_settings.unified_paint_settings | |||||
| ptr = ups if ups.use_unified_strength else brush | |||||
| parent.prop(ptr, prop_name, icon=icon, text=text, slider=slider) | |||||
| @staticmethod | |||||
| def prop_unified_weight(parent, context, brush, prop_name, *, icon='NONE', text=None, slider=False): | |||||
| ups = context.tool_settings.unified_paint_settings | |||||
| ptr = ups if ups.use_unified_weight else brush | |||||
| parent.prop(ptr, prop_name, icon=icon, text=text, slider=slider) | |||||
| @staticmethod | @staticmethod | ||||
| def prop_unified_color(parent, context, brush, prop_name, *, text=None): | def prop_unified_color(parent, context, brush, prop_name, *, text=None): | ||||
| Context not available. | |||||
| props.value = i | props.value = i | ||||
| def brush_texpaint_common(panel, context, layout, brush, _settings, projpaint=False): | def draw_all_brush_settings(layout, context, brush, mode, popover=False): | ||||
| capabilities = brush.image_paint_capabilities | """ Draw all brush settings for Sculpt, Texture/Vertex/Weight Paint modes, or skip certain settings for the popover """ | ||||
| # First, draw common brush settings # | |||||
| col = layout.column() | col = layout.column() | ||||
| draw_shared_brush_settings(col, context, brush, mode, popover) | |||||
| if brush.image_tool == 'FILL' and not projpaint: | |||||
| col.prop(brush, "fill_threshold", text="Gradient Type", slider=True) | ### Draw settings unique to each paint mode. ### | ||||
| elif brush.image_tool == 'SOFTEN': | # Sculpt Mode # | ||||
| col.row().prop(brush, "direction", expand=True) | if mode == 'SCULPT': | ||||
| col.prop(brush, "sharp_threshold") | capabilities = brush.sculpt_capabilities | ||||
| if not projpaint: | |||||
| col.prop(brush, "blur_kernel_radius") | # direction (the flag appears to be the wrong way around...) | ||||
| col.prop(brush, "blur_mode") | if not capabilities.has_direction and not popover: | ||||
| elif brush.image_tool == 'MASK': | col.prop(brush, "direction", expand=True) | ||||
| col.prop(brush, "weight", text="Mask Value", slider=True) | |||||
| # normal_radius_factor | |||||
| elif brush.image_tool == 'CLONE': | col.separator() | ||||
| if not projpaint: | col.prop(brush, "normal_radius_factor", slider=True) | ||||
| col.prop(brush, "clone_image", text="Image") | |||||
| col.prop(brush, "clone_alpha", text="Alpha") | if brush.sculpt_tool == 'ELASTIC_DEFORM': | ||||
| col.separator() | |||||
| if not panel.is_popover: | box = col.box() | ||||
| brush_basic_texpaint_settings(col, context, brush) | box.prop(brush, "elastic_deform_type") | ||||
| box.prop(brush, "elastic_deform_volume_preservation", slider=True) | |||||
| if brush.sculpt_tool == 'GRAB': | |||||
| col.separator() | |||||
| col.prop(brush, "use_grab_active_vertex") | |||||
| # topology_rake_factor | |||||
| if ( | |||||
| capabilities.has_topology_rake and | |||||
| context.sculpt_object.use_dynamic_topology_sculpting | |||||
| ): | |||||
| col.prop(brush, "topology_rake_factor", slider=True) | |||||
| # auto_smooth_factor and use_inverse_smooth_pressure | |||||
| if capabilities.has_auto_smooth: | |||||
| UnifiedPaintPanel.prop_unified(col, context, brush, "auto_smooth_factor", pressure_name="use_inverse_smooth_pressure", slider=True) | |||||
| # normal_weight | |||||
| if capabilities.has_normal_weight: | |||||
| col.prop(brush, "normal_weight", slider=True) | |||||
| # crease_pinch_factor | |||||
| if capabilities.has_pinch_factor: | |||||
| text = "Pinch" | |||||
| if brush.sculpt_tool in ('BLOB', 'SNAKE_HOOK'): | |||||
| text = "Magnify" | |||||
| col.prop(brush, "crease_pinch_factor", slider=True, text=text) | |||||
| # rake_factor | |||||
| if capabilities.has_rake_factor: | |||||
| col.prop(brush, "rake_factor", slider=True) | |||||
| if brush.sculpt_tool == 'MASK': | |||||
| col.prop(brush, "mask_tool") | |||||
| # plane_offset, use_offset_pressure, use_plane_trim, plane_trim | |||||
| if capabilities.has_plane_offset: | |||||
| box = col.box() | |||||
| box.prop(brush, "plane_offset", slider=True) | |||||
| box.prop(brush, "use_offset_pressure", text="") | |||||
| box.prop(brush, "use_plane_trim", text="Plane Trim") | |||||
| row = box.row() | |||||
| row.active = brush.use_plane_trim | |||||
| row.prop(brush, "plane_trim", slider=True, text="Distance") | |||||
| # height | |||||
| if capabilities.has_height: | |||||
| col.prop(brush, "height", slider=True, text="Height") | |||||
| # use_persistent, set_persistent_base | |||||
| if capabilities.has_persistence: | |||||
| ob = context.sculpt_object | |||||
| do_persistent = True | |||||
| # not supported yet for this case | |||||
| for md in ob.modifiers: | |||||
| if md.type == 'MULTIRES': | |||||
| do_persistent = False | |||||
| break | |||||
| if do_persistent: | |||||
| box = col.box() | |||||
| box.prop(brush, "use_persistent") | |||||
| box.operator("sculpt.set_persistent_base") | |||||
| col.prop(brush, "use_automasking_topology") | |||||
| if capabilities.has_sculpt_plane: | |||||
| box = col.box() | |||||
| box.prop(brush, "sculpt_plane") | |||||
| box.prop(brush, "use_original_normal") | |||||
| box.prop(brush, "use_original_plane") | |||||
| # 3D and 2D Texture Paint Mode # | |||||
| elif mode in ('TEXTURE_PAINT', '2D_PAINT'): | |||||
| capabilities = brush.image_paint_capabilities | |||||
| if capabilities.has_space_attenuation: | |||||
| col.prop(brush, "use_space_attenuation") | |||||
| if mode == 'TEXTURE_PAINT': | |||||
| col.prop(brush, "use_alpha") | |||||
| if brush.image_tool == 'FILL' and mode=='2D_PAINT': | |||||
| col.prop(brush, "fill_threshold", text="Gradient Type", slider=True) | |||||
| elif brush.image_tool == 'SOFTEN': | |||||
| col.prop(brush, "direction", expand=True) | |||||
| col.prop(brush, "sharp_threshold") | |||||
| if mode=='2D_PAINT': | |||||
| col.prop(brush, "blur_kernel_radius") | |||||
| col.prop(brush, "blur_mode") | |||||
| elif brush.image_tool == 'MASK': | |||||
| col.prop(brush, "weight", text="Mask Value", slider=True) | |||||
| elif brush.image_tool == 'CLONE': | |||||
| if mode=='2D_PAINT': | |||||
| col.prop(brush, "clone_image", text="Image") | |||||
| col.prop(brush, "clone_alpha", text="Alpha") | |||||
| # Vertex Paint Mode # | |||||
| elif mode == 'VERTEX_PAINT': | |||||
| col.prop(brush, "use_alpha") | |||||
| # Weight Paint Mode # | |||||
| elif mode == 'WEIGHT_PAINT': | |||||
| # No options are currently unique to weight paint mode, so they are all drawn with draw_shared_brush_settings(). | |||||
| pass | |||||
| def draw_shared_brush_settings(layout, context, brush, mode, popover=False): | |||||
| """ Draw settings that are shared between different paint modes. """ | |||||
| ### Determine which settings to draw. ### | |||||
| large_preview = False | |||||
| color = False | |||||
| blend_mode = False | |||||
| color_type = False | |||||
| size = False | |||||
| size_mode = False | |||||
| strength = False | |||||
| strength_pressure = False | |||||
| weight = False | |||||
| use_accumulate = False | |||||
| use_frontface = False | |||||
| use_projected = False | |||||
| # 3D and 2D Texture Paint # | |||||
| if mode in ('TEXTURE_PAINT', '2D_PAINT'): | |||||
| large_preview = True | |||||
| color = color_type = blend_mode = brush.image_paint_capabilities.has_color | |||||
| if not popover: | |||||
| size = brush.image_paint_capabilities.has_radius | |||||
| strength = strength_pressure = True | |||||
| use_accumulate = brush.image_paint_capabilities.has_accumulate | |||||
| # Sculpt # | |||||
| if mode == 'SCULPT': | |||||
| large_preview = True | |||||
| size_mode = True | |||||
| if not popover: | |||||
| size = True | |||||
| strength = True | |||||
| strength_pressure = brush.sculpt_capabilities.has_strength_pressure | |||||
| use_accumulate = brush.sculpt_capabilities.has_accumulate | |||||
| use_frontface = True | |||||
| use_projected = True | |||||
| # Vertex Paint # | |||||
| if mode == 'VERTEX_PAINT': | |||||
| if not popover: | |||||
| size = True | |||||
| strength = True | |||||
| strength_pressure = True | |||||
| color = blend_mode = brush.vertex_paint_capabilities.has_color | |||||
| if brush.vertex_tool != 'SMEAR': | |||||
| use_accumulate = True | |||||
| use_frontface = True | |||||
| use_projected = True | |||||
| # Weight Paint # | |||||
| if mode == 'WEIGHT_PAINT': | |||||
| if not popover: | |||||
| size = True | |||||
| weight = brush.weight_paint_capabilities.has_weight | |||||
| strength = strength_pressure = True | |||||
| blend_mode = True | |||||
| if brush.weight_tool != 'SMEAR': | |||||
| use_accumulate = True | |||||
| use_frontface = True | |||||
| use_projected = True | |||||
| # UV Sculpt # | |||||
| if mode == 'UV_SCULPT': | |||||
| size = True | |||||
| strength = True | |||||
| ### Draw settings. ### | |||||
| ups = context.scene.tool_settings.unified_paint_settings | |||||
| settings = UnifiedPaintPanel.paint_settings(context) | |||||
| if settings and not popover: | |||||
| row = layout.row() | |||||
| if large_preview: | |||||
| row.column().template_ID_preview(settings, "brush", new="brush.add", rows=3, cols=8, hide_buttons=True) | |||||
| else: | |||||
| row.column().template_ID(settings, "brush", new="brush.add") | |||||
| row.menu("VIEW3D_MT_brush_context_menu", icon='DOWNARROW_HLT', text="") | |||||
| blend_mode_ui = layout | |||||
| if color: | |||||
| color_box = layout.box() | |||||
| blend_mode_ui = color_box | |||||
| if color_type: | |||||
| row = color_box.row() | |||||
| row.use_property_split = False | |||||
| row.prop(brush, "color_type", expand=True) | |||||
| if brush.color_type == 'COLOR': | |||||
| brush_texpaint_common_color(context, color_box, brush) | |||||
| elif brush.color_type == 'GRADIENT': | |||||
| brush_texpaint_common_gradient(context, color_box, brush) | |||||
| if blend_mode: | |||||
| blend_mode_ui.prop(brush, "blend", text="Blend") | |||||
| if weight: | |||||
| UnifiedPaintPanel.prop_unified(layout, context, brush, "weight", unified_name="use_unified_weight", slider=True) | |||||
| size_owner = ups if ups.use_unified_size else brush | |||||
| size_ui = layout.box() if size_mode and not popover else layout | |||||
| size_prop = "size" | |||||
| if size_mode and (size_owner.use_locked_size == 'SCENE'): | |||||
| size_prop = "unprojected_radius" | |||||
| if size: | |||||
| UnifiedPaintPanel.prop_unified(size_ui, context, size_owner, size_prop, unified_name="use_unified_size", pressure_name="use_pressure_size", text="Radius", slider=True) | |||||
| if size_mode: | |||||
| size_ui.prop(size_owner, "use_locked_size", expand=True) | |||||
| if strength: | |||||
| pressure_name = "use_pressure_strength" if strength_pressure else None | |||||
| UnifiedPaintPanel.prop_unified(layout, context, brush, "strength", unified_name="use_unified_strength", pressure_name=pressure_name, slider=True) | |||||
| if use_accumulate: | |||||
| layout.prop(brush, "use_accumulate") | |||||
| if use_frontface: | |||||
| layout.prop(brush, "use_frontface", text="Front Faces Only") | |||||
| if use_projected: | |||||
| layout.prop(brush, "use_projected") | |||||
| def brush_texpaint_common_clone(_panel, context, layout, _brush, settings, projpaint=False): | def brush_texpaint_common_clone(_panel, context, layout, _brush, settings, projpaint=False): | ||||
| Context not available. | |||||
| col.menu("VIEW3D_MT_tools_projectpaint_clone", text=clone_text, translate=False) | col.menu("VIEW3D_MT_tools_projectpaint_clone", text=clone_text, translate=False) | ||||
| def brush_texpaint_common_color(_panel, context, layout, brush, _settings, projpaint=False): | def brush_texpaint_common_color(context, layout, brush): | ||||
| UnifiedPaintPanel.prop_unified_color_picker(layout, context, brush, "color", value_slider=True) | UnifiedPaintPanel.prop_unified_color_picker(layout, context, brush, "color", value_slider=True) | ||||
| ups = context.scene.tool_settings.unified_paint_settings | |||||
| row = layout.row(align=True) | row = layout.row(align=True) | ||||
| UnifiedPaintPanel.prop_unified_color(row, context, brush, "color", text="") | UnifiedPaintPanel.prop_unified_color(row, context, brush, "color", text="") | ||||
| UnifiedPaintPanel.prop_unified_color(row, context, brush, "secondary_color", text="") | UnifiedPaintPanel.prop_unified_color(row, context, brush, "secondary_color", text="") | ||||
| row.separator() | row.separator() | ||||
| row.operator("paint.brush_colors_flip", icon='FILE_REFRESH', text="", emboss=False) | row.operator("paint.brush_colors_flip", icon='FILE_REFRESH', text="", emboss=False) | ||||
| row.prop(ups, "use_unified_color", text="", icon='WORLD') | |||||
| def brush_texpaint_common_gradient(_panel, context, layout, brush, _settings, projpaint=False): | def brush_texpaint_common_gradient(context, layout, brush): | ||||
| layout.template_color_ramp(brush, "gradient", expand=True) | layout.template_color_ramp(brush, "gradient", expand=True) | ||||
| layout.use_property_split = True | layout.use_property_split = True | ||||
| ups = context.tool_settings.unified_paint_settings | |||||
| col = layout.column() | col = layout.column() | ||||
| if brush.image_tool == 'DRAW': | if brush.image_tool == 'DRAW': | ||||
| UnifiedPaintPanel.prop_unified_color(col, context, brush, "secondary_color", text="Background Color") | UnifiedPaintPanel.prop_unified(col, context, brush, "secondary_color", unified_name="use_unified_color", text="Background Color", display_unified_toggle=False) | ||||
| col.prop(brush, "gradient_stroke_mode", text="Gradient Mapping") | col.prop(brush, "gradient_stroke_mode", text="Gradient Mapping") | ||||
| if brush.gradient_stroke_mode in {'SPACING_REPEAT', 'SPACING_CLAMP'}: | if brush.gradient_stroke_mode in {'SPACING_REPEAT', 'SPACING_CLAMP'}: | ||||
| col.prop(brush, "grad_spacing") | col.prop(brush, "grad_spacing") | ||||
| Context not available. | |||||
| col.prop(brush, "gradient_fill_mode") | col.prop(brush, "gradient_fill_mode") | ||||
| def brush_texpaint_common_options(_panel, _context, layout, brush, _settings, projpaint=False): | |||||
| capabilities = brush.image_paint_capabilities | |||||
| col = layout.column() | |||||
| if capabilities.has_accumulate: | |||||
| col.prop(brush, "use_accumulate") | |||||
| if capabilities.has_space_attenuation: | |||||
| col.prop(brush, "use_space_attenuation") | |||||
| if projpaint: | |||||
| col.prop(brush, "use_alpha") | |||||
| # Used in both the View3D toolbar and texture properties | # Used in both the View3D toolbar and texture properties | ||||
| def brush_texture_settings(layout, brush, sculpt): | def brush_texture_settings(layout, brush, sculpt): | ||||
| tex_slot = brush.texture_slot | tex_slot = brush.texture_slot | ||||
| Context not available. | |||||
| # Share between topbar and brush panel. | # Share between topbar and brush panel. | ||||
| def brush_basic_wpaint_settings(layout, context, brush, *, compact=False): | |||||
| capabilities = brush.weight_paint_capabilities | |||||
| if capabilities.has_weight: | |||||
| row = layout.row(align=True) | |||||
| UnifiedPaintPanel.prop_unified_weight(row, context, brush, "weight", slider=True) | |||||
| row = layout.row(align=True) | |||||
| UnifiedPaintPanel.prop_unified_size(row, context, brush, "size", slider=True) | |||||
| UnifiedPaintPanel.prop_unified_size(row, context, brush, "use_pressure_size", text="") | |||||
| row = layout.row(align=True) | |||||
| UnifiedPaintPanel.prop_unified_strength(row, context, brush, "strength") | |||||
| UnifiedPaintPanel.prop_unified_strength(row, context, brush, "use_pressure_strength", text="") | |||||
| layout.prop(brush, "blend", text="" if compact else "Blend") | |||||
| def brush_basic_vpaint_settings(layout, context, brush, *, compact=False): | |||||
| capabilities = brush.vertex_paint_capabilities | |||||
| row = layout.row(align=True) | |||||
| UnifiedPaintPanel.prop_unified_size(row, context, brush, "size", slider=True) | |||||
| UnifiedPaintPanel.prop_unified_size(row, context, brush, "use_pressure_size", text="") | |||||
| row = layout.row(align=True) | |||||
| UnifiedPaintPanel.prop_unified_strength(row, context, brush, "strength") | |||||
| UnifiedPaintPanel.prop_unified_strength(row, context, brush, "use_pressure_strength", text="") | |||||
| if capabilities.has_color: | |||||
| layout.prop(brush, "blend", text="" if compact else "Blend") | |||||
| def brush_basic_texpaint_settings(layout, context, brush, *, compact=False): | def brush_basic_texpaint_settings(layout, context, brush, *, compact=False): | ||||
| """ Draw Tool Settings header for Vertex Paint and 2D and 3D Texture Paint modes. """ | |||||
| capabilities = brush.image_paint_capabilities | capabilities = brush.image_paint_capabilities | ||||
| if capabilities.has_radius: | |||||
| row = layout.row(align=True) | |||||
| UnifiedPaintPanel.prop_unified_size(row, context, brush, "size", slider=True) | |||||
| UnifiedPaintPanel.prop_unified_size(row, context, brush, "use_pressure_size", text="") | |||||
| row = layout.row(align=True) | |||||
| UnifiedPaintPanel.prop_unified_strength(row, context, brush, "strength") | |||||
| UnifiedPaintPanel.prop_unified_strength(row, context, brush, "use_pressure_strength", text="") | |||||
| if capabilities.has_color: | if capabilities.has_color: | ||||
| UnifiedPaintPanel.prop_unified_color(layout, context, brush, "color", text="") | |||||
| layout.prop(brush, "blend", text="" if compact else "Blend") | layout.prop(brush, "blend", text="" if compact else "Blend") | ||||
| UnifiedPaintPanel.prop_unified(layout, context, brush, "size", unified_name="use_unified_size", pressure_name="use_pressure_size", slider=True, text="Radius") | |||||
| def brush_basic_sculpt_settings(layout, context, brush, *, compact=False): | UnifiedPaintPanel.prop_unified(layout, context, brush, "strength", unified_name="use_unified_strength", pressure_name="use_pressure_strength") | ||||
| tool_settings = context.tool_settings | |||||
| capabilities = brush.sculpt_capabilities | |||||
| row = layout.row(align=True) | |||||
| ups = tool_settings.unified_paint_settings | |||||
| if ( | |||||
| (ups.use_unified_size and ups.use_locked_size == 'SCENE') or | |||||
| ((not ups.use_unified_size) and brush.use_locked_size == 'SCENE') | |||||
| ): | |||||
| UnifiedPaintPanel.prop_unified_size(row, context, brush, "unprojected_radius", slider=True, text="Radius") | |||||
| else: | |||||
| UnifiedPaintPanel.prop_unified_size(row, context, brush, "size", slider=True) | |||||
| UnifiedPaintPanel.prop_unified_size(row, context, brush, "use_pressure_size", text="") | |||||
| # strength, use_strength_pressure, and use_strength_attenuation | |||||
| row = layout.row(align=True) | |||||
| UnifiedPaintPanel.prop_unified_strength(row, context, brush, "strength") | |||||
| if capabilities.has_strength_pressure: | |||||
| UnifiedPaintPanel.prop_unified_strength(row, context, brush, "use_pressure_strength", text="") | |||||
| # direction | |||||
| if not capabilities.has_direction: | |||||
| layout.row().prop(brush, "direction", expand=True, **({"text": ""} if compact else {})) | |||||
| def brush_basic_gpencil_paint_settings(layout, _context, brush, *, compact=True): | def brush_basic_gpencil_paint_settings(layout, _context, brush, *, compact=True): | ||||
| Context not available. | |||||