1 # SPDX-FileCopyrightText: 2018-2022 Blender Foundation
3 # SPDX-License-Identifier: GPL-2.0-or-later
5 __author__
= "Nutti <nutti.metro@gmail.com>"
6 __status__
= "production"
8 __date__
= "22 Apr 2022"
11 from bpy
.props
import (
17 from bpy
.types
import AddonPreferences
20 from .op
.clip_uv
import MUV_OT_ClipUV
21 from .op
.flip_rotate_uv
import MUV_OT_FlipRotateUV
22 from .op
.mirror_uv
import MUV_OT_MirrorUV
23 from .op
.move_uv
import MUV_OT_MoveUV
24 from .op
.unwrap_constraint
import MUV_OT_UnwrapConstraint
25 from .op
.pack_uv
import MUV_OT_PackUV
26 from .op
.smooth_uv
import MUV_OT_SmoothUV
27 from .ui
.VIEW3D_MT_uv_map
import (
31 MUV_MT_PreserveUVAspect
,
34 MUV_MT_TextureProjection
,
37 from .ui
.VIEW3D_MT_object
import MUV_MT_CopyPasteUV_Object
38 from .ui
.IMAGE_MT_uvs
import (
39 MUV_MT_CopyPasteUV_UVEdit
,
45 from .utils
.bl_class_registry
import BlClassRegistry
46 from .utils
import compatibility
as compat
49 def view3d_uvmap_menu_fn(self
, context
):
54 layout
.label(text
="Copy/Paste UV", icon
=compat
.icon('IMAGE'))
56 layout
.menu(MUV_MT_CopyPasteUV
.bl_idname
, text
="Copy/Paste UV")
58 layout
.menu(MUV_MT_TransferUV
.bl_idname
, text
="Transfer UV")
61 layout
.label(text
="UV Manipulation", icon
=compat
.icon('IMAGE'))
63 ops
= layout
.operator(MUV_OT_FlipRotateUV
.bl_idname
, text
="Flip/Rotate UV")
64 ops
.seams
= sc
.muv_flip_rotate_uv_seams
66 ops
= layout
.operator(MUV_OT_MirrorUV
.bl_idname
, text
="Mirror UV")
67 ops
.axis
= sc
.muv_mirror_uv_axis
69 layout
.operator(MUV_OT_MoveUV
.bl_idname
, text
="Move UV")
71 layout
.menu(MUV_MT_WorldScaleUV
.bl_idname
, text
="World Scale UV")
73 layout
.menu(MUV_MT_PreserveUVAspect
.bl_idname
, text
="Preserve UV")
75 layout
.menu(MUV_MT_TextureLock
.bl_idname
, text
="Texture Lock")
77 layout
.menu(MUV_MT_TextureWrap
.bl_idname
, text
="Texture Wrap")
79 layout
.prop(sc
, "muv_uv_sculpt_enable", text
="UV Sculpt")
82 layout
.label(text
="UV Mapping", icon
=compat
.icon('IMAGE'))
84 ops
= layout
.operator(MUV_OT_UnwrapConstraint
.bl_idname
,
85 text
="Unwrap Constraint")
86 ops
.u_const
= sc
.muv_unwrap_constraint_u_const
87 ops
.v_const
= sc
.muv_unwrap_constraint_v_const
89 layout
.menu(MUV_MT_TextureProjection
.bl_idname
, text
="Texture Projection")
91 layout
.menu(MUV_MT_UVW
.bl_idname
, text
="UVW")
94 def view3d_object_menu_fn(self
, _
):
98 layout
.label(text
="Copy/Paste UV", icon
=compat
.icon('IMAGE'))
99 # Copy/Paste UV (Among Object)
100 layout
.menu(MUV_MT_CopyPasteUV_Object
.bl_idname
, text
="Copy/Paste UV")
103 def image_uvs_menu_fn(self
, context
):
108 layout
.label(text
="Copy/Paste UV", icon
=compat
.icon('IMAGE'))
109 # Copy/Paste UV (on UV/Image Editor)
110 layout
.menu(MUV_MT_CopyPasteUV_UVEdit
.bl_idname
, text
="Copy/Paste UV")
113 layout
.label(text
="UV Manipulation", icon
=compat
.icon('IMAGE'))
115 ops
= layout
.operator(MUV_OT_ClipUV
.bl_idname
, text
="Clip UV")
116 ops
.clip_uv_range_max
= sc
.muv_clip_uv_range_max
117 ops
.clip_uv_range_min
= sc
.muv_clip_uv_range_min
119 ops
= layout
.operator(MUV_OT_PackUV
.bl_idname
, text
="Pack UV")
120 ops
.allowable_center_deviation
= sc
.muv_pack_uv_allowable_center_deviation
121 ops
.allowable_size_deviation
= sc
.muv_pack_uv_allowable_size_deviation
122 ops
.accurate_island_copy
= sc
.muv_pack_uv_accurate_island_copy
123 ops
.stride
= sc
.muv_pack_uv_stride
124 ops
.apply_pack_uv
= sc
.muv_pack_uv_apply_pack_uv
126 layout
.menu(MUV_MT_SelectUV
.bl_idname
, text
="Select UV")
128 ops
= layout
.operator(MUV_OT_SmoothUV
.bl_idname
, text
="Smooth")
129 ops
.transmission
= sc
.muv_smooth_uv_transmission
130 ops
.select
= sc
.muv_smooth_uv_select
131 ops
.mesh_infl
= sc
.muv_smooth_uv_mesh_infl
133 layout
.menu(MUV_MT_AlignUV
.bl_idname
, text
="Align UV")
136 layout
.label(text
="Editor Enhancement", icon
=compat
.icon('IMAGE'))
138 layout
.menu(MUV_MT_AlignUVCursor
.bl_idname
, text
="Align UV Cursor")
140 layout
.prop(sc
, "muv_uv_bounding_box_show", text
="UV Bounding Box")
142 layout
.menu(MUV_MT_UVInspection
.bl_idname
, text
="UV Inspection")
145 def add_builtin_menu():
146 bpy
.types
.VIEW3D_MT_uv_map
.append(view3d_uvmap_menu_fn
)
147 bpy
.types
.VIEW3D_MT_object
.append(view3d_object_menu_fn
)
148 bpy
.types
.IMAGE_MT_uvs
.append(image_uvs_menu_fn
)
151 def remove_builtin_menu():
152 bpy
.types
.IMAGE_MT_uvs
.remove(image_uvs_menu_fn
)
153 bpy
.types
.VIEW3D_MT_object
.remove(view3d_object_menu_fn
)
154 bpy
.types
.VIEW3D_MT_uv_map
.remove(view3d_uvmap_menu_fn
)
157 def set_debug_mode(self
, value
):
158 self
['enable_debug_mode'] = value
161 def get_debug_mode(self
):
162 enabled
= self
.get('enable_debug_mode', False)
164 common
.enable_debugg_mode()
166 common
.disable_debug_mode()
171 @compat.make_annotations
172 class MUV_Preferences(AddonPreferences
):
173 """Preferences class: Preferences for this add-on"""
175 bl_idname
= "magic_uv"
177 def update_enable_builtin_menu(self
, _
):
178 if self
['enable_builtin_menu']:
181 remove_builtin_menu()
183 # enable to add features to built-in menu
184 enable_builtin_menu
= BoolProperty(
185 name
="Built-in Menu",
186 description
="Enable built-in menu",
188 update
=update_enable_builtin_menu
,
192 enable_debug_mode
= BoolProperty(
194 description
="Enable debugging mode",
201 uv_sculpt_brush_color
= FloatVectorProperty(
204 default
=(1.0, 0.4, 0.4, 1.0),
212 uv_inspection_overlapped_color
= FloatVectorProperty(
215 default
=(0.0, 0.0, 1.0, 0.3),
221 uv_inspection_overlapped_color_for_v3d
= FloatVectorProperty(
222 name
="Color (View3D)",
223 description
="Color in View3D",
224 default
=(0.0, 0.0, 1.0, 0.5),
232 uv_inspection_flipped_color
= FloatVectorProperty(
235 default
=(1.0, 0.0, 0.0, 0.3),
241 uv_inspection_flipped_color_for_v3d
= FloatVectorProperty(
242 name
="Color (View3D)",
243 description
="Color in View3D",
244 default
=(1.0, 0.0, 0.0, 0.5),
251 # for Texture Projection
252 texture_projection_canvas_padding
= FloatVectorProperty(
253 name
="Canvas Padding",
254 description
="Canvas Padding",
258 default
=(20.0, 20.0))
260 # for UV Bounding Box
261 uv_bounding_box_cp_size
= FloatProperty(
263 description
="Control Point Size",
267 uv_bounding_box_cp_react_size
= FloatProperty(
269 description
="Size event fired",
275 category
= EnumProperty(
277 description
="Preferences Category",
279 ('INFO', "Information", "Information about this add-on"),
280 ('CONFIG', "Configuration", "Configuration about this add-on"),
284 info_desc_expanded
= BoolProperty(
286 description
="Description",
289 info_loc_expanded
= BoolProperty(
291 description
="Location",
294 conf_uv_sculpt_expanded
= BoolProperty(
296 description
="UV Sculpt",
299 conf_uv_inspection_expanded
= BoolProperty(
300 name
="UV Inspection",
301 description
="UV Inspection",
304 conf_texture_projection_expanded
= BoolProperty(
305 name
="Texture Projection",
306 description
="Texture Projection",
309 conf_uv_bounding_box_expanded
= BoolProperty(
310 name
="UV Bounding Box",
311 description
="UV Bounding Box",
318 layout
.row().prop(self
, "category", expand
=True)
320 if self
.category
== 'INFO':
324 self
, "info_desc_expanded", text
="Description",
325 icon
='DISCLOSURE_TRI_DOWN' if self
.info_desc_expanded
326 else 'DISCLOSURE_TRI_RIGHT')
327 if self
.info_desc_expanded
:
328 col
= layout
.column(align
=True)
329 col
.label(text
="Magic UV is composed of many UV editing" +
331 col
.label(text
="See tutorial page if you are new to this" +
333 col
.label(text
="https://github.com/nutti/Magic-UV" +
337 self
, "info_loc_expanded", text
="Location",
338 icon
='DISCLOSURE_TRI_DOWN' if self
.info_loc_expanded
339 else 'DISCLOSURE_TRI_RIGHT')
340 if self
.info_loc_expanded
:
341 row
= layout
.row(align
=True)
342 sp
= compat
.layout_split(row
, 0.5)
343 sp
.label(text
="3D View > Sidebar > " +
344 "Copy/Paste UV (Object mode)")
345 sp
= compat
.layout_split(sp
, 1.0)
346 col
= sp
.column(align
=True)
347 col
.label(text
="Copy/Paste UV (Among objects)")
349 row
= layout
.row(align
=True)
350 sp
= compat
.layout_split(row
, 0.5)
351 sp
.label(text
="3D View > Sidebar > " +
352 "Copy/Paste UV (Edit mode)")
353 sp
= compat
.layout_split(sp
, 1.0)
354 col
= sp
.column(align
=True)
355 col
.label(text
="Copy/Paste UV (Among faces in 3D View)")
356 col
.label(text
="Transfer UV")
358 row
= layout
.row(align
=True)
359 sp
= compat
.layout_split(row
, 0.5)
360 sp
.label(text
="3D View > Sidebar > " +
361 "UV Manipulation (Edit mode)")
362 sp
= compat
.layout_split(sp
, 1.0)
363 col
= sp
.column(align
=True)
364 col
.label(text
="Flip/Rotate UV")
365 col
.label(text
="Mirror UV")
366 col
.label(text
="Move UV")
367 col
.label(text
="World Scale UV")
368 col
.label(text
="Preserve UV Aspect")
369 col
.label(text
="Texture Lock")
370 col
.label(text
="Texture Wrap")
371 col
.label(text
="UV Sculpt")
373 row
= layout
.row(align
=True)
374 sp
= compat
.layout_split(row
, 0.5)
375 sp
.label(text
="3D View > Sidebar > " +
376 "UV Manipulation (Edit mode)")
377 sp
= compat
.layout_split(sp
, 1.0)
378 col
= sp
.column(align
=True)
379 col
.label(text
="Unwrap Constraint")
380 col
.label(text
="Texture Projection")
381 col
.label(text
="UVW")
383 row
= layout
.row(align
=True)
384 sp
= compat
.layout_split(row
, 0.5)
385 sp
.label(text
="UV/Image Editor > Sidebar > Copy/Paste UV")
386 sp
= compat
.layout_split(sp
, 1.0)
387 col
= sp
.column(align
=True)
388 col
.label(text
="Copy/Paste UV " +
389 "(Among faces in UV/Image Editor)")
391 row
= layout
.row(align
=True)
392 sp
= compat
.layout_split(row
, 0.5)
393 sp
.label(text
="UV/Image Editor > Sidebar > UV Manipulation")
394 sp
= compat
.layout_split(sp
, 1.0)
395 col
= sp
.column(align
=True)
396 col
.label(text
="Align UV")
397 col
.label(text
="Smooth UV")
398 col
.label(text
="Select UV")
399 col
.label(text
="Pack UV (Extension)")
401 row
= layout
.row(align
=True)
402 sp
= compat
.layout_split(row
, 0.5)
403 sp
.label(text
="UV/Image Editor > Sidebar > " +
404 "Editor Enhancement")
405 sp
= compat
.layout_split(sp
, 1.0)
406 col
= sp
.column(align
=True)
407 col
.label(text
="Align UV Cursor")
408 col
.label(text
="UV Cursor Location")
409 col
.label(text
="UV Bounding Box")
410 col
.label(text
="UV Inspection")
412 elif self
.category
== 'CONFIG':
415 layout
.prop(self
, "enable_builtin_menu", text
="Built-in Menu")
416 layout
.prop(self
, "enable_debug_mode", text
="Debug Mode")
421 self
, "conf_uv_sculpt_expanded", text
="UV Sculpt",
422 icon
='DISCLOSURE_TRI_DOWN' if self
.conf_uv_sculpt_expanded
423 else 'DISCLOSURE_TRI_RIGHT')
424 if self
.conf_uv_sculpt_expanded
:
425 sp
= compat
.layout_split(layout
, 0.05)
426 col
= sp
.column() # spacer
427 sp
= compat
.layout_split(sp
, 0.3)
429 col
.label(text
="Brush Color:")
430 col
.prop(self
, "uv_sculpt_brush_color", text
="")
434 self
, "conf_uv_inspection_expanded", text
="UV Inspection",
435 icon
='DISCLOSURE_TRI_DOWN' if self
.conf_uv_inspection_expanded
436 else 'DISCLOSURE_TRI_RIGHT')
437 if self
.conf_uv_inspection_expanded
:
438 sp
= compat
.layout_split(layout
, 0.05)
439 col
= sp
.column() # spacer
440 sp
= compat
.layout_split(sp
, 0.3)
442 col
.label(text
="Overlapped UV Color:")
443 col
.prop(self
, "uv_inspection_overlapped_color", text
="")
444 sp
= compat
.layout_split(sp
, 0.45)
446 col
.label(text
="Flipped UV Color:")
447 col
.prop(self
, "uv_inspection_flipped_color", text
="")
449 sp
= compat
.layout_split(layout
, 0.05)
450 col
= sp
.column() # spacer
451 sp
= compat
.layout_split(sp
, 0.3)
453 col
.label(text
="Overlapped UV Color (View3D):")
454 col
.prop(self
, "uv_inspection_overlapped_color_for_v3d",
456 sp
= compat
.layout_split(sp
, 0.45)
458 col
.label(text
="Flipped UV Color (View3D):")
459 col
.prop(self
, "uv_inspection_flipped_color_for_v3d",
465 self
, "conf_texture_projection_expanded",
466 text
="Texture Projection",
467 icon
='DISCLOSURE_TRI_DOWN'
468 if self
.conf_texture_projection_expanded
469 else 'DISCLOSURE_TRI_RIGHT')
470 if self
.conf_texture_projection_expanded
:
471 sp
= compat
.layout_split(layout
, 0.05)
472 col
= sp
.column() # spacer
473 sp
= compat
.layout_split(sp
, 0.3)
475 col
.prop(self
, "texture_projection_canvas_padding")
479 self
, "conf_uv_bounding_box_expanded", text
="UV Bounding Box",
480 icon
='DISCLOSURE_TRI_DOWN'
481 if self
.conf_uv_bounding_box_expanded
482 else 'DISCLOSURE_TRI_RIGHT')
483 if self
.conf_uv_bounding_box_expanded
:
484 sp
= compat
.layout_split(layout
, 0.05)
485 col
= sp
.column() # spacer
486 sp
= compat
.layout_split(sp
, 0.3)
488 col
.label(text
="Control Point:")
489 col
.prop(self
, "uv_bounding_box_cp_size")
490 col
.prop(self
, "uv_bounding_box_cp_react_size")