Cleanup: use 'tool_settings' name everywhere in UI scripts
[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         parent.label(text="Unified Settings:")
52         row = parent.row()
53         row.prop(ups, "use_unified_size", text="Size")
54         row.prop(ups, "use_unified_strength", text="Strength")
55         if context.weight_paint_object:
56             parent.prop(ups, "use_unified_weight", text="Weight")
57         elif context.vertex_paint_object or context.image_paint_object:
58             parent.prop(ups, "use_unified_color", text="Color")
59         else:
60             parent.prop(ups, "use_unified_color", text="Color")
61
62     @staticmethod
63     def prop_unified_size(parent, context, brush, prop_name, icon='NONE', text="", slider=False):
64         ups = context.tool_settings.unified_paint_settings
65         ptr = ups if ups.use_unified_size else brush
66         parent.prop(ptr, prop_name, icon=icon, text=text, slider=slider)
67
68     @staticmethod
69     def prop_unified_strength(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_strength else brush
72         parent.prop(ptr, prop_name, icon=icon, text=text, slider=slider)
73
74     @staticmethod
75     def prop_unified_weight(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_weight else brush
78         parent.prop(ptr, prop_name, icon=icon, text=text, slider=slider)
79
80     @staticmethod
81     def prop_unified_color(parent, context, brush, prop_name, text=""):
82         ups = context.tool_settings.unified_paint_settings
83         ptr = ups if ups.use_unified_color else brush
84         parent.prop(ptr, prop_name, text=text)
85
86     @staticmethod
87     def prop_unified_color_picker(parent, context, brush, prop_name, value_slider=True):
88         ups = context.tool_settings.unified_paint_settings
89         ptr = ups if ups.use_unified_color else brush
90         parent.template_color_picker(ptr, prop_name, value_slider=value_slider)
91
92
93 class VIEW3D_MT_tools_projectpaint_clone(Menu):
94     bl_label = "Clone Layer"
95
96     def draw(self, context):
97         layout = self.layout
98
99         for i, tex in enumerate(context.active_object.data.uv_textures):
100             props = layout.operator("wm.context_set_int", text=tex.name, translate=False)
101             props.data_path = "active_object.data.uv_texture_clone_index"
102             props.value = i
103
104
105 def brush_texpaint_common(panel, context, layout, brush, settings, projpaint=False):
106     capabilities = brush.image_paint_capabilities
107
108     col = layout.column()
109
110     if brush.image_tool in {'DRAW', 'FILL'}:
111         if brush.blend not in {'ERASE_ALPHA', 'ADD_ALPHA'}:
112             if not brush.use_gradient:
113                 panel.prop_unified_color_picker(col, context, brush, "color", value_slider=True)
114
115             if settings.palette:
116                 col.template_palette(settings, "palette", color=True)
117
118             if brush.use_gradient:
119                 col.label("Gradient Colors")
120                 col.template_color_ramp(brush, "gradient", expand=True)
121
122                 if brush.image_tool == 'DRAW':
123                     col.label("Background Color")
124                     row = col.row(align=True)
125                     panel.prop_unified_color(row, context, brush, "secondary_color", text="")
126                     col.prop(brush, "gradient_stroke_mode", text="Mode")
127                     if brush.gradient_stroke_mode in {'SPACING_REPEAT', 'SPACING_CLAMP'}:
128                         col.prop(brush, "grad_spacing")
129                 else:  # if brush.image_tool == 'FILL':
130                     col.prop(brush, "gradient_fill_mode")
131             else:
132                 row = col.row(align=True)
133                 panel.prop_unified_color(row, context, brush, "color", text="")
134                 if brush.image_tool == 'FILL' and not projpaint:
135                     col.prop(brush, "fill_threshold")
136                 else:
137                     panel.prop_unified_color(row, context, brush, "secondary_color", text="")
138                     row.separator()
139                     row.operator("paint.brush_colors_flip", icon='FILE_REFRESH', text="")
140         else:
141             if brush.image_tool == 'FILL' and not projpaint:
142                 col.prop(brush, "fill_threshold")
143
144     elif brush.image_tool == 'SOFTEN':
145         col = layout.column(align=True)
146         col.row().prop(brush, "direction", expand=True)
147         col.separator()
148         col.prop(brush, "sharp_threshold")
149         if not projpaint:
150             col.prop(brush, "blur_kernel_radius")
151         col.separator()
152         col.prop(brush, "blur_mode")
153     elif brush.image_tool == 'MASK':
154         col.prop(brush, "weight", text="Mask Value", slider=True)
155
156     elif brush.image_tool == 'CLONE':
157         col.separator()
158         if projpaint:
159             if settings.mode == 'MATERIAL':
160                 col.prop(settings, "use_clone_layer", text="Clone from Paint Slot")
161             elif settings.mode == 'IMAGE':
162                 col.prop(settings, "use_clone_layer", text="Clone from Image/UV Map")
163
164             if settings.use_clone_layer:
165                 ob = context.active_object
166                 col = layout.column()
167
168                 if settings.mode == 'MATERIAL':
169                     if len(ob.material_slots) > 1:
170                         col.label("Materials")
171                         col.template_list("MATERIAL_UL_matslots", "",
172                                           ob, "material_slots",
173                                           ob, "active_material_index", rows=2)
174
175                     mat = ob.active_material
176                     if mat:
177                         col.label("Source Clone Slot")
178                         col.template_list("TEXTURE_UL_texpaintslots", "",
179                                           mat, "texture_paint_images",
180                                           mat, "paint_clone_slot", rows=2)
181
182                 elif settings.mode == 'IMAGE':
183                     mesh = ob.data
184
185                     clone_text = mesh.uv_texture_clone.name if mesh.uv_texture_clone else ""
186                     col.label("Source Clone Image")
187                     col.template_ID(settings, "clone_image")
188                     col.label("Source Clone UV Map")
189                     col.menu("VIEW3D_MT_tools_projectpaint_clone", text=clone_text, translate=False)
190         else:
191             col.prop(brush, "clone_image", text="Image")
192             col.prop(brush, "clone_alpha", text="Alpha")
193
194     col.separator()
195
196     if capabilities.has_radius:
197         row = col.row(align=True)
198         panel.prop_unified_size(row, context, brush, "size", slider=True, text="Radius")
199         panel.prop_unified_size(row, context, brush, "use_pressure_size")
200
201     row = col.row(align=True)
202
203     if capabilities.has_space_attenuation:
204         row.prop(brush, "use_space_attenuation", toggle=True, icon_only=True)
205
206     panel.prop_unified_strength(row, context, brush, "strength", text="Strength")
207     panel.prop_unified_strength(row, context, brush, "use_pressure_strength")
208
209     if brush.image_tool in {'DRAW', 'FILL'}:
210         col.separator()
211         col.prop(brush, "blend", text="Blend")
212
213     col = layout.column()
214
215     # use_accumulate
216     if capabilities.has_accumulate:
217         col = layout.column(align=True)
218         col.prop(brush, "use_accumulate")
219
220     if projpaint:
221         col.prop(brush, "use_alpha")
222
223     col.prop(brush, "use_gradient")
224
225     col.separator()
226     col.template_ID(settings, "palette", new="palette.new")
227
228
229 # Used in both the View3D toolbar and texture properties
230 def brush_texture_settings(layout, brush, sculpt):
231     tex_slot = brush.texture_slot
232
233     layout.label(text="Brush Mapping:")
234
235     # map_mode
236     if sculpt:
237         layout.row().prop(tex_slot, "map_mode", text="")
238         layout.separator()
239     else:
240         layout.row().prop(tex_slot, "tex_paint_map_mode", text="")
241         layout.separator()
242
243     if tex_slot.map_mode == 'STENCIL':
244         if brush.texture and brush.texture.type == 'IMAGE':
245             layout.operator("brush.stencil_fit_image_aspect")
246         layout.operator("brush.stencil_reset_transform")
247
248     # angle and texture_angle_source
249     if tex_slot.has_texture_angle:
250         col = layout.column()
251         col.label(text="Angle:")
252         col.prop(tex_slot, "angle", text="")
253         if tex_slot.has_texture_angle_source:
254             col.prop(tex_slot, "use_rake", text="Rake")
255
256             if brush.brush_capabilities.has_random_texture_angle and tex_slot.has_random_texture_angle:
257                 if sculpt:
258                     if brush.sculpt_capabilities.has_random_texture_angle:
259                         col.prop(tex_slot, "use_random", text="Random")
260                         if tex_slot.use_random:
261                             col.prop(tex_slot, "random_angle", text="")
262                 else:
263                     col.prop(tex_slot, "use_random", text="Random")
264                     if tex_slot.use_random:
265                         col.prop(tex_slot, "random_angle", text="")
266
267     # scale and offset
268     split = layout.split()
269     split.prop(tex_slot, "offset")
270     split.prop(tex_slot, "scale")
271
272     if sculpt:
273         # texture_sample_bias
274         col = layout.column(align=True)
275         col.label(text="Sample Bias:")
276         col.prop(brush, "texture_sample_bias", slider=True, text="")
277
278
279 def brush_mask_texture_settings(layout, brush):
280     mask_tex_slot = brush.mask_texture_slot
281
282     layout.label(text="Mask Mapping:")
283
284     # map_mode
285     layout.row().prop(mask_tex_slot, "mask_map_mode", text="")
286     layout.separator()
287
288     if mask_tex_slot.map_mode == 'STENCIL':
289         if brush.mask_texture and brush.mask_texture.type == 'IMAGE':
290             layout.operator("brush.stencil_fit_image_aspect").mask = True
291         layout.operator("brush.stencil_reset_transform").mask = True
292
293     col = layout.column()
294     col.prop(brush, "use_pressure_masking", text="")
295     # angle and texture_angle_source
296     if mask_tex_slot.has_texture_angle:
297         col = layout.column()
298         col.label(text="Angle:")
299         col.prop(mask_tex_slot, "angle", text="")
300         if mask_tex_slot.has_texture_angle_source:
301             col.prop(mask_tex_slot, "use_rake", text="Rake")
302
303             if brush.brush_capabilities.has_random_texture_angle and mask_tex_slot.has_random_texture_angle:
304                 col.prop(mask_tex_slot, "use_random", text="Random")
305                 if mask_tex_slot.use_random:
306                     col.prop(mask_tex_slot, "random_angle", text="")
307
308     # scale and offset
309     split = layout.split()
310     split.prop(mask_tex_slot, "offset")
311     split.prop(mask_tex_slot, "scale")
312
313
314 classes = (
315     VIEW3D_MT_tools_projectpaint_clone,
316 )
317
318 if __name__ == "__main__":  # only for live edit.
319     from bpy.utils import register_class
320     for cls in classes:
321         register_class(cls)