1 # SPDX-License-Identifier: GPL-2.0-or-later
3 __author__
= "Nutti <nutti.metro@gmail.com>"
4 __status__
= "production"
6 __date__
= "22 Apr 2022"
9 from bpy
.props
import (
15 from bpy
.types
import AddonPreferences
18 from .op
.clip_uv
import MUV_OT_ClipUV
19 from .op
.flip_rotate_uv
import MUV_OT_FlipRotateUV
20 from .op
.mirror_uv
import MUV_OT_MirrorUV
21 from .op
.move_uv
import MUV_OT_MoveUV
22 from .op
.unwrap_constraint
import MUV_OT_UnwrapConstraint
23 from .op
.pack_uv
import MUV_OT_PackUV
24 from .op
.smooth_uv
import MUV_OT_SmoothUV
25 from .ui
.VIEW3D_MT_uv_map
import (
29 MUV_MT_PreserveUVAspect
,
32 MUV_MT_TextureProjection
,
35 from .ui
.VIEW3D_MT_object
import MUV_MT_CopyPasteUV_Object
36 from .ui
.IMAGE_MT_uvs
import (
37 MUV_MT_CopyPasteUV_UVEdit
,
43 from .utils
.bl_class_registry
import BlClassRegistry
44 from .utils
import compatibility
as compat
47 def view3d_uvmap_menu_fn(self
, context
):
52 layout
.label(text
="Copy/Paste UV", icon
=compat
.icon('IMAGE'))
54 layout
.menu(MUV_MT_CopyPasteUV
.bl_idname
, text
="Copy/Paste UV")
56 layout
.menu(MUV_MT_TransferUV
.bl_idname
, text
="Transfer UV")
59 layout
.label(text
="UV Manipulation", icon
=compat
.icon('IMAGE'))
61 ops
= layout
.operator(MUV_OT_FlipRotateUV
.bl_idname
, text
="Flip/Rotate UV")
62 ops
.seams
= sc
.muv_flip_rotate_uv_seams
64 ops
= layout
.operator(MUV_OT_MirrorUV
.bl_idname
, text
="Mirror UV")
65 ops
.axis
= sc
.muv_mirror_uv_axis
67 layout
.operator(MUV_OT_MoveUV
.bl_idname
, text
="Move UV")
69 layout
.menu(MUV_MT_WorldScaleUV
.bl_idname
, text
="World Scale UV")
71 layout
.menu(MUV_MT_PreserveUVAspect
.bl_idname
, text
="Preserve UV")
73 layout
.menu(MUV_MT_TextureLock
.bl_idname
, text
="Texture Lock")
75 layout
.menu(MUV_MT_TextureWrap
.bl_idname
, text
="Texture Wrap")
77 layout
.prop(sc
, "muv_uv_sculpt_enable", text
="UV Sculpt")
80 layout
.label(text
="UV Mapping", icon
=compat
.icon('IMAGE'))
82 ops
= layout
.operator(MUV_OT_UnwrapConstraint
.bl_idname
,
83 text
="Unwrap Constraint")
84 ops
.u_const
= sc
.muv_unwrap_constraint_u_const
85 ops
.v_const
= sc
.muv_unwrap_constraint_v_const
87 layout
.menu(MUV_MT_TextureProjection
.bl_idname
, text
="Texture Projection")
89 layout
.menu(MUV_MT_UVW
.bl_idname
, text
="UVW")
92 def view3d_object_menu_fn(self
, _
):
96 layout
.label(text
="Copy/Paste UV", icon
=compat
.icon('IMAGE'))
97 # Copy/Paste UV (Among Object)
98 layout
.menu(MUV_MT_CopyPasteUV_Object
.bl_idname
, text
="Copy/Paste UV")
101 def image_uvs_menu_fn(self
, context
):
106 layout
.label(text
="Copy/Paste UV", icon
=compat
.icon('IMAGE'))
107 # Copy/Paste UV (on UV/Image Editor)
108 layout
.menu(MUV_MT_CopyPasteUV_UVEdit
.bl_idname
, text
="Copy/Paste UV")
111 layout
.label(text
="UV Manipulation", icon
=compat
.icon('IMAGE'))
113 ops
= layout
.operator(MUV_OT_ClipUV
.bl_idname
, text
="Clip UV")
114 ops
.clip_uv_range_max
= sc
.muv_clip_uv_range_max
115 ops
.clip_uv_range_min
= sc
.muv_clip_uv_range_min
117 ops
= layout
.operator(MUV_OT_PackUV
.bl_idname
, text
="Pack UV")
118 ops
.allowable_center_deviation
= sc
.muv_pack_uv_allowable_center_deviation
119 ops
.allowable_size_deviation
= sc
.muv_pack_uv_allowable_size_deviation
120 ops
.accurate_island_copy
= sc
.muv_pack_uv_accurate_island_copy
121 ops
.stride
= sc
.muv_pack_uv_stride
122 ops
.apply_pack_uv
= sc
.muv_pack_uv_apply_pack_uv
124 layout
.menu(MUV_MT_SelectUV
.bl_idname
, text
="Select UV")
126 ops
= layout
.operator(MUV_OT_SmoothUV
.bl_idname
, text
="Smooth")
127 ops
.transmission
= sc
.muv_smooth_uv_transmission
128 ops
.select
= sc
.muv_smooth_uv_select
129 ops
.mesh_infl
= sc
.muv_smooth_uv_mesh_infl
131 layout
.menu(MUV_MT_AlignUV
.bl_idname
, text
="Align UV")
134 layout
.label(text
="Editor Enhancement", icon
=compat
.icon('IMAGE'))
136 layout
.menu(MUV_MT_AlignUVCursor
.bl_idname
, text
="Align UV Cursor")
138 layout
.prop(sc
, "muv_uv_bounding_box_show", text
="UV Bounding Box")
140 layout
.menu(MUV_MT_UVInspection
.bl_idname
, text
="UV Inspection")
143 def add_builtin_menu():
144 bpy
.types
.VIEW3D_MT_uv_map
.append(view3d_uvmap_menu_fn
)
145 bpy
.types
.VIEW3D_MT_object
.append(view3d_object_menu_fn
)
146 bpy
.types
.IMAGE_MT_uvs
.append(image_uvs_menu_fn
)
149 def remove_builtin_menu():
150 bpy
.types
.IMAGE_MT_uvs
.remove(image_uvs_menu_fn
)
151 bpy
.types
.VIEW3D_MT_object
.remove(view3d_object_menu_fn
)
152 bpy
.types
.VIEW3D_MT_uv_map
.remove(view3d_uvmap_menu_fn
)
155 def set_debug_mode(self
, value
):
156 self
['enable_debug_mode'] = value
159 def get_debug_mode(self
):
160 enabled
= self
.get('enable_debug_mode', False)
162 common
.enable_debugg_mode()
164 common
.disable_debug_mode()
169 @compat.make_annotations
170 class MUV_Preferences(AddonPreferences
):
171 """Preferences class: Preferences for this add-on"""
173 bl_idname
= "magic_uv"
175 def update_enable_builtin_menu(self
, _
):
176 if self
['enable_builtin_menu']:
179 remove_builtin_menu()
181 # enable to add features to built-in menu
182 enable_builtin_menu
= BoolProperty(
183 name
="Built-in Menu",
184 description
="Enable built-in menu",
186 update
=update_enable_builtin_menu
,
190 enable_debug_mode
= BoolProperty(
192 description
="Enable debugging mode",
199 uv_sculpt_brush_color
= FloatVectorProperty(
202 default
=(1.0, 0.4, 0.4, 1.0),
210 uv_inspection_overlapped_color
= FloatVectorProperty(
213 default
=(0.0, 0.0, 1.0, 0.3),
219 uv_inspection_overlapped_color_for_v3d
= FloatVectorProperty(
220 name
="Color (View3D)",
221 description
="Color in View3D",
222 default
=(0.0, 0.0, 1.0, 0.5),
230 uv_inspection_flipped_color
= FloatVectorProperty(
233 default
=(1.0, 0.0, 0.0, 0.3),
239 uv_inspection_flipped_color_for_v3d
= FloatVectorProperty(
240 name
="Color (View3D)",
241 description
="Color in View3D",
242 default
=(1.0, 0.0, 0.0, 0.5),
249 # for Texture Projection
250 texture_projection_canvas_padding
= FloatVectorProperty(
251 name
="Canvas Padding",
252 description
="Canvas Padding",
256 default
=(20.0, 20.0))
258 # for UV Bounding Box
259 uv_bounding_box_cp_size
= FloatProperty(
261 description
="Control Point Size",
265 uv_bounding_box_cp_react_size
= FloatProperty(
267 description
="Size event fired",
273 category
= EnumProperty(
275 description
="Preferences Category",
277 ('INFO', "Information", "Information about this add-on"),
278 ('CONFIG', "Configuration", "Configuration about this add-on"),
282 info_desc_expanded
= BoolProperty(
284 description
="Description",
287 info_loc_expanded
= BoolProperty(
289 description
="Location",
292 conf_uv_sculpt_expanded
= BoolProperty(
294 description
="UV Sculpt",
297 conf_uv_inspection_expanded
= BoolProperty(
298 name
="UV Inspection",
299 description
="UV Inspection",
302 conf_texture_projection_expanded
= BoolProperty(
303 name
="Texture Projection",
304 description
="Texture Projection",
307 conf_uv_bounding_box_expanded
= BoolProperty(
308 name
="UV Bounding Box",
309 description
="UV Bounding Box",
316 layout
.row().prop(self
, "category", expand
=True)
318 if self
.category
== 'INFO':
322 self
, "info_desc_expanded", text
="Description",
323 icon
='DISCLOSURE_TRI_DOWN' if self
.info_desc_expanded
324 else 'DISCLOSURE_TRI_RIGHT')
325 if self
.info_desc_expanded
:
326 col
= layout
.column(align
=True)
327 col
.label(text
="Magic UV is composed of many UV editing" +
329 col
.label(text
="See tutorial page if you are new to this" +
331 col
.label(text
="https://github.com/nutti/Magic-UV" +
335 self
, "info_loc_expanded", text
="Location",
336 icon
='DISCLOSURE_TRI_DOWN' if self
.info_loc_expanded
337 else 'DISCLOSURE_TRI_RIGHT')
338 if self
.info_loc_expanded
:
339 row
= layout
.row(align
=True)
340 sp
= compat
.layout_split(row
, 0.5)
341 sp
.label(text
="3D View > Sidebar > " +
342 "Copy/Paste UV (Object mode)")
343 sp
= compat
.layout_split(sp
, 1.0)
344 col
= sp
.column(align
=True)
345 col
.label(text
="Copy/Paste UV (Among objects)")
347 row
= layout
.row(align
=True)
348 sp
= compat
.layout_split(row
, 0.5)
349 sp
.label(text
="3D View > Sidebar > " +
350 "Copy/Paste UV (Edit mode)")
351 sp
= compat
.layout_split(sp
, 1.0)
352 col
= sp
.column(align
=True)
353 col
.label(text
="Copy/Paste UV (Among faces in 3D View)")
354 col
.label(text
="Transfer UV")
356 row
= layout
.row(align
=True)
357 sp
= compat
.layout_split(row
, 0.5)
358 sp
.label(text
="3D View > Sidebar > " +
359 "UV Manipulation (Edit mode)")
360 sp
= compat
.layout_split(sp
, 1.0)
361 col
= sp
.column(align
=True)
362 col
.label(text
="Flip/Rotate UV")
363 col
.label(text
="Mirror UV")
364 col
.label(text
="Move UV")
365 col
.label(text
="World Scale UV")
366 col
.label(text
="Preserve UV Aspect")
367 col
.label(text
="Texture Lock")
368 col
.label(text
="Texture Wrap")
369 col
.label(text
="UV Sculpt")
371 row
= layout
.row(align
=True)
372 sp
= compat
.layout_split(row
, 0.5)
373 sp
.label(text
="3D View > Sidebar > " +
374 "UV Manipulation (Edit mode)")
375 sp
= compat
.layout_split(sp
, 1.0)
376 col
= sp
.column(align
=True)
377 col
.label(text
="Unwrap Constraint")
378 col
.label(text
="Texture Projection")
379 col
.label(text
="UVW")
381 row
= layout
.row(align
=True)
382 sp
= compat
.layout_split(row
, 0.5)
383 sp
.label(text
="UV/Image Editor > Sidebar > Copy/Paste UV")
384 sp
= compat
.layout_split(sp
, 1.0)
385 col
= sp
.column(align
=True)
386 col
.label(text
="Copy/Paste UV " +
387 "(Among faces in UV/Image Editor)")
389 row
= layout
.row(align
=True)
390 sp
= compat
.layout_split(row
, 0.5)
391 sp
.label(text
="UV/Image Editor > Sidebar > UV Manipulation")
392 sp
= compat
.layout_split(sp
, 1.0)
393 col
= sp
.column(align
=True)
394 col
.label(text
="Align UV")
395 col
.label(text
="Smooth UV")
396 col
.label(text
="Select UV")
397 col
.label(text
="Pack UV (Extension)")
399 row
= layout
.row(align
=True)
400 sp
= compat
.layout_split(row
, 0.5)
401 sp
.label(text
="UV/Image Editor > Sidebar > " +
402 "Editor Enhancement")
403 sp
= compat
.layout_split(sp
, 1.0)
404 col
= sp
.column(align
=True)
405 col
.label(text
="Align UV Cursor")
406 col
.label(text
="UV Cursor Location")
407 col
.label(text
="UV Bounding Box")
408 col
.label(text
="UV Inspection")
410 elif self
.category
== 'CONFIG':
413 layout
.prop(self
, "enable_builtin_menu", text
="Built-in Menu")
414 layout
.prop(self
, "enable_debug_mode", text
="Debug Mode")
419 self
, "conf_uv_sculpt_expanded", text
="UV Sculpt",
420 icon
='DISCLOSURE_TRI_DOWN' if self
.conf_uv_sculpt_expanded
421 else 'DISCLOSURE_TRI_RIGHT')
422 if self
.conf_uv_sculpt_expanded
:
423 sp
= compat
.layout_split(layout
, 0.05)
424 col
= sp
.column() # spacer
425 sp
= compat
.layout_split(sp
, 0.3)
427 col
.label(text
="Brush Color:")
428 col
.prop(self
, "uv_sculpt_brush_color", text
="")
432 self
, "conf_uv_inspection_expanded", text
="UV Inspection",
433 icon
='DISCLOSURE_TRI_DOWN' if self
.conf_uv_inspection_expanded
434 else 'DISCLOSURE_TRI_RIGHT')
435 if self
.conf_uv_inspection_expanded
:
436 sp
= compat
.layout_split(layout
, 0.05)
437 col
= sp
.column() # spacer
438 sp
= compat
.layout_split(sp
, 0.3)
440 col
.label(text
="Overlapped UV Color:")
441 col
.prop(self
, "uv_inspection_overlapped_color", text
="")
442 sp
= compat
.layout_split(sp
, 0.45)
444 col
.label(text
="Flipped UV Color:")
445 col
.prop(self
, "uv_inspection_flipped_color", text
="")
447 sp
= compat
.layout_split(layout
, 0.05)
448 col
= sp
.column() # spacer
449 sp
= compat
.layout_split(sp
, 0.3)
451 col
.label(text
="Overlapped UV Color (View3D):")
452 col
.prop(self
, "uv_inspection_overlapped_color_for_v3d",
454 sp
= compat
.layout_split(sp
, 0.45)
456 col
.label(text
="Flipped UV Color (View3D):")
457 col
.prop(self
, "uv_inspection_flipped_color_for_v3d",
463 self
, "conf_texture_projection_expanded",
464 text
="Texture Projection",
465 icon
='DISCLOSURE_TRI_DOWN'
466 if self
.conf_texture_projection_expanded
467 else 'DISCLOSURE_TRI_RIGHT')
468 if self
.conf_texture_projection_expanded
:
469 sp
= compat
.layout_split(layout
, 0.05)
470 col
= sp
.column() # spacer
471 sp
= compat
.layout_split(sp
, 0.3)
473 col
.prop(self
, "texture_projection_canvas_padding")
477 self
, "conf_uv_bounding_box_expanded", text
="UV Bounding Box",
478 icon
='DISCLOSURE_TRI_DOWN'
479 if self
.conf_uv_bounding_box_expanded
480 else 'DISCLOSURE_TRI_RIGHT')
481 if self
.conf_uv_bounding_box_expanded
:
482 sp
= compat
.layout_split(layout
, 0.05)
483 col
= sp
.column() # spacer
484 sp
= compat
.layout_split(sp
, 0.3)
486 col
.label(text
="Control Point:")
487 col
.prop(self
, "uv_bounding_box_cp_size")
488 col
.prop(self
, "uv_bounding_box_cp_react_size")