425681fc19a5a3fd47d91f9e514143b5483e9758
[blender.git] / release / scripts / startup / bl_ui / properties_texture.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
21 import bpy
22 from bpy.types import (
23     Menu,
24     Panel,
25     UIList,
26 )
27 from bpy.types import (
28     Brush,
29     FreestyleLineStyle,
30     ParticleSettings,
31     Texture,
32 )
33
34 from rna_prop_ui import PropertyPanel
35 from .properties_paint_common import brush_texture_settings
36
37
38 class TEXTURE_MT_specials(Menu):
39     bl_label = "Texture Specials"
40     COMPAT_ENGINES = {'BLENDER_RENDER'}
41
42     def draw(self, context):
43         layout = self.layout
44
45         layout.operator("texture.slot_copy", icon='COPYDOWN')
46         layout.operator("texture.slot_paste", icon='PASTEDOWN')
47
48
49 class TEXTURE_UL_texslots(UIList):
50
51     def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
52         slot = item
53         tex = slot.texture if slot else None
54
55         if self.layout_type in {'DEFAULT', 'COMPACT'}:
56             if tex:
57                 layout.prop(tex, "name", text="", emboss=False, icon_value=icon)
58             else:
59                 layout.label(text="", icon_value=icon)
60         elif self.layout_type == 'GRID':
61             layout.alignment = 'CENTER'
62             layout.label(text="", icon_value=icon)
63
64
65 def context_tex_datablock(context):
66     idblock = context.brush
67     if idblock:
68         return idblock
69
70     idblock = context.line_style
71     if idblock:
72         return idblock
73
74     if context.particle_system:
75         idblock = context.particle_system.settings
76
77     return idblock
78
79
80 class TextureButtonsPanel:
81     bl_space_type = 'PROPERTIES'
82     bl_region_type = 'WINDOW'
83     bl_context = "texture"
84
85
86 class TEXTURE_PT_preview(TextureButtonsPanel, Panel):
87     bl_label = "Preview"
88     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
89
90     @classmethod
91     def poll(cls, context):
92         tex = context.texture
93         return tex and (tex.type != 'NONE' or tex.use_nodes) and (context.engine in cls.COMPAT_ENGINES)
94
95     def draw(self, context):
96         layout = self.layout
97
98         tex = context.texture
99         slot = getattr(context, "texture_slot", None)
100         idblock = context_tex_datablock(context)
101
102         if idblock:
103             layout.template_preview(tex, parent=idblock, slot=slot)
104         else:
105             layout.template_preview(tex, slot=slot)
106
107         # Show Alpha Button for Brush Textures, see #29502
108         idblock = context_tex_datablock(context)
109         if isinstance(idblock, Brush):
110             layout.prop(tex, "use_preview_alpha")
111
112
113 class TEXTURE_PT_context(TextureButtonsPanel, Panel):
114     bl_label = ""
115     bl_context = "texture"
116     bl_options = {'HIDE_HEADER'}
117     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
118
119     def draw(self, context):
120         layout = self.layout
121
122         tex = context.texture
123         space = context.space_data
124         pin_id = space.pin_id
125         use_pin_id = space.use_pin_id
126         user = context.texture_user
127
128         col = layout.column()
129
130         if not (use_pin_id and isinstance(pin_id, bpy.types.Texture)):
131             pin_id = None
132
133         if not pin_id:
134             col.template_texture_user()
135
136         if user or pin_id:
137             col.separator()
138
139             if pin_id:
140                 col.template_ID(space, "pin_id")
141             else:
142                 propname = context.texture_user_property.identifier
143                 col.template_ID(user, propname, new="texture.new")
144
145             if tex:
146                 col.separator()
147
148                 split = col.split(factor=0.2)
149                 split.label(text="Type")
150                 split.prop(tex, "type", text="")
151
152
153 class TEXTURE_PT_node(TextureButtonsPanel, Panel):
154     bl_label = "Node"
155     bl_context = "texture"
156     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
157
158     @classmethod
159     def poll(cls, context):
160         node = context.texture_node
161         return node and (context.engine in cls.COMPAT_ENGINES)
162
163     def draw(self, context):
164         layout = self.layout
165
166         node = context.texture_node
167         ntree = node.id_data
168         layout.template_node_view(ntree, node, None)
169
170
171 class TEXTURE_PT_node_mapping(TextureButtonsPanel, Panel):
172     bl_label = "Mapping"
173     bl_context = "texture"
174     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
175
176     @classmethod
177     def poll(cls, context):
178         node = context.texture_node
179         # TODO(sergey): perform a faster/nicer check?
180         return node and hasattr(node, "texture_mapping") and (context.engine in cls.COMPAT_ENGINES)
181
182     def draw(self, context):
183         layout = self.layout
184         layout.use_property_split = True
185         layout.use_property_decorate = False  # No animation.
186
187         flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
188
189         node = context.texture_node
190
191         mapping = node.texture_mapping
192
193         col = flow.column()
194         col.prop(mapping, "vector_type")
195
196         col.separator()
197
198         col = col.column(align=True)
199         col.prop(mapping, "mapping_x", text="Projection X")
200         col.prop(mapping, "mapping_y", text="Y")
201         col.prop(mapping, "mapping_z", text="Z")
202
203         col.separator()
204
205         col = flow.column()
206         col.column().prop(mapping, "translation")
207
208         col = flow.column()
209         col.column().prop(mapping, "rotation")
210
211         col = flow.column()
212         col.column().prop(mapping, "scale")
213
214
215 class TextureTypePanel(TextureButtonsPanel):
216
217     @classmethod
218     def poll(cls, context):
219         tex = context.texture
220         engine = context.engine
221         return tex and ((tex.type == cls.tex_type and not tex.use_nodes) and (engine in cls.COMPAT_ENGINES))
222
223
224 class TEXTURE_PT_clouds(TextureTypePanel, Panel):
225     bl_label = "Clouds"
226     tex_type = 'CLOUDS'
227     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
228
229     def draw(self, context):
230         layout = self.layout
231         layout.use_property_split = True
232         flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
233
234         tex = context.texture
235
236         col = flow.column()
237         col.prop(tex, "noise_basis", text="Noise Basis")
238
239         col.separator()
240
241         col.prop(tex, "noise_type", text="Type")
242
243         col.separator()
244
245         col = flow.column()
246         col.prop(tex, "cloud_type")
247
248         col.separator()
249
250         col = flow.column()
251         col.prop(tex, "noise_scale", text="Size")
252         col.prop(tex, "noise_depth", text="Depth")
253         col.prop(tex, "nabla", text="Nabla")
254
255
256 class TEXTURE_PT_wood(TextureTypePanel, Panel):
257     bl_label = "Wood"
258     tex_type = 'WOOD'
259     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
260
261     def draw(self, context):
262         layout = self.layout
263         layout.use_property_split = True
264         flow = layout.grid_flow(row_major=True, columns=0, even_columns=False, even_rows=False, align=False)
265
266         tex = context.texture
267
268         col = flow.column()
269         col.prop(tex, "noise_basis", text="Noise Basis")
270
271         col.separator()
272
273         col.prop(tex, "wood_type")
274
275         col.separator()
276
277         col = flow.column()
278         col.prop(tex, "noise_basis_2", text="Second Basis")
279
280         col = col.column()
281         col.active = tex.wood_type in {'RINGNOISE', 'BANDNOISE'}
282         col.prop(tex, "noise_type", text="Type")
283
284         col.separator()
285
286         sub = flow.column()
287         sub.active = tex.wood_type in {'RINGNOISE', 'BANDNOISE'}
288         sub.prop(tex, "noise_scale", text="Size")
289         sub.prop(tex, "turbulence")
290         sub.prop(tex, "nabla")
291
292
293 class TEXTURE_PT_marble(TextureTypePanel, Panel):
294     bl_label = "Marble"
295     tex_type = 'MARBLE'
296     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
297
298     def draw(self, context):
299         layout = self.layout
300         layout.use_property_split = True
301         flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
302
303         tex = context.texture
304
305         col = flow.column()
306         col.prop(tex, "noise_basis", text="Noise Basis")
307
308         col.separator()
309
310         col.prop(tex, "marble_type")
311
312         col.separator()
313
314         col = flow.column()
315         col.prop(tex, "noise_basis_2", text="Second Basis")
316         col.prop(tex, "noise_type", text="Type")
317
318         col.separator()
319
320         col = flow.column()
321         col.prop(tex, "noise_scale", text="Size")
322         col.prop(tex, "noise_depth", text="Depth")
323         col.prop(tex, "turbulence")
324         col.prop(tex, "nabla")
325
326
327 class TEXTURE_PT_magic(TextureTypePanel, Panel):
328     bl_label = "Magic"
329     tex_type = 'MAGIC'
330     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
331
332     def draw(self, context):
333         layout = self.layout
334         layout.use_property_split = True
335         flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
336
337         tex = context.texture
338
339         col = flow.column()
340         col.prop(tex, "noise_depth", text="Depth")
341
342         col = flow.column()
343         col.prop(tex, "turbulence")
344
345
346 class TEXTURE_PT_blend(TextureTypePanel, Panel):
347     bl_label = "Blend"
348     tex_type = 'BLEND'
349     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
350
351     def draw(self, context):
352         layout = self.layout
353         layout.use_property_split = True
354         flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
355
356         tex = context.texture
357
358         col = flow.column()
359         col.prop(tex, "progression")
360
361         col.separator()
362
363         col = flow.column()
364         col.active = (tex.progression in {'LINEAR', 'QUADRATIC', 'EASING', 'RADIAL'})
365         col.prop(tex, "use_flip_axis", text="Orientation")
366
367
368 class TEXTURE_PT_stucci(TextureTypePanel, Panel):
369     bl_label = "Stucci"
370     tex_type = 'STUCCI'
371     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
372
373     def draw(self, context):
374         layout = self.layout
375         layout.use_property_split = True
376         flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
377
378         tex = context.texture
379
380         col = flow.column()
381         col.prop(tex, "noise_basis", text="Noise Basis")
382
383         col.separator()
384
385         col.row().prop(tex, "stucci_type")
386
387         col.separator()
388
389         col = flow.column()
390         col.prop(tex, "noise_type", text="Type")
391
392         col.separator()
393
394         col = flow.column()
395         col.prop(tex, "noise_scale", text="Size")
396         col.prop(tex, "turbulence")
397
398
399 class TEXTURE_PT_image(TextureTypePanel, Panel):
400     bl_label = "Image"
401     tex_type = 'IMAGE'
402     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
403
404     def draw(self, context):
405         # TODO: maybe expose the template_ID from the template image here.
406         layout = self.layout
407         del layout
408
409
410 class TEXTURE_PT_image_settings(TextureTypePanel, Panel):
411     bl_label = "Settings"
412     bl_parent_id = 'TEXTURE_PT_image'
413     tex_type = 'IMAGE'
414     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
415
416     def draw(self, context):
417         layout = self.layout
418
419         tex = context.texture
420         layout.template_image(tex, "image", tex.image_user)
421
422
423 def texture_filter_common(tex, layout):
424     layout.prop(tex, "filter_type", text="Filter Type")
425
426     if tex.use_mipmap and tex.filter_type in {'AREA', 'EWA', 'FELINE'}:
427         col = layout.column()
428         if tex.filter_type == 'FELINE':
429             col.prop(tex, "filter_lightprobes", text="Light Probes")
430         else:
431             col.prop(tex, "filter_eccentricity", text="Eccentricity")
432
433     layout.prop(tex, "filter_size", text="Size")
434     layout.prop(tex, "use_filter_size_min", text="Minimum Size")
435
436
437 class TEXTURE_PT_image_sampling(TextureTypePanel, Panel):
438     bl_label = "Sampling"
439     bl_options = {'DEFAULT_CLOSED'}
440     bl_parent_id = 'TEXTURE_PT_image'
441     tex_type = 'IMAGE'
442     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
443
444     def draw(self, context):
445         layout = self.layout
446         layout.use_property_split = True
447         flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
448
449         tex = context.texture
450
451         col = flow.column()
452         col.prop(tex, "use_interpolation")
453
454         col.separator()
455
456         col = flow.column()
457         col.prop(tex, "use_mipmap")
458         sub = col.column()
459         sub.active = tex.use_mipmap
460         sub.prop(tex, "use_mipmap_gauss", text="Gaussian Filter")
461
462         col.separator()
463
464         texture_filter_common(tex, flow)
465
466
467 class TEXTURE_PT_image_alpha(TextureTypePanel, Panel):
468     bl_label = "Alpha"
469     bl_options = {'DEFAULT_CLOSED'}
470     bl_parent_id = 'TEXTURE_PT_image'
471     tex_type = 'IMAGE'
472     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
473
474     def draw_header(self, context):
475         tex = context.texture
476         self.layout.prop(tex, "use_alpha", text="")
477
478     def draw(self, context):
479         layout = self.layout
480         layout.use_property_split = True
481
482         tex = context.texture
483
484         col = layout.column()
485         col.active = bool(tex.image and tex.image.use_alpha)
486         col.prop(tex, "use_calculate_alpha", text="Calculate")
487         col.prop(tex, "invert_alpha", text="Invert")
488
489
490 class TEXTURE_PT_image_mapping(TextureTypePanel, Panel):
491     bl_label = "Mapping"
492     bl_options = {'DEFAULT_CLOSED'}
493     bl_parent_id = 'TEXTURE_PT_image'
494     tex_type = 'IMAGE'
495     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
496
497     def draw(self, context):
498         layout = self.layout
499         layout.use_property_split = True
500
501         tex = context.texture
502
503         col = layout.column()
504         col.prop(tex, "use_flip_axis", text="Flip Axes")
505
506         col.separator()
507
508         subcol = layout.column()
509         subcol.prop(tex, "extension")  # use layout, to keep the same location in case of button cycling.
510
511         flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
512
513         if tex.extension == 'REPEAT':
514
515             col = flow.column()
516             sub = col.column(align=True)
517             sub.prop(tex, "repeat_x", text="Repeat X")
518             sub.prop(tex, "repeat_y", text="Y")
519
520             col = flow.column()
521             sub = col.column()
522             sub.active = (tex.repeat_x > 1)
523             sub.prop(tex, "use_mirror_x", text="Mirror X")
524
525             sub = col.column()
526             sub.active = (tex.repeat_y > 1)
527             sub.prop(tex, "use_mirror_y", text="Y")
528
529         elif tex.extension == 'CHECKER':
530             subcol.separator()
531
532             col = flow.column()
533             col.prop(tex, "checker_distance", text="Distance")
534
535             col = flow.column()
536             col.prop(tex, "use_checker_even", text="Tiles Even")
537             col.prop(tex, "use_checker_odd", text="Odd")
538         else:
539             del flow
540
541
542 class TEXTURE_PT_image_mapping_crop(TextureTypePanel, Panel):
543     bl_label = "Crop"
544     bl_options = {'DEFAULT_CLOSED'}
545     bl_parent_id = 'TEXTURE_PT_image_mapping'
546     tex_type = 'IMAGE'
547     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
548
549     def draw(self, context):
550         layout = self.layout
551         layout.use_property_split = True
552         flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
553
554         tex = context.texture
555
556         col = flow.column(align=True)
557         # col.prop(tex, "crop_rectangle")
558         col.prop(tex, "crop_min_x", text="Minimum X")
559         col.prop(tex, "crop_min_y", text="Y")
560
561         col = flow.column(align=True)
562         col.prop(tex, "crop_max_x", text="Maximum X")
563         col.prop(tex, "crop_max_y", text="Y")
564
565
566 class TEXTURE_PT_musgrave(TextureTypePanel, Panel):
567     bl_label = "Musgrave"
568     tex_type = 'MUSGRAVE'
569     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
570
571     def draw(self, context):
572         layout = self.layout
573         layout.use_property_split = True
574         flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
575
576         tex = context.texture
577
578         col = flow.column()
579         col.prop(tex, "noise_basis", text="Noise Basis")
580
581         col.separator()
582
583         col.prop(tex, "musgrave_type")
584
585         col.separator()
586
587         col.prop(tex, "noise_scale", text="Size")
588         col.prop(tex, "nabla")
589
590         col.separator()
591
592         col = flow.column()
593         col.prop(tex, "dimension_max", text="Dimension")
594         col.prop(tex, "lacunarity")
595         col.prop(tex, "octaves")
596
597         col.separator()
598
599         musgrave_type = tex.musgrave_type
600
601         col = flow.column()
602
603         if musgrave_type in {'HETERO_TERRAIN', 'RIDGED_MULTIFRACTAL', 'HYBRID_MULTIFRACTAL'}:
604             col.prop(tex, "offset")
605         col.prop(tex, "noise_intensity", text="Intensity")
606
607         if musgrave_type in {'RIDGED_MULTIFRACTAL', 'HYBRID_MULTIFRACTAL'}:
608             col.prop(tex, "gain")
609
610
611 class TEXTURE_PT_voronoi(TextureTypePanel, Panel):
612     bl_label = "Voronoi"
613     tex_type = 'VORONOI'
614     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
615
616     def draw(self, context):
617         layout = self.layout
618         layout.use_property_split = True
619         flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
620
621         tex = context.texture
622
623         col = flow.column()
624         col.prop(tex, "distance_metric")
625
626         sub = col.column()
627         sub.active = tex.distance_metric == 'MINKOVSKY'
628         sub.prop(tex, "minkovsky_exponent", text="Exponent")
629
630         sub.separator()
631
632         col = flow.column()
633         col.prop(tex, "color_mode")
634         col.prop(tex, "noise_intensity", text="Intensity")
635
636         col.separator()
637
638         col = flow.column()
639         col.prop(tex, "noise_scale", text="Size")
640         col.prop(tex, "nabla")
641
642
643 class TEXTURE_PT_voronoi_feature_weights(TextureTypePanel, Panel):
644     bl_label = "Feature Weights"
645     bl_parent_id = "TEXTURE_PT_voronoi"
646     tex_type = 'VORONOI'
647     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
648
649     def draw(self, context):
650         layout = self.layout
651         layout.use_property_split = True
652         flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=True)
653
654         tex = context.texture
655
656         col = flow.column(align=True)
657         col.prop(tex, "weight_1", text="First", slider=True)
658         col.prop(tex, "weight_2", text="Second", slider=True)
659
660         sub = flow.column(align=True)
661         sub.prop(tex, "weight_3", text="Third", slider=True)
662         sub.prop(tex, "weight_4", text="Fourth", slider=True)
663
664
665 class TEXTURE_PT_distortednoise(TextureTypePanel, Panel):
666     bl_label = "Distorted Noise"
667     tex_type = 'DISTORTED_NOISE'
668     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
669
670     def draw(self, context):
671         layout = self.layout
672         layout.use_property_split = True
673         flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
674
675         tex = context.texture
676
677         col = flow.column()
678         col.prop(tex, "noise_basis", text="Noise Basis")
679
680         col.separator()
681
682         col.prop(tex, "noise_distortion", text="Distortion")
683
684         col.separator()
685
686         col = flow.column()
687         col.prop(tex, "distortion", text="Amount")
688         col.prop(tex, "noise_scale", text="Size")
689         col.prop(tex, "nabla")
690
691
692 class TextureSlotPanel(TextureButtonsPanel):
693     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
694
695     @classmethod
696     def poll(cls, context):
697         if not hasattr(context, "texture_slot"):
698             return False
699
700         return (context.engine in cls.COMPAT_ENGINES)
701
702
703 class TEXTURE_PT_mapping(TextureSlotPanel, Panel):
704     bl_label = "Mapping"
705     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
706
707     @classmethod
708     def poll(cls, context):
709         idblock = context_tex_datablock(context)
710         if isinstance(idblock, Brush) and not context.sculpt_object:
711             return False
712
713         if not getattr(context, "texture_slot", None):
714             return False
715
716         engine = context.engine
717         return (engine in cls.COMPAT_ENGINES)
718
719     def draw(self, context):
720         layout = self.layout
721         layout.use_property_split = True
722         flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=True)
723
724         idblock = context_tex_datablock(context)
725
726         tex = context.texture_slot
727
728         if isinstance(idblock, Brush):
729             if context.sculpt_object or context.image_paint_object:
730                 brush_texture_settings(layout, idblock, context.sculpt_object)
731         else:
732             col = flow.column()
733
734             col.prop(tex, "texture_coords", text="Coordinates")
735
736             # Note: the ORCO case used to call ob.data, "texco_mesh" prop.
737             if tex.texture_coords == 'UV':
738                 ob = context.object
739
740                 if ob and ob.type == 'MESH':
741                     col.prop_search(tex, "uv_layer", ob.data, "uv_layers", text="Map")
742                 else:
743                     col.prop(tex, "uv_layer", text="Map")
744
745             elif tex.texture_coords == 'OBJECT':
746                 col.prop(tex, "object", text="Object")
747
748             elif tex.texture_coords == 'ALONG_STROKE':
749                 col.prop(tex, "use_tips", text="Use Tips")
750
751             col.separator()
752
753             if isinstance(idblock, FreestyleLineStyle):
754                 col = flow.column()
755                 col.prop(tex, "mapping", text="Projection")
756
757                 col.separator()
758
759                 col = flow.column()
760                 col.prop(tex, "mapping_x", text="Mapping X")
761                 col.prop(tex, "mapping_y", text="Y")
762                 col.prop(tex, "mapping_z", text="Z")
763
764                 col.separator()
765
766             col = flow.column(align=True)
767             col.column().prop(tex, "offset")
768
769             col = flow.column(align=True)
770             col.column().prop(tex, "scale")
771
772
773 class TEXTURE_PT_influence(TextureSlotPanel, Panel):
774     bl_label = "Influence"
775     bl_options = {'DEFAULT_CLOSED'}
776     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
777
778     @classmethod
779     def poll(cls, context):
780         idblock = context_tex_datablock(context)
781         if isinstance(idblock, Brush):
782             return False
783
784         if not getattr(context, "texture_slot", None):
785             return False
786
787         engine = context.engine
788         return (engine in cls.COMPAT_ENGINES)
789
790     def draw(self, context):
791         layout = self.layout
792         layout.use_property_split = True
793         flow = layout.grid_flow(row_major=False, columns=0, even_columns=False, even_rows=False, align=False)
794
795         idblock = context_tex_datablock(context)
796         tex = context.texture_slot
797
798         def factor_but(layout, toggle, factor, name):
799             row = layout.row(align=True)
800             row.active = getattr(tex, toggle)
801
802             row.prop(tex, factor, text=name, slider=True)
803             sub = row.row(align=True)
804             sub.prop(tex, toggle, text="")
805             return sub  # XXX, temp. use_map_normal needs to override.
806
807         if isinstance(idblock, ParticleSettings):
808             col = flow.column()
809             factor_but(col, "use_map_time", "time_factor", "General Time")
810             factor_but(col, "use_map_life", "life_factor", "Lifetime")
811             factor_but(col, "use_map_density", "density_factor", "Density")
812             factor_but(col, "use_map_size", "size_factor", "Size")
813
814             col.separator()
815
816             col = flow.column()
817             factor_but(col, "use_map_velocity", "velocity_factor", "Physics Velocity")
818             factor_but(col, "use_map_damp", "damp_factor", "Damp")
819             factor_but(col, "use_map_gravity", "gravity_factor", "Gravity")
820             factor_but(col, "use_map_field", "field_factor", "Force Fields")
821
822             col.separator()
823
824             col = flow.column()
825             factor_but(col, "use_map_length", "length_factor", "Hair Length")
826             factor_but(col, "use_map_clump", "clump_factor", "Clump")
827             factor_but(col, "use_map_twist", "twist_factor", "Twist")
828
829             col = flow.column()
830             factor_but(col, "use_map_kink_amp", "kink_amp_factor", "Kink Amplitude")
831             factor_but(col, "use_map_kink_freq", "kink_freq_factor", "Kink Frequency")
832             factor_but(col, "use_map_rough", "rough_factor", "Rough")
833
834         elif isinstance(idblock, FreestyleLineStyle):
835             col = flow.column()
836             factor_but(col, "use_map_color_diffuse", "diffuse_color_factor", "Color")
837             factor_but(col, "use_map_alpha", "alpha_factor", "Alpha")
838
839         if not isinstance(idblock, ParticleSettings):
840             col = flow.column()
841
842             col.prop(tex, "blend_type", text="Blend")
843             col.prop(tex, "use_rgb_to_intensity")
844
845             # color is used on gray-scale textures even when use_rgb_to_intensity is disabled.
846             col.prop(tex, "color", text="")
847
848             col = flow.column()
849             col.prop(tex, "invert", text="Negative")
850             col.prop(tex, "use_stencil")
851
852
853 class TextureColorsPoll:
854     @classmethod
855     def poll(cls, context):
856         tex = context.texture
857         return tex and (tex.type != 'NONE' or tex.use_nodes) and (context.engine in cls.COMPAT_ENGINES)
858
859
860 class TEXTURE_PT_colors(TextureButtonsPanel, TextureColorsPoll, Panel):
861     bl_label = "Colors"
862     bl_options = {'DEFAULT_CLOSED'}
863     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
864
865     def draw(self, context):
866         layout = self.layout
867         layout.use_property_split = True
868         flow = layout.grid_flow(row_major=False, columns=0, even_columns=False, even_rows=False, align=False)
869
870         tex = context.texture
871
872         col = flow.column()
873         col.prop(tex, "use_clamp", text="Clamp")
874
875         col = flow.column(align=True)
876         col.prop(tex, "factor_red", text="Multiply R")
877         col.prop(tex, "factor_green", text="G")
878         col.prop(tex, "factor_blue", text="B")
879
880         col.separator()
881
882         col = flow.column()
883         col.prop(tex, "intensity")
884         col.prop(tex, "contrast")
885         col.prop(tex, "saturation")
886
887
888 class TEXTURE_PT_colors_ramp(TextureButtonsPanel, TextureColorsPoll, Panel):
889     bl_label = "Color Ramp"
890     bl_options = {'DEFAULT_CLOSED'}
891     bl_parent_id = 'TEXTURE_PT_colors'
892     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
893
894     def draw_header(self, context):
895         tex = context.texture
896         self.layout.prop(tex, "use_color_ramp", text="")
897
898     def draw(self, context):
899         layout = self.layout
900
901         tex = context.texture
902
903         # Note: TODO after creation of a new texture, the template_color_ramp will be blank.
904         #       Possibly needs to be fixed in the template itself.
905         is_active = bool(tex and tex.use_color_ramp)
906         if is_active:
907             layout.template_color_ramp(tex, "color_ramp", expand=True)
908         else:
909             layout.alignment = 'RIGHT'
910             layout.label(text="Enable the Color Ramp first")
911
912
913 class TEXTURE_PT_custom_props(TextureButtonsPanel, PropertyPanel, Panel):
914     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
915     _context_path = "texture"
916     _property_type = Texture
917
918     @classmethod
919     def poll(cls, context):
920         return context.texture and (context.engine in cls.COMPAT_ENGINES)
921
922
923 classes = (
924     TEXTURE_MT_specials,
925     TEXTURE_UL_texslots,
926     TEXTURE_PT_preview,
927     TEXTURE_PT_context,
928     TEXTURE_PT_node,
929     TEXTURE_PT_node_mapping,
930     TEXTURE_PT_clouds,
931     TEXTURE_PT_wood,
932     TEXTURE_PT_marble,
933     TEXTURE_PT_magic,
934     TEXTURE_PT_blend,
935     TEXTURE_PT_stucci,
936     TEXTURE_PT_image,
937     TEXTURE_PT_image_settings,
938     TEXTURE_PT_image_alpha,
939     TEXTURE_PT_image_mapping,
940     TEXTURE_PT_image_mapping_crop,
941     TEXTURE_PT_image_sampling,
942     TEXTURE_PT_musgrave,
943     TEXTURE_PT_voronoi,
944     TEXTURE_PT_voronoi_feature_weights,
945     TEXTURE_PT_distortednoise,
946     TEXTURE_PT_influence,
947     TEXTURE_PT_mapping,
948     TEXTURE_PT_colors,
949     TEXTURE_PT_colors_ramp,
950     TEXTURE_PT_custom_props,
951 )
952
953 if __name__ == "__main__":  # only for live edit.
954     from bpy.utils import register_class
955     for cls in classes:
956         register_class(cls)