1 # SPDX-FileCopyrightText: 2017-2022 Blender Foundation
3 # SPDX-License-Identifier: GPL-2.0-or-later
6 from bpy
.types
import Menu
7 from . import utils_core
10 class TextureMenu(Menu
):
11 bl_label
= "Texture Options"
12 bl_idname
= "VIEW3D_MT_sv3_texture_menu"
15 def poll(self
, context
):
16 return utils_core
.get_mode() in (
22 def draw(self
, context
):
25 if utils_core
.get_mode() == 'SCULPT':
26 self
.sculpt(layout
, context
)
28 elif utils_core
.get_mode() == 'VERTEX_PAINT':
29 self
.vertpaint(layout
, context
)
32 self
.texpaint(layout
, context
)
34 def sculpt(self
, layout
, context
):
35 has_brush
= utils_core
.get_brush_link(context
, types
="brush")
36 tex_slot
= has_brush
.texture_slot
if has_brush
else None
39 layout
.row().menu(Textures
.bl_idname
)
40 layout
.row().menu(TextureMapMode
.bl_idname
)
41 layout
.row().separator()
45 if tex_slot
.map_mode
!= '3D':
46 if tex_slot
.map_mode
in ('RANDOM', 'VIEW_PLANE', 'AREA_PLANE'):
47 layout
.row().prop(tex_slot
, "use_rake", toggle
=True)
48 layout
.row().prop(tex_slot
, "use_random", toggle
=True)
51 layout
.row().prop(tex_slot
, "angle",
52 text
=utils_core
.PIW
+ "Angle", slider
=True)
54 if tex_slot
.map_mode
in ('RANDOM', 'VIEW_PLANE') and tex_slot
.use_random
:
55 layout
.row().prop(tex_slot
, "random_angle",
56 text
=utils_core
.PIW
+ "Random Angle", slider
=True)
59 if tex_slot
.map_mode
== 'STENCIL':
60 if has_brush
.texture
and has_brush
.texture
.type == 'IMAGE':
61 layout
.row().operator("brush.stencil_fit_image_aspect")
63 layout
.row().operator("brush.stencil_reset_transform")
66 layout
.row().label(text
="No Texture Slot available", icon
="INFO")
68 def vertpaint(self
, layout
, context
):
69 has_brush
= utils_core
.get_brush_link(context
, types
="brush")
70 tex_slot
= has_brush
.texture_slot
if has_brush
else None
73 layout
.row().menu(Textures
.bl_idname
)
74 layout
.row().menu(TextureMapMode
.bl_idname
)
78 if tex_slot
.map_mode
!= '3D':
79 if tex_slot
.map_mode
in ('RANDOM', 'VIEW_PLANE'):
80 layout
.row().prop(tex_slot
, "use_rake", toggle
=True)
81 layout
.row().prop(tex_slot
, "use_random", toggle
=True)
84 layout
.row().prop(tex_slot
, "angle",
85 text
=utils_core
.PIW
+ "Angle", slider
=True)
87 if tex_slot
.map_mode
in ('RANDOM', 'VIEW_PLANE') and tex_slot
.use_random
:
88 layout
.row().prop(tex_slot
, "random_angle",
89 text
=utils_core
.PIW
+ "Random Angle", slider
=True)
92 if tex_slot
.map_mode
== 'STENCIL':
93 if has_brush
.texture
and has_brush
.texture
.type == 'IMAGE':
94 layout
.row().operator("brush.stencil_fit_image_aspect")
96 layout
.row().operator("brush.stencil_reset_transform")
99 layout
.row().label(text
="No Texture Slot available", icon
="INFO")
101 def texpaint(self
, layout
, context
):
102 has_brush
= utils_core
.get_brush_link(context
, types
="brush")
103 tex_slot
= has_brush
.texture_slot
if has_brush
else None
104 mask_tex_slot
= has_brush
.mask_texture_slot
if has_brush
else None
107 layout
.row().label(text
="Texture", icon
='TEXTURE')
110 layout
.row().menu(Textures
.bl_idname
)
111 layout
.row().menu(TextureMapMode
.bl_idname
)
115 if tex_slot
.map_mode
!= '3D':
116 if tex_slot
.map_mode
in ('RANDOM', 'VIEW_PLANE'):
117 layout
.row().prop(tex_slot
, "use_rake", toggle
=True)
118 layout
.row().prop(tex_slot
, "use_random", toggle
=True)
121 layout
.row().prop(tex_slot
, "angle",
122 text
=utils_core
.PIW
+ "Angle", slider
=True)
124 if tex_slot
.map_mode
in ('RANDOM', 'VIEW_PLANE') and tex_slot
.use_random
:
125 layout
.row().prop(tex_slot
, "random_angle",
126 text
=utils_core
.PIW
+ "Random Angle", slider
=True)
129 if tex_slot
.map_mode
== 'STENCIL':
130 if has_brush
.texture
and has_brush
.texture
.type == 'IMAGE':
131 layout
.row().operator("brush.stencil_fit_image_aspect")
133 layout
.row().operator("brush.stencil_reset_transform")
136 layout
.row().label(text
="No Texture Slot available", icon
="INFO")
138 layout
.row().separator()
140 # Texture Mask Section
141 layout
.row().label(text
="Texture Mask", icon
='MOD_MASK')
144 layout
.row().menu(MaskTextures
.bl_idname
)
145 layout
.row().menu(MaskMapMode
.bl_idname
)
146 layout
.row().menu(MaskPressureModeMenu
.bl_idname
)
150 if mask_tex_slot
.mask_map_mode
in ('RANDOM', 'VIEW_PLANE'):
151 layout
.row().prop(mask_tex_slot
, "use_rake", toggle
=True)
152 layout
.row().prop(mask_tex_slot
, "use_random", toggle
=True)
155 layout
.row().prop(mask_tex_slot
, "angle",
156 text
=utils_core
.PIW
+ "Angle", icon_value
=5, slider
=True)
158 if mask_tex_slot
.mask_map_mode
in ('RANDOM', 'VIEW_PLANE') and mask_tex_slot
.use_random
:
159 layout
.row().prop(mask_tex_slot
, "random_angle",
160 text
=utils_core
.PIW
+ "Random Angle", slider
=True)
163 if mask_tex_slot
.mask_map_mode
== 'STENCIL':
164 if has_brush
.mask_texture
and has_brush
.mask_texture
.type == 'IMAGE':
165 layout
.row().operator("brush.stencil_fit_image_aspect")
167 prop
= layout
.row().operator("brush.stencil_reset_transform")
171 layout
.row().label(text
="Mask Texture not available", icon
="INFO")
174 class Textures(Menu
):
175 bl_label
= "Brush Texture"
176 bl_idname
= "VIEW3D_MT_sv3_texture_list"
179 if utils_core
.get_mode() == 'SCULPT':
180 datapath
= "tool_settings.sculpt.brush.texture"
182 elif utils_core
.get_mode() == 'VERTEX_PAINT':
183 datapath
= "tool_settings.vertex_paint.brush.texture"
185 elif utils_core
.get_mode() == 'TEXTURE_PAINT':
186 datapath
= "tool_settings.image_paint.brush.texture"
193 def draw(self
, context
):
194 datapath
= self
.init()
195 has_brush
= utils_core
.get_brush_link(context
, types
="brush")
196 current_texture
= eval("bpy.context.{}".format(datapath
)) if \
200 # get the current texture's name
202 current_texture
= current_texture
.name
204 layout
.row().label(text
="Brush Texture")
205 layout
.row().separator()
207 # add an item to set the texture to None
208 utils_core
.menuprop(layout
.row(), "None", "None",
209 datapath
, icon
='RADIOBUT_OFF', disable
=True,
210 disable_icon
='RADIOBUT_ON',
211 custom_disable_exp
=(None, current_texture
),
215 for item
in bpy
.data
.textures
:
216 utils_core
.menuprop(layout
.row(), item
.name
,
217 'bpy.data.textures["%s"]' % item
.name
,
218 datapath
, icon
='RADIOBUT_OFF',
220 disable_icon
='RADIOBUT_ON',
221 custom_disable_exp
=(item
.name
, current_texture
),
225 class TextureMapMode(Menu
):
226 bl_label
= "Brush Mapping"
227 bl_idname
= "VIEW3D_MT_sv3_texture_map_mode"
229 def draw(self
, context
):
231 has_brush
= utils_core
.get_brush_link(context
, types
="brush")
233 layout
.row().label(text
="Brush Mapping")
234 layout
.row().separator()
237 if utils_core
.get_mode() == 'SCULPT':
238 path
= "tool_settings.sculpt.brush.texture_slot.map_mode"
241 for item
in has_brush
. \
242 texture_slot
.bl_rna
.properties
['map_mode'].enum_items
:
244 layout
.row(), item
.name
, item
.identifier
, path
,
247 disable_icon
='RADIOBUT_ON'
249 elif utils_core
.get_mode() == 'VERTEX_PAINT':
250 path
= "tool_settings.vertex_paint.brush.texture_slot.map_mode"
253 for item
in has_brush
. \
254 texture_slot
.bl_rna
.properties
['map_mode'].enum_items
:
256 layout
.row(), item
.name
, item
.identifier
, path
,
259 disable_icon
='RADIOBUT_ON'
262 path
= "tool_settings.image_paint.brush.texture_slot.map_mode"
265 for item
in has_brush
. \
266 texture_slot
.bl_rna
.properties
['map_mode'].enum_items
:
268 layout
.row(), item
.name
, item
.identifier
, path
,
271 disable_icon
='RADIOBUT_ON'
274 layout
.row().label(text
="No brushes available", icon
="INFO")
277 class MaskTextures(Menu
):
278 bl_label
= "Mask Texture"
279 bl_idname
= "VIEW3D_MT_sv3_mask_texture_list"
281 def draw(self
, context
):
283 datapath
= "tool_settings.image_paint.brush.mask_texture"
284 has_brush
= utils_core
.get_brush_link(context
, types
="brush")
285 current_texture
= eval("bpy.context.{}".format(datapath
)) if \
288 layout
.row().label(text
="Mask Texture")
289 layout
.row().separator()
292 # get the current texture's name
294 current_texture
= current_texture
.name
296 # add an item to set the texture to None
298 layout
.row(), "None", "None",
299 datapath
, icon
='RADIOBUT_OFF', disable
=True,
300 disable_icon
='RADIOBUT_ON',
301 custom_disable_exp
=(None, current_texture
),
306 for item
in bpy
.data
.textures
:
308 layout
.row(), item
.name
, 'bpy.data.textures["%s"]' % item
.name
,
309 datapath
, icon
='RADIOBUT_OFF', disable
=True,
310 disable_icon
='RADIOBUT_ON',
311 custom_disable_exp
=(item
.name
, current_texture
),
315 layout
.row().label(text
="No brushes available", icon
="INFO")
318 class MaskMapMode(Menu
):
319 bl_label
= "Mask Mapping"
320 bl_idname
= "VIEW3D_MT_sv3_mask_map_mode"
322 def draw(self
, context
):
324 path
= "tool_settings.image_paint.brush.mask_texture_slot.mask_map_mode"
325 has_brush
= utils_core
.get_brush_link(context
, types
="brush")
327 layout
.row().label(text
="Mask Mapping")
328 layout
.row().separator()
331 mask_texture_slot
.bl_rna
.properties
['mask_map_mode'].enum_items
335 layout
.row(), item
.name
, item
.identifier
, path
,
338 disable_icon
='RADIOBUT_ON'
341 layout
.row().label(text
="No brushes available", icon
="INFO")
344 class TextureAngleSource(Menu
):
345 bl_label
= "Texture Angle Source"
346 bl_idname
= "VIEW3D_MT_sv3_texture_angle_source"
348 def draw(self
, context
):
350 has_brush
= utils_core
.get_brush_link(context
, types
="brush")
353 if utils_core
.get_mode() == 'SCULPT':
355 bl_rna
.properties
['texture_angle_source_random'].enum_items
356 path
= "tool_settings.sculpt.brush.texture_angle_source_random"
358 elif utils_core
.get_mode() == 'VERTEX_PAINT':
360 bl_rna
.properties
['texture_angle_source_random'].enum_items
361 path
= "tool_settings.vertex_paint.brush.texture_angle_source_random"
365 bl_rna
.properties
['texture_angle_source_random'].enum_items
366 path
= "tool_settings.image_paint.brush.texture_angle_source_random"
371 layout
.row(), item
[0], item
[1], path
,
374 disable_icon
='RADIOBUT_ON'
377 layout
.row().label(text
="No brushes available", icon
="INFO")
379 class MaskPressureModeMenu(Menu
):
380 bl_label
= "Mask Pressure Mode"
381 bl_idname
= "VIEW3D_MT_sv3_mask_pressure_mode_menu"
383 def draw(self
, context
):
385 path
= "tool_settings.image_paint.brush.use_pressure_masking"
387 layout
.row().label(text
="Mask Pressure Mode")
388 layout
.row().separator()
391 for item
in context
.tool_settings
.image_paint
.brush
. \
392 bl_rna
.properties
['use_pressure_masking'].enum_items
:
394 layout
.row(), item
.name
, item
.identifier
, path
,
397 disable_icon
='RADIOBUT_ON'
413 bpy
.utils
.register_class(cls
)
417 bpy
.utils
.unregister_class(cls
)