1 # SPDX-FileCopyrightText: 2017-2022 Blender Foundation
3 # SPDX-License-Identifier: GPL-2.0-or-later
5 __author__
= "kgeogeo, mem, Nutti <nutti.metro@gmail.com>"
6 __status__
= "production"
8 __date__
= "22 Apr 2022"
11 from bpy
.props
import BoolProperty
13 from mathutils
import Vector
16 from ..utils
.bl_class_registry
import BlClassRegistry
17 from ..utils
.property_class_registry
import PropertyClassRegistry
20 def _is_valid_context(context
):
21 # only 'VIEW_3D' space is allowed to execute
22 if not common
.is_valid_space(context
, ['VIEW_3D']):
25 # Multiple objects editing mode is not supported in this feature.
26 objs
= common
.get_uv_editable_objects(context
)
30 # only edit mode is allowed to execute
31 if context
.object.mode
!= 'EDIT':
37 @PropertyClassRegistry()
42 def init_props(cls
, scene
):
43 scene
.muv_move_uv_enabled
= BoolProperty(
44 name
="Move UV Enabled",
45 description
="Move UV is enabled",
50 def del_props(cls
, scene
):
51 del scene
.muv_move_uv_enabled
55 class MUV_OT_MoveUV(bpy
.types
.Operator
):
57 Operator class: Move UV
60 bl_idname
= "uv.muv_move_uv"
62 bl_options
= {'REGISTER', 'UNDO'}
67 self
.__topology
_dict
= []
68 self
.__prev
_mouse
= Vector((0.0, 0.0))
69 self
.__offset
_uv
= Vector((0.0, 0.0))
70 self
.__prev
_offset
_uv
= Vector((0.0, 0.0))
71 self
.__first
_time
= True
73 self
.__operating
= False
75 # Creation of BMesh is high cost, so cache related objects.
79 def poll(cls
, context
):
80 # we can not get area/space/region from console
81 if common
.is_console_mode():
83 if cls
.is_running(context
):
85 return _is_valid_context(context
)
88 def is_running(cls
, _
):
91 def _find_uv(self
, bm
, active_uv
):
94 for fidx
, f
in enumerate(bm
.faces
):
95 for vidx
, v
in enumerate(f
.verts
):
97 uvs
.append(f
.loops
[vidx
][active_uv
].uv
.copy())
98 topology_dict
.append([fidx
, vidx
])
100 return topology_dict
, uvs
102 def modal(self
, _
, event
):
103 if self
.__first
_time
is True:
104 self
.__prev
_mouse
= Vector((
105 event
.mouse_region_x
, event
.mouse_region_y
))
106 self
.__first
_time
= False
107 return {'RUNNING_MODAL'}
111 self
.__offset
_uv
+= Vector((
112 (event
.mouse_region_x
- self
.__prev
_mouse
.x
) / div
,
113 (event
.mouse_region_y
- self
.__prev
_mouse
.y
) / div
))
114 ouv
= self
.__offset
_uv
115 pouv
= self
.__prev
_offset
_uv
116 vec
= Vector((ouv
.x
- ouv
.y
, ouv
.x
+ ouv
.y
))
118 self
.__prev
_offset
_uv
= vec
119 self
.__prev
_mouse
= Vector((
120 event
.mouse_region_x
, event
.mouse_region_y
))
122 # check if operation is started
123 if not self
.__operating
:
124 if event
.type == 'LEFTMOUSE' and event
.value
== 'RELEASE':
125 self
.__operating
= True
126 return {'RUNNING_MODAL'}
129 obj
= self
.__cache
["active_object"]
130 bm
= self
.__cache
["bmesh"]
131 active_uv
= self
.__cache
["active_uv"]
132 for uv
in self
.__cache
["target_uv"]:
134 bmesh
.update_edit_mesh(obj
.data
)
136 # check mouse preference
137 confirm_btn
= 'LEFTMOUSE'
138 cancel_btn
= 'RIGHTMOUSE'
141 if event
.type == cancel_btn
and event
.value
== 'PRESS':
142 for (fidx
, vidx
), uv
in zip(self
.__topology
_dict
, self
.__ini
_uvs
):
143 bm
.faces
[fidx
].loops
[vidx
][active_uv
].uv
= uv
144 MUV_OT_MoveUV
.__running
= False
148 if event
.type == confirm_btn
and event
.value
== 'PRESS':
149 MUV_OT_MoveUV
.__running
= False
153 return {'RUNNING_MODAL'}
155 def execute(self
, context
):
156 MUV_OT_MoveUV
.__running
= True
157 self
.__operating
= False
158 self
.__first
_time
= True
160 context
.window_manager
.modal_handler_add(self
)
162 objs
= common
.get_uv_editable_objects(context
)
163 # poll() method ensures that only one object is selected.
165 bm
= bmesh
.from_edit_mesh(obj
.data
)
166 active_uv
= bm
.loops
.layers
.uv
.active
167 self
.__topology
_dict
, self
.__ini
_uvs
= self
._find
_uv
(bm
, active_uv
)
169 # Optimization: Store temporary variables which cause heavy
171 self
.__cache
["active_object"] = obj
172 self
.__cache
["bmesh"] = bm
173 self
.__cache
["active_uv"] = active_uv
174 self
.__cache
["target_uv"] = []
175 for fidx
, vidx
in self
.__topology
_dict
:
176 l
= bm
.faces
[fidx
].loops
[vidx
]
177 self
.__cache
["target_uv"].append(l
[active_uv
].uv
)
180 context
.area
.tag_redraw()
182 return {'RUNNING_MODAL'}