# ##### BEGIN GPL LICENSE BLOCK ##### # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation, # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # # ##### END GPL LICENSE BLOCK ##### # import bpy import math from bpy.types import ( Header, Menu, Panel, UIList, ) from .properties_paint_common import ( UnifiedPaintPanel, brush_texture_settings, brush_texpaint_common, brush_mask_texture_settings, ) from .properties_grease_pencil_common import ( AnnotationDataPanel, ) from bpy.app.translations import pgettext_iface as iface_ class ImagePaintPanel(UnifiedPaintPanel): bl_space_type = 'IMAGE_EDITOR' bl_region_type = 'TOOLS' class BrushButtonsPanel(UnifiedPaintPanel): bl_space_type = 'IMAGE_EDITOR' bl_region_type = 'TOOLS' @classmethod def poll(cls, context): sima = context.space_data toolsettings = context.tool_settings.image_paint return sima.show_paint and toolsettings.brush class UVToolsPanel: bl_space_type = 'IMAGE_EDITOR' bl_region_type = 'TOOLS' bl_category = "Tools" @classmethod def poll(cls, context): sima = context.space_data return sima.show_uvedit and not context.tool_settings.use_uv_sculpt class IMAGE_MT_view(Menu): bl_label = "View" def draw(self, context): layout = self.layout sima = context.space_data uv = sima.uv_editor toolsettings = context.tool_settings paint = toolsettings.image_paint show_uvedit = sima.show_uvedit show_render = sima.show_render layout.operator("image.properties", icon='MENU_PANEL') layout.operator("image.toolshelf", icon='MENU_PANEL') layout.separator() layout.prop(sima, "use_realtime_update") if show_uvedit: layout.prop(toolsettings, "show_uv_local_view") layout.prop(uv, "show_metadata") if paint.brush and (context.image_paint_object or sima.mode == 'PAINT'): layout.prop(uv, "show_texpaint") layout.prop(toolsettings, "show_uv_local_view", text="Show Same Material") layout.separator() layout.operator("image.view_zoom_in") layout.operator("image.view_zoom_out") layout.separator() layout.menu("IMAGE_MT_view_zoom") layout.separator() if show_uvedit: layout.operator("image.view_selected") layout.operator("image.view_all") layout.operator("image.view_all", text="View Fit").fit_view = True layout.separator() if show_render: layout.operator("image.render_border") layout.operator("image.clear_render_border") layout.separator() layout.operator("image.cycle_render_slot", text="Render Slot Cycle Next") layout.operator("image.cycle_render_slot", text="Render Slot Cycle Previous").reverse = True layout.separator() layout.menu("INFO_MT_area") class IMAGE_MT_view_zoom(Menu): bl_label = "Fractional Zoom" def draw(self, context): layout = self.layout ratios = ((1, 8), (1, 4), (1, 2), (1, 1), (2, 1), (4, 1), (8, 1)) for i, (a, b) in enumerate(ratios): if i in {3, 4}: # Draw separators around Zoom 1:1. layout.separator() layout.operator( "image.view_zoom_ratio", text=iface_(f"Zoom {a:d}:{b:d}"), translate=False, ).ratio = a / b class IMAGE_MT_select(Menu): bl_label = "Select" def draw(self, context): layout = self.layout layout.operator("uv.select_all", text="All").action = 'SELECT' layout.operator("uv.select_all", text="None").action = 'DESELECT' layout.operator("uv.select_all", text="Invert").action = 'INVERT' layout.separator() layout.operator("uv.select_box").pinned = False layout.operator("uv.select_box", text="Box Select Pinned").pinned = True layout.operator("uv.circle_select") layout.separator() layout.operator("uv.select_less", text="Less") layout.operator("uv.select_more", text="More") layout.separator() layout.operator("uv.select_pinned") layout.operator("uv.select_linked").extend = False layout.separator() layout.operator("uv.select_split") class IMAGE_MT_brush(Menu): bl_label = "Brush" def draw(self, context): layout = self.layout toolsettings = context.tool_settings settings = toolsettings.image_paint brush = settings.brush ups = context.tool_settings.unified_paint_settings layout.prop(ups, "use_unified_size", text="Unified Size") layout.prop(ups, "use_unified_strength", text="Unified Strength") layout.prop(ups, "use_unified_color", text="Unified Color") layout.separator() # Brush tool. layout.prop_menu_enum(brush, "image_tool") class IMAGE_MT_image(Menu): bl_label = "Image" def draw(self, context): layout = self.layout sima = context.space_data ima = sima.image show_render = sima.show_render layout.operator("image.new", text="New") layout.operator("image.open", text="Open...") layout.operator("image.read_viewlayers") if ima: layout.separator() if not show_render: layout.operator("image.replace", text="Replace...") layout.operator("image.reload", text="Reload") layout.operator("image.external_edit", text="Edit Externally") layout.separator() if ima: layout.operator("image.save", text="Save") layout.operator("image.save_as", text="Save As...") layout.operator("image.save_as", text="Save a Copy...").copy = True if ima and ima.source == 'SEQUENCE': layout.operator("image.save_sequence") layout.operator("image.save_dirty", text="Save All Images") if ima: layout.separator() layout.menu("IMAGE_MT_image_invert") if not show_render: if not ima.packed_file: layout.separator() layout.operator("image.pack", text="Pack") # Only for dirty && specific image types, perhaps # this could be done in operator poll too. if ima.is_dirty: if ima.source in {'FILE', 'GENERATED'} and ima.type != 'OPEN_EXR_MULTILAYER': if ima.packed_file: layout.separator() layout.operator("image.pack", text="Pack As PNG").as_png = True class IMAGE_MT_image_invert(Menu): bl_label = "Invert" def draw(self, context): layout = self.layout props = layout.operator("image.invert", text="Invert Image Colors") props.invert_r = True props.invert_g = True props.invert_b = True layout.separator() layout.operator("image.invert", text="Invert Red Channel").invert_r = True layout.operator("image.invert", text="Invert Green Channel").invert_g = True layout.operator("image.invert", text="Invert Blue Channel").invert_b = True layout.operator("image.invert", text="Invert Alpha Channel").invert_a = True class IMAGE_MT_uvs_showhide(Menu): bl_label = "Show/Hide Faces" def draw(self, context): layout = self.layout layout.operator("uv.reveal") layout.operator("uv.hide", text="Hide Selected").unselected = False layout.operator("uv.hide", text="Hide Unselected").unselected = True class IMAGE_MT_uvs_proportional(Menu): bl_label = "Proportional Editing" def draw(self, context): layout = self.layout layout.props_enum(context.tool_settings, "proportional_edit") layout.separator() layout.label(text="Falloff:") layout.props_enum(context.tool_settings, "proportional_edit_falloff") class IMAGE_MT_uvs_transform(Menu): bl_label = "Transform" def draw(self, context): layout = self.layout layout.operator("transform.translate") layout.operator("transform.rotate") layout.operator("transform.resize") layout.separator() layout.operator("transform.shear") class IMAGE_MT_uvs_snap(Menu): bl_label = "Snap" def draw(self, context): layout = self.layout layout.operator_context = 'EXEC_REGION_WIN' layout.operator("uv.snap_selected", text="Selected to Pixels").target = 'PIXELS' layout.operator("uv.snap_selected", text="Selected to Cursor").target = 'CURSOR' layout.operator("uv.snap_selected", text="Selected to Cursor (Offset)").target = 'CURSOR_OFFSET' layout.operator("uv.snap_selected", text="Selected to Adjacent Unselected").target = 'ADJACENT_UNSELECTED' layout.separator() layout.operator("uv.snap_cursor", text="Cursor to Pixels").target = 'PIXELS' layout.operator("uv.snap_cursor", text="Cursor to Selected").target = 'SELECTED' class IMAGE_MT_uvs_mirror(Menu): bl_label = "Mirror" def draw(self, context): layout = self.layout layout.operator("mesh.faces_mirror_uv") layout.separator() layout.operator_context = 'EXEC_REGION_WIN' layout.operator("transform.mirror", text="X Axis").constraint_axis[0] = True layout.operator("transform.mirror", text="Y Axis").constraint_axis[1] = True class IMAGE_MT_uvs_weldalign(Menu): bl_label = "Weld/Align" def draw(self, context): layout = self.layout layout.operator("uv.weld") # W, 1. layout.operator("uv.remove_doubles") layout.operator_enum("uv.align", "axis") # W, 2/3/4. class IMAGE_MT_uvs(Menu): bl_label = "UV" def draw(self, context): layout = self.layout sima = context.space_data uv = sima.uv_editor toolsettings = context.tool_settings layout.prop(uv, "use_snap_to_pixels") layout.prop(uv, "lock_bounds") layout.separator() layout.prop(toolsettings, "use_uv_sculpt") layout.separator() layout.prop(uv, "use_live_unwrap") layout.operator("uv.unwrap") layout.operator("uv.pin", text="Unpin").clear = True layout.operator("uv.pin").clear = False layout.separator() layout.operator("uv.pack_islands") layout.operator("uv.average_islands_scale") layout.operator("uv.minimize_stretch") layout.operator("uv.stitch") layout.separator() layout.operator("uv.mark_seam").clear = False layout.operator("uv.mark_seam", text="Clear Seam").clear = True layout.operator("uv.seams_from_islands") layout.separator() layout.menu("IMAGE_MT_uvs_transform") layout.menu("IMAGE_MT_uvs_mirror") layout.menu("IMAGE_MT_uvs_snap") layout.menu("IMAGE_MT_uvs_weldalign") layout.separator() layout.menu("IMAGE_MT_uvs_proportional") layout.separator() layout.menu("IMAGE_MT_uvs_showhide") class IMAGE_MT_uvs_select_mode(Menu): bl_label = "UV Select Mode" def draw(self, context): layout = self.layout layout.operator_context = 'INVOKE_REGION_WIN' toolsettings = context.tool_settings # Do smart things depending on whether uv_select_sync is on. if toolsettings.use_uv_select_sync: props = layout.operator("wm.context_set_value", text="Vertex", icon='VERTEXSEL') props.value = "(True, False, False)" props.data_path = "tool_settings.mesh_select_mode" props = layout.operator("wm.context_set_value", text="Edge", icon='EDGESEL') props.value = "(False, True, False)" props.data_path = "tool_settings.mesh_select_mode" props = layout.operator("wm.context_set_value", text="Face", icon='FACESEL') props.value = "(False, False, True)" props.data_path = "tool_settings.mesh_select_mode" else: props = layout.operator("wm.context_set_string", text="Vertex", icon='UV_VERTEXSEL') props.value = 'VERTEX' props.data_path = "tool_settings.uv_select_mode" props = layout.operator("wm.context_set_string", text="Edge", icon='UV_EDGESEL') props.value = 'EDGE' props.data_path = "tool_settings.uv_select_mode" props = layout.operator("wm.context_set_string", text="Face", icon='UV_FACESEL') props.value = 'FACE' props.data_path = "tool_settings.uv_select_mode" props = layout.operator("wm.context_set_string", text="Island", icon='UV_ISLANDSEL') props.value = 'ISLAND' props.data_path = "tool_settings.uv_select_mode" class IMAGE_MT_specials(Menu): bl_label = "UV Context Menu" def draw(self, context): layout = self.layout sima = context.space_data # UV Edit Mode if sima.show_uvedit: layout.operator("uv.unwrap") layout.operator("uv.follow_active_quads") layout.separator() layout.operator("uv.pin").clear = False layout.operator("uv.pin", text="Unpin").clear = True layout.separator() layout.operator("uv.weld") layout.operator("uv.stitch") layout.separator() layout.operator_enum("uv.align", "axis") # W, 2/3/4. layout.separator() layout.operator("transform.mirror", text="Mirror X").constraint_axis[0] = True layout.operator("transform.mirror", text="Mirror Y").constraint_axis[1] = True layout.separator() layout.menu("IMAGE_MT_uvs_snap") class IMAGE_MT_pivot_pie(Menu): bl_label = "Pivot Point" def draw(self, context): layout = self.layout pie = layout.menu_pie() pie.prop_enum(context.space_data, "pivot_point", value='CENTER') pie.prop_enum(context.space_data, "pivot_point", value='CURSOR') pie.prop_enum(context.space_data, "pivot_point", value='INDIVIDUAL_ORIGINS') pie.prop_enum(context.space_data, "pivot_point", value='MEDIAN') class IMAGE_MT_uvs_snap_pie(Menu): bl_label = "Snap" def draw(self, context): layout = self.layout pie = layout.menu_pie() layout.operator_context = 'EXEC_REGION_WIN' pie.operator("uv.snap_selected", text="Selected to Pixels", icon='RESTRICT_SELECT_OFF').target = 'PIXELS' pie.operator("uv.snap_cursor", text="Cursor to Pixels", icon='CURSOR').target = 'PIXELS' pie.operator("uv.snap_cursor", text="Cursor to Selected", icon='CURSOR').target = 'SELECTED' pie.operator("uv.snap_selected", text="Selected to Cursor", icon='RESTRICT_SELECT_OFF').target = 'CURSOR' pie.operator("uv.snap_selected", text="Selected to Cursor (Offset)", icon='RESTRICT_SELECT_OFF').target = 'CURSOR_OFFSET' pie.operator("uv.snap_selected", text="Selected to Adjacent Unselected", icon='RESTRICT_SELECT_OFF').target = 'ADJACENT_UNSELECTED' class IMAGE_HT_header(Header): bl_space_type = 'IMAGE_EDITOR' def draw(self, context): layout = self.layout sima = context.space_data ima = sima.image iuser = sima.image_user toolsettings = context.tool_settings mode = sima.mode show_render = sima.show_render show_uvedit = sima.show_uvedit show_maskedit = sima.show_maskedit row = layout.row(align=True) row.template_header() layout.prop(sima, "mode", text="") # UV editing. if show_uvedit: uvedit = sima.uv_editor layout.prop(toolsettings, "use_uv_select_sync", text="") if toolsettings.use_uv_select_sync: layout.template_edit_mode_selection() else: layout.prop(toolsettings, "uv_select_mode", text="", expand=True) layout.prop(uvedit, "sticky_select_mode", icon_only=True) MASK_MT_editor_menus.draw_collapsible(context, layout) layout.separator_spacer() layout.template_ID(sima, "image", new="image.new", open="image.open") if show_maskedit: row = layout.row() row.template_ID(sima, "mask", new="mask.new") layout.separator_spacer() if show_uvedit or show_maskedit or mode == 'PAINT': layout.prop(sima, "use_realtime_update", icon_only=True, icon='FILE_REFRESH') if not show_render: layout.prop(sima, "use_image_pin", text="") if show_uvedit: uvedit = sima.uv_editor mesh = context.edit_object.data layout.prop_search(mesh.uv_layers, "active", mesh, "uv_layers", text="") # Snap. row = layout.row(align=True) row.prop(toolsettings, "use_snap", text="") row.prop(toolsettings, "snap_uv_element", icon_only=True) if toolsettings.snap_uv_element != 'INCREMENT': row.prop(toolsettings, "snap_target", text="") row = layout.row(align=True) row.prop(toolsettings, "proportional_edit", icon_only=True) # if toolsettings.proportional_edit != 'DISABLED': sub = row.row(align=True) sub.active = toolsettings.proportional_edit != 'DISABLED' sub.prop(toolsettings, "proportional_edit_falloff", icon_only=True) layout.prop(sima, "pivot_point", icon_only=True) row = layout.row() row.popover( panel="IMAGE_PT_view_display", text="Display" ) if ima: if ima.is_stereo_3d: row = layout.row() row.prop(sima, "show_stereo_3d", text="") # layers. layout.template_image_layers(ima, iuser) # draw options. row = layout.row() row.prop(sima, "display_channels", icon_only=True) row = layout.row(align=True) if ima.type == 'COMPOSITE': row.operator("image.record_composite", icon='REC') if ima.type == 'COMPOSITE' and ima.source in {'MOVIE', 'SEQUENCE'}: row.operator("image.play_composite", icon='PLAY') class MASK_MT_editor_menus(Menu): bl_idname = "MASK_MT_editor_menus" bl_label = "" def draw(self, context): self.draw_menus(self.layout, context) @staticmethod def draw_menus(layout, context): sima = context.space_data ima = sima.image show_uvedit = sima.show_uvedit show_maskedit = sima.show_maskedit show_paint = sima.show_paint layout.menu("IMAGE_MT_view") if show_uvedit: layout.menu("IMAGE_MT_select") if show_maskedit: layout.menu("MASK_MT_select") if show_paint: layout.menu("IMAGE_MT_brush") if ima and ima.is_dirty: layout.menu("IMAGE_MT_image", text="Image*") else: layout.menu("IMAGE_MT_image", text="Image") if show_uvedit: layout.menu("IMAGE_MT_uvs") if show_maskedit: layout.menu("MASK_MT_mask") # ----------------------------------------------------------------------------- # Mask (similar code in space_clip.py, keep in sync) # note! - panel placement does _not_ fit well with image panels... need to fix. from .properties_mask_common import ( MASK_PT_mask, MASK_PT_layers, MASK_PT_spline, MASK_PT_point, MASK_PT_display, MASK_PT_tools, MASK_PT_add, ) class IMAGE_PT_mask(MASK_PT_mask, Panel): bl_space_type = 'IMAGE_EDITOR' bl_region_type = 'UI' class IMAGE_PT_mask_layers(MASK_PT_layers, Panel): bl_space_type = 'IMAGE_EDITOR' bl_region_type = 'UI' class IMAGE_PT_mask_display(MASK_PT_display, Panel): bl_space_type = 'IMAGE_EDITOR' bl_region_type = 'UI' class IMAGE_PT_active_mask_spline(MASK_PT_spline, Panel): bl_space_type = 'IMAGE_EDITOR' bl_region_type = 'UI' class IMAGE_PT_active_mask_point(MASK_PT_point, Panel): bl_space_type = 'IMAGE_EDITOR' bl_region_type = 'UI' class IMAGE_PT_tools_mask(MASK_PT_tools, Panel): bl_space_type = 'IMAGE_EDITOR' bl_region_type = 'TOOLS' bl_category = 'Mask' class IMAGE_PT_tools_mask_add(MASK_PT_add, Panel): bl_space_type = 'IMAGE_EDITOR' bl_region_type = 'TOOLS' bl_category = 'Mask' # --- end mask --- class IMAGE_PT_image_properties(Panel): bl_space_type = 'IMAGE_EDITOR' bl_region_type = 'UI' bl_label = "Image" @classmethod def poll(cls, context): sima = context.space_data return (sima.image) def draw(self, context): layout = self.layout sima = context.space_data iuser = sima.image_user layout.template_image(sima, "image", iuser, multiview=True) class IMAGE_PT_view_display(Panel): bl_space_type = 'IMAGE_EDITOR' bl_region_type = 'HEADER' bl_label = "Display" @classmethod def poll(cls, context): sima = context.space_data return (sima and (sima.image or sima.show_uvedit)) def draw(self, context): layout = self.layout layout.use_property_split = True sima = context.space_data ima = sima.image show_uvedit = sima.show_uvedit show_maskedit = sima.show_maskedit uvedit = sima.uv_editor col = layout.column() if ima: col.prop(ima, "display_aspect", text="Aspect Ratio") col.prop(sima, "show_repeat", text="Repeat Image") if show_uvedit or show_maskedit: col.separator() col = layout.column() col.prop(sima, "cursor_location", text="Cursor Location") if show_uvedit: col.prop(uvedit, "show_pixel_coords", text="Pixel Coordinates") class IMAGE_PT_view_display_uv_edit_overlays(Panel): bl_space_type = 'IMAGE_EDITOR' bl_region_type = 'HEADER' bl_label = "Overlays" bl_parent_id = 'IMAGE_PT_view_display' bl_options = {'DEFAULT_CLOSED'} @classmethod def poll(cls, context): sima = context.space_data return (sima and (sima.show_uvedit)) def draw(self, context): layout = self.layout layout.use_property_split = True sima = context.space_data uvedit = sima.uv_editor col = layout.column() split = col.split(factor=0.6) split.prop(uvedit, "show_edges", text="Edges") split.prop(uvedit, "edge_display_type", text="") col.prop(uvedit, "show_faces", text="Faces") col = layout.column() col.prop(uvedit, "show_smooth_edges", text="Smooth") col.prop(uvedit, "show_modified_edges", text="Modified") class IMAGE_PT_view_display_uv_edit_overlays_advanced(Panel): bl_space_type = 'IMAGE_EDITOR' bl_region_type = 'HEADER' bl_label = "Advanced" bl_parent_id = 'IMAGE_PT_view_display_uv_edit_overlays' bl_options = {'DEFAULT_CLOSED'} @classmethod def poll(cls, context): sima = context.space_data return (sima and (sima.show_uvedit)) def draw(self, context): layout = self.layout layout.use_property_split = True sima = context.space_data uvedit = sima.uv_editor col = layout.column() col.prop(uvedit, "show_stretch", text="Stretch") sub = col.column() sub.active = uvedit.show_stretch sub.prop(uvedit, "display_stretch_type", text="Type") class IMAGE_UL_render_slots(UIList): def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): slot = item layout.prop(slot, "name", text="", emboss=False) class IMAGE_PT_render_slots(Panel): bl_space_type = 'IMAGE_EDITOR' bl_region_type = 'UI' bl_label = "Render Slots" @classmethod def poll(cls, context): sima = context.space_data return (sima and sima.image and sima.show_render) def draw(self, context): layout = self.layout sima = context.space_data ima = sima.image row = layout.row() col = row.column() col.template_list( "IMAGE_UL_render_slots", "render_slots", ima, "render_slots", ima.render_slots, "active_index", rows=3 ) col = row.column(align=True) col.operator("image.add_render_slot", icon='ZOOMIN', text="") col.operator("image.remove_render_slot", icon='ZOOMOUT', text="") col.separator() col.operator("image.clear_render_slot", icon='X', text="") class IMAGE_PT_paint(Panel, ImagePaintPanel): bl_label = "Paint" bl_category = "Tools" def draw(self, context): layout = self.layout settings = context.tool_settings.image_paint brush = settings.brush col = layout.column() col.template_ID_preview(settings, "brush", new="brush.add", rows=2, cols=6) if brush: brush_texpaint_common(self, context, layout, brush, settings) @classmethod def poll(cls, context): sima = context.space_data return sima.show_paint class IMAGE_PT_tools_brush_overlay(BrushButtonsPanel, Panel): bl_label = "Overlay" bl_options = {'DEFAULT_CLOSED'} bl_category = "Options" def draw(self, context): layout = self.layout toolsettings = context.tool_settings.image_paint brush = toolsettings.brush tex_slot = brush.texture_slot tex_slot_mask = brush.mask_texture_slot col = layout.column() col.label(text="Curve:") row = col.row(align=True) row.prop( brush, "use_cursor_overlay", text="", toggle=True, icon='RESTRICT_VIEW_OFF' if brush.use_cursor_overlay else 'RESTRICT_VIEW_ON', ) sub = row.row(align=True) sub.prop(brush, "cursor_overlay_alpha", text="Alpha") sub.prop(brush, "use_cursor_overlay_override", toggle=True, text="", icon='BRUSH_DATA') col.active = brush.brush_capabilities.has_overlay col.label(text="Texture:") row = col.row(align=True) if tex_slot.map_mode != 'STENCIL': row.prop( brush, "use_primary_overlay", text="", toggle=True, icon='RESTRICT_VIEW_OFF' if brush.use_primary_overlay else 'RESTRICT_VIEW_ON', ) sub = row.row(align=True) sub.prop(brush, "texture_overlay_alpha", text="Alpha") sub.prop(brush, "use_primary_overlay_override", toggle=True, text="", icon='BRUSH_DATA') col.label(text="Mask Texture:") row = col.row(align=True) if tex_slot_mask.map_mode != 'STENCIL': row.prop( brush, "use_secondary_overlay", text="", toggle=True, icon='RESTRICT_VIEW_OFF' if brush.use_secondary_overlay else 'RESTRICT_VIEW_ON', ) sub = row.row(align=True) sub.prop(brush, "mask_overlay_alpha", text="Alpha") sub.prop(brush, "use_secondary_overlay_override", toggle=True, text="", icon='BRUSH_DATA') class IMAGE_PT_tools_brush_texture(BrushButtonsPanel, Panel): bl_label = "Texture" bl_options = {'DEFAULT_CLOSED'} bl_category = "Tools" def draw(self, context): layout = self.layout toolsettings = context.tool_settings.image_paint brush = toolsettings.brush col = layout.column() col.template_ID_preview(brush, "texture", new="texture.new", rows=3, cols=8) brush_texture_settings(col, brush, 0) class IMAGE_PT_tools_mask_texture(BrushButtonsPanel, Panel): bl_label = "Texture Mask" bl_options = {'DEFAULT_CLOSED'} bl_category = "Tools" def draw(self, context): layout = self.layout brush = context.tool_settings.image_paint.brush col = layout.column() col.template_ID_preview(brush, "mask_texture", new="texture.new", rows=3, cols=8) brush_mask_texture_settings(col, brush) class IMAGE_PT_tools_brush_tool(BrushButtonsPanel, Panel): bl_label = "Tool" bl_options = {'DEFAULT_CLOSED'} bl_category = "Options" def draw(self, context): layout = self.layout toolsettings = context.tool_settings.image_paint brush = toolsettings.brush layout.prop(brush, "image_tool", text="") row = layout.row(align=True) row.prop(brush, "use_paint_sculpt", text="", icon='SCULPTMODE_HLT') row.prop(brush, "use_paint_vertex", text="", icon='VPAINT_HLT') row.prop(brush, "use_paint_weight", text="", icon='WPAINT_HLT') row.prop(brush, "use_paint_image", text="", icon='TPAINT_HLT') class IMAGE_PT_paint_stroke(BrushButtonsPanel, Panel): bl_label = "Paint Stroke" bl_options = {'DEFAULT_CLOSED'} bl_category = "Tools" def draw(self, context): layout = self.layout toolsettings = context.tool_settings.image_paint brush = toolsettings.brush col = layout.column() col.label(text="Stroke Method:") col.prop(brush, "stroke_method", text="") if brush.use_anchor: col.separator() col.prop(brush, "use_edge_to_edge", text="Edge To Edge") if brush.use_airbrush: col.separator() col.prop(brush, "rate", text="Rate", slider=True) if brush.use_space: col.separator() row = col.row(align=True) row.prop(brush, "spacing", text="Spacing") row.prop(brush, "use_pressure_spacing", toggle=True, text="") if brush.use_line or brush.use_curve: col.separator() row = col.row(align=True) row.prop(brush, "spacing", text="Spacing") if brush.use_curve: col.separator() col.template_ID(brush, "paint_curve", new="paintcurve.new") col.operator("paintcurve.draw") col = layout.column() col.separator() row = col.row(align=True) row.prop(brush, "use_relative_jitter", icon_only=True) if brush.use_relative_jitter: row.prop(brush, "jitter", slider=True) else: row.prop(brush, "jitter_absolute") row.prop(brush, "use_pressure_jitter", toggle=True, text="") col = layout.column() col.separator() if brush.brush_capabilities.has_smooth_stroke: col.prop(brush, "use_smooth_stroke") sub = col.column() sub.active = brush.use_smooth_stroke sub.prop(brush, "smooth_stroke_radius", text="Radius", slider=True) sub.prop(brush, "smooth_stroke_factor", text="Factor", slider=True) col.separator() col.prop(toolsettings, "input_samples") class IMAGE_PT_paint_curve(BrushButtonsPanel, Panel): bl_label = "Paint Curve" bl_options = {'DEFAULT_CLOSED'} bl_category = "Tools" def draw(self, context): layout = self.layout toolsettings = context.tool_settings.image_paint brush = toolsettings.brush layout.template_curve_mapping(brush, "curve") col = layout.column(align=True) row = col.row(align=True) row.operator("brush.curve_preset", icon='SMOOTHCURVE', text="").shape = 'SMOOTH' row.operator("brush.curve_preset", icon='SPHERECURVE', text="").shape = 'ROUND' row.operator("brush.curve_preset", icon='ROOTCURVE', text="").shape = 'ROOT' row.operator("brush.curve_preset", icon='SHARPCURVE', text="").shape = 'SHARP' row.operator("brush.curve_preset", icon='LINCURVE', text="").shape = 'LINE' row.operator("brush.curve_preset", icon='NOCURVE', text="").shape = 'MAX' class IMAGE_PT_tools_imagepaint_symmetry(BrushButtonsPanel, Panel): bl_category = "Tools" bl_context = "imagepaint" bl_label = "Tiling" bl_options = {'DEFAULT_CLOSED'} def draw(self, context): layout = self.layout toolsettings = context.tool_settings ipaint = toolsettings.image_paint col = layout.column(align=True) row = col.row(align=True) row.prop(ipaint, "tile_x", text="X", toggle=True) row.prop(ipaint, "tile_y", text="Y", toggle=True) class IMAGE_PT_tools_brush_appearance(BrushButtonsPanel, Panel): bl_label = "Appearance" bl_options = {'DEFAULT_CLOSED'} bl_category = "Options" def draw(self, context): layout = self.layout toolsettings = context.tool_settings.image_paint brush = toolsettings.brush if brush is None: # unlikely but can happen. layout.label(text="Brush Unset") return col = layout.column(align=True) col.prop(toolsettings, "show_brush") sub = col.column() sub.active = toolsettings.show_brush sub.prop(brush, "cursor_color_add", text="") col.separator() col.prop(brush, "use_custom_icon") sub = col.column() sub.active = brush.use_custom_icon sub.prop(brush, "icon_filepath", text="") class IMAGE_PT_tools_paint_options(BrushButtonsPanel, Panel): bl_label = "Image Paint" bl_category = "Options" def draw(self, context): layout = self.layout toolsettings = context.tool_settings # brush = toolsettings.image_paint.brush ups = toolsettings.unified_paint_settings col = layout.column(align=True) col.label(text="Unified Settings:") row = col.row() row.prop(ups, "use_unified_size", text="Size") row.prop(ups, "use_unified_strength", text="Strength") col.prop(ups, "use_unified_color", text="Color") class IMAGE_PT_uv_sculpt_curve(Panel): bl_space_type = 'PROPERTIES' bl_region_type = 'WINDOW' bl_context = ".uv_sculpt" # dot on purpose (access from topbar) bl_category = "Options" bl_label = "UV Sculpt Curve" bl_options = {'DEFAULT_CLOSED'} @classmethod def poll(cls, context): return (context.uv_sculpt_object is not None) def draw(self, context): layout = self.layout toolsettings = context.tool_settings uvsculpt = toolsettings.uv_sculpt brush = uvsculpt.brush layout.template_curve_mapping(brush, "curve") row = layout.row(align=True) row.operator("brush.curve_preset", icon='SMOOTHCURVE', text="").shape = 'SMOOTH' row.operator("brush.curve_preset", icon='SPHERECURVE', text="").shape = 'ROUND' row.operator("brush.curve_preset", icon='ROOTCURVE', text="").shape = 'ROOT' row.operator("brush.curve_preset", icon='SHARPCURVE', text="").shape = 'SHARP' row.operator("brush.curve_preset", icon='LINCURVE', text="").shape = 'LINE' row.operator("brush.curve_preset", icon='NOCURVE', text="").shape = 'MAX' class IMAGE_PT_uv_sculpt(Panel): bl_space_type = 'PROPERTIES' bl_region_type = 'WINDOW' bl_context = ".uv_sculpt" # dot on purpose (access from topbar) bl_category = "Options" bl_label = "UV Sculpt" @classmethod def poll(cls, context): return (context.uv_sculpt_object is not None) def draw(self, context): from .properties_paint_common import UnifiedPaintPanel layout = self.layout toolsettings = context.tool_settings uvsculpt = toolsettings.uv_sculpt brush = uvsculpt.brush if not self.is_popover: if brush: col = layout.column() row = col.row(align=True) UnifiedPaintPanel.prop_unified_size(row, context, brush, "size", slider=True, text="Radius") UnifiedPaintPanel.prop_unified_size(row, context, brush, "use_pressure_size") row = col.row(align=True) UnifiedPaintPanel.prop_unified_strength(row, context, brush, "strength", slider=True, text="Strength") UnifiedPaintPanel.prop_unified_strength(row, context, brush, "use_pressure_strength") col = layout.column() col.prop(toolsettings, "uv_sculpt_lock_borders") col.prop(toolsettings, "uv_sculpt_all_islands") col.prop(toolsettings, "uv_sculpt_tool") if toolsettings.uv_sculpt_tool == 'RELAX': col.prop(toolsettings, "uv_relax_method") col.prop(uvsculpt, "show_brush") class ImageScopesPanel: @classmethod def poll(cls, context): sima = context.space_data if not (sima and sima.image): return False # scopes are not updated in paint modes, hide. if sima.mode == 'PAINT': return False ob = context.active_object if ob and ob.mode in {'TEXTURE_PAINT', 'EDIT'}: return False return True class IMAGE_PT_view_scopes(ImageScopesPanel, Panel): bl_space_type = 'IMAGE_EDITOR' bl_region_type = 'UI' bl_label = "Scopes" def draw(self, layout): return # nothing to draw. class IMAGE_PT_view_histogram(ImageScopesPanel, Panel): bl_space_type = 'IMAGE_EDITOR' bl_region_type = 'UI' bl_label = "Histogram" bl_parent_id = 'IMAGE_PT_view_scopes' def draw(self, context): layout = self.layout sima = context.space_data hist = sima.scopes.histogram layout.template_histogram(sima.scopes, "histogram") row = layout.row(align=True) row.prop(hist, "mode", expand=True) row.prop(hist, "show_line", text="") class IMAGE_PT_view_waveform(ImageScopesPanel, Panel): bl_space_type = 'IMAGE_EDITOR' bl_region_type = 'UI' bl_label = "Waveform" bl_parent_id = 'IMAGE_PT_view_scopes' bl_options = {'DEFAULT_CLOSED'} def draw(self, context): layout = self.layout sima = context.space_data layout.template_waveform(sima, "scopes") row = layout.split(factor=0.75) row.prop(sima.scopes, "waveform_alpha") row.prop(sima.scopes, "waveform_mode", text="") class IMAGE_PT_view_vectorscope(ImageScopesPanel, Panel): bl_space_type = 'IMAGE_EDITOR' bl_region_type = 'UI' bl_label = "Vectorscope" bl_parent_id = 'IMAGE_PT_view_scopes' bl_options = {'DEFAULT_CLOSED'} def draw(self, context): layout = self.layout sima = context.space_data layout.template_vectorscope(sima, "scopes") layout.prop(sima.scopes, "vectorscope_alpha") class IMAGE_PT_sample_line(ImageScopesPanel, Panel): bl_space_type = 'IMAGE_EDITOR' bl_region_type = 'UI' bl_label = "Sample Line" bl_parent_id = 'IMAGE_PT_view_scopes' bl_options = {'DEFAULT_CLOSED'} def draw(self, context): layout = self.layout sima = context.space_data hist = sima.sample_histogram layout.operator("image.sample_line") layout.template_histogram(sima, "sample_histogram") row = layout.row(align=True) row.prop(hist, "mode", expand=True) row.prop(hist, "show_line", text="") class IMAGE_PT_scope_sample(ImageScopesPanel, Panel): bl_space_type = 'IMAGE_EDITOR' bl_region_type = 'UI' bl_label = "Samples" bl_parent_id = 'IMAGE_PT_view_scopes' bl_options = {'DEFAULT_CLOSED'} def draw(self, context): layout = self.layout layout.use_property_split = True flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True) sima = context.space_data col = flow.column() col.prop(sima.scopes, "use_full_resolution") col = flow.column() col.active = not sima.scopes.use_full_resolution col.prop(sima.scopes, "accuracy") # Grease Pencil properties class IMAGE_PT_grease_pencil(AnnotationDataPanel, Panel): bl_space_type = 'IMAGE_EDITOR' bl_region_type = 'UI' # NOTE: this is just a wrapper around the generic GP Panel. # Grease Pencil drawing tools. classes = ( IMAGE_MT_view, IMAGE_MT_view_zoom, IMAGE_MT_select, IMAGE_MT_brush, IMAGE_MT_image, IMAGE_MT_image_invert, IMAGE_MT_uvs, IMAGE_MT_uvs_showhide, IMAGE_MT_uvs_proportional, IMAGE_MT_uvs_transform, IMAGE_MT_uvs_snap, IMAGE_MT_uvs_mirror, IMAGE_MT_uvs_weldalign, IMAGE_MT_uvs_select_mode, IMAGE_MT_specials, IMAGE_MT_pivot_pie, IMAGE_MT_uvs_snap_pie, IMAGE_HT_header, MASK_MT_editor_menus, IMAGE_PT_mask, IMAGE_PT_tools_mask_add, IMAGE_PT_mask_layers, IMAGE_PT_mask_display, IMAGE_PT_active_mask_spline, IMAGE_PT_active_mask_point, IMAGE_PT_image_properties, IMAGE_UL_render_slots, IMAGE_PT_render_slots, IMAGE_PT_view_display, IMAGE_PT_view_display_uv_edit_overlays, IMAGE_PT_view_display_uv_edit_overlays_advanced, IMAGE_PT_paint, IMAGE_PT_tools_brush_overlay, IMAGE_PT_tools_brush_texture, IMAGE_PT_tools_mask, IMAGE_PT_tools_mask_texture, IMAGE_PT_tools_brush_tool, IMAGE_PT_paint_stroke, IMAGE_PT_paint_curve, IMAGE_PT_tools_imagepaint_symmetry, IMAGE_PT_tools_brush_appearance, IMAGE_PT_tools_paint_options, IMAGE_PT_uv_sculpt, IMAGE_PT_uv_sculpt_curve, IMAGE_PT_view_scopes, IMAGE_PT_view_histogram, IMAGE_PT_view_waveform, IMAGE_PT_view_vectorscope, IMAGE_PT_sample_line, IMAGE_PT_scope_sample, IMAGE_PT_grease_pencil, ) if __name__ == "__main__": # only for live edit. from bpy.utils import register_class for cls in classes: register_class(cls)