Cleanup: style
[blender.git] / release / scripts / startup / bl_ui / properties_paint_common.py
1 # ##### BEGIN GPL LICENSE BLOCK #####
2 #
3 #  This program is free software; you can redistribute it and/or
4 #  modify it under the terms of the GNU General Public License
5 #  as published by the Free Software Foundation; either version 2
6 #  of the License, or (at your option) any later version.
7 #
8 #  This program is distributed in the hope that it will be useful,
9 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
10 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 #  GNU General Public License for more details.
12 #
13 #  You should have received a copy of the GNU General Public License
14 #  along with this program; if not, write to the Free Software Foundation,
15 #  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 #
17 # ##### END GPL LICENSE BLOCK #####
18
19 # <pep8 compliant>
20 from bpy.types import Menu
21
22
23 class UnifiedPaintPanel:
24     # subclass must set
25     # bl_space_type = 'IMAGE_EDITOR'
26     # bl_region_type = 'UI'
27
28     @staticmethod
29     def paint_settings(context):
30         tool_settings = context.tool_settings
31
32         if context.sculpt_object:
33             return tool_settings.sculpt
34         elif context.vertex_paint_object:
35             return tool_settings.vertex_paint
36         elif context.weight_paint_object:
37             return tool_settings.weight_paint
38         elif context.image_paint_object:
39             if (tool_settings.image_paint and tool_settings.image_paint.detect_data()):
40                 return tool_settings.image_paint
41
42             return None
43         elif context.particle_edit_object:
44             return tool_settings.particle_edit
45
46         return None
47
48     @staticmethod
49     def unified_paint_settings(parent, context):
50         ups = context.tool_settings.unified_paint_settings
51
52         flow = parent.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
53
54         col = flow.column()
55         col.prop(ups, "use_unified_size", text="Size")
56         col = flow.column()
57         col.prop(ups, "use_unified_strength", text="Strength")
58         if context.weight_paint_object:
59             col = flow.column()
60             col.prop(ups, "use_unified_weight", text="Weight")
61         elif context.vertex_paint_object or context.image_paint_object:
62             col = flow.column()
63             col.prop(ups, "use_unified_color", text="Color")
64         else:
65             col = flow.column()
66             col.prop(ups, "use_unified_color", text="Color")
67
68     @staticmethod
69     def prop_unified_size(parent, context, brush, prop_name, icon='NONE', text="", slider=False):
70         ups = context.tool_settings.unified_paint_settings
71         ptr = ups if ups.use_unified_size else brush
72         parent.prop(ptr, prop_name, icon=icon, text=text, slider=slider)
73
74     @staticmethod
75     def prop_unified_strength(parent, context, brush, prop_name, icon='NONE', text="", slider=False):
76         ups = context.tool_settings.unified_paint_settings
77         ptr = ups if ups.use_unified_strength else brush
78         parent.prop(ptr, prop_name, icon=icon, text=text, slider=slider)
79
80     @staticmethod
81     def prop_unified_weight(parent, context, brush, prop_name, icon='NONE', text="", slider=False):
82         ups = context.tool_settings.unified_paint_settings
83         ptr = ups if ups.use_unified_weight else brush
84         parent.prop(ptr, prop_name, icon=icon, text=text, slider=slider)
85
86     @staticmethod
87     def prop_unified_color(parent, context, brush, prop_name, text=""):
88         ups = context.tool_settings.unified_paint_settings
89         ptr = ups if ups.use_unified_color else brush
90         parent.prop(ptr, prop_name, text=text)
91
92     @staticmethod
93     def prop_unified_color_picker(parent, context, brush, prop_name, value_slider=True):
94         ups = context.tool_settings.unified_paint_settings
95         ptr = ups if ups.use_unified_color else brush
96         parent.template_color_picker(ptr, prop_name, value_slider=value_slider)
97
98
99 class VIEW3D_MT_tools_projectpaint_clone(Menu):
100     bl_label = "Clone Layer"
101
102     def draw(self, context):
103         layout = self.layout
104
105         for i, uv_layer in enumerate(context.active_object.data.uv_layers):
106             props = layout.operator("wm.context_set_int", text=uv_layer.name, translate=False)
107             props.data_path = "active_object.data.uv_layer_clone_index"
108             props.value = i
109
110
111 def brush_texpaint_common(panel, context, layout, brush, settings, projpaint=False):
112     capabilities = brush.image_paint_capabilities
113
114     col = layout.column()
115
116     if brush.image_tool in {'DRAW', 'FILL'}:
117         if brush.blend not in {'ERASE_ALPHA', 'ADD_ALPHA'}:
118             if not brush.use_gradient:
119                 panel.prop_unified_color_picker(col, context, brush, "color", value_slider=True)
120
121             if settings.palette:
122                 col.template_palette(settings, "palette", color=True)
123
124             if brush.use_gradient:
125                 col.label(text="Gradient Colors")
126                 col.template_color_ramp(brush, "gradient", expand=True)
127
128                 if brush.image_tool == 'DRAW':
129                     col.label(text="Background Color")
130                     row = col.row(align=True)
131                     panel.prop_unified_color(row, context, brush, "secondary_color", text="")
132                     col.prop(brush, "gradient_stroke_mode", text="Mode")
133                     if brush.gradient_stroke_mode in {'SPACING_REPEAT', 'SPACING_CLAMP'}:
134                         col.prop(brush, "grad_spacing")
135                 else:  # if brush.image_tool == 'FILL':
136                     col.prop(brush, "gradient_fill_mode")
137             else:
138                 row = col.row(align=True)
139                 panel.prop_unified_color(row, context, brush, "color", text="")
140                 if brush.image_tool == 'FILL' and not projpaint:
141                     col.prop(brush, "fill_threshold")
142                 else:
143                     panel.prop_unified_color(row, context, brush, "secondary_color", text="")
144                     row.separator()
145                     row.operator("paint.brush_colors_flip", icon='FILE_REFRESH', text="")
146         else:
147             if brush.image_tool == 'FILL' and not projpaint:
148                 col.prop(brush, "fill_threshold")
149
150     elif brush.image_tool == 'SOFTEN':
151         col = layout.column(align=True)
152         col.row().prop(brush, "direction", expand=True)
153         col.separator()
154         col.prop(brush, "sharp_threshold")
155         if not projpaint:
156             col.prop(brush, "blur_kernel_radius")
157         col.separator()
158         col.prop(brush, "blur_mode")
159     elif brush.image_tool == 'MASK':
160         col.prop(brush, "weight", text="Mask Value", slider=True)
161
162     elif brush.image_tool == 'CLONE':
163         col.separator()
164         if projpaint:
165             if settings.mode == 'MATERIAL':
166                 col.prop(settings, "use_clone_layer", text="Clone from Paint Slot")
167             elif settings.mode == 'IMAGE':
168                 col.prop(settings, "use_clone_layer", text="Clone from Image/UV Map")
169
170             if settings.use_clone_layer:
171                 ob = context.active_object
172                 col = layout.column()
173
174                 if settings.mode == 'MATERIAL':
175                     if len(ob.material_slots) > 1:
176                         col.label(text="Materials")
177                         col.template_list("MATERIAL_UL_matslots", "",
178                                           ob, "material_slots",
179                                           ob, "active_material_index", rows=2)
180
181                     mat = ob.active_material
182                     if mat:
183                         col.label(text="Source Clone Slot")
184                         col.template_list("TEXTURE_UL_texpaintslots", "",
185                                           mat, "texture_paint_images",
186                                           mat, "paint_clone_slot", rows=2)
187
188                 elif settings.mode == 'IMAGE':
189                     mesh = ob.data
190
191                     clone_text = mesh.uv_layer_clone.name if mesh.uv_layer_clone else ""
192                     col.label(text="Source Clone Image")
193                     col.template_ID(settings, "clone_image")
194                     col.label(text="Source Clone UV Map")
195                     col.menu("VIEW3D_MT_tools_projectpaint_clone", text=clone_text, translate=False)
196         else:
197             col.prop(brush, "clone_image", text="Image")
198             col.prop(brush, "clone_alpha", text="Alpha")
199
200     col.separator()
201
202     if capabilities.has_radius:
203         row = col.row(align=True)
204         panel.prop_unified_size(row, context, brush, "size", slider=True, text="Radius")
205         panel.prop_unified_size(row, context, brush, "use_pressure_size")
206
207     row = col.row(align=True)
208
209     if capabilities.has_space_attenuation:
210         row.prop(brush, "use_space_attenuation", toggle=True, icon_only=True)
211
212     panel.prop_unified_strength(row, context, brush, "strength", text="Strength")
213     panel.prop_unified_strength(row, context, brush, "use_pressure_strength")
214
215     if brush.image_tool in {'DRAW', 'FILL'}:
216         col.separator()
217         col.prop(brush, "blend", text="Blend")
218
219     col = layout.column()
220
221     # use_accumulate
222     if capabilities.has_accumulate:
223         col = layout.column(align=True)
224         col.prop(brush, "use_accumulate")
225
226     if projpaint:
227         col.prop(brush, "use_alpha")
228
229     col.prop(brush, "use_gradient")
230
231     col.separator()
232     col.template_ID(settings, "palette", new="palette.new")
233
234
235 # Used in both the View3D toolbar and texture properties
236 def brush_texture_settings(layout, brush, sculpt):
237     tex_slot = brush.texture_slot
238
239     layout.use_property_split = True
240     layout.use_property_decorate = False
241
242     # map_mode
243     if sculpt:
244         layout.prop(tex_slot, "map_mode", text="Mapping")
245     else:
246         layout.prop(tex_slot, "tex_paint_map_mode", text="Mapping")
247
248     layout.separator()
249
250     if tex_slot.map_mode == 'STENCIL':
251         if brush.texture and brush.texture.type == 'IMAGE':
252             layout.operator("brush.stencil_fit_image_aspect")
253         layout.operator("brush.stencil_reset_transform")
254
255     # angle and texture_angle_source
256     if tex_slot.has_texture_angle:
257         col = layout.column()
258         col.prop(tex_slot, "angle", text="Angle")
259         if tex_slot.has_texture_angle_source:
260             col.prop(tex_slot, "use_rake", text="Rake")
261
262             if brush.brush_capabilities.has_random_texture_angle and tex_slot.has_random_texture_angle:
263                 if sculpt:
264                     if brush.sculpt_capabilities.has_random_texture_angle:
265                         col.prop(tex_slot, "use_random", text="Random")
266                         if tex_slot.use_random:
267                             col.prop(tex_slot, "random_angle", text="Raandom Angle")
268                 else:
269                     col.prop(tex_slot, "use_random", text="Random")
270                     if tex_slot.use_random:
271                         col.prop(tex_slot, "random_angle", text="Random Angle")
272
273     # scale and offset
274     layout.prop(tex_slot, "offset")
275     layout.prop(tex_slot, "scale")
276
277     if sculpt:
278         # texture_sample_bias
279         layout.prop(brush, "texture_sample_bias", slider=True, text="Sample Bias")
280
281
282 def brush_mask_texture_settings(layout, brush):
283     mask_tex_slot = brush.mask_texture_slot
284
285     layout.use_property_split = True
286     layout.use_property_decorate = False
287
288     # map_mode
289     layout.row().prop(mask_tex_slot, "mask_map_mode", text="Mask Mapping")
290
291     if mask_tex_slot.map_mode == 'STENCIL':
292         if brush.mask_texture and brush.mask_texture.type == 'IMAGE':
293             layout.operator("brush.stencil_fit_image_aspect").mask = True
294         layout.operator("brush.stencil_reset_transform").mask = True
295
296     col = layout.column()
297     col.prop(brush, "use_pressure_masking", text="Pressure Masking")
298     # angle and texture_angle_source
299     if mask_tex_slot.has_texture_angle:
300         col = layout.column()
301         col.prop(mask_tex_slot, "angle", text="Angle")
302         if mask_tex_slot.has_texture_angle_source:
303             col.prop(mask_tex_slot, "use_rake", text="Rake")
304
305             if brush.brush_capabilities.has_random_texture_angle and mask_tex_slot.has_random_texture_angle:
306                 col.prop(mask_tex_slot, "use_random", text="Random")
307                 if mask_tex_slot.use_random:
308                     col.prop(mask_tex_slot, "random_angle", text="Random Angle")
309
310     # scale and offset
311     col.prop(mask_tex_slot, "offset")
312     col.prop(mask_tex_slot, "scale")
313
314
315 classes = (
316     VIEW3D_MT_tools_projectpaint_clone,
317 )
318
319 if __name__ == "__main__":  # only for live edit.
320     from bpy.utils import register_class
321     for cls in classes:
322         register_class(cls)