diff --git a/uv_magic_uv/__init__.py b/uv_magic_uv/__init__.py
index 61fcc8049b692f240755d5436f7168193e2e4410..ae0317ed8d15ec21e46e21d2c0a33bfa2a3e9a55 100644
--- a/uv_magic_uv/__init__.py
+++ b/uv_magic_uv/__init__.py
@@ -41,47 +41,24 @@ bl_info = {
     "category": "UV"
 }
 
-def check_version(major, minor, _):
-    """
-    Check blender version
-    """
-
-    if bpy.app.version[0] == major and bpy.app.version[1] == minor:
-        return 0
-    if bpy.app.version[0] > major:
-        return 1
-    if bpy.app.version[1] > minor:
-        return 1
-    return -1
-
 
 if "bpy" in locals():
     import importlib
     importlib.reload(common)
     importlib.reload(utils)
     utils.bl_class_registry.BlClassRegistry.cleanup()
-    if check_version(2, 80, 0) >= 0:
-        importlib.reload(lib)
-        importlib.reload(op)
-        importlib.reload(ui)
-        importlib.reload(properites)
-        importlib.reload(preferences)
-    else:
-        importlib.reload(legacy)
-    importlib.reload(impl)
+    importlib.reload(op)
+    importlib.reload(ui)
+    importlib.reload(properites)
+    importlib.reload(preferences)
 else:
     import bpy
     from . import common
     from . import utils
-    if check_version(2, 80, 0) >= 0:
-        from . import lib
-        from . import op
-        from . import ui
-        from . import properites
-        from . import preferences
-    else:
-        from . import legacy
-    from . import impl
+    from . import op
+    from . import ui
+    from . import properites
+    from . import preferences
 
 import os
 
@@ -95,9 +72,8 @@ def register_updater(bl_info):
     config.current_addon_path = os.path.dirname(os.path.realpath(__file__))
     config.branches = ["master", "develop"]
     config.addon_directory = config.current_addon_path[:config.current_addon_path.rfind("/")]
-    #config.min_release_version = bl_info["version"]
-    config.min_release_version = (5, 1)
-    config.target_addon_path = "uv_magic_uv"
+    config.min_release_version = bl_info["version"]
+    config.target_addon_path = "src/uv_magic_uv"
     updater = utils.addon_updator.AddonUpdatorManager.get_instance()
     updater.init(bl_info, config)
 
@@ -105,29 +81,17 @@ def register_updater(bl_info):
 def register():
     register_updater(bl_info)
 
-    if common.check_version(2, 80, 0) >= 0:
-        utils.bl_class_registry.BlClassRegistry.register()
-        properites.init_props(bpy.types.Scene)
-        if bpy.context.user_preferences.addons['uv_magic_uv'].preferences.enable_builtin_menu:
-            preferences.add_builtin_menu()
-    else:
-        utils.bl_class_registry.BlClassRegistry.register()
-        legacy.properites.init_props(bpy.types.Scene)
-        if legacy.preferences.Preferences.enable_builtin_menu:
-            legacy.preferences.add_builtin_menu()
+    utils.bl_class_registry.BlClassRegistry.register()
+    properites.init_props(bpy.types.Scene)
+    if utils.compatibility.get_user_preferences(bpy.context).addons['uv_magic_uv'].preferences.enable_builtin_menu:
+        preferences.add_builtin_menu()
 
 
 def unregister():
-    if common.check_version(2, 80, 0) >= 0:
-        if bpy.context.user_preferences.addons['uv_magic_uv'].preferences.enable_builtin_menu:
-            preferences.remove_builtin_menu()
-        properites.clear_props(bpy.types.Scene)
-        utils.bl_class_registry.BlClassRegistry.unregister()
-    else:
-        if legacy.preferences.Preferences.enable_builtin_menu:
-            legacy.preferences.remove_builtin_menu()
-        legacy.properites.clear_props(bpy.types.Scene)
-        utils.bl_class_registry.BlClassRegistry.unregister()
+    if utils.compatibility.get_user_preferences(bpy.context).addons['uv_magic_uv'].preferences.enable_builtin_menu:
+        preferences.remove_builtin_menu()
+    properites.clear_props(bpy.types.Scene)
+    utils.bl_class_registry.BlClassRegistry.unregister()
 
 
 if __name__ == "__main__":
diff --git a/uv_magic_uv/common.py b/uv_magic_uv/common.py
index 83c6ae741e56e38003765f0eb9690edc312f68f6..961ce447898b354bef34eef5eb105e7793d438e3 100644
--- a/uv_magic_uv/common.py
+++ b/uv_magic_uv/common.py
@@ -32,37 +32,10 @@ import bpy
 from mathutils import Vector
 import bmesh
 
+from .utils import compatibility as compat
 
-__all__ = [
-    'is_console_mode',
-    'is_debug_mode',
-    'enable_debugg_mode',
-    'disable_debug_mode',
-    'debug_print',
-    'check_version',
-    'redraw_all_areas',
-    'get_space_legacy',
-    'mouse_on_region_legacy',
-    'mouse_on_area_legacy',
-    'mouse_on_regions_legacy',
-    'create_bmesh',
-    'create_new_uv_map',
-    'get_island_info',
-    'get_island_info_from_bmesh',
-    'get_island_info_from_faces',
-    'get_uvimg_editor_board_size',
-    'calc_polygon_2d_area',
-    'calc_polygon_3d_area',
-    'measure_mesh_area',
-    'measure_uv_area_legacy',
-    'diff_point_to_segment',
-    'get_loop_sequences',
-    'get_overlapped_uv_info',
-    'get_flipped_uv_info',
-]
-
-
-__DEBUG_MODE = True
+
+__DEBUG_MODE = False
 
 
 def is_console_mode():
@@ -119,70 +92,6 @@ def redraw_all_areas():
         area.tag_redraw()
 
 
-def get_space_legacy(area_type, region_type, space_type):
-    """
-    Get current area/region/space
-    """
-
-    area = None
-    region = None
-    space = None
-
-    for area in bpy.context.screen.areas:
-        if area.type == area_type:
-            break
-    else:
-        return (None, None, None)
-    for region in area.regions:
-        if region.type == region_type:
-            break
-    for space in area.spaces:
-        if space.type == space_type:
-            break
-
-    return (area, region, space)
-
-
-def mouse_on_region_legacy(event, area_type, region_type):
-    pos = Vector((event.mouse_x, event.mouse_y))
-
-    _, region, _ = get_space_legacy(area_type, region_type, "")
-    if region is None:
-        return False
-
-    if (pos.x > region.x) and (pos.x < region.x + region.width) and \
-       (pos.y > region.y) and (pos.y < region.y + region.height):
-        return True
-
-    return False
-
-
-def mouse_on_area_legacy(event, area_type):
-    pos = Vector((event.mouse_x, event.mouse_y))
-
-    area, _, _ = get_space_legacy(area_type, "", "")
-    if area is None:
-        return False
-
-    if (pos.x > area.x) and (pos.x < area.x + area.width) and \
-       (pos.y > area.y) and (pos.y < area.y + area.height):
-        return True
-
-    return False
-
-
-def mouse_on_regions_legacy(event, area_type, regions):
-    if not mouse_on_area_legacy(event, area_type):
-        return False
-
-    for region in regions:
-        result = mouse_on_region_legacy(event, area_type, region)
-        if result:
-            return True
-
-    return False
-
-
 def get_space(area_type, region_type, space_type):
     """
     Get current area/region/space
@@ -199,8 +108,9 @@ def get_space(area_type, region_type, space_type):
         return (None, None, None)
     for region in area.regions:
         if region.type == region_type:
-            if region.width <= 1 or region.height <= 1:
-                continue
+            if compat.check_version(2, 80, 0) >= 0:
+                if region.width <= 1 or region.height <= 1:
+                    continue
             break
     else:
         return (area, None, None)
@@ -460,65 +370,6 @@ def measure_mesh_area(obj):
     return mesh_area
 
 
-def measure_uv_area_legacy(obj, tex_size=None):
-    bm = bmesh.from_edit_mesh(obj.data)
-    if check_version(2, 73, 0) >= 0:
-        bm.verts.ensure_lookup_table()
-        bm.edges.ensure_lookup_table()
-        bm.faces.ensure_lookup_table()
-
-    if not bm.loops.layers.uv:
-        return None
-    uv_layer = bm.loops.layers.uv.verify()
-
-    if not bm.faces.layers.tex:
-        return None
-    tex_layer = bm.faces.layers.tex.verify()
-
-    sel_faces = [f for f in bm.faces if f.select]
-
-    # measure
-    uv_area = 0.0
-    for f in sel_faces:
-        uvs = [l[uv_layer].uv for l in f.loops]
-        f_uv_area = calc_polygon_2d_area(uvs)
-
-        # user specified
-        if tex_size:
-            uv_area = uv_area + f_uv_area * tex_size[0] * tex_size[1]
-            continue
-
-        # try to find from texture_layer
-        img = None
-        if tex_layer:
-            img = f[tex_layer].image
-
-        # not found, then try to search from node
-        if not img:
-            for mat in obj.material_slots:
-                if not mat.material.node_tree:
-                    continue
-                for node in mat.material.node_tree.nodes:
-                    tex_node_types = [
-                        'TEX_ENVIRONMENT',
-                        'TEX_IMAGE',
-                    ]
-                    if node.type not in tex_node_types:
-                        continue
-                    if not node.image:
-                        continue
-                    img = node.image
-
-        # can not find from node, so we can not get texture size
-        if not img:
-            return None
-
-        img_size = img.size
-        uv_area = uv_area + f_uv_area * img_size[0] * img_size[1]
-
-    return uv_area
-
-
 def find_texture_layer(bm):
     if check_version(2, 80, 0) >= 0:
         return None
diff --git a/uv_magic_uv/impl/__init__.py b/uv_magic_uv/impl/__init__.py
deleted file mode 100644
index d22125af4321896496a08c18f692a1327cef8f8d..0000000000000000000000000000000000000000
--- a/uv_magic_uv/impl/__init__.py
+++ /dev/null
@@ -1,70 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-__author__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-if "bpy" in locals():
-    import importlib
-    importlib.reload(align_uv_cursor_impl)
-    importlib.reload(align_uv_impl)
-    importlib.reload(copy_paste_uv_impl)
-    importlib.reload(copy_paste_uv_uvedit_impl)
-    importlib.reload(flip_rotate_impl)
-    importlib.reload(mirror_uv_impl)
-    importlib.reload(move_uv_impl)
-    importlib.reload(pack_uv_impl)
-    importlib.reload(preserve_uv_aspect_impl)
-    importlib.reload(select_uv_impl)
-    importlib.reload(smooth_uv_impl)
-    importlib.reload(texture_lock_impl)
-    importlib.reload(texture_wrap_impl)
-    importlib.reload(transfer_uv_impl)
-    importlib.reload(unwrap_constraint_impl)
-    importlib.reload(uv_bounding_box_impl)
-    importlib.reload(uv_inspection_impl)
-    importlib.reload(uv_sculpt_impl)
-    importlib.reload(uvw_impl)
-    importlib.reload(world_scale_uv_impl)
-else:
-    from . import align_uv_cursor_impl
-    from . import align_uv_impl
-    from . import copy_paste_uv_impl
-    from . import copy_paste_uv_uvedit_impl
-    from . import flip_rotate_impl
-    from . import mirror_uv_impl
-    from . import move_uv_impl
-    from . import pack_uv_impl
-    from . import preserve_uv_aspect_impl
-    from . import select_uv_impl
-    from . import smooth_uv_impl
-    from . import texture_lock_impl
-    from . import texture_wrap_impl
-    from . import transfer_uv_impl
-    from . import unwrap_constraint_impl
-    from . import uv_bounding_box_impl
-    from . import uv_inspection_impl
-    from . import uv_sculpt_impl
-    from . import uvw_impl
-    from . import world_scale_uv_impl
-
-import bpy
diff --git a/uv_magic_uv/impl/align_uv_cursor_impl.py b/uv_magic_uv/impl/align_uv_cursor_impl.py
deleted file mode 100644
index 3056e87b0082a81391d07c9945ecf42d6ea2b2d2..0000000000000000000000000000000000000000
--- a/uv_magic_uv/impl/align_uv_cursor_impl.py
+++ /dev/null
@@ -1,239 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-__author__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-from mathutils import Vector
-import bmesh
-
-from .. import common
-
-
-def _is_valid_context(context):
-    # 'IMAGE_EDITOR' and 'VIEW_3D' space is allowed to execute.
-    # If 'View_3D' space is not allowed, you can't find option in Tool-Shelf
-    # after the execution
-    for space in context.area.spaces:
-        if (space.type == 'IMAGE_EDITOR') or (space.type == 'VIEW_3D'):
-            break
-    else:
-        return False
-
-    return True
-
-
-class AlignUVCursorLegacyImpl:
-    @classmethod
-    def poll(cls, context):
-        # we can not get area/space/region from console
-        if common.is_console_mode():
-            return True
-        return _is_valid_context(context)
-
-    def execute(self, ops_obj, context):
-        area, _, space = common.get_space_legacy('IMAGE_EDITOR', 'WINDOW',
-                                                 'IMAGE_EDITOR')
-        bd_size = common.get_uvimg_editor_board_size(area)
-
-        if ops_obj.base == 'UV':
-            obj = context.active_object
-            bm = bmesh.from_edit_mesh(obj.data)
-            if not bm.loops.layers.uv:
-                return None
-            uv_layer = bm.loops.layers.uv.verify()
-
-            max_ = Vector((-10000000.0, -10000000.0))
-            min_ = Vector((10000000.0, 10000000.0))
-            for f in bm.faces:
-                if not f.select:
-                    continue
-                for l in f.loops:
-                    uv = l[uv_layer].uv
-                    max_.x = max(max_.x, uv.x)
-                    max_.y = max(max_.y, uv.y)
-                    min_.x = min(min_.x, uv.x)
-                    min_.y = min(min_.y, uv.y)
-            center = Vector(((max_.x + min_.x) / 2.0, (max_.y + min_.y) / 2.0))
-
-        elif ops_obj.base == 'UV_SEL':
-            obj = context.active_object
-            bm = bmesh.from_edit_mesh(obj.data)
-            if not bm.loops.layers.uv:
-                return None
-            uv_layer = bm.loops.layers.uv.verify()
-
-            max_ = Vector((-10000000.0, -10000000.0))
-            min_ = Vector((10000000.0, 10000000.0))
-            for f in bm.faces:
-                if not f.select:
-                    continue
-                for l in f.loops:
-                    if not l[uv_layer].select:
-                        continue
-                    uv = l[uv_layer].uv
-                    max_.x = max(max_.x, uv.x)
-                    max_.y = max(max_.y, uv.y)
-                    min_.x = min(min_.x, uv.x)
-                    min_.y = min(min_.y, uv.y)
-            center = Vector(((max_.x + min_.x) / 2.0, (max_.y + min_.y) / 2.0))
-
-        elif ops_obj.base == 'TEXTURE':
-            min_ = Vector((0.0, 0.0))
-            max_ = Vector((1.0, 1.0))
-            center = Vector((0.5, 0.5))
-        else:
-            ops_obj.report({'ERROR'}, "Unknown Operation")
-            return {'CANCELLED'}
-
-        if ops_obj.position == 'CENTER':
-            cx = center.x * bd_size[0]
-            cy = center.y * bd_size[1]
-        elif ops_obj.position == 'LEFT_TOP':
-            cx = min_.x * bd_size[0]
-            cy = max_.y * bd_size[1]
-        elif ops_obj.position == 'LEFT_MIDDLE':
-            cx = min_.x * bd_size[0]
-            cy = center.y * bd_size[1]
-        elif ops_obj.position == 'LEFT_BOTTOM':
-            cx = min_.x * bd_size[0]
-            cy = min_.y * bd_size[1]
-        elif ops_obj.position == 'MIDDLE_TOP':
-            cx = center.x * bd_size[0]
-            cy = max_.y * bd_size[1]
-        elif ops_obj.position == 'MIDDLE_BOTTOM':
-            cx = center.x * bd_size[0]
-            cy = min_.y * bd_size[1]
-        elif ops_obj.position == 'RIGHT_TOP':
-            cx = max_.x * bd_size[0]
-            cy = max_.y * bd_size[1]
-        elif ops_obj.position == 'RIGHT_MIDDLE':
-            cx = max_.x * bd_size[0]
-            cy = center.y * bd_size[1]
-        elif ops_obj.position == 'RIGHT_BOTTOM':
-            cx = max_.x * bd_size[0]
-            cy = min_.y * bd_size[1]
-        else:
-            ops_obj.report({'ERROR'}, "Unknown Operation")
-            return {'CANCELLED'}
-
-        space.cursor_location = Vector((cx, cy))
-
-        return {'FINISHED'}
-
-
-class AlignUVCursorImpl:
-    @classmethod
-    def poll(cls, context):
-        # we can not get area/space/region from console
-        if common.is_console_mode():
-            return True
-        return _is_valid_context(context)
-
-    def execute(self, ops_obj, context):
-        _, _, space = common.get_space_legacy('IMAGE_EDITOR', 'WINDOW',
-                                              'IMAGE_EDITOR')
-
-        if ops_obj.base == 'UV':
-            obj = context.active_object
-            bm = bmesh.from_edit_mesh(obj.data)
-            if not bm.loops.layers.uv:
-                return None
-            uv_layer = bm.loops.layers.uv.verify()
-
-            max_ = Vector((-10000000.0, -10000000.0))
-            min_ = Vector((10000000.0, 10000000.0))
-            for f in bm.faces:
-                if not f.select:
-                    continue
-                for l in f.loops:
-                    uv = l[uv_layer].uv
-                    max_.x = max(max_.x, uv.x)
-                    max_.y = max(max_.y, uv.y)
-                    min_.x = min(min_.x, uv.x)
-                    min_.y = min(min_.y, uv.y)
-            center = Vector(((max_.x + min_.x) / 2.0, (max_.y + min_.y) / 2.0))
-
-        elif ops_obj.base == 'UV_SEL':
-            obj = context.active_object
-            bm = bmesh.from_edit_mesh(obj.data)
-            if not bm.loops.layers.uv:
-                return None
-            uv_layer = bm.loops.layers.uv.verify()
-
-            max_ = Vector((-10000000.0, -10000000.0))
-            min_ = Vector((10000000.0, 10000000.0))
-            for f in bm.faces:
-                if not f.select:
-                    continue
-                for l in f.loops:
-                    if not l[uv_layer].select:
-                        continue
-                    uv = l[uv_layer].uv
-                    max_.x = max(max_.x, uv.x)
-                    max_.y = max(max_.y, uv.y)
-                    min_.x = min(min_.x, uv.x)
-                    min_.y = min(min_.y, uv.y)
-            center = Vector(((max_.x + min_.x) / 2.0, (max_.y + min_.y) / 2.0))
-
-        elif ops_obj.base == 'TEXTURE':
-            min_ = Vector((0.0, 0.0))
-            max_ = Vector((1.0, 1.0))
-            center = Vector((0.5, 0.5))
-        else:
-            ops_obj.report({'ERROR'}, "Unknown Operation")
-            return {'CANCELLED'}
-
-        if ops_obj.position == 'CENTER':
-            cx = center.x
-            cy = center.y
-        elif ops_obj.position == 'LEFT_TOP':
-            cx = min_.x
-            cy = max_.y
-        elif ops_obj.position == 'LEFT_MIDDLE':
-            cx = min_.x
-            cy = center.y
-        elif ops_obj.position == 'LEFT_BOTTOM':
-            cx = min_.x
-            cy = min_.y
-        elif ops_obj.position == 'MIDDLE_TOP':
-            cx = center.x
-            cy = max_.y
-        elif ops_obj.position == 'MIDDLE_BOTTOM':
-            cx = center.x
-            cy = min_.y
-        elif ops_obj.position == 'RIGHT_TOP':
-            cx = max_.x
-            cy = max_.y
-        elif ops_obj.position == 'RIGHT_MIDDLE':
-            cx = max_.x
-            cy = center.y
-        elif ops_obj.position == 'RIGHT_BOTTOM':
-            cx = max_.x
-            cy = min_.y
-        else:
-            ops_obj.report({'ERROR'}, "Unknown Operation")
-            return {'CANCELLED'}
-
-        space.cursor_location = Vector((cx, cy))
-
-        return {'FINISHED'}
diff --git a/uv_magic_uv/impl/align_uv_impl.py b/uv_magic_uv/impl/align_uv_impl.py
deleted file mode 100644
index b8d7d33dd8d74b290703a23a273be0f9e52e2260..0000000000000000000000000000000000000000
--- a/uv_magic_uv/impl/align_uv_impl.py
+++ /dev/null
@@ -1,820 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-__author__ = "imdjs, Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import math
-from math import atan2, tan, sin, cos
-
-import bmesh
-from mathutils import Vector
-
-from .. import common
-
-
-def _is_valid_context(context):
-    obj = context.object
-
-    # only edit mode is allowed to execute
-    if obj is None:
-        return False
-    if obj.type != 'MESH':
-        return False
-    if context.object.mode != 'EDIT':
-        return False
-
-    # 'IMAGE_EDITOR' and 'VIEW_3D' space is allowed to execute.
-    # If 'View_3D' space is not allowed, you can't find option in Tool-Shelf
-    # after the execution
-    for space in context.area.spaces:
-        if (space.type == 'IMAGE_EDITOR') or (space.type == 'VIEW_3D'):
-            break
-    else:
-        return False
-
-    return True
-
-
-# get sum vertex length of loop sequences
-def _get_loop_vert_len(loops):
-    length = 0
-    for l1, l2 in zip(loops[:-1], loops[1:]):
-        diff = l2.vert.co - l1.vert.co
-        length = length + abs(diff.length)
-
-    return length
-
-
-# get sum uv length of loop sequences
-def _get_loop_uv_len(loops, uv_layer):
-    length = 0
-    for l1, l2 in zip(loops[:-1], loops[1:]):
-        diff = l2[uv_layer].uv - l1[uv_layer].uv
-        length = length + abs(diff.length)
-
-    return length
-
-
-# get center/radius of circle by 3 vertices
-def _get_circle(v):
-    alpha = atan2((v[0].y - v[1].y), (v[0].x - v[1].x)) + math.pi / 2
-    beta = atan2((v[1].y - v[2].y), (v[1].x - v[2].x)) + math.pi / 2
-    ex = (v[0].x + v[1].x) / 2.0
-    ey = (v[0].y + v[1].y) / 2.0
-    fx = (v[1].x + v[2].x) / 2.0
-    fy = (v[1].y + v[2].y) / 2.0
-    cx = (ey - fy - ex * tan(alpha) + fx * tan(beta)) / \
-         (tan(beta) - tan(alpha))
-    cy = ey - (ex - cx) * tan(alpha)
-    center = Vector((cx, cy))
-
-    r = v[0] - center
-    radian = r.length
-
-    return center, radian
-
-
-# get position on circle with same arc length
-def _calc_v_on_circle(v, center, radius):
-    base = v[0]
-    theta = atan2(base.y - center.y, base.x - center.x)
-    new_v = []
-    for i in range(len(v)):
-        angle = theta + i * 2 * math.pi / len(v)
-        new_v.append(Vector((center.x + radius * sin(angle),
-                             center.y + radius * cos(angle))))
-
-    return new_v
-
-
-class CircleImpl:
-    @classmethod
-    def poll(cls, context):
-        # we can not get area/space/region from console
-        if common.is_console_mode():
-            return True
-        return _is_valid_context(context)
-
-    def execute(self, ops_obj, context):
-        obj = context.active_object
-        bm = bmesh.from_edit_mesh(obj.data)
-        if common.check_version(2, 73, 0) >= 0:
-            bm.faces.ensure_lookup_table()
-        uv_layer = bm.loops.layers.uv.verify()
-
-        # loop_seqs[horizontal][vertical][loop]
-        loop_seqs, error = common.get_loop_sequences(bm, uv_layer, True)
-        if not loop_seqs:
-            ops_obj.report({'WARNING'}, error)
-            return {'CANCELLED'}
-
-        # get circle and new UVs
-        uvs = [hseq[0][0][uv_layer].uv.copy() for hseq in loop_seqs]
-        c, r = _get_circle(uvs[0:3])
-        new_uvs = _calc_v_on_circle(uvs, c, r)
-
-        # check center UV of circle
-        center = loop_seqs[0][-1][0].vert
-        for hseq in loop_seqs[1:]:
-            if len(hseq[-1]) != 1:
-                ops_obj.report({'WARNING'}, "Last face must be triangle")
-                return {'CANCELLED'}
-            if hseq[-1][0].vert != center:
-                ops_obj.report({'WARNING'}, "Center must be identical")
-                return {'CANCELLED'}
-
-        # align to circle
-        if ops_obj.transmission:
-            for hidx, hseq in enumerate(loop_seqs):
-                for vidx, pair in enumerate(hseq):
-                    all_ = int((len(hseq) + 1) / 2)
-                    r = (all_ - int((vidx + 1) / 2)) / all_
-                    pair[0][uv_layer].uv = c + (new_uvs[hidx] - c) * r
-                    if ops_obj.select:
-                        pair[0][uv_layer].select = True
-
-                    if len(pair) < 2:
-                        continue
-                    # for quad polygon
-                    next_hidx = (hidx + 1) % len(loop_seqs)
-                    pair[1][uv_layer].uv = c + ((new_uvs[next_hidx]) - c) * r
-                    if ops_obj.select:
-                        pair[1][uv_layer].select = True
-        else:
-            for hidx, hseq in enumerate(loop_seqs):
-                pair = hseq[0]
-                pair[0][uv_layer].uv = new_uvs[hidx]
-                pair[1][uv_layer].uv = new_uvs[(hidx + 1) % len(loop_seqs)]
-                if ops_obj.select:
-                    pair[0][uv_layer].select = True
-                    pair[1][uv_layer].select = True
-
-        bmesh.update_edit_mesh(obj.data)
-
-        return {'FINISHED'}
-
-
-# get accumulate vertex lengths of loop sequences
-def _get_loop_vert_accum_len(loops):
-    accum_lengths = [0.0]
-    length = 0
-    for l1, l2 in zip(loops[:-1], loops[1:]):
-        diff = l2.vert.co - l1.vert.co
-        length = length + abs(diff.length)
-        accum_lengths.extend([length])
-
-    return accum_lengths
-
-
-# get sum uv length of loop sequences
-def _get_loop_uv_accum_len(loops, uv_layer):
-    accum_lengths = [0.0]
-    length = 0
-    for l1, l2 in zip(loops[:-1], loops[1:]):
-        diff = l2[uv_layer].uv - l1[uv_layer].uv
-        length = length + abs(diff.length)
-        accum_lengths.extend([length])
-
-    return accum_lengths
-
-
-# get horizontal differential of UV influenced by mesh vertex
-def _get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, pidx, infl):
-    common.debug_print(
-        "loop_seqs[hidx={0}][vidx={1}][pidx={2}]".format(hidx, vidx, pidx))
-
-    base_uv = loop_seqs[0][vidx][0][uv_layer].uv.copy()
-
-    # calculate original length
-    hloops = []
-    for s in loop_seqs:
-        hloops.extend([s[vidx][0], s[vidx][1]])
-    total_vlen = _get_loop_vert_len(hloops)
-    accum_vlens = _get_loop_vert_accum_len(hloops)
-    total_uvlen = _get_loop_uv_len(hloops, uv_layer)
-    accum_uvlens = _get_loop_uv_accum_len(hloops, uv_layer)
-    orig_uvs = [l[uv_layer].uv.copy() for l in hloops]
-
-    # calculate target length
-    tgt_noinfl = total_uvlen * (hidx + pidx) / len(loop_seqs)
-    tgt_infl = total_uvlen * accum_vlens[hidx * 2 + pidx] / total_vlen
-    target_length = tgt_noinfl * (1 - infl) + tgt_infl * infl
-    common.debug_print(target_length)
-    common.debug_print(accum_uvlens)
-
-    # calculate target UV
-    for i in range(len(accum_uvlens[:-1])):
-        # get line segment which UV will be placed
-        if ((accum_uvlens[i] <= target_length) and
-                (accum_uvlens[i + 1] > target_length)):
-            tgt_seg_len = target_length - accum_uvlens[i]
-            seg_len = accum_uvlens[i + 1] - accum_uvlens[i]
-            uv1 = orig_uvs[i]
-            uv2 = orig_uvs[i + 1]
-            target_uv = (uv1 - base_uv) + (uv2 - uv1) * tgt_seg_len / seg_len
-            break
-        elif i == (len(accum_uvlens[:-1]) - 1):
-            if abs(accum_uvlens[i + 1] - target_length) > 0.000001:
-                raise Exception(
-                    "Internal Error: horizontal_target_length={}"
-                    " is not equal to {}"
-                    .format(target_length, accum_uvlens[-1]))
-            tgt_seg_len = target_length - accum_uvlens[i]
-            seg_len = accum_uvlens[i + 1] - accum_uvlens[i]
-            uv1 = orig_uvs[i]
-            uv2 = orig_uvs[i + 1]
-            target_uv = (uv1 - base_uv) + (uv2 - uv1) * tgt_seg_len / seg_len
-            break
-    else:
-        raise Exception("Internal Error: horizontal_target_length={}"
-                        " is not in range {} to {}"
-                        .format(target_length, accum_uvlens[0],
-                                accum_uvlens[-1]))
-
-    return target_uv
-
-
-# --------------------- LOOP STRUCTURE ----------------------
-#
-#  loops[hidx][vidx][pidx]
-#     hidx: horizontal index
-#     vidx: vertical index
-#     pidx: pair index
-#
-#              <----- horizontal ----->
-#
-#              (hidx, vidx, pidx) = (0, 3, 0)
-#              |      (hidx, vidx, pidx) = (1, 3, 0)
-#              v      v
-#          ^   o --- oo --- o
-#          |   |     ||     |
-# vertical |   o --- oo --- o  <- (hidx, vidx, pidx)
-#          |   o --- oo --- o          = (1, 2, 1)
-#          |   |     ||     |
-#          v   o --- oo --- o
-#              ^            ^
-#              |            (hidx, vidx, pidx) = (1, 0, 1)
-#              (hidx, vidx, pidx) = (0, 0, 0)
-#
-# -----------------------------------------------------------
-
-
-# get vertical differential of UV influenced by mesh vertex
-def _get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, pidx, infl):
-    common.debug_print(
-        "loop_seqs[hidx={0}][vidx={1}][pidx={2}]".format(hidx, vidx, pidx))
-
-    base_uv = loop_seqs[hidx][0][pidx][uv_layer].uv.copy()
-
-    # calculate original length
-    vloops = []
-    for s in loop_seqs[hidx]:
-        vloops.append(s[pidx])
-    total_vlen = _get_loop_vert_len(vloops)
-    accum_vlens = _get_loop_vert_accum_len(vloops)
-    total_uvlen = _get_loop_uv_len(vloops, uv_layer)
-    accum_uvlens = _get_loop_uv_accum_len(vloops, uv_layer)
-    orig_uvs = [l[uv_layer].uv.copy() for l in vloops]
-
-    # calculate target length
-    tgt_noinfl = total_uvlen * int((vidx + 1) / 2) * 2 / len(loop_seqs[hidx])
-    tgt_infl = total_uvlen * accum_vlens[vidx] / total_vlen
-    target_length = tgt_noinfl * (1 - infl) + tgt_infl * infl
-    common.debug_print(target_length)
-    common.debug_print(accum_uvlens)
-    print("#### {}".format(tgt_noinfl))
-    print("#### {}".format(tgt_infl))
-
-    # calculate target UV
-    for i in range(len(accum_uvlens[:-1])):
-        # get line segment which UV will be placed
-        if ((accum_uvlens[i] <= target_length) and
-                (accum_uvlens[i + 1] > target_length)):
-            tgt_seg_len = target_length - accum_uvlens[i]
-            seg_len = accum_uvlens[i + 1] - accum_uvlens[i]
-            uv1 = orig_uvs[i]
-            uv2 = orig_uvs[i + 1]
-            target_uv = (uv1 - base_uv) + (uv2 - uv1) * tgt_seg_len / seg_len
-            break
-        elif i == (len(accum_uvlens[:-1]) - 1):
-            if abs(accum_uvlens[i + 1] - target_length) > 0.000001:
-                raise Exception("Internal Error: horizontal_target_length={}"
-                                " is not equal to {}"
-                                .format(target_length, accum_uvlens[-1]))
-            tgt_seg_len = target_length - accum_uvlens[i]
-            seg_len = accum_uvlens[i + 1] - accum_uvlens[i]
-            uv1 = orig_uvs[i]
-            uv2 = orig_uvs[i + 1]
-            target_uv = (uv1 - base_uv) + (uv2 - uv1) * tgt_seg_len / seg_len
-            break
-    else:
-        raise Exception("Internal Error: horizontal_target_length={}"
-                        " is not in range {} to {}"
-                        .format(target_length, accum_uvlens[0],
-                                accum_uvlens[-1]))
-
-    return target_uv
-
-
-# get horizontal differential of UV no influenced
-def _get_hdiff_uv(uv_layer, loop_seqs, hidx):
-    base_uv = loop_seqs[0][0][0][uv_layer].uv.copy()
-    h_uv = loop_seqs[-1][0][1][uv_layer].uv.copy() - base_uv
-
-    return hidx * h_uv / len(loop_seqs)
-
-
-# get vertical differential of UV no influenced
-def _get_vdiff_uv(uv_layer, loop_seqs, vidx, hidx):
-    base_uv = loop_seqs[0][0][0][uv_layer].uv.copy()
-    v_uv = loop_seqs[0][-1][0][uv_layer].uv.copy() - base_uv
-
-    hseq = loop_seqs[hidx]
-    return int((vidx + 1) / 2) * v_uv / (len(hseq) / 2)
-
-
-class StraightenImpl:
-    @classmethod
-    def poll(cls, context):
-        # we can not get area/space/region from console
-        if common.is_console_mode():
-            return True
-        return _is_valid_context(context)
-
-    # selected and paralleled UV loop sequence will be aligned
-    def __align_w_transmission(self, ops_obj, loop_seqs, uv_layer):
-        base_uv = loop_seqs[0][0][0][uv_layer].uv.copy()
-
-        # calculate diff UVs
-        diff_uvs = []
-        # hseq[vertical][loop]
-        for hidx, hseq in enumerate(loop_seqs):
-            # pair[loop]
-            diffs = []
-            for vidx in range(0, len(hseq), 2):
-                if ops_obj.horizontal:
-                    hdiff_uvs = [
-                        _get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 0,
-                                            ops_obj.mesh_infl),
-                        _get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 1,
-                                            ops_obj.mesh_infl),
-                        _get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
-                                            hidx, 0, ops_obj.mesh_infl),
-                        _get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
-                                            hidx, 1, ops_obj.mesh_infl),
-                    ]
-                else:
-                    hdiff_uvs = [
-                        _get_hdiff_uv(uv_layer, loop_seqs, hidx),
-                        _get_hdiff_uv(uv_layer, loop_seqs, hidx + 1),
-                        _get_hdiff_uv(uv_layer, loop_seqs, hidx),
-                        _get_hdiff_uv(uv_layer, loop_seqs, hidx + 1)
-                    ]
-                if ops_obj.vertical:
-                    vdiff_uvs = [
-                        _get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 0,
-                                            ops_obj.mesh_infl),
-                        _get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 1,
-                                            ops_obj.mesh_infl),
-                        _get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
-                                            hidx, 0, ops_obj.mesh_infl),
-                        _get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
-                                            hidx, 1, ops_obj.mesh_infl),
-                    ]
-                else:
-                    vdiff_uvs = [
-                        _get_vdiff_uv(uv_layer, loop_seqs, vidx, hidx),
-                        _get_vdiff_uv(uv_layer, loop_seqs, vidx, hidx),
-                        _get_vdiff_uv(uv_layer, loop_seqs, vidx + 1, hidx),
-                        _get_vdiff_uv(uv_layer, loop_seqs, vidx + 1, hidx)
-                    ]
-                diffs.append([hdiff_uvs, vdiff_uvs])
-            diff_uvs.append(diffs)
-
-        # update UV
-        for hseq, diffs in zip(loop_seqs, diff_uvs):
-            for vidx in range(0, len(hseq), 2):
-                loops = [
-                    hseq[vidx][0], hseq[vidx][1],
-                    hseq[vidx + 1][0], hseq[vidx + 1][1]
-                ]
-                for l, hdiff, vdiff in zip(loops, diffs[int(vidx / 2)][0],
-                                           diffs[int(vidx / 2)][1]):
-                    l[uv_layer].uv = base_uv + hdiff + vdiff
-                    if ops_obj.select:
-                        l[uv_layer].select = True
-
-    # only selected UV loop sequence will be aligned
-    def __align_wo_transmission(self, ops_obj, loop_seqs, uv_layer):
-        base_uv = loop_seqs[0][0][0][uv_layer].uv.copy()
-
-        h_uv = loop_seqs[-1][0][1][uv_layer].uv.copy() - base_uv
-        for hidx, hseq in enumerate(loop_seqs):
-            # only selected loop pair is targeted
-            pair = hseq[0]
-            hdiff_uv_0 = hidx * h_uv / len(loop_seqs)
-            hdiff_uv_1 = (hidx + 1) * h_uv / len(loop_seqs)
-            pair[0][uv_layer].uv = base_uv + hdiff_uv_0
-            pair[1][uv_layer].uv = base_uv + hdiff_uv_1
-            if ops_obj.select:
-                pair[0][uv_layer].select = True
-                pair[1][uv_layer].select = True
-
-    def __align(self, ops_obj, loop_seqs, uv_layer):
-        if ops_obj.transmission:
-            self.__align_w_transmission(ops_obj, loop_seqs, uv_layer)
-        else:
-            self.__align_wo_transmission(ops_obj, loop_seqs, uv_layer)
-
-    def execute(self, ops_obj, context):
-        obj = context.active_object
-        bm = bmesh.from_edit_mesh(obj.data)
-        if common.check_version(2, 73, 0) >= 0:
-            bm.faces.ensure_lookup_table()
-        uv_layer = bm.loops.layers.uv.verify()
-
-        # loop_seqs[horizontal][vertical][loop]
-        loop_seqs, error = common.get_loop_sequences(bm, uv_layer)
-        if not loop_seqs:
-            ops_obj.report({'WARNING'}, error)
-            return {'CANCELLED'}
-
-        # align
-        self.__align(ops_obj, loop_seqs, uv_layer)
-
-        bmesh.update_edit_mesh(obj.data)
-
-        return {'FINISHED'}
-
-
-class AxisImpl:
-    @classmethod
-    def poll(cls, context):
-        # we can not get area/space/region from console
-        if common.is_console_mode():
-            return True
-        return _is_valid_context(context)
-
-    # get min/max of UV
-    def __get_uv_max_min(self, _, loop_seqs, uv_layer):
-        uv_max = Vector((-1000000.0, -1000000.0))
-        uv_min = Vector((1000000.0, 1000000.0))
-        for hseq in loop_seqs:
-            for l in hseq[0]:
-                uv = l[uv_layer].uv
-                uv_max.x = max(uv.x, uv_max.x)
-                uv_max.y = max(uv.y, uv_max.y)
-                uv_min.x = min(uv.x, uv_min.x)
-                uv_min.y = min(uv.y, uv_min.y)
-
-        return uv_max, uv_min
-
-    # get UV differentiation when UVs are aligned to X-axis
-    def __get_x_axis_align_diff_uvs(self, ops_obj, loop_seqs, uv_layer, uv_min,
-                                    width, height):
-        diff_uvs = []
-        for hidx, hseq in enumerate(loop_seqs):
-            pair = hseq[0]
-            luv0 = pair[0][uv_layer]
-            luv1 = pair[1][uv_layer]
-            target_uv0 = Vector((0.0, 0.0))
-            target_uv1 = Vector((0.0, 0.0))
-            if ops_obj.location == 'RIGHT_BOTTOM':
-                target_uv0.y = target_uv1.y = uv_min.y
-            elif ops_obj.location == 'MIDDLE':
-                target_uv0.y = target_uv1.y = uv_min.y + height * 0.5
-            elif ops_obj.location == 'LEFT_TOP':
-                target_uv0.y = target_uv1.y = uv_min.y + height
-            if luv0.uv.x < luv1.uv.x:
-                target_uv0.x = uv_min.x + hidx * width / len(loop_seqs)
-                target_uv1.x = uv_min.x + (hidx + 1) * width / len(loop_seqs)
-            else:
-                target_uv0.x = uv_min.x + (hidx + 1) * width / len(loop_seqs)
-                target_uv1.x = uv_min.x + hidx * width / len(loop_seqs)
-            diff_uvs.append([target_uv0 - luv0.uv, target_uv1 - luv1.uv])
-
-        return diff_uvs
-
-    # get UV differentiation when UVs are aligned to Y-axis
-    def __get_y_axis_align_diff_uvs(self, ops_obj, loop_seqs, uv_layer, uv_min,
-                                    width, height):
-        diff_uvs = []
-        for hidx, hseq in enumerate(loop_seqs):
-            pair = hseq[0]
-            luv0 = pair[0][uv_layer]
-            luv1 = pair[1][uv_layer]
-            target_uv0 = Vector((0.0, 0.0))
-            target_uv1 = Vector((0.0, 0.0))
-            if ops_obj.location == 'RIGHT_BOTTOM':
-                target_uv0.x = target_uv1.x = uv_min.x + width
-            elif ops_obj.location == 'MIDDLE':
-                target_uv0.x = target_uv1.x = uv_min.x + width * 0.5
-            elif ops_obj.location == 'LEFT_TOP':
-                target_uv0.x = target_uv1.x = uv_min.x
-            if luv0.uv.y < luv1.uv.y:
-                target_uv0.y = uv_min.y + hidx * height / len(loop_seqs)
-                target_uv1.y = uv_min.y + (hidx + 1) * height / len(loop_seqs)
-            else:
-                target_uv0.y = uv_min.y + (hidx + 1) * height / len(loop_seqs)
-                target_uv1.y = uv_min.y + hidx * height / len(loop_seqs)
-            diff_uvs.append([target_uv0 - luv0.uv, target_uv1 - luv1.uv])
-
-        return diff_uvs
-
-    # only selected UV loop sequence will be aligned along to X-axis
-    def __align_to_x_axis_wo_transmission(self, ops_obj, loop_seqs, uv_layer,
-                                          uv_min, width, height):
-        # reverse if the UV coordinate is not sorted by position
-        need_revese = loop_seqs[0][0][0][uv_layer].uv.x > \
-            loop_seqs[-1][0][0][uv_layer].uv.x
-        if need_revese:
-            loop_seqs.reverse()
-            for hidx, hseq in enumerate(loop_seqs):
-                for vidx, pair in enumerate(hseq):
-                    tmp = loop_seqs[hidx][vidx][0]
-                    loop_seqs[hidx][vidx][0] = loop_seqs[hidx][vidx][1]
-                    loop_seqs[hidx][vidx][1] = tmp
-
-        # get UV differential
-        diff_uvs = self.__get_x_axis_align_diff_uvs(ops_obj, loop_seqs,
-                                                    uv_layer, uv_min,
-                                                    width, height)
-
-        # update UV
-        for hseq, duv in zip(loop_seqs, diff_uvs):
-            pair = hseq[0]
-            luv0 = pair[0][uv_layer]
-            luv1 = pair[1][uv_layer]
-            luv0.uv = luv0.uv + duv[0]
-            luv1.uv = luv1.uv + duv[1]
-
-    # only selected UV loop sequence will be aligned along to Y-axis
-    def __align_to_y_axis_wo_transmission(self, ops_obj, loop_seqs, uv_layer,
-                                          uv_min, width, height):
-        # reverse if the UV coordinate is not sorted by position
-        need_revese = loop_seqs[0][0][0][uv_layer].uv.y > \
-            loop_seqs[-1][0][0][uv_layer].uv.y
-        if need_revese:
-            loop_seqs.reverse()
-            for hidx, hseq in enumerate(loop_seqs):
-                for vidx, pair in enumerate(hseq):
-                    tmp = loop_seqs[hidx][vidx][0]
-                    loop_seqs[hidx][vidx][0] = loop_seqs[hidx][vidx][1]
-                    loop_seqs[hidx][vidx][1] = tmp
-
-        # get UV differential
-        diff_uvs = self.__get_y_axis_align_diff_uvs(ops_obj, loop_seqs,
-                                                    uv_layer, uv_min,
-                                                    width, height)
-
-        # update UV
-        for hseq, duv in zip(loop_seqs, diff_uvs):
-            pair = hseq[0]
-            luv0 = pair[0][uv_layer]
-            luv1 = pair[1][uv_layer]
-            luv0.uv = luv0.uv + duv[0]
-            luv1.uv = luv1.uv + duv[1]
-
-    # selected and paralleled UV loop sequence will be aligned along to X-axis
-    def __align_to_x_axis_w_transmission(self, ops_obj, loop_seqs, uv_layer,
-                                         uv_min, width, height):
-        # reverse if the UV coordinate is not sorted by position
-        need_revese = loop_seqs[0][0][0][uv_layer].uv.x > \
-            loop_seqs[-1][0][0][uv_layer].uv.x
-        if need_revese:
-            loop_seqs.reverse()
-            for hidx, hseq in enumerate(loop_seqs):
-                for vidx in range(len(hseq)):
-                    tmp = loop_seqs[hidx][vidx][0]
-                    loop_seqs[hidx][vidx][0] = loop_seqs[hidx][vidx][1]
-                    loop_seqs[hidx][vidx][1] = tmp
-
-        # get offset UVs when the UVs are aligned to X-axis
-        align_diff_uvs = self.__get_x_axis_align_diff_uvs(ops_obj, loop_seqs,
-                                                          uv_layer, uv_min,
-                                                          width, height)
-        base_uv = loop_seqs[0][0][0][uv_layer].uv.copy()
-        offset_uvs = []
-        for hseq, aduv in zip(loop_seqs, align_diff_uvs):
-            luv0 = hseq[0][0][uv_layer]
-            luv1 = hseq[0][1][uv_layer]
-            offset_uvs.append([luv0.uv + aduv[0] - base_uv,
-                               luv1.uv + aduv[1] - base_uv])
-
-        # get UV differential
-        diff_uvs = []
-        # hseq[vertical][loop]
-        for hidx, hseq in enumerate(loop_seqs):
-            # pair[loop]
-            diffs = []
-            for vidx in range(0, len(hseq), 2):
-                if ops_obj.horizontal:
-                    hdiff_uvs = [
-                        _get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 0,
-                                            ops_obj.mesh_infl),
-                        _get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 1,
-                                            ops_obj.mesh_infl),
-                        _get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
-                                            hidx, 0, ops_obj.mesh_infl),
-                        _get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
-                                            hidx, 1, ops_obj.mesh_infl),
-                    ]
-                    hdiff_uvs[0].y = hdiff_uvs[0].y + offset_uvs[hidx][0].y
-                    hdiff_uvs[1].y = hdiff_uvs[1].y + offset_uvs[hidx][1].y
-                    hdiff_uvs[2].y = hdiff_uvs[2].y + offset_uvs[hidx][0].y
-                    hdiff_uvs[3].y = hdiff_uvs[3].y + offset_uvs[hidx][1].y
-                else:
-                    hdiff_uvs = [
-                        offset_uvs[hidx][0],
-                        offset_uvs[hidx][1],
-                        offset_uvs[hidx][0],
-                        offset_uvs[hidx][1],
-                    ]
-                if ops_obj.vertical:
-                    vdiff_uvs = [
-                        _get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 0,
-                                            ops_obj.mesh_infl),
-                        _get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 1,
-                                            ops_obj.mesh_infl),
-                        _get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
-                                            hidx, 0, ops_obj.mesh_infl),
-                        _get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
-                                            hidx, 1, ops_obj.mesh_infl),
-                    ]
-                else:
-                    vdiff_uvs = [
-                        _get_vdiff_uv(uv_layer, loop_seqs, vidx, hidx),
-                        _get_vdiff_uv(uv_layer, loop_seqs, vidx, hidx),
-                        _get_vdiff_uv(uv_layer, loop_seqs, vidx + 1, hidx),
-                        _get_vdiff_uv(uv_layer, loop_seqs, vidx + 1, hidx)
-                    ]
-                diffs.append([hdiff_uvs, vdiff_uvs])
-            diff_uvs.append(diffs)
-
-        # update UV
-        for hseq, diffs in zip(loop_seqs, diff_uvs):
-            for vidx in range(0, len(hseq), 2):
-                loops = [
-                    hseq[vidx][0], hseq[vidx][1],
-                    hseq[vidx + 1][0], hseq[vidx + 1][1]
-                ]
-                for l, hdiff, vdiff in zip(loops, diffs[int(vidx / 2)][0],
-                                           diffs[int(vidx / 2)][1]):
-                    l[uv_layer].uv = base_uv + hdiff + vdiff
-                    if ops_obj.select:
-                        l[uv_layer].select = True
-
-    # selected and paralleled UV loop sequence will be aligned along to Y-axis
-    def __align_to_y_axis_w_transmission(self, ops_obj, loop_seqs, uv_layer,
-                                         uv_min, width, height):
-        # reverse if the UV coordinate is not sorted by position
-        need_revese = loop_seqs[0][0][0][uv_layer].uv.y > \
-            loop_seqs[-1][0][-1][uv_layer].uv.y
-        if need_revese:
-            loop_seqs.reverse()
-            for hidx, hseq in enumerate(loop_seqs):
-                for vidx in range(len(hseq)):
-                    tmp = loop_seqs[hidx][vidx][0]
-                    loop_seqs[hidx][vidx][0] = loop_seqs[hidx][vidx][1]
-                    loop_seqs[hidx][vidx][1] = tmp
-
-        # get offset UVs when the UVs are aligned to Y-axis
-        align_diff_uvs = self.__get_y_axis_align_diff_uvs(ops_obj, loop_seqs,
-                                                          uv_layer, uv_min,
-                                                          width, height)
-        base_uv = loop_seqs[0][0][0][uv_layer].uv.copy()
-        offset_uvs = []
-        for hseq, aduv in zip(loop_seqs, align_diff_uvs):
-            luv0 = hseq[0][0][uv_layer]
-            luv1 = hseq[0][1][uv_layer]
-            offset_uvs.append([luv0.uv + aduv[0] - base_uv,
-                               luv1.uv + aduv[1] - base_uv])
-
-        # get UV differential
-        diff_uvs = []
-        # hseq[vertical][loop]
-        for hidx, hseq in enumerate(loop_seqs):
-            # pair[loop]
-            diffs = []
-            for vidx in range(0, len(hseq), 2):
-                if ops_obj.horizontal:
-                    hdiff_uvs = [
-                        _get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 0,
-                                            ops_obj.mesh_infl),
-                        _get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 1,
-                                            ops_obj.mesh_infl),
-                        _get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
-                                            hidx, 0, ops_obj.mesh_infl),
-                        _get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
-                                            hidx, 1, ops_obj.mesh_infl),
-                    ]
-                    hdiff_uvs[0].x = hdiff_uvs[0].x + offset_uvs[hidx][0].x
-                    hdiff_uvs[1].x = hdiff_uvs[1].x + offset_uvs[hidx][1].x
-                    hdiff_uvs[2].x = hdiff_uvs[2].x + offset_uvs[hidx][0].x
-                    hdiff_uvs[3].x = hdiff_uvs[3].x + offset_uvs[hidx][1].x
-                else:
-                    hdiff_uvs = [
-                        offset_uvs[hidx][0],
-                        offset_uvs[hidx][1],
-                        offset_uvs[hidx][0],
-                        offset_uvs[hidx][1],
-                    ]
-                if ops_obj.vertical:
-                    vdiff_uvs = [
-                        _get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 0,
-                                            ops_obj.mesh_infl),
-                        _get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 1,
-                                            ops_obj.mesh_infl),
-                        _get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
-                                            hidx, 0, ops_obj.mesh_infl),
-                        _get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
-                                            hidx, 1, ops_obj.mesh_infl),
-                    ]
-                else:
-                    vdiff_uvs = [
-                        _get_vdiff_uv(uv_layer, loop_seqs, vidx, hidx),
-                        _get_vdiff_uv(uv_layer, loop_seqs, vidx, hidx),
-                        _get_vdiff_uv(uv_layer, loop_seqs, vidx + 1, hidx),
-                        _get_vdiff_uv(uv_layer, loop_seqs, vidx + 1, hidx)
-                    ]
-                diffs.append([hdiff_uvs, vdiff_uvs])
-            diff_uvs.append(diffs)
-
-        # update UV
-        for hseq, diffs in zip(loop_seqs, diff_uvs):
-            for vidx in range(0, len(hseq), 2):
-                loops = [
-                    hseq[vidx][0], hseq[vidx][1],
-                    hseq[vidx + 1][0], hseq[vidx + 1][1]
-                ]
-                for l, hdiff, vdiff in zip(loops, diffs[int(vidx / 2)][0],
-                                           diffs[int(vidx / 2)][1]):
-                    l[uv_layer].uv = base_uv + hdiff + vdiff
-                    if ops_obj.select:
-                        l[uv_layer].select = True
-
-    def __align(self, ops_obj, loop_seqs, uv_layer, uv_min, width, height):
-        # align along to x-axis
-        if width > height:
-            if ops_obj.transmission:
-                self.__align_to_x_axis_w_transmission(ops_obj, loop_seqs,
-                                                      uv_layer, uv_min,
-                                                      width, height)
-            else:
-                self.__align_to_x_axis_wo_transmission(ops_obj, loop_seqs,
-                                                       uv_layer, uv_min,
-                                                       width, height)
-        # align along to y-axis
-        else:
-            if ops_obj.transmission:
-                self.__align_to_y_axis_w_transmission(ops_obj, loop_seqs,
-                                                      uv_layer, uv_min,
-                                                      width, height)
-            else:
-                self.__align_to_y_axis_wo_transmission(ops_obj, loop_seqs,
-                                                       uv_layer, uv_min,
-                                                       width, height)
-
-    def execute(self, ops_obj, context):
-        obj = context.active_object
-        bm = bmesh.from_edit_mesh(obj.data)
-        if common.check_version(2, 73, 0) >= 0:
-            bm.faces.ensure_lookup_table()
-        uv_layer = bm.loops.layers.uv.verify()
-
-        # loop_seqs[horizontal][vertical][loop]
-        loop_seqs, error = common.get_loop_sequences(bm, uv_layer)
-        if not loop_seqs:
-            ops_obj.report({'WARNING'}, error)
-            return {'CANCELLED'}
-
-        # get height and width
-        uv_max, uv_min = self.__get_uv_max_min(ops_obj, loop_seqs, uv_layer)
-        width = uv_max.x - uv_min.x
-        height = uv_max.y - uv_min.y
-
-        self.__align(ops_obj, loop_seqs, uv_layer, uv_min, width, height)
-
-        bmesh.update_edit_mesh(obj.data)
-
-        return {'FINISHED'}
diff --git a/uv_magic_uv/impl/copy_paste_uv_impl.py b/uv_magic_uv/impl/copy_paste_uv_impl.py
deleted file mode 100644
index ed44637b31b1b054010754a477e0f98bf5416662..0000000000000000000000000000000000000000
--- a/uv_magic_uv/impl/copy_paste_uv_impl.py
+++ /dev/null
@@ -1,271 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-__author__ = "imdjs, Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-
-import bmesh
-
-from .. import common
-
-
-__all__ = [
-    'is_valid_context',
-    'get_copy_uv_layers',
-    'get_paste_uv_layers',
-    'get_src_face_info',
-    'get_dest_face_info',
-    'get_select_history_src_face_info',
-    'get_select_history_dest_face_info',
-    'paste_uv',
-]
-
-
-def is_valid_context(context):
-    obj = context.object
-
-    # only edit mode is allowed to execute
-    if obj is None:
-        return False
-    if obj.type != 'MESH':
-        return False
-    if context.object.mode != 'EDIT':
-        return False
-
-    # only 'VIEW_3D' space is allowed to execute
-    for space in context.area.spaces:
-        if space.type == 'VIEW_3D':
-            break
-    else:
-        return False
-
-    return True
-
-
-def get_copy_uv_layers(ops_obj, bm, uv_map):
-    uv_layers = []
-    if uv_map == "__default":
-        if not bm.loops.layers.uv:
-            ops_obj.report(
-                {'WARNING'}, "Object must have more than one UV map")
-            return None
-        uv_layers.append(bm.loops.layers.uv.verify())
-        ops_obj.report({'INFO'}, "Copy UV coordinate")
-    elif uv_map == "__all":
-        for uv in bm.loops.layers.uv.keys():
-            uv_layers.append(bm.loops.layers.uv[uv])
-        ops_obj.report({'INFO'}, "Copy UV coordinate (UV map: ALL)")
-    else:
-        uv_layers.append(bm.loops.layers.uv[uv_map])
-        ops_obj.report(
-            {'INFO'}, "Copy UV coordinate (UV map:{})".format(uv_map))
-
-    return uv_layers
-
-
-def get_paste_uv_layers(ops_obj, obj, bm, src_info, uv_map):
-    uv_layers = []
-    if uv_map == "__default":
-        if not bm.loops.layers.uv:
-            ops_obj.report(
-                {'WARNING'}, "Object must have more than one UV map")
-            return None
-        uv_layers.append(bm.loops.layers.uv.verify())
-        ops_obj.report({'INFO'}, "Paste UV coordinate")
-    elif uv_map == "__new":
-        new_uv_map = common.create_new_uv_map(obj)
-        if not new_uv_map:
-            ops_obj.report({'WARNING'},
-                           "Reached to the maximum number of UV map")
-            return None
-        uv_layers.append(bm.loops.layers.uv[new_uv_map.name])
-        ops_obj.report(
-            {'INFO'}, "Paste UV coordinate (UV map:{})".format(new_uv_map))
-    elif uv_map == "__all":
-        for src_layer in src_info.keys():
-            if src_layer not in bm.loops.layers.uv.keys():
-                new_uv_map = common.create_new_uv_map(obj, src_layer)
-                if not new_uv_map:
-                    ops_obj.report({'WARNING'},
-                                   "Reached to the maximum number of UV map")
-                    return None
-            uv_layers.append(bm.loops.layers.uv[src_layer])
-        ops_obj.report({'INFO'}, "Paste UV coordinate (UV map: ALL)")
-    else:
-        uv_layers.append(bm.loops.layers.uv[uv_map])
-        ops_obj.report(
-            {'INFO'}, "Paste UV coordinate (UV map:{})".format(uv_map))
-
-    return uv_layers
-
-
-def get_src_face_info(ops_obj, bm, uv_layers, only_select=False):
-    src_info = {}
-    for layer in uv_layers:
-        face_info = []
-        for face in bm.faces:
-            if not only_select or face.select:
-                info = {
-                    "index": face.index,
-                    "uvs": [l[layer].uv.copy() for l in face.loops],
-                    "pin_uvs": [l[layer].pin_uv for l in face.loops],
-                    "seams": [l.edge.seam for l in face.loops],
-                }
-                face_info.append(info)
-        if not face_info:
-            ops_obj.report({'WARNING'}, "No faces are selected")
-            return None
-        src_info[layer.name] = face_info
-
-    return src_info
-
-
-def get_dest_face_info(ops_obj, bm, uv_layers, src_info, strategy,
-                       only_select=False):
-    dest_info = {}
-    for layer in uv_layers:
-        face_info = []
-        for face in bm.faces:
-            if not only_select or face.select:
-                info = {
-                    "index": face.index,
-                    "uvs": [l[layer].uv.copy() for l in face.loops],
-                }
-                face_info.append(info)
-        if not face_info:
-            ops_obj.report({'WARNING'}, "No faces are selected")
-            return None
-        key = list(src_info.keys())[0]
-        src_face_count = len(src_info[key])
-        dest_face_count = len(face_info)
-        if strategy == 'N_N' and src_face_count != dest_face_count:
-            ops_obj.report(
-                {'WARNING'},
-                "Number of selected faces is different from copied" +
-                "(src:{}, dest:{})"
-                .format(src_face_count, dest_face_count))
-            return None
-        dest_info[layer.name] = face_info
-
-    return dest_info
-
-
-def get_select_history_src_face_info(ops_obj, bm, uv_layers):
-    src_info = {}
-    for layer in uv_layers:
-        face_info = []
-        for hist in bm.select_history:
-            if isinstance(hist, bmesh.types.BMFace) and hist.select:
-                info = {
-                    "index": hist.index,
-                    "uvs": [l[layer].uv.copy() for l in hist.loops],
-                    "pin_uvs": [l[layer].pin_uv for l in hist.loops],
-                    "seams": [l.edge.seam for l in hist.loops],
-                }
-                face_info.append(info)
-        if not face_info:
-            ops_obj.report({'WARNING'}, "No faces are selected")
-            return None
-        src_info[layer.name] = face_info
-
-    return src_info
-
-
-def get_select_history_dest_face_info(ops_obj, bm, uv_layers, src_info,
-                                      strategy):
-    dest_info = {}
-    for layer in uv_layers:
-        face_info = []
-        for hist in bm.select_history:
-            if isinstance(hist, bmesh.types.BMFace) and hist.select:
-                info = {
-                    "index": hist.index,
-                    "uvs": [l[layer].uv.copy() for l in hist.loops],
-                }
-                face_info.append(info)
-        if not face_info:
-            ops_obj.report({'WARNING'}, "No faces are selected")
-            return None
-        key = list(src_info.keys())[0]
-        src_face_count = len(src_info[key])
-        dest_face_count = len(face_info)
-        if strategy == 'N_N' and src_face_count != dest_face_count:
-            ops_obj.report(
-                {'WARNING'},
-                "Number of selected faces is different from copied" +
-                "(src:{}, dest:{})"
-                .format(src_face_count, dest_face_count))
-            return None
-        dest_info[layer.name] = face_info
-
-    return dest_info
-
-
-def paste_uv(ops_obj, bm, src_info, dest_info, uv_layers, strategy, flip,
-             rotate, copy_seams):
-    for slayer_name, dlayer in zip(src_info.keys(), uv_layers):
-        src_faces = src_info[slayer_name]
-        dest_faces = dest_info[dlayer.name]
-
-        for idx, dinfo in enumerate(dest_faces):
-            sinfo = None
-            if strategy == 'N_N':
-                sinfo = src_faces[idx]
-            elif strategy == 'N_M':
-                sinfo = src_faces[idx % len(src_faces)]
-
-            suv = sinfo["uvs"]
-            spuv = sinfo["pin_uvs"]
-            ss = sinfo["seams"]
-            if len(sinfo["uvs"]) != len(dinfo["uvs"]):
-                ops_obj.report({'WARNING'}, "Some faces are different size")
-                return -1
-
-            suvs_fr = [uv for uv in suv]
-            spuvs_fr = [pin_uv for pin_uv in spuv]
-            ss_fr = [s for s in ss]
-
-            # flip UVs
-            if flip is True:
-                suvs_fr.reverse()
-                spuvs_fr.reverse()
-                ss_fr.reverse()
-
-            # rotate UVs
-            for _ in range(rotate):
-                uv = suvs_fr.pop()
-                pin_uv = spuvs_fr.pop()
-                s = ss_fr.pop()
-                suvs_fr.insert(0, uv)
-                spuvs_fr.insert(0, pin_uv)
-                ss_fr.insert(0, s)
-
-            # paste UVs
-            for l, suv, spuv, ss in zip(bm.faces[dinfo["index"]].loops,
-                                        suvs_fr, spuvs_fr, ss_fr):
-                l[dlayer].uv = suv
-                l[dlayer].pin_uv = spuv
-                if copy_seams is True:
-                    l.edge.seam = ss
-
-    return 0
diff --git a/uv_magic_uv/impl/copy_paste_uv_uvedit_impl.py b/uv_magic_uv/impl/copy_paste_uv_uvedit_impl.py
deleted file mode 100644
index f14a70d63c9c81fedc297ee0d107c24b9d708548..0000000000000000000000000000000000000000
--- a/uv_magic_uv/impl/copy_paste_uv_uvedit_impl.py
+++ /dev/null
@@ -1,166 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-__author__ = "imdjs, Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import math
-from math import atan2, sin, cos
-
-import bmesh
-from mathutils import Vector
-
-from .. import common
-
-
-__all__ = [
-    'is_valid_context',
-    'CopyUVImpl',
-    'PasteUVImpl',
-]
-
-
-def is_valid_context(context):
-    obj = context.object
-
-    # only edit mode is allowed to execute
-    if obj is None:
-        return False
-    if obj.type != 'MESH':
-        return False
-    if context.object.mode != 'EDIT':
-        return False
-
-    # 'IMAGE_EDITOR' and 'VIEW_3D' space is allowed to execute.
-    # If 'View_3D' space is not allowed, you can't find option in Tool-Shelf
-    # after the execution
-    for space in context.area.spaces:
-        if (space.type == 'IMAGE_EDITOR') or (space.type == 'VIEW_3D'):
-            break
-    else:
-        return False
-
-    return True
-
-
-class CopyUVImpl:
-    @classmethod
-    def poll(cls, context):
-        # we can not get area/space/region from console
-        if common.is_console_mode():
-            return True
-        return is_valid_context(context)
-
-    def execute(self, _, context):
-        props = context.scene.muv_props.copy_paste_uv_uvedit
-        obj = context.active_object
-        bm = bmesh.from_edit_mesh(obj.data)
-        uv_layer = bm.loops.layers.uv.verify()
-        if common.check_version(2, 73, 0) >= 0:
-            bm.faces.ensure_lookup_table()
-
-        props.src_uvs = []
-        for face in bm.faces:
-            if not face.select:
-                continue
-            skip = False
-            for l in face.loops:
-                if not l[uv_layer].select:
-                    skip = True
-                    break
-            if skip:
-                continue
-            props.src_uvs.append([l[uv_layer].uv.copy() for l in face.loops])
-
-        return {'FINISHED'}
-
-
-class PasteUVImpl:
-    @classmethod
-    def poll(cls, context):
-        # we can not get area/space/region from console
-        if common.is_console_mode():
-            return True
-        sc = context.scene
-        props = sc.muv_props.copy_paste_uv_uvedit
-        if not props.src_uvs:
-            return False
-        return is_valid_context(context)
-
-    def execute(self, _, context):
-        props = context.scene.muv_props.copy_paste_uv_uvedit
-        obj = context.active_object
-        bm = bmesh.from_edit_mesh(obj.data)
-        uv_layer = bm.loops.layers.uv.verify()
-        if common.check_version(2, 73, 0) >= 0:
-            bm.faces.ensure_lookup_table()
-
-        dest_uvs = []
-        dest_face_indices = []
-        for face in bm.faces:
-            if not face.select:
-                continue
-            skip = False
-            for l in face.loops:
-                if not l[uv_layer].select:
-                    skip = True
-                    break
-            if skip:
-                continue
-            dest_face_indices.append(face.index)
-            uvs = [l[uv_layer].uv.copy() for l in face.loops]
-            dest_uvs.append(uvs)
-
-        for suvs, duvs in zip(props.src_uvs, dest_uvs):
-            src_diff = suvs[1] - suvs[0]
-            dest_diff = duvs[1] - duvs[0]
-
-            src_base = suvs[0]
-            dest_base = duvs[0]
-
-            src_rad = atan2(src_diff.y, src_diff.x)
-            dest_rad = atan2(dest_diff.y, dest_diff.x)
-            if src_rad < dest_rad:
-                radian = dest_rad - src_rad
-            elif src_rad > dest_rad:
-                radian = math.pi * 2 - (src_rad - dest_rad)
-            else:       # src_rad == dest_rad
-                radian = 0.0
-
-            ratio = dest_diff.length / src_diff.length
-            break
-
-        for suvs, fidx in zip(props.src_uvs, dest_face_indices):
-            for l, suv in zip(bm.faces[fidx].loops, suvs):
-                base = suv - src_base
-                radian_ref = atan2(base.y, base.x)
-                radian_fin = (radian + radian_ref)
-                length = base.length
-                turn = Vector((length * cos(radian_fin),
-                               length * sin(radian_fin)))
-                target_uv = Vector((turn.x * ratio, turn.y * ratio)) + \
-                    dest_base
-                l[uv_layer].uv = target_uv
-
-        bmesh.update_edit_mesh(obj.data)
-
-        return {'FINISHED'}
diff --git a/uv_magic_uv/impl/flip_rotate_impl.py b/uv_magic_uv/impl/flip_rotate_impl.py
deleted file mode 100644
index f74bc256a6ac39c2958fc3ff50df3ae3299ce9ec..0000000000000000000000000000000000000000
--- a/uv_magic_uv/impl/flip_rotate_impl.py
+++ /dev/null
@@ -1,133 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-__author__ = "imdjs, Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-
-__all__ = [
-    'is_valid_context',
-    'get_uv_layer',
-    'get_src_face_info',
-]
-
-
-def is_valid_context(context):
-    obj = context.object
-
-    # only edit mode is allowed to execute
-    if obj is None:
-        return False
-    if obj.type != 'MESH':
-        return False
-    if context.object.mode != 'EDIT':
-        return False
-
-    # only 'VIEW_3D' space is allowed to execute
-    for space in context.area.spaces:
-        if space.type == 'VIEW_3D':
-            break
-    else:
-        return False
-
-    return True
-
-
-def get_uv_layer(ops_obj, bm):
-    # get UV layer
-    if not bm.loops.layers.uv:
-        ops_obj.report({'WARNING'}, "Object must have more than one UV map")
-        return None
-    uv_layer = bm.loops.layers.uv.verify()
-
-    return uv_layer
-
-
-def get_src_face_info(ops_obj, bm, uv_layers, only_select=False):
-    src_info = {}
-    for layer in uv_layers:
-        face_info = []
-        for face in bm.faces:
-            if not only_select or face.select:
-                info = {
-                    "index": face.index,
-                    "uvs": [l[layer].uv.copy() for l in face.loops],
-                    "pin_uvs": [l[layer].pin_uv for l in face.loops],
-                    "seams": [l.edge.seam for l in face.loops],
-                }
-                face_info.append(info)
-        if not face_info:
-            ops_obj.report({'WARNING'}, "No faces are selected")
-            return None
-        src_info[layer.name] = face_info
-
-    return src_info
-
-
-def paste_uv(ops_obj, bm, src_info, dest_info, uv_layers, strategy, flip,
-             rotate, copy_seams):
-    for slayer_name, dlayer in zip(src_info.keys(), uv_layers):
-        src_faces = src_info[slayer_name]
-        dest_faces = dest_info[dlayer.name]
-
-        for idx, dinfo in enumerate(dest_faces):
-            sinfo = None
-            if strategy == 'N_N':
-                sinfo = src_faces[idx]
-            elif strategy == 'N_M':
-                sinfo = src_faces[idx % len(src_faces)]
-
-            suv = sinfo["uvs"]
-            spuv = sinfo["pin_uvs"]
-            ss = sinfo["seams"]
-            if len(sinfo["uvs"]) != len(dinfo["uvs"]):
-                ops_obj.report({'WARNING'}, "Some faces are different size")
-                return -1
-
-            suvs_fr = [uv for uv in suv]
-            spuvs_fr = [pin_uv for pin_uv in spuv]
-            ss_fr = [s for s in ss]
-
-            # flip UVs
-            if flip is True:
-                suvs_fr.reverse()
-                spuvs_fr.reverse()
-                ss_fr.reverse()
-
-            # rotate UVs
-            for _ in range(rotate):
-                uv = suvs_fr.pop()
-                pin_uv = spuvs_fr.pop()
-                s = ss_fr.pop()
-                suvs_fr.insert(0, uv)
-                spuvs_fr.insert(0, pin_uv)
-                ss_fr.insert(0, s)
-
-            # paste UVs
-            for l, suv, spuv, ss in zip(bm.faces[dinfo["index"]].loops,
-                                        suvs_fr, spuvs_fr, ss_fr):
-                l[dlayer].uv = suv
-                l[dlayer].pin_uv = spuv
-                if copy_seams is True:
-                    l.edge.seam = ss
-
-    return 0
diff --git a/uv_magic_uv/impl/mirror_uv_impl.py b/uv_magic_uv/impl/mirror_uv_impl.py
deleted file mode 100644
index e79fbc2ce2d7c97ab5c65532e96133e19536bee6..0000000000000000000000000000000000000000
--- a/uv_magic_uv/impl/mirror_uv_impl.py
+++ /dev/null
@@ -1,158 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-__author__ = "Keith (Wahooney) Boshoff, Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bmesh
-from mathutils import Vector
-
-from .. import common
-
-
-__all__ = [
-    'is_valid_context',
-    'is_vector_similar',
-    'mirror_uvs',
-    'get_face_center',
-    'MirrorUVImpl',
-]
-
-
-def is_valid_context(context):
-    obj = context.object
-
-    # only edit mode is allowed to execute
-    if obj is None:
-        return False
-    if obj.type != 'MESH':
-        return False
-    if context.object.mode != 'EDIT':
-        return False
-
-    # only 'VIEW_3D' space is allowed to execute
-    for space in context.area.spaces:
-        if space.type == 'VIEW_3D':
-            break
-    else:
-        return False
-
-    return True
-
-
-def is_vector_similar(v1, v2, error):
-    """
-    Check if two vectors are similar, within an error threshold
-    """
-    within_err_x = abs(v2.x - v1.x) < error
-    within_err_y = abs(v2.y - v1.y) < error
-    within_err_z = abs(v2.z - v1.z) < error
-
-    return within_err_x and within_err_y and within_err_z
-
-
-def mirror_uvs(uv_layer, src, dst, axis, error):
-    """
-    Copy UV coordinates from one UV face to another
-    """
-    for sl in src.loops:
-        suv = sl[uv_layer].uv.copy()
-        svco = sl.vert.co.copy()
-        for dl in dst.loops:
-            dvco = dl.vert.co.copy()
-            if axis == 'X':
-                dvco.x = -dvco.x
-            elif axis == 'Y':
-                dvco.y = -dvco.y
-            elif axis == 'Z':
-                dvco.z = -dvco.z
-
-            if is_vector_similar(svco, dvco, error):
-                dl[uv_layer].uv = suv.copy()
-
-
-def get_face_center(face):
-    """
-    Get center coordinate of the face
-    """
-    center = Vector((0.0, 0.0, 0.0))
-    for v in face.verts:
-        center = center + v.co
-
-    return center / len(face.verts)
-
-
-class MirrorUVImpl:
-    @classmethod
-    def poll(cls, context):
-        # we can not get area/space/region from console
-        if common.is_console_mode():
-            return True
-        return is_valid_context(context)
-
-    def execute(self, ops_obj, context):
-        obj = context.active_object
-        bm = bmesh.from_edit_mesh(obj.data)
-
-        error = ops_obj.error
-        axis = ops_obj.axis
-
-        if common.check_version(2, 73, 0) >= 0:
-            bm.faces.ensure_lookup_table()
-        if not bm.loops.layers.uv:
-            ops_obj.report({'WARNING'},
-                           "Object must have more than one UV map")
-            return {'CANCELLED'}
-        uv_layer = bm.loops.layers.uv.verify()
-
-        faces = [f for f in bm.faces if f.select]
-        for f_dst in faces:
-            count = len(f_dst.verts)
-            for f_src in bm.faces:
-                # check if this is a candidate to do mirror UV
-                if f_src.index == f_dst.index:
-                    continue
-                if count != len(f_src.verts):
-                    continue
-
-                # test if the vertices x values are the same sign
-                dst = get_face_center(f_dst)
-                src = get_face_center(f_src)
-                if (dst.x > 0 and src.x > 0) or (dst.x < 0 and src.x < 0):
-                    continue
-
-                # invert source axis
-                if axis == 'X':
-                    src.x = -src.x
-                elif axis == 'Y':
-                    src.y = -src.z
-                elif axis == 'Z':
-                    src.z = -src.z
-
-                # do mirror UV
-                if is_vector_similar(dst, src, error):
-                    mirror_uvs(
-                        uv_layer, f_src, f_dst, ops_obj.axis, ops_obj.error)
-
-        bmesh.update_edit_mesh(obj.data)
-
-        return {'FINISHED'}
diff --git a/uv_magic_uv/impl/move_uv_impl.py b/uv_magic_uv/impl/move_uv_impl.py
deleted file mode 100644
index ce507fbab165c8ef75fc80e5a554a7344e62650c..0000000000000000000000000000000000000000
--- a/uv_magic_uv/impl/move_uv_impl.py
+++ /dev/null
@@ -1,166 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-__author__ = "imdjs, Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bmesh
-from mathutils import Vector
-
-from .. import common
-
-
-__all__ = [
-    'is_valid_context',
-    'find_uv',
-    'MoveUVImpl',
-]
-
-
-def is_valid_context(context):
-    obj = context.object
-
-    # only edit mode is allowed to execute
-    if obj is None:
-        return False
-    if obj.type != 'MESH':
-        return False
-    if context.object.mode != 'EDIT':
-        return False
-
-    # only 'VIEW_3D' space is allowed to execute
-    for space in context.area.spaces:
-        if space.type == 'VIEW_3D':
-            break
-    else:
-        return False
-
-    return True
-
-
-def find_uv(context):
-    bm = bmesh.from_edit_mesh(context.object.data)
-    topology_dict = []
-    uvs = []
-    active_uv = bm.loops.layers.uv.active
-    for fidx, f in enumerate(bm.faces):
-        for vidx, v in enumerate(f.verts):
-            if v.select:
-                uvs.append(f.loops[vidx][active_uv].uv.copy())
-                topology_dict.append([fidx, vidx])
-
-    return topology_dict, uvs
-
-
-class MoveUVImpl():
-    __running = False
-
-    def __init__(self):
-        self.__topology_dict = []
-        self.__prev_mouse = Vector((0.0, 0.0))
-        self.__offset_uv = Vector((0.0, 0.0))
-        self.__prev_offset_uv = Vector((0.0, 0.0))
-        self.__first_time = True
-        self.__ini_uvs = []
-        self.__operating = False
-
-    @classmethod
-    def poll(cls, context):
-        # we can not get area/space/region from console
-        if common.is_console_mode():
-            return False
-        if cls.is_running(context):
-            return False
-        return is_valid_context(context)
-
-    @classmethod
-    def is_running(cls, _):
-        return cls.__running
-
-    def modal(self, _, context, event):
-        if self.__first_time is True:
-            self.__prev_mouse = Vector((
-                event.mouse_region_x, event.mouse_region_y))
-            self.__first_time = False
-            return {'RUNNING_MODAL'}
-
-        # move UV
-        div = 10000
-        self.__offset_uv += Vector((
-            (event.mouse_region_x - self.__prev_mouse.x) / div,
-            (event.mouse_region_y - self.__prev_mouse.y) / div))
-        ouv = self.__offset_uv
-        pouv = self.__prev_offset_uv
-        vec = Vector((ouv.x - ouv.y, ouv.x + ouv.y))
-        dv = vec - pouv
-        self.__prev_offset_uv = vec
-        self.__prev_mouse = Vector((
-            event.mouse_region_x, event.mouse_region_y))
-
-        # check if operation is started
-        if not self.__operating:
-            if event.type == 'LEFTMOUSE' and event.value == 'RELEASE':
-                self.__operating = True
-            return {'RUNNING_MODAL'}
-
-        # update UV
-        obj = context.object
-        bm = bmesh.from_edit_mesh(obj.data)
-        active_uv = bm.loops.layers.uv.active
-        for fidx, vidx in self.__topology_dict:
-            l = bm.faces[fidx].loops[vidx]
-            l[active_uv].uv = l[active_uv].uv + dv
-        bmesh.update_edit_mesh(obj.data)
-
-        # check mouse preference
-        if context.user_preferences.inputs.select_mouse == 'RIGHT':
-            confirm_btn = 'LEFTMOUSE'
-            cancel_btn = 'RIGHTMOUSE'
-        else:
-            confirm_btn = 'RIGHTMOUSE'
-            cancel_btn = 'LEFTMOUSE'
-
-        # cancelled
-        if event.type == cancel_btn and event.value == 'PRESS':
-            for (fidx, vidx), uv in zip(self.__topology_dict, self.__ini_uvs):
-                bm.faces[fidx].loops[vidx][active_uv].uv = uv
-            MoveUVImpl.__running = False
-            return {'FINISHED'}
-        # confirmed
-        if event.type == confirm_btn and event.value == 'PRESS':
-            MoveUVImpl.__running = False
-            return {'FINISHED'}
-
-        return {'RUNNING_MODAL'}
-
-    def execute(self, ops_obj, context):
-        MoveUVImpl.__running = True
-        self.__operating = False
-        self.__first_time = True
-
-        context.window_manager.modal_handler_add(ops_obj)
-        self.__topology_dict, self.__ini_uvs = find_uv(context)
-
-        if context.area:
-            context.area.tag_redraw()
-
-        return {'RUNNING_MODAL'}
diff --git a/uv_magic_uv/impl/pack_uv_impl.py b/uv_magic_uv/impl/pack_uv_impl.py
deleted file mode 100644
index 49f954f3ca01f73f468a7668fdf5c70b4e938c64..0000000000000000000000000000000000000000
--- a/uv_magic_uv/impl/pack_uv_impl.py
+++ /dev/null
@@ -1,202 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-__author__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-from math import fabs
-
-import bpy
-import bmesh
-import mathutils
-from mathutils import Vector
-
-from .. import common
-
-
-__all__ = [
-    'PackUVImpl',
-]
-
-
-def is_valid_context(context):
-    obj = context.object
-
-    # only edit mode is allowed to execute
-    if obj is None:
-        return False
-    if obj.type != 'MESH':
-        return False
-    if context.object.mode != 'EDIT':
-        return False
-
-    # 'IMAGE_EDITOR' and 'VIEW_3D' space is allowed to execute.
-    # If 'View_3D' space is not allowed, you can't find option in Tool-Shelf
-    # after the execution
-    for space in context.area.spaces:
-        if (space.type == 'IMAGE_EDITOR') or (space.type == 'VIEW_3D'):
-            break
-    else:
-        return False
-
-    return True
-
-
-def sort_island_faces(kd, uvs, isl1, isl2):
-    """
-    Sort faces in island
-    """
-
-    sorted_faces = []
-    for f in isl1['sorted']:
-        _, idx, _ = kd.find(
-            Vector((f['ave_uv'].x, f['ave_uv'].y, 0.0)))
-        sorted_faces.append(isl2['faces'][uvs[idx]['face_idx']])
-    return sorted_faces
-
-
-def group_island(island_info, allowable_center_deviation,
-                 allowable_size_deviation):
-    """
-    Group island
-    """
-
-    num_group = 0
-    while True:
-        # search islands which is not parsed yet
-        isl_1 = None
-        for isl_1 in island_info:
-            if isl_1['group'] == -1:
-                break
-        else:
-            break   # all faces are parsed
-        if isl_1 is None:
-            break
-        isl_1['group'] = num_group
-        isl_1['sorted'] = isl_1['faces']
-
-        # search same island
-        for isl_2 in island_info:
-            if isl_2['group'] == -1:
-                dcx = isl_2['center'].x - isl_1['center'].x
-                dcy = isl_2['center'].y - isl_1['center'].y
-                dsx = isl_2['size'].x - isl_1['size'].x
-                dsy = isl_2['size'].y - isl_1['size'].y
-                center_x_matched = (
-                    fabs(dcx) < allowable_center_deviation[0]
-                )
-                center_y_matched = (
-                    fabs(dcy) < allowable_center_deviation[1]
-                )
-                size_x_matched = (
-                    fabs(dsx) < allowable_size_deviation[0]
-                )
-                size_y_matched = (
-                    fabs(dsy) < allowable_size_deviation[1]
-                )
-                center_matched = center_x_matched and center_y_matched
-                size_matched = size_x_matched and size_y_matched
-                num_uv_matched = (isl_2['num_uv'] == isl_1['num_uv'])
-                # are islands have same?
-                if center_matched and size_matched and num_uv_matched:
-                    isl_2['group'] = num_group
-                    kd = mathutils.kdtree.KDTree(len(isl_2['faces']))
-                    uvs = [
-                        {
-                            'uv': Vector(
-                                (f['ave_uv'].x, f['ave_uv'].y, 0.0)
-                            ),
-                            'face_idx': fidx
-                        } for fidx, f in enumerate(isl_2['faces'])
-                    ]
-                    for i, uv in enumerate(uvs):
-                        kd.insert(uv['uv'], i)
-                    kd.balance()
-                    # sort faces for copy/paste UV
-                    isl_2['sorted'] = sort_island_faces(kd, uvs, isl_1, isl_2)
-        num_group = num_group + 1
-
-    return num_group
-
-
-class PackUVImpl:
-    @classmethod
-    def poll(cls, context):
-        # we can not get area/space/region from console
-        if common.is_console_mode():
-            return True
-        return is_valid_context(context)
-
-    def execute(self, ops_obj, context):
-        obj = context.active_object
-        bm = bmesh.from_edit_mesh(obj.data)
-        if common.check_version(2, 73, 0) >= 0:
-            bm.faces.ensure_lookup_table()
-        if not bm.loops.layers.uv:
-            ops_obj.report({'WARNING'},
-                           "Object must have more than one UV map")
-            return {'CANCELLED'}
-        uv_layer = bm.loops.layers.uv.verify()
-
-        selected_faces = [f for f in bm.faces if f.select]
-        island_info = common.get_island_info(obj)
-        num_group = group_island(island_info,
-                                 ops_obj.allowable_center_deviation,
-                                 ops_obj.allowable_size_deviation)
-
-        loop_lists = [l for f in bm.faces for l in f.loops]
-        bpy.ops.mesh.select_all(action='DESELECT')
-
-        # pack UV
-        for gidx in range(num_group):
-            group = list(filter(
-                lambda i, idx=gidx: i['group'] == idx, island_info))
-            for f in group[0]['faces']:
-                f['face'].select = True
-        bmesh.update_edit_mesh(obj.data)
-        bpy.ops.uv.select_all(action='SELECT')
-        bpy.ops.uv.pack_islands(rotate=ops_obj.rotate, margin=ops_obj.margin)
-
-        # copy/paste UV among same islands
-        for gidx in range(num_group):
-            group = list(filter(
-                lambda i, idx=gidx: i['group'] == idx, island_info))
-            if len(group) <= 1:
-                continue
-            for g in group[1:]:
-                for (src_face, dest_face) in zip(
-                        group[0]['sorted'], g['sorted']):
-                    for (src_loop, dest_loop) in zip(
-                            src_face['face'].loops, dest_face['face'].loops):
-                        loop_lists[dest_loop.index][uv_layer].uv = loop_lists[
-                            src_loop.index][uv_layer].uv
-
-        # restore face/UV selection
-        bpy.ops.uv.select_all(action='DESELECT')
-        bpy.ops.mesh.select_all(action='DESELECT')
-        for f in selected_faces:
-            f.select = True
-        bpy.ops.uv.select_all(action='SELECT')
-
-        bmesh.update_edit_mesh(obj.data)
-
-        return {'FINISHED'}
diff --git a/uv_magic_uv/impl/preserve_uv_aspect_impl.py b/uv_magic_uv/impl/preserve_uv_aspect_impl.py
deleted file mode 100644
index 622ee1d365cf8124f01585912c61f8344922fac1..0000000000000000000000000000000000000000
--- a/uv_magic_uv/impl/preserve_uv_aspect_impl.py
+++ /dev/null
@@ -1,359 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-__author__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-import bmesh
-from mathutils import Vector
-
-from .. import common
-
-
-__all__ = [
-    'PreserveUVAspectLegacyImpl',
-]
-
-
-def is_valid_context(context):
-    obj = context.object
-
-    # only edit mode is allowed to execute
-    if obj is None:
-        return False
-    if obj.type != 'MESH':
-        return False
-    if context.object.mode != 'EDIT':
-        return False
-
-    # only 'VIEW_3D' space is allowed to execute
-    for space in context.area.spaces:
-        if space.type == 'VIEW_3D':
-            break
-    else:
-        return False
-
-    return True
-
-
-class PreserveUVAspectLegacyImpl:
-    @classmethod
-    def poll(cls, context):
-        # we can not get area/space/region from console
-        if common.is_console_mode():
-            return True
-        return is_valid_context(context)
-
-    def execute(self, ops_obj, context):
-        # Note: the current system only works if the
-        # f[tex_layer].image doesn't return None
-        # which will happen in certain cases
-        obj = context.active_object
-        bm = bmesh.from_edit_mesh(obj.data)
-
-        if common.check_version(2, 73, 0) >= 0:
-            bm.faces.ensure_lookup_table()
-
-        if not bm.loops.layers.uv:
-            ops_obj.report({'WARNING'},
-                           "Object must have more than one UV map")
-            return {'CANCELLED'}
-
-        uv_layer = bm.loops.layers.uv.verify()
-        tex_layer = bm.faces.layers.tex.verify()
-
-        sel_faces = [f for f in bm.faces if f.select]
-        dest_img = bpy.data.images[ops_obj.dest_img_name]
-
-        info = {}
-
-        for f in sel_faces:
-            if not f[tex_layer].image in info.keys():
-                info[f[tex_layer].image] = {}
-                info[f[tex_layer].image]['faces'] = []
-            info[f[tex_layer].image]['faces'].append(f)
-
-        for img in info:
-            if img is None:
-                continue
-
-            src_img = img
-            ratio = Vector((
-                dest_img.size[0] / src_img.size[0],
-                dest_img.size[1] / src_img.size[1]))
-
-            if ops_obj.origin == 'CENTER':
-                origin = Vector((0.0, 0.0))
-                num = 0
-                for f in info[img]['faces']:
-                    for l in f.loops:
-                        uv = l[uv_layer].uv
-                        origin = origin + uv
-                        num = num + 1
-                origin = origin / num
-            elif ops_obj.origin == 'LEFT_TOP':
-                origin = Vector((100000.0, -100000.0))
-                for f in info[img]['faces']:
-                    for l in f.loops:
-                        uv = l[uv_layer].uv
-                        origin.x = min(origin.x, uv.x)
-                        origin.y = max(origin.y, uv.y)
-            elif ops_obj.origin == 'LEFT_CENTER':
-                origin = Vector((100000.0, 0.0))
-                num = 0
-                for f in info[img]['faces']:
-                    for l in f.loops:
-                        uv = l[uv_layer].uv
-                        origin.x = min(origin.x, uv.x)
-                        origin.y = origin.y + uv.y
-                        num = num + 1
-                origin.y = origin.y / num
-            elif ops_obj.origin == 'LEFT_BOTTOM':
-                origin = Vector((100000.0, 100000.0))
-                for f in info[img]['faces']:
-                    for l in f.loops:
-                        uv = l[uv_layer].uv
-                        origin.x = min(origin.x, uv.x)
-                        origin.y = min(origin.y, uv.y)
-            elif ops_obj.origin == 'CENTER_TOP':
-                origin = Vector((0.0, -100000.0))
-                num = 0
-                for f in info[img]['faces']:
-                    for l in f.loops:
-                        uv = l[uv_layer].uv
-                        origin.x = origin.x + uv.x
-                        origin.y = max(origin.y, uv.y)
-                        num = num + 1
-                origin.x = origin.x / num
-            elif ops_obj.origin == 'CENTER_BOTTOM':
-                origin = Vector((0.0, 100000.0))
-                num = 0
-                for f in info[img]['faces']:
-                    for l in f.loops:
-                        uv = l[uv_layer].uv
-                        origin.x = origin.x + uv.x
-                        origin.y = min(origin.y, uv.y)
-                        num = num + 1
-                origin.x = origin.x / num
-            elif ops_obj.origin == 'RIGHT_TOP':
-                origin = Vector((-100000.0, -100000.0))
-                for f in info[img]['faces']:
-                    for l in f.loops:
-                        uv = l[uv_layer].uv
-                        origin.x = max(origin.x, uv.x)
-                        origin.y = max(origin.y, uv.y)
-            elif ops_obj.origin == 'RIGHT_CENTER':
-                origin = Vector((-100000.0, 0.0))
-                num = 0
-                for f in info[img]['faces']:
-                    for l in f.loops:
-                        uv = l[uv_layer].uv
-                        origin.x = max(origin.x, uv.x)
-                        origin.y = origin.y + uv.y
-                        num = num + 1
-                origin.y = origin.y / num
-            elif ops_obj.origin == 'RIGHT_BOTTOM':
-                origin = Vector((-100000.0, 100000.0))
-                for f in info[img]['faces']:
-                    for l in f.loops:
-                        uv = l[uv_layer].uv
-                        origin.x = max(origin.x, uv.x)
-                        origin.y = min(origin.y, uv.y)
-
-            info[img]['ratio'] = ratio
-            info[img]['origin'] = origin
-
-        for img in info:
-            if img is None:
-                continue
-
-            for f in info[img]['faces']:
-                f[tex_layer].image = dest_img
-                for l in f.loops:
-                    uv = l[uv_layer].uv
-                    origin = info[img]['origin']
-                    ratio = info[img]['ratio']
-                    diff = uv - origin
-                    diff.x = diff.x / ratio.x
-                    diff.y = diff.y / ratio.y
-                    uv.x = origin.x + diff.x
-                    uv.y = origin.y + diff.y
-                    l[uv_layer].uv = uv
-
-        bmesh.update_edit_mesh(obj.data)
-
-        return {'FINISHED'}
-
-
-class PreserveUVAspectImpl:
-    @classmethod
-    def poll(cls, context):
-        # we can not get area/space/region from console
-        if common.is_console_mode():
-            return True
-        return is_valid_context(context)
-
-    def execute(self, ops_obj, context):
-        # Note: the current system only works if the
-        # f[tex_layer].image doesn't return None
-        # which will happen in certain cases
-        obj = context.active_object
-        bm = bmesh.from_edit_mesh(obj.data)
-
-        if common.check_version(2, 73, 0) >= 0:
-            bm.faces.ensure_lookup_table()
-
-        if not bm.loops.layers.uv:
-            ops_obj.report({'WARNING'},
-                           "Object must have more than one UV map")
-            return {'CANCELLED'}
-
-        uv_layer = bm.loops.layers.uv.verify()
-        tex_image = common.find_image(obj)
-
-        sel_faces = [f for f in bm.faces if f.select]
-        dest_img = bpy.data.images[ops_obj.dest_img_name]
-
-        info = {}
-
-        for f in sel_faces:
-            if not tex_image in info.keys():
-                info[tex_image] = {}
-                info[tex_image]['faces'] = []
-            info[tex_image]['faces'].append(f)
-
-        for img in info:
-            if img is None:
-                continue
-
-            src_img = img
-            ratio = Vector((
-                dest_img.size[0] / src_img.size[0],
-                dest_img.size[1] / src_img.size[1]))
-
-            if ops_obj.origin == 'CENTER':
-                origin = Vector((0.0, 0.0))
-                num = 0
-                for f in info[img]['faces']:
-                    for l in f.loops:
-                        uv = l[uv_layer].uv
-                        origin = origin + uv
-                        num = num + 1
-                origin = origin / num
-            elif ops_obj.origin == 'LEFT_TOP':
-                origin = Vector((100000.0, -100000.0))
-                for f in info[img]['faces']:
-                    for l in f.loops:
-                        uv = l[uv_layer].uv
-                        origin.x = min(origin.x, uv.x)
-                        origin.y = max(origin.y, uv.y)
-            elif ops_obj.origin == 'LEFT_CENTER':
-                origin = Vector((100000.0, 0.0))
-                num = 0
-                for f in info[img]['faces']:
-                    for l in f.loops:
-                        uv = l[uv_layer].uv
-                        origin.x = min(origin.x, uv.x)
-                        origin.y = origin.y + uv.y
-                        num = num + 1
-                origin.y = origin.y / num
-            elif ops_obj.origin == 'LEFT_BOTTOM':
-                origin = Vector((100000.0, 100000.0))
-                for f in info[img]['faces']:
-                    for l in f.loops:
-                        uv = l[uv_layer].uv
-                        origin.x = min(origin.x, uv.x)
-                        origin.y = min(origin.y, uv.y)
-            elif ops_obj.origin == 'CENTER_TOP':
-                origin = Vector((0.0, -100000.0))
-                num = 0
-                for f in info[img]['faces']:
-                    for l in f.loops:
-                        uv = l[uv_layer].uv
-                        origin.x = origin.x + uv.x
-                        origin.y = max(origin.y, uv.y)
-                        num = num + 1
-                origin.x = origin.x / num
-            elif ops_obj.origin == 'CENTER_BOTTOM':
-                origin = Vector((0.0, 100000.0))
-                num = 0
-                for f in info[img]['faces']:
-                    for l in f.loops:
-                        uv = l[uv_layer].uv
-                        origin.x = origin.x + uv.x
-                        origin.y = min(origin.y, uv.y)
-                        num = num + 1
-                origin.x = origin.x / num
-            elif ops_obj.origin == 'RIGHT_TOP':
-                origin = Vector((-100000.0, -100000.0))
-                for f in info[img]['faces']:
-                    for l in f.loops:
-                        uv = l[uv_layer].uv
-                        origin.x = max(origin.x, uv.x)
-                        origin.y = max(origin.y, uv.y)
-            elif ops_obj.origin == 'RIGHT_CENTER':
-                origin = Vector((-100000.0, 0.0))
-                num = 0
-                for f in info[img]['faces']:
-                    for l in f.loops:
-                        uv = l[uv_layer].uv
-                        origin.x = max(origin.x, uv.x)
-                        origin.y = origin.y + uv.y
-                        num = num + 1
-                origin.y = origin.y / num
-            elif ops_obj.origin == 'RIGHT_BOTTOM':
-                origin = Vector((-100000.0, 100000.0))
-                for f in info[img]['faces']:
-                    for l in f.loops:
-                        uv = l[uv_layer].uv
-                        origin.x = max(origin.x, uv.x)
-                        origin.y = min(origin.y, uv.y)
-            else:
-                ops_obj.report({'ERROR'}, "Unknown Operation")
-                return {'CANCELLED'}
-
-            info[img]['ratio'] = ratio
-            info[img]['origin'] = origin
-
-        for img in info:
-            if img is None:
-                continue
-
-            nodes = common.find_texture_nodes(obj)
-            nodes[0].image = dest_img
-
-            for f in info[img]['faces']:
-                for l in f.loops:
-                    uv = l[uv_layer].uv
-                    origin = info[img]['origin']
-                    ratio = info[img]['ratio']
-                    diff = uv - origin
-                    diff.x = diff.x / ratio.x
-                    diff.y = diff.y / ratio.y
-                    uv.x = origin.x + diff.x
-                    uv.y = origin.y + diff.y
-                    l[uv_layer].uv = uv
-
-        bmesh.update_edit_mesh(obj.data)
-
-        return {'FINISHED'}
\ No newline at end of file
diff --git a/uv_magic_uv/impl/select_uv_impl.py b/uv_magic_uv/impl/select_uv_impl.py
deleted file mode 100644
index dbcaee7e99230add0e041c1e3e07f4aae5b388d3..0000000000000000000000000000000000000000
--- a/uv_magic_uv/impl/select_uv_impl.py
+++ /dev/null
@@ -1,120 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-__author__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bmesh
-
-from .. import common
-
-
-def _is_valid_context(context):
-    obj = context.object
-
-    # only edit mode is allowed to execute
-    if obj is None:
-        return False
-    if obj.type != 'MESH':
-        return False
-    if context.object.mode != 'EDIT':
-        return False
-
-    # 'IMAGE_EDITOR' and 'VIEW_3D' space is allowed to execute.
-    # If 'View_3D' space is not allowed, you can't find option in Tool-Shelf
-    # after the execution
-    for space in context.area.spaces:
-        if (space.type == 'IMAGE_EDITOR') or (space.type == 'VIEW_3D'):
-            break
-    else:
-        return False
-
-    return True
-
-
-class SelectOverlappedImpl:
-    @classmethod
-    def poll(cls, context):
-        # we can not get area/space/region from console
-        if common.is_console_mode():
-            return True
-        return _is_valid_context(context)
-
-    def execute(self, _, context):
-        obj = context.active_object
-        bm = bmesh.from_edit_mesh(obj.data)
-        if common.check_version(2, 73, 0) >= 0:
-            bm.faces.ensure_lookup_table()
-        uv_layer = bm.loops.layers.uv.verify()
-
-        if context.tool_settings.use_uv_select_sync:
-            sel_faces = [f for f in bm.faces]
-        else:
-            sel_faces = [f for f in bm.faces if f.select]
-
-        overlapped_info = common.get_overlapped_uv_info(bm, sel_faces,
-                                                        uv_layer, 'FACE')
-
-        for info in overlapped_info:
-            if context.tool_settings.use_uv_select_sync:
-                info["subject_face"].select = True
-            else:
-                for l in info["subject_face"].loops:
-                    l[uv_layer].select = True
-
-        bmesh.update_edit_mesh(obj.data)
-
-        return {'FINISHED'}
-
-
-class SelectFlippedImpl:
-    @classmethod
-    def poll(cls, context):
-        # we can not get area/space/region from console
-        if common.is_console_mode():
-            return True
-        return _is_valid_context(context)
-
-    def execute(self, _, context):
-        obj = context.active_object
-        bm = bmesh.from_edit_mesh(obj.data)
-        if common.check_version(2, 73, 0) >= 0:
-            bm.faces.ensure_lookup_table()
-        uv_layer = bm.loops.layers.uv.verify()
-
-        if context.tool_settings.use_uv_select_sync:
-            sel_faces = [f for f in bm.faces]
-        else:
-            sel_faces = [f for f in bm.faces if f.select]
-
-        flipped_info = common.get_flipped_uv_info(sel_faces, uv_layer)
-
-        for info in flipped_info:
-            if context.tool_settings.use_uv_select_sync:
-                info["face"].select = True
-            else:
-                for l in info["face"].loops:
-                    l[uv_layer].select = True
-
-        bmesh.update_edit_mesh(obj.data)
-
-        return {'FINISHED'}
diff --git a/uv_magic_uv/impl/smooth_uv_impl.py b/uv_magic_uv/impl/smooth_uv_impl.py
deleted file mode 100644
index dbc8afad38556df59b8c166b006c2fd5d13bd794..0000000000000000000000000000000000000000
--- a/uv_magic_uv/impl/smooth_uv_impl.py
+++ /dev/null
@@ -1,215 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-__author__ = "imdjs, Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bmesh
-
-from .. import common
-
-
-def _is_valid_context(context):
-    obj = context.object
-
-    # only edit mode is allowed to execute
-    if obj is None:
-        return False
-    if obj.type != 'MESH':
-        return False
-    if context.object.mode != 'EDIT':
-        return False
-
-    # 'IMAGE_EDITOR' and 'VIEW_3D' space is allowed to execute.
-    # If 'View_3D' space is not allowed, you can't find option in Tool-Shelf
-    # after the execution
-    for space in context.area.spaces:
-        if (space.type == 'IMAGE_EDITOR') or (space.type == 'VIEW_3D'):
-            break
-    else:
-        return False
-
-    return True
-
-
-class SmoothUVImpl:
-    @classmethod
-    def poll(cls, context):
-        # we can not get area/space/region from console
-        if common.is_console_mode():
-            return True
-        return _is_valid_context(context)
-
-    def __smooth_wo_transmission(self, ops_obj, loop_seqs, uv_layer):
-        # calculate path length
-        loops = []
-        for hseq in loop_seqs:
-            loops.extend([hseq[0][0], hseq[0][1]])
-        full_vlen = 0
-        accm_vlens = [0.0]
-        full_uvlen = 0
-        accm_uvlens = [0.0]
-        orig_uvs = [loop_seqs[0][0][0][uv_layer].uv.copy()]
-        for l1, l2 in zip(loops[:-1], loops[1:]):
-            diff_v = l2.vert.co - l1.vert.co
-            full_vlen = full_vlen + diff_v.length
-            accm_vlens.append(full_vlen)
-            diff_uv = l2[uv_layer].uv - l1[uv_layer].uv
-            full_uvlen = full_uvlen + diff_uv.length
-            accm_uvlens.append(full_uvlen)
-            orig_uvs.append(l2[uv_layer].uv.copy())
-
-        for hidx, hseq in enumerate(loop_seqs):
-            pair = hseq[0]
-            for pidx, l in enumerate(pair):
-                if ops_obj.select:
-                    l[uv_layer].select = True
-
-                # ignore start/end loop
-                if (hidx == 0 and pidx == 0) or\
-                   ((hidx == len(loop_seqs) - 1) and (pidx == len(pair) - 1)):
-                    continue
-
-                # calculate target path length
-                # target = no influenced * (1 - infl) + influenced * infl
-                tgt_noinfl = full_uvlen * (hidx + pidx) / (len(loop_seqs))
-                tgt_infl = full_uvlen * accm_vlens[hidx * 2 + pidx] / full_vlen
-                target_length = tgt_noinfl * (1 - ops_obj.mesh_infl) + \
-                    tgt_infl * ops_obj.mesh_infl
-
-                # get target UV
-                for i in range(len(accm_uvlens[:-1])):
-                    # get line segment which UV will be placed
-                    if ((accm_uvlens[i] <= target_length) and
-                            (accm_uvlens[i + 1] > target_length)):
-                        tgt_seg_len = target_length - accm_uvlens[i]
-                        seg_len = accm_uvlens[i + 1] - accm_uvlens[i]
-                        uv1 = orig_uvs[i]
-                        uv2 = orig_uvs[i + 1]
-                        target_uv = uv1 + (uv2 - uv1) * tgt_seg_len / seg_len
-                        break
-                else:
-                    ops_obj.report({'ERROR'}, "Failed to get target UV")
-                    return {'CANCELLED'}
-
-                # update UV
-                l[uv_layer].uv = target_uv
-
-    def __smooth_w_transmission(self, ops_obj, loop_seqs, uv_layer):
-        # calculate path length
-        loops = []
-        for vidx in range(len(loop_seqs[0])):
-            ls = []
-            for hseq in loop_seqs:
-                ls.extend(hseq[vidx])
-            loops.append(ls)
-
-        orig_uvs = []
-        accm_vlens = []
-        full_vlens = []
-        accm_uvlens = []
-        full_uvlens = []
-        for ls in loops:
-            full_v = 0.0
-            accm_v = [0.0]
-            full_uv = 0.0
-            accm_uv = [0.0]
-            uvs = [ls[0][uv_layer].uv.copy()]
-            for l1, l2 in zip(ls[:-1], ls[1:]):
-                diff_v = l2.vert.co - l1.vert.co
-                full_v = full_v + diff_v.length
-                accm_v.append(full_v)
-                diff_uv = l2[uv_layer].uv - l1[uv_layer].uv
-                full_uv = full_uv + diff_uv.length
-                accm_uv.append(full_uv)
-                uvs.append(l2[uv_layer].uv.copy())
-            accm_vlens.append(accm_v)
-            full_vlens.append(full_v)
-            accm_uvlens.append(accm_uv)
-            full_uvlens.append(full_uv)
-            orig_uvs.append(uvs)
-
-        for hidx, hseq in enumerate(loop_seqs):
-            for vidx, (pair, uvs, accm_v, full_v, accm_uv, full_uv)\
-                    in enumerate(zip(hseq, orig_uvs, accm_vlens, full_vlens,
-                                     accm_uvlens, full_uvlens)):
-                for pidx, l in enumerate(pair):
-                    if ops_obj.select:
-                        l[uv_layer].select = True
-
-                    # ignore start/end loop
-                    if hidx == 0 and pidx == 0:
-                        continue
-                    if hidx == len(loop_seqs) - 1 and pidx == len(pair) - 1:
-                        continue
-
-                    # calculate target path length
-                    # target = no influenced * (1 - infl) + influenced * infl
-                    tgt_noinfl = full_uv * (hidx + pidx) / (len(loop_seqs))
-                    tgt_infl = full_uv * accm_v[hidx * 2 + pidx] / full_v
-                    target_length = tgt_noinfl * (1 - ops_obj.mesh_infl) + \
-                        tgt_infl * ops_obj.mesh_infl
-
-                    # get target UV
-                    for i in range(len(accm_uv[:-1])):
-                        # get line segment to be placed
-                        if ((accm_uv[i] <= target_length) and
-                                (accm_uv[i + 1] > target_length)):
-                            tgt_seg_len = target_length - accm_uv[i]
-                            seg_len = accm_uv[i + 1] - accm_uv[i]
-                            uv1 = uvs[i]
-                            uv2 = uvs[i + 1]
-                            target_uv = uv1 +\
-                                (uv2 - uv1) * tgt_seg_len / seg_len
-                            break
-                    else:
-                        ops_obj.report({'ERROR'}, "Failed to get target UV")
-                        return {'CANCELLED'}
-
-                    # update UV
-                    l[uv_layer].uv = target_uv
-
-    def __smooth(self, ops_obj, loop_seqs, uv_layer):
-        if ops_obj.transmission:
-            self.__smooth_w_transmission(ops_obj, loop_seqs, uv_layer)
-        else:
-            self.__smooth_wo_transmission(ops_obj, loop_seqs, uv_layer)
-
-    def execute(self, ops_obj, context):
-        obj = context.active_object
-        bm = bmesh.from_edit_mesh(obj.data)
-        if common.check_version(2, 73, 0) >= 0:
-            bm.faces.ensure_lookup_table()
-        uv_layer = bm.loops.layers.uv.verify()
-
-        # loop_seqs[horizontal][vertical][loop]
-        loop_seqs, error = common.get_loop_sequences(bm, uv_layer)
-        if not loop_seqs:
-            ops_obj.report({'WARNING'}, error)
-            return {'CANCELLED'}
-
-        # smooth
-        self.__smooth(ops_obj, loop_seqs, uv_layer)
-
-        bmesh.update_edit_mesh(obj.data)
-
-        return {'FINISHED'}
diff --git a/uv_magic_uv/impl/texture_lock_impl.py b/uv_magic_uv/impl/texture_lock_impl.py
deleted file mode 100644
index c14eddb0f0877bf6cb1ecbd3a6571a023817edb4..0000000000000000000000000000000000000000
--- a/uv_magic_uv/impl/texture_lock_impl.py
+++ /dev/null
@@ -1,455 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-__author__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import math
-from math import atan2, cos, sqrt, sin, fabs
-
-import bpy
-import bmesh
-from mathutils import Vector
-
-from .. import common
-
-
-def _get_vco(verts_orig, loop):
-    """
-    Get vertex original coordinate from loop
-    """
-    for vo in verts_orig:
-        if vo["vidx"] == loop.vert.index and vo["moved"] is False:
-            return vo["vco"]
-    return loop.vert.co
-
-
-def _get_link_loops(vert):
-    """
-    Get loop linked to vertex
-    """
-    link_loops = []
-    for f in vert.link_faces:
-        adj_loops = []
-        for loop in f.loops:
-            # self loop
-            if loop.vert == vert:
-                l = loop
-            # linked loop
-            else:
-                for e in loop.vert.link_edges:
-                    if e.other_vert(loop.vert) == vert:
-                        adj_loops.append(loop)
-        if len(adj_loops) < 2:
-            return None
-
-        link_loops.append({"l": l, "l0": adj_loops[0], "l1": adj_loops[1]})
-    return link_loops
-
-
-def _get_ini_geom(link_loop, uv_layer, verts_orig, v_orig):
-    """
-    Get initial geometory
-    (Get interior angle of face in vertex/UV space)
-    """
-    u = link_loop["l"][uv_layer].uv
-    v0 = _get_vco(verts_orig, link_loop["l0"])
-    u0 = link_loop["l0"][uv_layer].uv
-    v1 = _get_vco(verts_orig, link_loop["l1"])
-    u1 = link_loop["l1"][uv_layer].uv
-
-    # get interior angle of face in vertex space
-    v0v1 = v1 - v0
-    v0v = v_orig["vco"] - v0
-    v1v = v_orig["vco"] - v1
-    theta0 = v0v1.angle(v0v)
-    theta1 = v0v1.angle(-v1v)
-    if (theta0 + theta1) > math.pi:
-        theta0 = v0v1.angle(-v0v)
-        theta1 = v0v1.angle(v1v)
-
-    # get interior angle of face in UV space
-    u0u1 = u1 - u0
-    u0u = u - u0
-    u1u = u - u1
-    phi0 = u0u1.angle(u0u)
-    phi1 = u0u1.angle(-u1u)
-    if (phi0 + phi1) > math.pi:
-        phi0 = u0u1.angle(-u0u)
-        phi1 = u0u1.angle(u1u)
-
-    # get direction of linked UV coordinate
-    # this will be used to judge whether angle is more or less than 180 degree
-    dir0 = u0u1.cross(u0u) > 0
-    dir1 = u0u1.cross(u1u) > 0
-
-    return {
-        "theta0": theta0,
-        "theta1": theta1,
-        "phi0": phi0,
-        "phi1": phi1,
-        "dir0": dir0,
-        "dir1": dir1}
-
-
-def _get_target_uv(link_loop, uv_layer, verts_orig, v, ini_geom):
-    """
-    Get target UV coordinate
-    """
-    v0 = _get_vco(verts_orig, link_loop["l0"])
-    lo0 = link_loop["l0"]
-    v1 = _get_vco(verts_orig, link_loop["l1"])
-    lo1 = link_loop["l1"]
-
-    # get interior angle of face in vertex space
-    v0v1 = v1 - v0
-    v0v = v.co - v0
-    v1v = v.co - v1
-    theta0 = v0v1.angle(v0v)
-    theta1 = v0v1.angle(-v1v)
-    if (theta0 + theta1) > math.pi:
-        theta0 = v0v1.angle(-v0v)
-        theta1 = v0v1.angle(v1v)
-
-    # calculate target interior angle in UV space
-    phi0 = theta0 * ini_geom["phi0"] / ini_geom["theta0"]
-    phi1 = theta1 * ini_geom["phi1"] / ini_geom["theta1"]
-
-    uv0 = lo0[uv_layer].uv
-    uv1 = lo1[uv_layer].uv
-
-    # calculate target vertex coordinate from target interior angle
-    tuv0, tuv1 = _calc_tri_vert(uv0, uv1, phi0, phi1)
-
-    # target UV coordinate depends on direction, so judge using direction of
-    # linked UV coordinate
-    u0u1 = uv1 - uv0
-    u0u = tuv0 - uv0
-    u1u = tuv0 - uv1
-    dir0 = u0u1.cross(u0u) > 0
-    dir1 = u0u1.cross(u1u) > 0
-    if (ini_geom["dir0"] != dir0) or (ini_geom["dir1"] != dir1):
-        return tuv1
-
-    return tuv0
-
-
-def _calc_tri_vert(v0, v1, angle0, angle1):
-    """
-    Calculate rest coordinate from other coordinates and angle of end
-    """
-    angle = math.pi - angle0 - angle1
-
-    alpha = atan2(v1.y - v0.y, v1.x - v0.x)
-    d = (v1.x - v0.x) / cos(alpha)
-    a = d * sin(angle0) / sin(angle)
-    b = d * sin(angle1) / sin(angle)
-    s = (a + b + d) / 2.0
-    if fabs(d) < 0.0000001:
-        xd = 0
-        yd = 0
-    else:
-        r = s * (s - a) * (s - b) * (s - d)
-        if r < 0:
-            xd = 0
-            yd = 0
-        else:
-            xd = (b * b - a * a + d * d) / (2 * d)
-            yd = 2 * sqrt(r) / d
-    x1 = xd * cos(alpha) - yd * sin(alpha) + v0.x
-    y1 = xd * sin(alpha) + yd * cos(alpha) + v0.y
-    x2 = xd * cos(alpha) + yd * sin(alpha) + v0.x
-    y2 = xd * sin(alpha) - yd * cos(alpha) + v0.y
-
-    return Vector((x1, y1)), Vector((x2, y2))
-
-
-def _is_valid_context(context):
-    obj = context.object
-
-    # only edit mode is allowed to execute
-    if obj is None:
-        return False
-    if obj.type != 'MESH':
-        return False
-    if context.object.mode != 'EDIT':
-        return False
-
-    # only 'VIEW_3D' space is allowed to execute
-    for space in context.area.spaces:
-        if space.type == 'VIEW_3D':
-            break
-    else:
-        return False
-
-    return True
-
-
-class LockImpl:
-    @classmethod
-    def poll(cls, context):
-        # we can not get area/space/region from console
-        if common.is_console_mode():
-            return True
-        return _is_valid_context(context)
-
-    @classmethod
-    def is_ready(cls, context):
-        sc = context.scene
-        props = sc.muv_props.texture_lock
-        if props.verts_orig:
-            return True
-        return False
-
-    def execute(self, ops_obj, context):
-        props = context.scene.muv_props.texture_lock
-        obj = bpy.context.active_object
-        bm = bmesh.from_edit_mesh(obj.data)
-        if common.check_version(2, 73, 0) >= 0:
-            bm.verts.ensure_lookup_table()
-            bm.edges.ensure_lookup_table()
-            bm.faces.ensure_lookup_table()
-
-        if not bm.loops.layers.uv:
-            ops_obj.report(
-                {'WARNING'}, "Object must have more than one UV map")
-            return {'CANCELLED'}
-
-        props.verts_orig = [
-            {"vidx": v.index, "vco": v.co.copy(), "moved": False}
-            for v in bm.verts if v.select]
-
-        return {'FINISHED'}
-
-
-class UnlockImpl:
-    @classmethod
-    def poll(cls, context):
-        # we can not get area/space/region from console
-        if common.is_console_mode():
-            return True
-        sc = context.scene
-        props = sc.muv_props.texture_lock
-        if not props.verts_orig:
-            return False
-        if not LockImpl.is_ready(context):
-            return False
-        if not _is_valid_context(context):
-            return False
-        return True
-
-    def execute(self, ops_obj, context):
-        sc = context.scene
-        props = sc.muv_props.texture_lock
-        obj = bpy.context.active_object
-        bm = bmesh.from_edit_mesh(obj.data)
-        if common.check_version(2, 73, 0) >= 0:
-            bm.verts.ensure_lookup_table()
-            bm.edges.ensure_lookup_table()
-            bm.faces.ensure_lookup_table()
-
-        if not bm.loops.layers.uv:
-            ops_obj.report(
-                {'WARNING'}, "Object must have more than one UV map")
-            return {'CANCELLED'}
-        uv_layer = bm.loops.layers.uv.verify()
-
-        verts = [v.index for v in bm.verts if v.select]
-        verts_orig = props.verts_orig
-
-        # move UV followed by vertex coordinate
-        for vidx, v_orig in zip(verts, verts_orig):
-            if vidx != v_orig["vidx"]:
-                ops_obj.report({'ERROR'}, "Internal Error")
-                return {"CANCELLED"}
-
-            v = bm.verts[vidx]
-            link_loops = _get_link_loops(v)
-
-            result = []
-
-            for ll in link_loops:
-                ini_geom = _get_ini_geom(ll, uv_layer, verts_orig, v_orig)
-                target_uv = _get_target_uv(
-                    ll, uv_layer, verts_orig, v, ini_geom)
-                result.append({"l": ll["l"], "uv": target_uv})
-
-            # connect other face's UV
-            if ops_obj.connect:
-                ave = Vector((0.0, 0.0))
-                for r in result:
-                    ave = ave + r["uv"]
-                ave = ave / len(result)
-                for r in result:
-                    r["l"][uv_layer].uv = ave
-            else:
-                for r in result:
-                    r["l"][uv_layer].uv = r["uv"]
-            v_orig["moved"] = True
-            bmesh.update_edit_mesh(obj.data)
-
-        props.verts_orig = None
-
-        return {'FINISHED'}
-
-
-class IntrImpl:
-    __timer = None
-
-    @classmethod
-    def poll(cls, context):
-        # we can not get area/space/region from console
-        if common.is_console_mode():
-            return False
-        return _is_valid_context(context)
-
-    @classmethod
-    def is_running(cls, _):
-        return 1 if cls.__timer else 0
-
-    @classmethod
-    def handle_add(cls, ops_obj, context):
-        if cls.__timer is None:
-            cls.__timer = context.window_manager.event_timer_add(
-                0.10, window=context.window)
-            context.window_manager.modal_handler_add(ops_obj)
-
-    @classmethod
-    def handle_remove(cls, context):
-        if cls.__timer is not None:
-            context.window_manager.event_timer_remove(cls.__timer)
-            cls.__timer = None
-
-    def __init__(self):
-        self.__intr_verts_orig = []
-        self.__intr_verts = []
-
-    def __sel_verts_changed(self, context):
-        obj = context.active_object
-        bm = bmesh.from_edit_mesh(obj.data)
-        if common.check_version(2, 73, 0) >= 0:
-            bm.verts.ensure_lookup_table()
-            bm.edges.ensure_lookup_table()
-            bm.faces.ensure_lookup_table()
-
-        prev = set(self.__intr_verts)
-        now = set([v.index for v in bm.verts if v.select])
-
-        return prev != now
-
-    def __reinit_verts(self, context):
-        obj = context.active_object
-        bm = bmesh.from_edit_mesh(obj.data)
-        if common.check_version(2, 73, 0) >= 0:
-            bm.verts.ensure_lookup_table()
-            bm.edges.ensure_lookup_table()
-            bm.faces.ensure_lookup_table()
-
-        self.__intr_verts_orig = [
-            {"vidx": v.index, "vco": v.co.copy(), "moved": False}
-            for v in bm.verts if v.select]
-        self.__intr_verts = [v.index for v in bm.verts if v.select]
-
-    def __update_uv(self, ops_obj, context):
-        """
-        Update UV when vertex coordinates are changed
-        """
-        obj = context.active_object
-        bm = bmesh.from_edit_mesh(obj.data)
-        if common.check_version(2, 73, 0) >= 0:
-            bm.verts.ensure_lookup_table()
-            bm.edges.ensure_lookup_table()
-            bm.faces.ensure_lookup_table()
-
-        if not bm.loops.layers.uv:
-            ops_obj.report({'WARNING'},
-                           "Object must have more than one UV map")
-            return
-        uv_layer = bm.loops.layers.uv.verify()
-
-        verts = [v.index for v in bm.verts if v.select]
-        verts_orig = self.__intr_verts_orig
-
-        for vidx, v_orig in zip(verts, verts_orig):
-            if vidx != v_orig["vidx"]:
-                ops_obj.report({'ERROR'}, "Internal Error")
-                return
-
-            v = bm.verts[vidx]
-            link_loops = _get_link_loops(v)
-
-            result = []
-            for ll in link_loops:
-                ini_geom = _get_ini_geom(ll, uv_layer, verts_orig, v_orig)
-                target_uv = _get_target_uv(
-                    ll, uv_layer, verts_orig, v, ini_geom)
-                result.append({"l": ll["l"], "uv": target_uv})
-
-            # UV connect option is always true, because it raises
-            # unexpected behavior
-            ave = Vector((0.0, 0.0))
-            for r in result:
-                ave = ave + r["uv"]
-            ave = ave / len(result)
-            for r in result:
-                r["l"][uv_layer].uv = ave
-            v_orig["moved"] = True
-            bmesh.update_edit_mesh(obj.data)
-
-        common.redraw_all_areas()
-        self.__intr_verts_orig = [
-            {"vidx": v.index, "vco": v.co.copy(), "moved": False}
-            for v in bm.verts if v.select]
-
-    def modal(self, ops_obj, context, event):
-        if not _is_valid_context(context):
-            IntrImpl.handle_remove(context)
-            return {'FINISHED'}
-
-        if not IntrImpl.is_running(context):
-            return {'FINISHED'}
-
-        if context.area:
-            context.area.tag_redraw()
-
-        if event.type == 'TIMER':
-            if self.__sel_verts_changed(context):
-                self.__reinit_verts(context)
-            else:
-                self.__update_uv(ops_obj, context)
-
-        return {'PASS_THROUGH'}
-
-    def invoke(self, ops_obj, context, _):
-        if not _is_valid_context(context):
-            return {'CANCELLED'}
-
-        if not IntrImpl.is_running(context):
-            IntrImpl.handle_add(ops_obj, context)
-            return {'RUNNING_MODAL'}
-        else:
-            IntrImpl.handle_remove(context)
-
-        if context.area:
-            context.area.tag_redraw()
-
-        return {'FINISHED'}
diff --git a/uv_magic_uv/impl/texture_projection_impl.py b/uv_magic_uv/impl/texture_projection_impl.py
deleted file mode 100644
index b64fa374825d251527325398efe593d5df466f83..0000000000000000000000000000000000000000
--- a/uv_magic_uv/impl/texture_projection_impl.py
+++ /dev/null
@@ -1,126 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-__author__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-from collections import namedtuple
-
-import bpy
-import mathutils
-
-
-_Rect = namedtuple('Rect', 'x0 y0 x1 y1')
-_Rect2 = namedtuple('Rect2', 'x y width height')
-
-
-def get_loaded_texture_name(_, __):
-    items = [(key, key, "") for key in bpy.data.images.keys()]
-    items.append(("None", "None", ""))
-    return items
-
-
-def get_canvas(context, magnitude):
-    """
-    Get canvas to be renderred texture
-    """
-    sc = context.scene
-    prefs = context.user_preferences.addons["uv_magic_uv"].preferences
-
-    region_w = context.region.width
-    region_h = context.region.height
-    canvas_w = region_w - prefs.texture_projection_canvas_padding[0] * 2.0
-    canvas_h = region_h - prefs.texture_projection_canvas_padding[1] * 2.0
-
-    img = bpy.data.images[sc.muv_texture_projection_tex_image]
-    tex_w = img.size[0]
-    tex_h = img.size[1]
-
-    center_x = region_w * 0.5
-    center_y = region_h * 0.5
-
-    if sc.muv_texture_projection_adjust_window:
-        ratio_x = canvas_w / tex_w
-        ratio_y = canvas_h / tex_h
-        if sc.muv_texture_projection_apply_tex_aspect:
-            ratio = ratio_y if ratio_x > ratio_y else ratio_x
-            len_x = ratio * tex_w
-            len_y = ratio * tex_h
-        else:
-            len_x = canvas_w
-            len_y = canvas_h
-    else:
-        if sc.muv_texture_projection_apply_tex_aspect:
-            len_x = tex_w * magnitude
-            len_y = tex_h * magnitude
-        else:
-            len_x = region_w * magnitude
-            len_y = region_h * magnitude
-
-    x0 = int(center_x - len_x * 0.5)
-    y0 = int(center_y - len_y * 0.5)
-    x1 = int(center_x + len_x * 0.5)
-    y1 = int(center_y + len_y * 0.5)
-
-    return _Rect(x0, y0, x1, y1)
-
-
-def rect_to_rect2(rect):
-    """
-    Convert Rect1 to Rect2
-    """
-
-    return _Rect2(rect.x0, rect.y0, rect.x1 - rect.x0, rect.y1 - rect.y0)
-
-
-def region_to_canvas(rg_vec, canvas):
-    """
-    Convert screen region to canvas
-    """
-
-    cv_rect = rect_to_rect2(canvas)
-    cv_vec = mathutils.Vector()
-    cv_vec.x = (rg_vec.x - cv_rect.x) / cv_rect.width
-    cv_vec.y = (rg_vec.y - cv_rect.y) / cv_rect.height
-
-    return cv_vec
-
-
-def is_valid_context(context):
-    obj = context.object
-
-    # only edit mode is allowed to execute
-    if obj is None:
-        return False
-    if obj.type != 'MESH':
-        return False
-    if context.object.mode != 'EDIT':
-        return False
-
-    # only 'VIEW_3D' space is allowed to execute
-    for space in context.area.spaces:
-        if space.type == 'VIEW_3D':
-            break
-    else:
-        return False
-
-    return True
diff --git a/uv_magic_uv/impl/texture_wrap_impl.py b/uv_magic_uv/impl/texture_wrap_impl.py
deleted file mode 100644
index 336b17608c4127c6ecf1baebfef4fc14c122959b..0000000000000000000000000000000000000000
--- a/uv_magic_uv/impl/texture_wrap_impl.py
+++ /dev/null
@@ -1,236 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-__author__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bmesh
-
-from .. import common
-
-
-def _is_valid_context(context):
-    obj = context.object
-
-    # only edit mode is allowed to execute
-    if obj is None:
-        return False
-    if obj.type != 'MESH':
-        return False
-    if context.object.mode != 'EDIT':
-        return False
-
-    # only 'VIEW_3D' space is allowed to execute
-    for space in context.area.spaces:
-        if space.type == 'VIEW_3D':
-            break
-    else:
-        return False
-
-    return True
-
-
-class ReferImpl:
-    @classmethod
-    def poll(cls, context):
-        # we can not get area/space/region from console
-        if common.is_console_mode():
-            return True
-        return _is_valid_context(context)
-
-    def execute(self, ops_obj, context):
-        props = context.scene.muv_props.texture_wrap
-        obj = context.active_object
-        bm = bmesh.from_edit_mesh(obj.data)
-        if common.check_version(2, 73, 0) >= 0:
-            bm.faces.ensure_lookup_table()
-
-        if not bm.loops.layers.uv:
-            ops_obj.report({'WARNING'},
-                           "Object must have more than one UV map")
-            return {'CANCELLED'}
-
-        sel_faces = [f for f in bm.faces if f.select]
-        if len(sel_faces) != 1:
-            ops_obj.report({'WARNING'}, "Must select only one face")
-            return {'CANCELLED'}
-
-        props.ref_face_index = sel_faces[0].index
-        props.ref_obj = obj
-
-        return {'FINISHED'}
-
-
-class SetImpl:
-    @classmethod
-    def poll(cls, context):
-        # we can not get area/space/region from console
-        if common.is_console_mode():
-            return True
-        sc = context.scene
-        props = sc.muv_props.texture_wrap
-        if not props.ref_obj:
-            return False
-        return _is_valid_context(context)
-
-    def execute(self, ops_obj, context):
-        sc = context.scene
-        props = sc.muv_props.texture_wrap
-        obj = context.active_object
-        bm = bmesh.from_edit_mesh(obj.data)
-        if common.check_version(2, 73, 0) >= 0:
-            bm.faces.ensure_lookup_table()
-
-        if not bm.loops.layers.uv:
-            ops_obj.report({'WARNING'},
-                           "Object must have more than one UV map")
-            return {'CANCELLED'}
-        uv_layer = bm.loops.layers.uv.verify()
-
-        if sc.muv_texture_wrap_selseq:
-            sel_faces = []
-            for hist in bm.select_history:
-                if isinstance(hist, bmesh.types.BMFace) and hist.select:
-                    sel_faces.append(hist)
-            if not sel_faces:
-                ops_obj.report({'WARNING'}, "Must select more than one face")
-                return {'CANCELLED'}
-        else:
-            sel_faces = [f for f in bm.faces if f.select]
-            if len(sel_faces) != 1:
-                ops_obj.report({'WARNING'}, "Must select only one face")
-                return {'CANCELLED'}
-
-        ref_face_index = props.ref_face_index
-        for face in sel_faces:
-            tgt_face_index = face.index
-            if ref_face_index == tgt_face_index:
-                ops_obj.report({'WARNING'}, "Must select different face")
-                return {'CANCELLED'}
-
-            if props.ref_obj != obj:
-                ops_obj.report({'WARNING'}, "Object must be same")
-                return {'CANCELLED'}
-
-            ref_face = bm.faces[ref_face_index]
-            tgt_face = bm.faces[tgt_face_index]
-
-            # get common vertices info
-            common_verts = []
-            for sl in ref_face.loops:
-                for dl in tgt_face.loops:
-                    if sl.vert == dl.vert:
-                        info = {"vert": sl.vert, "ref_loop": sl,
-                                "tgt_loop": dl}
-                        common_verts.append(info)
-                        break
-
-            if len(common_verts) != 2:
-                ops_obj.report({'WARNING'},
-                               "2 vertices must be shared among faces")
-                return {'CANCELLED'}
-
-            # get reference other vertices info
-            ref_other_verts = []
-            for sl in ref_face.loops:
-                for ci in common_verts:
-                    if sl.vert == ci["vert"]:
-                        break
-                else:
-                    info = {"vert": sl.vert, "loop": sl}
-                    ref_other_verts.append(info)
-
-            if not ref_other_verts:
-                ops_obj.report({'WARNING'},
-                               "More than 1 vertex must be unshared")
-                return {'CANCELLED'}
-
-            # get reference info
-            ref_info = {}
-            cv0 = common_verts[0]["vert"].co
-            cv1 = common_verts[1]["vert"].co
-            cuv0 = common_verts[0]["ref_loop"][uv_layer].uv
-            cuv1 = common_verts[1]["ref_loop"][uv_layer].uv
-            ov0 = ref_other_verts[0]["vert"].co
-            ouv0 = ref_other_verts[0]["loop"][uv_layer].uv
-            ref_info["vert_vdiff"] = cv1 - cv0
-            ref_info["uv_vdiff"] = cuv1 - cuv0
-            ref_info["vert_hdiff"], _ = common.diff_point_to_segment(
-                cv0, cv1, ov0)
-            ref_info["uv_hdiff"], _ = common.diff_point_to_segment(
-                cuv0, cuv1, ouv0)
-
-            # get target other vertices info
-            tgt_other_verts = []
-            for dl in tgt_face.loops:
-                for ci in common_verts:
-                    if dl.vert == ci["vert"]:
-                        break
-                else:
-                    info = {"vert": dl.vert, "loop": dl}
-                    tgt_other_verts.append(info)
-
-            if not tgt_other_verts:
-                ops_obj.report({'WARNING'},
-                               "More than 1 vertex must be unshared")
-                return {'CANCELLED'}
-
-            # get target info
-            for info in tgt_other_verts:
-                cv0 = common_verts[0]["vert"].co
-                cv1 = common_verts[1]["vert"].co
-                cuv0 = common_verts[0]["ref_loop"][uv_layer].uv
-                ov = info["vert"].co
-                info["vert_hdiff"], x = common.diff_point_to_segment(
-                    cv0, cv1, ov)
-                info["vert_vdiff"] = x - common_verts[0]["vert"].co
-
-                # calclulate factor
-                fact_h = -info["vert_hdiff"].length / \
-                    ref_info["vert_hdiff"].length
-                fact_v = info["vert_vdiff"].length / \
-                    ref_info["vert_vdiff"].length
-                duv_h = ref_info["uv_hdiff"] * fact_h
-                duv_v = ref_info["uv_vdiff"] * fact_v
-
-                # get target UV
-                info["target_uv"] = cuv0 + duv_h + duv_v
-
-            # apply to common UVs
-            for info in common_verts:
-                info["tgt_loop"][uv_layer].uv = \
-                    info["ref_loop"][uv_layer].uv.copy()
-            # apply to other UVs
-            for info in tgt_other_verts:
-                info["loop"][uv_layer].uv = info["target_uv"]
-
-            common.debug_print("===== Target Other Vertices =====")
-            common.debug_print(tgt_other_verts)
-
-            bmesh.update_edit_mesh(obj.data)
-
-            ref_face_index = tgt_face_index
-
-        if sc.muv_texture_wrap_set_and_refer:
-            props.ref_face_index = tgt_face_index
-
-        return {'FINISHED'}
diff --git a/uv_magic_uv/impl/transfer_uv_impl.py b/uv_magic_uv/impl/transfer_uv_impl.py
deleted file mode 100644
index adc973527f9d6dcd1a49c8a81150e8206917cc18..0000000000000000000000000000000000000000
--- a/uv_magic_uv/impl/transfer_uv_impl.py
+++ /dev/null
@@ -1,330 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-__author__ = "imdjs, Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-from collections import OrderedDict
-
-import bpy
-import bmesh
-
-from .. import common
-
-
-__all__ = [
-    'is_valid_context',
-    'get_uv_layer',
-    'main_parse',
-    'parse_faces',
-    'get_new_shared_faces',
-    'get_other_verts_edges',
-    'get_selected_src_faces',
-    'paste_uv',
-]
-
-
-def is_valid_context(context):
-    obj = context.object
-
-    # only edit mode is allowed to execute
-    if obj is None:
-        return False
-    if obj.type != 'MESH':
-        return False
-    if context.object.mode != 'EDIT':
-        return False
-
-    # only 'VIEW_3D' space is allowed to execute
-    for space in context.area.spaces:
-        if space.type == 'VIEW_3D':
-            break
-    else:
-        return False
-
-    return True
-
-
-def get_uv_layer(ops_obj, bm):
-    # get UV layer
-    if not bm.loops.layers.uv:
-        ops_obj.report({'WARNING'}, "Object must have more than one UV map")
-        return None
-    uv_layer = bm.loops.layers.uv.verify()
-
-    return uv_layer
-
-
-def main_parse(ops_obj, uv_layer, sel_faces, active_face, active_face_nor):
-    all_sorted_faces = OrderedDict()  # This is the main stuff
-
-    used_verts = set()
-    used_edges = set()
-
-    faces_to_parse = []
-
-    # get shared edge of two faces
-    cross_edges = []
-    for edge in active_face.edges:
-        if edge in sel_faces[0].edges and edge in sel_faces[1].edges:
-            cross_edges.append(edge)
-
-    # parse two selected faces
-    if cross_edges and len(cross_edges) == 1:
-        shared_edge = cross_edges[0]
-        vert1 = None
-        vert2 = None
-
-        dot_n = active_face_nor.normalized()
-        edge_vec_1 = (shared_edge.verts[1].co - shared_edge.verts[0].co)
-        edge_vec_len = edge_vec_1.length
-        edge_vec_1 = edge_vec_1.normalized()
-
-        af_center = active_face.calc_center_median()
-        af_vec = shared_edge.verts[0].co + (edge_vec_1 * (edge_vec_len * 0.5))
-        af_vec = (af_vec - af_center).normalized()
-
-        if af_vec.cross(edge_vec_1).dot(dot_n) > 0:
-            vert1 = shared_edge.verts[0]
-            vert2 = shared_edge.verts[1]
-        else:
-            vert1 = shared_edge.verts[1]
-            vert2 = shared_edge.verts[0]
-
-        # get active face stuff and uvs
-        face_stuff = get_other_verts_edges(
-            active_face, vert1, vert2, shared_edge, uv_layer)
-        all_sorted_faces[active_face] = face_stuff
-        used_verts.update(active_face.verts)
-        used_edges.update(active_face.edges)
-
-        # get first selected face stuff and uvs as they share shared_edge
-        second_face = sel_faces[0]
-        if second_face is active_face:
-            second_face = sel_faces[1]
-        face_stuff = get_other_verts_edges(
-            second_face, vert1, vert2, shared_edge, uv_layer)
-        all_sorted_faces[second_face] = face_stuff
-        used_verts.update(second_face.verts)
-        used_edges.update(second_face.edges)
-
-        # first Grow
-        faces_to_parse.append(active_face)
-        faces_to_parse.append(second_face)
-
-    else:
-        ops_obj.report({'WARNING'}, "Two faces should share one edge")
-        return None
-
-    # parse all faces
-    while True:
-        new_parsed_faces = []
-        if not faces_to_parse:
-            break
-        for face in faces_to_parse:
-            face_stuff = all_sorted_faces.get(face)
-            new_faces = parse_faces(face, face_stuff, used_verts, used_edges,
-                                    all_sorted_faces, uv_layer)
-            if new_faces is None:
-                ops_obj.report({'WARNING'}, "More than 2 faces share edge")
-                return None
-
-            new_parsed_faces += new_faces
-        faces_to_parse = new_parsed_faces
-
-    return all_sorted_faces
-
-
-def parse_faces(check_face, face_stuff, used_verts, used_edges,
-                all_sorted_faces, uv_layer):
-    """recurse faces around the new_grow only"""
-
-    new_shared_faces = []
-    for sorted_edge in face_stuff[1]:
-        shared_faces = sorted_edge.link_faces
-        if shared_faces:
-            if len(shared_faces) > 2:
-                bpy.ops.mesh.select_all(action='DESELECT')
-                for face_sel in shared_faces:
-                    face_sel.select = True
-                shared_faces = []
-                return None
-
-            clear_shared_faces = get_new_shared_faces(
-                check_face, sorted_edge, shared_faces, all_sorted_faces.keys())
-            if clear_shared_faces:
-                shared_face = clear_shared_faces[0]
-                # get vertices of the edge
-                vert1 = sorted_edge.verts[0]
-                vert2 = sorted_edge.verts[1]
-
-                common.debug_print(face_stuff[0], vert1, vert2)
-                if face_stuff[0].index(vert1) > face_stuff[0].index(vert2):
-                    vert1 = sorted_edge.verts[1]
-                    vert2 = sorted_edge.verts[0]
-
-                common.debug_print(shared_face.verts, vert1, vert2)
-                new_face_stuff = get_other_verts_edges(
-                    shared_face, vert1, vert2, sorted_edge, uv_layer)
-                all_sorted_faces[shared_face] = new_face_stuff
-                used_verts.update(shared_face.verts)
-                used_edges.update(shared_face.edges)
-
-                if common.is_debug_mode():
-                    shared_face.select = True  # test which faces are parsed
-
-                new_shared_faces.append(shared_face)
-
-    return new_shared_faces
-
-
-def get_new_shared_faces(orig_face, shared_edge, check_faces, used_faces):
-    shared_faces = []
-
-    for face in check_faces:
-        is_shared_edge = shared_edge in face.edges
-        not_used = face not in used_faces
-        not_orig = face is not orig_face
-        not_hide = face.hide is False
-        if is_shared_edge and not_used and not_orig and not_hide:
-            shared_faces.append(face)
-
-    return shared_faces
-
-
-def get_other_verts_edges(face, vert1, vert2, first_edge, uv_layer):
-    face_edges = [first_edge]
-    face_verts = [vert1, vert2]
-    face_loops = []
-
-    other_edges = [edge for edge in face.edges if edge not in face_edges]
-
-    for _ in range(len(other_edges)):
-        found_edge = None
-        # get sorted verts and edges
-        for edge in other_edges:
-            if face_verts[-1] in edge.verts:
-                other_vert = edge.other_vert(face_verts[-1])
-
-                if other_vert not in face_verts:
-                    face_verts.append(other_vert)
-
-                found_edge = edge
-                if found_edge not in face_edges:
-                    face_edges.append(edge)
-                break
-
-        other_edges.remove(found_edge)
-
-    # get sorted uvs
-    for vert in face_verts:
-        for loop in face.loops:
-            if loop.vert is vert:
-                face_loops.append(loop[uv_layer])
-                break
-
-    return [face_verts, face_edges, face_loops]
-
-
-def get_selected_src_faces(ops_obj, bm, uv_layer):
-    topology_copied = []
-
-    # get selected faces
-    active_face = bm.faces.active
-    sel_faces = [face for face in bm.faces if face.select]
-    if len(sel_faces) != 2:
-        ops_obj.report({'WARNING'}, "Two faces must be selected")
-        return None
-    if not active_face or active_face not in sel_faces:
-        ops_obj.report({'WARNING'}, "Two faces must be active")
-        return None
-
-    # parse all faces according to selection
-    active_face_nor = active_face.normal.copy()
-    all_sorted_faces = main_parse(ops_obj, uv_layer, sel_faces, active_face,
-                                  active_face_nor)
-
-    if all_sorted_faces:
-        for face_data in all_sorted_faces.values():
-            edges = face_data[1]
-            uv_loops = face_data[2]
-            uvs = [l.uv.copy() for l in uv_loops]
-            pin_uvs = [l.pin_uv for l in uv_loops]
-            seams = [e.seam for e in edges]
-            topology_copied.append([uvs, pin_uvs, seams])
-    else:
-        return None
-
-    return topology_copied
-
-
-def paste_uv(ops_obj, bm, uv_layer, src_faces, invert_normals, copy_seams):
-    # get selection history
-    all_sel_faces = [e for e in bm.select_history
-                     if isinstance(e, bmesh.types.BMFace) and e.select]
-    if len(all_sel_faces) % 2 != 0:
-        ops_obj.report({'WARNING'}, "Two faces must be selected")
-        return -1
-
-    # parse selection history
-    for i, _ in enumerate(all_sel_faces):
-        if (i == 0) or (i % 2 == 0):
-            continue
-        sel_faces = [all_sel_faces[i - 1], all_sel_faces[i]]
-        active_face = all_sel_faces[i]
-
-        # parse all faces according to selection history
-        active_face_nor = active_face.normal.copy()
-        if invert_normals:
-            active_face_nor.negate()
-        all_sorted_faces = main_parse(ops_obj, uv_layer, sel_faces,
-                                      active_face, active_face_nor)
-
-        if all_sorted_faces:
-            # check amount of copied/pasted faces
-            if len(all_sorted_faces) != len(src_faces):
-                ops_obj.report({'WARNING'},
-                               "Mesh has different amount of faces")
-                return -1
-
-            for j, face_data in enumerate(all_sorted_faces.values()):
-                copied_data = src_faces[j]
-
-                # check amount of copied/pasted verts
-                if len(copied_data[0]) != len(face_data[2]):
-                    bpy.ops.mesh.select_all(action='DESELECT')
-                    # select problematic face
-                    list(all_sorted_faces.keys())[j].select = True
-                    ops_obj.report({'WARNING'},
-                                   "Face have different amount of vertices")
-                    return 0
-
-                for k, (edge, uvloop) in enumerate(zip(face_data[1],
-                                                       face_data[2])):
-                    uvloop.uv = copied_data[0][k]
-                    uvloop.pin_uv = copied_data[1][k]
-                    if copy_seams:
-                        edge.seam = copied_data[2][k]
-        else:
-            return -1
-
-    return 0
diff --git a/uv_magic_uv/impl/unwrap_constraint_impl.py b/uv_magic_uv/impl/unwrap_constraint_impl.py
deleted file mode 100644
index 257197986a47f46e36428f735089239644cb8717..0000000000000000000000000000000000000000
--- a/uv_magic_uv/impl/unwrap_constraint_impl.py
+++ /dev/null
@@ -1,98 +0,0 @@
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-__author__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-import bmesh
-
-from .. import common
-
-
-def _is_valid_context(context):
-    obj = context.object
-
-    # only edit mode is allowed to execute
-    if obj is None:
-        return False
-    if obj.type != 'MESH':
-        return False
-    if context.object.mode != 'EDIT':
-        return False
-
-    # only 'VIEW_3D' space is allowed to execute
-    for space in context.area.spaces:
-        if space.type == 'VIEW_3D':
-            break
-    else:
-        return False
-
-    return True
-
-
-class UnwrapConstraintImpl:
-    @classmethod
-    def poll(cls, context):
-        # we can not get area/space/region from console
-        if common.is_console_mode():
-            return True
-        return _is_valid_context(context)
-
-    def execute(self, ops_obj, context):
-        obj = context.active_object
-        bm = bmesh.from_edit_mesh(obj.data)
-        if common.check_version(2, 73, 0) >= 0:
-            bm.faces.ensure_lookup_table()
-
-        # bpy.ops.uv.unwrap() makes one UV map at least
-        if not bm.loops.layers.uv:
-            ops_obj.report({'WARNING'},
-                           "Object must have more than one UV map")
-            return {'CANCELLED'}
-        uv_layer = bm.loops.layers.uv.verify()
-
-        # get original UV coordinate
-        faces = [f for f in bm.faces if f.select]
-        uv_list = []
-        for f in faces:
-            uvs = [l[uv_layer].uv.copy() for l in f.loops]
-            uv_list.append(uvs)
-
-        # unwrap
-        bpy.ops.uv.unwrap(
-            method=ops_obj.method,
-            fill_holes=ops_obj.fill_holes,
-            correct_aspect=ops_obj.correct_aspect,
-            use_subsurf_data=ops_obj.use_subsurf_data,
-            margin=ops_obj.margin)
-
-        # when U/V-Constraint is checked, revert original coordinate
-        for f, uvs in zip(faces, uv_list):
-            for l, uv in zip(f.loops, uvs):
-                if ops_obj.u_const:
-                    l[uv_layer].uv.x = uv.x
-                if ops_obj.v_const:
-                    l[uv_layer].uv.y = uv.y
-
-        # update mesh
-        bmesh.update_edit_mesh(obj.data)
-
-        return {'FINISHED'}
diff --git a/uv_magic_uv/impl/uv_bounding_box_impl.py b/uv_magic_uv/impl/uv_bounding_box_impl.py
deleted file mode 100644
index bce51f3e863c4d298ccdac2977d862946e09549b..0000000000000000000000000000000000000000
--- a/uv_magic_uv/impl/uv_bounding_box_impl.py
+++ /dev/null
@@ -1,55 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-__author__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-from enum import IntEnum
-import math
-
-import mathutils
-
-
-MAX_VALUE = 100000.0
-
-
-def is_valid_context(context):
-    obj = context.object
-
-    # only edit mode is allowed to execute
-    if obj is None:
-        return False
-    if obj.type != 'MESH':
-        return False
-    if context.object.mode != 'EDIT':
-        return False
-
-    # 'IMAGE_EDITOR' and 'VIEW_3D' space is allowed to execute.
-    # If 'View_3D' space is not allowed, you can't find option in Tool-Shelf
-    # after the execution
-    for space in context.area.spaces:
-        if (space.type == 'IMAGE_EDITOR') or (space.type == 'VIEW_3D'):
-            break
-    else:
-        return False
-
-    return True
diff --git a/uv_magic_uv/impl/uv_inspection_impl.py b/uv_magic_uv/impl/uv_inspection_impl.py
deleted file mode 100644
index caa3aa79ada5d749bc456ad6299209f5c19f1d29..0000000000000000000000000000000000000000
--- a/uv_magic_uv/impl/uv_inspection_impl.py
+++ /dev/null
@@ -1,70 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-__author__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bmesh
-
-from .. import common
-
-
-def is_valid_context(context):
-    obj = context.object
-
-    # only edit mode is allowed to execute
-    if obj is None:
-        return False
-    if obj.type != 'MESH':
-        return False
-    if context.object.mode != 'EDIT':
-        return False
-
-    # 'IMAGE_EDITOR' and 'VIEW_3D' space is allowed to execute.
-    # If 'View_3D' space is not allowed, you can't find option in Tool-Shelf
-    # after the execution
-    for space in context.area.spaces:
-        if (space.type == 'IMAGE_EDITOR') or (space.type == 'VIEW_3D'):
-            break
-    else:
-        return False
-
-    return True
-
-
-def update_uvinsp_info(context):
-    sc = context.scene
-    props = sc.muv_props.uv_inspection
-
-    obj = context.active_object
-    bm = bmesh.from_edit_mesh(obj.data)
-    if common.check_version(2, 73, 0) >= 0:
-        bm.faces.ensure_lookup_table()
-    uv_layer = bm.loops.layers.uv.verify()
-
-    if context.tool_settings.use_uv_select_sync:
-        sel_faces = [f for f in bm.faces]
-    else:
-        sel_faces = [f for f in bm.faces if f.select]
-    props.overlapped_info = common.get_overlapped_uv_info(
-        bm, sel_faces, uv_layer, sc.muv_uv_inspection_show_mode)
-    props.flipped_info = common.get_flipped_uv_info(sel_faces, uv_layer)
diff --git a/uv_magic_uv/impl/uv_sculpt_impl.py b/uv_magic_uv/impl/uv_sculpt_impl.py
deleted file mode 100644
index 284787d8cc2df504a26f0e20aa19b7203aee23a2..0000000000000000000000000000000000000000
--- a/uv_magic_uv/impl/uv_sculpt_impl.py
+++ /dev/null
@@ -1,57 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-__author__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-
-def is_valid_context(context):
-    obj = context.object
-
-    # only edit mode is allowed to execute
-    if obj is None:
-        return False
-    if obj.type != 'MESH':
-        return False
-    if context.object.mode != 'EDIT':
-        return False
-
-    # only 'VIEW_3D' space is allowed to execute
-    for space in context.area.spaces:
-        if space.type == 'VIEW_3D':
-            break
-    else:
-        return False
-
-    return True
-
-
-def get_strength(p, len_, factor):
-    f = factor
-
-    if p > len_:
-        return 0.0
-
-    if p < 0.0:
-        return f
-
-    return (len_ - p) * f / len_
diff --git a/uv_magic_uv/impl/uvw_impl.py b/uv_magic_uv/impl/uvw_impl.py
deleted file mode 100644
index 98da0dc9bb222730ed53f73f719709ec1025053f..0000000000000000000000000000000000000000
--- a/uv_magic_uv/impl/uvw_impl.py
+++ /dev/null
@@ -1,160 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-__author__ = "imdjs, Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-
-from math import sin, cos, pi
-
-from mathutils import Vector
-
-from .. import common
-
-
-def is_valid_context(context):
-    obj = context.object
-
-    # only edit mode is allowed to execute
-    if obj is None:
-        return False
-    if obj.type != 'MESH':
-        return False
-    if context.object.mode != 'EDIT':
-        return False
-
-    # only 'VIEW_3D' space is allowed to execute
-    for space in context.area.spaces:
-        if space.type == 'VIEW_3D':
-            break
-    else:
-        return False
-
-    return True
-
-
-def get_uv_layer(ops_obj, bm, assign_uvmap):
-    # get UV layer
-    if not bm.loops.layers.uv:
-        if assign_uvmap:
-            bm.loops.layers.uv.new()
-        else:
-            ops_obj.report({'WARNING'},
-                           "Object must have more than one UV map")
-            return None
-    uv_layer = bm.loops.layers.uv.verify()
-
-    return uv_layer
-
-
-def apply_box_map(bm, uv_layer, size, offset, rotation, tex_aspect):
-    scale = 1.0 / size
-
-    sx = 1.0 * scale
-    sy = 1.0 * scale
-    sz = 1.0 * scale
-    ofx = offset[0]
-    ofy = offset[1]
-    ofz = offset[2]
-    rx = rotation[0] * pi / 180.0
-    ry = rotation[1] * pi / 180.0
-    rz = rotation[2] * pi / 180.0
-    aspect = tex_aspect
-
-    sel_faces = [f for f in bm.faces if f.select]
-
-    # update UV coordinate
-    for f in sel_faces:
-        n = f.normal
-        for l in f.loops:
-            co = l.vert.co
-            x = co.x * sx
-            y = co.y * sy
-            z = co.z * sz
-
-            # X-plane
-            if abs(n[0]) >= abs(n[1]) and abs(n[0]) >= abs(n[2]):
-                if n[0] >= 0.0:
-                    u = (y - ofy) * cos(rx) + (z - ofz) * sin(rx)
-                    v = -(y * aspect - ofy) * sin(rx) + \
-                        (z * aspect - ofz) * cos(rx)
-                else:
-                    u = -(y - ofy) * cos(rx) + (z - ofz) * sin(rx)
-                    v = (y * aspect - ofy) * sin(rx) + \
-                        (z * aspect - ofz) * cos(rx)
-            # Y-plane
-            elif abs(n[1]) >= abs(n[0]) and abs(n[1]) >= abs(n[2]):
-                if n[1] >= 0.0:
-                    u = -(x - ofx) * cos(ry) + (z - ofz) * sin(ry)
-                    v = (x * aspect - ofx) * sin(ry) + \
-                        (z * aspect - ofz) * cos(ry)
-                else:
-                    u = (x - ofx) * cos(ry) + (z - ofz) * sin(ry)
-                    v = -(x * aspect - ofx) * sin(ry) + \
-                        (z * aspect - ofz) * cos(ry)
-            # Z-plane
-            else:
-                if n[2] >= 0.0:
-                    u = (x - ofx) * cos(rz) + (y - ofy) * sin(rz)
-                    v = -(x * aspect - ofx) * sin(rz) + \
-                        (y * aspect - ofy) * cos(rz)
-                else:
-                    u = -(x - ofx) * cos(rz) - (y + ofy) * sin(rz)
-                    v = -(x * aspect + ofx) * sin(rz) + \
-                        (y * aspect - ofy) * cos(rz)
-
-            l[uv_layer].uv = Vector((u, v))
-
-
-def apply_planer_map(bm, uv_layer, size, offset, rotation, tex_aspect):
-    scale = 1.0 / size
-
-    sx = 1.0 * scale
-    sy = 1.0 * scale
-    ofx = offset[0]
-    ofy = offset[1]
-    rz = rotation * pi / 180.0
-    aspect = tex_aspect
-
-    sel_faces = [f for f in bm.faces if f.select]
-
-    # calculate average of normal
-    n_ave = Vector((0.0, 0.0, 0.0))
-    for f in sel_faces:
-        n_ave = n_ave + f.normal
-    q = n_ave.rotation_difference(Vector((0.0, 0.0, 1.0)))
-
-    # update UV coordinate
-    for f in sel_faces:
-        for l in f.loops:
-            if common.check_version(2, 80, 0) >= 0:
-                # pylint: disable=E0001
-                co = q @ l.vert.co
-            else:
-                co = q * l.vert.co
-            x = co.x * sx
-            y = co.y * sy
-
-            u = x * cos(rz) - y * sin(rz) + ofx
-            v = -x * aspect * sin(rz) - y * aspect * cos(rz) + ofy
-
-            l[uv_layer].uv = Vector((u, v))
diff --git a/uv_magic_uv/impl/world_scale_uv_impl.py b/uv_magic_uv/impl/world_scale_uv_impl.py
deleted file mode 100644
index 3f376f0d6904d6a193d5b38ba049876be086423d..0000000000000000000000000000000000000000
--- a/uv_magic_uv/impl/world_scale_uv_impl.py
+++ /dev/null
@@ -1,383 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-__author__ = "McBuff, Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-from math import sqrt
-
-import bmesh
-from mathutils import Vector
-
-from .. import common
-
-
-def _is_valid_context(context):
-    obj = context.object
-
-    # only edit mode is allowed to execute
-    if obj is None:
-        return False
-    if obj.type != 'MESH':
-        return False
-    if context.object.mode != 'EDIT':
-        return False
-
-    # only 'VIEW_3D' space is allowed to execute
-    for space in context.area.spaces:
-        if space.type == 'VIEW_3D':
-            break
-    else:
-        return False
-
-    return True
-
-
-def _measure_wsuv_info(obj, tex_size=None):
-    mesh_area = common.measure_mesh_area(obj)
-    if common.check_version(2, 80, 0) >= 0:
-        uv_area = common.measure_uv_area(obj, tex_size)
-    else:
-        uv_area = common.measure_uv_area_legacy(obj, tex_size)
-
-    if not uv_area:
-        return None, mesh_area, None
-
-    if mesh_area == 0.0:
-        density = 0.0
-    else:
-        density = sqrt(uv_area) / sqrt(mesh_area)
-
-    return uv_area, mesh_area, density
-
-
-def _apply(obj, origin, factor):
-    bm = bmesh.from_edit_mesh(obj.data)
-    if common.check_version(2, 73, 0) >= 0:
-        bm.verts.ensure_lookup_table()
-        bm.edges.ensure_lookup_table()
-        bm.faces.ensure_lookup_table()
-
-    sel_faces = [f for f in bm.faces if f.select]
-
-    uv_layer = bm.loops.layers.uv.verify()
-
-    # calculate origin
-    if origin == 'CENTER':
-        origin = Vector((0.0, 0.0))
-        num = 0
-        for f in sel_faces:
-            for l in f.loops:
-                uv = l[uv_layer].uv
-                origin = origin + uv
-                num = num + 1
-        origin = origin / num
-    elif origin == 'LEFT_TOP':
-        origin = Vector((100000.0, -100000.0))
-        for f in sel_faces:
-            for l in f.loops:
-                uv = l[uv_layer].uv
-                origin.x = min(origin.x, uv.x)
-                origin.y = max(origin.y, uv.y)
-    elif origin == 'LEFT_CENTER':
-        origin = Vector((100000.0, 0.0))
-        num = 0
-        for f in sel_faces:
-            for l in f.loops:
-                uv = l[uv_layer].uv
-                origin.x = min(origin.x, uv.x)
-                origin.y = origin.y + uv.y
-                num = num + 1
-        origin.y = origin.y / num
-    elif origin == 'LEFT_BOTTOM':
-        origin = Vector((100000.0, 100000.0))
-        for f in sel_faces:
-            for l in f.loops:
-                uv = l[uv_layer].uv
-                origin.x = min(origin.x, uv.x)
-                origin.y = min(origin.y, uv.y)
-    elif origin == 'CENTER_TOP':
-        origin = Vector((0.0, -100000.0))
-        num = 0
-        for f in sel_faces:
-            for l in f.loops:
-                uv = l[uv_layer].uv
-                origin.x = origin.x + uv.x
-                origin.y = max(origin.y, uv.y)
-                num = num + 1
-        origin.x = origin.x / num
-    elif origin == 'CENTER_BOTTOM':
-        origin = Vector((0.0, 100000.0))
-        num = 0
-        for f in sel_faces:
-            for l in f.loops:
-                uv = l[uv_layer].uv
-                origin.x = origin.x + uv.x
-                origin.y = min(origin.y, uv.y)
-                num = num + 1
-        origin.x = origin.x / num
-    elif origin == 'RIGHT_TOP':
-        origin = Vector((-100000.0, -100000.0))
-        for f in sel_faces:
-            for l in f.loops:
-                uv = l[uv_layer].uv
-                origin.x = max(origin.x, uv.x)
-                origin.y = max(origin.y, uv.y)
-    elif origin == 'RIGHT_CENTER':
-        origin = Vector((-100000.0, 0.0))
-        num = 0
-        for f in sel_faces:
-            for l in f.loops:
-                uv = l[uv_layer].uv
-                origin.x = max(origin.x, uv.x)
-                origin.y = origin.y + uv.y
-                num = num + 1
-        origin.y = origin.y / num
-    elif origin == 'RIGHT_BOTTOM':
-        origin = Vector((-100000.0, 100000.0))
-        for f in sel_faces:
-            for l in f.loops:
-                uv = l[uv_layer].uv
-                origin.x = max(origin.x, uv.x)
-                origin.y = min(origin.y, uv.y)
-
-    # update UV coordinate
-    for f in sel_faces:
-        for l in f.loops:
-            uv = l[uv_layer].uv
-            diff = uv - origin
-            l[uv_layer].uv = origin + diff * factor
-
-    bmesh.update_edit_mesh(obj.data)
-
-
-class MeasureImpl:
-    @classmethod
-    def poll(cls, context):
-        # we can not get area/space/region from console
-        if common.is_console_mode():
-            return True
-        return _is_valid_context(context)
-
-    def execute(self, ops_obj, context):
-        sc = context.scene
-        obj = context.active_object
-
-        uv_area, mesh_area, density = _measure_wsuv_info(obj)
-        if not uv_area:
-            ops_obj.report({'WARNING'},
-                           "Object must have more than one UV map and texture")
-            return {'CANCELLED'}
-
-        sc.muv_world_scale_uv_src_uv_area = uv_area
-        sc.muv_world_scale_uv_src_mesh_area = mesh_area
-        sc.muv_world_scale_uv_src_density = density
-
-        ops_obj.report({'INFO'},
-                       "UV Area: {0}, Mesh Area: {1}, Texel Density: {2}"
-                       .format(uv_area, mesh_area, density))
-
-        return {'FINISHED'}
-
-
-class ApplyManualImpl:
-    @classmethod
-    def poll(cls, context):
-        # we can not get area/space/region from console
-        if common.is_console_mode():
-            return True
-        return _is_valid_context(context)
-
-    def __apply_manual(self, ops_obj, context):
-        obj = context.active_object
-        bm = bmesh.from_edit_mesh(obj.data)
-        if common.check_version(2, 73, 0) >= 0:
-            bm.verts.ensure_lookup_table()
-            bm.edges.ensure_lookup_table()
-            bm.faces.ensure_lookup_table()
-
-        tex_size = ops_obj.tgt_texture_size
-        uv_area, _, density = _measure_wsuv_info(obj, tex_size)
-        if not uv_area:
-            ops_obj.report({'WARNING'},
-                           "Object must have more than one UV map")
-            return {'CANCELLED'}
-
-        tgt_density = ops_obj.tgt_density
-        factor = tgt_density / density
-
-        _apply(context.active_object, ops_obj.origin, factor)
-        ops_obj.report({'INFO'}, "Scaling factor: {0}".format(factor))
-
-        return {'FINISHED'}
-
-    def draw(self, ops_obj, _):
-        layout = ops_obj.layout
-
-        layout.prop(ops_obj, "tgt_density")
-        layout.prop(ops_obj, "tgt_texture_size")
-        layout.prop(ops_obj, "origin")
-
-        layout.separator()
-
-    def invoke(self, ops_obj, context, _):
-        if ops_obj.show_dialog:
-            wm = context.window_manager
-            return wm.invoke_props_dialog(ops_obj)
-
-        return ops_obj.execute(context)
-
-    def execute(self, ops_obj, context):
-        return self.__apply_manual(ops_obj, context)
-
-
-class ApplyScalingDensityImpl:
-    @classmethod
-    def poll(cls, context):
-        # we can not get area/space/region from console
-        if common.is_console_mode():
-            return True
-        return _is_valid_context(context)
-
-    def __apply_scaling_density(self, ops_obj, context):
-        obj = context.active_object
-        bm = bmesh.from_edit_mesh(obj.data)
-        if common.check_version(2, 73, 0) >= 0:
-            bm.verts.ensure_lookup_table()
-            bm.edges.ensure_lookup_table()
-            bm.faces.ensure_lookup_table()
-
-        uv_area, _, density = _measure_wsuv_info(obj)
-        if not uv_area:
-            ops_obj.report({'WARNING'},
-                           "Object must have more than one UV map and texture")
-            return {'CANCELLED'}
-
-        tgt_density = ops_obj.src_density * ops_obj.tgt_scaling_factor
-        factor = tgt_density / density
-
-        _apply(context.active_object, ops_obj.origin, factor)
-        ops_obj.report({'INFO'}, "Scaling factor: {0}".format(factor))
-
-        return {'FINISHED'}
-
-    def draw(self, ops_obj, _):
-        layout = ops_obj.layout
-
-        layout.label(text="Source:")
-        col = layout.column()
-        col.prop(ops_obj, "src_density")
-        col.enabled = False
-
-        layout.separator()
-
-        if not ops_obj.same_density:
-            layout.prop(ops_obj, "tgt_scaling_factor")
-        layout.prop(ops_obj, "origin")
-
-        layout.separator()
-
-    def invoke(self, ops_obj, context, _):
-        sc = context.scene
-
-        if ops_obj.show_dialog:
-            wm = context.window_manager
-
-            if ops_obj.same_density:
-                ops_obj.tgt_scaling_factor = 1.0
-            else:
-                ops_obj.tgt_scaling_factor = \
-                    sc.muv_world_scale_uv_tgt_scaling_factor
-                ops_obj.src_density = sc.muv_world_scale_uv_src_density
-
-            return wm.invoke_props_dialog(ops_obj)
-
-        return ops_obj.execute(context)
-
-    def execute(self, ops_obj, context):
-        if ops_obj.same_density:
-            ops_obj.tgt_scaling_factor = 1.0
-
-        return self.__apply_scaling_density(ops_obj, context)
-
-
-class ApplyProportionalToMeshImpl:
-    @classmethod
-    def poll(cls, context):
-        # we can not get area/space/region from console
-        if common.is_console_mode():
-            return True
-        return _is_valid_context(context)
-
-    def __apply_proportional_to_mesh(self, ops_obj, context):
-        obj = context.active_object
-        bm = bmesh.from_edit_mesh(obj.data)
-        if common.check_version(2, 73, 0) >= 0:
-            bm.verts.ensure_lookup_table()
-            bm.edges.ensure_lookup_table()
-            bm.faces.ensure_lookup_table()
-
-        uv_area, mesh_area, density = _measure_wsuv_info(obj)
-        if not uv_area:
-            ops_obj.report({'WARNING'},
-                           "Object must have more than one UV map and texture")
-            return {'CANCELLED'}
-
-        tgt_density = ops_obj.src_density * sqrt(mesh_area) / sqrt(
-            ops_obj.src_mesh_area)
-
-        factor = tgt_density / density
-
-        _apply(context.active_object, ops_obj.origin, factor)
-        ops_obj.report({'INFO'}, "Scaling factor: {0}".format(factor))
-
-        return {'FINISHED'}
-
-    def draw(self, ops_obj, _):
-        layout = ops_obj.layout
-
-        layout.label(text="Source:")
-        col = layout.column(align=True)
-        col.prop(ops_obj, "src_density")
-        col.prop(ops_obj, "src_uv_area")
-        col.prop(ops_obj, "src_mesh_area")
-        col.enabled = False
-
-        layout.separator()
-        layout.prop(ops_obj, "origin")
-
-        layout.separator()
-
-    def invoke(self, ops_obj, context, _):
-        if ops_obj.show_dialog:
-            wm = context.window_manager
-            sc = context.scene
-
-            ops_obj.src_density = sc.muv_world_scale_uv_src_density
-            ops_obj.src_mesh_area = sc.muv_world_scale_uv_src_mesh_area
-
-            return wm.invoke_props_dialog(ops_obj)
-
-        return ops_obj.execute(context)
-
-    def execute(self, ops_obj, context):
-        return self.__apply_proportional_to_mesh(ops_obj, context)
diff --git a/uv_magic_uv/legacy/__init__.py b/uv_magic_uv/legacy/__init__.py
deleted file mode 100644
index 794d02bc0c0c9f380584bc1f290d13395ed65e1b..0000000000000000000000000000000000000000
--- a/uv_magic_uv/legacy/__init__.py
+++ /dev/null
@@ -1,38 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-__author__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-if "bpy" in locals():
-    import importlib
-    importlib.reload(op)
-    importlib.reload(ui)
-    importlib.reload(properites)
-    importlib.reload(preferences)
-else:
-    from . import op
-    from . import ui
-    from . import properites
-    from . import preferences
-
-import bpy
diff --git a/uv_magic_uv/legacy/op/__init__.py b/uv_magic_uv/legacy/op/__init__.py
deleted file mode 100644
index 9535b76d094b148741f5563ad34f356f810cad5a..0000000000000000000000000000000000000000
--- a/uv_magic_uv/legacy/op/__init__.py
+++ /dev/null
@@ -1,74 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-__author__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-if "bpy" in locals():
-    import importlib
-    importlib.reload(align_uv)
-    importlib.reload(align_uv_cursor)
-    importlib.reload(copy_paste_uv)
-    importlib.reload(copy_paste_uv_object)
-    importlib.reload(copy_paste_uv_uvedit)
-    importlib.reload(flip_rotate_uv)
-    importlib.reload(mirror_uv)
-    importlib.reload(move_uv)
-    importlib.reload(pack_uv)
-    importlib.reload(preserve_uv_aspect)
-    importlib.reload(select_uv)
-    importlib.reload(smooth_uv)
-    importlib.reload(texture_lock)
-    importlib.reload(texture_projection)
-    importlib.reload(texture_wrap)
-    importlib.reload(transfer_uv)
-    importlib.reload(unwrap_constraint)
-    importlib.reload(uv_bounding_box)
-    importlib.reload(uv_inspection)
-    importlib.reload(uv_sculpt)
-    importlib.reload(uvw)
-    importlib.reload(world_scale_uv)
-else:
-    from . import align_uv
-    from . import align_uv_cursor
-    from . import copy_paste_uv
-    from . import copy_paste_uv_object
-    from . import copy_paste_uv_uvedit
-    from . import flip_rotate_uv
-    from . import mirror_uv
-    from . import move_uv
-    from . import pack_uv
-    from . import preserve_uv_aspect
-    from . import select_uv
-    from . import smooth_uv
-    from . import texture_lock
-    from . import texture_projection
-    from . import texture_wrap
-    from . import transfer_uv
-    from . import unwrap_constraint
-    from . import uv_bounding_box
-    from . import uv_inspection
-    from . import uv_sculpt
-    from . import uvw
-    from . import world_scale_uv
-
-import bpy
diff --git a/uv_magic_uv/legacy/op/align_uv.py b/uv_magic_uv/legacy/op/align_uv.py
deleted file mode 100644
index a274d583ce7a04cc7b840fb14a27f764047c1ef6..0000000000000000000000000000000000000000
--- a/uv_magic_uv/legacy/op/align_uv.py
+++ /dev/null
@@ -1,231 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-__author__ = "imdjs, Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-from bpy.props import EnumProperty, BoolProperty, FloatProperty
-
-from ...utils.bl_class_registry import BlClassRegistry
-from ...utils.property_class_registry import PropertyClassRegistry
-from ...impl import align_uv_impl as impl
-
-
-@PropertyClassRegistry(legacy=True)
-class _Properties:
-    idname = "align_uv"
-
-    @classmethod
-    def init_props(cls, scene):
-        scene.muv_align_uv_enabled = BoolProperty(
-            name="Align UV Enabled",
-            description="Align UV is enabled",
-            default=False
-        )
-        scene.muv_align_uv_transmission = BoolProperty(
-            name="Transmission",
-            description="Align linked UVs",
-            default=False
-        )
-        scene.muv_align_uv_select = BoolProperty(
-            name="Select",
-            description="Select UVs which are aligned",
-            default=False
-        )
-        scene.muv_align_uv_vertical = BoolProperty(
-            name="Vert-Infl (Vertical)",
-            description="Align vertical direction influenced "
-                        "by mesh vertex proportion",
-            default=False
-        )
-        scene.muv_align_uv_horizontal = BoolProperty(
-            name="Vert-Infl (Horizontal)",
-            description="Align horizontal direction influenced "
-                        "by mesh vertex proportion",
-            default=False
-        )
-        scene.muv_align_uv_mesh_infl = FloatProperty(
-            name="Mesh Influence",
-            description="Influence rate of mesh vertex",
-            min=0.0,
-            max=1.0,
-            default=0.0
-        )
-        scene.muv_align_uv_location = EnumProperty(
-            name="Location",
-            description="Align location",
-            items=[
-                ('LEFT_TOP', "Left/Top", "Align to Left or Top"),
-                ('MIDDLE', "Middle", "Align to middle"),
-                ('RIGHT_BOTTOM', "Right/Bottom", "Align to Right or Bottom")
-            ],
-            default='MIDDLE'
-        )
-
-    @classmethod
-    def del_props(cls, scene):
-        del scene.muv_align_uv_enabled
-        del scene.muv_align_uv_transmission
-        del scene.muv_align_uv_select
-        del scene.muv_align_uv_vertical
-        del scene.muv_align_uv_horizontal
-        del scene.muv_align_uv_mesh_infl
-        del scene.muv_align_uv_location
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_AlignUV_Circle(bpy.types.Operator):
-
-    bl_idname = "uv.muv_align_uv_operator_circle"
-    bl_label = "Align UV (Circle)"
-    bl_description = "Align UV coordinates to Circle"
-    bl_options = {'REGISTER', 'UNDO'}
-
-    transmission = BoolProperty(
-        name="Transmission",
-        description="Align linked UVs",
-        default=False
-    )
-    select = BoolProperty(
-        name="Select",
-        description="Select UVs which are aligned",
-        default=False
-    )
-
-    def __init__(self):
-        self.__impl = impl.CircleImpl()
-
-    @classmethod
-    def poll(cls, context):
-        return impl.CircleImpl.poll(context)
-
-    def execute(self, context):
-        return self.__impl.execute(self, context)
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_AlignUV_Straighten(bpy.types.Operator):
-
-    bl_idname = "uv.muv_align_uv_operator_straighten"
-    bl_label = "Align UV (Straighten)"
-    bl_description = "Straighten UV coordinates"
-    bl_options = {'REGISTER', 'UNDO'}
-
-    transmission = BoolProperty(
-        name="Transmission",
-        description="Align linked UVs",
-        default=False
-    )
-    select = BoolProperty(
-        name="Select",
-        description="Select UVs which are aligned",
-        default=False
-    )
-    vertical = BoolProperty(
-        name="Vert-Infl (Vertical)",
-        description="Align vertical direction influenced "
-                    "by mesh vertex proportion",
-        default=False
-    )
-    horizontal = BoolProperty(
-        name="Vert-Infl (Horizontal)",
-        description="Align horizontal direction influenced "
-                    "by mesh vertex proportion",
-        default=False
-    )
-    mesh_infl = FloatProperty(
-        name="Mesh Influence",
-        description="Influence rate of mesh vertex",
-        min=0.0,
-        max=1.0,
-        default=0.0
-    )
-
-    def __init__(self):
-        self.__impl = impl.StraightenImpl()
-
-    @classmethod
-    def poll(cls, context):
-        return impl.StraightenImpl.poll(context)
-
-    def execute(self, context):
-        return self.__impl.execute(self, context)
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_AlignUV_Axis(bpy.types.Operator):
-
-    bl_idname = "uv.muv_align_uv_operator_axis"
-    bl_label = "Align UV (XY-Axis)"
-    bl_description = "Align UV to XY-axis"
-    bl_options = {'REGISTER', 'UNDO'}
-
-    transmission = BoolProperty(
-        name="Transmission",
-        description="Align linked UVs",
-        default=False
-    )
-    select = BoolProperty(
-        name="Select",
-        description="Select UVs which are aligned",
-        default=False
-    )
-    vertical = BoolProperty(
-        name="Vert-Infl (Vertical)",
-        description="Align vertical direction influenced "
-                    "by mesh vertex proportion",
-        default=False
-    )
-    horizontal = BoolProperty(
-        name="Vert-Infl (Horizontal)",
-        description="Align horizontal direction influenced "
-                    "by mesh vertex proportion",
-        default=False
-    )
-    location = EnumProperty(
-        name="Location",
-        description="Align location",
-        items=[
-            ('LEFT_TOP', "Left/Top", "Align to Left or Top"),
-            ('MIDDLE', "Middle", "Align to middle"),
-            ('RIGHT_BOTTOM', "Right/Bottom", "Align to Right or Bottom")
-        ],
-        default='MIDDLE'
-    )
-    mesh_infl = FloatProperty(
-        name="Mesh Influence",
-        description="Influence rate of mesh vertex",
-        min=0.0,
-        max=1.0,
-        default=0.0
-    )
-
-    def __init__(self):
-        self.__impl = impl.AxisImpl()
-
-    @classmethod
-    def poll(cls, context):
-        return impl.AxisImpl.poll(context)
-
-    def execute(self, context):
-        return self.__impl.execute(self, context)
diff --git a/uv_magic_uv/legacy/op/align_uv_cursor.py b/uv_magic_uv/legacy/op/align_uv_cursor.py
deleted file mode 100644
index 6a08de0b5cab5367c1f3ac927a8958703fca71a4..0000000000000000000000000000000000000000
--- a/uv_magic_uv/legacy/op/align_uv_cursor.py
+++ /dev/null
@@ -1,153 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-__author__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-from mathutils import Vector
-from bpy.props import EnumProperty, BoolProperty, FloatVectorProperty
-
-from ... import common
-from ...utils.bl_class_registry import BlClassRegistry
-from ...utils.property_class_registry import PropertyClassRegistry
-from ...impl import align_uv_cursor_impl as impl
-
-
-@PropertyClassRegistry(legacy=True)
-class _Properties:
-    idname = "align_uv_cursor"
-
-    @classmethod
-    def init_props(cls, scene):
-        def auvc_get_cursor_loc(self):
-            area, _, space = common.get_space_legacy('IMAGE_EDITOR', 'WINDOW',
-                                                     'IMAGE_EDITOR')
-            bd_size = common.get_uvimg_editor_board_size(area)
-            loc = space.cursor_location
-            if bd_size[0] < 0.000001:
-                cx = 0.0
-            else:
-                cx = loc[0] / bd_size[0]
-            if bd_size[1] < 0.000001:
-                cy = 0.0
-            else:
-                cy = loc[1] / bd_size[1]
-            self['muv_align_uv_cursor_cursor_loc'] = Vector((cx, cy))
-            return self.get('muv_align_uv_cursor_cursor_loc', (0.0, 0.0))
-
-        def auvc_set_cursor_loc(self, value):
-            self['muv_align_uv_cursor_cursor_loc'] = value
-            area, _, space = common.get_space_legacy('IMAGE_EDITOR', 'WINDOW',
-                                                     'IMAGE_EDITOR')
-            bd_size = common.get_uvimg_editor_board_size(area)
-            cx = bd_size[0] * value[0]
-            cy = bd_size[1] * value[1]
-            space.cursor_location = Vector((cx, cy))
-
-        scene.muv_align_uv_cursor_enabled = BoolProperty(
-            name="Align UV Cursor Enabled",
-            description="Align UV Cursor is enabled",
-            default=False
-        )
-
-        scene.muv_align_uv_cursor_cursor_loc = FloatVectorProperty(
-            name="UV Cursor Location",
-            size=2,
-            precision=4,
-            soft_min=-1.0,
-            soft_max=1.0,
-            step=1,
-            default=(0.000, 0.000),
-            get=auvc_get_cursor_loc,
-            set=auvc_set_cursor_loc
-        )
-        scene.muv_align_uv_cursor_align_method = EnumProperty(
-            name="Align Method",
-            description="Align Method",
-            default='TEXTURE',
-            items=[
-                ('TEXTURE', "Texture", "Align to texture"),
-                ('UV', "UV", "Align to UV"),
-                ('UV_SEL', "UV (Selected)", "Align to Selected UV")
-            ]
-        )
-
-        scene.muv_uv_cursor_location_enabled = BoolProperty(
-            name="UV Cursor Location Enabled",
-            description="UV Cursor Location is enabled",
-            default=False
-        )
-
-    @classmethod
-    def del_props(cls, scene):
-        del scene.muv_align_uv_cursor_enabled
-        del scene.muv_align_uv_cursor_cursor_loc
-        del scene.muv_align_uv_cursor_align_method
-
-        del scene.muv_uv_cursor_location_enabled
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_AlignUVCursor(bpy.types.Operator):
-
-    bl_idname = "uv.muv_align_uv_cursor_operator"
-    bl_label = "Align UV Cursor"
-    bl_description = "Align cursor to the center of UV island"
-    bl_options = {'REGISTER', 'UNDO'}
-
-    position = EnumProperty(
-        items=(
-            ('CENTER', "Center", "Align to Center"),
-            ('LEFT_TOP', "Left Top", "Align to Left Top"),
-            ('LEFT_MIDDLE', "Left Middle", "Align to Left Middle"),
-            ('LEFT_BOTTOM', "Left Bottom", "Align to Left Bottom"),
-            ('MIDDLE_TOP', "Middle Top", "Align to Middle Top"),
-            ('MIDDLE_BOTTOM', "Middle Bottom", "Align to Middle Bottom"),
-            ('RIGHT_TOP', "Right Top", "Align to Right Top"),
-            ('RIGHT_MIDDLE', "Right Middle", "Align to Right Middle"),
-            ('RIGHT_BOTTOM', "Right Bottom", "Align to Right Bottom")
-        ),
-        name="Position",
-        description="Align position",
-        default='CENTER'
-    )
-    base = EnumProperty(
-        items=(
-            ('TEXTURE', "Texture", "Align based on Texture"),
-            ('UV', "UV", "Align to UV"),
-            ('UV_SEL', "UV (Selected)", "Align to Selected UV")
-        ),
-        name="Base",
-        description="Align base",
-        default='TEXTURE'
-    )
-
-    def __init__(self):
-        self.__impl = impl.AlignUVCursorLegacyImpl()
-
-    @classmethod
-    def poll(cls, context):
-        return impl.AlignUVCursorLegacyImpl.poll(context)
-
-    def execute(self, context):
-        return self.__impl.execute(self, context)
diff --git a/uv_magic_uv/legacy/op/copy_paste_uv.py b/uv_magic_uv/legacy/op/copy_paste_uv.py
deleted file mode 100644
index a8aef017fb2e3c587be00cba29ea169b5775ddff..0000000000000000000000000000000000000000
--- a/uv_magic_uv/legacy/op/copy_paste_uv.py
+++ /dev/null
@@ -1,531 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-__author__ = "Nutti <nutti.metro@gmail.com>, Jace Priester"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-
-import bmesh
-import bpy.utils
-from bpy.props import (
-    StringProperty,
-    BoolProperty,
-    IntProperty,
-    EnumProperty,
-)
-
-from ...impl import copy_paste_uv_impl as impl
-from ... import common
-from ...utils.bl_class_registry import BlClassRegistry
-from ...utils.property_class_registry import PropertyClassRegistry
-
-__all__ = [
-    'Properties',
-    'MUV_OT_CopyPasteUV_CopyUV',
-    'MUV_MT_CopyPasteUV_CopyUV',
-    'MUV_OT_CopyPasteUV_PasteUV',
-    'MUV_MT_CopyPasteUV_PasteUV',
-    'MUV_OT_CopyPasteUV_SelSeqCopyUV',
-    'MUV_MT_CopyPasteUV_SelSeqCopyUV',
-    'MUV_OT_CopyPasteUV_SelSeqPasteUV',
-    'MUV_MT_CopyPasteUV_SelSeqPasteUV',
-]
-
-
-@PropertyClassRegistry(legacy=True)
-class Properties:
-    idname = "copy_paste_uv"
-
-    @classmethod
-    def init_props(cls, scene):
-        class Props():
-            src_info = None
-
-        scene.muv_props.copy_paste_uv = Props()
-        scene.muv_props.copy_paste_uv_selseq = Props()
-
-        scene.muv_copy_paste_uv_enabled = BoolProperty(
-            name="Copy/Paste UV Enabled",
-            description="Copy/Paste UV is enabled",
-            default=False
-        )
-        scene.muv_copy_paste_uv_copy_seams = BoolProperty(
-            name="Seams",
-            description="Copy Seams",
-            default=True
-        )
-        scene.muv_copy_paste_uv_mode = EnumProperty(
-            items=[
-                ('DEFAULT', "Default", "Default Mode"),
-                ('SEL_SEQ', "Selection Sequence", "Selection Sequence Mode")
-            ],
-            name="Copy/Paste UV Mode",
-            description="Copy/Paste UV Mode",
-            default='DEFAULT'
-        )
-        scene.muv_copy_paste_uv_strategy = EnumProperty(
-            name="Strategy",
-            description="Paste Strategy",
-            items=[
-                ('N_N', 'N:N', 'Number of faces must be equal to source'),
-                ('N_M', 'N:M', 'Number of faces must not be equal to source')
-            ],
-            default='N_M'
-        )
-
-    @classmethod
-    def del_props(cls, scene):
-        del scene.muv_props.copy_paste_uv
-        del scene.muv_props.copy_paste_uv_selseq
-        del scene.muv_copy_paste_uv_enabled
-        del scene.muv_copy_paste_uv_copy_seams
-        del scene.muv_copy_paste_uv_mode
-        del scene.muv_copy_paste_uv_strategy
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_CopyPasteUV_CopyUV(bpy.types.Operator):
-    """
-    Operation class: Copy UV coordinate
-    """
-
-    bl_idname = "uv.muv_copy_paste_uv_operator_copy_uv"
-    bl_label = "Copy UV"
-    bl_description = "Copy UV coordinate"
-    bl_options = {'REGISTER', 'UNDO'}
-
-    uv_map = StringProperty(default="__default", options={'HIDDEN'})
-
-    @classmethod
-    def poll(cls, context):
-        # we can not get area/space/region from console
-        if common.is_console_mode():
-            return True
-        return impl.is_valid_context(context)
-
-    def execute(self, context):
-        props = context.scene.muv_props.copy_paste_uv
-        obj = context.active_object
-        bm = common.create_bmesh(obj)
-
-        # get UV layer
-        uv_layers = impl.get_copy_uv_layers(self, bm, self.uv_map)
-        if not uv_layers:
-            return {'CANCELLED'}
-
-        # get selected face
-        src_info = impl.get_src_face_info(self, bm, uv_layers, True)
-        if src_info is None:
-            return {'CANCELLED'}
-        props.src_info = src_info
-
-        face_count = len(props.src_info[list(props.src_info.keys())[0]])
-        self.report({'INFO'}, "{} face(s) are copied".format(face_count))
-
-        return {'FINISHED'}
-
-
-@BlClassRegistry(legacy=True)
-class MUV_MT_CopyPasteUV_CopyUV(bpy.types.Menu):
-    """
-    Menu class: Copy UV coordinate
-    """
-
-    bl_idname = "uv.muv_copy_paste_uv_menu_copy_uv"
-    bl_label = "Copy UV (Menu)"
-    bl_description = "Menu of Copy UV coordinate"
-
-    @classmethod
-    def poll(cls, context):
-        return impl.is_valid_context(context)
-
-    def draw(self, context):
-        layout = self.layout
-        # create sub menu
-        obj = context.active_object
-        bm = common.create_bmesh(obj)
-        uv_maps = bm.loops.layers.uv.keys()
-
-        ops = layout.operator(MUV_OT_CopyPasteUV_CopyUV.bl_idname,
-                              text="[Default]")
-        ops.uv_map = "__default"
-
-        ops = layout.operator(MUV_OT_CopyPasteUV_CopyUV.bl_idname,
-                              text="[All]")
-        ops.uv_map = "__all"
-
-        for m in uv_maps:
-            ops = layout.operator(MUV_OT_CopyPasteUV_CopyUV.bl_idname, text=m)
-            ops.uv_map = m
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_CopyPasteUV_PasteUV(bpy.types.Operator):
-    """
-    Operation class: Paste UV coordinate
-    """
-
-    bl_idname = "uv.muv_copy_paste_uv_operator_paste_uv"
-    bl_label = "Paste UV"
-    bl_description = "Paste UV coordinate"
-    bl_options = {'REGISTER', 'UNDO'}
-
-    uv_map = StringProperty(default="__default", options={'HIDDEN'})
-    strategy = EnumProperty(
-        name="Strategy",
-        description="Paste Strategy",
-        items=[
-            ('N_N', 'N:N', 'Number of faces must be equal to source'),
-            ('N_M', 'N:M', 'Number of faces must not be equal to source')
-        ],
-        default="N_M"
-    )
-    flip_copied_uv = BoolProperty(
-        name="Flip Copied UV",
-        description="Flip Copied UV...",
-        default=False
-    )
-    rotate_copied_uv = IntProperty(
-        default=0,
-        name="Rotate Copied UV",
-        min=0,
-        max=30
-    )
-    copy_seams = BoolProperty(
-        name="Seams",
-        description="Copy Seams",
-        default=True
-    )
-
-    @classmethod
-    def poll(cls, context):
-        # we can not get area/space/region from console
-        if common.is_console_mode():
-            return True
-        sc = context.scene
-        props = sc.muv_props.copy_paste_uv
-        if not props.src_info:
-            return False
-        return impl.is_valid_context(context)
-
-    def execute(self, context):
-        props = context.scene.muv_props.copy_paste_uv
-        if not props.src_info:
-            self.report({'WARNING'}, "Need copy UV at first")
-            return {'CANCELLED'}
-        obj = context.active_object
-        bm = common.create_bmesh(obj)
-
-        # get UV layer
-        uv_layers = impl.get_paste_uv_layers(self, obj, bm, props.src_info,
-                                             self.uv_map)
-        if not uv_layers:
-            return {'CANCELLED'}
-
-        # get selected face
-        dest_info = impl.get_dest_face_info(self, bm, uv_layers,
-                                            props.src_info, self.strategy,
-                                            True)
-        if dest_info is None:
-            return {'CANCELLED'}
-
-        # paste
-        ret = impl.paste_uv(self, bm, props.src_info, dest_info, uv_layers,
-                            self.strategy, self.flip_copied_uv,
-                            self.rotate_copied_uv, self.copy_seams)
-        if ret:
-            return {'CANCELLED'}
-
-        face_count = len(props.src_info[list(dest_info.keys())[0]])
-        self.report({'INFO'}, "{} face(s) are pasted".format(face_count))
-
-        bmesh.update_edit_mesh(obj.data)
-        if self.copy_seams is True:
-            obj.data.show_edge_seams = True
-
-        return {'FINISHED'}
-
-
-@BlClassRegistry(legacy=True)
-class MUV_MT_CopyPasteUV_PasteUV(bpy.types.Menu):
-    """
-    Menu class: Paste UV coordinate
-    """
-
-    bl_idname = "uv.muv_copy_paste_uv_menu_paste_uv"
-    bl_label = "Paste UV (Menu)"
-    bl_description = "Menu of Paste UV coordinate"
-
-    @classmethod
-    def poll(cls, context):
-        sc = context.scene
-        props = sc.muv_props.copy_paste_uv
-        if not props.src_info:
-            return False
-        return impl.is_valid_context(context)
-
-    def draw(self, context):
-        sc = context.scene
-        layout = self.layout
-        # create sub menu
-        obj = context.active_object
-        bm = common.create_bmesh(obj)
-        uv_maps = bm.loops.layers.uv.keys()
-
-        ops = layout.operator(MUV_OT_CopyPasteUV_PasteUV.bl_idname,
-                              text="[Default]")
-        ops.uv_map = "__default"
-        ops.copy_seams = sc.muv_copy_paste_uv_copy_seams
-        ops.strategy = sc.muv_copy_paste_uv_strategy
-
-        ops = layout.operator(MUV_OT_CopyPasteUV_PasteUV.bl_idname,
-                              text="[New]")
-        ops.uv_map = "__new"
-        ops.copy_seams = sc.muv_copy_paste_uv_copy_seams
-        ops.strategy = sc.muv_copy_paste_uv_strategy
-
-        ops = layout.operator(MUV_OT_CopyPasteUV_PasteUV.bl_idname,
-                              text="[All]")
-        ops.uv_map = "__all"
-        ops.copy_seams = sc.muv_copy_paste_uv_copy_seams
-        ops.strategy = sc.muv_copy_paste_uv_strategy
-
-        for m in uv_maps:
-            ops = layout.operator(MUV_OT_CopyPasteUV_PasteUV.bl_idname, text=m)
-            ops.uv_map = m
-            ops.copy_seams = sc.muv_copy_paste_uv_copy_seams
-            ops.strategy = sc.muv_copy_paste_uv_strategy
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_CopyPasteUV_SelSeqCopyUV(bpy.types.Operator):
-    """
-    Operation class: Copy UV coordinate by selection sequence
-    """
-
-    bl_idname = "uv.muv_copy_paste_uv_operator_selseq_copy_uv"
-    bl_label = "Copy UV (Selection Sequence)"
-    bl_description = "Copy UV data by selection sequence"
-    bl_options = {'REGISTER', 'UNDO'}
-
-    uv_map = StringProperty(default="__default", options={'HIDDEN'})
-
-    @classmethod
-    def poll(cls, context):
-        # we can not get area/space/region from console
-        if common.is_console_mode():
-            return True
-        return impl.is_valid_context(context)
-
-    def execute(self, context):
-        props = context.scene.muv_props.copy_paste_uv_selseq
-        obj = context.active_object
-        bm = common.create_bmesh(obj)
-
-        # get UV layer
-        uv_layers = impl.get_copy_uv_layers(self, bm, self.uv_map)
-        if not uv_layers:
-            return {'CANCELLED'}
-
-        # get selected face
-        src_info = impl.get_select_history_src_face_info(self, bm, uv_layers)
-        if src_info is None:
-            return {'CANCELLED'}
-        props.src_info = src_info
-
-        face_count = len(props.src_info[list(props.src_info.keys())[0]])
-        self.report({'INFO'}, "{} face(s) are selected".format(face_count))
-
-        return {'FINISHED'}
-
-
-@BlClassRegistry(legacy=True)
-class MUV_MT_CopyPasteUV_SelSeqCopyUV(bpy.types.Menu):
-    """
-    Menu class: Copy UV coordinate by selection sequence
-    """
-
-    bl_idname = "uv.muv_copy_paste_uv_menu_selseq_copy_uv"
-    bl_label = "Copy UV (Selection Sequence) (Menu)"
-    bl_description = "Menu of Copy UV coordinate by selection sequence"
-
-    @classmethod
-    def poll(cls, context):
-        return impl.is_valid_context(context)
-
-    def draw(self, context):
-        layout = self.layout
-        obj = context.active_object
-        bm = common.create_bmesh(obj)
-        uv_maps = bm.loops.layers.uv.keys()
-
-        ops = layout.operator(MUV_OT_CopyPasteUV_SelSeqCopyUV.bl_idname,
-                              text="[Default]")
-        ops.uv_map = "__default"
-
-        ops = layout.operator(MUV_OT_CopyPasteUV_SelSeqCopyUV.bl_idname,
-                              text="[All]")
-        ops.uv_map = "__all"
-
-        for m in uv_maps:
-            ops = layout.operator(MUV_OT_CopyPasteUV_SelSeqCopyUV.bl_idname,
-                                  text=m)
-            ops.uv_map = m
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_CopyPasteUV_SelSeqPasteUV(bpy.types.Operator):
-    """
-    Operation class: Paste UV coordinate by selection sequence
-    """
-
-    bl_idname = "uv.muv_copy_paste_uv_operator_selseq_paste_uv"
-    bl_label = "Paste UV (Selection Sequence)"
-    bl_description = "Paste UV coordinate by selection sequence"
-    bl_options = {'REGISTER', 'UNDO'}
-
-    uv_map = StringProperty(default="__default", options={'HIDDEN'})
-    strategy = EnumProperty(
-        name="Strategy",
-        description="Paste Strategy",
-        items=[
-            ('N_N', 'N:N', 'Number of faces must be equal to source'),
-            ('N_M', 'N:M', 'Number of faces must not be equal to source')
-        ],
-        default="N_M"
-    )
-    flip_copied_uv = BoolProperty(
-        name="Flip Copied UV",
-        description="Flip Copied UV...",
-        default=False
-    )
-    rotate_copied_uv = IntProperty(
-        default=0,
-        name="Rotate Copied UV",
-        min=0,
-        max=30
-    )
-    copy_seams = BoolProperty(
-        name="Seams",
-        description="Copy Seams",
-        default=True
-    )
-
-    @classmethod
-    def poll(cls, context):
-        # we can not get area/space/region from console
-        if common.is_console_mode():
-            return True
-        sc = context.scene
-        props = sc.muv_props.copy_paste_uv_selseq
-        if not props.src_info:
-            return False
-        return impl.is_valid_context(context)
-
-    def execute(self, context):
-        props = context.scene.muv_props.copy_paste_uv_selseq
-        if not props.src_info:
-            self.report({'WARNING'}, "Need copy UV at first")
-            return {'CANCELLED'}
-        obj = context.active_object
-        bm = common.create_bmesh(obj)
-
-        # get UV layer
-        uv_layers = impl.get_paste_uv_layers(self, obj, bm, props.src_info,
-                                             self.uv_map)
-        if not uv_layers:
-            return {'CANCELLED'}
-
-        # get selected face
-        dest_info = impl.get_select_history_dest_face_info(self, bm, uv_layers,
-                                                           props.src_info,
-                                                           self.strategy)
-        if dest_info is None:
-            return {'CANCELLED'}
-
-        # paste
-        ret = impl.paste_uv(self, bm, props.src_info, dest_info, uv_layers,
-                            self.strategy, self.flip_copied_uv,
-                            self.rotate_copied_uv, self.copy_seams)
-        if ret:
-            return {'CANCELLED'}
-
-        face_count = len(props.src_info[list(dest_info.keys())[0]])
-        self.report({'INFO'}, "{} face(s) are pasted".format(face_count))
-
-        bmesh.update_edit_mesh(obj.data)
-        if self.copy_seams is True:
-            obj.data.show_edge_seams = True
-
-        return {'FINISHED'}
-
-
-@BlClassRegistry(legacy=True)
-class MUV_MT_CopyPasteUV_SelSeqPasteUV(bpy.types.Menu):
-    """
-    Menu class: Paste UV coordinate by selection sequence
-    """
-
-    bl_idname = "uv.muv_copy_paste_uv_menu_selseq_paste_uv"
-    bl_label = "Paste UV (Selection Sequence) (Menu)"
-    bl_description = "Menu of Paste UV coordinate by selection sequence"
-
-    @classmethod
-    def poll(cls, context):
-        sc = context.scene
-        props = sc.muv_props.copy_paste_uv_selseq
-        if not props.src_uvs or not props.src_pin_uvs:
-            return False
-        return impl.is_valid_context(context)
-
-    def draw(self, context):
-        sc = context.scene
-        layout = self.layout
-        # create sub menu
-        obj = context.active_object
-        bm = common.create_bmesh(obj)
-        uv_maps = bm.loops.layers.uv.keys()
-
-        ops = layout.operator(MUV_OT_CopyPasteUV_SelSeqPasteUV.bl_idname,
-                              text="[Default]")
-        ops.uv_map = "__default"
-        ops.copy_seams = sc.muv_copy_paste_uv_copy_seams
-        ops.strategy = sc.muv_copy_paste_uv_strategy
-
-        ops = layout.operator(MUV_OT_CopyPasteUV_SelSeqPasteUV.bl_idname,
-                              text="[New]")
-        ops.uv_map = "__new"
-        ops.copy_seams = sc.muv_copy_paste_uv_copy_seams
-        ops.strategy = sc.muv_copy_paste_uv_strategy
-
-        ops = layout.operator(MUV_OT_CopyPasteUV_SelSeqPasteUV.bl_idname,
-                              text="[All]")
-        ops.uv_map = "__all"
-        ops.copy_seams = sc.muv_copy_paste_uv_copy_seams
-        ops.strategy = sc.muv_copy_paste_uv_strategy
-
-        for m in uv_maps:
-            ops = layout.operator(MUV_OT_CopyPasteUV_SelSeqPasteUV.bl_idname,
-                                  text=m)
-            ops.uv_map = m
-            ops.copy_seams = sc.muv_copy_paste_uv_copy_seams
-            ops.strategy = sc.muv_copy_paste_uv_strategy
diff --git a/uv_magic_uv/legacy/op/copy_paste_uv_object.py b/uv_magic_uv/legacy/op/copy_paste_uv_object.py
deleted file mode 100644
index e09b003b91a96f5ed5fdf5bdcf7499f7f79d8ee2..0000000000000000000000000000000000000000
--- a/uv_magic_uv/legacy/op/copy_paste_uv_object.py
+++ /dev/null
@@ -1,298 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-__author__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bmesh
-import bpy
-from bpy.props import (
-    StringProperty,
-    BoolProperty,
-)
-
-from ...impl import copy_paste_uv_impl as impl
-from ... import common
-from ...utils.bl_class_registry import BlClassRegistry
-from ...utils.property_class_registry import PropertyClassRegistry
-
-__all__ = [
-    'Properties',
-    'MUV_OT_CopyPasteUVObject_CopyUV',
-    'MUV_MT_CopyPasteUVObject_CopyUV',
-    'MUV_OT_CopyPasteUVObject_PasteUV',
-    'MUV_MT_CopyPasteUVObject_PasteUV',
-]
-
-
-def is_valid_context(context):
-    obj = context.object
-
-    # only object mode is allowed to execute
-    if obj is None:
-        return False
-    if obj.type != 'MESH':
-        return False
-    if context.object.mode != 'OBJECT':
-        return False
-
-    # only 'VIEW_3D' space is allowed to execute
-    for space in context.area.spaces:
-        if space.type == 'VIEW_3D':
-            break
-    else:
-        return False
-
-    return True
-
-
-@PropertyClassRegistry(legacy=True)
-class Properties:
-    idname = "copy_paste_uv_object"
-
-    @classmethod
-    def init_props(cls, scene):
-        class Props():
-            src_info = None
-
-        scene.muv_props.copy_paste_uv_object = Props()
-
-        scene.muv_copy_paste_uv_object_copy_seams = BoolProperty(
-            name="Seams",
-            description="Copy Seams",
-            default=True
-        )
-
-    @classmethod
-    def del_props(cls, scene):
-        del scene.muv_props.copy_paste_uv_object
-        del scene.muv_copy_paste_uv_object_copy_seams
-
-
-def memorize_view_3d_mode(fn):
-    def __memorize_view_3d_mode(self, context):
-        mode_orig = bpy.context.object.mode
-        result = fn(self, context)
-        bpy.ops.object.mode_set(mode=mode_orig)
-        return result
-    return __memorize_view_3d_mode
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_CopyPasteUVObject_CopyUV(bpy.types.Operator):
-    """
-    Operation class: Copy UV coordinate among objects
-    """
-
-    bl_idname = "object.muv_copy_paste_uv_object_operator_copy_uv"
-    bl_label = "Copy UV (Among Objects)"
-    bl_description = "Copy UV coordinate (Among Objects)"
-    bl_options = {'REGISTER', 'UNDO'}
-
-    uv_map = StringProperty(default="__default", options={'HIDDEN'})
-
-    @classmethod
-    def poll(cls, context):
-        # we can not get area/space/region from console
-        if common.is_console_mode():
-            return True
-        return is_valid_context(context)
-
-    @memorize_view_3d_mode
-    def execute(self, context):
-        props = context.scene.muv_props.copy_paste_uv_object
-        bpy.ops.object.mode_set(mode='EDIT')
-        obj = context.active_object
-        bm = common.create_bmesh(obj)
-
-        # get UV layer
-        uv_layers = impl.get_copy_uv_layers(self, bm, self.uv_map)
-        if not uv_layers:
-            return {'CANCELLED'}
-
-        # get selected face
-        src_info = impl.get_src_face_info(self, bm, uv_layers)
-        if src_info is None:
-            return {'CANCELLED'}
-        props.src_info = src_info
-
-        self.report({'INFO'},
-                    "{}'s UV coordinates are copied".format(obj.name))
-
-        return {'FINISHED'}
-
-
-@BlClassRegistry(legacy=True)
-class MUV_MT_CopyPasteUVObject_CopyUV(bpy.types.Menu):
-    """
-    Menu class: Copy UV coordinate among objects
-    """
-
-    bl_idname = "object.muv_copy_paste_uv_object_menu_copy_uv"
-    bl_label = "Copy UV (Among Objects) (Menu)"
-    bl_description = "Menu of Copy UV coordinate (Among Objects)"
-
-    @classmethod
-    def poll(cls, context):
-        return is_valid_context(context)
-
-    def draw(self, _):
-        layout = self.layout
-        # create sub menu
-        uv_maps = bpy.context.active_object.data.uv_textures.keys()
-
-        ops = layout.operator(MUV_OT_CopyPasteUVObject_CopyUV.bl_idname,
-                              text="[Default]")
-        ops.uv_map = "__default"
-
-        ops = layout.operator(MUV_OT_CopyPasteUVObject_CopyUV.bl_idname,
-                              text="[All]")
-        ops.uv_map = "__all"
-
-        for m in uv_maps:
-            ops = layout.operator(MUV_OT_CopyPasteUVObject_CopyUV.bl_idname,
-                                  text=m)
-            ops.uv_map = m
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_CopyPasteUVObject_PasteUV(bpy.types.Operator):
-    """
-    Operation class: Paste UV coordinate among objects
-    """
-
-    bl_idname = "object.muv_copy_paste_uv_object_operator_paste_uv"
-    bl_label = "Paste UV (Among Objects)"
-    bl_description = "Paste UV coordinate (Among Objects)"
-    bl_options = {'REGISTER', 'UNDO'}
-
-    uv_map = StringProperty(default="__default", options={'HIDDEN'})
-    copy_seams = BoolProperty(
-        name="Seams",
-        description="Copy Seams",
-        default=True
-    )
-
-    @classmethod
-    def poll(cls, context):
-        # we can not get area/space/region from console
-        if common.is_console_mode():
-            return True
-        sc = context.scene
-        props = sc.muv_props.copy_paste_uv_object
-        if not props.src_info:
-            return False
-        return is_valid_context(context)
-
-    @memorize_view_3d_mode
-    def execute(self, context):
-        props = context.scene.muv_props.copy_paste_uv_object
-        if not props.src_info:
-            self.report({'WARNING'}, "Need copy UV at first")
-            return {'CANCELLED'}
-
-        for o in bpy.data.objects:
-            if not hasattr(o.data, "uv_textures") or not o.select:
-                continue
-
-            bpy.ops.object.mode_set(mode='OBJECT')
-            bpy.context.scene.objects.active = o
-            bpy.ops.object.mode_set(mode='EDIT')
-
-            obj = context.active_object
-            bm = common.create_bmesh(obj)
-
-            # get UV layer
-            uv_layers = impl.get_paste_uv_layers(self, obj, bm, props.src_info,
-                                                 self.uv_map)
-            if not uv_layers:
-                return {'CANCELLED'}
-
-            # get selected face
-            dest_info = impl.get_dest_face_info(self, bm, uv_layers,
-                                                props.src_info, 'N_N')
-            if dest_info is None:
-                return {'CANCELLED'}
-
-            # paste
-            ret = impl.paste_uv(self, bm, props.src_info, dest_info, uv_layers,
-                                'N_N', 0, 0, self.copy_seams)
-            if ret:
-                return {'CANCELLED'}
-
-            bmesh.update_edit_mesh(obj.data)
-            if self.copy_seams is True:
-                obj.data.show_edge_seams = True
-
-            self.report(
-                {'INFO'}, "{}'s UV coordinates are pasted".format(obj.name))
-
-        return {'FINISHED'}
-
-
-@BlClassRegistry(legacy=True)
-class MUV_MT_CopyPasteUVObject_PasteUV(bpy.types.Menu):
-    """
-    Menu class: Paste UV coordinate among objects
-    """
-
-    bl_idname = "object.muv_copy_paste_uv_object_menu_paste_uv"
-    bl_label = "Paste UV (Among Objects) (Menu)"
-    bl_description = "Menu of Paste UV coordinate (Among Objects)"
-
-    @classmethod
-    def poll(cls, context):
-        sc = context.scene
-        props = sc.muv_props.copy_paste_uv_object
-        if not props.src_info:
-            return False
-        return is_valid_context(context)
-
-    def draw(self, context):
-        sc = context.scene
-        layout = self.layout
-        # create sub menu
-        uv_maps = []
-        for obj in bpy.data.objects:
-            if hasattr(obj.data, "uv_textures") and obj.select:
-                uv_maps.extend(obj.data.uv_textures.keys())
-
-        ops = layout.operator(MUV_OT_CopyPasteUVObject_PasteUV.bl_idname,
-                              text="[Default]")
-        ops.uv_map = "__default"
-        ops.copy_seams = sc.muv_copy_paste_uv_object_copy_seams
-
-        ops = layout.operator(MUV_OT_CopyPasteUVObject_PasteUV.bl_idname,
-                              text="[New]")
-        ops.uv_map = "__new"
-        ops.copy_seams = sc.muv_copy_paste_uv_object_copy_seams
-
-        ops = layout.operator(MUV_OT_CopyPasteUVObject_PasteUV.bl_idname,
-                              text="[All]")
-        ops.uv_map = "__all"
-        ops.copy_seams = sc.muv_copy_paste_uv_object_copy_seams
-
-        for m in uv_maps:
-            ops = layout.operator(MUV_OT_CopyPasteUVObject_PasteUV.bl_idname,
-                                  text=m)
-            ops.uv_map = m
-            ops.copy_seams = sc.muv_copy_paste_uv_object_copy_seams
diff --git a/uv_magic_uv/legacy/op/copy_paste_uv_uvedit.py b/uv_magic_uv/legacy/op/copy_paste_uv_uvedit.py
deleted file mode 100644
index bb72d42a1b83708e2608e2db810a4c89bca103c5..0000000000000000000000000000000000000000
--- a/uv_magic_uv/legacy/op/copy_paste_uv_uvedit.py
+++ /dev/null
@@ -1,97 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-__author__ = "imdjs, Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-
-from ...utils.bl_class_registry import BlClassRegistry
-from ...utils.property_class_registry import PropertyClassRegistry
-from ...impl import copy_paste_uv_uvedit_impl as impl
-
-
-__all__ = [
-    'Properties',
-    'MUV_OT_CopyPasteUVUVEdit_CopyUV',
-    'MUV_OT_CopyPasteUVUVEdit_PasteUV',
-]
-
-
-@PropertyClassRegistry(legacy=True)
-class Properties:
-    idname = "copy_paste_uv_uvedit"
-
-    @classmethod
-    def init_props(cls, scene):
-        class Props():
-            src_uvs = None
-
-        scene.muv_props.copy_paste_uv_uvedit = Props()
-
-    @classmethod
-    def del_props(cls, scene):
-        del scene.muv_props.copy_paste_uv_uvedit
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_CopyPasteUVUVEdit_CopyUV(bpy.types.Operator):
-    """
-    Operation class: Copy UV coordinate on UV/Image Editor
-    """
-
-    bl_idname = "uv.muv_copy_paste_uv_uvedit_operator_copy_uv"
-    bl_label = "Copy UV (UV/Image Editor)"
-    bl_description = "Copy UV coordinate (only selected in UV/Image Editor)"
-    bl_options = {'REGISTER', 'UNDO'}
-
-    def __init__(self):
-        self.__impl = impl.CopyUVImpl()
-
-    @classmethod
-    def poll(cls, context):
-        return impl.CopyUVImpl.poll(context)
-
-    def execute(self, context):
-        return self.__impl.execute(self, context)
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_CopyPasteUVUVEdit_PasteUV(bpy.types.Operator):
-    """
-    Operation class: Paste UV coordinate on UV/Image Editor
-    """
-
-    bl_idname = "uv.muv_copy_paste_uv_uvedit_operator_paste_uv"
-    bl_label = "Paste UV (UV/Image Editor)"
-    bl_description = "Paste UV coordinate (only selected in UV/Image Editor)"
-    bl_options = {'REGISTER', 'UNDO'}
-
-    def __init__(self):
-        self.__impl = impl.PasteUVImpl()
-
-    @classmethod
-    def poll(cls, context):
-        return impl.PasteUVImpl.poll(context)
-
-    def execute(self, context):
-        return self.__impl.execute(self, context)
diff --git a/uv_magic_uv/legacy/op/flip_rotate_uv.py b/uv_magic_uv/legacy/op/flip_rotate_uv.py
deleted file mode 100644
index d94e4808c269ce75460fa4686a93ce93099ff143..0000000000000000000000000000000000000000
--- a/uv_magic_uv/legacy/op/flip_rotate_uv.py
+++ /dev/null
@@ -1,132 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-__author__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-import bmesh
-from bpy.props import (
-    BoolProperty,
-    IntProperty,
-)
-
-from ... import common
-from ...utils.bl_class_registry import BlClassRegistry
-from ...utils.property_class_registry import PropertyClassRegistry
-from ...impl import flip_rotate_impl as impl
-
-__all__ = [
-    'Properties',
-    'MUV_OT_FlipRotate',
-]
-
-
-@PropertyClassRegistry(legacy=True)
-class Properties:
-    idname = "flip_rotate_uv"
-
-    @classmethod
-    def init_props(cls, scene):
-        scene.muv_flip_rotate_uv_enabled = BoolProperty(
-            name="Flip/Rotate UV Enabled",
-            description="Flip/Rotate UV is enabled",
-            default=False
-        )
-        scene.muv_flip_rotate_uv_seams = BoolProperty(
-            name="Seams",
-            description="Seams",
-            default=True
-        )
-
-    @classmethod
-    def del_props(cls, scene):
-        del scene.muv_flip_rotate_uv_enabled
-        del scene.muv_flip_rotate_uv_seams
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_FlipRotate(bpy.types.Operator):
-    """
-    Operation class: Flip and Rotate UV coordinate
-    """
-
-    bl_idname = "uv.muv_flip_rotate_uv_operator"
-    bl_label = "Flip/Rotate UV"
-    bl_description = "Flip/Rotate UV coordinate"
-    bl_options = {'REGISTER', 'UNDO'}
-
-    flip = BoolProperty(
-        name="Flip UV",
-        description="Flip UV...",
-        default=False
-    )
-    rotate = IntProperty(
-        default=0,
-        name="Rotate UV",
-        min=0,
-        max=30
-    )
-    seams = BoolProperty(
-        name="Seams",
-        description="Seams",
-        default=True
-    )
-
-    @classmethod
-    def poll(cls, context):
-        # we can not get area/space/region from console
-        if common.is_console_mode():
-            return True
-        return impl.is_valid_context(context)
-
-    def execute(self, context):
-        self.report({'INFO'}, "Flip/Rotate UV")
-        obj = context.active_object
-        bm = bmesh.from_edit_mesh(obj.data)
-        if common.check_version(2, 73, 0) >= 0:
-            bm.faces.ensure_lookup_table()
-
-        # get UV layer
-        uv_layer = impl.get_uv_layer(self, bm)
-        if not uv_layer:
-            return {'CANCELLED'}
-
-        # get selected face
-        src_info = impl.get_src_face_info(self, bm, [uv_layer], True)
-        if not src_info:
-            return {'CANCELLED'}
-
-        face_count = len(src_info[list(src_info.keys())[0]])
-        self.report({'INFO'}, "{} face(s) are selected".format(face_count))
-
-        # paste
-        ret = impl.paste_uv(self, bm, src_info, src_info, [uv_layer], 'N_N',
-                            self.flip, self.rotate, self.seams)
-        if ret:
-            return {'CANCELLED'}
-
-        bmesh.update_edit_mesh(obj.data)
-        if self.seams is True:
-            obj.data.show_edge_seams = True
-
-        return {'FINISHED'}
diff --git a/uv_magic_uv/legacy/op/mirror_uv.py b/uv_magic_uv/legacy/op/mirror_uv.py
deleted file mode 100644
index e869e5e8ab964f5ef9c52347643398f0315713a2..0000000000000000000000000000000000000000
--- a/uv_magic_uv/legacy/op/mirror_uv.py
+++ /dev/null
@@ -1,110 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-__author__ = "Keith (Wahooney) Boshoff, Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-from bpy.props import (
-    EnumProperty,
-    FloatProperty,
-    BoolProperty,
-)
-
-from ...utils.bl_class_registry import BlClassRegistry
-from ...utils.property_class_registry import PropertyClassRegistry
-from ...impl import mirror_uv_impl as impl
-
-
-__all__ = [
-    'Properties',
-    'MUV_OT_MirrorUV',
-]
-
-
-@PropertyClassRegistry(legacy=True)
-class Properties:
-    idname = "mirror_uv"
-
-    @classmethod
-    def init_props(cls, scene):
-        scene.muv_mirror_uv_enabled = BoolProperty(
-            name="Mirror UV Enabled",
-            description="Mirror UV is enabled",
-            default=False
-        )
-        scene.muv_mirror_uv_axis = EnumProperty(
-            items=[
-                ('X', "X", "Mirror Along X axis"),
-                ('Y', "Y", "Mirror Along Y axis"),
-                ('Z', "Z", "Mirror Along Z axis")
-            ],
-            name="Axis",
-            description="Mirror Axis",
-            default='X'
-        )
-
-    @classmethod
-    def del_props(cls, scene):
-        del scene.muv_mirror_uv_enabled
-        del scene.muv_mirror_uv_axis
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_MirrorUV(bpy.types.Operator):
-    """
-    Operation class: Mirror UV
-    """
-
-    bl_idname = "uv.muv_mirror_uv_operator"
-    bl_label = "Mirror UV"
-    bl_options = {'REGISTER', 'UNDO'}
-
-    axis = EnumProperty(
-        items=(
-            ('X', "X", "Mirror Along X axis"),
-            ('Y', "Y", "Mirror Along Y axis"),
-            ('Z', "Z", "Mirror Along Z axis")
-        ),
-        name="Axis",
-        description="Mirror Axis",
-        default='X'
-    )
-    error = FloatProperty(
-        name="Error",
-        description="Error threshold",
-        default=0.001,
-        min=0.0,
-        max=100.0,
-        soft_min=0.0,
-        soft_max=1.0
-    )
-
-    def __init__(self):
-        self.__impl = impl.MirrorUVImpl()
-
-    @classmethod
-    def poll(cls, context):
-        return impl.MirrorUVImpl.poll(context)
-
-    def execute(self, context):
-        return self.__impl.execute(self, context)
diff --git a/uv_magic_uv/legacy/op/move_uv.py b/uv_magic_uv/legacy/op/move_uv.py
deleted file mode 100644
index 2988c2ce6cf699e551d05ef71f8cd35d0e67a544..0000000000000000000000000000000000000000
--- a/uv_magic_uv/legacy/op/move_uv.py
+++ /dev/null
@@ -1,82 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-__author__ = "kgeogeo, mem, Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-from bpy.props import BoolProperty
-
-from ...impl import move_uv_impl as impl
-from ...utils.bl_class_registry import BlClassRegistry
-from ...utils.property_class_registry import PropertyClassRegistry
-
-
-__all__ = [
-    'Properties',
-    'MUV_OT_MoveUV',
-]
-
-
-@PropertyClassRegistry(legacy=True)
-class Properties:
-    idname = "move_uv"
-
-    @classmethod
-    def init_props(cls, scene):
-        scene.muv_move_uv_enabled = BoolProperty(
-            name="Move UV Enabled",
-            description="Move UV is enabled",
-            default=False
-        )
-
-    @classmethod
-    def del_props(cls, scene):
-        del scene.muv_move_uv_enabled
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_MoveUV(bpy.types.Operator):
-    """
-    Operator class: Move UV
-    """
-
-    bl_idname = "uv.muv_move_uv_operator"
-    bl_label = "Move UV"
-    bl_options = {'REGISTER', 'UNDO'}
-
-    def __init__(self):
-        self.__impl = impl.MoveUVImpl()
-
-    @classmethod
-    def poll(cls, context):
-        return impl.MoveUVImpl.poll(context)
-
-    @classmethod
-    def is_running(cls, _):
-        return impl.MoveUVImpl.is_running(_)
-
-    def modal(self, context, event):
-        return self.__impl.modal(self, context, event)
-
-    def execute(self, context):
-        return self.__impl.execute(self, context)
diff --git a/uv_magic_uv/legacy/op/pack_uv.py b/uv_magic_uv/legacy/op/pack_uv.py
deleted file mode 100644
index f2e1a190fce96cf8c6a6cf55266e9f7ce5c257ad..0000000000000000000000000000000000000000
--- a/uv_magic_uv/legacy/op/pack_uv.py
+++ /dev/null
@@ -1,129 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-__author__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-from bpy.props import (
-    FloatProperty,
-    FloatVectorProperty,
-    BoolProperty,
-)
-
-from ...utils.bl_class_registry import BlClassRegistry
-from ...utils.property_class_registry import PropertyClassRegistry
-from ...impl import pack_uv_impl as impl
-
-
-__all__ = [
-    'Properties',
-    'MUV_OT_PackUV',
-]
-
-
-@PropertyClassRegistry(legacy=True)
-class Properties:
-    idname = "pack_uv"
-
-    @classmethod
-    def init_props(cls, scene):
-        scene.muv_pack_uv_enabled = BoolProperty(
-            name="Pack UV Enabled",
-            description="Pack UV is enabled",
-            default=False
-        )
-        scene.muv_pack_uv_allowable_center_deviation = FloatVectorProperty(
-            name="Allowable Center Deviation",
-            description="Allowable center deviation to judge same UV island",
-            min=0.000001,
-            max=0.1,
-            default=(0.001, 0.001),
-            size=2
-        )
-        scene.muv_pack_uv_allowable_size_deviation = FloatVectorProperty(
-            name="Allowable Size Deviation",
-            description="Allowable sizse deviation to judge same UV island",
-            min=0.000001,
-            max=0.1,
-            default=(0.001, 0.001),
-            size=2
-        )
-
-    @classmethod
-    def del_props(cls, scene):
-        del scene.muv_pack_uv_enabled
-        del scene.muv_pack_uv_allowable_center_deviation
-        del scene.muv_pack_uv_allowable_size_deviation
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_PackUV(bpy.types.Operator):
-    """
-    Operation class: Pack UV with same UV islands are integrated
-    Island matching algorithm
-     - Same center of UV island
-     - Same size of UV island
-     - Same number of UV
-    """
-
-    bl_idname = "uv.muv_pack_uv_operator"
-    bl_label = "Pack UV"
-    bl_description = "Pack UV (Same UV Islands are integrated)"
-    bl_options = {'REGISTER', 'UNDO'}
-
-    rotate = BoolProperty(
-        name="Rotate",
-        description="Rotate option used by default pack UV function",
-        default=False)
-    margin = FloatProperty(
-        name="Margin",
-        description="Margin used by default pack UV function",
-        min=0,
-        max=1,
-        default=0.001)
-    allowable_center_deviation = FloatVectorProperty(
-        name="Allowable Center Deviation",
-        description="Allowable center deviation to judge same UV island",
-        min=0.000001,
-        max=0.1,
-        default=(0.001, 0.001),
-        size=2
-    )
-    allowable_size_deviation = FloatVectorProperty(
-        name="Allowable Size Deviation",
-        description="Allowable sizse deviation to judge same UV island",
-        min=0.000001,
-        max=0.1,
-        default=(0.001, 0.001),
-        size=2
-    )
-
-    def __init__(self):
-        self.__impl = impl.PackUVImpl()
-
-    @classmethod
-    def poll(cls, context):
-        return impl.PackUVImpl.poll(context)
-
-    def execute(self, context):
-        return self.__impl.execute(self, context)
diff --git a/uv_magic_uv/legacy/op/preserve_uv_aspect.py b/uv_magic_uv/legacy/op/preserve_uv_aspect.py
deleted file mode 100644
index c6693e9ae7c9ca6274955659d06ed738b1c5e55d..0000000000000000000000000000000000000000
--- a/uv_magic_uv/legacy/op/preserve_uv_aspect.py
+++ /dev/null
@@ -1,124 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-__author__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-from bpy.props import StringProperty, EnumProperty, BoolProperty
-
-from ...utils.bl_class_registry import BlClassRegistry
-from ...utils.property_class_registry import PropertyClassRegistry
-from ...impl import preserve_uv_aspect_impl as impl
-
-
-__all__ = [
-    'Properties',
-    'MUV_OT_PreserveUVAspect',
-]
-
-
-@PropertyClassRegistry(legacy=True)
-class Properties:
-    idname = "preserve_uv_aspect"
-
-    @classmethod
-    def init_props(cls, scene):
-        def get_loaded_texture_name(_, __):
-            items = [(key, key, "") for key in bpy.data.images.keys()]
-            items.append(("None", "None", ""))
-            return items
-
-        scene.muv_preserve_uv_aspect_enabled = BoolProperty(
-            name="Preserve UV Aspect Enabled",
-            description="Preserve UV Aspect is enabled",
-            default=False
-        )
-        scene.muv_preserve_uv_aspect_tex_image = EnumProperty(
-            name="Image",
-            description="Texture Image",
-            items=get_loaded_texture_name
-        )
-        scene.muv_preserve_uv_aspect_origin = EnumProperty(
-            name="Origin",
-            description="Aspect Origin",
-            items=[
-                ('CENTER', 'Center', 'Center'),
-                ('LEFT_TOP', 'Left Top', 'Left Bottom'),
-                ('LEFT_CENTER', 'Left Center', 'Left Center'),
-                ('LEFT_BOTTOM', 'Left Bottom', 'Left Bottom'),
-                ('CENTER_TOP', 'Center Top', 'Center Top'),
-                ('CENTER_BOTTOM', 'Center Bottom', 'Center Bottom'),
-                ('RIGHT_TOP', 'Right Top', 'Right Top'),
-                ('RIGHT_CENTER', 'Right Center', 'Right Center'),
-                ('RIGHT_BOTTOM', 'Right Bottom', 'Right Bottom')
-
-            ],
-            default="CENTER"
-        )
-
-    @classmethod
-    def del_props(cls, scene):
-        del scene.muv_preserve_uv_aspect_enabled
-        del scene.muv_preserve_uv_aspect_tex_image
-        del scene.muv_preserve_uv_aspect_origin
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_PreserveUVAspect(bpy.types.Operator):
-    """
-    Operation class: Preserve UV Aspect
-    """
-
-    bl_idname = "uv.muv_preserve_uv_aspect_operator"
-    bl_label = "Preserve UV Aspect"
-    bl_description = "Choose Image"
-    bl_options = {'REGISTER', 'UNDO'}
-
-    dest_img_name = StringProperty(options={'HIDDEN'})
-    origin = EnumProperty(
-        name="Origin",
-        description="Aspect Origin",
-        items=[
-            ('CENTER', 'Center', 'Center'),
-            ('LEFT_TOP', 'Left Top', 'Left Bottom'),
-            ('LEFT_CENTER', 'Left Center', 'Left Center'),
-            ('LEFT_BOTTOM', 'Left Bottom', 'Left Bottom'),
-            ('CENTER_TOP', 'Center Top', 'Center Top'),
-            ('CENTER_BOTTOM', 'Center Bottom', 'Center Bottom'),
-            ('RIGHT_TOP', 'Right Top', 'Right Top'),
-            ('RIGHT_CENTER', 'Right Center', 'Right Center'),
-            ('RIGHT_BOTTOM', 'Right Bottom', 'Right Bottom')
-
-        ],
-        default="CENTER"
-    )
-
-    def __init__(self):
-        self.__impl = impl.PreserveUVAspectLegacyImpl()
-
-    @classmethod
-    def poll(cls, context):
-        return impl.PreserveUVAspectLegacyImpl.poll(context)
-
-    def execute(self, context):
-        return self.__impl.execute(self, context)
diff --git a/uv_magic_uv/legacy/op/select_uv.py b/uv_magic_uv/legacy/op/select_uv.py
deleted file mode 100644
index c4a7639d0ad14a8890b57fb5f7e68fddbf6439c1..0000000000000000000000000000000000000000
--- a/uv_magic_uv/legacy/op/select_uv.py
+++ /dev/null
@@ -1,92 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-__author__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-from bpy.props import BoolProperty
-
-from ...utils.bl_class_registry import BlClassRegistry
-from ...utils.property_class_registry import PropertyClassRegistry
-from ...impl import select_uv_impl as impl
-
-
-@PropertyClassRegistry(legacy=True)
-class _Properties:
-    idname = "select_uv"
-
-    @classmethod
-    def init_props(cls, scene):
-        scene.muv_select_uv_enabled = BoolProperty(
-            name="Select UV Enabled",
-            description="Select UV is enabled",
-            default=False
-        )
-
-    @classmethod
-    def del_props(cls, scene):
-        del scene.muv_select_uv_enabled
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_SelectUV_SelectOverlapped(bpy.types.Operator):
-    """
-    Operation class: Select faces which have overlapped UVs
-    """
-
-    bl_idname = "uv.muv_select_uv_operator_select_overlapped"
-    bl_label = "Overlapped"
-    bl_description = "Select faces which have overlapped UVs"
-    bl_options = {'REGISTER', 'UNDO'}
-
-    def __init__(self):
-        self.__impl = impl.SelectOverlappedImpl()
-
-    @classmethod
-    def poll(cls, context):
-        return impl.SelectOverlappedImpl.poll(context)
-
-    def execute(self, context):
-        return self.__impl.execute(self, context)
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_SelectUV_SelectFlipped(bpy.types.Operator):
-    """
-    Operation class: Select faces which have flipped UVs
-    """
-
-    bl_idname = "uv.muv_select_uv_operator_select_flipped"
-    bl_label = "Flipped"
-    bl_description = "Select faces which have flipped UVs"
-    bl_options = {'REGISTER', 'UNDO'}
-
-    def __init__(self):
-        self.__impl = impl.SelectFlippedImpl()
-
-    @classmethod
-    def poll(cls, context):
-        return impl.SelectFlippedImpl.poll(context)
-
-    def execute(self, context):
-        return self.__impl.execute(self, context)
diff --git a/uv_magic_uv/legacy/op/smooth_uv.py b/uv_magic_uv/legacy/op/smooth_uv.py
deleted file mode 100644
index 2e80e98c806c52dff2e3cbf084c51dbcd0a92dea..0000000000000000000000000000000000000000
--- a/uv_magic_uv/legacy/op/smooth_uv.py
+++ /dev/null
@@ -1,105 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-__author__ = "imdjs, Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-from bpy.props import BoolProperty, FloatProperty
-
-from ...utils.bl_class_registry import BlClassRegistry
-from ...utils.property_class_registry import PropertyClassRegistry
-from ...impl import smooth_uv_impl as impl
-
-
-@PropertyClassRegistry(legacy=True)
-class _Properties:
-    idname = "smooth_uv"
-
-    @classmethod
-    def init_props(cls, scene):
-        scene.muv_smooth_uv_enabled = BoolProperty(
-            name="Smooth UV Enabled",
-            description="Smooth UV is enabled",
-            default=False
-        )
-        scene.muv_smooth_uv_transmission = BoolProperty(
-            name="Transmission",
-            description="Smooth linked UVs",
-            default=False
-        )
-        scene.muv_smooth_uv_mesh_infl = FloatProperty(
-            name="Mesh Influence",
-            description="Influence rate of mesh vertex",
-            min=0.0,
-            max=1.0,
-            default=0.0
-        )
-        scene.muv_smooth_uv_select = BoolProperty(
-            name="Select",
-            description="Select UVs which are smoothed",
-            default=False
-        )
-
-    @classmethod
-    def del_props(cls, scene):
-        del scene.muv_smooth_uv_enabled
-        del scene.muv_smooth_uv_transmission
-        del scene.muv_smooth_uv_mesh_infl
-        del scene.muv_smooth_uv_select
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_SmoothUV(bpy.types.Operator):
-
-    bl_idname = "uv.muv_smooth_uv_operator"
-    bl_label = "Smooth"
-    bl_description = "Smooth UV coordinates"
-    bl_options = {'REGISTER', 'UNDO'}
-
-    transmission = BoolProperty(
-        name="Transmission",
-        description="Smooth linked UVs",
-        default=False
-    )
-    mesh_infl = FloatProperty(
-        name="Mesh Influence",
-        description="Influence rate of mesh vertex",
-        min=0.0,
-        max=1.0,
-        default=0.0
-    )
-    select = BoolProperty(
-        name="Select",
-        description="Select UVs which are smoothed",
-        default=False
-    )
-
-    def __init__(self):
-        self.__impl = impl.SmoothUVImpl()
-
-    @classmethod
-    def poll(cls, context):
-        return impl.SmoothUVImpl.poll(context)
-
-    def execute(self, context):
-        return self.__impl.execute(self, context)
diff --git a/uv_magic_uv/legacy/op/texture_lock.py b/uv_magic_uv/legacy/op/texture_lock.py
deleted file mode 100644
index ab06baf5a0d62ddaa6033fcad7c7596f56bc970d..0000000000000000000000000000000000000000
--- a/uv_magic_uv/legacy/op/texture_lock.py
+++ /dev/null
@@ -1,158 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-__author__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-from bpy.props import BoolProperty
-
-from ...utils.bl_class_registry import BlClassRegistry
-from ...utils.property_class_registry import PropertyClassRegistry
-from ...impl import texture_lock_impl as impl
-
-
-@PropertyClassRegistry(legacy=True)
-class _Properties:
-    idname = "texture_lock"
-
-    @classmethod
-    def init_props(cls, scene):
-        class Props():
-            verts_orig = None
-
-        scene.muv_props.texture_lock = Props()
-
-        def get_func(_):
-            return MUV_OT_TextureLock_Intr.is_running(bpy.context)
-
-        def set_func(_, __):
-            pass
-
-        def update_func(_, __):
-            bpy.ops.uv.muv_texture_lock_operator_intr('INVOKE_REGION_WIN')
-
-        scene.muv_texture_lock_enabled = BoolProperty(
-            name="Texture Lock Enabled",
-            description="Texture Lock is enabled",
-            default=False
-        )
-        scene.muv_texture_lock_lock = BoolProperty(
-            name="Texture Lock Locked",
-            description="Texture Lock is locked",
-            default=False,
-            get=get_func,
-            set=set_func,
-            update=update_func
-        )
-        scene.muv_texture_lock_connect = BoolProperty(
-            name="Connect UV",
-            default=True
-        )
-
-    @classmethod
-    def del_props(cls, scene):
-        del scene.muv_props.texture_lock
-        del scene.muv_texture_lock_enabled
-        del scene.muv_texture_lock_lock
-        del scene.muv_texture_lock_connect
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_TextureLock_Lock(bpy.types.Operator):
-    """
-    Operation class: Lock Texture
-    """
-
-    bl_idname = "uv.muv_texture_lock_operator_lock"
-    bl_label = "Lock Texture"
-    bl_description = "Lock Texture"
-    bl_options = {'REGISTER', 'UNDO'}
-
-    def __init__(self):
-        self.__impl = impl.LockImpl()
-
-    @classmethod
-    def poll(cls, context):
-        return impl.LockImpl.poll(context)
-
-    @classmethod
-    def is_ready(cls, context):
-        return impl.LockImpl.is_ready(context)
-
-    def execute(self, context):
-        return self.__impl.execute(self, context)
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_TextureLock_Unlock(bpy.types.Operator):
-    """
-    Operation class: Unlock Texture
-    """
-
-    bl_idname = "uv.muv_texture_lock_operator_unlock"
-    bl_label = "Unlock Texture"
-    bl_description = "Unlock Texture"
-    bl_options = {'REGISTER', 'UNDO'}
-
-    connect = BoolProperty(
-        name="Connect UV",
-        default=True
-    )
-
-    def __init__(self):
-        self.__impl = impl.UnlockImpl()
-
-    @classmethod
-    def poll(cls, context):
-        return impl.UnlockImpl.poll(context)
-
-    def execute(self, context):
-        return self.__impl.execute(self, context)
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_TextureLock_Intr(bpy.types.Operator):
-    """
-    Operation class: Texture Lock (Interactive mode)
-    """
-
-    bl_idname = "uv.muv_texture_lock_operator_intr"
-    bl_label = "Texture Lock (Interactive mode)"
-    bl_description = "Internal operation for Texture Lock (Interactive mode)"
-
-    def __init__(self):
-        self.__impl = impl.IntrImpl()
-
-    @classmethod
-    def poll(cls, context):
-        return impl.IntrImpl.poll(context)
-
-    @classmethod
-    def is_running(cls, context):
-        return impl.IntrImpl.is_running(context)
-
-    def modal(self, context, event):
-        return self.__impl.modal(self, context, event)
-
-    def invoke(self, context, event):
-        return self.__impl.invoke(self, context, event)
diff --git a/uv_magic_uv/legacy/op/texture_projection.py b/uv_magic_uv/legacy/op/texture_projection.py
deleted file mode 100644
index bb73138bb6aa16a1559befe56a75c29ebedb799c..0000000000000000000000000000000000000000
--- a/uv_magic_uv/legacy/op/texture_projection.py
+++ /dev/null
@@ -1,296 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-__author__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-import bgl
-import bmesh
-from bpy_extras import view3d_utils
-from bpy.props import (
-    BoolProperty,
-    EnumProperty,
-    FloatProperty,
-)
-
-from ... import common
-from ...utils.bl_class_registry import BlClassRegistry
-from ...utils.property_class_registry import PropertyClassRegistry
-from ...impl import texture_projection_impl as impl
-
-
-@PropertyClassRegistry(legacy=True)
-class Properties:
-    idname = "texture_projection"
-
-    @classmethod
-    def init_props(cls, scene):
-        def get_func(_):
-            return MUV_OT_TextureProjection.is_running(bpy.context)
-
-        def set_func(_, __):
-            pass
-
-        def update_func(_, __):
-            bpy.ops.uv.muv_texture_projection_operator('INVOKE_REGION_WIN')
-
-        scene.muv_texture_projection_enabled = BoolProperty(
-            name="Texture Projection Enabled",
-            description="Texture Projection is enabled",
-            default=False
-        )
-        scene.muv_texture_projection_enable = BoolProperty(
-            name="Texture Projection Enabled",
-            description="Texture Projection is enabled",
-            default=False,
-            get=get_func,
-            set=set_func,
-            update=update_func
-        )
-        scene.muv_texture_projection_tex_magnitude = FloatProperty(
-            name="Magnitude",
-            description="Texture Magnitude",
-            default=0.5,
-            min=0.0,
-            max=100.0
-        )
-        scene.muv_texture_projection_tex_image = EnumProperty(
-            name="Image",
-            description="Texture Image",
-            items=impl.get_loaded_texture_name
-        )
-        scene.muv_texture_projection_tex_transparency = FloatProperty(
-            name="Transparency",
-            description="Texture Transparency",
-            default=0.2,
-            min=0.0,
-            max=1.0
-        )
-        scene.muv_texture_projection_adjust_window = BoolProperty(
-            name="Adjust Window",
-            description="Size of renderered texture is fitted to window",
-            default=True
-        )
-        scene.muv_texture_projection_apply_tex_aspect = BoolProperty(
-            name="Texture Aspect Ratio",
-            description="Apply Texture Aspect ratio to displayed texture",
-            default=True
-        )
-        scene.muv_texture_projection_assign_uvmap = BoolProperty(
-            name="Assign UVMap",
-            description="Assign UVMap when no UVmaps are available",
-            default=True
-        )
-
-    @classmethod
-    def del_props(cls, scene):
-        del scene.muv_texture_projection_enabled
-        del scene.muv_texture_projection_tex_magnitude
-        del scene.muv_texture_projection_tex_image
-        del scene.muv_texture_projection_tex_transparency
-        del scene.muv_texture_projection_adjust_window
-        del scene.muv_texture_projection_apply_tex_aspect
-        del scene.muv_texture_projection_assign_uvmap
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_TextureProjection(bpy.types.Operator):
-    """
-    Operation class: Texture Projection
-    Render texture
-    """
-
-    bl_idname = "uv.muv_texture_projection_operator"
-    bl_description = "Render selected texture"
-    bl_label = "Texture renderer"
-
-    __handle = None
-
-    @classmethod
-    def poll(cls, context):
-        # we can not get area/space/region from console
-        if common.is_console_mode():
-            return False
-        return impl.is_valid_context(context)
-
-    @classmethod
-    def is_running(cls, _):
-        return 1 if cls.__handle else 0
-
-    @classmethod
-    def handle_add(cls, obj, context):
-        cls.__handle = bpy.types.SpaceView3D.draw_handler_add(
-            MUV_OT_TextureProjection.draw_texture,
-            (obj, context), 'WINDOW', 'POST_PIXEL')
-
-    @classmethod
-    def handle_remove(cls):
-        if cls.__handle is not None:
-            bpy.types.SpaceView3D.draw_handler_remove(cls.__handle, 'WINDOW')
-            cls.__handle = None
-
-    @classmethod
-    def draw_texture(cls, _, context):
-        sc = context.scene
-
-        if not cls.is_running(context):
-            return
-
-        # no textures are selected
-        if sc.muv_texture_projection_tex_image == "None":
-            return
-
-        # get texture to be renderred
-        img = bpy.data.images[sc.muv_texture_projection_tex_image]
-
-        # setup rendering region
-        rect = impl.get_canvas(context, sc.muv_texture_projection_tex_magnitude)
-        positions = [
-            [rect.x0, rect.y0],
-            [rect.x0, rect.y1],
-            [rect.x1, rect.y1],
-            [rect.x1, rect.y0]
-        ]
-        tex_coords = [
-            [0.0, 0.0],
-            [0.0, 1.0],
-            [1.0, 1.0],
-            [1.0, 0.0]
-        ]
-
-        # OpenGL configuration
-        bgl.glEnable(bgl.GL_BLEND)
-        bgl.glEnable(bgl.GL_TEXTURE_2D)
-        if img.bindcode:
-            bind = img.bindcode[0]
-            bgl.glBindTexture(bgl.GL_TEXTURE_2D, bind)
-            bgl.glTexParameteri(
-                bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_MIN_FILTER, bgl.GL_LINEAR)
-            bgl.glTexParameteri(
-                bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_MAG_FILTER, bgl.GL_LINEAR)
-            bgl.glTexEnvi(
-                bgl.GL_TEXTURE_ENV, bgl.GL_TEXTURE_ENV_MODE, bgl.GL_MODULATE)
-
-        # render texture
-        bgl.glBegin(bgl.GL_QUADS)
-        bgl.glColor4f(1.0, 1.0, 1.0,
-                      sc.muv_texture_projection_tex_transparency)
-        for (v1, v2), (u, v) in zip(positions, tex_coords):
-            bgl.glTexCoord2f(u, v)
-            bgl.glVertex2f(v1, v2)
-        bgl.glEnd()
-
-    def invoke(self, context, _):
-        if not MUV_OT_TextureProjection.is_running(context):
-            MUV_OT_TextureProjection.handle_add(self, context)
-        else:
-            MUV_OT_TextureProjection.handle_remove()
-
-        if context.area:
-            context.area.tag_redraw()
-
-        return {'FINISHED'}
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_TextureProjection_Project(bpy.types.Operator):
-    """
-    Operation class: Project texture
-    """
-
-    bl_idname = "uv.muv_texture_projection_operator_project"
-    bl_label = "Project Texture"
-    bl_description = "Project Texture"
-    bl_options = {'REGISTER', 'UNDO'}
-
-    @classmethod
-    def poll(cls, context):
-        # we can not get area/space/region from console
-        if common.is_console_mode():
-            return True
-        if not MUV_OT_TextureProjection.is_running(context):
-            return False
-        return impl.is_valid_context(context)
-
-    def execute(self, context):
-        sc = context.scene
-
-        if sc.muv_texture_projection_tex_image == "None":
-            self.report({'WARNING'}, "No textures are selected")
-            return {'CANCELLED'}
-
-        _, region, space = common.get_space_legacy(
-            'VIEW_3D', 'WINDOW', 'VIEW_3D')
-
-        # get faces to be texture projected
-        obj = context.active_object
-        world_mat = obj.matrix_world
-        bm = bmesh.from_edit_mesh(obj.data)
-        if common.check_version(2, 73, 0) >= 0:
-            bm.faces.ensure_lookup_table()
-
-        # get UV and texture layer
-        if not bm.loops.layers.uv:
-            if sc.muv_texture_projection_assign_uvmap:
-                bm.loops.layers.uv.new()
-            else:
-                self.report({'WARNING'},
-                            "Object must have more than one UV map")
-                return {'CANCELLED'}
-
-        uv_layer = bm.loops.layers.uv.verify()
-        tex_layer = bm.faces.layers.tex.verify()
-
-        sel_faces = [f for f in bm.faces if f.select]
-
-        # transform 3d space to screen region
-        v_screen = [
-            view3d_utils.location_3d_to_region_2d(
-                region,
-                space.region_3d,
-                world_mat * l.vert.co)
-            for f in sel_faces for l in f.loops
-        ]
-
-        # transform screen region to canvas
-        v_canvas = [
-            impl.region_to_canvas(
-                v,
-                impl.get_canvas(bpy.context,
-                                sc.muv_texture_projection_tex_magnitude)
-            ) for v in v_screen
-        ]
-
-        # project texture to object
-        i = 0
-        for f in sel_faces:
-            f[tex_layer].image = \
-                bpy.data.images[sc.muv_texture_projection_tex_image]
-            for l in f.loops:
-                l[uv_layer].uv = v_canvas[i].to_2d()
-                i = i + 1
-
-        common.redraw_all_areas()
-        bmesh.update_edit_mesh(obj.data)
-
-        return {'FINISHED'}
diff --git a/uv_magic_uv/legacy/op/texture_wrap.py b/uv_magic_uv/legacy/op/texture_wrap.py
deleted file mode 100644
index 85c9d1748ffe8cc9df2d011ec4d56c5c5a9b056b..0000000000000000000000000000000000000000
--- a/uv_magic_uv/legacy/op/texture_wrap.py
+++ /dev/null
@@ -1,113 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-__author__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-from bpy.props import (
-    BoolProperty,
-)
-
-from ...utils.bl_class_registry import BlClassRegistry
-from ...utils.property_class_registry import PropertyClassRegistry
-from ...impl import texture_wrap_impl as impl
-
-
-@PropertyClassRegistry(legacy=True)
-class _Properties:
-    idname = "texture_wrap"
-
-    @classmethod
-    def init_props(cls, scene):
-        class Props():
-            ref_face_index = -1
-            ref_obj = None
-
-        scene.muv_props.texture_wrap = Props()
-
-        scene.muv_texture_wrap_enabled = BoolProperty(
-            name="Texture Wrap",
-            description="Texture Wrap is enabled",
-            default=False
-        )
-        scene.muv_texture_wrap_set_and_refer = BoolProperty(
-            name="Set and Refer",
-            description="Refer and set UV",
-            default=True
-        )
-        scene.muv_texture_wrap_selseq = BoolProperty(
-            name="Selection Sequence",
-            description="Set UV sequentially",
-            default=False
-        )
-
-    @classmethod
-    def del_props(cls, scene):
-        del scene.muv_props.texture_wrap
-        del scene.muv_texture_wrap_enabled
-        del scene.muv_texture_wrap_set_and_refer
-        del scene.muv_texture_wrap_selseq
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_TextureWrap_Refer(bpy.types.Operator):
-    """
-    Operation class: Refer UV
-    """
-
-    bl_idname = "uv.muv_texture_wrap_operator_refer"
-    bl_label = "Refer"
-    bl_description = "Refer UV"
-    bl_options = {'REGISTER', 'UNDO'}
-
-    def __init__(self):
-        self.__impl = impl.ReferImpl()
-
-    @classmethod
-    def poll(cls, context):
-        return impl.ReferImpl.poll(context)
-
-    def execute(self, context):
-        return self.__impl.execute(self, context)
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_TextureWrap_Set(bpy.types.Operator):
-    """
-    Operation class: Set UV
-    """
-
-    bl_idname = "uv.muv_texture_wrap_operator_set"
-    bl_label = "Set"
-    bl_description = "Set UV"
-    bl_options = {'REGISTER', 'UNDO'}
-
-    def __init__(self):
-        self.__impl = impl.SetImpl()
-
-    @classmethod
-    def poll(cls, context):
-        return impl.SetImpl.poll(context)
-
-    def execute(self, context):
-        return self.__impl.execute(self, context)
diff --git a/uv_magic_uv/legacy/op/transfer_uv.py b/uv_magic_uv/legacy/op/transfer_uv.py
deleted file mode 100644
index cd0e4dd9feffde6d3d95a6e8484bcdc38e24ce48..0000000000000000000000000000000000000000
--- a/uv_magic_uv/legacy/op/transfer_uv.py
+++ /dev/null
@@ -1,172 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-__author__ = "Nutti <nutti.metro@gmail.com>, Mifth, MaxRobinot"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-import bmesh
-from bpy.props import BoolProperty
-
-from ... import common
-from ...impl import transfer_uv_impl as impl
-from ...utils.bl_class_registry import BlClassRegistry
-from ...utils.property_class_registry import PropertyClassRegistry
-
-
-__all__ = [
-    'Properties',
-    'MUV_OT_TransferUV_CopyUV',
-    'MUV_OT_TransferUV_PasteUV',
-]
-
-
-@PropertyClassRegistry(legacy=True)
-class Properties:
-    idname = "transfer_uv"
-
-    @classmethod
-    def init_props(cls, scene):
-        class Props():
-            topology_copied = None
-
-        scene.muv_props.transfer_uv = Props()
-
-        scene.muv_transfer_uv_enabled = BoolProperty(
-            name="Transfer UV Enabled",
-            description="Transfer UV is enabled",
-            default=False
-        )
-        scene.muv_transfer_uv_invert_normals = BoolProperty(
-            name="Invert Normals",
-            description="Invert Normals",
-            default=False
-        )
-        scene.muv_transfer_uv_copy_seams = BoolProperty(
-            name="Copy Seams",
-            description="Copy Seams",
-            default=True
-        )
-
-    @classmethod
-    def del_props(cls, scene):
-        del scene.muv_transfer_uv_enabled
-        del scene.muv_transfer_uv_invert_normals
-        del scene.muv_transfer_uv_copy_seams
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_TransferUV_CopyUV(bpy.types.Operator):
-    """
-        Operation class: Transfer UV copy
-        Topological based copy
-    """
-
-    bl_idname = "uv.muv_transfer_uv_operator_copy_uv"
-    bl_label = "Transfer UV Copy UV"
-    bl_description = "Transfer UV Copy UV (Topological based copy)"
-    bl_options = {'REGISTER', 'UNDO'}
-
-    @classmethod
-    def poll(cls, context):
-        # we can not get area/space/region from console
-        if common.is_console_mode():
-            return True
-        return impl.is_valid_context(context)
-
-    def execute(self, context):
-        props = context.scene.muv_props.transfer_uv
-        active_obj = context.scene.objects.active
-        bm = bmesh.from_edit_mesh(active_obj.data)
-        if common.check_version(2, 73, 0) >= 0:
-            bm.faces.ensure_lookup_table()
-
-        uv_layer = impl.get_uv_layer(self, bm)
-        if uv_layer is None:
-            return {'CANCELLED'}
-
-        faces = impl.get_selected_src_faces(self, bm, uv_layer)
-        if faces is None:
-            return {'CANCELLED'}
-        props.topology_copied = faces
-
-        bmesh.update_edit_mesh(active_obj.data)
-
-        return {'FINISHED'}
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_TransferUV_PasteUV(bpy.types.Operator):
-    """
-        Operation class: Transfer UV paste
-        Topological based paste
-    """
-
-    bl_idname = "uv.muv_transfer_uv_operator_paste_uv"
-    bl_label = "Transfer UV Paste UV"
-    bl_description = "Transfer UV Paste UV (Topological based paste)"
-    bl_options = {'REGISTER', 'UNDO'}
-
-    invert_normals = BoolProperty(
-        name="Invert Normals",
-        description="Invert Normals",
-        default=False
-    )
-    copy_seams = BoolProperty(
-        name="Copy Seams",
-        description="Copy Seams",
-        default=True
-    )
-
-    @classmethod
-    def poll(cls, context):
-        # we can not get area/space/region from console
-        if common.is_console_mode():
-            return True
-        sc = context.scene
-        props = sc.muv_props.transfer_uv
-        if not props.topology_copied:
-            return False
-        return impl.is_valid_context(context)
-
-    def execute(self, context):
-        props = context.scene.muv_props.transfer_uv
-        active_obj = context.scene.objects.active
-        bm = bmesh.from_edit_mesh(active_obj.data)
-        if common.check_version(2, 73, 0) >= 0:
-            bm.faces.ensure_lookup_table()
-
-        # get UV layer
-        uv_layer = impl.get_uv_layer(self, bm)
-        if uv_layer is None:
-            return {'CANCELLED'}
-
-        ret = impl.paste_uv(self, bm, uv_layer, props.topology_copied,
-                            self.invert_normals, self.copy_seams)
-        if ret:
-            return {'CANCELLED'}
-
-        bmesh.update_edit_mesh(active_obj.data)
-        if self.copy_seams:
-            active_obj.data.show_edge_seams = True
-
-        return {'FINISHED'}
diff --git a/uv_magic_uv/legacy/op/unwrap_constraint.py b/uv_magic_uv/legacy/op/unwrap_constraint.py
deleted file mode 100644
index b7faa77a39f876e6a50cb834ec574ab33cc85089..0000000000000000000000000000000000000000
--- a/uv_magic_uv/legacy/op/unwrap_constraint.py
+++ /dev/null
@@ -1,125 +0,0 @@
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-__author__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-from bpy.props import (
-    BoolProperty,
-    EnumProperty,
-    FloatProperty,
-)
-
-from ...utils.bl_class_registry import BlClassRegistry
-from ...utils.property_class_registry import PropertyClassRegistry
-from ...impl import unwrap_constraint_impl as impl
-
-
-@PropertyClassRegistry(legacy=True)
-class _Properties:
-    idname = "unwrap_constraint"
-
-    @classmethod
-    def init_props(cls, scene):
-        scene.muv_unwrap_constraint_enabled = BoolProperty(
-            name="Unwrap Constraint Enabled",
-            description="Unwrap Constraint is enabled",
-            default=False
-        )
-        scene.muv_unwrap_constraint_u_const = BoolProperty(
-            name="U-Constraint",
-            description="Keep UV U-axis coordinate",
-            default=False
-        )
-        scene.muv_unwrap_constraint_v_const = BoolProperty(
-            name="V-Constraint",
-            description="Keep UV V-axis coordinate",
-            default=False
-        )
-
-    @classmethod
-    def del_props(cls, scene):
-        del scene.muv_unwrap_constraint_enabled
-        del scene.muv_unwrap_constraint_u_const
-        del scene.muv_unwrap_constraint_v_const
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_UnwrapConstraint(bpy.types.Operator):
-    """
-    Operation class: Unwrap with constrain UV coordinate
-    """
-
-    bl_idname = "uv.muv_unwrap_constraint_operator"
-    bl_label = "Unwrap Constraint"
-    bl_description = "Unwrap while keeping uv coordinate"
-    bl_options = {'REGISTER', 'UNDO'}
-
-    # property for original unwrap
-    method = EnumProperty(
-        name="Method",
-        description="Unwrapping method",
-        items=[
-            ('ANGLE_BASED', 'Angle Based', 'Angle Based'),
-            ('CONFORMAL', 'Conformal', 'Conformal')
-        ],
-        default='ANGLE_BASED')
-    fill_holes = BoolProperty(
-        name="Fill Holes",
-        description="Virtual fill holes in meshes before unwrapping",
-        default=True)
-    correct_aspect = BoolProperty(
-        name="Correct Aspect",
-        description="Map UVs taking image aspect ratio into account",
-        default=True)
-    use_subsurf_data = BoolProperty(
-        name="Use Subsurf Modifier",
-        description="""Map UVs taking vertex position after subsurf
-                       into account""",
-        default=False)
-    margin = FloatProperty(
-        name="Margin",
-        description="Space between islands",
-        max=1.0,
-        min=0.0,
-        default=0.001)
-
-    # property for this operation
-    u_const = BoolProperty(
-        name="U-Constraint",
-        description="Keep UV U-axis coordinate",
-        default=False
-    )
-    v_const = BoolProperty(
-        name="V-Constraint",
-        description="Keep UV V-axis coordinate",
-        default=False
-    )
-
-    def __init__(self):
-        self.__impl = impl.UnwrapConstraintImpl()
-
-    @classmethod
-    def poll(cls, context):
-        return impl.UnwrapConstraintImpl.poll(context)
-
-    def execute(self, context):
-        return self.__impl.execute(self, context)
diff --git a/uv_magic_uv/legacy/op/uv_bounding_box.py b/uv_magic_uv/legacy/op/uv_bounding_box.py
deleted file mode 100644
index 74c5f15c5f915f61ec02875fff481cb687c99fe6..0000000000000000000000000000000000000000
--- a/uv_magic_uv/legacy/op/uv_bounding_box.py
+++ /dev/null
@@ -1,810 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-__author__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-from enum import IntEnum
-import math
-
-import bpy
-import bgl
-import mathutils
-import bmesh
-from bpy.props import BoolProperty, EnumProperty
-
-from ... import common
-from ...utils.bl_class_registry import BlClassRegistry
-from ...utils.property_class_registry import PropertyClassRegistry
-from ...impl import uv_bounding_box_impl as impl
-
-
-MAX_VALUE = 100000.0
-
-
-@PropertyClassRegistry(legacy=True)
-class _Properties:
-    idname = "uv_bounding_box"
-
-    @classmethod
-    def init_props(cls, scene):
-        class Props():
-            uv_info_ini = []
-            ctrl_points_ini = []
-            ctrl_points = []
-
-        scene.muv_props.uv_bounding_box = Props()
-
-        def get_func(_):
-            return MUV_OT_UVBoundingBox.is_running(bpy.context)
-
-        def set_func(_, __):
-            pass
-
-        def update_func(_, __):
-            bpy.ops.uv.muv_uv_bounding_box_operator('INVOKE_REGION_WIN')
-
-        scene.muv_uv_bounding_box_enabled = BoolProperty(
-            name="UV Bounding Box Enabled",
-            description="UV Bounding Box is enabled",
-            default=False
-        )
-        scene.muv_uv_bounding_box_show = BoolProperty(
-            name="UV Bounding Box Showed",
-            description="UV Bounding Box is showed",
-            default=False,
-            get=get_func,
-            set=set_func,
-            update=update_func
-        )
-        scene.muv_uv_bounding_box_uniform_scaling = BoolProperty(
-            name="Uniform Scaling",
-            description="Enable Uniform Scaling",
-            default=False
-        )
-        scene.muv_uv_bounding_box_boundary = EnumProperty(
-            name="Boundary",
-            description="Boundary",
-            default='UV_SEL',
-            items=[
-                ('UV', "UV", "Boundary is decided by UV"),
-                ('UV_SEL', "UV (Selected)",
-                 "Boundary is decided by Selected UV")
-            ]
-        )
-
-    @classmethod
-    def del_props(cls, scene):
-        del scene.muv_props.uv_bounding_box
-        del scene.muv_uv_bounding_box_enabled
-        del scene.muv_uv_bounding_box_show
-        del scene.muv_uv_bounding_box_uniform_scaling
-        del scene.muv_uv_bounding_box_boundary
-
-
-class CommandBase:
-    """
-    Custom class: Base class of command
-    """
-
-    def __init__(self):
-        self.op = 'NONE'        # operation
-
-    def to_matrix(self):
-        # mat = I
-        mat = mathutils.Matrix()
-        mat.identity()
-        return mat
-
-
-class TranslationCommand(CommandBase):
-    """
-    Custom class: Translation operation
-    """
-
-    def __init__(self, ix, iy):
-        super().__init__()
-        self.op = 'TRANSLATION'
-        self.__x = ix       # current x
-        self.__y = iy       # current y
-        self.__ix = ix      # initial x
-        self.__iy = iy      # initial y
-
-    def to_matrix(self):
-        # mat = Mt
-        dx = self.__x - self.__ix
-        dy = self.__y - self.__iy
-        return mathutils.Matrix.Translation((dx, dy, 0))
-
-    def set(self, x, y):
-        self.__x = x
-        self.__y = y
-
-
-class RotationCommand(CommandBase):
-    """
-    Custom class: Rotation operation
-    """
-
-    def __init__(self, ix, iy, cx, cy):
-        super().__init__()
-        self.op = 'ROTATION'
-        self.__x = ix       # current x
-        self.__y = iy       # current y
-        self.__cx = cx      # center of rotation x
-        self.__cy = cy      # center of rotation y
-        dx = self.__x - self.__cx
-        dy = self.__y - self.__cy
-        self.__iangle = math.atan2(dy, dx)      # initial rotation angle
-
-    def to_matrix(self):
-        # mat = Mt * Mr * Mt^-1
-        dx = self.__x - self.__cx
-        dy = self.__y - self.__cy
-        angle = math.atan2(dy, dx) - self.__iangle
-        mti = mathutils.Matrix.Translation((-self.__cx, -self.__cy, 0.0))
-        mr = mathutils.Matrix.Rotation(angle, 4, 'Z')
-        mt = mathutils.Matrix.Translation((self.__cx, self.__cy, 0.0))
-        return mt * mr * mti
-
-    def set(self, x, y):
-        self.__x = x
-        self.__y = y
-
-
-class ScalingCommand(CommandBase):
-    """
-    Custom class: Scaling operation
-    """
-
-    def __init__(self, ix, iy, ox, oy, dir_x, dir_y, mat):
-        super().__init__()
-        self.op = 'SCALING'
-        self.__ix = ix          # initial x
-        self.__iy = iy          # initial y
-        self.__x = ix           # current x
-        self.__y = iy           # current y
-        self.__ox = ox          # origin of scaling x
-        self.__oy = oy          # origin of scaling y
-        self.__dir_x = dir_x    # direction of scaling x
-        self.__dir_y = dir_y    # direction of scaling y
-        self.__mat = mat
-        # initial origin of scaling = M(to original transform) * (ox, oy)
-        iov = mat * mathutils.Vector((ox, oy, 0.0))
-        self.__iox = iov.x      # initial origin of scaling X
-        self.__ioy = iov.y      # initial origin of scaling y
-
-    def to_matrix(self):
-        """
-        mat = M(to original transform)^-1 * Mt(to origin) * Ms *
-              Mt(to origin)^-1 * M(to original transform)
-        """
-        m = self.__mat
-        mi = self.__mat.inverted()
-        mtoi = mathutils.Matrix.Translation((-self.__iox, -self.__ioy, 0.0))
-        mto = mathutils.Matrix.Translation((self.__iox, self.__ioy, 0.0))
-        # every point must be transformed to origin
-        t = m * mathutils.Vector((self.__ix, self.__iy, 0.0))
-        tix, tiy = t.x, t.y
-        t = m * mathutils.Vector((self.__ox, self.__oy, 0.0))
-        tox, toy = t.x, t.y
-        t = m * mathutils.Vector((self.__x, self.__y, 0.0))
-        tx, ty = t.x, t.y
-        ms = mathutils.Matrix()
-        ms.identity()
-        if self.__dir_x == 1:
-            ms[0][0] = (tx - tox) * self.__dir_x / (tix - tox)
-        if self.__dir_y == 1:
-            ms[1][1] = (ty - toy) * self.__dir_y / (tiy - toy)
-        return mi * mto * ms * mtoi * m
-
-    def set(self, x, y):
-        self.__x = x
-        self.__y = y
-
-
-class UniformScalingCommand(CommandBase):
-    """
-    Custom class: Uniform Scaling operation
-    """
-
-    def __init__(self, ix, iy, ox, oy, mat):
-        super().__init__()
-        self.op = 'SCALING'
-        self.__ix = ix          # initial x
-        self.__iy = iy          # initial y
-        self.__x = ix           # current x
-        self.__y = iy           # current y
-        self.__ox = ox          # origin of scaling x
-        self.__oy = oy          # origin of scaling y
-        self.__mat = mat
-        # initial origin of scaling = M(to original transform) * (ox, oy)
-        iov = mat * mathutils.Vector((ox, oy, 0.0))
-        self.__iox = iov.x      # initial origin of scaling x
-        self.__ioy = iov.y      # initial origin of scaling y
-        self.__dir_x = 1
-        self.__dir_y = 1
-
-    def to_matrix(self):
-        """
-        mat = M(to original transform)^-1 * Mt(to origin) * Ms *
-              Mt(to origin)^-1 * M(to original transform)
-        """
-        m = self.__mat
-        mi = self.__mat.inverted()
-        mtoi = mathutils.Matrix.Translation((-self.__iox, -self.__ioy, 0.0))
-        mto = mathutils.Matrix.Translation((self.__iox, self.__ioy, 0.0))
-        # every point must be transformed to origin
-        t = m * mathutils.Vector((self.__ix, self.__iy, 0.0))
-        tix, tiy = t.x, t.y
-        t = m * mathutils.Vector((self.__ox, self.__oy, 0.0))
-        tox, toy = t.x, t.y
-        t = m * mathutils.Vector((self.__x, self.__y, 0.0))
-        tx, ty = t.x, t.y
-        ms = mathutils.Matrix()
-        ms.identity()
-        tir = math.sqrt((tix - tox) * (tix - tox) + (tiy - toy) * (tiy - toy))
-        tr = math.sqrt((tx - tox) * (tx - tox) + (ty - toy) * (ty - toy))
-
-        sr = tr / tir
-
-        if ((tx - tox) * (tix - tox)) > 0:
-            self.__dir_x = 1
-        else:
-            self.__dir_x = -1
-        if ((ty - toy) * (tiy - toy)) > 0:
-            self.__dir_y = 1
-        else:
-            self.__dir_y = -1
-
-        ms[0][0] = sr * self.__dir_x
-        ms[1][1] = sr * self.__dir_y
-
-        return mi * mto * ms * mtoi * m
-
-    def set(self, x, y):
-        self.__x = x
-        self.__y = y
-
-
-class CommandExecuter:
-    """
-    Custom class: manage command history and execute command
-    """
-
-    def __init__(self):
-        self.__cmd_list = []        # history
-        self.__cmd_list_redo = []   # redo list
-
-    def execute(self, begin=0, end=-1):
-        """
-        create matrix from history
-        """
-        mat = mathutils.Matrix()
-        mat.identity()
-        for i, cmd in enumerate(self.__cmd_list):
-            if begin <= i and (end == -1 or i <= end):
-                mat = cmd.to_matrix() * mat
-        return mat
-
-    def undo_size(self):
-        """
-        get history size
-        """
-        return len(self.__cmd_list)
-
-    def top(self):
-        """
-        get top of history
-        """
-        if len(self.__cmd_list) <= 0:
-            return None
-        return self.__cmd_list[-1]
-
-    def append(self, cmd):
-        """
-        append command
-        """
-        self.__cmd_list.append(cmd)
-        self.__cmd_list_redo = []
-
-    def undo(self):
-        """
-        undo command
-        """
-        if len(self.__cmd_list) <= 0:
-            return
-        self.__cmd_list_redo.append(self.__cmd_list.pop())
-
-    def redo(self):
-        """
-        redo command
-        """
-        if len(self.__cmd_list_redo) <= 0:
-            return
-        self.__cmd_list.append(self.__cmd_list_redo.pop())
-
-    def pop(self):
-        if len(self.__cmd_list) <= 0:
-            return None
-        return self.__cmd_list.pop()
-
-    def push(self, cmd):
-        self.__cmd_list.append(cmd)
-
-
-class State(IntEnum):
-    """
-    Enum: State definition used by MUV_UVBBStateMgr
-    """
-    NONE = 0
-    TRANSLATING = 1
-    SCALING_1 = 2
-    SCALING_2 = 3
-    SCALING_3 = 4
-    SCALING_4 = 5
-    SCALING_5 = 6
-    SCALING_6 = 7
-    SCALING_7 = 8
-    SCALING_8 = 9
-    ROTATING = 10
-    UNIFORM_SCALING_1 = 11
-    UNIFORM_SCALING_2 = 12
-    UNIFORM_SCALING_3 = 13
-    UNIFORM_SCALING_4 = 14
-
-
-class StateBase:
-    """
-    Custom class: Base class of state
-    """
-
-    def __init__(self):
-        pass
-
-    def update(self, context, event, ctrl_points, mouse_view):
-        raise NotImplementedError
-
-
-class StateNone(StateBase):
-    """
-    Custom class:
-    No state
-    Wait for event from mouse
-    """
-
-    def __init__(self, cmd_exec):
-        super().__init__()
-        self.__cmd_exec = cmd_exec
-
-    def update(self, context, event, ctrl_points, mouse_view):
-        """
-        Update state
-        """
-        prefs = context.user_preferences.addons["uv_magic_uv"].preferences
-        cp_react_size = prefs.uv_bounding_box_cp_react_size
-        is_uscaling = context.scene.muv_uv_bounding_box_uniform_scaling
-        if (event.type == 'LEFTMOUSE') and (event.value == 'PRESS'):
-            x, y = context.region.view2d.view_to_region(
-                mouse_view.x, mouse_view.y)
-            for i, p in enumerate(ctrl_points):
-                px, py = context.region.view2d.view_to_region(p.x, p.y)
-                in_cp_x = (px + cp_react_size > x and
-                           px - cp_react_size < x)
-                in_cp_y = (py + cp_react_size > y and
-                           py - cp_react_size < y)
-                if in_cp_x and in_cp_y:
-                    if is_uscaling:
-                        arr = [1, 3, 6, 8]
-                        if i in arr:
-                            return (
-                                State.UNIFORM_SCALING_1 +
-                                arr.index(i)
-                            )
-                    else:
-                        return State.TRANSLATING + i
-
-        return State.NONE
-
-
-class StateTranslating(StateBase):
-    """
-    Custom class: Translating state
-    """
-
-    def __init__(self, cmd_exec, ctrl_points):
-        super().__init__()
-        self.__cmd_exec = cmd_exec
-        ix, iy = ctrl_points[0].x, ctrl_points[0].y
-        self.__cmd_exec.append(TranslationCommand(ix, iy))
-
-    def update(self, context, event, ctrl_points, mouse_view):
-        if event.type == 'LEFTMOUSE':
-            if event.value == 'RELEASE':
-                return State.NONE
-        if event.type == 'MOUSEMOVE':
-            x, y = mouse_view.x, mouse_view.y
-            self.__cmd_exec.top().set(x, y)
-        return State.TRANSLATING
-
-
-class StateScaling(StateBase):
-    """
-    Custom class: Scaling state
-    """
-
-    def __init__(self, cmd_exec, state, ctrl_points):
-        super().__init__()
-        self.__state = state
-        self.__cmd_exec = cmd_exec
-        dir_x_list = [1, 1, 1, 0, 0, 1, 1, 1]
-        dir_y_list = [1, 0, 1, 1, 1, 1, 0, 1]
-        idx = state - 2
-        ix, iy = ctrl_points[idx + 1].x, ctrl_points[idx + 1].y
-        ox, oy = ctrl_points[8 - idx].x, ctrl_points[8 - idx].y
-        dir_x, dir_y = dir_x_list[idx], dir_y_list[idx]
-        mat = self.__cmd_exec.execute(end=self.__cmd_exec.undo_size())
-        self.__cmd_exec.append(
-            ScalingCommand(ix, iy, ox, oy, dir_x, dir_y, mat.inverted()))
-
-    def update(self, context, event, ctrl_points, mouse_view):
-        if event.type == 'LEFTMOUSE':
-            if event.value == 'RELEASE':
-                return State.NONE
-        if event.type == 'MOUSEMOVE':
-            x, y = mouse_view.x, mouse_view.y
-            self.__cmd_exec.top().set(x, y)
-        return self.__state
-
-
-class StateUniformScaling(StateBase):
-    """
-    Custom class: Uniform Scaling state
-    """
-
-    def __init__(self, cmd_exec, state, ctrl_points):
-        super().__init__()
-        self.__state = state
-        self.__cmd_exec = cmd_exec
-        icp_idx = [1, 3, 6, 8]
-        ocp_idx = [8, 6, 3, 1]
-        idx = state - State.UNIFORM_SCALING_1
-        ix, iy = ctrl_points[icp_idx[idx]].x, ctrl_points[icp_idx[idx]].y
-        ox, oy = ctrl_points[ocp_idx[idx]].x, ctrl_points[ocp_idx[idx]].y
-        mat = self.__cmd_exec.execute(end=self.__cmd_exec.undo_size())
-        self.__cmd_exec.append(UniformScalingCommand(
-            ix, iy, ox, oy, mat.inverted()))
-
-    def update(self, context, event, ctrl_points, mouse_view):
-        if event.type == 'LEFTMOUSE':
-            if event.value == 'RELEASE':
-                return State.NONE
-        if event.type == 'MOUSEMOVE':
-            x, y = mouse_view.x, mouse_view.y
-            self.__cmd_exec.top().set(x, y)
-
-        return self.__state
-
-
-class StateRotating(StateBase):
-    """
-    Custom class: Rotating state
-    """
-
-    def __init__(self, cmd_exec, ctrl_points):
-        super().__init__()
-        self.__cmd_exec = cmd_exec
-        ix, iy = ctrl_points[9].x, ctrl_points[9].y
-        ox, oy = ctrl_points[0].x, ctrl_points[0].y
-        self.__cmd_exec.append(RotationCommand(ix, iy, ox, oy))
-
-    def update(self, context, event, ctrl_points, mouse_view):
-        if event.type == 'LEFTMOUSE':
-            if event.value == 'RELEASE':
-                return State.NONE
-        if event.type == 'MOUSEMOVE':
-            x, y = mouse_view.x, mouse_view.y
-            self.__cmd_exec.top().set(x, y)
-        return State.ROTATING
-
-
-class StateManager:
-    """
-    Custom class: Manage state about this feature
-    """
-
-    def __init__(self, cmd_exec):
-        self.__cmd_exec = cmd_exec          # command executer
-        self.__state = State.NONE   # current state
-        self.__state_obj = StateNone(self.__cmd_exec)
-
-    def __update_state(self, next_state, ctrl_points):
-        """
-        Update state
-        """
-
-        if next_state == self.__state:
-            return
-        obj = None
-        if next_state == State.TRANSLATING:
-            obj = StateTranslating(self.__cmd_exec, ctrl_points)
-        elif State.SCALING_1 <= next_state <= State.SCALING_8:
-            obj = StateScaling(
-                self.__cmd_exec, next_state, ctrl_points)
-        elif next_state == State.ROTATING:
-            obj = StateRotating(self.__cmd_exec, ctrl_points)
-        elif next_state == State.NONE:
-            obj = StateNone(self.__cmd_exec)
-        elif (State.UNIFORM_SCALING_1 <= next_state <=
-              State.UNIFORM_SCALING_4):
-            obj = StateUniformScaling(
-                self.__cmd_exec, next_state, ctrl_points)
-
-        if obj is not None:
-            self.__state_obj = obj
-
-        self.__state = next_state
-
-    def update(self, context, ctrl_points, event):
-        mouse_region = mathutils.Vector((
-            event.mouse_region_x, event.mouse_region_y))
-        mouse_view = mathutils.Vector((context.region.view2d.region_to_view(
-            mouse_region.x, mouse_region.y)))
-        next_state = self.__state_obj.update(
-            context, event, ctrl_points, mouse_view)
-        self.__update_state(next_state, ctrl_points)
-
-        return self.__state
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_UVBoundingBox(bpy.types.Operator):
-    """
-    Operation class: UV Bounding Box
-    """
-
-    bl_idname = "uv.muv_uv_bounding_box_operator"
-    bl_label = "UV Bounding Box"
-    bl_description = "Internal operation for UV Bounding Box"
-    bl_options = {'REGISTER', 'UNDO'}
-
-    def __init__(self):
-        self.__timer = None
-        self.__cmd_exec = CommandExecuter()         # Command executor
-        self.__state_mgr = StateManager(self.__cmd_exec)   # State Manager
-
-    __handle = None
-    __timer = None
-
-    @classmethod
-    def poll(cls, context):
-        # we can not get area/space/region from console
-        if common.is_console_mode():
-            return False
-        return impl.is_valid_context(context)
-
-    @classmethod
-    def is_running(cls, _):
-        return 1 if cls.__handle else 0
-
-    @classmethod
-    def handle_add(cls, obj, context):
-        if cls.__handle is None:
-            sie = bpy.types.SpaceImageEditor
-            cls.__handle = sie.draw_handler_add(
-                cls.draw_bb, (obj, context), "WINDOW", "POST_PIXEL")
-        if cls.__timer is None:
-            cls.__timer = context.window_manager.event_timer_add(
-                0.1, window=context.window)
-            context.window_manager.modal_handler_add(obj)
-
-    @classmethod
-    def handle_remove(cls, context):
-        if cls.__handle is not None:
-            sie = bpy.types.SpaceImageEditor
-            sie.draw_handler_remove(cls.__handle, "WINDOW")
-            cls.__handle = None
-        if cls.__timer is not None:
-            context.window_manager.event_timer_remove(cls.__timer)
-            cls.__timer = None
-
-    @classmethod
-    def __draw_ctrl_point(cls, context, pos):
-        """
-        Draw control point
-        """
-        prefs = context.user_preferences.addons["uv_magic_uv"].preferences
-        cp_size = prefs.uv_bounding_box_cp_size
-        offset = cp_size / 2
-        verts = [
-            [pos.x - offset, pos.y - offset],
-            [pos.x - offset, pos.y + offset],
-            [pos.x + offset, pos.y + offset],
-            [pos.x + offset, pos.y - offset]
-        ]
-        bgl.glEnable(bgl.GL_BLEND)
-        bgl.glBegin(bgl.GL_QUADS)
-        bgl.glColor4f(1.0, 1.0, 1.0, 1.0)
-        for (x, y) in verts:
-            bgl.glVertex2f(x, y)
-        bgl.glEnd()
-
-    @classmethod
-    def draw_bb(cls, _, context):
-        """
-        Draw bounding box
-        """
-        props = context.scene.muv_props.uv_bounding_box
-
-        if not MUV_OT_UVBoundingBox.is_running(context):
-            return
-
-        if not impl.is_valid_context(context):
-            return
-
-        for cp in props.ctrl_points:
-            cls.__draw_ctrl_point(
-                context, mathutils.Vector(
-                    context.region.view2d.view_to_region(cp.x, cp.y)))
-
-    def __get_uv_info(self, context):
-        """
-        Get UV coordinate
-        """
-        sc = context.scene
-        obj = context.active_object
-        uv_info = []
-        bm = bmesh.from_edit_mesh(obj.data)
-        if common.check_version(2, 73, 0) >= 0:
-            bm.faces.ensure_lookup_table()
-        if not bm.loops.layers.uv:
-            return None
-        uv_layer = bm.loops.layers.uv.verify()
-        for f in bm.faces:
-            if not f.select:
-                continue
-            for i, l in enumerate(f.loops):
-                if sc.muv_uv_bounding_box_boundary == 'UV_SEL':
-                    if l[uv_layer].select:
-                        uv_info.append((f.index, i, l[uv_layer].uv.copy()))
-                elif sc.muv_uv_bounding_box_boundary == 'UV':
-                    uv_info.append((f.index, i, l[uv_layer].uv.copy()))
-        if not uv_info:
-            return None
-        return uv_info
-
-    def __get_ctrl_point(self, uv_info_ini):
-        """
-        Get control point
-        """
-        left = MAX_VALUE
-        right = -MAX_VALUE
-        top = -MAX_VALUE
-        bottom = MAX_VALUE
-
-        for info in uv_info_ini:
-            uv = info[2]
-            if uv.x < left:
-                left = uv.x
-            if uv.x > right:
-                right = uv.x
-            if uv.y < bottom:
-                bottom = uv.y
-            if uv.y > top:
-                top = uv.y
-
-        points = [
-            mathutils.Vector((
-                (left + right) * 0.5, (top + bottom) * 0.5, 0.0
-            )),
-            mathutils.Vector((left, top, 0.0)),
-            mathutils.Vector((left, (top + bottom) * 0.5, 0.0)),
-            mathutils.Vector((left, bottom, 0.0)),
-            mathutils.Vector(((left + right) * 0.5, top, 0.0)),
-            mathutils.Vector(((left + right) * 0.5, bottom, 0.0)),
-            mathutils.Vector((right, top, 0.0)),
-            mathutils.Vector((right, (top + bottom) * 0.5, 0.0)),
-            mathutils.Vector((right, bottom, 0.0)),
-            mathutils.Vector(((left + right) * 0.5, top + 0.03, 0.0))
-        ]
-
-        return points
-
-    def __update_uvs(self, context, uv_info_ini, trans_mat):
-        """
-        Update UV coordinate
-        """
-        obj = context.active_object
-        bm = bmesh.from_edit_mesh(obj.data)
-        if common.check_version(2, 73, 0) >= 0:
-            bm.faces.ensure_lookup_table()
-        if not bm.loops.layers.uv:
-            return
-        uv_layer = bm.loops.layers.uv.verify()
-        for info in uv_info_ini:
-            fidx = info[0]
-            lidx = info[1]
-            uv = info[2]
-            v = mathutils.Vector((uv.x, uv.y, 0.0))
-            av = trans_mat * v
-            bm.faces[fidx].loops[lidx][uv_layer].uv = mathutils.Vector(
-                (av.x, av.y))
-
-    def __update_ctrl_point(self, ctrl_points_ini, trans_mat):
-        """
-        Update control point
-        """
-        return [trans_mat * cp for cp in ctrl_points_ini]
-
-    def modal(self, context, event):
-        props = context.scene.muv_props.uv_bounding_box
-        common.redraw_all_areas()
-
-        if not MUV_OT_UVBoundingBox.is_running(context):
-            return {'FINISHED'}
-
-        if not impl.is_valid_context(context):
-            MUV_OT_UVBoundingBox.handle_remove(context)
-            return {'FINISHED'}
-
-        region_types = [
-            'HEADER',
-            'UI',
-            'TOOLS',
-        ]
-        if not common.mouse_on_area_legacy(event, 'IMAGE_EDITOR') or \
-           common.mouse_on_regions_legacy(event, 'IMAGE_EDITOR', region_types):
-            return {'PASS_THROUGH'}
-
-        if event.type == 'TIMER':
-            trans_mat = self.__cmd_exec.execute()
-            self.__update_uvs(context, props.uv_info_ini, trans_mat)
-            props.ctrl_points = self.__update_ctrl_point(
-                props.ctrl_points_ini, trans_mat)
-
-        state = self.__state_mgr.update(context, props.ctrl_points, event)
-        if state == State.NONE:
-            return {'PASS_THROUGH'}
-
-        return {'RUNNING_MODAL'}
-
-    def invoke(self, context, _):
-        props = context.scene.muv_props.uv_bounding_box
-
-        if MUV_OT_UVBoundingBox.is_running(context):
-            MUV_OT_UVBoundingBox.handle_remove(context)
-            return {'FINISHED'}
-
-        props.uv_info_ini = self.__get_uv_info(context)
-        if props.uv_info_ini is None:
-            return {'CANCELLED'}
-
-        MUV_OT_UVBoundingBox.handle_add(self, context)
-
-        props.ctrl_points_ini = self.__get_ctrl_point(props.uv_info_ini)
-        trans_mat = self.__cmd_exec.execute()
-        # Update is needed in order to display control point
-        self.__update_uvs(context, props.uv_info_ini, trans_mat)
-        props.ctrl_points = self.__update_ctrl_point(
-            props.ctrl_points_ini, trans_mat)
-
-        return {'RUNNING_MODAL'}
diff --git a/uv_magic_uv/legacy/op/uv_inspection.py b/uv_magic_uv/legacy/op/uv_inspection.py
deleted file mode 100644
index df7e17e940595772978ac938166293181eba3376..0000000000000000000000000000000000000000
--- a/uv_magic_uv/legacy/op/uv_inspection.py
+++ /dev/null
@@ -1,231 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-__author__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-import bgl
-from bpy.props import BoolProperty, EnumProperty
-
-from ... import common
-from ...utils.bl_class_registry import BlClassRegistry
-from ...utils.property_class_registry import PropertyClassRegistry
-from ...impl import uv_inspection_impl as impl
-
-
-@PropertyClassRegistry(legacy=True)
-class _Properties:
-    idname = "uv_inspection"
-
-    @classmethod
-    def init_props(cls, scene):
-        class Props():
-            overlapped_info = []
-            flipped_info = []
-
-        scene.muv_props.uv_inspection = Props()
-
-        def get_func(_):
-            return MUV_OT_UVInspection_Render.is_running(bpy.context)
-
-        def set_func(_, __):
-            pass
-
-        def update_func(_, __):
-            bpy.ops.uv.muv_uv_inspection_operator_render('INVOKE_REGION_WIN')
-
-        scene.muv_uv_inspection_enabled = BoolProperty(
-            name="UV Inspection Enabled",
-            description="UV Inspection is enabled",
-            default=False
-        )
-        scene.muv_uv_inspection_show = BoolProperty(
-            name="UV Inspection Showed",
-            description="UV Inspection is showed",
-            default=False,
-            get=get_func,
-            set=set_func,
-            update=update_func
-        )
-        scene.muv_uv_inspection_show_overlapped = BoolProperty(
-            name="Overlapped",
-            description="Show overlapped UVs",
-            default=False
-        )
-        scene.muv_uv_inspection_show_flipped = BoolProperty(
-            name="Flipped",
-            description="Show flipped UVs",
-            default=False
-        )
-        scene.muv_uv_inspection_show_mode = EnumProperty(
-            name="Mode",
-            description="Show mode",
-            items=[
-                ('PART', "Part", "Show only overlapped/flipped part"),
-                ('FACE', "Face", "Show overlapped/flipped face")
-            ],
-            default='PART'
-        )
-
-    @classmethod
-    def del_props(cls, scene):
-        del scene.muv_props.uv_inspection
-        del scene.muv_uv_inspection_enabled
-        del scene.muv_uv_inspection_show
-        del scene.muv_uv_inspection_show_overlapped
-        del scene.muv_uv_inspection_show_flipped
-        del scene.muv_uv_inspection_show_mode
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_UVInspection_Render(bpy.types.Operator):
-    """
-    Operation class: Render UV Inspection
-    No operation (only rendering)
-    """
-
-    bl_idname = "uv.muv_uv_inspection_operator_render"
-    bl_description = "Render overlapped/flipped UVs"
-    bl_label = "Overlapped/Flipped UV renderer"
-
-    __handle = None
-
-    @classmethod
-    def poll(cls, context):
-        # we can not get area/space/region from console
-        if common.is_console_mode():
-            return False
-        return impl.is_valid_context(context)
-
-    @classmethod
-    def is_running(cls, _):
-        return 1 if cls.__handle else 0
-
-    @classmethod
-    def handle_add(cls, obj, context):
-        sie = bpy.types.SpaceImageEditor
-        cls.__handle = sie.draw_handler_add(
-            MUV_OT_UVInspection_Render.draw, (obj, context),
-            'WINDOW', 'POST_PIXEL')
-
-    @classmethod
-    def handle_remove(cls):
-        if cls.__handle is not None:
-            bpy.types.SpaceImageEditor.draw_handler_remove(
-                cls.__handle, 'WINDOW')
-            cls.__handle = None
-
-    @staticmethod
-    def draw(_, context):
-        sc = context.scene
-        props = sc.muv_props.uv_inspection
-        prefs = context.user_preferences.addons["uv_magic_uv"].preferences
-
-        if not MUV_OT_UVInspection_Render.is_running(context):
-            return
-
-        # OpenGL configuration
-        bgl.glEnable(bgl.GL_BLEND)
-
-        # render overlapped UV
-        if sc.muv_uv_inspection_show_overlapped:
-            color = prefs.uv_inspection_overlapped_color
-            for info in props.overlapped_info:
-                if sc.muv_uv_inspection_show_mode == 'PART':
-                    for poly in info["polygons"]:
-                        bgl.glBegin(bgl.GL_TRIANGLE_FAN)
-                        bgl.glColor4f(color[0], color[1], color[2], color[3])
-                        for uv in poly:
-                            x, y = context.region.view2d.view_to_region(
-                                uv.x, uv.y)
-                            bgl.glVertex2f(x, y)
-                        bgl.glEnd()
-                elif sc.muv_uv_inspection_show_mode == 'FACE':
-                    bgl.glBegin(bgl.GL_TRIANGLE_FAN)
-                    bgl.glColor4f(color[0], color[1], color[2], color[3])
-                    for uv in info["subject_uvs"]:
-                        x, y = context.region.view2d.view_to_region(uv.x, uv.y)
-                        bgl.glVertex2f(x, y)
-                    bgl.glEnd()
-
-        # render flipped UV
-        if sc.muv_uv_inspection_show_flipped:
-            color = prefs.uv_inspection_flipped_color
-            for info in props.flipped_info:
-                if sc.muv_uv_inspection_show_mode == 'PART':
-                    for poly in info["polygons"]:
-                        bgl.glBegin(bgl.GL_TRIANGLE_FAN)
-                        bgl.glColor4f(color[0], color[1], color[2], color[3])
-                        for uv in poly:
-                            x, y = context.region.view2d.view_to_region(
-                                uv.x, uv.y)
-                            bgl.glVertex2f(x, y)
-                        bgl.glEnd()
-                elif sc.muv_uv_inspection_show_mode == 'FACE':
-                    bgl.glBegin(bgl.GL_TRIANGLE_FAN)
-                    bgl.glColor4f(color[0], color[1], color[2], color[3])
-                    for uv in info["uvs"]:
-                        x, y = context.region.view2d.view_to_region(uv.x, uv.y)
-                        bgl.glVertex2f(x, y)
-                    bgl.glEnd()
-
-    def invoke(self, context, _):
-        if not MUV_OT_UVInspection_Render.is_running(context):
-            impl.update_uvinsp_info(context)
-            MUV_OT_UVInspection_Render.handle_add(self, context)
-        else:
-            MUV_OT_UVInspection_Render.handle_remove()
-
-        if context.area:
-            context.area.tag_redraw()
-
-        return {'FINISHED'}
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_UVInspection_Update(bpy.types.Operator):
-    """
-    Operation class: Update
-    """
-
-    bl_idname = "uv.muv_uv_inspection_operator_update"
-    bl_label = "Update UV Inspection"
-    bl_description = "Update UV Inspection"
-    bl_options = {'REGISTER', 'UNDO'}
-
-    @classmethod
-    def poll(cls, context):
-        # we can not get area/space/region from console
-        if common.is_console_mode():
-            return True
-        if not MUV_OT_UVInspection_Render.is_running(context):
-            return False
-        return impl.is_valid_context(context)
-
-    def execute(self, context):
-        impl.update_uvinsp_info(context)
-
-        if context.area:
-            context.area.tag_redraw()
-
-        return {'FINISHED'}
diff --git a/uv_magic_uv/legacy/op/uv_sculpt.py b/uv_magic_uv/legacy/op/uv_sculpt.py
deleted file mode 100644
index 47a850d823a94c9b18c96d754543c45b67e26905..0000000000000000000000000000000000000000
--- a/uv_magic_uv/legacy/op/uv_sculpt.py
+++ /dev/null
@@ -1,450 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-__author__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-
-from math import pi, cos, tan, sin
-
-import bpy
-from bpy.props import (
-    BoolProperty,
-    IntProperty,
-    EnumProperty,
-    FloatProperty,
-)
-import bmesh
-import bgl
-from mathutils import Vector
-from bpy_extras import view3d_utils
-from mathutils.bvhtree import BVHTree
-from mathutils.geometry import barycentric_transform
-
-from ... import common
-from ...utils.bl_class_registry import BlClassRegistry
-from ...utils.property_class_registry import PropertyClassRegistry
-from ...impl import uv_sculpt_impl as impl
-
-
-@PropertyClassRegistry(legacy=True)
-class _Properties:
-    idname = "uv_sculpt"
-
-    @classmethod
-    def init_props(cls, scene):
-        def get_func(_):
-            return MUV_OT_UVSculpt.is_running(bpy.context)
-
-        def set_func(_, __):
-            pass
-
-        def update_func(_, __):
-            bpy.ops.uv.muv_uv_sculpt_operator('INVOKE_REGION_WIN')
-
-        scene.muv_uv_sculpt_enabled = BoolProperty(
-            name="UV Sculpt",
-            description="UV Sculpt is enabled",
-            default=False
-        )
-        scene.muv_uv_sculpt_enable = BoolProperty(
-            name="UV Sculpt Showed",
-            description="UV Sculpt is enabled",
-            default=False,
-            get=get_func,
-            set=set_func,
-            update=update_func
-        )
-        scene.muv_uv_sculpt_radius = IntProperty(
-            name="Radius",
-            description="Radius of the brush",
-            min=1,
-            max=500,
-            default=30
-        )
-        scene.muv_uv_sculpt_strength = FloatProperty(
-            name="Strength",
-            description="How powerful the effect of the brush when applied",
-            min=0.0,
-            max=1.0,
-            default=0.03,
-        )
-        scene.muv_uv_sculpt_tools = EnumProperty(
-            name="Tools",
-            description="Select Tools for the UV sculpt brushes",
-            items=[
-                ('GRAB', "Grab", "Grab UVs"),
-                ('RELAX', "Relax", "Relax UVs"),
-                ('PINCH', "Pinch", "Pinch UVs")
-            ],
-            default='GRAB'
-        )
-        scene.muv_uv_sculpt_show_brush = BoolProperty(
-            name="Show Brush",
-            description="Show Brush",
-            default=True
-        )
-        scene.muv_uv_sculpt_pinch_invert = BoolProperty(
-            name="Invert",
-            description="Pinch UV to invert direction",
-            default=False
-        )
-        scene.muv_uv_sculpt_relax_method = EnumProperty(
-            name="Method",
-            description="Algorithm used for relaxation",
-            items=[
-                ('HC', "HC", "Use HC method for relaxation"),
-                ('LAPLACIAN', "Laplacian",
-                 "Use laplacian method for relaxation")
-            ],
-            default='HC'
-        )
-
-    @classmethod
-    def del_props(cls, scene):
-        del scene.muv_uv_sculpt_enabled
-        del scene.muv_uv_sculpt_enable
-        del scene.muv_uv_sculpt_radius
-        del scene.muv_uv_sculpt_strength
-        del scene.muv_uv_sculpt_tools
-        del scene.muv_uv_sculpt_show_brush
-        del scene.muv_uv_sculpt_pinch_invert
-        del scene.muv_uv_sculpt_relax_method
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_UVSculpt(bpy.types.Operator):
-    """
-    Operation class: UV Sculpt in View3D
-    """
-
-    bl_idname = "uv.muv_uv_sculpt_operator"
-    bl_label = "UV Sculpt"
-    bl_description = "UV Sculpt in View3D"
-    bl_options = {'REGISTER'}
-
-    __handle = None
-    __timer = None
-
-    @classmethod
-    def poll(cls, context):
-        # we can not get area/space/region from console
-        if common.is_console_mode():
-            return False
-        return impl.is_valid_context(context)
-
-    @classmethod
-    def is_running(cls, _):
-        return 1 if cls.__handle else 0
-
-    @classmethod
-    def handle_add(cls, obj, context):
-        if not cls.__handle:
-            sv = bpy.types.SpaceView3D
-            cls.__handle = sv.draw_handler_add(cls.draw_brush, (obj, context),
-                                               "WINDOW", "POST_PIXEL")
-        if not cls.__timer:
-            cls.__timer = context.window_manager.event_timer_add(
-                0.1, window=context.window)
-            context.window_manager.modal_handler_add(obj)
-
-    @classmethod
-    def handle_remove(cls, context):
-        if cls.__handle:
-            sv = bpy.types.SpaceView3D
-            sv.draw_handler_remove(cls.__handle, "WINDOW")
-            cls.__handle = None
-        if cls.__timer:
-            context.window_manager.event_timer_remove(cls.__timer)
-            cls.__timer = None
-
-    @classmethod
-    def draw_brush(cls, obj, context):
-        sc = context.scene
-        prefs = context.user_preferences.addons["uv_magic_uv"].preferences
-
-        num_segment = 180
-        theta = 2 * pi / num_segment
-        fact_t = tan(theta)
-        fact_r = cos(theta)
-        color = prefs.uv_sculpt_brush_color
-
-        bgl.glBegin(bgl.GL_LINE_STRIP)
-        bgl.glColor4f(color[0], color[1], color[2], color[3])
-        x = sc.muv_uv_sculpt_radius * cos(0.0)
-        y = sc.muv_uv_sculpt_radius * sin(0.0)
-        for _ in range(num_segment):
-            bgl.glVertex2f(x + obj.current_mco.x, y + obj.current_mco.y)
-            tx = -y
-            ty = x
-            x = x + tx * fact_t
-            y = y + ty * fact_t
-            x = x * fact_r
-            y = y * fact_r
-        bgl.glEnd()
-
-    def __init__(self):
-        self.__loop_info = []
-        self.__stroking = False
-        self.current_mco = Vector((0.0, 0.0))
-        self.__initial_mco = Vector((0.0, 0.0))
-
-    def __stroke_init(self, context, _):
-        sc = context.scene
-
-        self.__initial_mco = self.current_mco
-
-        # get influenced UV
-        obj = context.active_object
-        world_mat = obj.matrix_world
-        bm = bmesh.from_edit_mesh(obj.data)
-        uv_layer = bm.loops.layers.uv.verify()
-        _, region, space = common.get_space_legacy('VIEW_3D', 'WINDOW',
-                                                   'VIEW_3D')
-
-        self.__loop_info = []
-        for f in bm.faces:
-            if not f.select:
-                continue
-            for i, l in enumerate(f.loops):
-                loc_2d = view3d_utils.location_3d_to_region_2d(
-                    region, space.region_3d, world_mat * l.vert.co)
-                diff = loc_2d - self.__initial_mco
-                if diff.length < sc.muv_uv_sculpt_radius:
-                    info = {
-                        "face_idx": f.index,
-                        "loop_idx": i,
-                        "initial_vco": l.vert.co.copy(),
-                        "initial_vco_2d": loc_2d,
-                        "initial_uv": l[uv_layer].uv.copy(),
-                        "strength": impl.get_strength(
-                            diff.length, sc.muv_uv_sculpt_radius,
-                            sc.muv_uv_sculpt_strength)
-                    }
-                    self.__loop_info.append(info)
-
-    def __stroke_apply(self, context, _):
-        sc = context.scene
-        obj = context.active_object
-        world_mat = obj.matrix_world
-        bm = bmesh.from_edit_mesh(obj.data)
-        uv_layer = bm.loops.layers.uv.verify()
-        mco = self.current_mco
-
-        if sc.muv_uv_sculpt_tools == 'GRAB':
-            for info in self.__loop_info:
-                diff_uv = (mco - self.__initial_mco) * info["strength"]
-                l = bm.faces[info["face_idx"]].loops[info["loop_idx"]]
-                l[uv_layer].uv = info["initial_uv"] + diff_uv / 100.0
-
-        elif sc.muv_uv_sculpt_tools == 'PINCH':
-            _, region, space = common.get_space_legacy('VIEW_3D', 'WINDOW',
-                                                       'VIEW_3D')
-            loop_info = []
-            for f in bm.faces:
-                if not f.select:
-                    continue
-                for i, l in enumerate(f.loops):
-                    loc_2d = view3d_utils.location_3d_to_region_2d(
-                        region, space.region_3d, world_mat * l.vert.co)
-                    diff = loc_2d - self.__initial_mco
-                    if diff.length < sc.muv_uv_sculpt_radius:
-                        info = {
-                            "face_idx": f.index,
-                            "loop_idx": i,
-                            "initial_vco": l.vert.co.copy(),
-                            "initial_vco_2d": loc_2d,
-                            "initial_uv": l[uv_layer].uv.copy(),
-                            "strength": impl.get_strength(
-                                diff.length, sc.muv_uv_sculpt_radius,
-                                sc.muv_uv_sculpt_strength)
-                        }
-                        loop_info.append(info)
-
-            # mouse coordinate to UV coordinate
-            ray_vec = view3d_utils.region_2d_to_vector_3d(region,
-                                                          space.region_3d, mco)
-            ray_vec.normalize()
-            ray_orig = view3d_utils.region_2d_to_origin_3d(region,
-                                                           space.region_3d,
-                                                           mco)
-            ray_tgt = ray_orig + ray_vec * 1000000.0
-            mwi = world_mat.inverted()
-            ray_orig_obj = mwi * ray_orig
-            ray_tgt_obj = mwi * ray_tgt
-            ray_dir_obj = ray_tgt_obj - ray_orig_obj
-            ray_dir_obj.normalize()
-            tree = BVHTree.FromBMesh(bm)
-            loc, _, fidx, _ = tree.ray_cast(ray_orig_obj, ray_dir_obj)
-            if not loc:
-                return
-            loops = [l for l in bm.faces[fidx].loops]
-            uvs = [Vector((l[uv_layer].uv.x, l[uv_layer].uv.y, 0.0))
-                   for l in loops]
-            target_uv = barycentric_transform(
-                loc, loops[0].vert.co, loops[1].vert.co, loops[2].vert.co,
-                uvs[0], uvs[1], uvs[2])
-            target_uv = Vector((target_uv.x, target_uv.y))
-
-            # move to target UV coordinate
-            for info in loop_info:
-                l = bm.faces[info["face_idx"]].loops[info["loop_idx"]]
-                if sc.muv_uv_sculpt_pinch_invert:
-                    diff_uv = (l[uv_layer].uv - target_uv) * info["strength"]
-                else:
-                    diff_uv = (target_uv - l[uv_layer].uv) * info["strength"]
-                l[uv_layer].uv = l[uv_layer].uv + diff_uv / 10.0
-
-        elif sc.muv_uv_sculpt_tools == 'RELAX':
-            _, region, space = common.get_space_legacy('VIEW_3D', 'WINDOW',
-                                                       'VIEW_3D')
-
-            # get vertex and loop relation
-            vert_db = {}
-            for f in bm.faces:
-                for l in f.loops:
-                    if l.vert in vert_db:
-                        vert_db[l.vert]["loops"].append(l)
-                    else:
-                        vert_db[l.vert] = {"loops": [l]}
-
-            # get relaxation information
-            for k in vert_db.keys():
-                d = vert_db[k]
-                d["uv_sum"] = Vector((0.0, 0.0))
-                d["uv_count"] = 0
-
-                for l in d["loops"]:
-                    ln = l.link_loop_next
-                    lp = l.link_loop_prev
-                    d["uv_sum"] = d["uv_sum"] + ln[uv_layer].uv
-                    d["uv_sum"] = d["uv_sum"] + lp[uv_layer].uv
-                    d["uv_count"] = d["uv_count"] + 2
-                d["uv_p"] = d["uv_sum"] / d["uv_count"]
-                d["uv_b"] = d["uv_p"] - d["loops"][0][uv_layer].uv
-            for k in vert_db.keys():
-                d = vert_db[k]
-                d["uv_sum_b"] = Vector((0.0, 0.0))
-                for l in d["loops"]:
-                    ln = l.link_loop_next
-                    lp = l.link_loop_prev
-                    dn = vert_db[ln.vert]
-                    dp = vert_db[lp.vert]
-                    d["uv_sum_b"] = d["uv_sum_b"] + dn["uv_b"] + dp["uv_b"]
-
-            # apply
-            for f in bm.faces:
-                if not f.select:
-                    continue
-                for i, l in enumerate(f.loops):
-                    loc_2d = view3d_utils.location_3d_to_region_2d(
-                        region, space.region_3d, world_mat * l.vert.co)
-                    diff = loc_2d - self.__initial_mco
-                    if diff.length >= sc.muv_uv_sculpt_radius:
-                        continue
-                    db = vert_db[l.vert]
-                    strength = impl.get_strength(diff.length,
-                                                 sc.muv_uv_sculpt_radius,
-                                                 sc.muv_uv_sculpt_strength)
-
-                    base = (1.0 - strength) * l[uv_layer].uv
-                    if sc.muv_uv_sculpt_relax_method == 'HC':
-                        t = 0.5 * (db["uv_b"] + db["uv_sum_b"] / d["uv_count"])
-                        diff = strength * (db["uv_p"] - t)
-                        target_uv = base + diff
-                    elif sc.muv_uv_sculpt_relax_method == 'LAPLACIAN':
-                        diff = strength * db["uv_p"]
-                        target_uv = base + diff
-                    else:
-                        continue
-
-                    l[uv_layer].uv = target_uv
-
-        bmesh.update_edit_mesh(obj.data)
-
-    def __stroke_exit(self, context, _):
-        sc = context.scene
-        obj = context.active_object
-        bm = bmesh.from_edit_mesh(obj.data)
-        uv_layer = bm.loops.layers.uv.verify()
-        mco = self.current_mco
-
-        if sc.muv_uv_sculpt_tools == 'GRAB':
-            for info in self.__loop_info:
-                diff_uv = (mco - self.__initial_mco) * info["strength"]
-                l = bm.faces[info["face_idx"]].loops[info["loop_idx"]]
-                l[uv_layer].uv = info["initial_uv"] + diff_uv / 100.0
-
-        bmesh.update_edit_mesh(obj.data)
-
-    def modal(self, context, event):
-        if context.area:
-            context.area.tag_redraw()
-
-        if not MUV_OT_UVSculpt.is_running(context):
-            MUV_OT_UVSculpt.handle_remove(context)
-
-            return {'FINISHED'}
-
-        self.current_mco = Vector((event.mouse_region_x, event.mouse_region_y))
-
-        region_types = [
-            'HEADER',
-            'UI',
-            'TOOLS',
-            'TOOL_PROPS',
-        ]
-        if not common.mouse_on_area_legacy(event, 'VIEW_3D') or \
-           common.mouse_on_regions_legacy(event, 'VIEW_3D', region_types):
-            return {'PASS_THROUGH'}
-
-        if event.type == 'LEFTMOUSE':
-            if event.value == 'PRESS':
-                if not self.__stroking:
-                    self.__stroke_init(context, event)
-                self.__stroking = True
-            elif event.value == 'RELEASE':
-                if self.__stroking:
-                    self.__stroke_exit(context, event)
-                self.__stroking = False
-            return {'RUNNING_MODAL'}
-        elif event.type == 'MOUSEMOVE':
-            if self.__stroking:
-                self.__stroke_apply(context, event)
-            return {'RUNNING_MODAL'}
-        elif event.type == 'TIMER':
-            if self.__stroking:
-                self.__stroke_apply(context, event)
-            return {'RUNNING_MODAL'}
-
-        return {'PASS_THROUGH'}
-
-    def invoke(self, context, _):
-        if context.area:
-            context.area.tag_redraw()
-
-        if MUV_OT_UVSculpt.is_running(context):
-            MUV_OT_UVSculpt.handle_remove(context)
-        else:
-            MUV_OT_UVSculpt.handle_add(self, context)
-
-        return {'RUNNING_MODAL'}
diff --git a/uv_magic_uv/legacy/op/uvw.py b/uv_magic_uv/legacy/op/uvw.py
deleted file mode 100644
index 56777b18aa18f1a451a0bcbafb42a31ead56012d..0000000000000000000000000000000000000000
--- a/uv_magic_uv/legacy/op/uvw.py
+++ /dev/null
@@ -1,181 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-__author__ = "Alexander Milovsky, Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-import bmesh
-from bpy.props import (
-    FloatProperty,
-    FloatVectorProperty,
-    BoolProperty
-)
-
-from ... import common
-from ...impl import uvw_impl as impl
-from ...utils.bl_class_registry import BlClassRegistry
-from ...utils.property_class_registry import PropertyClassRegistry
-
-
-__all__ = [
-    'Properties',
-    'MUV_OT_UVW_BoxMap',
-    'MUV_OT_UVW_BestPlanerMap',
-]
-
-
-@PropertyClassRegistry(legacy=True)
-class Properties:
-    idname = "uvw"
-
-    @classmethod
-    def init_props(cls, scene):
-        scene.muv_uvw_enabled = BoolProperty(
-            name="UVW Enabled",
-            description="UVW is enabled",
-            default=False
-        )
-        scene.muv_uvw_assign_uvmap = BoolProperty(
-            name="Assign UVMap",
-            description="Assign UVMap when no UVmaps are available",
-            default=True
-        )
-
-    @classmethod
-    def del_props(cls, scene):
-        del scene.muv_uvw_enabled
-        del scene.muv_uvw_assign_uvmap
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_UVW_BoxMap(bpy.types.Operator):
-    bl_idname = "uv.muv_uvw_operator_box_map"
-    bl_label = "Box Map"
-    bl_options = {'REGISTER', 'UNDO'}
-
-    size = FloatProperty(
-        name="Size",
-        default=1.0,
-        precision=4
-    )
-    rotation = FloatVectorProperty(
-        name="XYZ Rotation",
-        size=3,
-        default=(0.0, 0.0, 0.0)
-    )
-    offset = FloatVectorProperty(
-        name="XYZ Offset",
-        size=3,
-        default=(0.0, 0.0, 0.0)
-    )
-    tex_aspect = FloatProperty(
-        name="Texture Aspect",
-        default=1.0,
-        precision=4
-    )
-    assign_uvmap = BoolProperty(
-        name="Assign UVMap",
-        description="Assign UVMap when no UVmaps are available",
-        default=True
-    )
-
-    @classmethod
-    def poll(cls, context):
-        # we can not get area/space/region from console
-        if common.is_console_mode():
-            return True
-        return impl.is_valid_context(context)
-
-    def execute(self, context):
-        obj = context.active_object
-        bm = bmesh.from_edit_mesh(obj.data)
-        if common.check_version(2, 73, 0) >= 0:
-            bm.faces.ensure_lookup_table()
-
-        # get UV layer
-        uv_layer = impl.get_uv_layer(self, bm, self.assign_uvmap)
-        if not uv_layer:
-            return {'CANCELLED'}
-
-        impl.apply_box_map(bm, uv_layer, self.size, self.offset,
-                           self.rotation, self.tex_aspect)
-        bmesh.update_edit_mesh(obj.data)
-
-        return {'FINISHED'}
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_UVW_BestPlanerMap(bpy.types.Operator):
-    bl_idname = "uv.muv_uvw_operator_best_planer_map"
-    bl_label = "Best Planer Map"
-    bl_options = {'REGISTER', 'UNDO'}
-
-    size = FloatProperty(
-        name="Size",
-        default=1.0,
-        precision=4
-    )
-    rotation = FloatProperty(
-        name="XY Rotation",
-        default=0.0
-    )
-    offset = FloatVectorProperty(
-        name="XY Offset",
-        size=2,
-        default=(0.0, 0.0)
-    )
-    tex_aspect = FloatProperty(
-        name="Texture Aspect",
-        default=1.0,
-        precision=4
-    )
-    assign_uvmap = BoolProperty(
-        name="Assign UVMap",
-        description="Assign UVMap when no UVmaps are available",
-        default=True
-    )
-
-    @classmethod
-    def poll(cls, context):
-        # we can not get area/space/region from console
-        if common.is_console_mode():
-            return True
-        return impl.is_valid_context(context)
-
-    def execute(self, context):
-        obj = context.active_object
-        bm = bmesh.from_edit_mesh(obj.data)
-        if common.check_version(2, 73, 0) >= 0:
-            bm.faces.ensure_lookup_table()
-
-        # get UV layer
-        uv_layer = impl.get_uv_layer(self, bm, self.assign_uvmap)
-        if not uv_layer:
-            return {'CANCELLED'}
-
-        impl.apply_planer_map(bm, uv_layer, self.size, self.offset,
-                              self.rotation, self.tex_aspect)
-
-        bmesh.update_edit_mesh(obj.data)
-
-        return {'FINISHED'}
diff --git a/uv_magic_uv/legacy/op/world_scale_uv.py b/uv_magic_uv/legacy/op/world_scale_uv.py
deleted file mode 100644
index 4a6b28694528cdf95661b1e8d47f0e6763a7e0f4..0000000000000000000000000000000000000000
--- a/uv_magic_uv/legacy/op/world_scale_uv.py
+++ /dev/null
@@ -1,359 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-__author__ = "McBuff, Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-from bpy.props import (
-    EnumProperty,
-    FloatProperty,
-    IntVectorProperty,
-    BoolProperty,
-)
-
-from ...utils.bl_class_registry import BlClassRegistry
-from ...utils.property_class_registry import PropertyClassRegistry
-from ...impl import world_scale_uv_impl as impl
-
-
-@PropertyClassRegistry(legacy=True)
-class Properties:
-    idname = "world_scale_uv"
-
-    @classmethod
-    def init_props(cls, scene):
-        scene.muv_world_scale_uv_enabled = BoolProperty(
-            name="World Scale UV Enabled",
-            description="World Scale UV is enabled",
-            default=False
-        )
-        scene.muv_world_scale_uv_src_mesh_area = FloatProperty(
-            name="Mesh Area",
-            description="Source Mesh Area",
-            default=0.0,
-            min=0.0
-        )
-        scene.muv_world_scale_uv_src_uv_area = FloatProperty(
-            name="UV Area",
-            description="Source UV Area",
-            default=0.0,
-            min=0.0
-        )
-        scene.muv_world_scale_uv_src_density = FloatProperty(
-            name="Density",
-            description="Source Texel Density",
-            default=0.0,
-            min=0.0
-        )
-        scene.muv_world_scale_uv_tgt_density = FloatProperty(
-            name="Density",
-            description="Target Texel Density",
-            default=0.0,
-            min=0.0
-        )
-        scene.muv_world_scale_uv_tgt_scaling_factor = FloatProperty(
-            name="Scaling Factor",
-            default=1.0,
-            max=1000.0,
-            min=0.00001
-        )
-        scene.muv_world_scale_uv_tgt_texture_size = IntVectorProperty(
-            name="Texture Size",
-            size=2,
-            min=1,
-            soft_max=10240,
-            default=(1024, 1024),
-        )
-        scene.muv_world_scale_uv_mode = EnumProperty(
-            name="Mode",
-            description="Density calculation mode",
-            items=[
-                ('PROPORTIONAL_TO_MESH', "Proportional to Mesh",
-                 "Apply density proportionaled by mesh size"),
-                ('SCALING_DENSITY', "Scaling Density",
-                 "Apply scaled density from source"),
-                ('SAME_DENSITY', "Same Density",
-                 "Apply same density of source"),
-                ('MANUAL', "Manual", "Specify density and size by manual"),
-            ],
-            default='MANUAL'
-        )
-        scene.muv_world_scale_uv_origin = EnumProperty(
-            name="Origin",
-            description="Aspect Origin",
-            items=[
-                ('CENTER', "Center", "Center"),
-                ('LEFT_TOP', "Left Top", "Left Bottom"),
-                ('LEFT_CENTER', "Left Center", "Left Center"),
-                ('LEFT_BOTTOM', "Left Bottom", "Left Bottom"),
-                ('CENTER_TOP', "Center Top", "Center Top"),
-                ('CENTER_BOTTOM', "Center Bottom", "Center Bottom"),
-                ('RIGHT_TOP', "Right Top", "Right Top"),
-                ('RIGHT_CENTER', "Right Center", "Right Center"),
-                ('RIGHT_BOTTOM', "Right Bottom", "Right Bottom")
-
-            ],
-            default='CENTER'
-        )
-
-    @classmethod
-    def del_props(cls, scene):
-        del scene.muv_world_scale_uv_enabled
-        del scene.muv_world_scale_uv_src_mesh_area
-        del scene.muv_world_scale_uv_src_uv_area
-        del scene.muv_world_scale_uv_src_density
-        del scene.muv_world_scale_uv_tgt_density
-        del scene.muv_world_scale_uv_tgt_scaling_factor
-        del scene.muv_world_scale_uv_mode
-        del scene.muv_world_scale_uv_origin
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_WorldScaleUV_Measure(bpy.types.Operator):
-    """
-    Operation class: Measure face size
-    """
-
-    bl_idname = "uv.muv_world_scale_uv_operator_measure"
-    bl_label = "Measure World Scale UV"
-    bl_description = "Measure face size for scale calculation"
-    bl_options = {'REGISTER', 'UNDO'}
-
-    def __init__(self):
-        self.__impl = impl.MeasureImpl()
-
-    @classmethod
-    def poll(cls, context):
-        return impl.MeasureImpl.poll(context)
-
-    def execute(self, context):
-        return self.__impl.execute(self, context)
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_WorldScaleUV_ApplyManual(bpy.types.Operator):
-    """
-    Operation class: Apply scaled UV (Manual)
-    """
-
-    bl_idname = "uv.muv_world_scale_uv_operator_apply_manual"
-    bl_label = "Apply World Scale UV (Manual)"
-    bl_description = "Apply scaled UV based on user specification"
-    bl_options = {'REGISTER', 'UNDO'}
-
-    tgt_density = FloatProperty(
-        name="Density",
-        description="Target Texel Density",
-        default=1.0,
-        min=0.0
-    )
-    tgt_texture_size = IntVectorProperty(
-        name="Texture Size",
-        size=2,
-        min=1,
-        soft_max=10240,
-        default=(1024, 1024),
-    )
-    origin = EnumProperty(
-        name="Origin",
-        description="Aspect Origin",
-        items=[
-            ('CENTER', "Center", "Center"),
-            ('LEFT_TOP', "Left Top", "Left Bottom"),
-            ('LEFT_CENTER', "Left Center", "Left Center"),
-            ('LEFT_BOTTOM', "Left Bottom", "Left Bottom"),
-            ('CENTER_TOP', "Center Top", "Center Top"),
-            ('CENTER_BOTTOM', "Center Bottom", "Center Bottom"),
-            ('RIGHT_TOP', "Right Top", "Right Top"),
-            ('RIGHT_CENTER', "Right Center", "Right Center"),
-            ('RIGHT_BOTTOM', "Right Bottom", "Right Bottom")
-
-        ],
-        default='CENTER'
-    )
-    show_dialog = BoolProperty(
-        name="Show Diaglog Menu",
-        description="Show dialog menu if true",
-        default=True,
-        options={'HIDDEN', 'SKIP_SAVE'}
-    )
-
-    def __init__(self):
-        self.__impl = impl.ApplyManualImpl()
-
-    @classmethod
-    def poll(cls, context):
-        return impl.ApplyManualImpl.poll(context)
-
-    def draw(self, context):
-        self.__impl.draw(self, context)
-
-    def invoke(self, context, event):
-        return self.__impl.invoke(self, context, event)
-
-    def execute(self, context):
-        return self.__impl.execute(self, context)
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_WorldScaleUV_ApplyScalingDensity(bpy.types.Operator):
-    """
-    Operation class: Apply scaled UV (Scaling Density)
-    """
-
-    bl_idname = "uv.muv_world_scale_uv_operator_apply_scaling_density"
-    bl_label = "Apply World Scale UV (Scaling Density)"
-    bl_description = "Apply scaled UV with scaling density"
-    bl_options = {'REGISTER', 'UNDO'}
-
-    tgt_scaling_factor = FloatProperty(
-        name="Scaling Factor",
-        default=1.0,
-        max=1000.0,
-        min=0.00001
-    )
-    origin = EnumProperty(
-        name="Origin",
-        description="Aspect Origin",
-        items=[
-            ('CENTER', "Center", "Center"),
-            ('LEFT_TOP', "Left Top", "Left Bottom"),
-            ('LEFT_CENTER', "Left Center", "Left Center"),
-            ('LEFT_BOTTOM', "Left Bottom", "Left Bottom"),
-            ('CENTER_TOP', "Center Top", "Center Top"),
-            ('CENTER_BOTTOM', "Center Bottom", "Center Bottom"),
-            ('RIGHT_TOP', "Right Top", "Right Top"),
-            ('RIGHT_CENTER', "Right Center", "Right Center"),
-            ('RIGHT_BOTTOM', "Right Bottom", "Right Bottom")
-
-        ],
-        default='CENTER'
-    )
-    src_density = FloatProperty(
-        name="Density",
-        description="Source Texel Density",
-        default=0.0,
-        min=0.0,
-        options={'HIDDEN'}
-    )
-    same_density = BoolProperty(
-        name="Same Density",
-        description="Apply same density",
-        default=False,
-        options={'HIDDEN'}
-    )
-    show_dialog = BoolProperty(
-        name="Show Diaglog Menu",
-        description="Show dialog menu if true",
-        default=True,
-        options={'HIDDEN', 'SKIP_SAVE'}
-    )
-
-    def __init__(self):
-        self.__impl = impl.ApplyScalingDensityImpl()
-
-    @classmethod
-    def poll(cls, context):
-        return impl.ApplyScalingDensityImpl.poll(context)
-
-    def draw(self, context):
-        self.__impl.draw(self, context)
-
-    def invoke(self, context, event):
-        return self.__impl.invoke(self, context, event)
-
-    def execute(self, context):
-        return self.__impl.execute(self, context)
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_WorldScaleUV_ApplyProportionalToMesh(bpy.types.Operator):
-    """
-    Operation class: Apply scaled UV (Proportional to mesh)
-    """
-
-    bl_idname = "uv.muv_world_scale_uv_operator_apply_proportional_to_mesh"
-    bl_label = "Apply World Scale UV (Proportional to mesh)"
-    bl_description = "Apply scaled UV proportionaled to mesh"
-    bl_options = {'REGISTER', 'UNDO'}
-
-    origin = EnumProperty(
-        name="Origin",
-        description="Aspect Origin",
-        items=[
-            ('CENTER', "Center", "Center"),
-            ('LEFT_TOP', "Left Top", "Left Bottom"),
-            ('LEFT_CENTER', "Left Center", "Left Center"),
-            ('LEFT_BOTTOM', "Left Bottom", "Left Bottom"),
-            ('CENTER_TOP', "Center Top", "Center Top"),
-            ('CENTER_BOTTOM', "Center Bottom", "Center Bottom"),
-            ('RIGHT_TOP', "Right Top", "Right Top"),
-            ('RIGHT_CENTER', "Right Center", "Right Center"),
-            ('RIGHT_BOTTOM', "Right Bottom", "Right Bottom")
-
-        ],
-        default='CENTER'
-    )
-    src_density = FloatProperty(
-        name="Source Density",
-        description="Source Texel Density",
-        default=0.0,
-        min=0.0,
-        options={'HIDDEN'}
-    )
-    src_uv_area = FloatProperty(
-        name="Source UV Area",
-        description="Source UV Area",
-        default=0.0,
-        min=0.0,
-        options={'HIDDEN'}
-    )
-    src_mesh_area = FloatProperty(
-        name="Source Mesh Area",
-        description="Source Mesh Area",
-        default=0.0,
-        min=0.0,
-        options={'HIDDEN'}
-    )
-    show_dialog = BoolProperty(
-        name="Show Diaglog Menu",
-        description="Show dialog menu if true",
-        default=True,
-        options={'HIDDEN', 'SKIP_SAVE'}
-    )
-
-    def __init__(self):
-        self.__impl = impl.ApplyProportionalToMeshImpl()
-
-    @classmethod
-    def poll(cls, context):
-        return impl.ApplyProportionalToMeshImpl.poll(context)
-
-    def draw(self, context):
-        self.__impl.draw(self, context)
-
-    def invoke(self, context, event):
-        return self.__impl.invoke(self, context, event)
-
-    def execute(self, context):
-        return self.__impl.execute(self, context)
diff --git a/uv_magic_uv/legacy/preferences.py b/uv_magic_uv/legacy/preferences.py
deleted file mode 100644
index e21f175394099191ee5d57e42d982236a4c5dc5f..0000000000000000000000000000000000000000
--- a/uv_magic_uv/legacy/preferences.py
+++ /dev/null
@@ -1,518 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-__author__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-from bpy.props import (
-    FloatProperty,
-    FloatVectorProperty,
-    BoolProperty,
-    EnumProperty,
-    IntProperty,
-    StringProperty,
-)
-from bpy.types import AddonPreferences
-
-from . import op
-from . import ui
-from ..utils.bl_class_registry import BlClassRegistry
-from ..utils.addon_updator import AddonUpdatorManager
-
-__all__ = [
-    'add_builtin_menu',
-    'remove_builtin_menu',
-    'Preferences'
-]
-
-
-def view3d_uvmap_menu_fn(self, context):
-    layout = self.layout
-    sc = context.scene
-
-    layout.separator()
-    layout.label(text="Copy/Paste UV", icon='IMAGE_COL')
-    # Copy/Paste UV
-    layout.menu(ui.VIEW3D_MT_uv_map.MUV_MT_CopyPasteUV.bl_idname,
-                text="Copy/Paste UV")
-    # Transfer UV
-    layout.menu(ui.VIEW3D_MT_uv_map.MUV_MT_TransferUV.bl_idname,
-                text="Transfer UV")
-
-    layout.separator()
-    layout.label("UV Manipulation", icon='IMAGE_COL')
-    # Flip/Rotate UV
-    ops = layout.operator(op.flip_rotate_uv.MUV_OT_FlipRotate.bl_idname,
-                          text="Flip/Rotate UV")
-    ops.seams = sc.muv_flip_rotate_uv_seams
-    # Mirror UV
-    ops = layout.operator(op.mirror_uv.MUV_OT_MirrorUV.bl_idname,
-                          text="Mirror UV")
-    ops.axis = sc.muv_mirror_uv_axis
-    # Move UV
-    layout.operator(op.move_uv.MUV_OT_MoveUV.bl_idname, text="Move UV")
-    # World Scale UV
-    layout.menu(ui.VIEW3D_MT_uv_map.MUV_MT_WorldScaleUV.bl_idname,
-                text="World Scale UV")
-    # Preserve UV
-    layout.menu(ui.VIEW3D_MT_uv_map.MUV_MT_PreserveUVAspect.bl_idname,
-                text="Preserve UV")
-    # Texture Lock
-    layout.menu(ui.VIEW3D_MT_uv_map.MUV_MT_TextureLock.bl_idname,
-                text="Texture Lock")
-    # Texture Wrap
-    layout.menu(ui.VIEW3D_MT_uv_map.MUV_MT_TextureWrap.bl_idname,
-                text="Texture Wrap")
-    # UV Sculpt
-    layout.prop(sc, "muv_uv_sculpt_enable", text="UV Sculpt")
-
-    layout.separator()
-    layout.label("UV Mapping", icon='IMAGE_COL')
-    # Unwrap Constraint
-    ops = layout.operator(
-        op.unwrap_constraint.MUV_OT_UnwrapConstraint.bl_idname,
-        text="Unwrap Constraint")
-    ops.u_const = sc.muv_unwrap_constraint_u_const
-    ops.v_const = sc.muv_unwrap_constraint_v_const
-    # Texture Projection
-    layout.menu(ui.VIEW3D_MT_uv_map.MUV_MT_TextureProjection.bl_idname,
-                text="Texture Projection")
-    # UVW
-    layout.menu(ui.VIEW3D_MT_uv_map.MUV_MT_UVW.bl_idname, text="UVW")
-
-
-def view3d_object_menu_fn(self, _):
-    layout = self.layout
-
-    layout.separator()
-    # Copy/Paste UV (Among Objecct)
-    layout.menu(ui.VIEW3D_MT_object.MUV_MT_CopyPasteUV_Object.bl_idname,
-                text="Copy/Paste UV")
-    layout.label("Copy/Paste UV", icon='IMAGE_COL')
-
-
-def image_uvs_menu_fn(self, context):
-    layout = self.layout
-    sc = context.scene
-
-    layout.separator()
-    # Align UV Cursor
-    layout.menu(ui.IMAGE_MT_uvs.MUV_MT_AlignUVCursor.bl_idname,
-                text="Align UV Cursor")
-    # UV Bounding Box
-    layout.prop(sc, "muv_uv_bounding_box_show", text="UV Bounding Box")
-    # UV Inspection
-    layout.menu(ui.IMAGE_MT_uvs.MUV_MT_UVInspection.bl_idname,
-                text="UV Inspection")
-    layout.label("Editor Enhancement", icon='IMAGE_COL')
-
-    layout.separator()
-    # Align UV
-    layout.menu(ui.IMAGE_MT_uvs.MUV_MT_AlignUV.bl_idname, text="Align UV")
-    # Smooth UV
-    ops = layout.operator(op.smooth_uv.MUV_OT_SmoothUV.bl_idname,
-                          text="Smooth")
-    ops.transmission = sc.muv_smooth_uv_transmission
-    ops.select = sc.muv_smooth_uv_select
-    ops.mesh_infl = sc.muv_smooth_uv_mesh_infl
-    # Select UV
-    layout.menu(ui.IMAGE_MT_uvs.MUV_MT_SelectUV.bl_idname, text="Select UV")
-    # Pack UV
-    ops = layout.operator(op.pack_uv.MUV_OT_PackUV.bl_idname, text="Pack UV")
-    ops.allowable_center_deviation = sc.muv_pack_uv_allowable_center_deviation
-    ops.allowable_size_deviation = sc.muv_pack_uv_allowable_size_deviation
-    layout.label("UV Manipulation", icon='IMAGE_COL')
-
-    layout.separator()
-    # Copy/Paste UV (on UV/Image Editor)
-    layout.menu(ui.IMAGE_MT_uvs.MUV_MT_CopyPasteUV_UVEdit.bl_idname,
-                text="Copy/Paste UV")
-    layout.label("Copy/Paste UV", icon='IMAGE_COL')
-
-
-def add_builtin_menu():
-    bpy.types.VIEW3D_MT_uv_map.append(view3d_uvmap_menu_fn)
-    bpy.types.VIEW3D_MT_object.append(view3d_object_menu_fn)
-    bpy.types.IMAGE_MT_uvs.append(image_uvs_menu_fn)
-
-
-def remove_builtin_menu():
-    bpy.types.IMAGE_MT_uvs.remove(image_uvs_menu_fn)
-    bpy.types.VIEW3D_MT_uv_map.remove(view3d_uvmap_menu_fn)
-    bpy.types.VIEW3D_MT_object.remove(view3d_object_menu_fn)
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_CheckAddonUpdate(bpy.types.Operator):
-    bl_idname = "uv.muv_check_addon_update"
-    bl_label = "Check Update"
-    bl_description = "Check Add-on Update"
-    bl_options = {'REGISTER', 'UNDO'}
-
-    def execute(self, context):
-        updater = AddonUpdatorManager.get_instance()
-        updater.check_update_candidate()
-
-        return {'FINISHED'}
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_UpdateAddon(bpy.types.Operator):
-    bl_idname = "uv.muv_update_addon"
-    bl_label = "Update"
-    bl_description = "Update Add-on"
-    bl_options = {'REGISTER', 'UNDO'}
-
-    branch_name = StringProperty(
-        name="Branch Name",
-        description="Branch name to update",
-        default="",
-    )
-
-    def execute(self, context):
-        updater = AddonUpdatorManager.get_instance()
-        updater.update(self.branch_name)
-
-        return {'FINISHED'}
-
-
-def get_update_candidate_branches(_, __):
-    updater = AddonUpdatorManager.get_instance()
-    if not updater.candidate_checked():
-        return []
-
-    return [(name, name, "") for name in updater.get_candidate_branch_names()]
-
-
-@BlClassRegistry(legacy=True)
-class Preferences(AddonPreferences):
-    """Preferences class: Preferences for this add-on"""
-
-    bl_idname = "uv_magic_uv"
-
-    def update_enable_builtin_menu(self, _):
-        if self['enable_builtin_menu']:
-            add_builtin_menu()
-        else:
-            remove_builtin_menu()
-
-    # enable to add features to built-in menu
-    enable_builtin_menu = BoolProperty(
-        name="Built-in Menu",
-        description="Enable built-in menu",
-        default=True,
-        update=update_enable_builtin_menu
-    )
-
-    # for UV Sculpt
-    uv_sculpt_brush_color = FloatVectorProperty(
-        name="Color",
-        description="Color",
-        default=(1.0, 0.4, 0.4, 1.0),
-        min=0.0,
-        max=1.0,
-        size=4,
-        subtype='COLOR'
-    )
-
-    # for Overlapped UV
-    uv_inspection_overlapped_color = FloatVectorProperty(
-        name="Color",
-        description="Color",
-        default=(0.0, 0.0, 1.0, 0.3),
-        min=0.0,
-        max=1.0,
-        size=4,
-        subtype='COLOR'
-    )
-
-    # for Flipped UV
-    uv_inspection_flipped_color = FloatVectorProperty(
-        name="Color",
-        description="Color",
-        default=(1.0, 0.0, 0.0, 0.3),
-        min=0.0,
-        max=1.0,
-        size=4,
-        subtype='COLOR'
-    )
-
-    # for Texture Projection
-    texture_projection_canvas_padding = FloatVectorProperty(
-        name="Canvas Padding",
-        description="Canvas Padding",
-        size=2,
-        max=50.0,
-        min=0.0,
-        default=(20.0, 20.0))
-
-    # for UV Bounding Box
-    uv_bounding_box_cp_size = FloatProperty(
-        name="Size",
-        description="Control Point Size",
-        default=6.0,
-        min=3.0,
-        max=100.0)
-    uv_bounding_box_cp_react_size = FloatProperty(
-        name="React Size",
-        description="Size event fired",
-        default=10.0,
-        min=3.0,
-        max=100.0)
-
-    # for UI
-    category = EnumProperty(
-        name="Category",
-        description="Preferences Category",
-        items=[
-            ('INFO', "Information", "Information about this add-on"),
-            ('CONFIG', "Configuration", "Configuration about this add-on"),
-            ('UPDATE', "Update", "Update this add-on"),
-        ],
-        default='INFO'
-    )
-    info_desc_expanded = BoolProperty(
-        name="Description",
-        description="Description",
-        default=False
-    )
-    info_loc_expanded = BoolProperty(
-        name="Location",
-        description="Location",
-        default=False
-    )
-    conf_uv_sculpt_expanded = BoolProperty(
-        name="UV Sculpt",
-        description="UV Sculpt",
-        default=False
-    )
-    conf_uv_inspection_expanded = BoolProperty(
-        name="UV Inspection",
-        description="UV Inspection",
-        default=False
-    )
-    conf_texture_projection_expanded = BoolProperty(
-        name="Texture Projection",
-        description="Texture Projection",
-        default=False
-    )
-    conf_uv_bounding_box_expanded = BoolProperty(
-        name="UV Bounding Box",
-        description="UV Bounding Box",
-        default=False
-    )
-
-    # for add-on updater
-    auto_check_update = BoolProperty(
-        name="Auto-check for Update",
-        description="If enabled, auto-check for updates using an interval",
-        default=False
-    )
-    updater_intrval_months = IntProperty(
-        name='Months',
-        description="Number of months between checking for updates",
-        default=0,
-        min=0
-    )
-    updater_intrval_days = IntProperty(
-        name='Days',
-        description="Number of days between checking for updates",
-        default=7,
-        min=0
-    )
-    updater_intrval_hours = IntProperty(
-        name='Hours',
-        description="Number of hours between checking for updates",
-        default=0,
-        min=0,
-        max=23
-    )
-    updater_intrval_minutes = IntProperty(
-        name='Minutes',
-        description="Number of minutes between checking for updates",
-        default=0,
-        min=0,
-        max=59
-    )
-
-    # for add-on updater
-    updater_branch_to_update = EnumProperty(
-        name="branch",
-        description="Target branch to update add-on",
-        items=get_update_candidate_branches
-    )
-
-    def draw(self, context):
-        layout = self.layout
-
-        layout.row().prop(self, "category", expand=True)
-
-        if self.category == 'INFO':
-            layout.prop(
-                self, "info_desc_expanded", text="Description",
-                icon='DISCLOSURE_TRI_DOWN' if self.info_desc_expanded
-                else 'DISCLOSURE_TRI_RIGHT')
-            if self.info_desc_expanded:
-                column = layout.column(align=True)
-                column.label("Magic UV is composed of many UV editing" +
-                             " features.")
-                column.label("See tutorial page if you are new to this" +
-                             " add-on.")
-                column.label("https://github.com/nutti/Magic-UV/wiki/Tutorial")
-
-            layout.prop(
-                self, "info_loc_expanded", text="Location",
-                icon='DISCLOSURE_TRI_DOWN' if self.info_loc_expanded
-                else 'DISCLOSURE_TRI_RIGHT')
-            if self.info_loc_expanded:
-                row = layout.row(align=True)
-                sp = row.split(percentage=0.5)
-                sp.label("3D View > Tool shelf > Copy/Paste UV (Object mode)")
-                sp = sp.split(percentage=1.0)
-                col = sp.column(align=True)
-                col.label("Copy/Paste UV (Among objects)")
-
-                row = layout.row(align=True)
-                sp = row.split(percentage=0.5)
-                sp.label("3D View > Tool shelf > Copy/Paste UV (Edit mode)")
-                sp = sp.split(percentage=1.0)
-                col = sp.column(align=True)
-                col.label("Copy/Paste UV (Among faces in 3D View)")
-                col.label("Transfer UV")
-
-                row = layout.row(align=True)
-                sp = row.split(percentage=0.5)
-                sp.label("3D View > Tool shelf > UV Manipulation (Edit mode)")
-                sp = sp.split(percentage=1.0)
-                col = sp.column(align=True)
-                col.label("Flip/Rotate UV")
-                col.label("Mirror UV")
-                col.label("Move UV")
-                col.label("World Scale UV")
-                col.label("Preserve UV Aspect")
-                col.label("Texture Lock")
-                col.label("Texture Wrap")
-                col.label("UV Sculpt")
-
-                row = layout.row(align=True)
-                sp = row.split(percentage=0.5)
-                sp.label("3D View > Tool shelf > UV Manipulation (Edit mode)")
-                sp = sp.split(percentage=1.0)
-                col = sp.column(align=True)
-                col.label("Unwrap Constraint")
-                col.label("Texture Projection")
-                col.label("UVW")
-
-                row = layout.row(align=True)
-                sp = row.split(percentage=0.5)
-                sp.label("UV/Image Editor > Tool shelf > Copy/Paste UV")
-                sp = sp.split(percentage=1.0)
-                col = sp.column(align=True)
-                col.label("Copy/Paste UV (Among faces in UV/Image Editor)")
-
-                row = layout.row(align=True)
-                sp = row.split(percentage=0.5)
-                sp.label("UV/Image Editor > Tool shelf > UV Manipulation")
-                sp = sp.split(percentage=1.0)
-                col = sp.column(align=True)
-                col.label("Align UV")
-                col.label("Smooth UV")
-                col.label("Select UV")
-                col.label("Pack UV (Extension)")
-
-                row = layout.row(align=True)
-                sp = row.split(percentage=0.5)
-                sp.label("UV/Image Editor > Tool shelf > Editor Enhancement")
-                sp = sp.split(percentage=1.0)
-                col = sp.column(align=True)
-                col.label("Align UV Cursor")
-                col.label("UV Cursor Location")
-                col.label("UV Bounding Box")
-                col.label("UV Inspection")
-
-        elif self.category == 'CONFIG':
-            layout.prop(self, "enable_builtin_menu", text="Built-in Menu")
-
-            layout.separator()
-
-            layout.prop(
-                self, "conf_uv_sculpt_expanded", text="UV Sculpt",
-                icon='DISCLOSURE_TRI_DOWN' if self.conf_uv_sculpt_expanded
-                else 'DISCLOSURE_TRI_RIGHT')
-            if self.conf_uv_sculpt_expanded:
-                sp = layout.split(percentage=0.05)
-                col = sp.column()  # spacer
-                sp = sp.split(percentage=0.3)
-                col = sp.column()
-                col.label("Brush Color:")
-                col.prop(self, "uv_sculpt_brush_color", text="")
-                layout.separator()
-
-            layout.prop(
-                self, "conf_uv_inspection_expanded", text="UV Inspection",
-                icon='DISCLOSURE_TRI_DOWN' if self.conf_uv_inspection_expanded
-                else 'DISCLOSURE_TRI_RIGHT')
-            if self.conf_uv_inspection_expanded:
-                sp = layout.split(percentage=0.05)
-                col = sp.column()  # spacer
-                sp = sp.split(percentage=0.3)
-                col = sp.column()
-                col.label("Overlapped UV Color:")
-                col.prop(self, "uv_inspection_overlapped_color", text="")
-                sp = sp.split(percentage=0.45)
-                col = sp.column()
-                col.label("Flipped UV Color:")
-                col.prop(self, "uv_inspection_flipped_color", text="")
-                layout.separator()
-
-            layout.prop(
-                self, "conf_texture_projection_expanded",
-                text="Texture Projection",
-                icon='DISCLOSURE_TRI_DOWN'
-                if self.conf_texture_projection_expanded
-                else 'DISCLOSURE_TRI_RIGHT')
-            if self.conf_texture_projection_expanded:
-                sp = layout.split(percentage=0.05)
-                col = sp.column()       # spacer
-                sp = sp.split(percentage=0.3)
-                col = sp.column()
-                col.prop(self, "texture_projection_canvas_padding")
-                layout.separator()
-
-            layout.prop(
-                self, "conf_uv_bounding_box_expanded", text="UV Bounding Box",
-                icon='DISCLOSURE_TRI_DOWN'
-                if self.conf_uv_bounding_box_expanded
-                else 'DISCLOSURE_TRI_RIGHT')
-            if self.conf_uv_bounding_box_expanded:
-                sp = layout.split(percentage=0.05)
-                col = sp.column()       # spacer
-                sp = sp.split(percentage=0.3)
-                col = sp.column()
-                col.label("Control Point:")
-                col.prop(self, "uv_bounding_box_cp_size")
-                col.prop(self, "uv_bounding_box_cp_react_size")
-                layout.separator()
-
-        elif self.category == 'UPDATE':
-            addon_updater_ops.update_settings_ui(self, context)
diff --git a/uv_magic_uv/legacy/properites.py b/uv_magic_uv/legacy/properites.py
deleted file mode 100644
index b64a48f39010fdfa5357146a0bcbbaac08dea18e..0000000000000000000000000000000000000000
--- a/uv_magic_uv/legacy/properites.py
+++ /dev/null
@@ -1,61 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-__author__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-
-from ..utils.property_class_registry import PropertyClassRegistry
-
-__all__ = [
-    'MUV_Properties',
-    'init_props',
-    'clear_props',
-]
-
-
-# Properties used in this add-on.
-# pylint: disable=W0612
-class MUV_Properties():
-    def __init__(self):
-        self.prefs = MUV_Prefs()
-
-
-class MUV_Prefs():
-    expanded = {
-        "info_desc": False,
-        "info_loc": False,
-        "conf_uvsculpt": False,
-        "conf_uvinsp": False,
-        "conf_texproj": False,
-        "conf_uvbb": False
-    }
-
-
-def init_props(scene):
-    scene.muv_props = MUV_Properties()
-    PropertyClassRegistry.init_props(scene)
-
-
-def clear_props(scene):
-    PropertyClassRegistry.del_props(scene)
-    del scene.muv_props
diff --git a/uv_magic_uv/legacy/ui/IMAGE_MT_uvs.py b/uv_magic_uv/legacy/ui/IMAGE_MT_uvs.py
deleted file mode 100644
index bf071bf5f07ea56d291e8fa1f6bc3640ea8d11dc..0000000000000000000000000000000000000000
--- a/uv_magic_uv/legacy/ui/IMAGE_MT_uvs.py
+++ /dev/null
@@ -1,197 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-__author__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-
-from ..op import (
-    align_uv_cursor,
-    copy_paste_uv_uvedit,
-    align_uv,
-    select_uv,
-    uv_inspection
-)
-from ...utils.bl_class_registry import BlClassRegistry
-
-__all__ = [
-    'MUV_MT_CopyPasteUV_UVEdit',
-    'MUV_MT_AlignUV',
-    'MUV_MT_SelectUV',
-    'MUV_MT_AlignUVCursor',
-    'MUV_MT_UVInspection',
-]
-
-
-@BlClassRegistry(legacy=True)
-class MUV_MT_CopyPasteUV_UVEdit(bpy.types.Menu):
-    """
-    Menu class: Master menu of Copy/Paste UV coordinate on UV/ImageEditor
-    """
-
-    bl_idname = "uv.muv_copy_paste_uv_uvedit_menu"
-    bl_label = "Copy/Paste UV"
-    bl_description = "Copy and Paste UV coordinate among object"
-
-    def draw(self, _):
-        layout = self.layout
-
-        layout.operator(
-            copy_paste_uv_uvedit.MUV_OT_CopyPasteUVUVEdit_CopyUV.bl_idname,
-            text="Copy")
-        layout.operator(
-            copy_paste_uv_uvedit.MUV_OT_CopyPasteUVUVEdit_PasteUV.bl_idname,
-            text="Paste")
-
-
-@BlClassRegistry(legacy=True)
-class MUV_MT_AlignUV(bpy.types.Menu):
-    """
-    Menu class: Master menu of Align UV
-    """
-
-    bl_idname = "uv.muv_align_uv_menu"
-    bl_label = "Align UV"
-    bl_description = "Align UV"
-
-    def draw(self, context):
-        layout = self.layout
-        sc = context.scene
-
-        ops = layout.operator(align_uv.MUV_OT_AlignUV_Circle.bl_idname,
-                              text="Circle")
-        ops.transmission = sc.muv_align_uv_transmission
-        ops.select = sc.muv_align_uv_select
-
-        ops = layout.operator(align_uv.MUV_OT_AlignUV_Straighten.bl_idname,
-                              text="Straighten")
-        ops.transmission = sc.muv_align_uv_transmission
-        ops.select = sc.muv_align_uv_select
-        ops.vertical = sc.muv_align_uv_vertical
-        ops.horizontal = sc.muv_align_uv_horizontal
-
-        ops = layout.operator(align_uv.MUV_OT_AlignUV_Axis.bl_idname,
-                              text="XY-axis")
-        ops.transmission = sc.muv_align_uv_transmission
-        ops.select = sc.muv_align_uv_select
-        ops.vertical = sc.muv_align_uv_vertical
-        ops.horizontal = sc.muv_align_uv_horizontal
-        ops.location = sc.muv_align_uv_location
-
-
-@BlClassRegistry(legacy=True)
-class MUV_MT_SelectUV(bpy.types.Menu):
-    """
-    Menu class: Master menu of Select UV
-    """
-
-    bl_idname = "uv.muv_select_uv_menu"
-    bl_label = "Select UV"
-    bl_description = "Select UV"
-
-    def draw(self, _):
-        layout = self.layout
-
-        layout.operator(select_uv.MUV_OT_SelectUV_SelectOverlapped.bl_idname,
-                        text="Overlapped")
-        layout.operator(select_uv.MUV_OT_SelectUV_SelectFlipped.bl_idname,
-                        text="Flipped")
-
-
-@BlClassRegistry(legacy=True)
-class MUV_MT_AlignUVCursor(bpy.types.Menu):
-    """
-    Menu class: Master menu of Align UV Cursor
-    """
-
-    bl_idname = "uv.muv_align_uv_cursor_menu"
-    bl_label = "Align UV Cursor"
-    bl_description = "Align UV cursor"
-
-    def draw(self, context):
-        layout = self.layout
-        sc = context.scene
-
-        ops = layout.operator(align_uv_cursor.MUV_OT_AlignUVCursor.bl_idname,
-                              text="Left Top")
-        ops.position = 'LEFT_TOP'
-        ops.base = sc.muv_align_uv_cursor_align_method
-
-        ops = layout.operator(align_uv_cursor.MUV_OT_AlignUVCursor.bl_idname,
-                              text="Middle Top")
-        ops.position = 'MIDDLE_TOP'
-        ops.base = sc.muv_align_uv_cursor_align_method
-
-        ops = layout.operator(align_uv_cursor.MUV_OT_AlignUVCursor.bl_idname,
-                              text="Right Top")
-        ops.position = 'RIGHT_TOP'
-        ops.base = sc.muv_align_uv_cursor_align_method
-
-        ops = layout.operator(align_uv_cursor.MUV_OT_AlignUVCursor.bl_idname,
-                              text="Left Middle")
-        ops.position = 'LEFT_MIDDLE'
-        ops.base = sc.muv_align_uv_cursor_align_method
-
-        ops = layout.operator(align_uv_cursor.MUV_OT_AlignUVCursor.bl_idname,
-                              text="Center")
-        ops.position = 'CENTER'
-        ops.base = sc.muv_align_uv_cursor_align_method
-
-        ops = layout.operator(align_uv_cursor.MUV_OT_AlignUVCursor.bl_idname,
-                              text="Right Middle")
-        ops.position = 'RIGHT_MIDDLE'
-        ops.base = sc.muv_align_uv_cursor_align_method
-
-        ops = layout.operator(align_uv_cursor.MUV_OT_AlignUVCursor.bl_idname,
-                              text="Left Bottom")
-        ops.position = 'LEFT_BOTTOM'
-        ops.base = sc.muv_align_uv_cursor_align_method
-
-        ops = layout.operator(align_uv_cursor.MUV_OT_AlignUVCursor.bl_idname,
-                              text="Middle Bottom")
-        ops.position = 'MIDDLE_BOTTOM'
-        ops.base = sc.muv_align_uv_cursor_align_method
-
-        ops = layout.operator(align_uv_cursor.MUV_OT_AlignUVCursor.bl_idname,
-                              text="Right Bottom")
-        ops.position = 'RIGHT_BOTTOM'
-        ops.base = sc.muv_align_uv_cursor_align_method
-
-
-@BlClassRegistry(legacy=True)
-class MUV_MT_UVInspection(bpy.types.Menu):
-    """
-    Menu class: Master menu of UV Inspection
-    """
-
-    bl_idname = "uv.muv_uv_inspection_menu"
-    bl_label = "UV Inspection"
-    bl_description = "UV Inspection"
-
-    def draw(self, context):
-        layout = self.layout
-        sc = context.scene
-
-        layout.prop(sc, "muv_uv_inspection_show", text="UV Inspection")
-        layout.operator(uv_inspection.MUV_OT_UVInspection_Update.bl_idname,
-                        text="Update")
diff --git a/uv_magic_uv/legacy/ui/VIEW3D_MT_object.py b/uv_magic_uv/legacy/ui/VIEW3D_MT_object.py
deleted file mode 100644
index e1c751ae798dfc1793bae3dfc08b362dd62e2a17..0000000000000000000000000000000000000000
--- a/uv_magic_uv/legacy/ui/VIEW3D_MT_object.py
+++ /dev/null
@@ -1,54 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-__author__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-
-from ..op import copy_paste_uv_object
-from ...utils.bl_class_registry import BlClassRegistry
-
-__all__ = [
-    'MUV_MT_CopyPasteUV_Object',
-]
-
-
-@BlClassRegistry(legacy=True)
-class MUV_MT_CopyPasteUV_Object(bpy.types.Menu):
-    """
-    Menu class: Master menu of Copy/Paste UV coordinate among object
-    """
-
-    bl_idname = "uv.muv_copy_paste_uv_object_menu"
-    bl_label = "Copy/Paste UV"
-    bl_description = "Copy and Paste UV coordinate among object"
-
-    def draw(self, _):
-        layout = self.layout
-
-        layout.menu(
-            copy_paste_uv_object.MUV_MT_CopyPasteUVObject_CopyUV.bl_idname,
-            text="Copy")
-        layout.menu(
-            copy_paste_uv_object.MUV_MT_CopyPasteUVObject_PasteUV.bl_idname,
-            text="Paste")
diff --git a/uv_magic_uv/legacy/ui/VIEW3D_MT_uv_map.py b/uv_magic_uv/legacy/ui/VIEW3D_MT_uv_map.py
deleted file mode 100644
index d229322a034aa382920c3b0ab782bb1d1f891d20..0000000000000000000000000000000000000000
--- a/uv_magic_uv/legacy/ui/VIEW3D_MT_uv_map.py
+++ /dev/null
@@ -1,257 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-__author__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-import bpy.utils
-
-from ..op import (
-    texture_lock,
-    copy_paste_uv,
-    preserve_uv_aspect,
-    texture_projection,
-    texture_wrap,
-    transfer_uv,
-    uvw,
-    world_scale_uv
-)
-from ..op.world_scale_uv import MUV_OT_WorldScaleUV_ApplyProportionalToMesh
-from ...utils.bl_class_registry import BlClassRegistry
-
-__all__ = [
-    'MUV_MT_CopyPasteUV',
-    'MUV_MT_TransferUV',
-    'MUV_MT_TextureLock',
-    'MUV_MT_WorldScaleUV',
-    'MUV_MT_TextureWrap',
-    'MUV_MT_UVW',
-    'MUV_MT_TextureProjection',
-    'MUV_MT_PreserveUVAspect',
-]
-
-
-@BlClassRegistry(legacy=True)
-class MUV_MT_CopyPasteUV(bpy.types.Menu):
-    """
-    Menu class: Master menu of Copy/Paste UV coordinate
-    """
-
-    bl_idname = "uv.muv_copy_paste_uv_menu"
-    bl_label = "Copy/Paste UV"
-    bl_description = "Copy and Paste UV coordinate"
-
-    def draw(self, _):
-        layout = self.layout
-
-        layout.label(text="Default")
-        layout.menu(copy_paste_uv.MUV_MT_CopyPasteUV_CopyUV.bl_idname,
-                    text="Copy")
-        layout.menu(copy_paste_uv.MUV_MT_CopyPasteUV_PasteUV.bl_idname,
-                    text="Paste")
-
-        layout.separator()
-
-        layout.label(text="Selection Sequence")
-        layout.menu(copy_paste_uv.MUV_MT_CopyPasteUV_SelSeqCopyUV.bl_idname,
-                    text="Copy")
-        layout.menu(copy_paste_uv.MUV_MT_CopyPasteUV_SelSeqPasteUV.bl_idname,
-                    text="Paste")
-
-
-@BlClassRegistry(legacy=True)
-class MUV_MT_TransferUV(bpy.types.Menu):
-    """
-    Menu class: Master menu of Transfer UV coordinate
-    """
-
-    bl_idname = "uv.muv_transfer_uv_menu"
-    bl_label = "Transfer UV"
-    bl_description = "Transfer UV coordinate"
-
-    def draw(self, context):
-        layout = self.layout
-        sc = context.scene
-
-        layout.operator(transfer_uv.MUV_OT_TransferUV_CopyUV.bl_idname,
-                        text="Copy")
-        ops = layout.operator(transfer_uv.MUV_OT_TransferUV_PasteUV.bl_idname,
-                              text="Paste")
-        ops.invert_normals = sc.muv_transfer_uv_invert_normals
-        ops.copy_seams = sc.muv_transfer_uv_copy_seams
-
-
-@BlClassRegistry(legacy=True)
-class MUV_MT_TextureLock(bpy.types.Menu):
-    """
-    Menu class: Master menu of Texture Lock
-    """
-
-    bl_idname = "uv.muv_texture_lock_menu"
-    bl_label = "Texture Lock"
-    bl_description = "Lock texture when vertices of mesh (Preserve UV)"
-
-    def draw(self, context):
-        layout = self.layout
-        sc = context.scene
-
-        layout.label("Normal Mode")
-        layout.operator(
-            texture_lock.MUV_OT_TextureLock_Lock.bl_idname,
-            text="Lock"
-            if not texture_lock.MUV_OT_TextureLock_Lock.is_ready(context)
-            else "ReLock")
-        ops = layout.operator(texture_lock.MUV_OT_TextureLock_Unlock.bl_idname,
-                              text="Unlock")
-        ops.connect = sc.muv_texture_lock_connect
-
-        layout.separator()
-
-        layout.label("Interactive Mode")
-        layout.prop(sc, "muv_texture_lock_lock", text="Lock")
-
-
-@BlClassRegistry(legacy=True)
-class MUV_MT_WorldScaleUV(bpy.types.Menu):
-    """
-    Menu class: Master menu of world scale UV
-    """
-
-    bl_idname = "uv.muv_world_scale_uv_menu"
-    bl_label = "World Scale UV"
-    bl_description = ""
-
-    def draw(self, context):
-        layout = self.layout
-        sc = context.scene
-
-        layout.operator(world_scale_uv.MUV_OT_WorldScaleUV_Measure.bl_idname,
-                        text="Measure")
-
-        layout.operator(
-            world_scale_uv.MUV_OT_WorldScaleUV_ApplyManual.bl_idname,
-            text="Apply (Manual)")
-
-        ops = layout.operator(
-            world_scale_uv.MUV_OT_WorldScaleUV_ApplyScalingDensity.bl_idname,
-            text="Apply (Same Desity)")
-        ops.src_density = sc.muv_world_scale_uv_src_density
-        ops.same_density = True
-
-        ops = layout.operator(
-            world_scale_uv.MUV_OT_WorldScaleUV_ApplyScalingDensity.bl_idname,
-            text="Apply (Scaling Desity)")
-        ops.src_density = sc.muv_world_scale_uv_src_density
-        ops.same_density = False
-        ops.tgt_scaling_factor = sc.muv_world_scale_uv_tgt_scaling_factor
-
-        ops = layout.operator(
-            MUV_OT_WorldScaleUV_ApplyProportionalToMesh.bl_idname,
-            text="Apply (Proportional to Mesh)")
-        ops.src_density = sc.muv_world_scale_uv_src_density
-        ops.src_uv_area = sc.muv_world_scale_uv_src_uv_area
-        ops.src_mesh_area = sc.muv_world_scale_uv_src_mesh_area
-        ops.origin = sc.muv_world_scale_uv_origin
-
-
-@BlClassRegistry(legacy=True)
-class MUV_MT_TextureWrap(bpy.types.Menu):
-    """
-    Menu class: Master menu of Texture Wrap
-    """
-
-    bl_idname = "uv.muv_texture_wrap_menu"
-    bl_label = "Texture Wrap"
-    bl_description = ""
-
-    def draw(self, _):
-        layout = self.layout
-
-        layout.operator(texture_wrap.MUV_OT_TextureWrap_Refer.bl_idname,
-                        text="Refer")
-        layout.operator(texture_wrap.MUV_OT_TextureWrap_Set.bl_idname,
-                        text="Set")
-
-
-@BlClassRegistry(legacy=True)
-class MUV_MT_UVW(bpy.types.Menu):
-    """
-    Menu class: Master menu of UVW
-    """
-
-    bl_idname = "uv.muv_uvw_menu"
-    bl_label = "UVW"
-    bl_description = ""
-
-    def draw(self, context):
-        layout = self.layout
-        sc = context.scene
-
-        ops = layout.operator(uvw.MUV_OT_UVW_BoxMap.bl_idname, text="Box")
-        ops.assign_uvmap = sc.muv_uvw_assign_uvmap
-
-        ops = layout.operator(uvw.MUV_OT_UVW_BestPlanerMap.bl_idname,
-                              text="Best Planner")
-        ops.assign_uvmap = sc.muv_uvw_assign_uvmap
-
-
-@BlClassRegistry(legacy=True)
-class MUV_MT_TextureProjection(bpy.types.Menu):
-    """
-    Menu class: Master menu of Texture Projection
-    """
-
-    bl_idname = "uv.muv_texture_projection_menu"
-    bl_label = "Texture Projection"
-    bl_description = ""
-
-    def draw(self, context):
-        layout = self.layout
-        sc = context.scene
-
-        layout.prop(sc, "muv_texture_projection_enable",
-                    text="Texture Projection")
-        layout.operator(
-            texture_projection.MUV_OT_TextureProjection_Project.bl_idname,
-            text="Project")
-
-
-@BlClassRegistry(legacy=True)
-class MUV_MT_PreserveUVAspect(bpy.types.Menu):
-    """
-    Menu class: Master menu of Preserve UV Aspect
-    """
-
-    bl_idname = "uv.muv_preserve_uv_aspect_menu"
-    bl_label = "Preserve UV Aspect"
-    bl_description = ""
-
-    def draw(self, context):
-        layout = self.layout
-        sc = context.scene
-
-        for key in bpy.data.images.keys():
-            ops = layout.operator(
-                preserve_uv_aspect.MUV_OT_PreserveUVAspect.bl_idname, text=key)
-            ops.dest_img_name = key
-            ops.origin = sc.muv_preserve_uv_aspect_origin
diff --git a/uv_magic_uv/legacy/ui/__init__.py b/uv_magic_uv/legacy/ui/__init__.py
deleted file mode 100644
index bf790a8e4203c5d0e6593d695283e020c3368d49..0000000000000000000000000000000000000000
--- a/uv_magic_uv/legacy/ui/__init__.py
+++ /dev/null
@@ -1,50 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-__author__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-if "bpy" in locals():
-    import importlib
-    importlib.reload(view3d_copy_paste_uv_objectmode)
-    importlib.reload(view3d_copy_paste_uv_editmode)
-    importlib.reload(view3d_uv_manipulation)
-    importlib.reload(view3d_uv_mapping)
-    importlib.reload(uvedit_copy_paste_uv)
-    importlib.reload(uvedit_uv_manipulation)
-    importlib.reload(uvedit_editor_enhancement)
-    importlib.reload(VIEW3D_MT_uv_map)
-    importlib.reload(VIEW3D_MT_object)
-    importlib.reload(IMAGE_MT_uvs)
-else:
-    from . import view3d_copy_paste_uv_objectmode
-    from . import view3d_copy_paste_uv_editmode
-    from . import view3d_uv_manipulation
-    from . import view3d_uv_mapping
-    from . import uvedit_copy_paste_uv
-    from . import uvedit_uv_manipulation
-    from . import uvedit_editor_enhancement
-    from . import VIEW3D_MT_uv_map
-    from . import VIEW3D_MT_object
-    from . import IMAGE_MT_uvs
-
-import bpy
\ No newline at end of file
diff --git a/uv_magic_uv/legacy/ui/uvedit_copy_paste_uv.py b/uv_magic_uv/legacy/ui/uvedit_copy_paste_uv.py
deleted file mode 100644
index 9848f03b78951ca083828a90d32912459a8ecaeb..0000000000000000000000000000000000000000
--- a/uv_magic_uv/legacy/ui/uvedit_copy_paste_uv.py
+++ /dev/null
@@ -1,62 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-__author__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-
-from ..op import copy_paste_uv_uvedit
-from ...utils.bl_class_registry import BlClassRegistry
-
-__all__ = [
-    'MUV_PT_UVEdit_CopyPasteUV',
-]
-
-
-@BlClassRegistry(legacy=True)
-class MUV_PT_UVEdit_CopyPasteUV(bpy.types.Panel):
-    """
-    Panel class: Copy/Paste UV on Property Panel on UV/ImageEditor
-    """
-
-    bl_space_type = 'IMAGE_EDITOR'
-    bl_region_type = 'TOOLS'
-    bl_label = "Copy/Paste UV"
-    bl_category = "Magic UV"
-    bl_context = 'mesh_edit'
-    bl_options = {'DEFAULT_CLOSED'}
-
-    def draw_header(self, _):
-        layout = self.layout
-        layout.label(text="", icon='IMAGE_COL')
-
-    def draw(self, _):
-        layout = self.layout
-
-        row = layout.row(align=True)
-        row.operator(
-            copy_paste_uv_uvedit.MUV_OT_CopyPasteUVUVEdit_CopyUV.bl_idname,
-            text="Copy")
-        row.operator(
-            copy_paste_uv_uvedit.MUV_OT_CopyPasteUVUVEdit_PasteUV.bl_idname,
-            text="Paste")
diff --git a/uv_magic_uv/legacy/ui/uvedit_editor_enhancement.py b/uv_magic_uv/legacy/ui/uvedit_editor_enhancement.py
deleted file mode 100644
index 3f750febfbefbc51fd5f062b8916ad4572ea0b72..0000000000000000000000000000000000000000
--- a/uv_magic_uv/legacy/ui/uvedit_editor_enhancement.py
+++ /dev/null
@@ -1,149 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-__author__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-
-from ..op import (
-    align_uv_cursor,
-    uv_bounding_box,
-    uv_inspection,
-)
-from ...utils.bl_class_registry import BlClassRegistry
-
-__all__ = [
-    'MUV_PT_UVEdit_EditorEnhancement',
-]
-
-
-@BlClassRegistry(legacy=True)
-class MUV_PT_UVEdit_EditorEnhancement(bpy.types.Panel):
-    """
-    Panel class: UV/Image Editor Enhancement
-    """
-
-    bl_space_type = 'IMAGE_EDITOR'
-    bl_region_type = 'TOOLS'
-    bl_label = "Editor Enhancement"
-    bl_category = "Magic UV"
-    bl_context = 'mesh_edit'
-    bl_options = {'DEFAULT_CLOSED'}
-
-    def draw_header(self, _):
-        layout = self.layout
-        layout.label(text="", icon='IMAGE_COL')
-
-    def draw(self, context):
-        layout = self.layout
-        sc = context.scene
-
-        box = layout.box()
-        box.prop(sc, "muv_align_uv_cursor_enabled", text="Align UV Cursor")
-        if sc.muv_align_uv_cursor_enabled:
-            box.prop(sc, "muv_align_uv_cursor_align_method", expand=True)
-
-            col = box.column(align=True)
-
-            row = col.row(align=True)
-            ops = row.operator(align_uv_cursor.MUV_OT_AlignUVCursor.bl_idname,
-                               text="Left Top")
-            ops.position = 'LEFT_TOP'
-            ops.base = sc.muv_align_uv_cursor_align_method
-            ops = row.operator(align_uv_cursor.MUV_OT_AlignUVCursor.bl_idname,
-                               text="Middle Top")
-            ops.position = 'MIDDLE_TOP'
-            ops.base = sc.muv_align_uv_cursor_align_method
-            ops = row.operator(align_uv_cursor.MUV_OT_AlignUVCursor.bl_idname,
-                               text="Right Top")
-            ops.position = 'RIGHT_TOP'
-            ops.base = sc.muv_align_uv_cursor_align_method
-
-            row = col.row(align=True)
-            ops = row.operator(align_uv_cursor.MUV_OT_AlignUVCursor.bl_idname,
-                               text="Left Middle")
-            ops.position = 'LEFT_MIDDLE'
-            ops.base = sc.muv_align_uv_cursor_align_method
-            ops = row.operator(align_uv_cursor.MUV_OT_AlignUVCursor.bl_idname,
-                               text="Center")
-            ops.position = 'CENTER'
-            ops.base = sc.muv_align_uv_cursor_align_method
-            ops = row.operator(align_uv_cursor.MUV_OT_AlignUVCursor.bl_idname,
-                               text="Right Middle")
-            ops.position = 'RIGHT_MIDDLE'
-            ops.base = sc.muv_align_uv_cursor_align_method
-
-            row = col.row(align=True)
-            ops = row.operator(align_uv_cursor.MUV_OT_AlignUVCursor.bl_idname,
-                               text="Left Bottom")
-            ops.position = 'LEFT_BOTTOM'
-            ops.base = sc.muv_align_uv_cursor_align_method
-            ops = row.operator(align_uv_cursor.MUV_OT_AlignUVCursor.bl_idname,
-                               text="Middle Bottom")
-            ops.position = 'MIDDLE_BOTTOM'
-            ops.base = sc.muv_align_uv_cursor_align_method
-            ops = row.operator(align_uv_cursor.MUV_OT_AlignUVCursor.bl_idname,
-                               text="Right Bottom")
-            ops.position = 'RIGHT_BOTTOM'
-            ops.base = sc.muv_align_uv_cursor_align_method
-
-        box = layout.box()
-        box.prop(sc, "muv_uv_cursor_location_enabled",
-                 text="UV Cursor Location")
-        if sc.muv_uv_cursor_location_enabled:
-            box.prop(sc, "muv_align_uv_cursor_cursor_loc", text="")
-
-        box = layout.box()
-        box.prop(sc, "muv_uv_bounding_box_enabled", text="UV Bounding Box")
-        if sc.muv_uv_bounding_box_enabled:
-            box.prop(
-                sc, "muv_uv_bounding_box_show",
-                text="Hide"
-                if uv_bounding_box.MUV_OT_UVBoundingBox.is_running(context)
-                else "Show",
-                icon='RESTRICT_VIEW_OFF'
-                if uv_bounding_box.MUV_OT_UVBoundingBox.is_running(context)
-                else 'RESTRICT_VIEW_ON')
-            box.prop(sc, "muv_uv_bounding_box_uniform_scaling",
-                     text="Uniform Scaling")
-            box.prop(sc, "muv_uv_bounding_box_boundary", text="Boundary")
-
-        box = layout.box()
-        box.prop(sc, "muv_uv_inspection_enabled", text="UV Inspection")
-        if sc.muv_uv_inspection_enabled:
-            row = box.row()
-            row.prop(
-                sc, "muv_uv_inspection_show",
-                text="Hide"
-                if uv_inspection.MUV_OT_UVInspection_Render.is_running(context)
-                else "Show",
-                icon='RESTRICT_VIEW_OFF'
-                if uv_inspection.MUV_OT_UVInspection_Render.is_running(context)
-                else 'RESTRICT_VIEW_ON')
-            row.operator(uv_inspection.MUV_OT_UVInspection_Update.bl_idname,
-                         text="Update")
-            row = box.row()
-            row.prop(sc, "muv_uv_inspection_show_overlapped")
-            row.prop(sc, "muv_uv_inspection_show_flipped")
-            row = box.row()
-            row.prop(sc, "muv_uv_inspection_show_mode")
diff --git a/uv_magic_uv/legacy/ui/uvedit_uv_manipulation.py b/uv_magic_uv/legacy/ui/uvedit_uv_manipulation.py
deleted file mode 100644
index 96cf17d324c17eeba2b45cf478559702a237ff90..0000000000000000000000000000000000000000
--- a/uv_magic_uv/legacy/ui/uvedit_uv_manipulation.py
+++ /dev/null
@@ -1,130 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-__author__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-
-from ..op import (
-    align_uv,
-    smooth_uv,
-    pack_uv,
-    select_uv,
-)
-from ...utils.bl_class_registry import BlClassRegistry
-
-__all__ = [
-    'MUV_PT_UVEdit_UVManipulation',
-]
-
-
-@BlClassRegistry(legacy=True)
-class MUV_PT_UVEdit_UVManipulation(bpy.types.Panel):
-    """
-    Panel class: UV Manipulation on Property Panel on UV/ImageEditor
-    """
-
-    bl_space_type = 'IMAGE_EDITOR'
-    bl_region_type = 'TOOLS'
-    bl_label = "UV Manipulation"
-    bl_category = "Magic UV"
-    bl_context = 'mesh_edit'
-    bl_options = {'DEFAULT_CLOSED'}
-
-    def draw_header(self, _):
-        layout = self.layout
-        layout.label(text="", icon='IMAGE_COL')
-
-    def draw(self, context):
-        sc = context.scene
-        layout = self.layout
-
-        box = layout.box()
-        box.prop(sc, "muv_align_uv_enabled", text="Align UV")
-        if sc.muv_align_uv_enabled:
-            col = box.column()
-            row = col.row(align=True)
-            ops = row.operator(align_uv.MUV_OT_AlignUV_Circle.bl_idname,
-                               text="Circle")
-            ops.transmission = sc.muv_align_uv_transmission
-            ops.select = sc.muv_align_uv_select
-            ops = row.operator(align_uv.MUV_OT_AlignUV_Straighten.bl_idname,
-                               text="Straighten")
-            ops.transmission = sc.muv_align_uv_transmission
-            ops.select = sc.muv_align_uv_select
-            ops.vertical = sc.muv_align_uv_vertical
-            ops.horizontal = sc.muv_align_uv_horizontal
-            ops.mesh_infl = sc.muv_align_uv_mesh_infl
-            row = col.row()
-            ops = row.operator(align_uv.MUV_OT_AlignUV_Axis.bl_idname,
-                               text="XY-axis")
-            ops.transmission = sc.muv_align_uv_transmission
-            ops.select = sc.muv_align_uv_select
-            ops.vertical = sc.muv_align_uv_vertical
-            ops.horizontal = sc.muv_align_uv_horizontal
-            ops.location = sc.muv_align_uv_location
-            ops.mesh_infl = sc.muv_align_uv_mesh_infl
-            row.prop(sc, "muv_align_uv_location", text="")
-
-            col = box.column(align=True)
-            row = col.row(align=True)
-            row.prop(sc, "muv_align_uv_transmission", text="Transmission")
-            row.prop(sc, "muv_align_uv_select", text="Select")
-            row = col.row(align=True)
-            row.prop(sc, "muv_align_uv_vertical", text="Vertical")
-            row.prop(sc, "muv_align_uv_horizontal", text="Horizontal")
-            col.prop(sc, "muv_align_uv_mesh_infl", text="Mesh Influence")
-
-        box = layout.box()
-        box.prop(sc, "muv_smooth_uv_enabled", text="Smooth UV")
-        if sc.muv_smooth_uv_enabled:
-            ops = box.operator(smooth_uv.MUV_OT_SmoothUV.bl_idname,
-                               text="Smooth")
-            ops.transmission = sc.muv_smooth_uv_transmission
-            ops.select = sc.muv_smooth_uv_select
-            ops.mesh_infl = sc.muv_smooth_uv_mesh_infl
-            col = box.column(align=True)
-            row = col.row(align=True)
-            row.prop(sc, "muv_smooth_uv_transmission", text="Transmission")
-            row.prop(sc, "muv_smooth_uv_select", text="Select")
-            col.prop(sc, "muv_smooth_uv_mesh_infl", text="Mesh Influence")
-
-        box = layout.box()
-        box.prop(sc, "muv_select_uv_enabled", text="Select UV")
-        if sc.muv_select_uv_enabled:
-            row = box.row(align=True)
-            row.operator(select_uv.MUV_OT_SelectUV_SelectOverlapped.bl_idname)
-            row.operator(select_uv.MUV_OT_SelectUV_SelectFlipped.bl_idname)
-
-        box = layout.box()
-        box.prop(sc, "muv_pack_uv_enabled", text="Pack UV (Extension)")
-        if sc.muv_pack_uv_enabled:
-            ops = box.operator(pack_uv.MUV_OT_PackUV.bl_idname, text="Pack UV")
-            ops.allowable_center_deviation = \
-                sc.muv_pack_uv_allowable_center_deviation
-            ops.allowable_size_deviation = \
-                sc.muv_pack_uv_allowable_size_deviation
-            box.label("Allowable Center Deviation:")
-            box.prop(sc, "muv_pack_uv_allowable_center_deviation", text="")
-            box.label("Allowable Size Deviation:")
-            box.prop(sc, "muv_pack_uv_allowable_size_deviation", text="")
diff --git a/uv_magic_uv/legacy/ui/view3d_copy_paste_uv_editmode.py b/uv_magic_uv/legacy/ui/view3d_copy_paste_uv_editmode.py
deleted file mode 100644
index ee2713b22d19cfd193dd1ddd430e679c41aa0c1a..0000000000000000000000000000000000000000
--- a/uv_magic_uv/legacy/ui/view3d_copy_paste_uv_editmode.py
+++ /dev/null
@@ -1,93 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-__author__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-
-from ..op import (
-    transfer_uv,
-    copy_paste_uv,
-)
-from ...utils.bl_class_registry import BlClassRegistry
-
-__all__ = [
-    'MUV_PT_View3D_Edit_CopyPasteUV',
-]
-
-
-@BlClassRegistry(legacy=True)
-class MUV_PT_View3D_Edit_CopyPasteUV(bpy.types.Panel):
-    """
-    Panel class: Copy/Paste UV on Property Panel on View3D
-    """
-
-    bl_space_type = 'VIEW_3D'
-    bl_region_type = 'TOOLS'
-    bl_label = "Copy/Paste UV"
-    bl_category = "Magic UV"
-    bl_context = 'mesh_edit'
-    bl_options = {'DEFAULT_CLOSED'}
-
-    def draw_header(self, _):
-        layout = self.layout
-        layout.label(text="", icon='IMAGE_COL')
-
-    def draw(self, context):
-        sc = context.scene
-        layout = self.layout
-
-        box = layout.box()
-        box.prop(sc, "muv_copy_paste_uv_enabled", text="Copy/Paste UV")
-        if sc.muv_copy_paste_uv_enabled:
-            row = box.row(align=True)
-            if sc.muv_copy_paste_uv_mode == 'DEFAULT':
-                row.menu(copy_paste_uv.MUV_MT_CopyPasteUV_CopyUV.bl_idname,
-                         text="Copy")
-                row.menu(copy_paste_uv.MUV_MT_CopyPasteUV_PasteUV.bl_idname,
-                         text="Paste")
-            elif sc.muv_copy_paste_uv_mode == 'SEL_SEQ':
-                row.menu(
-                    copy_paste_uv.MUV_MT_CopyPasteUV_SelSeqCopyUV.bl_idname,
-                    text="Copy")
-                row.menu(
-                    copy_paste_uv.MUV_MT_CopyPasteUV_SelSeqPasteUV.bl_idname,
-                    text="Paste")
-            box.prop(sc, "muv_copy_paste_uv_mode", expand=True)
-            box.prop(sc, "muv_copy_paste_uv_copy_seams", text="Seams")
-            box.prop(sc, "muv_copy_paste_uv_strategy", text="Strategy")
-
-        box = layout.box()
-        box.prop(sc, "muv_transfer_uv_enabled", text="Transfer UV")
-        if sc.muv_transfer_uv_enabled:
-            row = box.row(align=True)
-            row.operator(transfer_uv.MUV_OT_TransferUV_CopyUV.bl_idname,
-                         text="Copy")
-            ops = row.operator(transfer_uv.MUV_OT_TransferUV_PasteUV.bl_idname,
-                               text="Paste")
-            ops.invert_normals = sc.muv_transfer_uv_invert_normals
-            ops.copy_seams = sc.muv_transfer_uv_copy_seams
-            row = box.row()
-            row.prop(sc, "muv_transfer_uv_invert_normals",
-                     text="Invert Normals")
-            row.prop(sc, "muv_transfer_uv_copy_seams", text="Seams")
diff --git a/uv_magic_uv/legacy/ui/view3d_copy_paste_uv_objectmode.py b/uv_magic_uv/legacy/ui/view3d_copy_paste_uv_objectmode.py
deleted file mode 100644
index 58031b0f3158a2f78689741713bd55ac3d899bb7..0000000000000000000000000000000000000000
--- a/uv_magic_uv/legacy/ui/view3d_copy_paste_uv_objectmode.py
+++ /dev/null
@@ -1,65 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-__author__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-
-from ..op import copy_paste_uv_object
-from ...utils.bl_class_registry import BlClassRegistry
-
-__all__ = [
-    'MUV_PT_View3D_Object_CopyPasteUV',
-]
-
-
-@BlClassRegistry(legacy=True)
-class MUV_PT_View3D_Object_CopyPasteUV(bpy.types.Panel):
-    """
-    Panel class: Copy/Paste UV on Property Panel on View3D
-    """
-
-    bl_space_type = 'VIEW_3D'
-    bl_region_type = 'TOOLS'
-    bl_label = "Copy/Paste UV"
-    bl_category = "Magic UV"
-    bl_context = 'objectmode'
-    bl_options = {'DEFAULT_CLOSED'}
-
-    def draw_header(self, _):
-        layout = self.layout
-        layout.label(text="", icon='IMAGE_COL')
-
-    def draw(self, context):
-        sc = context.scene
-        layout = self.layout
-
-        row = layout.row(align=True)
-        row.menu(
-            copy_paste_uv_object.MUV_MT_CopyPasteUVObject_CopyUV.bl_idname,
-            text="Copy")
-        row.menu(
-            copy_paste_uv_object.MUV_MT_CopyPasteUVObject_PasteUV.bl_idname,
-            text="Paste")
-        layout.prop(sc, "muv_copy_paste_uv_object_copy_seams",
-                    text="Seams")
diff --git a/uv_magic_uv/legacy/ui/view3d_uv_manipulation.py b/uv_magic_uv/legacy/ui/view3d_uv_manipulation.py
deleted file mode 100644
index 7d828a38fb1bf5aef2356f0a955badb4b915c17e..0000000000000000000000000000000000000000
--- a/uv_magic_uv/legacy/ui/view3d_uv_manipulation.py
+++ /dev/null
@@ -1,289 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-__author__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-
-from ..op import (
-    move_uv,
-    flip_rotate_uv,
-    mirror_uv,
-    preserve_uv_aspect,
-    texture_lock,
-    texture_wrap,
-    uv_sculpt,
-    world_scale_uv,
-)
-from ..op.world_scale_uv import (
-    MUV_OT_WorldScaleUV_ApplyProportionalToMesh,
-    MUV_OT_WorldScaleUV_ApplyScalingDensity
-)
-from ...utils.bl_class_registry import BlClassRegistry
-
-__all__ = [
-    'MUV_PT_View3D_UVManipulation',
-]
-
-
-@BlClassRegistry(legacy=True)
-class MUV_PT_View3D_UVManipulation(bpy.types.Panel):
-    """
-    Panel class: UV Manipulation on Property Panel on View3D
-    """
-
-    bl_space_type = 'VIEW_3D'
-    bl_region_type = 'TOOLS'
-    bl_label = "UV Manipulation"
-    bl_category = "Magic UV"
-    bl_context = 'mesh_edit'
-    bl_options = {'DEFAULT_CLOSED'}
-
-    def draw_header(self, _):
-        layout = self.layout
-        layout.label(text="", icon='IMAGE_COL')
-
-    def draw(self, context):
-        sc = context.scene
-        layout = self.layout
-
-        box = layout.box()
-        box.prop(sc, "muv_flip_rotate_uv_enabled", text="Flip/Rotate UV")
-        if sc.muv_flip_rotate_uv_enabled:
-            row = box.row()
-            ops = row.operator(flip_rotate_uv.MUV_OT_FlipRotate.bl_idname,
-                               text="Flip/Rotate")
-            ops.seams = sc.muv_flip_rotate_uv_seams
-            row.prop(sc, "muv_flip_rotate_uv_seams", text="Seams")
-
-        box = layout.box()
-        box.prop(sc, "muv_mirror_uv_enabled", text="Mirror UV")
-        if sc.muv_mirror_uv_enabled:
-            row = box.row()
-            ops = row.operator(mirror_uv.MUV_OT_MirrorUV.bl_idname,
-                               text="Mirror")
-            ops.axis = sc.muv_mirror_uv_axis
-            row.prop(sc, "muv_mirror_uv_axis", text="")
-
-        box = layout.box()
-        box.prop(sc, "muv_move_uv_enabled", text="Move UV")
-        if sc.muv_move_uv_enabled:
-            col = box.column()
-            if not move_uv.MUV_OT_MoveUV.is_running(context):
-                col.operator(move_uv.MUV_OT_MoveUV.bl_idname, icon='PLAY',
-                             text="Start")
-            else:
-                col.operator(move_uv.MUV_OT_MoveUV.bl_idname, icon='PAUSE',
-                             text="Stop")
-
-        box = layout.box()
-        box.prop(sc, "muv_world_scale_uv_enabled", text="World Scale UV")
-        if sc.muv_world_scale_uv_enabled:
-            box.prop(sc, "muv_world_scale_uv_mode", text="")
-
-            if sc.muv_world_scale_uv_mode == 'MANUAL':
-                sp = box.split(percentage=0.5)
-                col = sp.column()
-                col.prop(sc, "muv_world_scale_uv_tgt_texture_size",
-                         text="Texture Size")
-                sp = sp.split(percentage=1.0)
-                col = sp.column()
-                col.label("Density:")
-                col.prop(sc, "muv_world_scale_uv_tgt_density", text="")
-                box.prop(sc, "muv_world_scale_uv_origin", text="Origin")
-                ops = box.operator(
-                    world_scale_uv.MUV_OT_WorldScaleUV_ApplyManual.bl_idname,
-                    text="Apply")
-                ops.tgt_density = sc.muv_world_scale_uv_tgt_density
-                ops.tgt_texture_size = sc.muv_world_scale_uv_tgt_texture_size
-                ops.origin = sc.muv_world_scale_uv_origin
-                ops.show_dialog = False
-
-            elif sc.muv_world_scale_uv_mode == 'SAME_DENSITY':
-                sp = box.split(percentage=0.4)
-                col = sp.column(align=True)
-                col.label("Source:")
-                sp = sp.split(percentage=1.0)
-                col = sp.column(align=True)
-                col.operator(
-                    world_scale_uv.MUV_OT_WorldScaleUV_Measure.bl_idname,
-                    text="Measure")
-
-                sp = box.split(percentage=0.7)
-                col = sp.column(align=True)
-                col.prop(sc, "muv_world_scale_uv_src_density", text="Density")
-                col.enabled = False
-                sp = sp.split(percentage=1.0)
-                col = sp.column(align=True)
-                col.label("px2/cm2")
-
-                box.separator()
-                box.prop(sc, "muv_world_scale_uv_origin", text="Origin")
-                ops = box.operator(
-                    MUV_OT_WorldScaleUV_ApplyScalingDensity.bl_idname,
-                    text="Apply")
-                ops.src_density = sc.muv_world_scale_uv_src_density
-                ops.origin = sc.muv_world_scale_uv_origin
-                ops.same_density = True
-                ops.show_dialog = False
-
-            elif sc.muv_world_scale_uv_mode == 'SCALING_DENSITY':
-                sp = box.split(percentage=0.4)
-                col = sp.column(align=True)
-                col.label("Source:")
-                sp = sp.split(percentage=1.0)
-                col = sp.column(align=True)
-                col.operator(
-                    world_scale_uv.MUV_OT_WorldScaleUV_Measure.bl_idname,
-                    text="Measure")
-
-                sp = box.split(percentage=0.7)
-                col = sp.column(align=True)
-                col.prop(sc, "muv_world_scale_uv_src_density", text="Density")
-                col.enabled = False
-                sp = sp.split(percentage=1.0)
-                col = sp.column(align=True)
-                col.label("px2/cm2")
-
-                box.separator()
-                box.prop(sc, "muv_world_scale_uv_tgt_scaling_factor",
-                         text="Scaling Factor")
-                box.prop(sc, "muv_world_scale_uv_origin", text="Origin")
-                ops = box.operator(
-                    MUV_OT_WorldScaleUV_ApplyScalingDensity.bl_idname,
-                    text="Apply")
-                ops.src_density = sc.muv_world_scale_uv_src_density
-                ops.origin = sc.muv_world_scale_uv_origin
-                ops.same_density = False
-                ops.show_dialog = False
-                ops.tgt_scaling_factor = \
-                    sc.muv_world_scale_uv_tgt_scaling_factor
-
-            elif sc.muv_world_scale_uv_mode == 'PROPORTIONAL_TO_MESH':
-                sp = box.split(percentage=0.4)
-                col = sp.column(align=True)
-                col.label("Source:")
-                sp = sp.split(percentage=1.0)
-                col = sp.column(align=True)
-                col.operator(
-                    world_scale_uv.MUV_OT_WorldScaleUV_Measure.bl_idname,
-                    text="Measure")
-
-                sp = box.split(percentage=0.7)
-                col = sp.column(align=True)
-                col.prop(sc, "muv_world_scale_uv_src_mesh_area",
-                         text="Mesh Area")
-                col.prop(sc, "muv_world_scale_uv_src_uv_area", text="UV Area")
-                col.prop(sc, "muv_world_scale_uv_src_density", text="Density")
-                col.enabled = False
-                sp = sp.split(percentage=1.0)
-                col = sp.column(align=True)
-                col.label("cm2")
-                col.label("px2")
-                col.label("px2/cm2")
-                col.enabled = False
-
-                box.separator()
-                box.prop(sc, "muv_world_scale_uv_origin", text="Origin")
-                ops = box.operator(
-                    MUV_OT_WorldScaleUV_ApplyProportionalToMesh.bl_idname,
-                    text="Apply")
-                ops.src_density = sc.muv_world_scale_uv_src_density
-                ops.src_uv_area = sc.muv_world_scale_uv_src_uv_area
-                ops.src_mesh_area = sc.muv_world_scale_uv_src_mesh_area
-                ops.origin = sc.muv_world_scale_uv_origin
-                ops.show_dialog = False
-
-        box = layout.box()
-        box.prop(sc, "muv_preserve_uv_aspect_enabled",
-                 text="Preserve UV Aspect")
-        if sc.muv_preserve_uv_aspect_enabled:
-            row = box.row()
-            ops = row.operator(
-                preserve_uv_aspect.MUV_OT_PreserveUVAspect.bl_idname,
-                text="Change Image")
-            ops.dest_img_name = sc.muv_preserve_uv_aspect_tex_image
-            ops.origin = sc.muv_preserve_uv_aspect_origin
-            row.prop(sc, "muv_preserve_uv_aspect_tex_image", text="")
-            box.prop(sc, "muv_preserve_uv_aspect_origin", text="Origin")
-
-        box = layout.box()
-        box.prop(sc, "muv_texture_lock_enabled", text="Texture Lock")
-        if sc.muv_texture_lock_enabled:
-            row = box.row(align=True)
-            col = row.column(align=True)
-            col.label("Normal Mode:")
-            col = row.column(align=True)
-            col.operator(
-                texture_lock.MUV_OT_TextureLock_Lock.bl_idname,
-                text="Lock"
-                if not texture_lock.MUV_OT_TextureLock_Lock.is_ready(context)
-                else "ReLock")
-            ops = col.operator(
-                texture_lock.MUV_OT_TextureLock_Unlock.bl_idname,
-                text="Unlock")
-            ops.connect = sc.muv_texture_lock_connect
-            col.prop(sc, "muv_texture_lock_connect", text="Connect")
-
-            row = box.row(align=True)
-            row.label("Interactive Mode:")
-            box.prop(
-                sc, "muv_texture_lock_lock",
-                text="Unlock"
-                if texture_lock.MUV_OT_TextureLock_Intr.is_running(context)
-                else "Lock",
-                icon='RESTRICT_VIEW_OFF'
-                if texture_lock.MUV_OT_TextureLock_Intr.is_running(context)
-                else 'RESTRICT_VIEW_ON')
-
-        box = layout.box()
-        box.prop(sc, "muv_texture_wrap_enabled", text="Texture Wrap")
-        if sc.muv_texture_wrap_enabled:
-            row = box.row(align=True)
-            row.operator(texture_wrap.MUV_OT_TextureWrap_Refer.bl_idname,
-                         text="Refer")
-            row.operator(texture_wrap.MUV_OT_TextureWrap_Set.bl_idname,
-                         text="Set")
-            box.prop(sc, "muv_texture_wrap_set_and_refer")
-            box.prop(sc, "muv_texture_wrap_selseq")
-
-        box = layout.box()
-        box.prop(sc, "muv_uv_sculpt_enabled", text="UV Sculpt")
-        if sc.muv_uv_sculpt_enabled:
-            box.prop(
-                sc, "muv_uv_sculpt_enable",
-                text="Disable"if uv_sculpt.MUV_OT_UVSculpt.is_running(context)
-                else "Enable",
-                icon='RESTRICT_VIEW_OFF'
-                if uv_sculpt.MUV_OT_UVSculpt.is_running(context)
-                else 'RESTRICT_VIEW_ON')
-            col = box.column()
-            col.label("Brush:")
-            col.prop(sc, "muv_uv_sculpt_radius")
-            col.prop(sc, "muv_uv_sculpt_strength")
-            box.prop(sc, "muv_uv_sculpt_tools")
-            if sc.muv_uv_sculpt_tools == 'PINCH':
-                box.prop(sc, "muv_uv_sculpt_pinch_invert")
-            elif sc.muv_uv_sculpt_tools == 'RELAX':
-                box.prop(sc, "muv_uv_sculpt_relax_method")
-            box.prop(sc, "muv_uv_sculpt_show_brush")
diff --git a/uv_magic_uv/legacy/ui/view3d_uv_mapping.py b/uv_magic_uv/legacy/ui/view3d_uv_mapping.py
deleted file mode 100644
index 3de86d0de00a0f698dd86a002e39cca95ba8c2a0..0000000000000000000000000000000000000000
--- a/uv_magic_uv/legacy/ui/view3d_uv_mapping.py
+++ /dev/null
@@ -1,116 +0,0 @@
-# <pep8-80 compliant>
-
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-__author__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-
-from ..op import (
-    uvw,
-    texture_projection,
-    unwrap_constraint,
-)
-from ..op.texture_projection import (
-    MUV_OT_TextureProjection
-)
-from ...utils.bl_class_registry import BlClassRegistry
-
-__all__ = [
-    'MUV_PT_View3D_UVMapping',
-]
-
-
-@BlClassRegistry(legacy=True)
-class MUV_PT_View3D_UVMapping(bpy.types.Panel):
-    """
-    Panel class: UV Mapping on Property Panel on View3D
-    """
-
-    bl_space_type = 'VIEW_3D'
-    bl_region_type = 'TOOLS'
-    bl_label = "UV Mapping"
-    bl_category = "Magic UV"
-    bl_context = 'mesh_edit'
-    bl_options = {'DEFAULT_CLOSED'}
-
-    def draw_header(self, _):
-        layout = self.layout
-        layout.label(text="", icon='IMAGE_COL')
-
-    def draw(self, context):
-        sc = context.scene
-        layout = self.layout
-
-        box = layout.box()
-        box.prop(sc, "muv_unwrap_constraint_enabled", text="Unwrap Constraint")
-        if sc.muv_unwrap_constraint_enabled:
-            ops = box.operator(
-                unwrap_constraint.MUV_OT_UnwrapConstraint.bl_idname,
-                text="Unwrap")
-            ops.u_const = sc.muv_unwrap_constraint_u_const
-            ops.v_const = sc.muv_unwrap_constraint_v_const
-            row = box.row(align=True)
-            row.prop(sc, "muv_unwrap_constraint_u_const", text="U-Constraint")
-            row.prop(sc, "muv_unwrap_constraint_v_const", text="V-Constraint")
-
-        box = layout.box()
-        box.prop(sc, "muv_texture_projection_enabled",
-                 text="Texture Projection")
-        if sc.muv_texture_projection_enabled:
-            row = box.row()
-            row.prop(
-                sc, "muv_texture_projection_enable",
-                text="Disable"
-                if MUV_OT_TextureProjection.is_running(context)
-                else "Enable",
-                icon='RESTRICT_VIEW_OFF'
-                if MUV_OT_TextureProjection.is_running(context)
-                else 'RESTRICT_VIEW_ON')
-            row.prop(sc, "muv_texture_projection_tex_image", text="")
-            box.prop(sc, "muv_texture_projection_tex_transparency",
-                     text="Transparency")
-            col = box.column(align=True)
-            row = col.row()
-            row.prop(sc, "muv_texture_projection_adjust_window",
-                     text="Adjust Window")
-            if not sc.muv_texture_projection_adjust_window:
-                row.prop(sc, "muv_texture_projection_tex_magnitude",
-                         text="Magnitude")
-            col.prop(sc, "muv_texture_projection_apply_tex_aspect",
-                     text="Texture Aspect Ratio")
-            col.prop(sc, "muv_texture_projection_assign_uvmap",
-                     text="Assign UVMap")
-            box.operator(
-                texture_projection.MUV_OT_TextureProjection_Project.bl_idname,
-                text="Project")
-
-        box = layout.box()
-        box.prop(sc, "muv_uvw_enabled", text="UVW")
-        if sc.muv_uvw_enabled:
-            row = box.row(align=True)
-            ops = row.operator(uvw.MUV_OT_UVW_BoxMap.bl_idname, text="Box")
-            ops.assign_uvmap = sc.muv_uvw_assign_uvmap
-            ops = row.operator(uvw.MUV_OT_UVW_BestPlanerMap.bl_idname,
-                               text="Best Planner")
-            ops.assign_uvmap = sc.muv_uvw_assign_uvmap
-            box.prop(sc, "muv_uvw_assign_uvmap", text="Assign UVMap")
diff --git a/uv_magic_uv/lib/bglx.py b/uv_magic_uv/lib/bglx.py
index c4dadd697a7d9538b35d3af187faee467167cbab..72e030fa9aa11acba90ec29edfd540f4b503c5f7 100644
--- a/uv_magic_uv/lib/bglx.py
+++ b/uv_magic_uv/lib/bglx.py
@@ -1,10 +1,13 @@
 from threading import Lock
 
+import bgl
+from bgl import Buffer as Buffer
 import gpu
 from gpu_extras.batch import batch_for_shader
 
 GL_LINES = 0
 GL_LINE_STRIP = 1
+GL_LINE_LOOP = 2
 GL_TRIANGLES = 5
 GL_TRIANGLE_FAN = 6
 GL_QUADS = 4
@@ -18,7 +21,11 @@ class InternalData:
 
     @classmethod
     def __internal_new(cls):
-        return super().__new__(cls)
+        inst = super().__new__(cls)
+        inst.color = [1.0, 1.0, 1.0, 1.0]
+        inst.line_width = 1.0
+
+        return inst
 
     @classmethod
     def get_instance(cls):
@@ -47,6 +54,9 @@ class InternalData:
     def set_color(self, c):
         self.color = c
 
+    def set_line_width(self, width):
+        self.line_width = width
+
     def clear(self):
         self.prim_mode = None
         self.verts = []
@@ -65,14 +75,21 @@ class InternalData:
     def get_color(self):
         return self.color
 
+    def get_line_width(self):
+        return self.line_width
+
     def get_tex_coords(self):
         return self.tex_coords
 
 
-def glBegin(mode):
+def glLineWidth(width):
     inst = InternalData.get_instance()
-    inst.init()
-    inst.set_prim_mode(mode)
+    inst.set_line_width(width)
+
+
+def glColor3f(r, g, b):
+    inst = InternalData.get_instance()
+    inst.set_color([r, g, b, 1.0])
 
 
 def glColor4f(r, g, b, a):
@@ -80,6 +97,21 @@ def glColor4f(r, g, b, a):
     inst.set_color([r, g, b, a])
 
 
+def glRecti(x0, y0, x1, y1):
+    glBegin(GL_QUADS)
+    glVertex2f(x0, y0)
+    glVertex2f(x0, y1)
+    glVertex2f(x1, y1)
+    glVertex2f(x1, y0)
+    glEnd()
+
+
+def glBegin(mode):
+    inst = InternalData.get_instance()
+    inst.init()
+    inst.set_prim_mode(mode)
+
+
 def _get_transparency_shader():
     vertex_shader = '''
     uniform mat4 modelViewMatrix;
@@ -149,6 +181,11 @@ def glEnd():
     elif inst.get_prim_mode() == GL_LINE_STRIP:
         batch = batch_for_shader(shader, 'LINE_STRIP', data)
 
+
+    elif inst.get_prim_mode() == GL_LINE_LOOP:
+        data["pos"].append(data["pos"][0])
+        batch = batch_for_shader(shader, 'LINE_STRIP', data)
+
     elif inst.get_prim_mode() == GL_TRIANGLES:
         indices = []
         for i in range(0, len(coords), 3):
@@ -189,3 +226,35 @@ def glVertex2f(x, y):
 def glTexCoord2f(u, v):
     inst = InternalData.get_instance()
     inst.add_tex_coord([u, v])
+
+
+GL_BLEND = bgl.GL_BLEND
+GL_LINE_SMOOTH = bgl.GL_LINE_SMOOTH
+GL_INT = bgl.GL_INT
+GL_SCISSOR_BOX = bgl.GL_SCISSOR_BOX
+GL_TEXTURE_2D = bgl.GL_TEXTURE_2D
+GL_TEXTURE0 = bgl.GL_TEXTURE0
+
+
+def glEnable(cap):
+    bgl.glEnable(cap)
+
+
+def glDisable(cap):
+    bgl.glDisable(cap)
+
+
+def glScissor(x, y, width, height):
+    bgl.glScissor(x, y, width, height)
+
+
+def glGetIntegerv(pname, params):
+    bgl.glGetIntegerv(pname, params)
+
+
+def glActiveTexture(texture):
+    bgl.glActiveTexture(texture)
+
+
+def glBindTexture(target, texture):
+    bgl.glBindTexture(target, texture)
diff --git a/uv_magic_uv/op/align_uv.py b/uv_magic_uv/op/align_uv.py
index fbd119d298fc2ef9df63a37ac771830e8e83ea2a..8225858e4e5029eb09be2ff8b2ee17d1523d5588 100644
--- a/uv_magic_uv/op/align_uv.py
+++ b/uv_magic_uv/op/align_uv.py
@@ -23,12 +23,271 @@ __status__ = "production"
 __version__ = "5.2"
 __date__ = "17 Nov 2018"
 
+import math
+from math import atan2, tan, sin, cos
+
 import bpy
 from bpy.props import EnumProperty, BoolProperty, FloatProperty
+import bmesh
+from mathutils import Vector
 
 from ..utils.bl_class_registry import BlClassRegistry
 from ..utils.property_class_registry import PropertyClassRegistry
-from ..impl import align_uv_impl as impl
+from ..utils import compatibility as compat
+
+from .. import common
+
+
+def _is_valid_context(context):
+    obj = context.object
+
+    # only edit mode is allowed to execute
+    if obj is None:
+        return False
+    if obj.type != 'MESH':
+        return False
+    if context.object.mode != 'EDIT':
+        return False
+
+    # 'IMAGE_EDITOR' and 'VIEW_3D' space is allowed to execute.
+    # If 'View_3D' space is not allowed, you can't find option in Tool-Shelf
+    # after the execution
+    for space in context.area.spaces:
+        if (space.type == 'IMAGE_EDITOR') or (space.type == 'VIEW_3D'):
+            break
+    else:
+        return False
+
+    return True
+
+
+# get sum vertex length of loop sequences
+def _get_loop_vert_len(loops):
+    length = 0
+    for l1, l2 in zip(loops[:-1], loops[1:]):
+        diff = l2.vert.co - l1.vert.co
+        length = length + abs(diff.length)
+
+    return length
+
+
+# get sum uv length of loop sequences
+def _get_loop_uv_len(loops, uv_layer):
+    length = 0
+    for l1, l2 in zip(loops[:-1], loops[1:]):
+        diff = l2[uv_layer].uv - l1[uv_layer].uv
+        length = length + abs(diff.length)
+
+    return length
+
+
+# get center/radius of circle by 3 vertices
+def _get_circle(v):
+    alpha = atan2((v[0].y - v[1].y), (v[0].x - v[1].x)) + math.pi / 2
+    beta = atan2((v[1].y - v[2].y), (v[1].x - v[2].x)) + math.pi / 2
+    ex = (v[0].x + v[1].x) / 2.0
+    ey = (v[0].y + v[1].y) / 2.0
+    fx = (v[1].x + v[2].x) / 2.0
+    fy = (v[1].y + v[2].y) / 2.0
+    cx = (ey - fy - ex * tan(alpha) + fx * tan(beta)) / \
+         (tan(beta) - tan(alpha))
+    cy = ey - (ex - cx) * tan(alpha)
+    center = Vector((cx, cy))
+
+    r = v[0] - center
+    radian = r.length
+
+    return center, radian
+
+
+# get position on circle with same arc length
+def _calc_v_on_circle(v, center, radius):
+    base = v[0]
+    theta = atan2(base.y - center.y, base.x - center.x)
+    new_v = []
+    for i in range(len(v)):
+        angle = theta + i * 2 * math.pi / len(v)
+        new_v.append(Vector((center.x + radius * sin(angle),
+                             center.y + radius * cos(angle))))
+
+    return new_v
+
+
+# get accumulate vertex lengths of loop sequences
+def _get_loop_vert_accum_len(loops):
+    accum_lengths = [0.0]
+    length = 0
+    for l1, l2 in zip(loops[:-1], loops[1:]):
+        diff = l2.vert.co - l1.vert.co
+        length = length + abs(diff.length)
+        accum_lengths.extend([length])
+
+    return accum_lengths
+
+
+# get sum uv length of loop sequences
+def _get_loop_uv_accum_len(loops, uv_layer):
+    accum_lengths = [0.0]
+    length = 0
+    for l1, l2 in zip(loops[:-1], loops[1:]):
+        diff = l2[uv_layer].uv - l1[uv_layer].uv
+        length = length + abs(diff.length)
+        accum_lengths.extend([length])
+
+    return accum_lengths
+
+
+# get horizontal differential of UV influenced by mesh vertex
+def _get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, pidx, infl):
+    common.debug_print(
+        "loop_seqs[hidx={0}][vidx={1}][pidx={2}]".format(hidx, vidx, pidx))
+
+    base_uv = loop_seqs[0][vidx][0][uv_layer].uv.copy()
+
+    # calculate original length
+    hloops = []
+    for s in loop_seqs:
+        hloops.extend([s[vidx][0], s[vidx][1]])
+    total_vlen = _get_loop_vert_len(hloops)
+    accum_vlens = _get_loop_vert_accum_len(hloops)
+    total_uvlen = _get_loop_uv_len(hloops, uv_layer)
+    accum_uvlens = _get_loop_uv_accum_len(hloops, uv_layer)
+    orig_uvs = [l[uv_layer].uv.copy() for l in hloops]
+
+    # calculate target length
+    tgt_noinfl = total_uvlen * (hidx + pidx) / len(loop_seqs)
+    tgt_infl = total_uvlen * accum_vlens[hidx * 2 + pidx] / total_vlen
+    target_length = tgt_noinfl * (1 - infl) + tgt_infl * infl
+    common.debug_print(target_length)
+    common.debug_print(accum_uvlens)
+
+    # calculate target UV
+    for i in range(len(accum_uvlens[:-1])):
+        # get line segment which UV will be placed
+        if ((accum_uvlens[i] <= target_length) and
+                (accum_uvlens[i + 1] > target_length)):
+            tgt_seg_len = target_length - accum_uvlens[i]
+            seg_len = accum_uvlens[i + 1] - accum_uvlens[i]
+            uv1 = orig_uvs[i]
+            uv2 = orig_uvs[i + 1]
+            target_uv = (uv1 - base_uv) + (uv2 - uv1) * tgt_seg_len / seg_len
+            break
+        elif i == (len(accum_uvlens[:-1]) - 1):
+            if abs(accum_uvlens[i + 1] - target_length) > 0.000001:
+                raise Exception(
+                    "Internal Error: horizontal_target_length={}"
+                    " is not equal to {}"
+                    .format(target_length, accum_uvlens[-1]))
+            tgt_seg_len = target_length - accum_uvlens[i]
+            seg_len = accum_uvlens[i + 1] - accum_uvlens[i]
+            uv1 = orig_uvs[i]
+            uv2 = orig_uvs[i + 1]
+            target_uv = (uv1 - base_uv) + (uv2 - uv1) * tgt_seg_len / seg_len
+            break
+    else:
+        raise Exception("Internal Error: horizontal_target_length={}"
+                        " is not in range {} to {}"
+                        .format(target_length, accum_uvlens[0],
+                                accum_uvlens[-1]))
+
+    return target_uv
+
+
+# --------------------- LOOP STRUCTURE ----------------------
+#
+#  loops[hidx][vidx][pidx]
+#     hidx: horizontal index
+#     vidx: vertical index
+#     pidx: pair index
+#
+#              <----- horizontal ----->
+#
+#              (hidx, vidx, pidx) = (0, 3, 0)
+#              |      (hidx, vidx, pidx) = (1, 3, 0)
+#              v      v
+#          ^   o --- oo --- o
+#          |   |     ||     |
+# vertical |   o --- oo --- o  <- (hidx, vidx, pidx)
+#          |   o --- oo --- o          = (1, 2, 1)
+#          |   |     ||     |
+#          v   o --- oo --- o
+#              ^            ^
+#              |            (hidx, vidx, pidx) = (1, 0, 1)
+#              (hidx, vidx, pidx) = (0, 0, 0)
+#
+# -----------------------------------------------------------
+
+
+# get vertical differential of UV influenced by mesh vertex
+def _get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, pidx, infl):
+    common.debug_print(
+        "loop_seqs[hidx={0}][vidx={1}][pidx={2}]".format(hidx, vidx, pidx))
+
+    base_uv = loop_seqs[hidx][0][pidx][uv_layer].uv.copy()
+
+    # calculate original length
+    vloops = []
+    for s in loop_seqs[hidx]:
+        vloops.append(s[pidx])
+    total_vlen = _get_loop_vert_len(vloops)
+    accum_vlens = _get_loop_vert_accum_len(vloops)
+    total_uvlen = _get_loop_uv_len(vloops, uv_layer)
+    accum_uvlens = _get_loop_uv_accum_len(vloops, uv_layer)
+    orig_uvs = [l[uv_layer].uv.copy() for l in vloops]
+
+    # calculate target length
+    tgt_noinfl = total_uvlen * int((vidx + 1) / 2) * 2 / len(loop_seqs[hidx])
+    tgt_infl = total_uvlen * accum_vlens[vidx] / total_vlen
+    target_length = tgt_noinfl * (1 - infl) + tgt_infl * infl
+    common.debug_print(target_length)
+    common.debug_print(accum_uvlens)
+
+    # calculate target UV
+    for i in range(len(accum_uvlens[:-1])):
+        # get line segment which UV will be placed
+        if ((accum_uvlens[i] <= target_length) and
+                (accum_uvlens[i + 1] > target_length)):
+            tgt_seg_len = target_length - accum_uvlens[i]
+            seg_len = accum_uvlens[i + 1] - accum_uvlens[i]
+            uv1 = orig_uvs[i]
+            uv2 = orig_uvs[i + 1]
+            target_uv = (uv1 - base_uv) + (uv2 - uv1) * tgt_seg_len / seg_len
+            break
+        elif i == (len(accum_uvlens[:-1]) - 1):
+            if abs(accum_uvlens[i + 1] - target_length) > 0.000001:
+                raise Exception("Internal Error: horizontal_target_length={}"
+                                " is not equal to {}"
+                                .format(target_length, accum_uvlens[-1]))
+            tgt_seg_len = target_length - accum_uvlens[i]
+            seg_len = accum_uvlens[i + 1] - accum_uvlens[i]
+            uv1 = orig_uvs[i]
+            uv2 = orig_uvs[i + 1]
+            target_uv = (uv1 - base_uv) + (uv2 - uv1) * tgt_seg_len / seg_len
+            break
+    else:
+        raise Exception("Internal Error: horizontal_target_length={}"
+                        " is not in range {} to {}"
+                        .format(target_length, accum_uvlens[0],
+                                accum_uvlens[-1]))
+
+    return target_uv
+
+
+# get horizontal differential of UV no influenced
+def _get_hdiff_uv(uv_layer, loop_seqs, hidx):
+    base_uv = loop_seqs[0][0][0][uv_layer].uv.copy()
+    h_uv = loop_seqs[-1][0][1][uv_layer].uv.copy() - base_uv
+
+    return hidx * h_uv / len(loop_seqs)
+
+
+# get vertical differential of UV no influenced
+def _get_vdiff_uv(uv_layer, loop_seqs, vidx, hidx):
+    base_uv = loop_seqs[0][0][0][uv_layer].uv.copy()
+    v_uv = loop_seqs[0][-1][0][uv_layer].uv.copy() - base_uv
+
+    hseq = loop_seqs[hidx]
+    return int((vidx + 1) / 2) * v_uv / (len(hseq) / 2)
 
 
 @PropertyClassRegistry()
@@ -94,6 +353,7 @@ class _Properties:
 
 
 @BlClassRegistry()
+@compat.make_annotations
 class MUV_OT_AlignUV_Circle(bpy.types.Operator):
 
     bl_idname = "uv.muv_align_uv_operator_circle"
@@ -101,29 +361,85 @@ class MUV_OT_AlignUV_Circle(bpy.types.Operator):
     bl_description = "Align UV coordinates to Circle"
     bl_options = {'REGISTER', 'UNDO'}
 
-    transmission: BoolProperty(
+    transmission = BoolProperty(
         name="Transmission",
         description="Align linked UVs",
         default=False
     )
-    select: BoolProperty(
+    select = BoolProperty(
         name="Select",
         description="Select UVs which are aligned",
         default=False
     )
 
-    def __init__(self):
-        self.__impl = impl.CircleImpl()
-
     @classmethod
     def poll(cls, context):
-        return impl.CircleImpl.poll(context)
+        # we can not get area/space/region from console
+        if common.is_console_mode():
+            return True
+        return _is_valid_context(context)
 
     def execute(self, context):
-        return self.__impl.execute(self, context)
+        obj = context.active_object
+        bm = bmesh.from_edit_mesh(obj.data)
+        if common.check_version(2, 73, 0) >= 0:
+            bm.faces.ensure_lookup_table()
+        uv_layer = bm.loops.layers.uv.verify()
+
+        # loop_seqs[horizontal][vertical][loop]
+        loop_seqs, error = common.get_loop_sequences(bm, uv_layer, True)
+        if not loop_seqs:
+            self.report({'WARNING'}, error)
+            return {'CANCELLED'}
+
+        # get circle and new UVs
+        uvs = [hseq[0][0][uv_layer].uv.copy() for hseq in loop_seqs]
+        c, r = _get_circle(uvs[0:3])
+        new_uvs = _calc_v_on_circle(uvs, c, r)
+
+        # check center UV of circle
+        center = loop_seqs[0][-1][0].vert
+        for hseq in loop_seqs[1:]:
+            if len(hseq[-1]) != 1:
+                self.report({'WARNING'}, "Last face must be triangle")
+                return {'CANCELLED'}
+            if hseq[-1][0].vert != center:
+                self.report({'WARNING'}, "Center must be identical")
+                return {'CANCELLED'}
+
+        # align to circle
+        if self.transmission:
+            for hidx, hseq in enumerate(loop_seqs):
+                for vidx, pair in enumerate(hseq):
+                    all_ = int((len(hseq) + 1) / 2)
+                    r = (all_ - int((vidx + 1) / 2)) / all_
+                    pair[0][uv_layer].uv = c + (new_uvs[hidx] - c) * r
+                    if self.select:
+                        pair[0][uv_layer].select = True
+
+                    if len(pair) < 2:
+                        continue
+                    # for quad polygon
+                    next_hidx = (hidx + 1) % len(loop_seqs)
+                    pair[1][uv_layer].uv = c + ((new_uvs[next_hidx]) - c) * r
+                    if self.select:
+                        pair[1][uv_layer].select = True
+        else:
+            for hidx, hseq in enumerate(loop_seqs):
+                pair = hseq[0]
+                pair[0][uv_layer].uv = new_uvs[hidx]
+                pair[1][uv_layer].uv = new_uvs[(hidx + 1) % len(loop_seqs)]
+                if self.select:
+                    pair[0][uv_layer].select = True
+                    pair[1][uv_layer].select = True
+
+        bmesh.update_edit_mesh(obj.data)
+
+        return {'FINISHED'}
 
 
 @BlClassRegistry()
+@compat.make_annotations
 class MUV_OT_AlignUV_Straighten(bpy.types.Operator):
 
     bl_idname = "uv.muv_align_uv_operator_straighten"
@@ -131,29 +447,29 @@ class MUV_OT_AlignUV_Straighten(bpy.types.Operator):
     bl_description = "Straighten UV coordinates"
     bl_options = {'REGISTER', 'UNDO'}
 
-    transmission: BoolProperty(
+    transmission = BoolProperty(
         name="Transmission",
         description="Align linked UVs",
         default=False
     )
-    select: BoolProperty(
+    select = BoolProperty(
         name="Select",
         description="Select UVs which are aligned",
         default=False
     )
-    vertical: BoolProperty(
+    vertical = BoolProperty(
         name="Vert-Infl (Vertical)",
         description="Align vertical direction influenced "
                     "by mesh vertex proportion",
         default=False
     )
-    horizontal: BoolProperty(
+    horizontal = BoolProperty(
         name="Vert-Infl (Horizontal)",
         description="Align horizontal direction influenced "
                     "by mesh vertex proportion",
         default=False
     )
-    mesh_infl: FloatProperty(
+    mesh_infl = FloatProperty(
         name="Mesh Influence",
         description="Influence rate of mesh vertex",
         min=0.0,
@@ -161,18 +477,121 @@ class MUV_OT_AlignUV_Straighten(bpy.types.Operator):
         default=0.0
     )
 
-    def __init__(self):
-        self.__impl = impl.StraightenImpl()
-
     @classmethod
     def poll(cls, context):
-        return impl.StraightenImpl.poll(context)
+        # we can not get area/space/region from console
+        if common.is_console_mode():
+            return True
+        return _is_valid_context(context)
+
+    # selected and paralleled UV loop sequence will be aligned
+    def __align_w_transmission(self, loop_seqs, uv_layer):
+        base_uv = loop_seqs[0][0][0][uv_layer].uv.copy()
+
+        # calculate diff UVs
+        diff_uvs = []
+        # hseq[vertical][loop]
+        for hidx, hseq in enumerate(loop_seqs):
+            # pair[loop]
+            diffs = []
+            for vidx in range(0, len(hseq), 2):
+                if self.horizontal:
+                    hdiff_uvs = [
+                        _get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 0,
+                                            self.mesh_infl),
+                        _get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 1,
+                                            self.mesh_infl),
+                        _get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
+                                            hidx, 0, self.mesh_infl),
+                        _get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
+                                            hidx, 1, self.mesh_infl),
+                    ]
+                else:
+                    hdiff_uvs = [
+                        _get_hdiff_uv(uv_layer, loop_seqs, hidx),
+                        _get_hdiff_uv(uv_layer, loop_seqs, hidx + 1),
+                        _get_hdiff_uv(uv_layer, loop_seqs, hidx),
+                        _get_hdiff_uv(uv_layer, loop_seqs, hidx + 1)
+                    ]
+                if self.vertical:
+                    vdiff_uvs = [
+                        _get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 0,
+                                            self.mesh_infl),
+                        _get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 1,
+                                            self.mesh_infl),
+                        _get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
+                                            hidx, 0, self.mesh_infl),
+                        _get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
+                                            hidx, 1, self.mesh_infl),
+                    ]
+                else:
+                    vdiff_uvs = [
+                        _get_vdiff_uv(uv_layer, loop_seqs, vidx, hidx),
+                        _get_vdiff_uv(uv_layer, loop_seqs, vidx, hidx),
+                        _get_vdiff_uv(uv_layer, loop_seqs, vidx + 1, hidx),
+                        _get_vdiff_uv(uv_layer, loop_seqs, vidx + 1, hidx)
+                    ]
+                diffs.append([hdiff_uvs, vdiff_uvs])
+            diff_uvs.append(diffs)
+
+        # update UV
+        for hseq, diffs in zip(loop_seqs, diff_uvs):
+            for vidx in range(0, len(hseq), 2):
+                loops = [
+                    hseq[vidx][0], hseq[vidx][1],
+                    hseq[vidx + 1][0], hseq[vidx + 1][1]
+                ]
+                for l, hdiff, vdiff in zip(loops, diffs[int(vidx / 2)][0],
+                                           diffs[int(vidx / 2)][1]):
+                    l[uv_layer].uv = base_uv + hdiff + vdiff
+                    if self.select:
+                        l[uv_layer].select = True
+
+    # only selected UV loop sequence will be aligned
+    def __align_wo_transmission(self, loop_seqs, uv_layer):
+        base_uv = loop_seqs[0][0][0][uv_layer].uv.copy()
+
+        h_uv = loop_seqs[-1][0][1][uv_layer].uv.copy() - base_uv
+        for hidx, hseq in enumerate(loop_seqs):
+            # only selected loop pair is targeted
+            pair = hseq[0]
+            hdiff_uv_0 = hidx * h_uv / len(loop_seqs)
+            hdiff_uv_1 = (hidx + 1) * h_uv / len(loop_seqs)
+            pair[0][uv_layer].uv = base_uv + hdiff_uv_0
+            pair[1][uv_layer].uv = base_uv + hdiff_uv_1
+            if self.select:
+                pair[0][uv_layer].select = True
+                pair[1][uv_layer].select = True
+
+    def __align(self, loop_seqs, uv_layer):
+        if self.transmission:
+            self.__align_w_transmission(loop_seqs, uv_layer)
+        else:
+            self.__align_wo_transmission(loop_seqs, uv_layer)
 
     def execute(self, context):
-        return self.__impl.execute(self, context)
+        obj = context.active_object
+        bm = bmesh.from_edit_mesh(obj.data)
+        if common.check_version(2, 73, 0) >= 0:
+            bm.faces.ensure_lookup_table()
+        uv_layer = bm.loops.layers.uv.verify()
+
+        # loop_seqs[horizontal][vertical][loop]
+        loop_seqs, error = common.get_loop_sequences(bm, uv_layer)
+        if not loop_seqs:
+            self.report({'WARNING'}, error)
+            return {'CANCELLED'}
+
+        # align
+        self.__align(loop_seqs, uv_layer)
+
+        bmesh.update_edit_mesh(obj.data)
+
+        return {'FINISHED'}
 
 
 @BlClassRegistry()
+@compat.make_annotations
 class MUV_OT_AlignUV_Axis(bpy.types.Operator):
 
     bl_idname = "uv.muv_align_uv_operator_axis"
@@ -180,29 +599,29 @@ class MUV_OT_AlignUV_Axis(bpy.types.Operator):
     bl_description = "Align UV to XY-axis"
     bl_options = {'REGISTER', 'UNDO'}
 
-    transmission: BoolProperty(
+    transmission = BoolProperty(
         name="Transmission",
         description="Align linked UVs",
         default=False
     )
-    select: BoolProperty(
+    select = BoolProperty(
         name="Select",
         description="Select UVs which are aligned",
         default=False
     )
-    vertical: BoolProperty(
+    vertical = BoolProperty(
         name="Vert-Infl (Vertical)",
         description="Align vertical direction influenced "
                     "by mesh vertex proportion",
         default=False
     )
-    horizontal: BoolProperty(
+    horizontal = BoolProperty(
         name="Vert-Infl (Horizontal)",
         description="Align horizontal direction influenced "
                     "by mesh vertex proportion",
         default=False
     )
-    location: EnumProperty(
+    location = EnumProperty(
         name="Location",
         description="Align location",
         items=[
@@ -212,7 +631,7 @@ class MUV_OT_AlignUV_Axis(bpy.types.Operator):
         ],
         default='MIDDLE'
     )
-    mesh_infl: FloatProperty(
+    mesh_infl = FloatProperty(
         name="Mesh Influence",
         description="Influence rate of mesh vertex",
         min=0.0,
@@ -220,12 +639,353 @@ class MUV_OT_AlignUV_Axis(bpy.types.Operator):
         default=0.0
     )
 
-    def __init__(self):
-        self.__impl = impl.AxisImpl()
-
     @classmethod
     def poll(cls, context):
-        return impl.AxisImpl.poll(context)
+        # we can not get area/space/region from console
+        if common.is_console_mode():
+            return True
+        return _is_valid_context(context)
+
+    # get min/max of UV
+    def __get_uv_max_min(self, loop_seqs, uv_layer):
+        uv_max = Vector((-1000000.0, -1000000.0))
+        uv_min = Vector((1000000.0, 1000000.0))
+        for hseq in loop_seqs:
+            for l in hseq[0]:
+                uv = l[uv_layer].uv
+                uv_max.x = max(uv.x, uv_max.x)
+                uv_max.y = max(uv.y, uv_max.y)
+                uv_min.x = min(uv.x, uv_min.x)
+                uv_min.y = min(uv.y, uv_min.y)
+
+        return uv_max, uv_min
+
+    # get UV differentiation when UVs are aligned to X-axis
+    def __get_x_axis_align_diff_uvs(self, loop_seqs, uv_layer, uv_min,
+                                    width, height):
+        diff_uvs = []
+        for hidx, hseq in enumerate(loop_seqs):
+            pair = hseq[0]
+            luv0 = pair[0][uv_layer]
+            luv1 = pair[1][uv_layer]
+            target_uv0 = Vector((0.0, 0.0))
+            target_uv1 = Vector((0.0, 0.0))
+            if self.location == 'RIGHT_BOTTOM':
+                target_uv0.y = target_uv1.y = uv_min.y
+            elif self.location == 'MIDDLE':
+                target_uv0.y = target_uv1.y = uv_min.y + height * 0.5
+            elif self.location == 'LEFT_TOP':
+                target_uv0.y = target_uv1.y = uv_min.y + height
+            if luv0.uv.x < luv1.uv.x:
+                target_uv0.x = uv_min.x + hidx * width / len(loop_seqs)
+                target_uv1.x = uv_min.x + (hidx + 1) * width / len(loop_seqs)
+            else:
+                target_uv0.x = uv_min.x + (hidx + 1) * width / len(loop_seqs)
+                target_uv1.x = uv_min.x + hidx * width / len(loop_seqs)
+            diff_uvs.append([target_uv0 - luv0.uv, target_uv1 - luv1.uv])
+
+        return diff_uvs
+
+    # get UV differentiation when UVs are aligned to Y-axis
+    def __get_y_axis_align_diff_uvs(self, loop_seqs, uv_layer, uv_min,
+                                    width, height):
+        diff_uvs = []
+        for hidx, hseq in enumerate(loop_seqs):
+            pair = hseq[0]
+            luv0 = pair[0][uv_layer]
+            luv1 = pair[1][uv_layer]
+            target_uv0 = Vector((0.0, 0.0))
+            target_uv1 = Vector((0.0, 0.0))
+            if self.location == 'RIGHT_BOTTOM':
+                target_uv0.x = target_uv1.x = uv_min.x + width
+            elif self.location == 'MIDDLE':
+                target_uv0.x = target_uv1.x = uv_min.x + width * 0.5
+            elif self.location == 'LEFT_TOP':
+                target_uv0.x = target_uv1.x = uv_min.x
+            if luv0.uv.y < luv1.uv.y:
+                target_uv0.y = uv_min.y + hidx * height / len(loop_seqs)
+                target_uv1.y = uv_min.y + (hidx + 1) * height / len(loop_seqs)
+            else:
+                target_uv0.y = uv_min.y + (hidx + 1) * height / len(loop_seqs)
+                target_uv1.y = uv_min.y + hidx * height / len(loop_seqs)
+            diff_uvs.append([target_uv0 - luv0.uv, target_uv1 - luv1.uv])
+
+        return diff_uvs
+
+    # only selected UV loop sequence will be aligned along to X-axis
+    def __align_to_x_axis_wo_transmission(self, loop_seqs, uv_layer,
+                                          uv_min, width, height):
+        # reverse if the UV coordinate is not sorted by position
+        need_revese = loop_seqs[0][0][0][uv_layer].uv.x > \
+            loop_seqs[-1][0][0][uv_layer].uv.x
+        if need_revese:
+            loop_seqs.reverse()
+            for hidx, hseq in enumerate(loop_seqs):
+                for vidx, pair in enumerate(hseq):
+                    tmp = loop_seqs[hidx][vidx][0]
+                    loop_seqs[hidx][vidx][0] = loop_seqs[hidx][vidx][1]
+                    loop_seqs[hidx][vidx][1] = tmp
+
+        # get UV differential
+        diff_uvs = self.__get_x_axis_align_diff_uvs(loop_seqs,
+                                                    uv_layer, uv_min,
+                                                    width, height)
+
+        # update UV
+        for hseq, duv in zip(loop_seqs, diff_uvs):
+            pair = hseq[0]
+            luv0 = pair[0][uv_layer]
+            luv1 = pair[1][uv_layer]
+            luv0.uv = luv0.uv + duv[0]
+            luv1.uv = luv1.uv + duv[1]
+
+    # only selected UV loop sequence will be aligned along to Y-axis
+    def __align_to_y_axis_wo_transmission(self, loop_seqs, uv_layer,
+                                          uv_min, width, height):
+        # reverse if the UV coordinate is not sorted by position
+        need_revese = loop_seqs[0][0][0][uv_layer].uv.y > \
+            loop_seqs[-1][0][0][uv_layer].uv.y
+        if need_revese:
+            loop_seqs.reverse()
+            for hidx, hseq in enumerate(loop_seqs):
+                for vidx, pair in enumerate(hseq):
+                    tmp = loop_seqs[hidx][vidx][0]
+                    loop_seqs[hidx][vidx][0] = loop_seqs[hidx][vidx][1]
+                    loop_seqs[hidx][vidx][1] = tmp
+
+        # get UV differential
+        diff_uvs = self.__get_y_axis_align_diff_uvs(loop_seqs,
+                                                    uv_layer, uv_min,
+                                                    width, height)
+
+        # update UV
+        for hseq, duv in zip(loop_seqs, diff_uvs):
+            pair = hseq[0]
+            luv0 = pair[0][uv_layer]
+            luv1 = pair[1][uv_layer]
+            luv0.uv = luv0.uv + duv[0]
+            luv1.uv = luv1.uv + duv[1]
+
+    # selected and paralleled UV loop sequence will be aligned along to X-axis
+    def __align_to_x_axis_w_transmission(self, loop_seqs, uv_layer,
+                                         uv_min, width, height):
+        # reverse if the UV coordinate is not sorted by position
+        need_revese = loop_seqs[0][0][0][uv_layer].uv.x > \
+            loop_seqs[-1][0][0][uv_layer].uv.x
+        if need_revese:
+            loop_seqs.reverse()
+            for hidx, hseq in enumerate(loop_seqs):
+                for vidx in range(len(hseq)):
+                    tmp = loop_seqs[hidx][vidx][0]
+                    loop_seqs[hidx][vidx][0] = loop_seqs[hidx][vidx][1]
+                    loop_seqs[hidx][vidx][1] = tmp
+
+        # get offset UVs when the UVs are aligned to X-axis
+        align_diff_uvs = self.__get_x_axis_align_diff_uvs(loop_seqs,
+                                                          uv_layer, uv_min,
+                                                          width, height)
+        base_uv = loop_seqs[0][0][0][uv_layer].uv.copy()
+        offset_uvs = []
+        for hseq, aduv in zip(loop_seqs, align_diff_uvs):
+            luv0 = hseq[0][0][uv_layer]
+            luv1 = hseq[0][1][uv_layer]
+            offset_uvs.append([luv0.uv + aduv[0] - base_uv,
+                               luv1.uv + aduv[1] - base_uv])
+
+        # get UV differential
+        diff_uvs = []
+        # hseq[vertical][loop]
+        for hidx, hseq in enumerate(loop_seqs):
+            # pair[loop]
+            diffs = []
+            for vidx in range(0, len(hseq), 2):
+                if self.horizontal:
+                    hdiff_uvs = [
+                        _get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 0,
+                                            self.mesh_infl),
+                        _get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 1,
+                                            self.mesh_infl),
+                        _get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
+                                            hidx, 0, self.mesh_infl),
+                        _get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
+                                            hidx, 1, self.mesh_infl),
+                    ]
+                    hdiff_uvs[0].y = hdiff_uvs[0].y + offset_uvs[hidx][0].y
+                    hdiff_uvs[1].y = hdiff_uvs[1].y + offset_uvs[hidx][1].y
+                    hdiff_uvs[2].y = hdiff_uvs[2].y + offset_uvs[hidx][0].y
+                    hdiff_uvs[3].y = hdiff_uvs[3].y + offset_uvs[hidx][1].y
+                else:
+                    hdiff_uvs = [
+                        offset_uvs[hidx][0],
+                        offset_uvs[hidx][1],
+                        offset_uvs[hidx][0],
+                        offset_uvs[hidx][1],
+                    ]
+                if self.vertical:
+                    vdiff_uvs = [
+                        _get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 0,
+                                            self.mesh_infl),
+                        _get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 1,
+                                            self.mesh_infl),
+                        _get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
+                                            hidx, 0, self.mesh_infl),
+                        _get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
+                                            hidx, 1, self.mesh_infl),
+                    ]
+                else:
+                    vdiff_uvs = [
+                        _get_vdiff_uv(uv_layer, loop_seqs, vidx, hidx),
+                        _get_vdiff_uv(uv_layer, loop_seqs, vidx, hidx),
+                        _get_vdiff_uv(uv_layer, loop_seqs, vidx + 1, hidx),
+                        _get_vdiff_uv(uv_layer, loop_seqs, vidx + 1, hidx)
+                    ]
+                diffs.append([hdiff_uvs, vdiff_uvs])
+            diff_uvs.append(diffs)
+
+        # update UV
+        for hseq, diffs in zip(loop_seqs, diff_uvs):
+            for vidx in range(0, len(hseq), 2):
+                loops = [
+                    hseq[vidx][0], hseq[vidx][1],
+                    hseq[vidx + 1][0], hseq[vidx + 1][1]
+                ]
+                for l, hdiff, vdiff in zip(loops, diffs[int(vidx / 2)][0],
+                                           diffs[int(vidx / 2)][1]):
+                    l[uv_layer].uv = base_uv + hdiff + vdiff
+                    if self.select:
+                        l[uv_layer].select = True
+
+    # selected and paralleled UV loop sequence will be aligned along to Y-axis
+    def __align_to_y_axis_w_transmission(self, loop_seqs, uv_layer,
+                                         uv_min, width, height):
+        # reverse if the UV coordinate is not sorted by position
+        need_revese = loop_seqs[0][0][0][uv_layer].uv.y > \
+            loop_seqs[-1][0][-1][uv_layer].uv.y
+        if need_revese:
+            loop_seqs.reverse()
+            for hidx, hseq in enumerate(loop_seqs):
+                for vidx in range(len(hseq)):
+                    tmp = loop_seqs[hidx][vidx][0]
+                    loop_seqs[hidx][vidx][0] = loop_seqs[hidx][vidx][1]
+                    loop_seqs[hidx][vidx][1] = tmp
+
+        # get offset UVs when the UVs are aligned to Y-axis
+        align_diff_uvs = self.__get_y_axis_align_diff_uvs(loop_seqs,
+                                                          uv_layer, uv_min,
+                                                          width, height)
+        base_uv = loop_seqs[0][0][0][uv_layer].uv.copy()
+        offset_uvs = []
+        for hseq, aduv in zip(loop_seqs, align_diff_uvs):
+            luv0 = hseq[0][0][uv_layer]
+            luv1 = hseq[0][1][uv_layer]
+            offset_uvs.append([luv0.uv + aduv[0] - base_uv,
+                               luv1.uv + aduv[1] - base_uv])
+
+        # get UV differential
+        diff_uvs = []
+        # hseq[vertical][loop]
+        for hidx, hseq in enumerate(loop_seqs):
+            # pair[loop]
+            diffs = []
+            for vidx in range(0, len(hseq), 2):
+                if self.horizontal:
+                    hdiff_uvs = [
+                        _get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 0,
+                                            self.mesh_infl),
+                        _get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 1,
+                                            self.mesh_infl),
+                        _get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
+                                            hidx, 0, self.mesh_infl),
+                        _get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
+                                            hidx, 1, self.mesh_infl),
+                    ]
+                    hdiff_uvs[0].x = hdiff_uvs[0].x + offset_uvs[hidx][0].x
+                    hdiff_uvs[1].x = hdiff_uvs[1].x + offset_uvs[hidx][1].x
+                    hdiff_uvs[2].x = hdiff_uvs[2].x + offset_uvs[hidx][0].x
+                    hdiff_uvs[3].x = hdiff_uvs[3].x + offset_uvs[hidx][1].x
+                else:
+                    hdiff_uvs = [
+                        offset_uvs[hidx][0],
+                        offset_uvs[hidx][1],
+                        offset_uvs[hidx][0],
+                        offset_uvs[hidx][1],
+                    ]
+                if self.vertical:
+                    vdiff_uvs = [
+                        _get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 0,
+                                            self.mesh_infl),
+                        _get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 1,
+                                            self.mesh_infl),
+                        _get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
+                                            hidx, 0, self.mesh_infl),
+                        _get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
+                                            hidx, 1, self.mesh_infl),
+                    ]
+                else:
+                    vdiff_uvs = [
+                        _get_vdiff_uv(uv_layer, loop_seqs, vidx, hidx),
+                        _get_vdiff_uv(uv_layer, loop_seqs, vidx, hidx),
+                        _get_vdiff_uv(uv_layer, loop_seqs, vidx + 1, hidx),
+                        _get_vdiff_uv(uv_layer, loop_seqs, vidx + 1, hidx)
+                    ]
+                diffs.append([hdiff_uvs, vdiff_uvs])
+            diff_uvs.append(diffs)
+
+        # update UV
+        for hseq, diffs in zip(loop_seqs, diff_uvs):
+            for vidx in range(0, len(hseq), 2):
+                loops = [
+                    hseq[vidx][0], hseq[vidx][1],
+                    hseq[vidx + 1][0], hseq[vidx + 1][1]
+                ]
+                for l, hdiff, vdiff in zip(loops, diffs[int(vidx / 2)][0],
+                                           diffs[int(vidx / 2)][1]):
+                    l[uv_layer].uv = base_uv + hdiff + vdiff
+                    if self.select:
+                        l[uv_layer].select = True
+
+    def __align(self, loop_seqs, uv_layer, uv_min, width, height):
+        # align along to x-axis
+        if width > height:
+            if self.transmission:
+                self.__align_to_x_axis_w_transmission(loop_seqs,
+                                                      uv_layer, uv_min,
+                                                      width, height)
+            else:
+                self.__align_to_x_axis_wo_transmission(loop_seqs,
+                                                       uv_layer, uv_min,
+                                                       width, height)
+        # align along to y-axis
+        else:
+            if self.transmission:
+                self.__align_to_y_axis_w_transmission(loop_seqs,
+                                                      uv_layer, uv_min,
+                                                      width, height)
+            else:
+                self.__align_to_y_axis_wo_transmission(loop_seqs,
+                                                       uv_layer, uv_min,
+                                                       width, height)
 
     def execute(self, context):
-        return self.__impl.execute(self, context)
+        obj = context.active_object
+        bm = bmesh.from_edit_mesh(obj.data)
+        if common.check_version(2, 73, 0) >= 0:
+            bm.faces.ensure_lookup_table()
+        uv_layer = bm.loops.layers.uv.verify()
+
+        # loop_seqs[horizontal][vertical][loop]
+        loop_seqs, error = common.get_loop_sequences(bm, uv_layer)
+        if not loop_seqs:
+            self.report({'WARNING'}, error)
+            return {'CANCELLED'}
+
+        # get height and width
+        uv_max, uv_min = self.__get_uv_max_min(loop_seqs, uv_layer)
+        width = uv_max.x - uv_min.x
+        height = uv_max.y - uv_min.y
+
+        self.__align(loop_seqs, uv_layer, uv_min, width, height)
+
+        bmesh.update_edit_mesh(obj.data)
+
+        return {'FINISHED'}
diff --git a/uv_magic_uv/op/align_uv_cursor.py b/uv_magic_uv/op/align_uv_cursor.py
index 6de4bbcfd50740ca374cf1215e05a0fdc8eda25b..ab4e93b422eb57919749a856145fa292fd1050c9 100644
--- a/uv_magic_uv/op/align_uv_cursor.py
+++ b/uv_magic_uv/op/align_uv_cursor.py
@@ -26,11 +26,25 @@ __date__ = "17 Nov 2018"
 import bpy
 from mathutils import Vector
 from bpy.props import EnumProperty, BoolProperty, FloatVectorProperty
+import bmesh
 
 from .. import common
 from ..utils.bl_class_registry import BlClassRegistry
 from ..utils.property_class_registry import PropertyClassRegistry
-from ..impl import align_uv_cursor_impl as impl
+from ..utils import compatibility as compat
+
+
+def _is_valid_context(context):
+    # 'IMAGE_EDITOR' and 'VIEW_3D' space is allowed to execute.
+    # If 'View_3D' space is not allowed, you can't find option in Tool-Shelf
+    # after the execution
+    for space in context.area.spaces:
+        if (space.type == 'IMAGE_EDITOR') or (space.type == 'VIEW_3D'):
+            break
+    else:
+        return False
+
+    return True
 
 
 @PropertyClassRegistry()
@@ -40,17 +54,37 @@ class _Properties:
     @classmethod
     def init_props(cls, scene):
         def auvc_get_cursor_loc(self):
-            _, _, space = common.get_space_legacy('IMAGE_EDITOR', 'WINDOW',
-                                                  'IMAGE_EDITOR')
+            area, _, space = common.get_space('IMAGE_EDITOR', 'WINDOW',
+                                              'IMAGE_EDITOR')
+            if compat.check_version(2, 80, 0) < 0:
+                bd_size = common.get_uvimg_editor_board_size(area)
+            else:
+                bd_size = [1.0, 1.0]
             loc = space.cursor_location
-            self['muv_align_uv_cursor_cursor_loc'] = Vector((loc[0], loc[1]))
+
+            if bd_size[0] < 0.000001:
+                cx = 0.0
+            else:
+                cx = loc[0] / bd_size[0]
+            if bd_size[1] < 0.000001:
+                cy = 0.0
+            else:
+                cy = loc[1] / bd_size[1]
+
+            self['muv_align_uv_cursor_cursor_loc'] = Vector((cx, cy))
             return self.get('muv_align_uv_cursor_cursor_loc', (0.0, 0.0))
 
         def auvc_set_cursor_loc(self, value):
             self['muv_align_uv_cursor_cursor_loc'] = value
-            _, _, space = common.get_space_legacy('IMAGE_EDITOR', 'WINDOW',
-                                                  'IMAGE_EDITOR')
-            space.cursor_location = Vector((value[0], value[1]))
+            area, _, space = common.get_space('IMAGE_EDITOR', 'WINDOW',
+                                              'IMAGE_EDITOR')
+            if compat.check_version(2, 80, 0) < 0:
+                bd_size = common.get_uvimg_editor_board_size(area)
+            else:
+                bd_size = [1.0, 1.0]
+            cx = bd_size[0] * value[0]
+            cy = bd_size[1] * value[1]
+            space.cursor_location = Vector((cx, cy))
 
         scene.muv_align_uv_cursor_enabled = BoolProperty(
             name="Align UV Cursor Enabled",
@@ -96,6 +130,7 @@ class _Properties:
 
 
 @BlClassRegistry()
+@compat.make_annotations
 class MUV_OT_AlignUVCursor(bpy.types.Operator):
 
     bl_idname = "uv.muv_align_uv_cursor_operator"
@@ -103,7 +138,7 @@ class MUV_OT_AlignUVCursor(bpy.types.Operator):
     bl_description = "Align cursor to the center of UV island"
     bl_options = {'REGISTER', 'UNDO'}
 
-    position: EnumProperty(
+    position = EnumProperty(
         items=(
             ('CENTER', "Center", "Align to Center"),
             ('LEFT_TOP', "Left Top", "Align to Left Top"),
@@ -119,7 +154,7 @@ class MUV_OT_AlignUVCursor(bpy.types.Operator):
         description="Align position",
         default='CENTER'
     )
-    base: EnumProperty(
+    base = EnumProperty(
         items=(
             ('TEXTURE', "Texture", "Align based on Texture"),
             ('UV', "UV", "Align to UV"),
@@ -130,12 +165,105 @@ class MUV_OT_AlignUVCursor(bpy.types.Operator):
         default='TEXTURE'
     )
 
-    def __init__(self):
-        self.__impl = impl.AlignUVCursorImpl()
-
     @classmethod
     def poll(cls, context):
-        return impl.AlignUVCursorImpl.poll(context)
+        # we can not get area/space/region from console
+        if common.is_console_mode():
+            return True
+        return _is_valid_context(context)
 
     def execute(self, context):
-        return self.__impl.execute(self, context)
+        area, _, space = common.get_space('IMAGE_EDITOR', 'WINDOW',
+                                          'IMAGE_EDITOR')
+        if compat.check_version(2, 80, 0) < 0:
+            bd_size = common.get_uvimg_editor_board_size(area)
+        else:
+            bd_size = [1.0, 1.0]
+
+        if self.base == 'UV':
+            obj = context.active_object
+            bm = bmesh.from_edit_mesh(obj.data)
+            if not bm.loops.layers.uv:
+                return None
+            uv_layer = bm.loops.layers.uv.verify()
+
+            max_ = Vector((-10000000.0, -10000000.0))
+            min_ = Vector((10000000.0, 10000000.0))
+            for f in bm.faces:
+                if not f.select:
+                    continue
+                for l in f.loops:
+                    uv = l[uv_layer].uv
+                    max_.x = max(max_.x, uv.x)
+                    max_.y = max(max_.y, uv.y)
+                    min_.x = min(min_.x, uv.x)
+                    min_.y = min(min_.y, uv.y)
+            center = Vector(((max_.x + min_.x) / 2.0, (max_.y + min_.y) / 2.0))
+
+        elif self.base == 'UV_SEL':
+            obj = context.active_object
+            bm = bmesh.from_edit_mesh(obj.data)
+            if not bm.loops.layers.uv:
+                return None
+            uv_layer = bm.loops.layers.uv.verify()
+
+            max_ = Vector((-10000000.0, -10000000.0))
+            min_ = Vector((10000000.0, 10000000.0))
+            for f in bm.faces:
+                if not f.select:
+                    continue
+                for l in f.loops:
+                    if not l[uv_layer].select:
+                        continue
+                    uv = l[uv_layer].uv
+                    max_.x = max(max_.x, uv.x)
+                    max_.y = max(max_.y, uv.y)
+                    min_.x = min(min_.x, uv.x)
+                    min_.y = min(min_.y, uv.y)
+            center = Vector(((max_.x + min_.x) / 2.0, (max_.y + min_.y) / 2.0))
+
+        elif self.base == 'TEXTURE':
+            min_ = Vector((0.0, 0.0))
+            max_ = Vector((1.0, 1.0))
+            center = Vector((0.5, 0.5))
+        else:
+            self.report({'ERROR'}, "Unknown Operation")
+            return {'CANCELLED'}
+
+        if self.position == 'CENTER':
+            cx = center.x
+            cy = center.y
+        elif self.position == 'LEFT_TOP':
+            cx = min_.x
+            cy = max_.y
+        elif self.position == 'LEFT_MIDDLE':
+            cx = min_.x
+            cy = center.y
+        elif self.position == 'LEFT_BOTTOM':
+            cx = min_.x
+            cy = min_.y
+        elif self.position == 'MIDDLE_TOP':
+            cx = center.x
+            cy = max_.y
+        elif self.position == 'MIDDLE_BOTTOM':
+            cx = center.x
+            cy = min_.y
+        elif self.position == 'RIGHT_TOP':
+            cx = max_.x
+            cy = max_.y
+        elif self.position == 'RIGHT_MIDDLE':
+            cx = max_.x
+            cy = center.y
+        elif self.position == 'RIGHT_BOTTOM':
+            cx = max_.x
+            cy = min_.y
+        else:
+            self.report({'ERROR'}, "Unknown Operation")
+            return {'CANCELLED'}
+
+        cx = cx * bd_size[0]
+        cy = cy * bd_size[1]
+
+        space.cursor_location = Vector((cx, cy))
+
+        return {'FINISHED'}
diff --git a/uv_magic_uv/op/copy_paste_uv.py b/uv_magic_uv/op/copy_paste_uv.py
index 23bc8343853fa275a4d414e19a7ab68ea628de82..f5ff883e235fe319b10420e0b8537a23e3d9e498 100644
--- a/uv_magic_uv/op/copy_paste_uv.py
+++ b/uv_magic_uv/op/copy_paste_uv.py
@@ -23,7 +23,6 @@ __status__ = "production"
 __version__ = "5.2"
 __date__ = "17 Nov 2018"
 
-
 import bmesh
 import bpy.utils
 from bpy.props import (
@@ -33,26 +32,244 @@ from bpy.props import (
     EnumProperty,
 )
 
-from ..impl import copy_paste_uv_impl as impl
 from .. import common
 from ..utils.bl_class_registry import BlClassRegistry
 from ..utils.property_class_registry import PropertyClassRegistry
-
-__all__ = [
-    'Properties',
-    'MUV_OT_CopyPasteUV_CopyUV',
-    'MUV_MT_CopyPasteUV_CopyUV',
-    'MUV_OT_CopyPasteUV_PasteUV',
-    'MUV_MT_CopyPasteUV_PasteUV',
-    'MUV_OT_CopyPasteUV_SelSeqCopyUV',
-    'MUV_MT_CopyPasteUV_SelSeqCopyUV',
-    'MUV_OT_CopyPasteUV_SelSeqPasteUV',
-    'MUV_MT_CopyPasteUV_SelSeqPasteUV',
-]
+from ..utils import compatibility as compat
+
+
+def _is_valid_context(context):
+    obj = context.object
+
+    # only edit mode is allowed to execute
+    if obj is None:
+        return False
+    if obj.type != 'MESH':
+        return False
+    if context.object.mode != 'EDIT':
+        return False
+
+    # only 'VIEW_3D' space is allowed to execute
+    for space in context.area.spaces:
+        if space.type == 'VIEW_3D':
+            break
+    else:
+        return False
+
+    return True
+
+
+def get_copy_uv_layers(ops_obj, bm, uv_map):
+    uv_layers = []
+    if uv_map == "__default":
+        if not bm.loops.layers.uv:
+            ops_obj.report(
+                {'WARNING'}, "Object must have more than one UV map")
+            return None
+        uv_layers.append(bm.loops.layers.uv.verify())
+        ops_obj.report({'INFO'}, "Copy UV coordinate")
+    elif uv_map == "__all":
+        for uv in bm.loops.layers.uv.keys():
+            uv_layers.append(bm.loops.layers.uv[uv])
+        ops_obj.report({'INFO'}, "Copy UV coordinate (UV map: ALL)")
+    else:
+        uv_layers.append(bm.loops.layers.uv[uv_map])
+        ops_obj.report(
+            {'INFO'}, "Copy UV coordinate (UV map:{})".format(uv_map))
+
+    return uv_layers
+
+
+def get_paste_uv_layers(ops_obj, obj, bm, src_info, uv_map):
+    uv_layers = []
+    if uv_map == "__default":
+        if not bm.loops.layers.uv:
+            ops_obj.report(
+                {'WARNING'}, "Object must have more than one UV map")
+            return None
+        uv_layers.append(bm.loops.layers.uv.verify())
+        ops_obj.report({'INFO'}, "Paste UV coordinate")
+    elif uv_map == "__new":
+        new_uv_map = common.create_new_uv_map(obj)
+        if not new_uv_map:
+            ops_obj.report({'WARNING'},
+                           "Reached to the maximum number of UV map")
+            return None
+        uv_layers.append(bm.loops.layers.uv[new_uv_map.name])
+        ops_obj.report(
+            {'INFO'}, "Paste UV coordinate (UV map:{})".format(new_uv_map))
+    elif uv_map == "__all":
+        for src_layer in src_info.keys():
+            if src_layer not in bm.loops.layers.uv.keys():
+                new_uv_map = common.create_new_uv_map(obj, src_layer)
+                if not new_uv_map:
+                    ops_obj.report({'WARNING'},
+                                   "Reached to the maximum number of UV map")
+                    return None
+            uv_layers.append(bm.loops.layers.uv[src_layer])
+        ops_obj.report({'INFO'}, "Paste UV coordinate (UV map: ALL)")
+    else:
+        uv_layers.append(bm.loops.layers.uv[uv_map])
+        ops_obj.report(
+            {'INFO'}, "Paste UV coordinate (UV map:{})".format(uv_map))
+
+    return uv_layers
+
+
+def get_src_face_info(ops_obj, bm, uv_layers, only_select=False):
+    src_info = {}
+    for layer in uv_layers:
+        face_info = []
+        for face in bm.faces:
+            if not only_select or face.select:
+                info = {
+                    "index": face.index,
+                    "uvs": [l[layer].uv.copy() for l in face.loops],
+                    "pin_uvs": [l[layer].pin_uv for l in face.loops],
+                    "seams": [l.edge.seam for l in face.loops],
+                }
+                face_info.append(info)
+        if not face_info:
+            ops_obj.report({'WARNING'}, "No faces are selected")
+            return None
+        src_info[layer.name] = face_info
+
+    return src_info
+
+
+def get_dest_face_info(ops_obj, bm, uv_layers, src_info, strategy,
+                       only_select=False):
+    dest_info = {}
+    for layer in uv_layers:
+        face_info = []
+        for face in bm.faces:
+            if not only_select or face.select:
+                info = {
+                    "index": face.index,
+                    "uvs": [l[layer].uv.copy() for l in face.loops],
+                }
+                face_info.append(info)
+        if not face_info:
+            ops_obj.report({'WARNING'}, "No faces are selected")
+            return None
+        key = list(src_info.keys())[0]
+        src_face_count = len(src_info[key])
+        dest_face_count = len(face_info)
+        if strategy == 'N_N' and src_face_count != dest_face_count:
+            ops_obj.report(
+                {'WARNING'},
+                "Number of selected faces is different from copied" +
+                "(src:{}, dest:{})"
+                .format(src_face_count, dest_face_count))
+            return None
+        dest_info[layer.name] = face_info
+
+    return dest_info
+
+
+def _get_select_history_src_face_info(ops_obj, bm, uv_layers):
+    src_info = {}
+    for layer in uv_layers:
+        face_info = []
+        for hist in bm.select_history:
+            if isinstance(hist, bmesh.types.BMFace) and hist.select:
+                info = {
+                    "index": hist.index,
+                    "uvs": [l[layer].uv.copy() for l in hist.loops],
+                    "pin_uvs": [l[layer].pin_uv for l in hist.loops],
+                    "seams": [l.edge.seam for l in hist.loops],
+                }
+                face_info.append(info)
+        if not face_info:
+            ops_obj.report({'WARNING'}, "No faces are selected")
+            return None
+        src_info[layer.name] = face_info
+
+    return src_info
+
+
+def _get_select_history_dest_face_info(ops_obj, bm, uv_layers, src_info,
+                                       strategy):
+    dest_info = {}
+    for layer in uv_layers:
+        face_info = []
+        for hist in bm.select_history:
+            if isinstance(hist, bmesh.types.BMFace) and hist.select:
+                info = {
+                    "index": hist.index,
+                    "uvs": [l[layer].uv.copy() for l in hist.loops],
+                }
+                face_info.append(info)
+        if not face_info:
+            ops_obj.report({'WARNING'}, "No faces are selected")
+            return None
+        key = list(src_info.keys())[0]
+        src_face_count = len(src_info[key])
+        dest_face_count = len(face_info)
+        if strategy == 'N_N' and src_face_count != dest_face_count:
+            ops_obj.report(
+                {'WARNING'},
+                "Number of selected faces is different from copied" +
+                "(src:{}, dest:{})"
+                .format(src_face_count, dest_face_count))
+            return None
+        dest_info[layer.name] = face_info
+
+    return dest_info
+
+
+def paste_uv(ops_obj, bm, src_info, dest_info, uv_layers, strategy, flip,
+             rotate, copy_seams):
+    for slayer_name, dlayer in zip(src_info.keys(), uv_layers):
+        src_faces = src_info[slayer_name]
+        dest_faces = dest_info[dlayer.name]
+
+        for idx, dinfo in enumerate(dest_faces):
+            sinfo = None
+            if strategy == 'N_N':
+                sinfo = src_faces[idx]
+            elif strategy == 'N_M':
+                sinfo = src_faces[idx % len(src_faces)]
+
+            suv = sinfo["uvs"]
+            spuv = sinfo["pin_uvs"]
+            ss = sinfo["seams"]
+            if len(sinfo["uvs"]) != len(dinfo["uvs"]):
+                ops_obj.report({'WARNING'}, "Some faces are different size")
+                return -1
+
+            suvs_fr = [uv for uv in suv]
+            spuvs_fr = [pin_uv for pin_uv in spuv]
+            ss_fr = [s for s in ss]
+
+            # flip UVs
+            if flip is True:
+                suvs_fr.reverse()
+                spuvs_fr.reverse()
+                ss_fr.reverse()
+
+            # rotate UVs
+            for _ in range(rotate):
+                uv = suvs_fr.pop()
+                pin_uv = spuvs_fr.pop()
+                s = ss_fr.pop()
+                suvs_fr.insert(0, uv)
+                spuvs_fr.insert(0, pin_uv)
+                ss_fr.insert(0, s)
+
+            # paste UVs
+            for l, suv, spuv, ss in zip(bm.faces[dinfo["index"]].loops,
+                                        suvs_fr, spuvs_fr, ss_fr):
+                l[dlayer].uv = suv
+                l[dlayer].pin_uv = spuv
+                if copy_seams is True:
+                    l.edge.seam = ss
+
+    return 0
 
 
 @PropertyClassRegistry()
-class Properties:
+class _Properties:
     idname = "copy_paste_uv"
 
     @classmethod
@@ -103,6 +320,7 @@ class Properties:
 
 
 @BlClassRegistry()
+@compat.make_annotations
 class MUV_OT_CopyPasteUV_CopyUV(bpy.types.Operator):
     """
     Operation class: Copy UV coordinate
@@ -113,14 +331,14 @@ class MUV_OT_CopyPasteUV_CopyUV(bpy.types.Operator):
     bl_description = "Copy UV coordinate"
     bl_options = {'REGISTER', 'UNDO'}
 
-    uv_map: StringProperty(default="__default", options={'HIDDEN'})
+    uv_map = StringProperty(default="__default", options={'HIDDEN'})
 
     @classmethod
     def poll(cls, context):
         # we can not get area/space/region from console
         if common.is_console_mode():
             return True
-        return impl.is_valid_context(context)
+        return _is_valid_context(context)
 
     def execute(self, context):
         props = context.scene.muv_props.copy_paste_uv
@@ -128,12 +346,12 @@ class MUV_OT_CopyPasteUV_CopyUV(bpy.types.Operator):
         bm = common.create_bmesh(obj)
 
         # get UV layer
-        uv_layers = impl.get_copy_uv_layers(self, bm, self.uv_map)
+        uv_layers = get_copy_uv_layers(self, bm, self.uv_map)
         if not uv_layers:
             return {'CANCELLED'}
 
         # get selected face
-        src_info = impl.get_src_face_info(self, bm, uv_layers)
+        src_info = get_src_face_info(self, bm, uv_layers, True)
         if src_info is None:
             return {'CANCELLED'}
         props.src_info = src_info
@@ -156,7 +374,7 @@ class MUV_MT_CopyPasteUV_CopyUV(bpy.types.Menu):
 
     @classmethod
     def poll(cls, context):
-        return impl.is_valid_context(context)
+        return _is_valid_context(context)
 
     def draw(self, context):
         layout = self.layout
@@ -179,6 +397,7 @@ class MUV_MT_CopyPasteUV_CopyUV(bpy.types.Menu):
 
 
 @BlClassRegistry()
+@compat.make_annotations
 class MUV_OT_CopyPasteUV_PasteUV(bpy.types.Operator):
     """
     Operation class: Paste UV coordinate
@@ -189,8 +408,8 @@ class MUV_OT_CopyPasteUV_PasteUV(bpy.types.Operator):
     bl_description = "Paste UV coordinate"
     bl_options = {'REGISTER', 'UNDO'}
 
-    uv_map: StringProperty(default="__default", options={'HIDDEN'})
-    strategy: EnumProperty(
+    uv_map = StringProperty(default="__default", options={'HIDDEN'})
+    strategy = EnumProperty(
         name="Strategy",
         description="Paste Strategy",
         items=[
@@ -199,18 +418,18 @@ class MUV_OT_CopyPasteUV_PasteUV(bpy.types.Operator):
         ],
         default="N_M"
     )
-    flip_copied_uv: BoolProperty(
+    flip_copied_uv = BoolProperty(
         name="Flip Copied UV",
         description="Flip Copied UV...",
         default=False
     )
-    rotate_copied_uv: IntProperty(
+    rotate_copied_uv = IntProperty(
         default=0,
         name="Rotate Copied UV",
         min=0,
         max=30
     )
-    copy_seams: BoolProperty(
+    copy_seams = BoolProperty(
         name="Seams",
         description="Copy Seams",
         default=True
@@ -225,7 +444,7 @@ class MUV_OT_CopyPasteUV_PasteUV(bpy.types.Operator):
         props = sc.muv_props.copy_paste_uv
         if not props.src_info:
             return False
-        return impl.is_valid_context(context)
+        return _is_valid_context(context)
 
     def execute(self, context):
         props = context.scene.muv_props.copy_paste_uv
@@ -236,21 +455,21 @@ class MUV_OT_CopyPasteUV_PasteUV(bpy.types.Operator):
         bm = common.create_bmesh(obj)
 
         # get UV layer
-        uv_layers = impl.get_paste_uv_layers(self, obj, bm, props.src_info,
-                                             self.uv_map)
+        uv_layers = get_paste_uv_layers(self, obj, bm, props.src_info,
+                                        self.uv_map)
         if not uv_layers:
             return {'CANCELLED'}
 
         # get selected face
-        dest_info = impl.get_dest_face_info(self, bm, uv_layers,
-                                            props.src_info, self.strategy)
+        dest_info = get_dest_face_info(self, bm, uv_layers,
+                                       props.src_info, self.strategy, True)
         if dest_info is None:
             return {'CANCELLED'}
 
         # paste
-        ret = impl.paste_uv(self, bm, props.src_info, dest_info, uv_layers,
-                            self.strategy, self.flip_copied_uv,
-                            self.rotate_copied_uv, self.copy_seams)
+        ret = paste_uv(self, bm, props.src_info, dest_info, uv_layers,
+                       self.strategy, self.flip_copied_uv,
+                       self.rotate_copied_uv, self.copy_seams)
         if ret:
             return {'CANCELLED'}
 
@@ -259,6 +478,10 @@ class MUV_OT_CopyPasteUV_PasteUV(bpy.types.Operator):
 
         bmesh.update_edit_mesh(obj.data)
 
+        if compat.check_version(2, 80, 0) < 0:
+            if self.copy_seams is True:
+                obj.data.show_edge_seams = True
+
         return {'FINISHED'}
 
 
@@ -278,7 +501,7 @@ class MUV_MT_CopyPasteUV_PasteUV(bpy.types.Menu):
         props = sc.muv_props.copy_paste_uv
         if not props.src_info:
             return False
-        return impl.is_valid_context(context)
+        return _is_valid_context(context)
 
     def draw(self, context):
         sc = context.scene
@@ -314,6 +537,7 @@ class MUV_MT_CopyPasteUV_PasteUV(bpy.types.Menu):
 
 
 @BlClassRegistry()
+@compat.make_annotations
 class MUV_OT_CopyPasteUV_SelSeqCopyUV(bpy.types.Operator):
     """
     Operation class: Copy UV coordinate by selection sequence
@@ -324,14 +548,14 @@ class MUV_OT_CopyPasteUV_SelSeqCopyUV(bpy.types.Operator):
     bl_description = "Copy UV data by selection sequence"
     bl_options = {'REGISTER', 'UNDO'}
 
-    uv_map: StringProperty(default="__default", options={'HIDDEN'})
+    uv_map = StringProperty(default="__default", options={'HIDDEN'})
 
     @classmethod
     def poll(cls, context):
         # we can not get area/space/region from console
         if common.is_console_mode():
             return True
-        return impl.is_valid_context(context)
+        return _is_valid_context(context)
 
     def execute(self, context):
         props = context.scene.muv_props.copy_paste_uv_selseq
@@ -339,12 +563,12 @@ class MUV_OT_CopyPasteUV_SelSeqCopyUV(bpy.types.Operator):
         bm = common.create_bmesh(obj)
 
         # get UV layer
-        uv_layers = impl.get_copy_uv_layers(self, bm, self.uv_map)
+        uv_layers = get_copy_uv_layers(self, bm, self.uv_map)
         if not uv_layers:
             return {'CANCELLED'}
 
         # get selected face
-        src_info = impl.get_select_history_src_face_info(self, bm, uv_layers)
+        src_info = _get_select_history_src_face_info(self, bm, uv_layers)
         if src_info is None:
             return {'CANCELLED'}
         props.src_info = src_info
@@ -367,7 +591,7 @@ class MUV_MT_CopyPasteUV_SelSeqCopyUV(bpy.types.Menu):
 
     @classmethod
     def poll(cls, context):
-        return impl.is_valid_context(context)
+        return _is_valid_context(context)
 
     def draw(self, context):
         layout = self.layout
@@ -390,6 +614,7 @@ class MUV_MT_CopyPasteUV_SelSeqCopyUV(bpy.types.Menu):
 
 
 @BlClassRegistry()
+@compat.make_annotations
 class MUV_OT_CopyPasteUV_SelSeqPasteUV(bpy.types.Operator):
     """
     Operation class: Paste UV coordinate by selection sequence
@@ -400,8 +625,8 @@ class MUV_OT_CopyPasteUV_SelSeqPasteUV(bpy.types.Operator):
     bl_description = "Paste UV coordinate by selection sequence"
     bl_options = {'REGISTER', 'UNDO'}
 
-    uv_map: StringProperty(default="__default", options={'HIDDEN'})
-    strategy: EnumProperty(
+    uv_map = StringProperty(default="__default", options={'HIDDEN'})
+    strategy = EnumProperty(
         name="Strategy",
         description="Paste Strategy",
         items=[
@@ -410,18 +635,18 @@ class MUV_OT_CopyPasteUV_SelSeqPasteUV(bpy.types.Operator):
         ],
         default="N_M"
     )
-    flip_copied_uv: BoolProperty(
+    flip_copied_uv = BoolProperty(
         name="Flip Copied UV",
         description="Flip Copied UV...",
         default=False
     )
-    rotate_copied_uv: IntProperty(
+    rotate_copied_uv = IntProperty(
         default=0,
         name="Rotate Copied UV",
         min=0,
         max=30
     )
-    copy_seams: BoolProperty(
+    copy_seams = BoolProperty(
         name="Seams",
         description="Copy Seams",
         default=True
@@ -436,7 +661,7 @@ class MUV_OT_CopyPasteUV_SelSeqPasteUV(bpy.types.Operator):
         props = sc.muv_props.copy_paste_uv_selseq
         if not props.src_info:
             return False
-        return impl.is_valid_context(context)
+        return _is_valid_context(context)
 
     def execute(self, context):
         props = context.scene.muv_props.copy_paste_uv_selseq
@@ -447,22 +672,22 @@ class MUV_OT_CopyPasteUV_SelSeqPasteUV(bpy.types.Operator):
         bm = common.create_bmesh(obj)
 
         # get UV layer
-        uv_layers = impl.get_paste_uv_layers(self, obj, bm, props.src_info,
-                                             self.uv_map)
+        uv_layers = get_paste_uv_layers(self, obj, bm, props.src_info,
+                                        self.uv_map)
         if not uv_layers:
             return {'CANCELLED'}
 
         # get selected face
-        dest_info = impl.get_select_history_dest_face_info(self, bm, uv_layers,
-                                                           props.src_info,
-                                                           self.strategy)
+        dest_info = _get_select_history_dest_face_info(self, bm, uv_layers,
+                                                       props.src_info,
+                                                       self.strategy)
         if dest_info is None:
             return {'CANCELLED'}
 
         # paste
-        ret = impl.paste_uv(self, bm, props.src_info, dest_info, uv_layers,
-                            self.strategy, self.flip_copied_uv,
-                            self.rotate_copied_uv, self.copy_seams)
+        ret = paste_uv(self, bm, props.src_info, dest_info, uv_layers,
+                       self.strategy, self.flip_copied_uv,
+                       self.rotate_copied_uv, self.copy_seams)
         if ret:
             return {'CANCELLED'}
 
@@ -471,6 +696,10 @@ class MUV_OT_CopyPasteUV_SelSeqPasteUV(bpy.types.Operator):
 
         bmesh.update_edit_mesh(obj.data)
 
+        if compat.check_version(2, 80, 0) < 0:
+            if self.copy_seams is True:
+                obj.data.show_edge_seams = True
+
         return {'FINISHED'}
 
 
@@ -490,7 +719,7 @@ class MUV_MT_CopyPasteUV_SelSeqPasteUV(bpy.types.Menu):
         props = sc.muv_props.copy_paste_uv_selseq
         if not props.src_uvs or not props.src_pin_uvs:
             return False
-        return impl.is_valid_context(context)
+        return _is_valid_context(context)
 
     def draw(self, context):
         sc = context.scene
diff --git a/uv_magic_uv/op/copy_paste_uv_object.py b/uv_magic_uv/op/copy_paste_uv_object.py
index d9f42447a538735b5d8c0515cb729e8f249ea14a..dc7073b81572d77781f750c5a2cd6639b451e396 100644
--- a/uv_magic_uv/op/copy_paste_uv_object.py
+++ b/uv_magic_uv/op/copy_paste_uv_object.py
@@ -30,21 +30,20 @@ from bpy.props import (
     BoolProperty,
 )
 
-from ..impl import copy_paste_uv_impl as impl
+from .copy_paste_uv import (
+    get_copy_uv_layers,
+    get_src_face_info,
+    get_paste_uv_layers,
+    get_dest_face_info,
+    paste_uv,
+)
 from .. import common
 from ..utils.bl_class_registry import BlClassRegistry
 from ..utils.property_class_registry import PropertyClassRegistry
-
-__all__ = [
-    'Properties',
-    'MUV_OT_CopyPasteUVObject_CopyUV',
-    'MUV_MT_CopyPasteUVObject_CopyUV',
-    'MUV_OT_CopyPasteUVObject_PasteUV',
-    'MUV_MT_CopyPasteUVObject_PasteUV',
-]
+from ..utils import compatibility as compat
 
 
-def is_valid_context(context):
+def _is_valid_context(context):
     obj = context.object
 
     # only object mode is allowed to execute
@@ -66,7 +65,7 @@ def is_valid_context(context):
 
 
 @PropertyClassRegistry()
-class Properties:
+class _Properties:
     idname = "copy_paste_uv_object"
 
     @classmethod
@@ -98,6 +97,7 @@ def memorize_view_3d_mode(fn):
 
 
 @BlClassRegistry()
+@compat.make_annotations
 class MUV_OT_CopyPasteUVObject_CopyUV(bpy.types.Operator):
     """
     Operation class: Copy UV coordinate among objects
@@ -108,14 +108,14 @@ class MUV_OT_CopyPasteUVObject_CopyUV(bpy.types.Operator):
     bl_description = "Copy UV coordinate (Among Objects)"
     bl_options = {'REGISTER', 'UNDO'}
 
-    uv_map: StringProperty(default="__default", options={'HIDDEN'})
+    uv_map = StringProperty(default="__default", options={'HIDDEN'})
 
     @classmethod
     def poll(cls, context):
         # we can not get area/space/region from console
         if common.is_console_mode():
             return True
-        return is_valid_context(context)
+        return _is_valid_context(context)
 
     @memorize_view_3d_mode
     def execute(self, context):
@@ -125,12 +125,12 @@ class MUV_OT_CopyPasteUVObject_CopyUV(bpy.types.Operator):
         bm = common.create_bmesh(obj)
 
         # get UV layer
-        uv_layers = impl.get_copy_uv_layers(self, bm, self.uv_map)
+        uv_layers = get_copy_uv_layers(self, bm, self.uv_map)
         if not uv_layers:
             return {'CANCELLED'}
 
         # get selected face
-        src_info = impl.get_src_face_info(self, bm, uv_layers)
+        src_info = get_src_face_info(self, bm, uv_layers)
         if src_info is None:
             return {'CANCELLED'}
         props.src_info = src_info
@@ -153,12 +153,12 @@ class MUV_MT_CopyPasteUVObject_CopyUV(bpy.types.Menu):
 
     @classmethod
     def poll(cls, context):
-        return is_valid_context(context)
+        return _is_valid_context(context)
 
     def draw(self, _):
         layout = self.layout
         # create sub menu
-        uv_maps = bpy.context.active_object.data.uv_layers.keys()
+        uv_maps = compat.get_object_uv_layers(bpy.context.active_object).keys()
 
         ops = layout.operator(MUV_OT_CopyPasteUVObject_CopyUV.bl_idname,
                               text="[Default]")
@@ -175,6 +175,7 @@ class MUV_MT_CopyPasteUVObject_CopyUV(bpy.types.Menu):
 
 
 @BlClassRegistry()
+@compat.make_annotations
 class MUV_OT_CopyPasteUVObject_PasteUV(bpy.types.Operator):
     """
     Operation class: Paste UV coordinate among objects
@@ -185,8 +186,8 @@ class MUV_OT_CopyPasteUVObject_PasteUV(bpy.types.Operator):
     bl_description = "Paste UV coordinate (Among Objects)"
     bl_options = {'REGISTER', 'UNDO'}
 
-    uv_map: StringProperty(default="__default", options={'HIDDEN'})
-    copy_seams: BoolProperty(
+    uv_map = StringProperty(default="__default", options={'HIDDEN'})
+    copy_seams = BoolProperty(
         name="Seams",
         description="Copy Seams",
         default=True
@@ -201,7 +202,7 @@ class MUV_OT_CopyPasteUVObject_PasteUV(bpy.types.Operator):
         props = sc.muv_props.copy_paste_uv_object
         if not props.src_info:
             return False
-        return is_valid_context(context)
+        return _is_valid_context(context)
 
     @memorize_view_3d_mode
     def execute(self, context):
@@ -211,36 +212,40 @@ class MUV_OT_CopyPasteUVObject_PasteUV(bpy.types.Operator):
             return {'CANCELLED'}
 
         for o in bpy.data.objects:
-            if not hasattr(o.data, "uv_layers") or not o.select_get():
+            if not compat.object_has_uv_layers(o) or not compat.get_object_select(o):
                 continue
 
             bpy.ops.object.mode_set(mode='OBJECT')
-            bpy.context.view_layer.objects.active = o
+            compat.set_active_object(o)
             bpy.ops.object.mode_set(mode='EDIT')
 
             obj = context.active_object
             bm = common.create_bmesh(obj)
 
             # get UV layer
-            uv_layers = impl.get_paste_uv_layers(self, obj, bm, props.src_info,
-                                                 self.uv_map)
+            uv_layers = get_paste_uv_layers(self, obj, bm, props.src_info,
+                                            self.uv_map)
             if not uv_layers:
                 return {'CANCELLED'}
 
             # get selected face
-            dest_info = impl.get_dest_face_info(self, bm, uv_layers,
-                                                props.src_info, 'N_N')
+            dest_info = get_dest_face_info(self, bm, uv_layers,
+                                           props.src_info, 'N_N')
             if dest_info is None:
                 return {'CANCELLED'}
 
             # paste
-            ret = impl.paste_uv(self, bm, props.src_info, dest_info, uv_layers,
-                                'N_N', 0, 0, self.copy_seams)
+            ret = paste_uv(self, bm, props.src_info, dest_info, uv_layers,
+                           'N_N', 0, 0, self.copy_seams)
             if ret:
                 return {'CANCELLED'}
 
             bmesh.update_edit_mesh(obj.data)
 
+            if compat.check_version(2, 80, 0) < 0:
+                if self.copy_seams is True:
+                    obj.data.show_edge_seams = True
+
             self.report(
                 {'INFO'}, "{}'s UV coordinates are pasted".format(obj.name))
 
@@ -263,7 +268,7 @@ class MUV_MT_CopyPasteUVObject_PasteUV(bpy.types.Menu):
         props = sc.muv_props.copy_paste_uv_object
         if not props.src_info:
             return False
-        return is_valid_context(context)
+        return _is_valid_context(context)
 
     def draw(self, context):
         sc = context.scene
@@ -271,8 +276,8 @@ class MUV_MT_CopyPasteUVObject_PasteUV(bpy.types.Menu):
         # create sub menu
         uv_maps = []
         for obj in bpy.data.objects:
-            if hasattr(obj.data, "uv_layers") and obj.select_get():
-                uv_maps.extend(obj.data.uv_layers.keys())
+            if compat.object_has_uv_layers(obj) and compat.get_object_select(obj):
+                uv_maps.extend(compat.get_object_uv_layers(obj).keys())
 
         ops = layout.operator(MUV_OT_CopyPasteUVObject_PasteUV.bl_idname,
                               text="[Default]")
diff --git a/uv_magic_uv/op/copy_paste_uv_uvedit.py b/uv_magic_uv/op/copy_paste_uv_uvedit.py
index 719687a6016e510212c10ac05f2c9fa8994bda7d..16c0dfa5da36e38768a69d6d78c119a4811facdd 100644
--- a/uv_magic_uv/op/copy_paste_uv_uvedit.py
+++ b/uv_magic_uv/op/copy_paste_uv_uvedit.py
@@ -24,21 +24,43 @@ __version__ = "5.2"
 __date__ = "17 Nov 2018"
 
 import bpy
+import math
+from math import atan2, sin, cos
+
+import bmesh
+from mathutils import Vector
+
+from .. import common
 
 from ..utils.bl_class_registry import BlClassRegistry
 from ..utils.property_class_registry import PropertyClassRegistry
-from ..impl import copy_paste_uv_uvedit_impl as impl
 
 
-__all__ = [
-    'Properties',
-    'MUV_OT_CopyPasteUVUVEdit_CopyUV',
-    'MUV_OT_CopyPasteUVUVEdit_PasteUV',
-]
+def _is_valid_context(context):
+    obj = context.object
+
+    # only edit mode is allowed to execute
+    if obj is None:
+        return False
+    if obj.type != 'MESH':
+        return False
+    if context.object.mode != 'EDIT':
+        return False
+
+    # 'IMAGE_EDITOR' and 'VIEW_3D' space is allowed to execute.
+    # If 'View_3D' space is not allowed, you can't find option in Tool-Shelf
+    # after the execution
+    for space in context.area.spaces:
+        if (space.type == 'IMAGE_EDITOR') or (space.type == 'VIEW_3D'):
+            break
+    else:
+        return False
+
+    return True
 
 
 @PropertyClassRegistry()
-class Properties:
+class _Properties:
     idname = "copy_paste_uv_uvedit"
 
     @classmethod
@@ -64,15 +86,35 @@ class MUV_OT_CopyPasteUVUVEdit_CopyUV(bpy.types.Operator):
     bl_description = "Copy UV coordinate (only selected in UV/Image Editor)"
     bl_options = {'REGISTER', 'UNDO'}
 
-    def __init__(self):
-        self.__impl = impl.CopyUVImpl()
-
     @classmethod
     def poll(cls, context):
-        return impl.CopyUVImpl.poll(context)
+        # we can not get area/space/region from console
+        if common.is_console_mode():
+            return True
+        return _is_valid_context(context)
 
     def execute(self, context):
-        return self.__impl.execute(self, context)
+        props = context.scene.muv_props.copy_paste_uv_uvedit
+        obj = context.active_object
+        bm = bmesh.from_edit_mesh(obj.data)
+        uv_layer = bm.loops.layers.uv.verify()
+        if common.check_version(2, 73, 0) >= 0:
+            bm.faces.ensure_lookup_table()
+
+        props.src_uvs = []
+        for face in bm.faces:
+            if not face.select:
+                continue
+            skip = False
+            for l in face.loops:
+                if not l[uv_layer].select:
+                    skip = True
+                    break
+            if skip:
+                continue
+            props.src_uvs.append([l[uv_layer].uv.copy() for l in face.loops])
+
+        return {'FINISHED'}
 
 
 @BlClassRegistry()
@@ -86,12 +128,72 @@ class MUV_OT_CopyPasteUVUVEdit_PasteUV(bpy.types.Operator):
     bl_description = "Paste UV coordinate (only selected in UV/Image Editor)"
     bl_options = {'REGISTER', 'UNDO'}
 
-    def __init__(self):
-        self.__impl = impl.PasteUVImpl()
-
     @classmethod
     def poll(cls, context):
-        return impl.PasteUVImpl.poll(context)
+        # we can not get area/space/region from console
+        if common.is_console_mode():
+            return True
+        sc = context.scene
+        props = sc.muv_props.copy_paste_uv_uvedit
+        if not props.src_uvs:
+            return False
+        return _is_valid_context(context)
 
     def execute(self, context):
-        return self.__impl.execute(self, context)
+        props = context.scene.muv_props.copy_paste_uv_uvedit
+        obj = context.active_object
+        bm = bmesh.from_edit_mesh(obj.data)
+        uv_layer = bm.loops.layers.uv.verify()
+        if common.check_version(2, 73, 0) >= 0:
+            bm.faces.ensure_lookup_table()
+
+        dest_uvs = []
+        dest_face_indices = []
+        for face in bm.faces:
+            if not face.select:
+                continue
+            skip = False
+            for l in face.loops:
+                if not l[uv_layer].select:
+                    skip = True
+                    break
+            if skip:
+                continue
+            dest_face_indices.append(face.index)
+            uvs = [l[uv_layer].uv.copy() for l in face.loops]
+            dest_uvs.append(uvs)
+
+        for suvs, duvs in zip(props.src_uvs, dest_uvs):
+            src_diff = suvs[1] - suvs[0]
+            dest_diff = duvs[1] - duvs[0]
+
+            src_base = suvs[0]
+            dest_base = duvs[0]
+
+            src_rad = atan2(src_diff.y, src_diff.x)
+            dest_rad = atan2(dest_diff.y, dest_diff.x)
+            if src_rad < dest_rad:
+                radian = dest_rad - src_rad
+            elif src_rad > dest_rad:
+                radian = math.pi * 2 - (src_rad - dest_rad)
+            else:       # src_rad == dest_rad
+                radian = 0.0
+
+            ratio = dest_diff.length / src_diff.length
+            break
+
+        for suvs, fidx in zip(props.src_uvs, dest_face_indices):
+            for l, suv in zip(bm.faces[fidx].loops, suvs):
+                base = suv - src_base
+                radian_ref = atan2(base.y, base.x)
+                radian_fin = (radian + radian_ref)
+                length = base.length
+                turn = Vector((length * cos(radian_fin),
+                               length * sin(radian_fin)))
+                target_uv = Vector((turn.x * ratio, turn.y * ratio)) + \
+                    dest_base
+                l[uv_layer].uv = target_uv
+
+        bmesh.update_edit_mesh(obj.data)
+
+        return {'FINISHED'}
diff --git a/uv_magic_uv/op/flip_rotate_uv.py b/uv_magic_uv/op/flip_rotate_uv.py
index d16370528b1927d9df1fadf5bd713253036dd1a4..2ecab25415ec8e85f4bfc53e57b324574e10421a 100644
--- a/uv_magic_uv/op/flip_rotate_uv.py
+++ b/uv_magic_uv/op/flip_rotate_uv.py
@@ -33,16 +33,113 @@ from bpy.props import (
 from .. import common
 from ..utils.bl_class_registry import BlClassRegistry
 from ..utils.property_class_registry import PropertyClassRegistry
-from ..impl import flip_rotate_impl as impl
-
-__all__ = [
-    'Properties',
-    'MUV_OT_FlipRotate',
-]
+from ..utils import compatibility as compat
+
+
+def _is_valid_context(context):
+    obj = context.object
+
+    # only edit mode is allowed to execute
+    if obj is None:
+        return False
+    if obj.type != 'MESH':
+        return False
+    if context.object.mode != 'EDIT':
+        return False
+
+    # only 'VIEW_3D' space is allowed to execute
+    for space in context.area.spaces:
+        if space.type == 'VIEW_3D':
+            break
+    else:
+        return False
+
+    return True
+
+
+def _get_uv_layer(ops_obj, bm):
+    # get UV layer
+    if not bm.loops.layers.uv:
+        ops_obj.report({'WARNING'}, "Object must have more than one UV map")
+        return None
+    uv_layer = bm.loops.layers.uv.verify()
+
+    return uv_layer
+
+
+def _get_src_face_info(ops_obj, bm, uv_layers, only_select=False):
+    src_info = {}
+    for layer in uv_layers:
+        face_info = []
+        for face in bm.faces:
+            if not only_select or face.select:
+                info = {
+                    "index": face.index,
+                    "uvs": [l[layer].uv.copy() for l in face.loops],
+                    "pin_uvs": [l[layer].pin_uv for l in face.loops],
+                    "seams": [l.edge.seam for l in face.loops],
+                }
+                face_info.append(info)
+        if not face_info:
+            ops_obj.report({'WARNING'}, "No faces are selected")
+            return None
+        src_info[layer.name] = face_info
+
+    return src_info
+
+
+def _paste_uv(ops_obj, bm, src_info, dest_info, uv_layers, strategy, flip,
+              rotate, copy_seams):
+    for slayer_name, dlayer in zip(src_info.keys(), uv_layers):
+        src_faces = src_info[slayer_name]
+        dest_faces = dest_info[dlayer.name]
+
+        for idx, dinfo in enumerate(dest_faces):
+            sinfo = None
+            if strategy == 'N_N':
+                sinfo = src_faces[idx]
+            elif strategy == 'N_M':
+                sinfo = src_faces[idx % len(src_faces)]
+
+            suv = sinfo["uvs"]
+            spuv = sinfo["pin_uvs"]
+            ss = sinfo["seams"]
+            if len(sinfo["uvs"]) != len(dinfo["uvs"]):
+                ops_obj.report({'WARNING'}, "Some faces are different size")
+                return -1
+
+            suvs_fr = [uv for uv in suv]
+            spuvs_fr = [pin_uv for pin_uv in spuv]
+            ss_fr = [s for s in ss]
+
+            # flip UVs
+            if flip is True:
+                suvs_fr.reverse()
+                spuvs_fr.reverse()
+                ss_fr.reverse()
+
+            # rotate UVs
+            for _ in range(rotate):
+                uv = suvs_fr.pop()
+                pin_uv = spuvs_fr.pop()
+                s = ss_fr.pop()
+                suvs_fr.insert(0, uv)
+                spuvs_fr.insert(0, pin_uv)
+                ss_fr.insert(0, s)
+
+            # paste UVs
+            for l, suv, spuv, ss in zip(bm.faces[dinfo["index"]].loops,
+                                        suvs_fr, spuvs_fr, ss_fr):
+                l[dlayer].uv = suv
+                l[dlayer].pin_uv = spuv
+                if copy_seams is True:
+                    l.edge.seam = ss
+
+    return 0
 
 
 @PropertyClassRegistry()
-class Properties:
+class _Properties:
     idname = "flip_rotate_uv"
 
     @classmethod
@@ -65,6 +162,7 @@ class Properties:
 
 
 @BlClassRegistry()
+@compat.make_annotations
 class MUV_OT_FlipRotate(bpy.types.Operator):
     """
     Operation class: Flip and Rotate UV coordinate
@@ -75,18 +173,18 @@ class MUV_OT_FlipRotate(bpy.types.Operator):
     bl_description = "Flip/Rotate UV coordinate"
     bl_options = {'REGISTER', 'UNDO'}
 
-    flip: BoolProperty(
+    flip = BoolProperty(
         name="Flip UV",
         description="Flip UV...",
         default=False
     )
-    rotate: IntProperty(
+    rotate = IntProperty(
         default=0,
         name="Rotate UV",
         min=0,
         max=30
     )
-    seams: BoolProperty(
+    seams = BoolProperty(
         name="Seams",
         description="Seams",
         default=True
@@ -97,7 +195,7 @@ class MUV_OT_FlipRotate(bpy.types.Operator):
         # we can not get area/space/region from console
         if common.is_console_mode():
             return True
-        return impl.is_valid_context(context)
+        return _is_valid_context(context)
 
     def execute(self, context):
         self.report({'INFO'}, "Flip/Rotate UV")
@@ -107,12 +205,12 @@ class MUV_OT_FlipRotate(bpy.types.Operator):
             bm.faces.ensure_lookup_table()
 
         # get UV layer
-        uv_layer = impl.get_uv_layer(self, bm)
+        uv_layer = _get_uv_layer(self, bm)
         if not uv_layer:
             return {'CANCELLED'}
 
         # get selected face
-        src_info = impl.get_src_face_info(self, bm, [uv_layer], True)
+        src_info = _get_src_face_info(self, bm, [uv_layer], True)
         if not src_info:
             return {'CANCELLED'}
 
@@ -120,11 +218,15 @@ class MUV_OT_FlipRotate(bpy.types.Operator):
         self.report({'INFO'}, "{} face(s) are selected".format(face_count))
 
         # paste
-        ret = impl.paste_uv(self, bm, src_info, src_info, [uv_layer], 'N_N',
-                            self.flip, self.rotate, self.seams)
+        ret = _paste_uv(self, bm, src_info, src_info, [uv_layer], 'N_N',
+                        self.flip, self.rotate, self.seams)
         if ret:
             return {'CANCELLED'}
 
         bmesh.update_edit_mesh(obj.data)
 
+        if compat.check_version(2, 80, 0) < 0:
+            if self.seams is True:
+                obj.data.show_edge_seams = True
+
         return {'FINISHED'}
diff --git a/uv_magic_uv/op/mirror_uv.py b/uv_magic_uv/op/mirror_uv.py
index 6793ca232e2bdcafbb4a95c02dbc1edc0cd3bbbb..b806daea5daec2a49d52cb500fe869f827a51eef 100644
--- a/uv_magic_uv/op/mirror_uv.py
+++ b/uv_magic_uv/op/mirror_uv.py
@@ -29,20 +29,80 @@ from bpy.props import (
     FloatProperty,
     BoolProperty,
 )
+import bmesh
+from mathutils import Vector
 
 from ..utils.bl_class_registry import BlClassRegistry
 from ..utils.property_class_registry import PropertyClassRegistry
-from ..impl import mirror_uv_impl as impl
+from ..utils import compatibility as compat
+from .. import common
 
 
-__all__ = [
-    'Properties',
-    'MUV_OT_MirrorUV',
-]
+def is_valid_context(context):
+    obj = context.object
+
+    # only edit mode is allowed to execute
+    if obj is None:
+        return False
+    if obj.type != 'MESH':
+        return False
+    if context.object.mode != 'EDIT':
+        return False
+
+    # only 'VIEW_3D' space is allowed to execute
+    for space in context.area.spaces:
+        if space.type == 'VIEW_3D':
+            break
+    else:
+        return False
+
+    return True
+
+
+def is_vector_similar(v1, v2, error):
+    """
+    Check if two vectors are similar, within an error threshold
+    """
+    within_err_x = abs(v2.x - v1.x) < error
+    within_err_y = abs(v2.y - v1.y) < error
+    within_err_z = abs(v2.z - v1.z) < error
+
+    return within_err_x and within_err_y and within_err_z
+
+
+def mirror_uvs(uv_layer, src, dst, axis, error):
+    """
+    Copy UV coordinates from one UV face to another
+    """
+    for sl in src.loops:
+        suv = sl[uv_layer].uv.copy()
+        svco = sl.vert.co.copy()
+        for dl in dst.loops:
+            dvco = dl.vert.co.copy()
+            if axis == 'X':
+                dvco.x = -dvco.x
+            elif axis == 'Y':
+                dvco.y = -dvco.y
+            elif axis == 'Z':
+                dvco.z = -dvco.z
+
+            if is_vector_similar(svco, dvco, error):
+                dl[uv_layer].uv = suv.copy()
+
+
+def get_face_center(face):
+    """
+    Get center coordinate of the face
+    """
+    center = Vector((0.0, 0.0, 0.0))
+    for v in face.verts:
+        center = center + v.co
+
+    return center / len(face.verts)
 
 
 @PropertyClassRegistry()
-class Properties:
+class _Properties:
     idname = "mirror_uv"
 
     @classmethod
@@ -70,6 +130,7 @@ class Properties:
 
 
 @BlClassRegistry()
+@compat.make_annotations
 class MUV_OT_MirrorUV(bpy.types.Operator):
     """
     Operation class: Mirror UV
@@ -79,7 +140,7 @@ class MUV_OT_MirrorUV(bpy.types.Operator):
     bl_label = "Mirror UV"
     bl_options = {'REGISTER', 'UNDO'}
 
-    axis: EnumProperty(
+    axis = EnumProperty(
         items=(
             ('X', "X", "Mirror Along X axis"),
             ('Y', "Y", "Mirror Along Y axis"),
@@ -89,7 +150,7 @@ class MUV_OT_MirrorUV(bpy.types.Operator):
         description="Mirror Axis",
         default='X'
     )
-    error: FloatProperty(
+    error = FloatProperty(
         name="Error",
         description="Error threshold",
         default=0.001,
@@ -99,12 +160,56 @@ class MUV_OT_MirrorUV(bpy.types.Operator):
         soft_max=1.0
     )
 
-    def __init__(self):
-        self.__impl = impl.MirrorUVImpl()
-
     @classmethod
     def poll(cls, context):
-        return impl.MirrorUVImpl.poll(context)
+        # we can not get area/space/region from console
+        if common.is_console_mode():
+            return True
+        return is_valid_context(context)
 
     def execute(self, context):
-        return self.__impl.execute(self, context)
+        obj = context.active_object
+        bm = bmesh.from_edit_mesh(obj.data)
+
+        error = self.error
+        axis = self.axis
+
+        if common.check_version(2, 73, 0) >= 0:
+            bm.faces.ensure_lookup_table()
+        if not bm.loops.layers.uv:
+            self.report({'WARNING'},
+                        "Object must have more than one UV map")
+            return {'CANCELLED'}
+        uv_layer = bm.loops.layers.uv.verify()
+
+        faces = [f for f in bm.faces if f.select]
+        for f_dst in faces:
+            count = len(f_dst.verts)
+            for f_src in bm.faces:
+                # check if this is a candidate to do mirror UV
+                if f_src.index == f_dst.index:
+                    continue
+                if count != len(f_src.verts):
+                    continue
+
+                # test if the vertices x values are the same sign
+                dst = get_face_center(f_dst)
+                src = get_face_center(f_src)
+                if (dst.x > 0 and src.x > 0) or (dst.x < 0 and src.x < 0):
+                    continue
+
+                # invert source axis
+                if axis == 'X':
+                    src.x = -src.x
+                elif axis == 'Y':
+                    src.y = -src.z
+                elif axis == 'Z':
+                    src.z = -src.z
+
+                # do mirror UV
+                if is_vector_similar(dst, src, error):
+                    mirror_uvs(uv_layer, f_src, f_dst, self.axis, self.error)
+
+        bmesh.update_edit_mesh(obj.data)
+
+        return {'FINISHED'}
diff --git a/uv_magic_uv/op/move_uv.py b/uv_magic_uv/op/move_uv.py
index 653918d350e20c1f82e3f7b110efe73e7900dd10..b747892ae4300d81e2dfc2b21030bd35fb79f9bf 100644
--- a/uv_magic_uv/op/move_uv.py
+++ b/uv_magic_uv/op/move_uv.py
@@ -25,20 +25,51 @@ __date__ = "17 Nov 2018"
 
 import bpy
 from bpy.props import BoolProperty
+import bmesh
+from mathutils import Vector
 
-from ..impl import move_uv_impl as impl
+from .. import common
 from ..utils.bl_class_registry import BlClassRegistry
 from ..utils.property_class_registry import PropertyClassRegistry
 
 
-__all__ = [
-    'Properties',
-    'MUV_OT_MoveUV',
-]
+def _is_valid_context(context):
+    obj = context.object
+
+    # only edit mode is allowed to execute
+    if obj is None:
+        return False
+    if obj.type != 'MESH':
+        return False
+    if context.object.mode != 'EDIT':
+        return False
+
+    # only 'VIEW_3D' space is allowed to execute
+    for space in context.area.spaces:
+        if space.type == 'VIEW_3D':
+            break
+    else:
+        return False
+
+    return True
+
+
+def _find_uv(context):
+    bm = bmesh.from_edit_mesh(context.object.data)
+    topology_dict = []
+    uvs = []
+    active_uv = bm.loops.layers.uv.active
+    for fidx, f in enumerate(bm.faces):
+        for vidx, v in enumerate(f.verts):
+            if v.select:
+                uvs.append(f.loops[vidx][active_uv].uv.copy())
+                topology_dict.append([fidx, vidx])
+
+    return topology_dict, uvs
 
 
 @PropertyClassRegistry()
-class Properties:
+class _Properties:
     idname = "move_uv"
 
     @classmethod
@@ -64,19 +95,91 @@ class MUV_OT_MoveUV(bpy.types.Operator):
     bl_label = "Move UV"
     bl_options = {'REGISTER', 'UNDO'}
 
+    __running = False
+
     def __init__(self):
-        self.__impl = impl.MoveUVImpl()
+        self.__topology_dict = []
+        self.__prev_mouse = Vector((0.0, 0.0))
+        self.__offset_uv = Vector((0.0, 0.0))
+        self.__prev_offset_uv = Vector((0.0, 0.0))
+        self.__first_time = True
+        self.__ini_uvs = []
+        self.__operating = False
 
     @classmethod
     def poll(cls, context):
-        return impl.MoveUVImpl.poll(context)
+        # we can not get area/space/region from console
+        if common.is_console_mode():
+            return False
+        if cls.is_running(context):
+            return False
+        return _is_valid_context(context)
 
     @classmethod
     def is_running(cls, _):
-        return impl.MoveUVImpl.is_running(_)
+        return cls.__running
 
     def modal(self, context, event):
-        return self.__impl.modal(self, context, event)
+        if self.__first_time is True:
+            self.__prev_mouse = Vector((
+                event.mouse_region_x, event.mouse_region_y))
+            self.__first_time = False
+            return {'RUNNING_MODAL'}
+
+        # move UV
+        div = 10000
+        self.__offset_uv += Vector((
+            (event.mouse_region_x - self.__prev_mouse.x) / div,
+            (event.mouse_region_y - self.__prev_mouse.y) / div))
+        ouv = self.__offset_uv
+        pouv = self.__prev_offset_uv
+        vec = Vector((ouv.x - ouv.y, ouv.x + ouv.y))
+        dv = vec - pouv
+        self.__prev_offset_uv = vec
+        self.__prev_mouse = Vector((
+            event.mouse_region_x, event.mouse_region_y))
+
+        # check if operation is started
+        if not self.__operating:
+            if event.type == 'LEFTMOUSE' and event.value == 'RELEASE':
+                self.__operating = True
+            return {'RUNNING_MODAL'}
+
+        # update UV
+        obj = context.object
+        bm = bmesh.from_edit_mesh(obj.data)
+        active_uv = bm.loops.layers.uv.active
+        for fidx, vidx in self.__topology_dict:
+            l = bm.faces[fidx].loops[vidx]
+            l[active_uv].uv = l[active_uv].uv + dv
+        bmesh.update_edit_mesh(obj.data)
+
+        # check mouse preference
+        confirm_btn = 'LEFTMOUSE'
+        cancel_btn = 'RIGHTMOUSE'
+
+        # cancelled
+        if event.type == cancel_btn and event.value == 'PRESS':
+            for (fidx, vidx), uv in zip(self.__topology_dict, self.__ini_uvs):
+                bm.faces[fidx].loops[vidx][active_uv].uv = uv
+            MUV_OT_MoveUV.__running = False
+            return {'FINISHED'}
+        # confirmed
+        if event.type == confirm_btn and event.value == 'PRESS':
+            MUV_OT_MoveUV.__running = False
+            return {'FINISHED'}
+
+        return {'RUNNING_MODAL'}
 
     def execute(self, context):
-        return self.__impl.execute(self, context)
+        MUV_OT_MoveUV.__running = True
+        self.__operating = False
+        self.__first_time = True
+
+        context.window_manager.modal_handler_add(self)
+        self.__topology_dict, self.__ini_uvs = _find_uv(context)
+
+        if context.area:
+            context.area.tag_redraw()
+
+        return {'RUNNING_MODAL'}
diff --git a/uv_magic_uv/op/pack_uv.py b/uv_magic_uv/op/pack_uv.py
index 84f195c5d64f853313aef3f31e4f1a978b22cdc5..35685221c772f656e97a78bc453ed4dd6c8726da 100644
--- a/uv_magic_uv/op/pack_uv.py
+++ b/uv_magic_uv/op/pack_uv.py
@@ -23,26 +23,126 @@ __status__ = "production"
 __version__ = "5.2"
 __date__ = "17 Nov 2018"
 
+from math import fabs
+
 import bpy
 from bpy.props import (
     FloatProperty,
     FloatVectorProperty,
     BoolProperty,
 )
+import bmesh
+import mathutils
+from mathutils import Vector
 
 from ..utils.bl_class_registry import BlClassRegistry
 from ..utils.property_class_registry import PropertyClassRegistry
-from ..impl import pack_uv_impl as impl
+from ..utils import compatibility as compat
+from .. import common
+
+
+def _is_valid_context(context):
+    obj = context.object
+
+    # only edit mode is allowed to execute
+    if obj is None:
+        return False
+    if obj.type != 'MESH':
+        return False
+    if context.object.mode != 'EDIT':
+        return False
+
+    # 'IMAGE_EDITOR' and 'VIEW_3D' space is allowed to execute.
+    # If 'View_3D' space is not allowed, you can't find option in Tool-Shelf
+    # after the execution
+    for space in context.area.spaces:
+        if (space.type == 'IMAGE_EDITOR') or (space.type == 'VIEW_3D'):
+            break
+    else:
+        return False
+
+    return True
+
+
+def _sort_island_faces(kd, uvs, isl1, isl2):
+    """
+    Sort faces in island
+    """
+
+    sorted_faces = []
+    for f in isl1['sorted']:
+        _, idx, _ = kd.find(
+            Vector((f['ave_uv'].x, f['ave_uv'].y, 0.0)))
+        sorted_faces.append(isl2['faces'][uvs[idx]['face_idx']])
+    return sorted_faces
+
 
+def _group_island(island_info, allowable_center_deviation,
+                  allowable_size_deviation):
+    """
+    Group island
+    """
+
+    num_group = 0
+    while True:
+        # search islands which is not parsed yet
+        isl_1 = None
+        for isl_1 in island_info:
+            if isl_1['group'] == -1:
+                break
+        else:
+            break   # all faces are parsed
+        if isl_1 is None:
+            break
+        isl_1['group'] = num_group
+        isl_1['sorted'] = isl_1['faces']
 
-__all__ = [
-    'Properties',
-    'MUV_OT_PackUV',
-]
+        # search same island
+        for isl_2 in island_info:
+            if isl_2['group'] == -1:
+                dcx = isl_2['center'].x - isl_1['center'].x
+                dcy = isl_2['center'].y - isl_1['center'].y
+                dsx = isl_2['size'].x - isl_1['size'].x
+                dsy = isl_2['size'].y - isl_1['size'].y
+                center_x_matched = (
+                    fabs(dcx) < allowable_center_deviation[0]
+                )
+                center_y_matched = (
+                    fabs(dcy) < allowable_center_deviation[1]
+                )
+                size_x_matched = (
+                    fabs(dsx) < allowable_size_deviation[0]
+                )
+                size_y_matched = (
+                    fabs(dsy) < allowable_size_deviation[1]
+                )
+                center_matched = center_x_matched and center_y_matched
+                size_matched = size_x_matched and size_y_matched
+                num_uv_matched = (isl_2['num_uv'] == isl_1['num_uv'])
+                # are islands have same?
+                if center_matched and size_matched and num_uv_matched:
+                    isl_2['group'] = num_group
+                    kd = mathutils.kdtree.KDTree(len(isl_2['faces']))
+                    uvs = [
+                        {
+                            'uv': Vector(
+                                (f['ave_uv'].x, f['ave_uv'].y, 0.0)
+                            ),
+                            'face_idx': fidx
+                        } for fidx, f in enumerate(isl_2['faces'])
+                    ]
+                    for i, uv in enumerate(uvs):
+                        kd.insert(uv['uv'], i)
+                    kd.balance()
+                    # sort faces for copy/paste UV
+                    isl_2['sorted'] = _sort_island_faces(kd, uvs, isl_1, isl_2)
+        num_group = num_group + 1
+
+    return num_group
 
 
 @PropertyClassRegistry()
-class Properties:
+class _Properties:
     idname = "pack_uv"
 
     @classmethod
@@ -77,6 +177,7 @@ class Properties:
 
 
 @BlClassRegistry()
+@compat.make_annotations
 class MUV_OT_PackUV(bpy.types.Operator):
     """
     Operation class: Pack UV with same UV islands are integrated
@@ -91,17 +192,17 @@ class MUV_OT_PackUV(bpy.types.Operator):
     bl_description = "Pack UV (Same UV Islands are integrated)"
     bl_options = {'REGISTER', 'UNDO'}
 
-    rotate: BoolProperty(
+    rotate = BoolProperty(
         name="Rotate",
         description="Rotate option used by default pack UV function",
         default=False)
-    margin: FloatProperty(
+    margin = FloatProperty(
         name="Margin",
         description="Margin used by default pack UV function",
         min=0,
         max=1,
         default=0.001)
-    allowable_center_deviation: FloatVectorProperty(
+    allowable_center_deviation = FloatVectorProperty(
         name="Allowable Center Deviation",
         description="Allowable center deviation to judge same UV island",
         min=0.000001,
@@ -109,7 +210,7 @@ class MUV_OT_PackUV(bpy.types.Operator):
         default=(0.001, 0.001),
         size=2
     )
-    allowable_size_deviation: FloatVectorProperty(
+    allowable_size_deviation = FloatVectorProperty(
         name="Allowable Size Deviation",
         description="Allowable sizse deviation to judge same UV island",
         min=0.000001,
@@ -118,12 +219,64 @@ class MUV_OT_PackUV(bpy.types.Operator):
         size=2
     )
 
-    def __init__(self):
-        self.__impl = impl.PackUVImpl()
-
     @classmethod
     def poll(cls, context):
-        return impl.PackUVImpl.poll(context)
+        # we can not get area/space/region from console
+        if common.is_console_mode():
+            return True
+        return _is_valid_context(context)
 
     def execute(self, context):
-        return self.__impl.execute(self, context)
+        obj = context.active_object
+        bm = bmesh.from_edit_mesh(obj.data)
+        if common.check_version(2, 73, 0) >= 0:
+            bm.faces.ensure_lookup_table()
+        if not bm.loops.layers.uv:
+            self.report({'WARNING'},
+                        "Object must have more than one UV map")
+            return {'CANCELLED'}
+        uv_layer = bm.loops.layers.uv.verify()
+
+        selected_faces = [f for f in bm.faces if f.select]
+        island_info = common.get_island_info(obj)
+        num_group = _group_island(island_info,
+                                  self.allowable_center_deviation,
+                                  self.allowable_size_deviation)
+
+        loop_lists = [l for f in bm.faces for l in f.loops]
+        bpy.ops.mesh.select_all(action='DESELECT')
+
+        # pack UV
+        for gidx in range(num_group):
+            group = list(filter(
+                lambda i, idx=gidx: i['group'] == idx, island_info))
+            for f in group[0]['faces']:
+                f['face'].select = True
+        bmesh.update_edit_mesh(obj.data)
+        bpy.ops.uv.select_all(action='SELECT')
+        bpy.ops.uv.pack_islands(rotate=self.rotate, margin=self.margin)
+
+        # copy/paste UV among same islands
+        for gidx in range(num_group):
+            group = list(filter(
+                lambda i, idx=gidx: i['group'] == idx, island_info))
+            if len(group) <= 1:
+                continue
+            for g in group[1:]:
+                for (src_face, dest_face) in zip(
+                        group[0]['sorted'], g['sorted']):
+                    for (src_loop, dest_loop) in zip(
+                            src_face['face'].loops, dest_face['face'].loops):
+                        loop_lists[dest_loop.index][uv_layer].uv = loop_lists[
+                            src_loop.index][uv_layer].uv
+
+        # restore face/UV selection
+        bpy.ops.uv.select_all(action='DESELECT')
+        bpy.ops.mesh.select_all(action='DESELECT')
+        for f in selected_faces:
+            f.select = True
+        bpy.ops.uv.select_all(action='SELECT')
+
+        bmesh.update_edit_mesh(obj.data)
+
+        return {'FINISHED'}
diff --git a/uv_magic_uv/op/preserve_uv_aspect.py b/uv_magic_uv/op/preserve_uv_aspect.py
index ca4969fde12536f649dfc85cb2c725d06027fead..a200edaccd802b1ae16438047286a45a8c127caa 100644
--- a/uv_magic_uv/op/preserve_uv_aspect.py
+++ b/uv_magic_uv/op/preserve_uv_aspect.py
@@ -25,16 +25,34 @@ __date__ = "17 Nov 2018"
 
 import bpy
 from bpy.props import StringProperty, EnumProperty, BoolProperty
+import bmesh
+from mathutils import Vector
 
+from .. import common
 from ..utils.bl_class_registry import BlClassRegistry
 from ..utils.property_class_registry import PropertyClassRegistry
-from ..impl import preserve_uv_aspect_impl as impl
+from ..utils import compatibility as compat
 
 
-__all__ = [
-    'Properties',
-    'MUV_OT_PreserveUVAspect',
-]
+def _is_valid_context(context):
+    obj = context.object
+
+    # only edit mode is allowed to execute
+    if obj is None:
+        return False
+    if obj.type != 'MESH':
+        return False
+    if context.object.mode != 'EDIT':
+        return False
+
+    # only 'VIEW_3D' space is allowed to execute
+    for space in context.area.spaces:
+        if space.type == 'VIEW_3D':
+            break
+    else:
+        return False
+
+    return True
 
 
 @PropertyClassRegistry()
@@ -84,6 +102,7 @@ class _Properties:
 
 
 @BlClassRegistry()
+@compat.make_annotations
 class MUV_OT_PreserveUVAspect(bpy.types.Operator):
     """
     Operation class: Preserve UV Aspect
@@ -94,8 +113,8 @@ class MUV_OT_PreserveUVAspect(bpy.types.Operator):
     bl_description = "Choose Image"
     bl_options = {'REGISTER', 'UNDO'}
 
-    dest_img_name: StringProperty(options={'HIDDEN'})
-    origin: EnumProperty(
+    dest_img_name = StringProperty(options={'HIDDEN'})
+    origin = EnumProperty(
         name="Origin",
         description="Aspect Origin",
         items=[
@@ -113,12 +132,166 @@ class MUV_OT_PreserveUVAspect(bpy.types.Operator):
         default="CENTER"
     )
 
-    def __init__(self):
-        self.__impl = impl.PreserveUVAspectImpl()
-
     @classmethod
     def poll(cls, context):
-        return impl.PreserveUVAspectImpl.poll(context)
+        # we can not get area/space/region from console
+        if common.is_console_mode():
+            return True
+        return _is_valid_context(context)
 
     def execute(self, context):
-        return self.__impl.execute(self, context)
+        # Note: the current system only works if the
+        # f[tex_layer].image doesn't return None
+        # which will happen in certain cases
+        obj = context.active_object
+        bm = bmesh.from_edit_mesh(obj.data)
+
+        if common.check_version(2, 73, 0) >= 0:
+            bm.faces.ensure_lookup_table()
+
+        if not bm.loops.layers.uv:
+            self.report({'WARNING'},
+                        "Object must have more than one UV map")
+            return {'CANCELLED'}
+
+        uv_layer = bm.loops.layers.uv.verify()
+
+        sel_faces = [f for f in bm.faces if f.select]
+        dest_img = bpy.data.images[self.dest_img_name]
+
+        info = {}
+
+        if compat.check_version(2, 80, 0) >= 0:
+            tex_image = common.find_image(obj)
+            for f in sel_faces:
+                if tex_image not in info.keys():
+                    info[tex_image] = {}
+                    info[tex_image]['faces'] = []
+                info[tex_image]['faces'].append(f)
+        else:
+            tex_layer = bm.faces.layers.tex.verify()
+            for f in sel_faces:
+                if not f[tex_layer].image in info.keys():
+                    info[f[tex_layer].image] = {}
+                    info[f[tex_layer].image]['faces'] = []
+                info[f[tex_layer].image]['faces'].append(f)
+
+        for img in info:
+            if img is None:
+                continue
+
+            src_img = img
+            ratio = Vector((
+                dest_img.size[0] / src_img.size[0],
+                dest_img.size[1] / src_img.size[1]))
+
+            if self.origin == 'CENTER':
+                origin = Vector((0.0, 0.0))
+                num = 0
+                for f in info[img]['faces']:
+                    for l in f.loops:
+                        uv = l[uv_layer].uv
+                        origin = origin + uv
+                        num = num + 1
+                origin = origin / num
+            elif self.origin == 'LEFT_TOP':
+                origin = Vector((100000.0, -100000.0))
+                for f in info[img]['faces']:
+                    for l in f.loops:
+                        uv = l[uv_layer].uv
+                        origin.x = min(origin.x, uv.x)
+                        origin.y = max(origin.y, uv.y)
+            elif self.origin == 'LEFT_CENTER':
+                origin = Vector((100000.0, 0.0))
+                num = 0
+                for f in info[img]['faces']:
+                    for l in f.loops:
+                        uv = l[uv_layer].uv
+                        origin.x = min(origin.x, uv.x)
+                        origin.y = origin.y + uv.y
+                        num = num + 1
+                origin.y = origin.y / num
+            elif self.origin == 'LEFT_BOTTOM':
+                origin = Vector((100000.0, 100000.0))
+                for f in info[img]['faces']:
+                    for l in f.loops:
+                        uv = l[uv_layer].uv
+                        origin.x = min(origin.x, uv.x)
+                        origin.y = min(origin.y, uv.y)
+            elif self.origin == 'CENTER_TOP':
+                origin = Vector((0.0, -100000.0))
+                num = 0
+                for f in info[img]['faces']:
+                    for l in f.loops:
+                        uv = l[uv_layer].uv
+                        origin.x = origin.x + uv.x
+                        origin.y = max(origin.y, uv.y)
+                        num = num + 1
+                origin.x = origin.x / num
+            elif self.origin == 'CENTER_BOTTOM':
+                origin = Vector((0.0, 100000.0))
+                num = 0
+                for f in info[img]['faces']:
+                    for l in f.loops:
+                        uv = l[uv_layer].uv
+                        origin.x = origin.x + uv.x
+                        origin.y = min(origin.y, uv.y)
+                        num = num + 1
+                origin.x = origin.x / num
+            elif self.origin == 'RIGHT_TOP':
+                origin = Vector((-100000.0, -100000.0))
+                for f in info[img]['faces']:
+                    for l in f.loops:
+                        uv = l[uv_layer].uv
+                        origin.x = max(origin.x, uv.x)
+                        origin.y = max(origin.y, uv.y)
+            elif self.origin == 'RIGHT_CENTER':
+                origin = Vector((-100000.0, 0.0))
+                num = 0
+                for f in info[img]['faces']:
+                    for l in f.loops:
+                        uv = l[uv_layer].uv
+                        origin.x = max(origin.x, uv.x)
+                        origin.y = origin.y + uv.y
+                        num = num + 1
+                origin.y = origin.y / num
+            elif self.origin == 'RIGHT_BOTTOM':
+                origin = Vector((-100000.0, 100000.0))
+                for f in info[img]['faces']:
+                    for l in f.loops:
+                        uv = l[uv_layer].uv
+                        origin.x = max(origin.x, uv.x)
+                        origin.y = min(origin.y, uv.y)
+            else:
+                self.report({'ERROR'}, "Unknown Operation")
+                return {'CANCELLED'}
+
+            info[img]['ratio'] = ratio
+            info[img]['origin'] = origin
+
+        for img in info:
+            if img is None:
+                continue
+
+            if compat.check_version(2, 80, 0) >= 0:
+                nodes = common.find_texture_nodes(obj)
+                nodes[0].image = dest_img
+
+            for f in info[img]['faces']:
+                if compat.check_version(2, 80, 0) < 0:
+                    tex_layer = bm.faces.layers.tex.verify()
+                    f[tex_layer].image = dest_img
+                for l in f.loops:
+                    uv = l[uv_layer].uv
+                    origin = info[img]['origin']
+                    ratio = info[img]['ratio']
+                    diff = uv - origin
+                    diff.x = diff.x / ratio.x
+                    diff.y = diff.y / ratio.y
+                    uv.x = origin.x + diff.x
+                    uv.y = origin.y + diff.y
+                    l[uv_layer].uv = uv
+
+        bmesh.update_edit_mesh(obj.data)
+
+        return {'FINISHED'}
diff --git a/uv_magic_uv/op/select_uv.py b/uv_magic_uv/op/select_uv.py
index 789af9ce8bd7b4e76c982c4290eff16519526e88..4664551e44b052d9bdc467ed6ee7defc22d79a41 100644
--- a/uv_magic_uv/op/select_uv.py
+++ b/uv_magic_uv/op/select_uv.py
@@ -25,10 +25,34 @@ __date__ = "17 Nov 2018"
 
 import bpy
 from bpy.props import BoolProperty
+import bmesh
 
+from .. import common
 from ..utils.bl_class_registry import BlClassRegistry
 from ..utils.property_class_registry import PropertyClassRegistry
-from ..impl import select_uv_impl as impl
+
+
+def _is_valid_context(context):
+    obj = context.object
+
+    # only edit mode is allowed to execute
+    if obj is None:
+        return False
+    if obj.type != 'MESH':
+        return False
+    if context.object.mode != 'EDIT':
+        return False
+
+    # 'IMAGE_EDITOR' and 'VIEW_3D' space is allowed to execute.
+    # If 'View_3D' space is not allowed, you can't find option in Tool-Shelf
+    # after the execution
+    for space in context.area.spaces:
+        if (space.type == 'IMAGE_EDITOR') or (space.type == 'VIEW_3D'):
+            break
+    else:
+        return False
+
+    return True
 
 
 @PropertyClassRegistry()
@@ -59,15 +83,38 @@ class MUV_OT_SelectUV_SelectOverlapped(bpy.types.Operator):
     bl_description = "Select faces which have overlapped UVs"
     bl_options = {'REGISTER', 'UNDO'}
 
-    def __init__(self):
-        self.__impl = impl.SelectOverlappedImpl()
-
     @classmethod
     def poll(cls, context):
-        return impl.SelectOverlappedImpl.poll(context)
+        # we can not get area/space/region from console
+        if common.is_console_mode():
+            return True
+        return _is_valid_context(context)
 
     def execute(self, context):
-        return self.__impl.execute(self, context)
+        obj = context.active_object
+        bm = bmesh.from_edit_mesh(obj.data)
+        if common.check_version(2, 73, 0) >= 0:
+            bm.faces.ensure_lookup_table()
+        uv_layer = bm.loops.layers.uv.verify()
+
+        if context.tool_settings.use_uv_select_sync:
+            sel_faces = [f for f in bm.faces]
+        else:
+            sel_faces = [f for f in bm.faces if f.select]
+
+        overlapped_info = common.get_overlapped_uv_info(bm, sel_faces,
+                                                        uv_layer, 'FACE')
+
+        for info in overlapped_info:
+            if context.tool_settings.use_uv_select_sync:
+                info["subject_face"].select = True
+            else:
+                for l in info["subject_face"].loops:
+                    l[uv_layer].select = True
+
+        bmesh.update_edit_mesh(obj.data)
+
+        return {'FINISHED'}
 
 
 @BlClassRegistry()
@@ -81,12 +128,34 @@ class MUV_OT_SelectUV_SelectFlipped(bpy.types.Operator):
     bl_description = "Select faces which have flipped UVs"
     bl_options = {'REGISTER', 'UNDO'}
 
-    def __init__(self):
-        self.__impl = impl.SelectFlippedImpl()
-
     @classmethod
     def poll(cls, context):
-        return impl.SelectFlippedImpl.poll(context)
+        # we can not get area/space/region from console
+        if common.is_console_mode():
+            return True
+        return _is_valid_context(context)
 
     def execute(self, context):
-        return self.__impl.execute(self, context)
+        obj = context.active_object
+        bm = bmesh.from_edit_mesh(obj.data)
+        if common.check_version(2, 73, 0) >= 0:
+            bm.faces.ensure_lookup_table()
+        uv_layer = bm.loops.layers.uv.verify()
+
+        if context.tool_settings.use_uv_select_sync:
+            sel_faces = [f for f in bm.faces]
+        else:
+            sel_faces = [f for f in bm.faces if f.select]
+
+        flipped_info = common.get_flipped_uv_info(sel_faces, uv_layer)
+
+        for info in flipped_info:
+            if context.tool_settings.use_uv_select_sync:
+                info["face"].select = True
+            else:
+                for l in info["face"].loops:
+                    l[uv_layer].select = True
+
+        bmesh.update_edit_mesh(obj.data)
+
+        return {'FINISHED'}
diff --git a/uv_magic_uv/op/smooth_uv.py b/uv_magic_uv/op/smooth_uv.py
index d448d10834ea4dc9bce9d8b0c80ec719cadb435f..83a4a1a5a2b94b61395b2415ed7373d602856d92 100644
--- a/uv_magic_uv/op/smooth_uv.py
+++ b/uv_magic_uv/op/smooth_uv.py
@@ -25,10 +25,35 @@ __date__ = "17 Nov 2018"
 
 import bpy
 from bpy.props import BoolProperty, FloatProperty
+import bmesh
 
+from .. import common
 from ..utils.bl_class_registry import BlClassRegistry
 from ..utils.property_class_registry import PropertyClassRegistry
-from ..impl import smooth_uv_impl as impl
+from ..utils import compatibility as compat
+
+
+def _is_valid_context(context):
+    obj = context.object
+
+    # only edit mode is allowed to execute
+    if obj is None:
+        return False
+    if obj.type != 'MESH':
+        return False
+    if context.object.mode != 'EDIT':
+        return False
+
+    # 'IMAGE_EDITOR' and 'VIEW_3D' space is allowed to execute.
+    # If 'View_3D' space is not allowed, you can't find option in Tool-Shelf
+    # after the execution
+    for space in context.area.spaces:
+        if (space.type == 'IMAGE_EDITOR') or (space.type == 'VIEW_3D'):
+            break
+    else:
+        return False
+
+    return True
 
 
 @PropertyClassRegistry()
@@ -69,6 +94,7 @@ class _Properties:
 
 
 @BlClassRegistry()
+@compat.make_annotations
 class MUV_OT_SmoothUV(bpy.types.Operator):
 
     bl_idname = "uv.muv_smooth_uv_operator"
@@ -76,30 +102,182 @@ class MUV_OT_SmoothUV(bpy.types.Operator):
     bl_description = "Smooth UV coordinates"
     bl_options = {'REGISTER', 'UNDO'}
 
-    transmission: BoolProperty(
+    transmission = BoolProperty(
         name="Transmission",
         description="Smooth linked UVs",
         default=False
     )
-    mesh_infl: FloatProperty(
+    mesh_infl = FloatProperty(
         name="Mesh Influence",
         description="Influence rate of mesh vertex",
         min=0.0,
         max=1.0,
         default=0.0
     )
-    select: BoolProperty(
+    select = BoolProperty(
         name="Select",
         description="Select UVs which are smoothed",
         default=False
     )
 
-    def __init__(self):
-        self.__impl = impl.SmoothUVImpl()
-
     @classmethod
     def poll(cls, context):
-        return impl.SmoothUVImpl.poll(context)
+        # we can not get area/space/region from console
+        if common.is_console_mode():
+            return True
+        return _is_valid_context(context)
+
+    def __smooth_wo_transmission(self, loop_seqs, uv_layer):
+        # calculate path length
+        loops = []
+        for hseq in loop_seqs:
+            loops.extend([hseq[0][0], hseq[0][1]])
+        full_vlen = 0
+        accm_vlens = [0.0]
+        full_uvlen = 0
+        accm_uvlens = [0.0]
+        orig_uvs = [loop_seqs[0][0][0][uv_layer].uv.copy()]
+        for l1, l2 in zip(loops[:-1], loops[1:]):
+            diff_v = l2.vert.co - l1.vert.co
+            full_vlen = full_vlen + diff_v.length
+            accm_vlens.append(full_vlen)
+            diff_uv = l2[uv_layer].uv - l1[uv_layer].uv
+            full_uvlen = full_uvlen + diff_uv.length
+            accm_uvlens.append(full_uvlen)
+            orig_uvs.append(l2[uv_layer].uv.copy())
+
+        for hidx, hseq in enumerate(loop_seqs):
+            pair = hseq[0]
+            for pidx, l in enumerate(pair):
+                if self.select:
+                    l[uv_layer].select = True
+
+                # ignore start/end loop
+                if (hidx == 0 and pidx == 0) or\
+                   ((hidx == len(loop_seqs) - 1) and (pidx == len(pair) - 1)):
+                    continue
+
+                # calculate target path length
+                # target = no influenced * (1 - infl) + influenced * infl
+                tgt_noinfl = full_uvlen * (hidx + pidx) / (len(loop_seqs))
+                tgt_infl = full_uvlen * accm_vlens[hidx * 2 + pidx] / full_vlen
+                target_length = tgt_noinfl * (1 - self.mesh_infl) + \
+                    tgt_infl * self.mesh_infl
+
+                # get target UV
+                for i in range(len(accm_uvlens[:-1])):
+                    # get line segment which UV will be placed
+                    if ((accm_uvlens[i] <= target_length) and
+                            (accm_uvlens[i + 1] > target_length)):
+                        tgt_seg_len = target_length - accm_uvlens[i]
+                        seg_len = accm_uvlens[i + 1] - accm_uvlens[i]
+                        uv1 = orig_uvs[i]
+                        uv2 = orig_uvs[i + 1]
+                        target_uv = uv1 + (uv2 - uv1) * tgt_seg_len / seg_len
+                        break
+                else:
+                    self.report({'ERROR'}, "Failed to get target UV")
+                    return {'CANCELLED'}
+
+                # update UV
+                l[uv_layer].uv = target_uv
+
+    def __smooth_w_transmission(self, loop_seqs, uv_layer):
+        # calculate path length
+        loops = []
+        for vidx in range(len(loop_seqs[0])):
+            ls = []
+            for hseq in loop_seqs:
+                ls.extend(hseq[vidx])
+            loops.append(ls)
+
+        orig_uvs = []
+        accm_vlens = []
+        full_vlens = []
+        accm_uvlens = []
+        full_uvlens = []
+        for ls in loops:
+            full_v = 0.0
+            accm_v = [0.0]
+            full_uv = 0.0
+            accm_uv = [0.0]
+            uvs = [ls[0][uv_layer].uv.copy()]
+            for l1, l2 in zip(ls[:-1], ls[1:]):
+                diff_v = l2.vert.co - l1.vert.co
+                full_v = full_v + diff_v.length
+                accm_v.append(full_v)
+                diff_uv = l2[uv_layer].uv - l1[uv_layer].uv
+                full_uv = full_uv + diff_uv.length
+                accm_uv.append(full_uv)
+                uvs.append(l2[uv_layer].uv.copy())
+            accm_vlens.append(accm_v)
+            full_vlens.append(full_v)
+            accm_uvlens.append(accm_uv)
+            full_uvlens.append(full_uv)
+            orig_uvs.append(uvs)
+
+        for hidx, hseq in enumerate(loop_seqs):
+            for vidx, (pair, uvs, accm_v, full_v, accm_uv, full_uv)\
+                    in enumerate(zip(hseq, orig_uvs, accm_vlens, full_vlens,
+                                     accm_uvlens, full_uvlens)):
+                for pidx, l in enumerate(pair):
+                    if self.select:
+                        l[uv_layer].select = True
+
+                    # ignore start/end loop
+                    if hidx == 0 and pidx == 0:
+                        continue
+                    if hidx == len(loop_seqs) - 1 and pidx == len(pair) - 1:
+                        continue
+
+                    # calculate target path length
+                    # target = no influenced * (1 - infl) + influenced * infl
+                    tgt_noinfl = full_uv * (hidx + pidx) / (len(loop_seqs))
+                    tgt_infl = full_uv * accm_v[hidx * 2 + pidx] / full_v
+                    target_length = tgt_noinfl * (1 - self.mesh_infl) + \
+                        tgt_infl * self.mesh_infl
+
+                    # get target UV
+                    for i in range(len(accm_uv[:-1])):
+                        # get line segment to be placed
+                        if ((accm_uv[i] <= target_length) and
+                                (accm_uv[i + 1] > target_length)):
+                            tgt_seg_len = target_length - accm_uv[i]
+                            seg_len = accm_uv[i + 1] - accm_uv[i]
+                            uv1 = uvs[i]
+                            uv2 = uvs[i + 1]
+                            target_uv = uv1 +\
+                                (uv2 - uv1) * tgt_seg_len / seg_len
+                            break
+                    else:
+                        self.report({'ERROR'}, "Failed to get target UV")
+                        return {'CANCELLED'}
+
+                    # update UV
+                    l[uv_layer].uv = target_uv
+
+    def __smooth(self, loop_seqs, uv_layer):
+        if self.transmission:
+            self.__smooth_w_transmission(loop_seqs, uv_layer)
+        else:
+            self.__smooth_wo_transmission(loop_seqs, uv_layer)
 
     def execute(self, context):
-        return self.__impl.execute(self, context)
+        obj = context.active_object
+        bm = bmesh.from_edit_mesh(obj.data)
+        if common.check_version(2, 73, 0) >= 0:
+            bm.faces.ensure_lookup_table()
+        uv_layer = bm.loops.layers.uv.verify()
+
+        # loop_seqs[horizontal][vertical][loop]
+        loop_seqs, error = common.get_loop_sequences(bm, uv_layer)
+        if not loop_seqs:
+            self.report({'WARNING'}, error)
+            return {'CANCELLED'}
+
+        # smooth
+        self.__smooth(loop_seqs, uv_layer)
+
+        bmesh.update_edit_mesh(obj.data)
+
+        return {'FINISHED'}
diff --git a/uv_magic_uv/op/texture_lock.py b/uv_magic_uv/op/texture_lock.py
index b1b437531258ad43d169332bd3f058e10c6e38c3..f43a6fa9c15b16348d8c3472f34b369b625333e5 100644
--- a/uv_magic_uv/op/texture_lock.py
+++ b/uv_magic_uv/op/texture_lock.py
@@ -23,12 +23,189 @@ __status__ = "production"
 __version__ = "5.2"
 __date__ = "17 Nov 2018"
 
+import math
+from math import atan2, cos, sqrt, sin, fabs
+
 import bpy
 from bpy.props import BoolProperty
+import bmesh
+from mathutils import Vector
 
+from .. import common
 from ..utils.bl_class_registry import BlClassRegistry
 from ..utils.property_class_registry import PropertyClassRegistry
-from ..impl import texture_lock_impl as impl
+from ..utils import compatibility as compat
+
+
+def _get_vco(verts_orig, loop):
+    """
+    Get vertex original coordinate from loop
+    """
+    for vo in verts_orig:
+        if vo["vidx"] == loop.vert.index and vo["moved"] is False:
+            return vo["vco"]
+    return loop.vert.co
+
+
+def _get_link_loops(vert):
+    """
+    Get loop linked to vertex
+    """
+    link_loops = []
+    for f in vert.link_faces:
+        adj_loops = []
+        for loop in f.loops:
+            # self loop
+            if loop.vert == vert:
+                l = loop
+            # linked loop
+            else:
+                for e in loop.vert.link_edges:
+                    if e.other_vert(loop.vert) == vert:
+                        adj_loops.append(loop)
+        if len(adj_loops) < 2:
+            return None
+
+        link_loops.append({"l": l, "l0": adj_loops[0], "l1": adj_loops[1]})
+    return link_loops
+
+
+def _get_ini_geom(link_loop, uv_layer, verts_orig, v_orig):
+    """
+    Get initial geometory
+    (Get interior angle of face in vertex/UV space)
+    """
+    u = link_loop["l"][uv_layer].uv
+    v0 = _get_vco(verts_orig, link_loop["l0"])
+    u0 = link_loop["l0"][uv_layer].uv
+    v1 = _get_vco(verts_orig, link_loop["l1"])
+    u1 = link_loop["l1"][uv_layer].uv
+
+    # get interior angle of face in vertex space
+    v0v1 = v1 - v0
+    v0v = v_orig["vco"] - v0
+    v1v = v_orig["vco"] - v1
+    theta0 = v0v1.angle(v0v)
+    theta1 = v0v1.angle(-v1v)
+    if (theta0 + theta1) > math.pi:
+        theta0 = v0v1.angle(-v0v)
+        theta1 = v0v1.angle(v1v)
+
+    # get interior angle of face in UV space
+    u0u1 = u1 - u0
+    u0u = u - u0
+    u1u = u - u1
+    phi0 = u0u1.angle(u0u)
+    phi1 = u0u1.angle(-u1u)
+    if (phi0 + phi1) > math.pi:
+        phi0 = u0u1.angle(-u0u)
+        phi1 = u0u1.angle(u1u)
+
+    # get direction of linked UV coordinate
+    # this will be used to judge whether angle is more or less than 180 degree
+    dir0 = u0u1.cross(u0u) > 0
+    dir1 = u0u1.cross(u1u) > 0
+
+    return {
+        "theta0": theta0,
+        "theta1": theta1,
+        "phi0": phi0,
+        "phi1": phi1,
+        "dir0": dir0,
+        "dir1": dir1}
+
+
+def _get_target_uv(link_loop, uv_layer, verts_orig, v, ini_geom):
+    """
+    Get target UV coordinate
+    """
+    v0 = _get_vco(verts_orig, link_loop["l0"])
+    lo0 = link_loop["l0"]
+    v1 = _get_vco(verts_orig, link_loop["l1"])
+    lo1 = link_loop["l1"]
+
+    # get interior angle of face in vertex space
+    v0v1 = v1 - v0
+    v0v = v.co - v0
+    v1v = v.co - v1
+    theta0 = v0v1.angle(v0v)
+    theta1 = v0v1.angle(-v1v)
+    if (theta0 + theta1) > math.pi:
+        theta0 = v0v1.angle(-v0v)
+        theta1 = v0v1.angle(v1v)
+
+    # calculate target interior angle in UV space
+    phi0 = theta0 * ini_geom["phi0"] / ini_geom["theta0"]
+    phi1 = theta1 * ini_geom["phi1"] / ini_geom["theta1"]
+
+    uv0 = lo0[uv_layer].uv
+    uv1 = lo1[uv_layer].uv
+
+    # calculate target vertex coordinate from target interior angle
+    tuv0, tuv1 = _calc_tri_vert(uv0, uv1, phi0, phi1)
+
+    # target UV coordinate depends on direction, so judge using direction of
+    # linked UV coordinate
+    u0u1 = uv1 - uv0
+    u0u = tuv0 - uv0
+    u1u = tuv0 - uv1
+    dir0 = u0u1.cross(u0u) > 0
+    dir1 = u0u1.cross(u1u) > 0
+    if (ini_geom["dir0"] != dir0) or (ini_geom["dir1"] != dir1):
+        return tuv1
+
+    return tuv0
+
+
+def _calc_tri_vert(v0, v1, angle0, angle1):
+    """
+    Calculate rest coordinate from other coordinates and angle of end
+    """
+    angle = math.pi - angle0 - angle1
+
+    alpha = atan2(v1.y - v0.y, v1.x - v0.x)
+    d = (v1.x - v0.x) / cos(alpha)
+    a = d * sin(angle0) / sin(angle)
+    b = d * sin(angle1) / sin(angle)
+    s = (a + b + d) / 2.0
+    if fabs(d) < 0.0000001:
+        xd = 0
+        yd = 0
+    else:
+        r = s * (s - a) * (s - b) * (s - d)
+        if r < 0:
+            xd = 0
+            yd = 0
+        else:
+            xd = (b * b - a * a + d * d) / (2 * d)
+            yd = 2 * sqrt(r) / d
+    x1 = xd * cos(alpha) - yd * sin(alpha) + v0.x
+    y1 = xd * sin(alpha) + yd * cos(alpha) + v0.y
+    x2 = xd * cos(alpha) + yd * sin(alpha) + v0.x
+    y2 = xd * sin(alpha) - yd * cos(alpha) + v0.y
+
+    return Vector((x1, y1)), Vector((x2, y2))
+
+
+def _is_valid_context(context):
+    obj = context.object
+
+    # only edit mode is allowed to execute
+    if obj is None:
+        return False
+    if obj.type != 'MESH':
+        return False
+    if context.object.mode != 'EDIT':
+        return False
+
+    # only 'VIEW_3D' space is allowed to execute
+    for space in context.area.spaces:
+        if space.type == 'VIEW_3D':
+            break
+    else:
+        return False
+
+    return True
 
 
 @PropertyClassRegistry()
@@ -88,22 +265,43 @@ class MUV_OT_TextureLock_Lock(bpy.types.Operator):
     bl_description = "Lock Texture"
     bl_options = {'REGISTER', 'UNDO'}
 
-    def __init__(self):
-        self.__impl = impl.LockImpl()
-
     @classmethod
     def poll(cls, context):
-        return impl.LockImpl.poll(context)
+        # we can not get area/space/region from console
+        if common.is_console_mode():
+            return True
+        return _is_valid_context(context)
 
     @classmethod
     def is_ready(cls, context):
-        return impl.LockImpl.is_ready(context)
+        sc = context.scene
+        props = sc.muv_props.texture_lock
+        if props.verts_orig:
+            return True
+        return False
 
     def execute(self, context):
-        return self.__impl.execute(self, context)
+        props = context.scene.muv_props.texture_lock
+        obj = bpy.context.active_object
+        bm = bmesh.from_edit_mesh(obj.data)
+        if common.check_version(2, 73, 0) >= 0:
+            bm.verts.ensure_lookup_table()
+            bm.edges.ensure_lookup_table()
+            bm.faces.ensure_lookup_table()
+
+        if not bm.loops.layers.uv:
+            self.report({'WARNING'}, "Object must have more than one UV map")
+            return {'CANCELLED'}
+
+        props.verts_orig = [
+            {"vidx": v.index, "vco": v.co.copy(), "moved": False}
+            for v in bm.verts if v.select]
+
+        return {'FINISHED'}
 
 
 @BlClassRegistry()
+@compat.make_annotations
 class MUV_OT_TextureLock_Unlock(bpy.types.Operator):
     """
     Operation class: Unlock Texture
@@ -114,20 +312,78 @@ class MUV_OT_TextureLock_Unlock(bpy.types.Operator):
     bl_description = "Unlock Texture"
     bl_options = {'REGISTER', 'UNDO'}
 
-    connect: BoolProperty(
+    connect = BoolProperty(
         name="Connect UV",
         default=True
     )
 
-    def __init__(self):
-        self.__impl = impl.UnlockImpl()
-
     @classmethod
     def poll(cls, context):
-        return impl.UnlockImpl.poll(context)
+        # we can not get area/space/region from console
+        if common.is_console_mode():
+            return True
+        sc = context.scene
+        props = sc.muv_props.texture_lock
+        if not props.verts_orig:
+            return False
+        if not MUV_OT_TextureLock_Lock.is_ready(context):
+            return False
+        if not _is_valid_context(context):
+            return False
+        return True
 
     def execute(self, context):
-        return self.__impl.execute(self, context)
+        sc = context.scene
+        props = sc.muv_props.texture_lock
+        obj = bpy.context.active_object
+        bm = bmesh.from_edit_mesh(obj.data)
+        if common.check_version(2, 73, 0) >= 0:
+            bm.verts.ensure_lookup_table()
+            bm.edges.ensure_lookup_table()
+            bm.faces.ensure_lookup_table()
+
+        if not bm.loops.layers.uv:
+            self.report({'WARNING'}, "Object must have more than one UV map")
+            return {'CANCELLED'}
+        uv_layer = bm.loops.layers.uv.verify()
+
+        verts = [v.index for v in bm.verts if v.select]
+        verts_orig = props.verts_orig
+
+        # move UV followed by vertex coordinate
+        for vidx, v_orig in zip(verts, verts_orig):
+            if vidx != v_orig["vidx"]:
+                self.report({'ERROR'}, "Internal Error")
+                return {"CANCELLED"}
+
+            v = bm.verts[vidx]
+            link_loops = _get_link_loops(v)
+
+            result = []
+
+            for ll in link_loops:
+                ini_geom = _get_ini_geom(ll, uv_layer, verts_orig, v_orig)
+                target_uv = _get_target_uv(
+                    ll, uv_layer, verts_orig, v, ini_geom)
+                result.append({"l": ll["l"], "uv": target_uv})
+
+            # connect other face's UV
+            if self.connect:
+                ave = Vector((0.0, 0.0))
+                for r in result:
+                    ave = ave + r["uv"]
+                ave = ave / len(result)
+                for r in result:
+                    r["l"][uv_layer].uv = ave
+            else:
+                for r in result:
+                    r["l"][uv_layer].uv = r["uv"]
+            v_orig["moved"] = True
+            bmesh.update_edit_mesh(obj.data)
+
+        props.verts_orig = None
+
+        return {'FINISHED'}
 
 
 @BlClassRegistry()
@@ -140,19 +396,142 @@ class MUV_OT_TextureLock_Intr(bpy.types.Operator):
     bl_label = "Texture Lock (Interactive mode)"
     bl_description = "Internal operation for Texture Lock (Interactive mode)"
 
-    def __init__(self):
-        self.__impl = impl.IntrImpl()
+    __timer = None
 
     @classmethod
     def poll(cls, context):
-        return impl.IntrImpl.poll(context)
+        # we can not get area/space/region from console
+        if common.is_console_mode():
+            return False
+        return _is_valid_context(context)
+
+    @classmethod
+    def is_running(cls, _):
+        return 1 if cls.__timer else 0
+
+    @classmethod
+    def handle_add(cls, ops_obj, context):
+        if cls.__timer is None:
+            cls.__timer = context.window_manager.event_timer_add(
+                0.10, window=context.window)
+            context.window_manager.modal_handler_add(ops_obj)
 
     @classmethod
-    def is_running(cls, context):
-        return impl.IntrImpl.is_running(context)
+    def handle_remove(cls, context):
+        if cls.__timer is not None:
+            context.window_manager.event_timer_remove(cls.__timer)
+            cls.__timer = None
+
+    def __init__(self):
+        self.__intr_verts_orig = []
+        self.__intr_verts = []
+
+    def __sel_verts_changed(self, context):
+        obj = context.active_object
+        bm = bmesh.from_edit_mesh(obj.data)
+        if common.check_version(2, 73, 0) >= 0:
+            bm.verts.ensure_lookup_table()
+            bm.edges.ensure_lookup_table()
+            bm.faces.ensure_lookup_table()
+
+        prev = set(self.__intr_verts)
+        now = set([v.index for v in bm.verts if v.select])
+
+        return prev != now
+
+    def __reinit_verts(self, context):
+        obj = context.active_object
+        bm = bmesh.from_edit_mesh(obj.data)
+        if common.check_version(2, 73, 0) >= 0:
+            bm.verts.ensure_lookup_table()
+            bm.edges.ensure_lookup_table()
+            bm.faces.ensure_lookup_table()
+
+        self.__intr_verts_orig = [
+            {"vidx": v.index, "vco": v.co.copy(), "moved": False}
+            for v in bm.verts if v.select]
+        self.__intr_verts = [v.index for v in bm.verts if v.select]
+
+    def __update_uv(self, context):
+        """
+        Update UV when vertex coordinates are changed
+        """
+        obj = context.active_object
+        bm = bmesh.from_edit_mesh(obj.data)
+        if common.check_version(2, 73, 0) >= 0:
+            bm.verts.ensure_lookup_table()
+            bm.edges.ensure_lookup_table()
+            bm.faces.ensure_lookup_table()
+
+        if not bm.loops.layers.uv:
+            self.report({'WARNING'}, "Object must have more than one UV map")
+            return
+        uv_layer = bm.loops.layers.uv.verify()
+
+        verts = [v.index for v in bm.verts if v.select]
+        verts_orig = self.__intr_verts_orig
+
+        for vidx, v_orig in zip(verts, verts_orig):
+            if vidx != v_orig["vidx"]:
+                self.report({'ERROR'}, "Internal Error")
+                return
+
+            v = bm.verts[vidx]
+            link_loops = _get_link_loops(v)
+
+            result = []
+            for ll in link_loops:
+                ini_geom = _get_ini_geom(ll, uv_layer, verts_orig, v_orig)
+                target_uv = _get_target_uv(
+                    ll, uv_layer, verts_orig, v, ini_geom)
+                result.append({"l": ll["l"], "uv": target_uv})
+
+            # UV connect option is always true, because it raises
+            # unexpected behavior
+            ave = Vector((0.0, 0.0))
+            for r in result:
+                ave = ave + r["uv"]
+            ave = ave / len(result)
+            for r in result:
+                r["l"][uv_layer].uv = ave
+            v_orig["moved"] = True
+            bmesh.update_edit_mesh(obj.data)
+
+        common.redraw_all_areas()
+        self.__intr_verts_orig = [
+            {"vidx": v.index, "vco": v.co.copy(), "moved": False}
+            for v in bm.verts if v.select]
 
     def modal(self, context, event):
-        return self.__impl.modal(self, context, event)
+        if not _is_valid_context(context):
+            MUV_OT_TextureLock_Intr.handle_remove(context)
+            return {'FINISHED'}
+
+        if not MUV_OT_TextureLock_Intr.is_running(context):
+            return {'FINISHED'}
+
+        if context.area:
+            context.area.tag_redraw()
+
+        if event.type == 'TIMER':
+            if self.__sel_verts_changed(context):
+                self.__reinit_verts(context)
+            else:
+                self.__update_uv(context)
+
+        return {'PASS_THROUGH'}
+
+    def invoke(self, context, _):
+        if not _is_valid_context(context):
+            return {'CANCELLED'}
+
+        if not MUV_OT_TextureLock_Intr.is_running(context):
+            MUV_OT_TextureLock_Intr.handle_add(self, context)
+            return {'RUNNING_MODAL'}
+        else:
+            MUV_OT_TextureLock_Intr.handle_remove(context)
+
+        if context.area:
+            context.area.tag_redraw()
 
-    def invoke(self, context, event):
-        return self.__impl.invoke(self, context, event)
+        return {'FINISHED'}
diff --git a/uv_magic_uv/op/texture_projection.py b/uv_magic_uv/op/texture_projection.py
index f6a3a89f0679d5badce13953ab4cbb0db5c0594c..cb7c25bb125ca2d32d00f06b780d1c72fd3caeda 100644
--- a/uv_magic_uv/op/texture_projection.py
+++ b/uv_magic_uv/op/texture_projection.py
@@ -23,8 +23,9 @@ __status__ = "production"
 __version__ = "5.2"
 __date__ = "17 Nov 2018"
 
+from collections import namedtuple
+
 import bpy
-import bgl
 import bmesh
 from bpy_extras import view3d_utils
 from bpy.props import (
@@ -32,17 +33,118 @@ from bpy.props import (
     EnumProperty,
     FloatProperty,
 )
+import mathutils
 
 from .. import common
 from ..utils.bl_class_registry import BlClassRegistry
 from ..utils.property_class_registry import PropertyClassRegistry
-from ..impl import texture_projection_impl as impl
+from ..utils import compatibility as compat
+
+if compat.check_version(2, 80, 0) >= 0:
+    from ..lib import bglx as bgl
+else:
+    import bgl
+
+
+_Rect = namedtuple('Rect', 'x0 y0 x1 y1')
+_Rect2 = namedtuple('Rect2', 'x y width height')
+
+
+def get_loaded_texture_name(_, __):
+    items = [(key, key, "") for key in bpy.data.images.keys()]
+    items.append(("None", "None", ""))
+    return items
+
+
+def get_canvas(context, magnitude):
+    """
+    Get canvas to be renderred texture
+    """
+    sc = context.scene
+    prefs = compat.get_user_preferences(context).addons["uv_magic_uv"].preferences
+
+    region_w = context.region.width
+    region_h = context.region.height
+    canvas_w = region_w - prefs.texture_projection_canvas_padding[0] * 2.0
+    canvas_h = region_h - prefs.texture_projection_canvas_padding[1] * 2.0
+
+    img = bpy.data.images[sc.muv_texture_projection_tex_image]
+    tex_w = img.size[0]
+    tex_h = img.size[1]
+
+    center_x = region_w * 0.5
+    center_y = region_h * 0.5
+
+    if sc.muv_texture_projection_adjust_window:
+        ratio_x = canvas_w / tex_w
+        ratio_y = canvas_h / tex_h
+        if sc.muv_texture_projection_apply_tex_aspect:
+            ratio = ratio_y if ratio_x > ratio_y else ratio_x
+            len_x = ratio * tex_w
+            len_y = ratio * tex_h
+        else:
+            len_x = canvas_w
+            len_y = canvas_h
+    else:
+        if sc.muv_texture_projection_apply_tex_aspect:
+            len_x = tex_w * magnitude
+            len_y = tex_h * magnitude
+        else:
+            len_x = region_w * magnitude
+            len_y = region_h * magnitude
 
-from ..lib import bglx
+    x0 = int(center_x - len_x * 0.5)
+    y0 = int(center_y - len_y * 0.5)
+    x1 = int(center_x + len_x * 0.5)
+    y1 = int(center_y + len_y * 0.5)
+
+    return _Rect(x0, y0, x1, y1)
+
+
+def rect_to_rect2(rect):
+    """
+    Convert Rect1 to Rect2
+    """
+
+    return _Rect2(rect.x0, rect.y0, rect.x1 - rect.x0, rect.y1 - rect.y0)
+
+
+def region_to_canvas(rg_vec, canvas):
+    """
+    Convert screen region to canvas
+    """
+
+    cv_rect = rect_to_rect2(canvas)
+    cv_vec = mathutils.Vector()
+    cv_vec.x = (rg_vec.x - cv_rect.x) / cv_rect.width
+    cv_vec.y = (rg_vec.y - cv_rect.y) / cv_rect.height
+
+    return cv_vec
+
+
+def is_valid_context(context):
+    obj = context.object
+
+    # only edit mode is allowed to execute
+    if obj is None:
+        return False
+    if obj.type != 'MESH':
+        return False
+    if context.object.mode != 'EDIT':
+        return False
+
+    # only 'VIEW_3D' space is allowed to execute
+    for space in context.area.spaces:
+        if space.type == 'VIEW_3D':
+            break
+    else:
+        return False
+
+    return True
 
 
 @PropertyClassRegistry()
-class Properties:
+class _Properties:
     idname = "texture_projection"
 
     @classmethod
@@ -79,7 +181,7 @@ class Properties:
         scene.muv_texture_projection_tex_image = EnumProperty(
             name="Image",
             description="Texture Image",
-            items=impl.get_loaded_texture_name
+            items=get_loaded_texture_name
         )
         scene.muv_texture_projection_tex_transparency = FloatProperty(
             name="Transparency",
@@ -133,7 +235,7 @@ class MUV_OT_TextureProjection(bpy.types.Operator):
         # we can not get area/space/region from console
         if common.is_console_mode():
             return False
-        return impl.is_valid_context(context)
+        return is_valid_context(context)
 
     @classmethod
     def is_running(cls, _):
@@ -166,7 +268,7 @@ class MUV_OT_TextureProjection(bpy.types.Operator):
         img = bpy.data.images[sc.muv_texture_projection_tex_image]
 
         # setup rendering region
-        rect = impl.get_canvas(context, sc.muv_texture_projection_tex_magnitude)
+        rect = get_canvas(context, sc.muv_texture_projection_tex_magnitude)
         positions = [
             [rect.x0, rect.y0],
             [rect.x0, rect.y1],
@@ -181,21 +283,35 @@ class MUV_OT_TextureProjection(bpy.types.Operator):
         ]
 
         # OpenGL configuration
-        bgl.glEnable(bgl.GL_BLEND)
-        bgl.glEnable(bgl.GL_TEXTURE_2D)
-        bgl.glActiveTexture(bgl.GL_TEXTURE0)
-        if img.bindcode:
-            bind = img.bindcode
-            bgl.glBindTexture(bgl.GL_TEXTURE_2D, bind)
+        if compat.check_version(2, 80, 0) >= 0:
+            bgl.glEnable(bgl.GL_BLEND)
+            bgl.glEnable(bgl.GL_TEXTURE_2D)
+            bgl.glActiveTexture(bgl.GL_TEXTURE0)
+            if img.bindcode:
+                bind = img.bindcode
+                bgl.glBindTexture(bgl.GL_TEXTURE_2D, bind)
+        else:
+            bgl.glEnable(bgl.GL_BLEND)
+            bgl.glEnable(bgl.GL_TEXTURE_2D)
+            if img.bindcode:
+                bind = img.bindcode[0]
+                bgl.glBindTexture(bgl.GL_TEXTURE_2D, bind)
+                bgl.glTexParameteri(
+                    bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_MIN_FILTER, bgl.GL_LINEAR)
+                bgl.glTexParameteri(
+                    bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_MAG_FILTER, bgl.GL_LINEAR)
+                bgl.glTexEnvi(
+                    bgl.GL_TEXTURE_ENV, bgl.GL_TEXTURE_ENV_MODE,
+                    bgl.GL_MODULATE)
 
         # render texture
-        bglx.glBegin(bglx.GL_QUADS)
-        bglx.glColor4f(1.0, 1.0, 1.0,
+        bgl.glBegin(bgl.GL_QUADS)
+        bgl.glColor4f(1.0, 1.0, 1.0,
                        sc.muv_texture_projection_tex_transparency)
         for (v1, v2), (u, v) in zip(positions, tex_coords):
-            bglx.glTexCoord2f(u, v)
-            bglx.glVertex2f(v1, v2)
-        bglx.glEnd()
+            bgl.glTexCoord2f(u, v)
+            bgl.glVertex2f(v1, v2)
+        bgl.glEnd()
 
     def invoke(self, context, _):
         if not MUV_OT_TextureProjection.is_running(context):
@@ -227,7 +343,7 @@ class MUV_OT_TextureProjection_Project(bpy.types.Operator):
             return True
         if not MUV_OT_TextureProjection.is_running(context):
             return False
-        return impl.is_valid_context(context)
+        return is_valid_context(context)
 
     def execute(self, context):
         sc = context.scene
@@ -255,6 +371,9 @@ class MUV_OT_TextureProjection_Project(bpy.types.Operator):
                 return {'CANCELLED'}
 
         uv_layer = bm.loops.layers.uv.verify()
+        if compat.check_version(2, 80, 0) < 0:
+            tex_layer = bm.faces.layers.tex.verify()
+
         sel_faces = [f for f in bm.faces if f.select]
 
         # transform 3d space to screen region
@@ -262,26 +381,30 @@ class MUV_OT_TextureProjection_Project(bpy.types.Operator):
             view3d_utils.location_3d_to_region_2d(
                 region,
                 space.region_3d,
-                world_mat @ l.vert.co)
+                compat.matmul(world_mat, l.vert.co))
             for f in sel_faces for l in f.loops
         ]
 
         # transform screen region to canvas
         v_canvas = [
-            impl.region_to_canvas(
+            region_to_canvas(
                 v,
-                impl.get_canvas(bpy.context,
-                                sc.muv_texture_projection_tex_magnitude)
+                get_canvas(bpy.context,
+                           sc.muv_texture_projection_tex_magnitude)
             ) for v in v_screen
         ]
 
-        # set texture
-        nodes = common.find_texture_nodes(obj)
-        nodes[0].image = bpy.data.images[sc.muv_texture_projection_tex_image]
+        if compat.check_version(2, 80, 0) >= 0:
+            # set texture
+            nodes = common.find_texture_nodes(obj)
+            nodes[0].image = bpy.data.images[sc.muv_texture_projection_tex_image]
 
         # project texture to object
         i = 0
         for f in sel_faces:
+            if compat.check_version(2, 80, 0) < 0:
+                f[tex_layer].image = \
+                    bpy.data.images[sc.muv_texture_projection_tex_image]
             for l in f.loops:
                 l[uv_layer].uv = v_canvas[i].to_2d()
                 i = i + 1
diff --git a/uv_magic_uv/op/texture_wrap.py b/uv_magic_uv/op/texture_wrap.py
index 70fb66049867fb5fde8946bf0467e0a3266c3017..c78ffed9ced4644ed52d2d5f798e7444fe6fe64b 100644
--- a/uv_magic_uv/op/texture_wrap.py
+++ b/uv_magic_uv/op/texture_wrap.py
@@ -27,10 +27,32 @@ import bpy
 from bpy.props import (
     BoolProperty,
 )
+import bmesh
 
+from .. import common
 from ..utils.bl_class_registry import BlClassRegistry
 from ..utils.property_class_registry import PropertyClassRegistry
-from ..impl import texture_wrap_impl as impl
+
+
+def _is_valid_context(context):
+    obj = context.object
+
+    # only edit mode is allowed to execute
+    if obj is None:
+        return False
+    if obj.type != 'MESH':
+        return False
+    if context.object.mode != 'EDIT':
+        return False
+
+    # only 'VIEW_3D' space is allowed to execute
+    for space in context.area.spaces:
+        if space.type == 'VIEW_3D':
+            break
+    else:
+        return False
+
+    return True
 
 
 @PropertyClassRegistry()
@@ -80,15 +102,33 @@ class MUV_OT_TextureWrap_Refer(bpy.types.Operator):
     bl_description = "Refer UV"
     bl_options = {'REGISTER', 'UNDO'}
 
-    def __init__(self):
-        self.__impl = impl.ReferImpl()
-
     @classmethod
     def poll(cls, context):
-        return impl.ReferImpl.poll(context)
+        # we can not get area/space/region from console
+        if common.is_console_mode():
+            return True
+        return _is_valid_context(context)
 
     def execute(self, context):
-        return self.__impl.execute(self, context)
+        props = context.scene.muv_props.texture_wrap
+        obj = context.active_object
+        bm = bmesh.from_edit_mesh(obj.data)
+        if common.check_version(2, 73, 0) >= 0:
+            bm.faces.ensure_lookup_table()
+
+        if not bm.loops.layers.uv:
+            self.report({'WARNING'}, "Object must have more than one UV map")
+            return {'CANCELLED'}
+
+        sel_faces = [f for f in bm.faces if f.select]
+        if len(sel_faces) != 1:
+            self.report({'WARNING'}, "Must select only one face")
+            return {'CANCELLED'}
+
+        props.ref_face_index = sel_faces[0].index
+        props.ref_obj = obj
+
+        return {'FINISHED'}
 
 
 @BlClassRegistry()
@@ -102,12 +142,153 @@ class MUV_OT_TextureWrap_Set(bpy.types.Operator):
     bl_description = "Set UV"
     bl_options = {'REGISTER', 'UNDO'}
 
-    def __init__(self):
-        self.__impl = impl.SetImpl()
-
     @classmethod
     def poll(cls, context):
-        return impl.SetImpl.poll(context)
+        # we can not get area/space/region from console
+        if common.is_console_mode():
+            return True
+        sc = context.scene
+        props = sc.muv_props.texture_wrap
+        if not props.ref_obj:
+            return False
+        return _is_valid_context(context)
 
     def execute(self, context):
-        return self.__impl.execute(self, context)
+        sc = context.scene
+        props = sc.muv_props.texture_wrap
+        obj = context.active_object
+        bm = bmesh.from_edit_mesh(obj.data)
+        if common.check_version(2, 73, 0) >= 0:
+            bm.faces.ensure_lookup_table()
+
+        if not bm.loops.layers.uv:
+            self.report({'WARNING'}, "Object must have more than one UV map")
+            return {'CANCELLED'}
+        uv_layer = bm.loops.layers.uv.verify()
+
+        if sc.muv_texture_wrap_selseq:
+            sel_faces = []
+            for hist in bm.select_history:
+                if isinstance(hist, bmesh.types.BMFace) and hist.select:
+                    sel_faces.append(hist)
+            if not sel_faces:
+                self.report({'WARNING'}, "Must select more than one face")
+                return {'CANCELLED'}
+        else:
+            sel_faces = [f for f in bm.faces if f.select]
+            if len(sel_faces) != 1:
+                self.report({'WARNING'}, "Must select only one face")
+                return {'CANCELLED'}
+
+        ref_face_index = props.ref_face_index
+        for face in sel_faces:
+            tgt_face_index = face.index
+            if ref_face_index == tgt_face_index:
+                self.report({'WARNING'}, "Must select different face")
+                return {'CANCELLED'}
+
+            if props.ref_obj != obj:
+                self.report({'WARNING'}, "Object must be same")
+                return {'CANCELLED'}
+
+            ref_face = bm.faces[ref_face_index]
+            tgt_face = bm.faces[tgt_face_index]
+
+            # get common vertices info
+            common_verts = []
+            for sl in ref_face.loops:
+                for dl in tgt_face.loops:
+                    if sl.vert == dl.vert:
+                        info = {"vert": sl.vert, "ref_loop": sl,
+                                "tgt_loop": dl}
+                        common_verts.append(info)
+                        break
+
+            if len(common_verts) != 2:
+                self.report({'WARNING'},
+                            "2 vertices must be shared among faces")
+                return {'CANCELLED'}
+
+            # get reference other vertices info
+            ref_other_verts = []
+            for sl in ref_face.loops:
+                for ci in common_verts:
+                    if sl.vert == ci["vert"]:
+                        break
+                else:
+                    info = {"vert": sl.vert, "loop": sl}
+                    ref_other_verts.append(info)
+
+            if not ref_other_verts:
+                self.report({'WARNING'}, "More than 1 vertex must be unshared")
+                return {'CANCELLED'}
+
+            # get reference info
+            ref_info = {}
+            cv0 = common_verts[0]["vert"].co
+            cv1 = common_verts[1]["vert"].co
+            cuv0 = common_verts[0]["ref_loop"][uv_layer].uv
+            cuv1 = common_verts[1]["ref_loop"][uv_layer].uv
+            ov0 = ref_other_verts[0]["vert"].co
+            ouv0 = ref_other_verts[0]["loop"][uv_layer].uv
+            ref_info["vert_vdiff"] = cv1 - cv0
+            ref_info["uv_vdiff"] = cuv1 - cuv0
+            ref_info["vert_hdiff"], _ = common.diff_point_to_segment(
+                cv0, cv1, ov0)
+            ref_info["uv_hdiff"], _ = common.diff_point_to_segment(
+                cuv0, cuv1, ouv0)
+
+            # get target other vertices info
+            tgt_other_verts = []
+            for dl in tgt_face.loops:
+                for ci in common_verts:
+                    if dl.vert == ci["vert"]:
+                        break
+                else:
+                    info = {"vert": dl.vert, "loop": dl}
+                    tgt_other_verts.append(info)
+
+            if not tgt_other_verts:
+                self.report({'WARNING'}, "More than 1 vertex must be unshared")
+                return {'CANCELLED'}
+
+            # get target info
+            for info in tgt_other_verts:
+                cv0 = common_verts[0]["vert"].co
+                cv1 = common_verts[1]["vert"].co
+                cuv0 = common_verts[0]["ref_loop"][uv_layer].uv
+                ov = info["vert"].co
+                info["vert_hdiff"], x = common.diff_point_to_segment(
+                    cv0, cv1, ov)
+                info["vert_vdiff"] = x - common_verts[0]["vert"].co
+
+                # calclulate factor
+                fact_h = -info["vert_hdiff"].length / \
+                    ref_info["vert_hdiff"].length
+                fact_v = info["vert_vdiff"].length / \
+                    ref_info["vert_vdiff"].length
+                duv_h = ref_info["uv_hdiff"] * fact_h
+                duv_v = ref_info["uv_vdiff"] * fact_v
+
+                # get target UV
+                info["target_uv"] = cuv0 + duv_h + duv_v
+
+            # apply to common UVs
+            for info in common_verts:
+                info["tgt_loop"][uv_layer].uv = \
+                    info["ref_loop"][uv_layer].uv.copy()
+            # apply to other UVs
+            for info in tgt_other_verts:
+                info["loop"][uv_layer].uv = info["target_uv"]
+
+            common.debug_print("===== Target Other Vertices =====")
+            common.debug_print(tgt_other_verts)
+
+            bmesh.update_edit_mesh(obj.data)
+
+            ref_face_index = tgt_face_index
+
+        if sc.muv_texture_wrap_set_and_refer:
+            props.ref_face_index = tgt_face_index
+
+        return {'FINISHED'}
diff --git a/uv_magic_uv/op/transfer_uv.py b/uv_magic_uv/op/transfer_uv.py
index db05b34379ef8c6da680abc5292b4515802c23e5..25d430b9bb24863ff033e732eb2e60addfa6d15a 100644
--- a/uv_magic_uv/op/transfer_uv.py
+++ b/uv_magic_uv/op/transfer_uv.py
@@ -23,25 +23,307 @@ __status__ = "production"
 __version__ = "5.2"
 __date__ = "17 Nov 2018"
 
+from collections import OrderedDict
+
 import bpy
 import bmesh
 from bpy.props import BoolProperty
 
 from .. import common
-from ..impl import transfer_uv_impl as impl
 from ..utils.bl_class_registry import BlClassRegistry
 from ..utils.property_class_registry import PropertyClassRegistry
+from ..utils import compatibility as compat
+
+
+def _is_valid_context(context):
+    obj = context.object
+
+    # only edit mode is allowed to execute
+    if obj is None:
+        return False
+    if obj.type != 'MESH':
+        return False
+    if context.object.mode != 'EDIT':
+        return False
+
+    # only 'VIEW_3D' space is allowed to execute
+    for space in context.area.spaces:
+        if space.type == 'VIEW_3D':
+            break
+    else:
+        return False
+
+    return True
+
+
+def _get_uv_layer(ops_obj, bm):
+    # get UV layer
+    if not bm.loops.layers.uv:
+        ops_obj.report({'WARNING'}, "Object must have more than one UV map")
+        return None
+    uv_layer = bm.loops.layers.uv.verify()
+
+    return uv_layer
+
+
+def _main_parse(ops_obj, uv_layer, sel_faces, active_face, active_face_nor):
+    all_sorted_faces = OrderedDict()  # This is the main stuff
+
+    used_verts = set()
+    used_edges = set()
+
+    faces_to_parse = []
+
+    # get shared edge of two faces
+    cross_edges = []
+    for edge in active_face.edges:
+        if edge in sel_faces[0].edges and edge in sel_faces[1].edges:
+            cross_edges.append(edge)
+
+    # parse two selected faces
+    if cross_edges and len(cross_edges) == 1:
+        shared_edge = cross_edges[0]
+        vert1 = None
+        vert2 = None
+
+        dot_n = active_face_nor.normalized()
+        edge_vec_1 = (shared_edge.verts[1].co - shared_edge.verts[0].co)
+        edge_vec_len = edge_vec_1.length
+        edge_vec_1 = edge_vec_1.normalized()
+
+        af_center = active_face.calc_center_median()
+        af_vec = shared_edge.verts[0].co + (edge_vec_1 * (edge_vec_len * 0.5))
+        af_vec = (af_vec - af_center).normalized()
+
+        if af_vec.cross(edge_vec_1).dot(dot_n) > 0:
+            vert1 = shared_edge.verts[0]
+            vert2 = shared_edge.verts[1]
+        else:
+            vert1 = shared_edge.verts[1]
+            vert2 = shared_edge.verts[0]
+
+        # get active face stuff and uvs
+        face_stuff = _get_other_verts_edges(
+            active_face, vert1, vert2, shared_edge, uv_layer)
+        all_sorted_faces[active_face] = face_stuff
+        used_verts.update(active_face.verts)
+        used_edges.update(active_face.edges)
+
+        # get first selected face stuff and uvs as they share shared_edge
+        second_face = sel_faces[0]
+        if second_face is active_face:
+            second_face = sel_faces[1]
+        face_stuff = _get_other_verts_edges(
+            second_face, vert1, vert2, shared_edge, uv_layer)
+        all_sorted_faces[second_face] = face_stuff
+        used_verts.update(second_face.verts)
+        used_edges.update(second_face.edges)
+
+        # first Grow
+        faces_to_parse.append(active_face)
+        faces_to_parse.append(second_face)
+
+    else:
+        ops_obj.report({'WARNING'}, "Two faces should share one edge")
+        return None
+
+    # parse all faces
+    while True:
+        new_parsed_faces = []
+        if not faces_to_parse:
+            break
+        for face in faces_to_parse:
+            face_stuff = all_sorted_faces.get(face)
+            new_faces = _parse_faces(face, face_stuff, used_verts, used_edges,
+                                     all_sorted_faces, uv_layer)
+            if new_faces is None:
+                ops_obj.report({'WARNING'}, "More than 2 faces share edge")
+                return None
+
+            new_parsed_faces += new_faces
+        faces_to_parse = new_parsed_faces
+
+    return all_sorted_faces
+
+
+def _parse_faces(check_face, face_stuff, used_verts, used_edges,
+                 all_sorted_faces, uv_layer):
+    """recurse faces around the new_grow only"""
+
+    new_shared_faces = []
+    for sorted_edge in face_stuff[1]:
+        shared_faces = sorted_edge.link_faces
+        if shared_faces:
+            if len(shared_faces) > 2:
+                bpy.ops.mesh.select_all(action='DESELECT')
+                for face_sel in shared_faces:
+                    face_sel.select = True
+                shared_faces = []
+                return None
+
+            clear_shared_faces = _get_new_shared_faces(
+                check_face, sorted_edge, shared_faces, all_sorted_faces.keys())
+            if clear_shared_faces:
+                shared_face = clear_shared_faces[0]
+                # get vertices of the edge
+                vert1 = sorted_edge.verts[0]
+                vert2 = sorted_edge.verts[1]
+
+                common.debug_print(face_stuff[0], vert1, vert2)
+                if face_stuff[0].index(vert1) > face_stuff[0].index(vert2):
+                    vert1 = sorted_edge.verts[1]
+                    vert2 = sorted_edge.verts[0]
+
+                common.debug_print(shared_face.verts, vert1, vert2)
+                new_face_stuff = _get_other_verts_edges(
+                    shared_face, vert1, vert2, sorted_edge, uv_layer)
+                all_sorted_faces[shared_face] = new_face_stuff
+                used_verts.update(shared_face.verts)
+                used_edges.update(shared_face.edges)
 
+                if common.is_debug_mode():
+                    shared_face.select = True  # test which faces are parsed
 
-__all__ = [
-    'Properties',
-    'MUV_OT_TransferUV_CopyUV',
-    'MUV_OT_TransferUV_PasteUV',
-]
+                new_shared_faces.append(shared_face)
+
+    return new_shared_faces
+
+
+def _get_new_shared_faces(orig_face, shared_edge, check_faces, used_faces):
+    shared_faces = []
+
+    for face in check_faces:
+        is_shared_edge = shared_edge in face.edges
+        not_used = face not in used_faces
+        not_orig = face is not orig_face
+        not_hide = face.hide is False
+        if is_shared_edge and not_used and not_orig and not_hide:
+            shared_faces.append(face)
+
+    return shared_faces
+
+
+def _get_other_verts_edges(face, vert1, vert2, first_edge, uv_layer):
+    face_edges = [first_edge]
+    face_verts = [vert1, vert2]
+    face_loops = []
+
+    other_edges = [edge for edge in face.edges if edge not in face_edges]
+
+    for _ in range(len(other_edges)):
+        found_edge = None
+        # get sorted verts and edges
+        for edge in other_edges:
+            if face_verts[-1] in edge.verts:
+                other_vert = edge.other_vert(face_verts[-1])
+
+                if other_vert not in face_verts:
+                    face_verts.append(other_vert)
+
+                found_edge = edge
+                if found_edge not in face_edges:
+                    face_edges.append(edge)
+                break
+
+        other_edges.remove(found_edge)
+
+    # get sorted uvs
+    for vert in face_verts:
+        for loop in face.loops:
+            if loop.vert is vert:
+                face_loops.append(loop[uv_layer])
+                break
+
+    return [face_verts, face_edges, face_loops]
+
+
+def _get_selected_src_faces(ops_obj, bm, uv_layer):
+    topology_copied = []
+
+    # get selected faces
+    active_face = bm.faces.active
+    sel_faces = [face for face in bm.faces if face.select]
+    if len(sel_faces) != 2:
+        ops_obj.report({'WARNING'}, "Two faces must be selected")
+        return None
+    if not active_face or active_face not in sel_faces:
+        ops_obj.report({'WARNING'}, "Two faces must be active")
+        return None
+
+    # parse all faces according to selection
+    active_face_nor = active_face.normal.copy()
+    all_sorted_faces = _main_parse(ops_obj, uv_layer, sel_faces, active_face,
+                                   active_face_nor)
+
+    if all_sorted_faces:
+        for face_data in all_sorted_faces.values():
+            edges = face_data[1]
+            uv_loops = face_data[2]
+            uvs = [l.uv.copy() for l in uv_loops]
+            pin_uvs = [l.pin_uv for l in uv_loops]
+            seams = [e.seam for e in edges]
+            topology_copied.append([uvs, pin_uvs, seams])
+    else:
+        return None
+
+    return topology_copied
+
+
+def _paste_uv(ops_obj, bm, uv_layer, src_faces, invert_normals, copy_seams):
+    # get selection history
+    all_sel_faces = [e for e in bm.select_history
+                     if isinstance(e, bmesh.types.BMFace) and e.select]
+    if len(all_sel_faces) % 2 != 0:
+        ops_obj.report({'WARNING'}, "Two faces must be selected")
+        return -1
+
+    # parse selection history
+    for i, _ in enumerate(all_sel_faces):
+        if (i == 0) or (i % 2 == 0):
+            continue
+        sel_faces = [all_sel_faces[i - 1], all_sel_faces[i]]
+        active_face = all_sel_faces[i]
+
+        # parse all faces according to selection history
+        active_face_nor = active_face.normal.copy()
+        if invert_normals:
+            active_face_nor.negate()
+        all_sorted_faces = _main_parse(ops_obj, uv_layer, sel_faces,
+                                       active_face, active_face_nor)
+
+        if all_sorted_faces:
+            # check amount of copied/pasted faces
+            if len(all_sorted_faces) != len(src_faces):
+                ops_obj.report({'WARNING'},
+                               "Mesh has different amount of faces")
+                return -1
+
+            for j, face_data in enumerate(all_sorted_faces.values()):
+                copied_data = src_faces[j]
+
+                # check amount of copied/pasted verts
+                if len(copied_data[0]) != len(face_data[2]):
+                    bpy.ops.mesh.select_all(action='DESELECT')
+                    # select problematic face
+                    list(all_sorted_faces.keys())[j].select = True
+                    ops_obj.report({'WARNING'},
+                                   "Face have different amount of vertices")
+                    return 0
+
+                for k, (edge, uvloop) in enumerate(zip(face_data[1],
+                                                       face_data[2])):
+                    uvloop.uv = copied_data[0][k]
+                    uvloop.pin_uv = copied_data[1][k]
+                    if copy_seams:
+                        edge.seam = copied_data[2][k]
+        else:
+            return -1
+
+    return 0
 
 
 @PropertyClassRegistry()
-class Properties:
+class _Properties:
     idname = "transfer_uv"
 
     @classmethod
@@ -91,19 +373,20 @@ class MUV_OT_TransferUV_CopyUV(bpy.types.Operator):
         # we can not get area/space/region from console
         if common.is_console_mode():
             return True
-        return impl.is_valid_context(context)
+        return _is_valid_context(context)
 
     def execute(self, context):
         props = context.scene.muv_props.transfer_uv
-        active_obj = context.active_object
+        active_obj = compat.get_active_object(context)
         bm = bmesh.from_edit_mesh(active_obj.data)
-        bm.faces.ensure_lookup_table()
+        if compat.check_version(2, 73, 0) >= 0:
+            bm.faces.ensure_lookup_table()
 
-        uv_layer = impl.get_uv_layer(self, bm)
+        uv_layer = _get_uv_layer(self, bm)
         if uv_layer is None:
             return {'CANCELLED'}
 
-        faces = impl.get_selected_src_faces(self, bm, uv_layer)
+        faces = _get_selected_src_faces(self, bm, uv_layer)
         if faces is None:
             return {'CANCELLED'}
         props.topology_copied = faces
@@ -114,6 +397,7 @@ class MUV_OT_TransferUV_CopyUV(bpy.types.Operator):
 
 
 @BlClassRegistry()
+@compat.make_annotations
 class MUV_OT_TransferUV_PasteUV(bpy.types.Operator):
     """
         Operation class: Transfer UV paste
@@ -125,12 +409,12 @@ class MUV_OT_TransferUV_PasteUV(bpy.types.Operator):
     bl_description = "Transfer UV Paste UV (Topological based paste)"
     bl_options = {'REGISTER', 'UNDO'}
 
-    invert_normals: BoolProperty(
+    invert_normals = BoolProperty(
         name="Invert Normals",
         description="Invert Normals",
         default=False
     )
-    copy_seams: BoolProperty(
+    copy_seams = BoolProperty(
         name="Copy Seams",
         description="Copy Seams",
         default=True
@@ -145,24 +429,29 @@ class MUV_OT_TransferUV_PasteUV(bpy.types.Operator):
         props = sc.muv_props.transfer_uv
         if not props.topology_copied:
             return False
-        return impl.is_valid_context(context)
+        return _is_valid_context(context)
 
     def execute(self, context):
         props = context.scene.muv_props.transfer_uv
-        active_obj = context.active_object
+        active_obj = compat.get_active_object(context)
         bm = bmesh.from_edit_mesh(active_obj.data)
-        bm.faces.ensure_lookup_table()
+        if compat.check_version(2, 73, 0) >= 0:
+            bm.faces.ensure_lookup_table()
 
         # get UV layer
-        uv_layer = impl.get_uv_layer(self, bm)
+        uv_layer = _get_uv_layer(self, bm)
         if uv_layer is None:
             return {'CANCELLED'}
 
-        ret = impl.paste_uv(self, bm, uv_layer, props.topology_copied,
-                            self.invert_normals, self.copy_seams)
+        ret = _paste_uv(self, bm, uv_layer, props.topology_copied,
+                        self.invert_normals, self.copy_seams)
         if ret:
             return {'CANCELLED'}
 
         bmesh.update_edit_mesh(active_obj.data)
 
+        if compat.check_version(2, 80, 0) < 0:
+            if self.copy_seams:
+                active_obj.data.show_edge_seams = True
+
         return {'FINISHED'}
diff --git a/uv_magic_uv/op/unwrap_constraint.py b/uv_magic_uv/op/unwrap_constraint.py
index df16f7834920c72306b107253f7baa0167049f36..897271601d63a3f09c7fcb6649aa2f1ac633dbcd 100644
--- a/uv_magic_uv/op/unwrap_constraint.py
+++ b/uv_magic_uv/op/unwrap_constraint.py
@@ -27,10 +27,33 @@ from bpy.props import (
     EnumProperty,
     FloatProperty,
 )
+import bmesh
 
+from .. import common
 from ..utils.bl_class_registry import BlClassRegistry
 from ..utils.property_class_registry import PropertyClassRegistry
-from ..impl import unwrap_constraint_impl as impl
+from ..utils import compatibility as compat
+
+
+def _is_valid_context(context):
+    obj = context.object
+
+    # only edit mode is allowed to execute
+    if obj is None:
+        return False
+    if obj.type != 'MESH':
+        return False
+    if context.object.mode != 'EDIT':
+        return False
+
+    # only 'VIEW_3D' space is allowed to execute
+    for space in context.area.spaces:
+        if space.type == 'VIEW_3D':
+            break
+    else:
+        return False
+
+    return True
 
 
 @PropertyClassRegistry()
@@ -63,6 +86,7 @@ class _Properties:
 
 
 @BlClassRegistry(legacy=True)
+@compat.make_annotations
 class MUV_OT_UnwrapConstraint(bpy.types.Operator):
     """
     Operation class: Unwrap with constrain UV coordinate
@@ -74,7 +98,7 @@ class MUV_OT_UnwrapConstraint(bpy.types.Operator):
     bl_options = {'REGISTER', 'UNDO'}
 
     # property for original unwrap
-    method: EnumProperty(
+    method = EnumProperty(
         name="Method",
         description="Unwrapping method",
         items=[
@@ -82,20 +106,20 @@ class MUV_OT_UnwrapConstraint(bpy.types.Operator):
             ('CONFORMAL', 'Conformal', 'Conformal')
         ],
         default='ANGLE_BASED')
-    fill_holes: BoolProperty(
+    fill_holes = BoolProperty(
         name="Fill Holes",
         description="Virtual fill holes in meshes before unwrapping",
         default=True)
-    correct_aspect: BoolProperty(
+    correct_aspect = BoolProperty(
         name="Correct Aspect",
         description="Map UVs taking image aspect ratio into account",
         default=True)
-    use_subsurf_data: BoolProperty(
+    use_subsurf_data = BoolProperty(
         name="Use Subsurf Modifier",
         description="""Map UVs taking vertex position after subsurf
                        into account""",
         default=False)
-    margin: FloatProperty(
+    margin = FloatProperty(
         name="Margin",
         description="Space between islands",
         max=1.0,
@@ -103,23 +127,60 @@ class MUV_OT_UnwrapConstraint(bpy.types.Operator):
         default=0.001)
 
     # property for this operation
-    u_const: BoolProperty(
+    u_const = BoolProperty(
         name="U-Constraint",
         description="Keep UV U-axis coordinate",
         default=False
     )
-    v_const: BoolProperty(
+    v_const = BoolProperty(
         name="V-Constraint",
         description="Keep UV V-axis coordinate",
         default=False
     )
 
-    def __init__(self):
-        self.__impl = impl.UnwrapConstraintImpl()
-
     @classmethod
     def poll(cls, context):
-        return impl.UnwrapConstraintImpl.poll(context)
+        # we can not get area/space/region from console
+        if common.is_console_mode():
+            return True
+        return _is_valid_context(context)
 
     def execute(self, context):
-        return self.__impl.execute(self, context)
+        obj = context.active_object
+        bm = bmesh.from_edit_mesh(obj.data)
+        if common.check_version(2, 73, 0) >= 0:
+            bm.faces.ensure_lookup_table()
+
+        # bpy.ops.uv.unwrap() makes one UV map at least
+        if not bm.loops.layers.uv:
+            self.report({'WARNING'}, "Object must have more than one UV map")
+            return {'CANCELLED'}
+        uv_layer = bm.loops.layers.uv.verify()
+
+        # get original UV coordinate
+        faces = [f for f in bm.faces if f.select]
+        uv_list = []
+        for f in faces:
+            uvs = [l[uv_layer].uv.copy() for l in f.loops]
+            uv_list.append(uvs)
+
+        # unwrap
+        bpy.ops.uv.unwrap(
+            method=self.method,
+            fill_holes=self.fill_holes,
+            correct_aspect=self.correct_aspect,
+            use_subsurf_data=self.use_subsurf_data,
+            margin=self.margin)
+
+        # when U/V-Constraint is checked, revert original coordinate
+        for f, uvs in zip(faces, uv_list):
+            for l, uv in zip(f.loops, uvs):
+                if self.u_const:
+                    l[uv_layer].uv.x = uv.x
+                if self.v_const:
+                    l[uv_layer].uv.y = uv.y
+
+        # update mesh
+        bmesh.update_edit_mesh(obj.data)
+
+        return {'FINISHED'}
diff --git a/uv_magic_uv/op/uv_bounding_box.py b/uv_magic_uv/op/uv_bounding_box.py
index 82cdea45a8361e97ce3dc2499f4251a218af161b..4839934bb783fbe9b6bc20941ba11d8cf39b07cb 100644
--- a/uv_magic_uv/op/uv_bounding_box.py
+++ b/uv_magic_uv/op/uv_bounding_box.py
@@ -27,7 +27,6 @@ from enum import IntEnum
 import math
 
 import bpy
-import bgl
 import mathutils
 import bmesh
 from bpy.props import BoolProperty, EnumProperty
@@ -35,14 +34,40 @@ from bpy.props import BoolProperty, EnumProperty
 from .. import common
 from ..utils.bl_class_registry import BlClassRegistry
 from ..utils.property_class_registry import PropertyClassRegistry
-from ..impl import uv_bounding_box_impl as impl
+from ..utils import compatibility as compat
 
-from ..lib import bglx
+if compat.check_version(2, 80, 0) >= 0:
+    from ..lib import bglx as bgl
+else:
+    import bgl
 
 
 MAX_VALUE = 100000.0
 
 
+def _is_valid_context(context):
+    obj = context.object
+
+    # only edit mode is allowed to execute
+    if obj is None:
+        return False
+    if obj.type != 'MESH':
+        return False
+    if context.object.mode != 'EDIT':
+        return False
+
+    # 'IMAGE_EDITOR' and 'VIEW_3D' space is allowed to execute.
+    # If 'View_3D' space is not allowed, you can't find option in Tool-Shelf
+    # after the execution
+    for space in context.area.spaces:
+        if (space.type == 'IMAGE_EDITOR') or (space.type == 'VIEW_3D'):
+            break
+    else:
+        return False
+
+    return True
+
+
 @PropertyClassRegistry()
 class _Properties:
     idname = "uv_bounding_box"
@@ -166,7 +191,7 @@ class RotationCommand(CommandBase):
         mti = mathutils.Matrix.Translation((-self.__cx, -self.__cy, 0.0))
         mr = mathutils.Matrix.Rotation(angle, 4, 'Z')
         mt = mathutils.Matrix.Translation((self.__cx, self.__cy, 0.0))
-        return mt @ mr @ mti
+        return compat.matmul(compat.matmul(mt, mr), mti)
 
     def set(self, x, y):
         self.__x = x
@@ -191,7 +216,7 @@ class ScalingCommand(CommandBase):
         self.__dir_y = dir_y    # direction of scaling y
         self.__mat = mat
         # initial origin of scaling = M(to original transform) * (ox, oy)
-        iov = mat @ mathutils.Vector((ox, oy, 0.0))
+        iov = compat.matmul(mat, mathutils.Vector((ox, oy, 0.0)))
         self.__iox = iov.x      # initial origin of scaling X
         self.__ioy = iov.y      # initial origin of scaling y
 
@@ -205,11 +230,11 @@ class ScalingCommand(CommandBase):
         mtoi = mathutils.Matrix.Translation((-self.__iox, -self.__ioy, 0.0))
         mto = mathutils.Matrix.Translation((self.__iox, self.__ioy, 0.0))
         # every point must be transformed to origin
-        t = m @ mathutils.Vector((self.__ix, self.__iy, 0.0))
+        t = compat.matmul(m, mathutils.Vector((self.__ix, self.__iy, 0.0)))
         tix, tiy = t.x, t.y
-        t = m @ mathutils.Vector((self.__ox, self.__oy, 0.0))
+        t = compat.matmul(m, mathutils.Vector((self.__ox, self.__oy, 0.0)))
         tox, toy = t.x, t.y
-        t = m @ mathutils.Vector((self.__x, self.__y, 0.0))
+        t = compat.matmul(m, mathutils.Vector((self.__x, self.__y, 0.0)))
         tx, ty = t.x, t.y
         ms = mathutils.Matrix()
         ms.identity()
@@ -217,7 +242,8 @@ class ScalingCommand(CommandBase):
             ms[0][0] = (tx - tox) * self.__dir_x / (tix - tox)
         if self.__dir_y == 1:
             ms[1][1] = (ty - toy) * self.__dir_y / (tiy - toy)
-        return mi @ mto @ ms @ mtoi @ m
+        return compat.matmul(compat.matmul(compat.matmul(
+                        compat.matmul(mi, mto), ms), mtoi), m)
 
     def set(self, x, y):
         self.__x = x
@@ -240,7 +266,7 @@ class UniformScalingCommand(CommandBase):
         self.__oy = oy          # origin of scaling y
         self.__mat = mat
         # initial origin of scaling = M(to original transform) * (ox, oy)
-        iov = mat @ mathutils.Vector((ox, oy, 0.0))
+        iov = compat.matmul(mat, mathutils.Vector((ox, oy, 0.0)))
         self.__iox = iov.x      # initial origin of scaling x
         self.__ioy = iov.y      # initial origin of scaling y
         self.__dir_x = 1
@@ -256,11 +282,11 @@ class UniformScalingCommand(CommandBase):
         mtoi = mathutils.Matrix.Translation((-self.__iox, -self.__ioy, 0.0))
         mto = mathutils.Matrix.Translation((self.__iox, self.__ioy, 0.0))
         # every point must be transformed to origin
-        t = m @ mathutils.Vector((self.__ix, self.__iy, 0.0))
+        t = compat.matmul(m, mathutils.Vector((self.__ix, self.__iy, 0.0)))
         tix, tiy = t.x, t.y
-        t = m @ mathutils.Vector((self.__ox, self.__oy, 0.0))
+        t = compat.matmul(m, mathutils.Vector((self.__ox, self.__oy, 0.0)))
         tox, toy = t.x, t.y
-        t = m @ mathutils.Vector((self.__x, self.__y, 0.0))
+        t = compat.matmul(m, mathutils.Vector((self.__x, self.__y, 0.0)))
         tx, ty = t.x, t.y
         ms = mathutils.Matrix()
         ms.identity()
@@ -281,7 +307,8 @@ class UniformScalingCommand(CommandBase):
         ms[0][0] = sr * self.__dir_x
         ms[1][1] = sr * self.__dir_y
 
-        return mi @ mto @ ms @ mtoi @ m
+        return compat.matmul(compat.matmul(compat.matmul(
+                        compat.matmul(mi, mto), ms), mtoi), m)
 
     def set(self, x, y):
         self.__x = x
@@ -305,7 +332,7 @@ class CommandExecuter:
         mat.identity()
         for i, cmd in enumerate(self.__cmd_list):
             if begin <= i and (end == -1 or i <= end):
-                mat = cmd.to_matrix() @ mat
+                mat = compat.matmul(cmd.to_matrix(), mat)
         return mat
 
     def undo_size(self):
@@ -402,7 +429,7 @@ class StateNone(StateBase):
         """
         Update state
         """
-        prefs = context.user_preferences.addons["uv_magic_uv"].preferences
+        prefs = compat.get_user_preferences(context).addons["uv_magic_uv"].preferences
         cp_react_size = prefs.uv_bounding_box_cp_react_size
         is_uscaling = context.scene.muv_uv_bounding_box_uniform_scaling
         if (event.type == 'LEFTMOUSE') and (event.value == 'PRESS'):
@@ -602,7 +629,7 @@ class MUV_OT_UVBoundingBox(bpy.types.Operator):
         # we can not get area/space/region from console
         if common.is_console_mode():
             return False
-        return impl.is_valid_context(context)
+        return _is_valid_context(context)
 
     @classmethod
     def is_running(cls, _):
@@ -634,7 +661,7 @@ class MUV_OT_UVBoundingBox(bpy.types.Operator):
         """
         Draw control point
         """
-        prefs = context.user_preferences.addons["uv_magic_uv"].preferences
+        prefs = compat.get_user_preferences(context).addons["uv_magic_uv"].preferences
         cp_size = prefs.uv_bounding_box_cp_size
         offset = cp_size / 2
         verts = [
@@ -644,11 +671,11 @@ class MUV_OT_UVBoundingBox(bpy.types.Operator):
             [pos.x + offset, pos.y - offset]
         ]
         bgl.glEnable(bgl.GL_BLEND)
-        bglx.glBegin(bglx.GL_QUADS)
-        bglx.glColor4f(1.0, 1.0, 1.0, 1.0)
+        bgl.glBegin(bgl.GL_QUADS)
+        bgl.glColor4f(1.0, 1.0, 1.0, 1.0)
         for (x, y) in verts:
-            bglx.glVertex2f(x, y)
-        bglx.glEnd()
+            bgl.glVertex2f(x, y)
+        bgl.glEnd()
 
     @classmethod
     def draw_bb(cls, _, context):
@@ -660,7 +687,7 @@ class MUV_OT_UVBoundingBox(bpy.types.Operator):
         if not MUV_OT_UVBoundingBox.is_running(context):
             return
 
-        if not impl.is_valid_context(context):
+        if not _is_valid_context(context):
             return
 
         for cp in props.ctrl_points:
@@ -747,7 +774,7 @@ class MUV_OT_UVBoundingBox(bpy.types.Operator):
             lidx = info[1]
             uv = info[2]
             v = mathutils.Vector((uv.x, uv.y, 0.0))
-            av = trans_mat @ v
+            av = compat.matmul(trans_mat, v)
             bm.faces[fidx].loops[lidx][uv_layer].uv = mathutils.Vector(
                 (av.x, av.y))
         bmesh.update_edit_mesh(obj.data)
@@ -756,7 +783,7 @@ class MUV_OT_UVBoundingBox(bpy.types.Operator):
         """
         Update control point
         """
-        return [trans_mat @ cp for cp in ctrl_points_ini]
+        return [compat.matmul(trans_mat, cp) for cp in ctrl_points_ini]
 
     def modal(self, context, event):
         props = context.scene.muv_props.uv_bounding_box
@@ -765,7 +792,7 @@ class MUV_OT_UVBoundingBox(bpy.types.Operator):
         if not MUV_OT_UVBoundingBox.is_running(context):
             return {'FINISHED'}
 
-        if not impl.is_valid_context(context):
+        if not _is_valid_context(context):
             MUV_OT_UVBoundingBox.handle_remove(context)
             return {'FINISHED'}
 
@@ -774,8 +801,8 @@ class MUV_OT_UVBoundingBox(bpy.types.Operator):
             'UI',
             'TOOLS',
         ]
-        if not common.mouse_on_area_legacy(event, 'IMAGE_EDITOR') or \
-           common.mouse_on_regions_legacy(event, 'IMAGE_EDITOR', region_types):
+        if not common.mouse_on_area(event, 'IMAGE_EDITOR') or \
+           common.mouse_on_regions(event, 'IMAGE_EDITOR', region_types):
             return {'PASS_THROUGH'}
 
         if event.type == 'TIMER':
diff --git a/uv_magic_uv/op/uv_inspection.py b/uv_magic_uv/op/uv_inspection.py
index 63d73fdfe2c736c42a4f7df1093ead12d2b23fdb..0978158d9cc23e63639b8e9e2247313c5be0aadb 100644
--- a/uv_magic_uv/op/uv_inspection.py
+++ b/uv_magic_uv/op/uv_inspection.py
@@ -24,15 +24,60 @@ __version__ = "5.2"
 __date__ = "17 Nov 2018"
 
 import bpy
-import bgl
 from bpy.props import BoolProperty, EnumProperty
+import bmesh
 
 from .. import common
 from ..utils.bl_class_registry import BlClassRegistry
 from ..utils.property_class_registry import PropertyClassRegistry
-from ..impl import uv_inspection_impl as impl
+from ..utils import compatibility as compat
 
-from ..lib import bglx
+if compat.check_version(2, 80, 0) >= 0:
+    from ..lib import bglx as bgl
+else:
+    import bgl
+
+
+def _is_valid_context(context):
+    obj = context.object
+
+    # only edit mode is allowed to execute
+    if obj is None:
+        return False
+    if obj.type != 'MESH':
+        return False
+    if context.object.mode != 'EDIT':
+        return False
+
+    # 'IMAGE_EDITOR' and 'VIEW_3D' space is allowed to execute.
+    # If 'View_3D' space is not allowed, you can't find option in Tool-Shelf
+    # after the execution
+    for space in context.area.spaces:
+        if (space.type == 'IMAGE_EDITOR') or (space.type == 'VIEW_3D'):
+            break
+    else:
+        return False
+
+    return True
+
+
+def _update_uvinsp_info(context):
+    sc = context.scene
+    props = sc.muv_props.uv_inspection
+
+    obj = context.active_object
+    bm = bmesh.from_edit_mesh(obj.data)
+    if common.check_version(2, 73, 0) >= 0:
+        bm.faces.ensure_lookup_table()
+    uv_layer = bm.loops.layers.uv.verify()
+
+    if context.tool_settings.use_uv_select_sync:
+        sel_faces = [f for f in bm.faces]
+    else:
+        sel_faces = [f for f in bm.faces if f.select]
+    props.overlapped_info = common.get_overlapped_uv_info(
+        bm, sel_faces, uv_layer, sc.muv_uv_inspection_show_mode)
+    props.flipped_info = common.get_flipped_uv_info(sel_faces, uv_layer)
 
 
 @PropertyClassRegistry()
@@ -117,7 +162,7 @@ class MUV_OT_UVInspection_Render(bpy.types.Operator):
         # we can not get area/space/region from console
         if common.is_console_mode():
             return False
-        return impl.is_valid_context(context)
+        return _is_valid_context(context)
 
     @classmethod
     def is_running(cls, _):
@@ -141,7 +186,7 @@ class MUV_OT_UVInspection_Render(bpy.types.Operator):
     def draw(_, context):
         sc = context.scene
         props = sc.muv_props.uv_inspection
-        prefs = context.user_preferences.addons["uv_magic_uv"].preferences
+        prefs = compat.get_user_preferences(context).addons["uv_magic_uv"].preferences
 
         if not MUV_OT_UVInspection_Render.is_running(context):
             return
@@ -155,20 +200,20 @@ class MUV_OT_UVInspection_Render(bpy.types.Operator):
             for info in props.overlapped_info:
                 if sc.muv_uv_inspection_show_mode == 'PART':
                     for poly in info["polygons"]:
-                        bglx.glBegin(bglx.GL_TRIANGLE_FAN)
-                        bglx.glColor4f(color[0], color[1], color[2], color[3])
+                        bgl.glBegin(bgl.GL_TRIANGLE_FAN)
+                        bgl.glColor4f(color[0], color[1], color[2], color[3])
                         for uv in poly:
                             x, y = context.region.view2d.view_to_region(
                                 uv.x, uv.y)
-                            bglx.glVertex2f(x, y)
-                        bglx.glEnd()
+                            bgl.glVertex2f(x, y)
+                        bgl.glEnd()
                 elif sc.muv_uv_inspection_show_mode == 'FACE':
-                    bglx.glBegin(bglx.GL_TRIANGLE_FAN)
-                    bglx.glColor4f(color[0], color[1], color[2], color[3])
+                    bgl.glBegin(bgl.GL_TRIANGLE_FAN)
+                    bgl.glColor4f(color[0], color[1], color[2], color[3])
                     for uv in info["subject_uvs"]:
                         x, y = context.region.view2d.view_to_region(uv.x, uv.y)
-                        bglx.glVertex2f(x, y)
-                    bglx.glEnd()
+                        bgl.glVertex2f(x, y)
+                    bgl.glEnd()
 
         # render flipped UV
         if sc.muv_uv_inspection_show_flipped:
@@ -176,26 +221,26 @@ class MUV_OT_UVInspection_Render(bpy.types.Operator):
             for info in props.flipped_info:
                 if sc.muv_uv_inspection_show_mode == 'PART':
                     for poly in info["polygons"]:
-                        bglx.glBegin(bglx.GL_TRIANGLE_FAN)
-                        bglx.glColor4f(color[0], color[1], color[2], color[3])
+                        bgl.glBegin(bgl.GL_TRIANGLE_FAN)
+                        bgl.glColor4f(color[0], color[1], color[2], color[3])
                         for uv in poly:
                             x, y = context.region.view2d.view_to_region(
                                 uv.x, uv.y)
-                            bglx.glVertex2f(x, y)
-                        bglx.glEnd()
+                            bgl.glVertex2f(x, y)
+                        bgl.glEnd()
                 elif sc.muv_uv_inspection_show_mode == 'FACE':
-                    bglx.glBegin(bglx.GL_TRIANGLE_FAN)
-                    bglx.glColor4f(color[0], color[1], color[2], color[3])
+                    bgl.glBegin(bgl.GL_TRIANGLE_FAN)
+                    bgl.glColor4f(color[0], color[1], color[2], color[3])
                     for uv in info["uvs"]:
                         x, y = context.region.view2d.view_to_region(uv.x, uv.y)
-                        bglx.glVertex2f(x, y)
-                    bglx.glEnd()
+                        bgl.glVertex2f(x, y)
+                    bgl.glEnd()
 
         bgl.glDisable(bgl.GL_BLEND)
 
     def invoke(self, context, _):
         if not MUV_OT_UVInspection_Render.is_running(context):
-            impl.update_uvinsp_info(context)
+            _update_uvinsp_info(context)
             MUV_OT_UVInspection_Render.handle_add(self, context)
         else:
             MUV_OT_UVInspection_Render.handle_remove()
@@ -224,10 +269,10 @@ class MUV_OT_UVInspection_Update(bpy.types.Operator):
             return True
         if not MUV_OT_UVInspection_Render.is_running(context):
             return False
-        return impl.is_valid_context(context)
+        return _is_valid_context(context)
 
     def execute(self, context):
-        impl.update_uvinsp_info(context)
+        _update_uvinsp_info(context)
 
         if context.area:
             context.area.tag_redraw()
diff --git a/uv_magic_uv/op/uv_sculpt.py b/uv_magic_uv/op/uv_sculpt.py
index cc1c057578e6759f7cb3889e252450991d2511db..7dc1b8436325ade14396c53a4680633a83592242 100644
--- a/uv_magic_uv/op/uv_sculpt.py
+++ b/uv_magic_uv/op/uv_sculpt.py
@@ -41,9 +41,46 @@ from bpy.props import (
 from .. import common
 from ..utils.bl_class_registry import BlClassRegistry
 from ..utils.property_class_registry import PropertyClassRegistry
-from ..impl import uv_sculpt_impl as impl
+from ..utils import compatibility as compat
 
-from ..lib import bglx
+
+if compat.check_version(2, 80, 0) >= 0:
+    from ..lib import bglx as bgl
+else:
+    import bgl
+
+
+def _is_valid_context(context):
+    obj = context.object
+
+    # only edit mode is allowed to execute
+    if obj is None:
+        return False
+    if obj.type != 'MESH':
+        return False
+    if context.object.mode != 'EDIT':
+        return False
+
+    # only 'VIEW_3D' space is allowed to execute
+    for space in context.area.spaces:
+        if space.type == 'VIEW_3D':
+            break
+    else:
+        return False
+
+    return True
+
+
+def _get_strength(p, len_, factor):
+    f = factor
+
+    if p > len_:
+        return 0.0
+
+    if p < 0.0:
+        return f
+
+    return (len_ - p) * f / len_
 
 
 @PropertyClassRegistry()
@@ -150,7 +187,7 @@ class MUV_OT_UVSculpt(bpy.types.Operator):
         # we can not get area/space/region from console
         if common.is_console_mode():
             return False
-        return impl.is_valid_context(context)
+        return _is_valid_context(context)
 
     @classmethod
     def is_running(cls, _):
@@ -180,7 +217,7 @@ class MUV_OT_UVSculpt(bpy.types.Operator):
     @classmethod
     def draw_brush(cls, obj, context):
         sc = context.scene
-        prefs = context.user_preferences.addons["uv_magic_uv"].preferences
+        prefs = compat.get_user_preferences(context).addons["uv_magic_uv"].preferences
 
         num_segment = 180
         theta = 2 * pi / num_segment
@@ -188,19 +225,19 @@ class MUV_OT_UVSculpt(bpy.types.Operator):
         fact_r = cos(theta)
         color = prefs.uv_sculpt_brush_color
 
-        bglx.glBegin(bglx.GL_LINE_STRIP)
-        bglx.glColor4f(color[0], color[1], color[2], color[3])
+        bgl.glBegin(bgl.GL_LINE_STRIP)
+        bgl.glColor4f(color[0], color[1], color[2], color[3])
         x = sc.muv_uv_sculpt_radius * cos(0.0)
         y = sc.muv_uv_sculpt_radius * sin(0.0)
         for _ in range(num_segment):
-            bglx.glVertex2f(x + obj.current_mco.x, y + obj.current_mco.y)
+            bgl.glVertex2f(x + obj.current_mco.x, y + obj.current_mco.y)
             tx = -y
             ty = x
             x = x + tx * fact_t
             y = y + ty * fact_t
             x = x * fact_r
             y = y * fact_r
-        bglx.glEnd()
+        bgl.glEnd()
 
     def __init__(self):
         self.__loop_info = []
@@ -226,7 +263,8 @@ class MUV_OT_UVSculpt(bpy.types.Operator):
                 continue
             for i, l in enumerate(f.loops):
                 loc_2d = view3d_utils.location_3d_to_region_2d(
-                    region, space.region_3d, world_mat @ l.vert.co)
+                    region, space.region_3d,
+                    compat.matmul(world_mat, l.vert.co))
                 diff = loc_2d - self.__initial_mco
                 if diff.length < sc.muv_uv_sculpt_radius:
                     info = {
@@ -235,7 +273,7 @@ class MUV_OT_UVSculpt(bpy.types.Operator):
                         "initial_vco": l.vert.co.copy(),
                         "initial_vco_2d": loc_2d,
                         "initial_uv": l[uv_layer].uv.copy(),
-                        "strength": impl.get_strength(
+                        "strength": _get_strength(
                             diff.length, sc.muv_uv_sculpt_radius,
                             sc.muv_uv_sculpt_strength)
                     }
@@ -263,7 +301,8 @@ class MUV_OT_UVSculpt(bpy.types.Operator):
                     continue
                 for i, l in enumerate(f.loops):
                     loc_2d = view3d_utils.location_3d_to_region_2d(
-                        region, space.region_3d, world_mat @ l.vert.co)
+                        region, space.region_3d,
+                        compat.matmul(world_mat, l.vert.co))
                     diff = loc_2d - self.__initial_mco
                     if diff.length < sc.muv_uv_sculpt_radius:
                         info = {
@@ -272,7 +311,7 @@ class MUV_OT_UVSculpt(bpy.types.Operator):
                             "initial_vco": l.vert.co.copy(),
                             "initial_vco_2d": loc_2d,
                             "initial_uv": l[uv_layer].uv.copy(),
-                            "strength": impl.get_strength(
+                            "strength": _get_strength(
                                 diff.length, sc.muv_uv_sculpt_radius,
                                 sc.muv_uv_sculpt_strength)
                         }
@@ -287,8 +326,8 @@ class MUV_OT_UVSculpt(bpy.types.Operator):
                                                            mco)
             ray_tgt = ray_orig + ray_vec * 1000000.0
             mwi = world_mat.inverted()
-            ray_orig_obj = mwi @ ray_orig
-            ray_tgt_obj = mwi @ ray_tgt
+            ray_orig_obj = compat.matmul(mwi, ray_orig)
+            ray_tgt_obj = compat.matmul(mwi, ray_tgt)
             ray_dir_obj = ray_tgt_obj - ray_orig_obj
             ray_dir_obj.normalize()
             tree = BVHTree.FromBMesh(bm)
@@ -354,14 +393,15 @@ class MUV_OT_UVSculpt(bpy.types.Operator):
                     continue
                 for i, l in enumerate(f.loops):
                     loc_2d = view3d_utils.location_3d_to_region_2d(
-                        region, space.region_3d, world_mat @ l.vert.co)
+                        region, space.region_3d,
+                        compat.matmul(world_mat, l.vert.co))
                     diff = loc_2d - self.__initial_mco
                     if diff.length >= sc.muv_uv_sculpt_radius:
                         continue
                     db = vert_db[l.vert]
-                    strength = impl.get_strength(diff.length,
-                                                 sc.muv_uv_sculpt_radius,
-                                                 sc.muv_uv_sculpt_strength)
+                    strength = _get_strength(diff.length,
+                                             sc.muv_uv_sculpt_radius,
+                                             sc.muv_uv_sculpt_strength)
 
                     base = (1.0 - strength) * l[uv_layer].uv
                     if sc.muv_uv_sculpt_relax_method == 'HC':
diff --git a/uv_magic_uv/op/uvw.py b/uv_magic_uv/op/uvw.py
index c97e0e042e2f1b3f3c47264306a381ed393d96ff..9b44100cd92943ee2129b707159317877bc6205e 100644
--- a/uv_magic_uv/op/uvw.py
+++ b/uv_magic_uv/op/uvw.py
@@ -23,6 +23,8 @@ __status__ = "production"
 __version__ = "5.2"
 __date__ = "17 Nov 2018"
 
+from math import sin, cos, pi
+
 import bpy
 import bmesh
 from bpy.props import (
@@ -30,22 +32,145 @@ from bpy.props import (
     FloatVectorProperty,
     BoolProperty
 )
+from mathutils import Vector
 
 from .. import common
-from ..impl import uvw_impl as impl
 from ..utils.bl_class_registry import BlClassRegistry
 from ..utils.property_class_registry import PropertyClassRegistry
+from ..utils import compatibility as compat
+
+
+def _is_valid_context(context):
+    obj = context.object
+
+    # only edit mode is allowed to execute
+    if obj is None:
+        return False
+    if obj.type != 'MESH':
+        return False
+    if context.object.mode != 'EDIT':
+        return False
+
+    # only 'VIEW_3D' space is allowed to execute
+    for space in context.area.spaces:
+        if space.type == 'VIEW_3D':
+            break
+    else:
+        return False
+
+    return True
+
+
+def _get_uv_layer(ops_obj, bm, assign_uvmap):
+    # get UV layer
+    if not bm.loops.layers.uv:
+        if assign_uvmap:
+            bm.loops.layers.uv.new()
+        else:
+            ops_obj.report({'WARNING'},
+                           "Object must have more than one UV map")
+            return None
+    uv_layer = bm.loops.layers.uv.verify()
+
+    return uv_layer
+
+
+def _apply_box_map(bm, uv_layer, size, offset, rotation, tex_aspect):
+    scale = 1.0 / size
+
+    sx = 1.0 * scale
+    sy = 1.0 * scale
+    sz = 1.0 * scale
+    ofx = offset[0]
+    ofy = offset[1]
+    ofz = offset[2]
+    rx = rotation[0] * pi / 180.0
+    ry = rotation[1] * pi / 180.0
+    rz = rotation[2] * pi / 180.0
+    aspect = tex_aspect
+
+    sel_faces = [f for f in bm.faces if f.select]
+
+    # update UV coordinate
+    for f in sel_faces:
+        n = f.normal
+        for l in f.loops:
+            co = l.vert.co
+            x = co.x * sx
+            y = co.y * sy
+            z = co.z * sz
+
+            # X-plane
+            if abs(n[0]) >= abs(n[1]) and abs(n[0]) >= abs(n[2]):
+                if n[0] >= 0.0:
+                    u = (y - ofy) * cos(rx) + (z - ofz) * sin(rx)
+                    v = -(y * aspect - ofy) * sin(rx) + \
+                        (z * aspect - ofz) * cos(rx)
+                else:
+                    u = -(y - ofy) * cos(rx) + (z - ofz) * sin(rx)
+                    v = (y * aspect - ofy) * sin(rx) + \
+                        (z * aspect - ofz) * cos(rx)
+            # Y-plane
+            elif abs(n[1]) >= abs(n[0]) and abs(n[1]) >= abs(n[2]):
+                if n[1] >= 0.0:
+                    u = -(x - ofx) * cos(ry) + (z - ofz) * sin(ry)
+                    v = (x * aspect - ofx) * sin(ry) + \
+                        (z * aspect - ofz) * cos(ry)
+                else:
+                    u = (x - ofx) * cos(ry) + (z - ofz) * sin(ry)
+                    v = -(x * aspect - ofx) * sin(ry) + \
+                        (z * aspect - ofz) * cos(ry)
+            # Z-plane
+            else:
+                if n[2] >= 0.0:
+                    u = (x - ofx) * cos(rz) + (y - ofy) * sin(rz)
+                    v = -(x * aspect - ofx) * sin(rz) + \
+                        (y * aspect - ofy) * cos(rz)
+                else:
+                    u = -(x - ofx) * cos(rz) - (y + ofy) * sin(rz)
+                    v = -(x * aspect + ofx) * sin(rz) + \
+                        (y * aspect - ofy) * cos(rz)
+
+            l[uv_layer].uv = Vector((u, v))
+
+
+def _apply_planer_map(bm, uv_layer, size, offset, rotation, tex_aspect):
+    scale = 1.0 / size
+
+    sx = 1.0 * scale
+    sy = 1.0 * scale
+    ofx = offset[0]
+    ofy = offset[1]
+    rz = rotation * pi / 180.0
+    aspect = tex_aspect
+
+    sel_faces = [f for f in bm.faces if f.select]
+
+    # calculate average of normal
+    n_ave = Vector((0.0, 0.0, 0.0))
+    for f in sel_faces:
+        n_ave = n_ave + f.normal
+    q = n_ave.rotation_difference(Vector((0.0, 0.0, 1.0)))
+
+    # update UV coordinate
+    for f in sel_faces:
+        for l in f.loops:
+            if common.check_version(2, 80, 0) >= 0:
+                # pylint: disable=E0001
+                co = q @ l.vert.co
+            else:
+                co = q * l.vert.co
+            x = co.x * sx
+            y = co.y * sy
 
+            u = x * cos(rz) - y * sin(rz) + ofx
+            v = -x * aspect * sin(rz) - y * aspect * cos(rz) + ofy
 
-__all__ = [
-    'Properties',
-    'MUV_OT_UVW_BoxMap',
-    'MUV_OT_UVW_BestPlanerMap',
-]
+            l[uv_layer].uv = Vector((u, v))
 
 
 @PropertyClassRegistry()
-class Properties:
+class _Properties:
     idname = "uvw"
 
     @classmethod
@@ -68,32 +193,33 @@ class Properties:
 
 
 @BlClassRegistry()
+@compat.make_annotations
 class MUV_OT_UVW_BoxMap(bpy.types.Operator):
     bl_idname = "uv.muv_uvw_operator_box_map"
     bl_label = "Box Map"
     bl_options = {'REGISTER', 'UNDO'}
 
-    size: FloatProperty(
+    size = FloatProperty(
         name="Size",
         default=1.0,
         precision=4
     )
-    rotation: FloatVectorProperty(
+    rotation = FloatVectorProperty(
         name="XYZ Rotation",
         size=3,
         default=(0.0, 0.0, 0.0)
     )
-    offset: FloatVectorProperty(
+    offset = FloatVectorProperty(
         name="XYZ Offset",
         size=3,
         default=(0.0, 0.0, 0.0)
     )
-    tex_aspect: FloatProperty(
+    tex_aspect = FloatProperty(
         name="Texture Aspect",
         default=1.0,
         precision=4
     )
-    assign_uvmap: BoolProperty(
+    assign_uvmap = BoolProperty(
         name="Assign UVMap",
         description="Assign UVMap when no UVmaps are available",
         default=True
@@ -104,7 +230,7 @@ class MUV_OT_UVW_BoxMap(bpy.types.Operator):
         # we can not get area/space/region from console
         if common.is_console_mode():
             return True
-        return impl.is_valid_context(context)
+        return _is_valid_context(context)
 
     def execute(self, context):
         obj = context.active_object
@@ -113,43 +239,44 @@ class MUV_OT_UVW_BoxMap(bpy.types.Operator):
             bm.faces.ensure_lookup_table()
 
         # get UV layer
-        uv_layer = impl.get_uv_layer(self, bm, self.assign_uvmap)
+        uv_layer = _get_uv_layer(self, bm, self.assign_uvmap)
         if not uv_layer:
             return {'CANCELLED'}
 
-        impl.apply_box_map(bm, uv_layer, self.size, self.offset,
-                           self.rotation, self.tex_aspect)
+        _apply_box_map(bm, uv_layer, self.size, self.offset, self.rotation,
+                       self.tex_aspect)
         bmesh.update_edit_mesh(obj.data)
 
         return {'FINISHED'}
 
 
 @BlClassRegistry()
+@compat.make_annotations
 class MUV_OT_UVW_BestPlanerMap(bpy.types.Operator):
     bl_idname = "uv.muv_uvw_operator_best_planer_map"
     bl_label = "Best Planer Map"
     bl_options = {'REGISTER', 'UNDO'}
 
-    size: FloatProperty(
+    size = FloatProperty(
         name="Size",
         default=1.0,
         precision=4
     )
-    rotation: FloatProperty(
+    rotation = FloatProperty(
         name="XY Rotation",
         default=0.0
     )
-    offset: FloatVectorProperty(
+    offset = FloatVectorProperty(
         name="XY Offset",
         size=2,
         default=(0.0, 0.0)
     )
-    tex_aspect: FloatProperty(
+    tex_aspect = FloatProperty(
         name="Texture Aspect",
         default=1.0,
         precision=4
     )
-    assign_uvmap: BoolProperty(
+    assign_uvmap = BoolProperty(
         name="Assign UVMap",
         description="Assign UVMap when no UVmaps are available",
         default=True
@@ -160,7 +287,7 @@ class MUV_OT_UVW_BestPlanerMap(bpy.types.Operator):
         # we can not get area/space/region from console
         if common.is_console_mode():
             return True
-        return impl.is_valid_context(context)
+        return _is_valid_context(context)
 
     def execute(self, context):
         obj = context.active_object
@@ -169,12 +296,12 @@ class MUV_OT_UVW_BestPlanerMap(bpy.types.Operator):
             bm.faces.ensure_lookup_table()
 
         # get UV layer
-        uv_layer = impl.get_uv_layer(self, bm, self.assign_uvmap)
+        uv_layer = _get_uv_layer(self, bm, self.assign_uvmap)
         if not uv_layer:
             return {'CANCELLED'}
 
-        impl.apply_planer_map(bm, uv_layer, self.size, self.offset,
-                              self.rotation, self.tex_aspect)
+        _apply_planer_map(bm, uv_layer, self.size, self.offset, self.rotation,
+                          self.tex_aspect)
 
         bmesh.update_edit_mesh(obj.data)
 
diff --git a/uv_magic_uv/op/world_scale_uv.py b/uv_magic_uv/op/world_scale_uv.py
index a957d5d464ac387fdc9acfe350ba76d31ce64f52..ae46e4a93f4cabcc3a40b40ea84b215f7424a9a8 100644
--- a/uv_magic_uv/op/world_scale_uv.py
+++ b/uv_magic_uv/op/world_scale_uv.py
@@ -23,6 +23,7 @@ __status__ = "production"
 __version__ = "5.2"
 __date__ = "17 Nov 2018"
 
+from math import sqrt
 
 import bpy
 from bpy.props import (
@@ -31,14 +32,153 @@ from bpy.props import (
     IntVectorProperty,
     BoolProperty,
 )
+import bmesh
+from mathutils import Vector
 
+from .. import common
 from ..utils.bl_class_registry import BlClassRegistry
 from ..utils.property_class_registry import PropertyClassRegistry
-from ..impl import world_scale_uv_impl as impl
+from ..utils import compatibility as compat
+
+
+def _is_valid_context(context):
+    obj = context.object
+
+    # only edit mode is allowed to execute
+    if obj is None:
+        return False
+    if obj.type != 'MESH':
+        return False
+    if context.object.mode != 'EDIT':
+        return False
+
+    # only 'VIEW_3D' space is allowed to execute
+    for space in context.area.spaces:
+        if space.type == 'VIEW_3D':
+            break
+    else:
+        return False
+
+    return True
+
+
+def _measure_wsuv_info(obj, tex_size=None):
+    mesh_area = common.measure_mesh_area(obj)
+    uv_area = common.measure_uv_area(obj, tex_size)
+
+    if not uv_area:
+        return None, mesh_area, None
+
+    if mesh_area == 0.0:
+        density = 0.0
+    else:
+        density = sqrt(uv_area) / sqrt(mesh_area)
+
+    return uv_area, mesh_area, density
+
+
+def _apply(obj, origin, factor):
+    bm = bmesh.from_edit_mesh(obj.data)
+    if common.check_version(2, 73, 0) >= 0:
+        bm.verts.ensure_lookup_table()
+        bm.edges.ensure_lookup_table()
+        bm.faces.ensure_lookup_table()
+
+    sel_faces = [f for f in bm.faces if f.select]
+
+    uv_layer = bm.loops.layers.uv.verify()
+
+    # calculate origin
+    if origin == 'CENTER':
+        origin = Vector((0.0, 0.0))
+        num = 0
+        for f in sel_faces:
+            for l in f.loops:
+                uv = l[uv_layer].uv
+                origin = origin + uv
+                num = num + 1
+        origin = origin / num
+    elif origin == 'LEFT_TOP':
+        origin = Vector((100000.0, -100000.0))
+        for f in sel_faces:
+            for l in f.loops:
+                uv = l[uv_layer].uv
+                origin.x = min(origin.x, uv.x)
+                origin.y = max(origin.y, uv.y)
+    elif origin == 'LEFT_CENTER':
+        origin = Vector((100000.0, 0.0))
+        num = 0
+        for f in sel_faces:
+            for l in f.loops:
+                uv = l[uv_layer].uv
+                origin.x = min(origin.x, uv.x)
+                origin.y = origin.y + uv.y
+                num = num + 1
+        origin.y = origin.y / num
+    elif origin == 'LEFT_BOTTOM':
+        origin = Vector((100000.0, 100000.0))
+        for f in sel_faces:
+            for l in f.loops:
+                uv = l[uv_layer].uv
+                origin.x = min(origin.x, uv.x)
+                origin.y = min(origin.y, uv.y)
+    elif origin == 'CENTER_TOP':
+        origin = Vector((0.0, -100000.0))
+        num = 0
+        for f in sel_faces:
+            for l in f.loops:
+                uv = l[uv_layer].uv
+                origin.x = origin.x + uv.x
+                origin.y = max(origin.y, uv.y)
+                num = num + 1
+        origin.x = origin.x / num
+    elif origin == 'CENTER_BOTTOM':
+        origin = Vector((0.0, 100000.0))
+        num = 0
+        for f in sel_faces:
+            for l in f.loops:
+                uv = l[uv_layer].uv
+                origin.x = origin.x + uv.x
+                origin.y = min(origin.y, uv.y)
+                num = num + 1
+        origin.x = origin.x / num
+    elif origin == 'RIGHT_TOP':
+        origin = Vector((-100000.0, -100000.0))
+        for f in sel_faces:
+            for l in f.loops:
+                uv = l[uv_layer].uv
+                origin.x = max(origin.x, uv.x)
+                origin.y = max(origin.y, uv.y)
+    elif origin == 'RIGHT_CENTER':
+        origin = Vector((-100000.0, 0.0))
+        num = 0
+        for f in sel_faces:
+            for l in f.loops:
+                uv = l[uv_layer].uv
+                origin.x = max(origin.x, uv.x)
+                origin.y = origin.y + uv.y
+                num = num + 1
+        origin.y = origin.y / num
+    elif origin == 'RIGHT_BOTTOM':
+        origin = Vector((-100000.0, 100000.0))
+        for f in sel_faces:
+            for l in f.loops:
+                uv = l[uv_layer].uv
+                origin.x = max(origin.x, uv.x)
+                origin.y = min(origin.y, uv.y)
+
+    # update UV coordinate
+    for f in sel_faces:
+        for l in f.loops:
+            uv = l[uv_layer].uv
+            diff = uv - origin
+            l[uv_layer].uv = origin + diff * factor
+
+    bmesh.update_edit_mesh(obj.data)
 
 
 @PropertyClassRegistry()
-class Properties:
+class _Properties:
     idname = "world_scale_uv"
 
     @classmethod
@@ -140,18 +280,35 @@ class MUV_OT_WorldScaleUV_Measure(bpy.types.Operator):
     bl_description = "Measure face size for scale calculation"
     bl_options = {'REGISTER', 'UNDO'}
 
-    def __init__(self):
-        self.__impl = impl.MeasureImpl()
-
     @classmethod
     def poll(cls, context):
-        return impl.MeasureImpl.poll(context)
+        # we can not get area/space/region from console
+        if common.is_console_mode():
+            return True
+        return _is_valid_context(context)
 
     def execute(self, context):
-        return self.__impl.execute(self, context)
+        sc = context.scene
+        obj = context.active_object
+
+        uv_area, mesh_area, density = _measure_wsuv_info(obj)
+        if not uv_area:
+            self.report({'WARNING'},
+                        "Object must have more than one UV map and texture")
+            return {'CANCELLED'}
+
+        sc.muv_world_scale_uv_src_uv_area = uv_area
+        sc.muv_world_scale_uv_src_mesh_area = mesh_area
+        sc.muv_world_scale_uv_src_density = density
+
+        self.report({'INFO'}, "UV Area: {0}, Mesh Area: {1}, Texel Density: {2}"
+                              .format(uv_area, mesh_area, density))
+
+        return {'FINISHED'}
 
 
 @BlClassRegistry()
+@compat.make_annotations
 class MUV_OT_WorldScaleUV_ApplyManual(bpy.types.Operator):
     """
     Operation class: Apply scaled UV (Manual)
@@ -162,20 +319,20 @@ class MUV_OT_WorldScaleUV_ApplyManual(bpy.types.Operator):
     bl_description = "Apply scaled UV based on user specification"
     bl_options = {'REGISTER', 'UNDO'}
 
-    tgt_density: FloatProperty(
+    tgt_density = FloatProperty(
         name="Density",
         description="Target Texel Density",
         default=1.0,
         min=0.0
     )
-    tgt_texture_size: IntVectorProperty(
+    tgt_texture_size = IntVectorProperty(
         name="Texture Size",
         size=2,
         min=1,
         soft_max=10240,
         default=(1024, 1024),
     )
-    origin: EnumProperty(
+    origin = EnumProperty(
         name="Origin",
         description="Aspect Origin",
         items=[
@@ -192,31 +349,64 @@ class MUV_OT_WorldScaleUV_ApplyManual(bpy.types.Operator):
         ],
         default='CENTER'
     )
-    show_dialog: BoolProperty(
+    show_dialog = BoolProperty(
         name="Show Diaglog Menu",
         description="Show dialog menu if true",
         default=True,
         options={'HIDDEN', 'SKIP_SAVE'}
     )
 
-    def __init__(self):
-        self.__impl = impl.ApplyManualImpl()
-
     @classmethod
     def poll(cls, context):
-        return impl.ApplyManualImpl.poll(context)
+        # we can not get area/space/region from console
+        if common.is_console_mode():
+            return True
+        return _is_valid_context(context)
+
+    def __apply_manual(self, context):
+        obj = context.active_object
+        bm = bmesh.from_edit_mesh(obj.data)
+        if common.check_version(2, 73, 0) >= 0:
+            bm.verts.ensure_lookup_table()
+            bm.edges.ensure_lookup_table()
+            bm.faces.ensure_lookup_table()
+
+        tex_size = self.tgt_texture_size
+        uv_area, _, density = _measure_wsuv_info(obj, tex_size)
+        if not uv_area:
+            self.report({'WARNING'}, "Object must have more than one UV map")
+            return {'CANCELLED'}
+
+        tgt_density = self.tgt_density
+        factor = tgt_density / density
+
+        _apply(context.active_object, self.origin, factor)
+        self.report({'INFO'}, "Scaling factor: {0}".format(factor))
+
+        return {'FINISHED'}
 
-    def draw(self, context):
-        self.__impl.draw(self, context)
+    def draw(self, _):
+        layout = self.layout
 
-    def invoke(self, context, event):
-        return self.__impl.invoke(self, context, event)
+        layout.prop(self, "tgt_density")
+        layout.prop(self, "tgt_texture_size")
+        layout.prop(self, "origin")
+
+        layout.separator()
+
+    def invoke(self, context, _):
+        if self.show_dialog:
+            wm = context.window_manager
+            return wm.invoke_props_dialog(self)
+
+        return self.execute(context)
 
     def execute(self, context):
-        return self.__impl.execute(self, context)
+        return self.__apply_manual(context)
 
 
 @BlClassRegistry()
+@compat.make_annotations
 class MUV_OT_WorldScaleUV_ApplyScalingDensity(bpy.types.Operator):
     """
     Operation class: Apply scaled UV (Scaling Density)
@@ -227,13 +417,13 @@ class MUV_OT_WorldScaleUV_ApplyScalingDensity(bpy.types.Operator):
     bl_description = "Apply scaled UV with scaling density"
     bl_options = {'REGISTER', 'UNDO'}
 
-    tgt_scaling_factor: FloatProperty(
+    tgt_scaling_factor = FloatProperty(
         name="Scaling Factor",
         default=1.0,
         max=1000.0,
         min=0.00001
     )
-    origin: EnumProperty(
+    origin = EnumProperty(
         name="Origin",
         description="Aspect Origin",
         items=[
@@ -250,44 +440,97 @@ class MUV_OT_WorldScaleUV_ApplyScalingDensity(bpy.types.Operator):
         ],
         default='CENTER'
     )
-    src_density: FloatProperty(
+    src_density = FloatProperty(
         name="Density",
         description="Source Texel Density",
         default=0.0,
         min=0.0,
         options={'HIDDEN'}
     )
-    same_density: BoolProperty(
+    same_density = BoolProperty(
         name="Same Density",
         description="Apply same density",
         default=False,
         options={'HIDDEN'}
     )
-    show_dialog: BoolProperty(
+    show_dialog = BoolProperty(
         name="Show Diaglog Menu",
         description="Show dialog menu if true",
         default=True,
         options={'HIDDEN', 'SKIP_SAVE'}
     )
 
-    def __init__(self):
-        self.__impl = impl.ApplyScalingDensityImpl()
-
     @classmethod
     def poll(cls, context):
-        return impl.ApplyScalingDensityImpl.poll(context)
+        # we can not get area/space/region from console
+        if common.is_console_mode():
+            return True
+        return _is_valid_context(context)
+
+    def __apply_scaling_density(self, context):
+        obj = context.active_object
+        bm = bmesh.from_edit_mesh(obj.data)
+        if common.check_version(2, 73, 0) >= 0:
+            bm.verts.ensure_lookup_table()
+            bm.edges.ensure_lookup_table()
+            bm.faces.ensure_lookup_table()
+
+        uv_area, _, density = _measure_wsuv_info(obj)
+        if not uv_area:
+            self.report({'WARNING'},
+                        "Object must have more than one UV map and texture")
+            return {'CANCELLED'}
+
+        tgt_density = self.src_density * self.tgt_scaling_factor
+        factor = tgt_density / density
+
+        _apply(context.active_object, self.origin, factor)
+        self.report({'INFO'}, "Scaling factor: {0}".format(factor))
+
+        return {'FINISHED'}
+
+    def draw(self, _):
+        layout = self.layout
 
-    def draw(self, context):
-        self.__impl.draw(self, context)
+        layout.label(text="Source:")
+        col = layout.column()
+        col.prop(self, "src_density")
+        col.enabled = False
 
-    def invoke(self, context, event):
-        return self.__impl.invoke(self, context, event)
+        layout.separator()
+
+        if not self.same_density:
+            layout.prop(self, "tgt_scaling_factor")
+        layout.prop(self, "origin")
+
+        layout.separator()
+
+    def invoke(self, context, _):
+        sc = context.scene
+
+        if self.show_dialog:
+            wm = context.window_manager
+
+            if self.same_density:
+                self.tgt_scaling_factor = 1.0
+            else:
+                self.tgt_scaling_factor = \
+                    sc.muv_world_scale_uv_tgt_scaling_factor
+                self.src_density = sc.muv_world_scale_uv_src_density
+
+            return wm.invoke_props_dialog(self)
+
+        return self.execute(context)
 
     def execute(self, context):
-        return self.__impl.execute(self, context)
+        if self.same_density:
+            self.tgt_scaling_factor = 1.0
+
+        return self.__apply_scaling_density(context)
 
 
 @BlClassRegistry()
+@compat.make_annotations
 class MUV_OT_WorldScaleUV_ApplyProportionalToMesh(bpy.types.Operator):
     """
     Operation class: Apply scaled UV (Proportional to mesh)
@@ -298,7 +541,7 @@ class MUV_OT_WorldScaleUV_ApplyProportionalToMesh(bpy.types.Operator):
     bl_description = "Apply scaled UV proportionaled to mesh"
     bl_options = {'REGISTER', 'UNDO'}
 
-    origin: EnumProperty(
+    origin = EnumProperty(
         name="Origin",
         description="Aspect Origin",
         items=[
@@ -315,46 +558,91 @@ class MUV_OT_WorldScaleUV_ApplyProportionalToMesh(bpy.types.Operator):
         ],
         default='CENTER'
     )
-    src_density: FloatProperty(
+    src_density = FloatProperty(
         name="Source Density",
         description="Source Texel Density",
         default=0.0,
         min=0.0,
         options={'HIDDEN'}
     )
-    src_uv_area: FloatProperty(
+    src_uv_area = FloatProperty(
         name="Source UV Area",
         description="Source UV Area",
         default=0.0,
         min=0.0,
         options={'HIDDEN'}
     )
-    src_mesh_area: FloatProperty(
+    src_mesh_area = FloatProperty(
         name="Source Mesh Area",
         description="Source Mesh Area",
         default=0.0,
         min=0.0,
         options={'HIDDEN'}
     )
-    show_dialog: BoolProperty(
+    show_dialog = BoolProperty(
         name="Show Diaglog Menu",
         description="Show dialog menu if true",
         default=True,
         options={'HIDDEN', 'SKIP_SAVE'}
     )
 
-    def __init__(self):
-        self.__impl = impl.ApplyProportionalToMeshImpl()
-
     @classmethod
     def poll(cls, context):
-        return impl.ApplyProportionalToMeshImpl.poll(context)
+        # we can not get area/space/region from console
+        if common.is_console_mode():
+            return True
+        return _is_valid_context(context)
+
+    def __apply_proportional_to_mesh(self, context):
+        obj = context.active_object
+        bm = bmesh.from_edit_mesh(obj.data)
+        if common.check_version(2, 73, 0) >= 0:
+            bm.verts.ensure_lookup_table()
+            bm.edges.ensure_lookup_table()
+            bm.faces.ensure_lookup_table()
+
+        uv_area, mesh_area, density = _measure_wsuv_info(obj)
+        if not uv_area:
+            self.report({'WARNING'},
+                        "Object must have more than one UV map and texture")
+            return {'CANCELLED'}
+
+        tgt_density = self.src_density * sqrt(mesh_area) / sqrt(
+            self.src_mesh_area)
+
+        factor = tgt_density / density
+
+        _apply(context.active_object, self.origin, factor)
+        self.report({'INFO'}, "Scaling factor: {0}".format(factor))
+
+        return {'FINISHED'}
+
+    def draw(self, _):
+        layout = self.layout
+
+        layout.label(text="Source:")
+        col = layout.column(align=True)
+        col.prop(self, "src_density")
+        col.prop(self, "src_uv_area")
+        col.prop(self, "src_mesh_area")
+        col.enabled = False
+
+        layout.separator()
+        layout.prop(self, "origin")
+
+        layout.separator()
+
+    def invoke(self, context, _):
+        if self.show_dialog:
+            wm = context.window_manager
+            sc = context.scene
+
+            self.src_density = sc.muv_world_scale_uv_src_density
+            self.src_mesh_area = sc.muv_world_scale_uv_src_mesh_area
 
-    def draw(self, context):
-        self.__impl.draw(self, context)
+            return wm.invoke_props_dialog(self)
 
-    def invoke(self, context, event):
-        return self.__impl.invoke(self, context, event)
+        return self.execute(context)
 
     def execute(self, context):
-        return self.__impl.execute(self, context)
+        return self.__apply_proportional_to_mesh(context)
diff --git a/uv_magic_uv/preferences.py b/uv_magic_uv/preferences.py
index a58d08d4f05178e3d43ce860806dd96f9541c89c..01d7155e66a6bc714e97566ebd1c0abf876a49ca 100644
--- a/uv_magic_uv/preferences.py
+++ b/uv_magic_uv/preferences.py
@@ -37,6 +37,7 @@ from . import op
 from . import ui
 from .utils.bl_class_registry import BlClassRegistry
 from .utils.addon_updator import AddonUpdatorManager
+from .utils import compatibility as compat
 
 
 def view3d_uvmap_menu_fn(self, context):
@@ -44,7 +45,7 @@ def view3d_uvmap_menu_fn(self, context):
     sc = context.scene
 
     layout.separator()
-    layout.label(text="Copy/Paste UV", icon='IMAGE')
+    layout.label(text="Copy/Paste UV", icon=compat.icon('IMAGE'))
     # Copy/Paste UV
     layout.menu(ui.VIEW3D_MT_uv_map.MUV_MT_CopyPasteUV.bl_idname,
                 text="Copy/Paste UV")
@@ -53,7 +54,7 @@ def view3d_uvmap_menu_fn(self, context):
                 text="Transfer UV")
 
     layout.separator()
-    layout.label(text="UV Manipulation", icon='IMAGE')
+    layout.label(text="UV Manipulation", icon=compat.icon('IMAGE'))
     # Flip/Rotate UV
     ops = layout.operator(op.flip_rotate_uv.MUV_OT_FlipRotate.bl_idname,
                           text="Flip/Rotate UV")
@@ -80,7 +81,7 @@ def view3d_uvmap_menu_fn(self, context):
     layout.prop(sc, "muv_uv_sculpt_enable", text="UV Sculpt")
 
     layout.separator()
-    layout.label(text="UV Mapping", icon='IMAGE')
+    layout.label(text="UV Mapping", icon=compat.icon('IMAGE'))
     # Unwrap Constraint
     ops = layout.operator(
         op.unwrap_constraint.MUV_OT_UnwrapConstraint.bl_idname,
@@ -98,7 +99,7 @@ def view3d_object_menu_fn(self, _):
     layout = self.layout
 
     layout.separator()
-    layout.label(text="Copy/Paste UV", icon='IMAGE')
+    layout.label(text="Copy/Paste UV", icon=compat.icon('IMAGE'))
     # Copy/Paste UV (Among Object)
     layout.menu(ui.VIEW3D_MT_object.MUV_MT_CopyPasteUV_Object.bl_idname,
                 text="Copy/Paste UV")
@@ -110,13 +111,13 @@ def image_uvs_menu_fn(self, context):
 
     layout.separator()
     # Copy/Paste UV (on UV/Image Editor)
-    layout.label(text="Copy/Paste UV", icon='IMAGE')
+    layout.label(text="Copy/Paste UV", icon=compat.icon('IMAGE'))
     layout.menu(ui.IMAGE_MT_uvs.MUV_MT_CopyPasteUV_UVEdit.bl_idname,
                 text="Copy/Paste UV")
 
     layout.separator()
     # Pack UV
-    layout.label(text="UV Manipulation", icon='IMAGE')
+    layout.label(text="UV Manipulation", icon=compat.icon('IMAGE'))
     ops = layout.operator(op.pack_uv.MUV_OT_PackUV.bl_idname, text="Pack UV")
     ops.allowable_center_deviation = sc.muv_pack_uv_allowable_center_deviation
     ops.allowable_size_deviation = sc.muv_pack_uv_allowable_size_deviation
@@ -133,7 +134,7 @@ def image_uvs_menu_fn(self, context):
 
     layout.separator()
     # Align UV Cursor
-    layout.label(text="Editor Enhancement", icon='IMAGE')
+    layout.label(text="Editor Enhancement", icon=compat.icon('IMAGE'))
     layout.menu(ui.IMAGE_MT_uvs.MUV_MT_AlignUVCursor.bl_idname,
                 text="Align UV Cursor")
     # UV Bounding Box
@@ -170,13 +171,14 @@ class MUV_OT_CheckAddonUpdate(bpy.types.Operator):
 
 
 @BlClassRegistry()
+@compat.make_annotations
 class MUV_OT_UpdateAddon(bpy.types.Operator):
     bl_idname = "uv.muv_update_addon"
     bl_label = "Update"
     bl_description = "Update Add-on"
     bl_options = {'REGISTER', 'UNDO'}
 
-    branch_name: StringProperty(
+    branch_name = StringProperty(
         name="Branch Name",
         description="Branch name to update",
         default="",
@@ -198,6 +200,7 @@ def get_update_candidate_branches(_, __):
 
 
 @BlClassRegistry()
+@compat.make_annotations
 class Preferences(AddonPreferences):
     """Preferences class: Preferences for this add-on"""
 
@@ -210,7 +213,7 @@ class Preferences(AddonPreferences):
             remove_builtin_menu()
 
     # enable to add features to built-in menu
-    enable_builtin_menu: BoolProperty(
+    enable_builtin_menu = BoolProperty(
         name="Built-in Menu",
         description="Enable built-in menu",
         default=True,
@@ -218,7 +221,7 @@ class Preferences(AddonPreferences):
     )
 
     # for UV Sculpt
-    uv_sculpt_brush_color: FloatVectorProperty(
+    uv_sculpt_brush_color = FloatVectorProperty(
         name="Color",
         description="Color",
         default=(1.0, 0.4, 0.4, 1.0),
@@ -229,7 +232,7 @@ class Preferences(AddonPreferences):
     )
 
     # for Overlapped UV
-    uv_inspection_overlapped_color: FloatVectorProperty(
+    uv_inspection_overlapped_color = FloatVectorProperty(
         name="Color",
         description="Color",
         default=(0.0, 0.0, 1.0, 0.3),
@@ -240,7 +243,7 @@ class Preferences(AddonPreferences):
     )
 
     # for Flipped UV
-    uv_inspection_flipped_color: FloatVectorProperty(
+    uv_inspection_flipped_color = FloatVectorProperty(
         name="Color",
         description="Color",
         default=(1.0, 0.0, 0.0, 0.3),
@@ -251,7 +254,7 @@ class Preferences(AddonPreferences):
     )
 
     # for Texture Projection
-    texture_projection_canvas_padding: FloatVectorProperty(
+    texture_projection_canvas_padding = FloatVectorProperty(
         name="Canvas Padding",
         description="Canvas Padding",
         size=2,
@@ -260,13 +263,13 @@ class Preferences(AddonPreferences):
         default=(20.0, 20.0))
 
     # for UV Bounding Box
-    uv_bounding_box_cp_size: FloatProperty(
+    uv_bounding_box_cp_size = FloatProperty(
         name="Size",
         description="Control Point Size",
         default=6.0,
         min=3.0,
         max=100.0)
-    uv_bounding_box_cp_react_size: FloatProperty(
+    uv_bounding_box_cp_react_size = FloatProperty(
         name="React Size",
         description="Size event fired",
         default=10.0,
@@ -274,7 +277,7 @@ class Preferences(AddonPreferences):
         max=100.0)
 
     # for UI
-    category: EnumProperty(
+    category = EnumProperty(
         name="Category",
         description="Preferences Category",
         items=[
@@ -284,39 +287,39 @@ class Preferences(AddonPreferences):
         ],
         default='INFO'
     )
-    info_desc_expanded: BoolProperty(
+    info_desc_expanded = BoolProperty(
         name="Description",
         description="Description",
         default=False
     )
-    info_loc_expanded: BoolProperty(
+    info_loc_expanded = BoolProperty(
         name="Location",
         description="Location",
         default=False
     )
-    conf_uv_sculpt_expanded: BoolProperty(
+    conf_uv_sculpt_expanded = BoolProperty(
         name="UV Sculpt",
         description="UV Sculpt",
         default=False
     )
-    conf_uv_inspection_expanded: BoolProperty(
+    conf_uv_inspection_expanded = BoolProperty(
         name="UV Inspection",
         description="UV Inspection",
         default=False
     )
-    conf_texture_projection_expanded: BoolProperty(
+    conf_texture_projection_expanded = BoolProperty(
         name="Texture Projection",
         description="Texture Projection",
         default=False
     )
-    conf_uv_bounding_box_expanded: BoolProperty(
+    conf_uv_bounding_box_expanded = BoolProperty(
         name="UV Bounding Box",
         description="UV Bounding Box",
         default=False
     )
 
     # for add-on updater
-    updater_branch_to_update: EnumProperty(
+    updater_branch_to_update = EnumProperty(
         name="branch",
         description="Target branch to update add-on",
         items=get_update_candidate_branches
@@ -349,27 +352,27 @@ class Preferences(AddonPreferences):
                 else 'DISCLOSURE_TRI_RIGHT')
             if self.info_loc_expanded:
                 row = layout.row(align=True)
-                sp = row.split(factor=0.5)
+                sp = compat.layout_split(row, 0.5)
                 sp.label(text="3D View > Tool shelf > " +
                               "Copy/Paste UV (Object mode)")
-                sp = sp.split(factor=1.0)
+                sp = compat.layout_split(sp, 1.0)
                 col = sp.column(align=True)
                 col.label(text="Copy/Paste UV (Among objects)")
 
                 row = layout.row(align=True)
-                sp = row.split(factor=0.5)
+                sp = compat.layout_split(row, 0.5)
                 sp.label(text="3D View > Tool shelf > " +
                               "Copy/Paste UV (Edit mode)")
-                sp = sp.split(factor=1.0)
+                sp = compat.layout_split(sp, 1.0)
                 col = sp.column(align=True)
                 col.label(text="Copy/Paste UV (Among faces in 3D View)")
                 col.label(text="Transfer UV")
 
                 row = layout.row(align=True)
-                sp = row.split(factor=0.5)
+                sp = compat.layout_split(row, 0.5)
                 sp.label(text="3D View > Tool shelf > " +
                               "UV Manipulation (Edit mode)")
-                sp = sp.split(factor=1.0)
+                sp = compat.layout_split(sp, 1.0)
                 col = sp.column(align=True)
                 col.label(text="Flip/Rotate UV")
                 col.label(text="Mirror UV")
@@ -381,26 +384,26 @@ class Preferences(AddonPreferences):
                 col.label(text="UV Sculpt")
 
                 row = layout.row(align=True)
-                sp = row.split(factor=0.5)
+                sp = compat.layout_split(row, 0.5)
                 sp.label(text="3D View > Tool shelf > " +
                               "UV Manipulation (Edit mode)")
-                sp = sp.split(factor=1.0)
+                sp = compat.layout_split(sp, 1.0)
                 col = sp.column(align=True)
                 col.label(text="Unwrap Constraint")
                 col.label(text="Texture Projection")
                 col.label(text="UVW")
 
                 row = layout.row(align=True)
-                sp = row.split(factor=0.5)
+                sp = compat.layout_split(row, 0.5)
                 sp.label(text="UV/Image Editor > Tool shelf > Copy/Paste UV")
-                sp = sp.split(factor=1.0)
+                sp = compat.layout_split(sp, 1.0)
                 col = sp.column(align=True)
                 col.label(text="Copy/Paste UV (Among faces in UV/Image Editor)")
 
                 row = layout.row(align=True)
-                sp = row.split(factor=0.5)
+                sp = compat.layout_split(row, 0.5)
                 sp.label(text="UV/Image Editor > Tool shelf > UV Manipulation")
-                sp = sp.split(factor=1.0)
+                sp = compat.layout_split(sp, 1.0)
                 col = sp.column(align=True)
                 col.label(text="Align UV")
                 col.label(text="Smooth UV")
@@ -408,10 +411,10 @@ class Preferences(AddonPreferences):
                 col.label(text="Pack UV (Extension)")
 
                 row = layout.row(align=True)
-                sp = row.split(factor=0.5)
+                sp = compat.layout_split(row, 0.5)
                 sp.label(text="UV/Image Editor > Tool shelf > " +
                               "Editor Enhancement")
-                sp = sp.split(factor=1.0)
+                sp = compat.layout_split(sp, 1.0)
                 col = sp.column(align=True)
                 col.label(text="Align UV Cursor")
                 col.label(text="UV Cursor Location")
@@ -430,9 +433,9 @@ class Preferences(AddonPreferences):
                 icon='DISCLOSURE_TRI_DOWN' if self.conf_uv_sculpt_expanded
                 else 'DISCLOSURE_TRI_RIGHT')
             if self.conf_uv_sculpt_expanded:
-                sp = layout.split(factor=0.05)
+                sp = compat.layout_split(layout, 0.05)
                 col = sp.column()  # spacer
-                sp = sp.split(factor=0.3)
+                sp = compat.layout_split(sp, 0.3)
                 col = sp.column()
                 col.label(text="Brush Color:")
                 col.prop(self, "uv_sculpt_brush_color", text="")
@@ -443,13 +446,13 @@ class Preferences(AddonPreferences):
                 icon='DISCLOSURE_TRI_DOWN' if self.conf_uv_inspection_expanded
                 else 'DISCLOSURE_TRI_RIGHT')
             if self.conf_uv_inspection_expanded:
-                sp = layout.split(factor=0.05)
+                sp = compat.layout_split(layout, 0.05)
                 col = sp.column()  # spacer
-                sp = sp.split(factor=0.3)
+                sp = compat.layout_split(sp, 0.3)
                 col = sp.column()
                 col.label(text="Overlapped UV Color:")
                 col.prop(self, "uv_inspection_overlapped_color", text="")
-                sp = sp.split(factor=0.45)
+                sp = compat.layout_split(sp, 0.45)
                 col = sp.column()
                 col.label(text="Flipped UV Color:")
                 col.prop(self, "uv_inspection_flipped_color", text="")
@@ -462,9 +465,9 @@ class Preferences(AddonPreferences):
                 if self.conf_texture_projection_expanded
                 else 'DISCLOSURE_TRI_RIGHT')
             if self.conf_texture_projection_expanded:
-                sp = layout.split(factor=0.05)
+                sp = compat.layout_split(layout, 0.05)
                 col = sp.column()       # spacer
-                sp = sp.split(factor=0.3)
+                sp = compat.layout_split(sp, 0.3)
                 col = sp.column()
                 col.prop(self, "texture_projection_canvas_padding")
                 layout.separator()
@@ -475,9 +478,9 @@ class Preferences(AddonPreferences):
                 if self.conf_uv_bounding_box_expanded
                 else 'DISCLOSURE_TRI_RIGHT')
             if self.conf_uv_bounding_box_expanded:
-                sp = layout.split(factor=0.05)
+                sp = compat.layout_split(layout, 0.05)
                 col = sp.column()       # spacer
-                sp = sp.split(factor=0.3)
+                sp = compat.layout_split(sp, 0.3)
                 col = sp.column()
                 col.label(text="Control Point:")
                 col.prop(self, "uv_bounding_box_cp_size")
diff --git a/uv_magic_uv/properites.py b/uv_magic_uv/properites.py
index 60ce26eb10922b797645122d854ad52666941767..81ebbb4d6fa34806fe8795390e612a159a9eb5fc 100644
--- a/uv_magic_uv/properites.py
+++ b/uv_magic_uv/properites.py
@@ -24,16 +24,6 @@ __version__ = "5.2"
 __date__ = "17 Nov 2018"
 
 
-from .utils.property_class_registry import PropertyClassRegistry
-
-
-__all__ = [
-    'MUV_Properties',
-    'init_props',
-    'clear_props',
-]
-
-
 # Properties used in this add-on.
 # pylint: disable=W0612
 class MUV_Properties():
@@ -41,6 +31,7 @@ class MUV_Properties():
         self.prefs = MUV_Prefs()
 
 
+# TODO: delete this
 class MUV_Prefs():
     expanded = {
         "info_desc": False,
diff --git a/uv_magic_uv/ui/IMAGE_MT_uvs.py b/uv_magic_uv/ui/IMAGE_MT_uvs.py
index dfb509c7f185b1187e5d5d4d7301baf2b81bd851..3881f547c2b6d6db0ecec9dbff4a321451c68de6 100644
--- a/uv_magic_uv/ui/IMAGE_MT_uvs.py
+++ b/uv_magic_uv/ui/IMAGE_MT_uvs.py
@@ -41,10 +41,6 @@ from ..op.select_uv import (
 from ..op.uv_inspection import MUV_OT_UVInspection_Update
 from ..utils.bl_class_registry import BlClassRegistry
 
-__all__ = [
-    'MUV_MT_CopyPasteUV_UVEdit',
-]
-
 
 @BlClassRegistry()
 class MUV_MT_CopyPasteUV_UVEdit(bpy.types.Menu):
diff --git a/uv_magic_uv/ui/VIEW3D_MT_object.py b/uv_magic_uv/ui/VIEW3D_MT_object.py
index 318cd82c6ea6506a1176da5413359906ff4e116a..0d51a65bda5a6c08cb4c9e34dea5a7e7662bbf1b 100644
--- a/uv_magic_uv/ui/VIEW3D_MT_object.py
+++ b/uv_magic_uv/ui/VIEW3D_MT_object.py
@@ -28,10 +28,6 @@ import bpy
 from ..op import copy_paste_uv_object
 from ..utils.bl_class_registry import BlClassRegistry
 
-__all__ = [
-    'MUV_MT_CopyPasteUV_Object',
-]
-
 
 @BlClassRegistry()
 class MUV_MT_CopyPasteUV_Object(bpy.types.Menu):
diff --git a/uv_magic_uv/ui/VIEW3D_MT_uv_map.py b/uv_magic_uv/ui/VIEW3D_MT_uv_map.py
index 012ce0472c84da1097b391ca13dc4e7af04536f0..d673ed4ded482d8f454539eaa0a1da2ee08afe44 100644
--- a/uv_magic_uv/ui/VIEW3D_MT_uv_map.py
+++ b/uv_magic_uv/ui/VIEW3D_MT_uv_map.py
@@ -45,18 +45,9 @@ from ..op.world_scale_uv import (
     MUV_OT_WorldScaleUV_ApplyScalingDensity,
     MUV_OT_WorldScaleUV_ApplyProportionalToMesh,
 )
-from ..op.texture_projection import (
-    MUV_OT_TextureProjection,
-    MUV_OT_TextureProjection_Project,
-)
+from ..op.texture_projection import MUV_OT_TextureProjection_Project
 from ..utils.bl_class_registry import BlClassRegistry
 
-__all__ = [
-    'MUV_MT_CopyPasteUV',
-    'MUV_MT_TransferUV',
-    'MUV_MT_UVW',
-]
-
 
 @BlClassRegistry()
 class MUV_MT_CopyPasteUV(bpy.types.Menu):
diff --git a/uv_magic_uv/ui/uvedit_copy_paste_uv.py b/uv_magic_uv/ui/uvedit_copy_paste_uv.py
index e21a5abd336d6af9c7eb259582a29de1ad89a452..7b8a1c526e3bc73230d9ae1dc37c101a9ec5e766 100644
--- a/uv_magic_uv/ui/uvedit_copy_paste_uv.py
+++ b/uv_magic_uv/ui/uvedit_copy_paste_uv.py
@@ -27,13 +27,11 @@ import bpy
 
 from ..op import copy_paste_uv_uvedit
 from ..utils.bl_class_registry import BlClassRegistry
-
-__all__ = [
-    'MUV_PT_UVEdit_CopyPasteUV',
-]
+from ..utils import compatibility as compat
 
 
 @BlClassRegistry()
+@compat.ChangeRegionType(region_type='TOOLS')
 class MUV_PT_UVEdit_CopyPasteUV(bpy.types.Panel):
     """
     Panel class: Copy/Paste UV on Property Panel on UV/ImageEditor
@@ -48,7 +46,7 @@ class MUV_PT_UVEdit_CopyPasteUV(bpy.types.Panel):
 
     def draw_header(self, _):
         layout = self.layout
-        layout.label(text="", icon='IMAGE')
+        layout.label(text="", icon=compat.icon('IMAGE'))
 
     def draw(self, _):
         layout = self.layout
diff --git a/uv_magic_uv/ui/uvedit_editor_enhancement.py b/uv_magic_uv/ui/uvedit_editor_enhancement.py
index cfd9ef28c260e01681a19881751a2ffa4db9324a..7c366aa7d9fd93b1c3345dbdf1f56bf425e8df3c 100644
--- a/uv_magic_uv/ui/uvedit_editor_enhancement.py
+++ b/uv_magic_uv/ui/uvedit_editor_enhancement.py
@@ -34,13 +34,11 @@ from ..op.uv_inspection import (
     MUV_OT_UVInspection_Update,
 )
 from ..utils.bl_class_registry import BlClassRegistry
-
-__all__ = [
-    'MUV_PT_UVEdit_EditorEnhancement',
-]
+from ..utils import compatibility as compat
 
 
 @BlClassRegistry()
+@compat.ChangeRegionType(region_type='TOOLS')
 class MUV_PT_UVEdit_EditorEnhancement(bpy.types.Panel):
     """
     Panel class: UV/Image Editor Enhancement
@@ -55,7 +53,7 @@ class MUV_PT_UVEdit_EditorEnhancement(bpy.types.Panel):
 
     def draw_header(self, _):
         layout = self.layout
-        layout.label(text="", icon='IMAGE')
+        layout.label(text="", icon=compat.icon('IMAGE'))
 
     def draw(self, context):
         layout = self.layout
diff --git a/uv_magic_uv/ui/uvedit_uv_manipulation.py b/uv_magic_uv/ui/uvedit_uv_manipulation.py
index f5bd27e3ff818344149c18178f1a52a2e5391924..d8c7795735bff7a791741ebae87f370f54cd51d2 100644
--- a/uv_magic_uv/ui/uvedit_uv_manipulation.py
+++ b/uv_magic_uv/ui/uvedit_uv_manipulation.py
@@ -39,9 +39,11 @@ from ..op.select_uv import (
 )
 from ..op.pack_uv import MUV_OT_PackUV
 from ..utils.bl_class_registry import BlClassRegistry
+from ..utils import compatibility as compat
 
 
 @BlClassRegistry()
+@compat.ChangeRegionType(region_type='TOOLS')
 class MUV_PT_UVEdit_UVManipulation(bpy.types.Panel):
     """
     Panel class: UV Manipulation on Property Panel on UV/ImageEditor
@@ -56,7 +58,7 @@ class MUV_PT_UVEdit_UVManipulation(bpy.types.Panel):
 
     def draw_header(self, _):
         layout = self.layout
-        layout.label(text="", icon='IMAGE')
+        layout.label(text="", icon=compat.icon('IMAGE'))
 
     def draw(self, context):
         sc = context.scene
diff --git a/uv_magic_uv/ui/view3d_copy_paste_uv_editmode.py b/uv_magic_uv/ui/view3d_copy_paste_uv_editmode.py
index 14fba24a2c7e80e254726308417ae4e6e30d93f6..0fc4df141a718b1873f55876d037cf70a8f7a978 100644
--- a/uv_magic_uv/ui/view3d_copy_paste_uv_editmode.py
+++ b/uv_magic_uv/ui/view3d_copy_paste_uv_editmode.py
@@ -30,13 +30,11 @@ from ..op import (
     transfer_uv,
 )
 from ..utils.bl_class_registry import BlClassRegistry
-
-__all__ = [
-    'MUV_PT_CopyPasteUVEditMode',
-]
+from ..utils import compatibility as compat
 
 
 @BlClassRegistry()
+@compat.ChangeRegionType(region_type='TOOLS')
 class MUV_PT_CopyPasteUVEditMode(bpy.types.Panel):
     """
     Panel class: Copy/Paste UV on Property Panel on View3D
@@ -51,7 +49,7 @@ class MUV_PT_CopyPasteUVEditMode(bpy.types.Panel):
 
     def draw_header(self, _):
         layout = self.layout
-        layout.label(text="", icon='IMAGE')
+        layout.label(text="", icon=compat.icon('IMAGE'))
 
     def draw(self, context):
         sc = context.scene
diff --git a/uv_magic_uv/ui/view3d_copy_paste_uv_objectmode.py b/uv_magic_uv/ui/view3d_copy_paste_uv_objectmode.py
index 6dd0d3b43584e8bd479da565dbe9b6de34381e95..36968ffbbebe0072b237386119255e01179a66b1 100644
--- a/uv_magic_uv/ui/view3d_copy_paste_uv_objectmode.py
+++ b/uv_magic_uv/ui/view3d_copy_paste_uv_objectmode.py
@@ -27,13 +27,11 @@ import bpy
 
 from ..op import copy_paste_uv_object
 from ..utils.bl_class_registry import BlClassRegistry
-
-__all__ = [
-    'MUV_PT_View3D_Object_CopyPasteUV',
-]
+from ..utils import compatibility as compat
 
 
 @BlClassRegistry()
+@compat.ChangeRegionType(region_type='TOOLS')
 class MUV_PT_View3D_Object_CopyPasteUV(bpy.types.Panel):
     """
     Panel class: Copy/Paste UV on Property Panel on View3D
@@ -48,7 +46,7 @@ class MUV_PT_View3D_Object_CopyPasteUV(bpy.types.Panel):
 
     def draw_header(self, _):
         layout = self.layout
-        layout.label(text="", icon='IMAGE')
+        layout.label(text="", icon=compat.icon('IMAGE'))
 
     def draw(self, context):
         sc = context.scene
diff --git a/uv_magic_uv/ui/view3d_uv_manipulation.py b/uv_magic_uv/ui/view3d_uv_manipulation.py
index 4c09bdf298b29ddc17eab16d280541ca5ef60dd4..e385da386720122ffc3a7360be0bff5bc81734c7 100644
--- a/uv_magic_uv/ui/view3d_uv_manipulation.py
+++ b/uv_magic_uv/ui/view3d_uv_manipulation.py
@@ -48,13 +48,11 @@ from ..op.mirror_uv import MUV_OT_MirrorUV
 from ..op.move_uv import MUV_OT_MoveUV
 from ..op.preserve_uv_aspect import MUV_OT_PreserveUVAspect
 from ..utils.bl_class_registry import BlClassRegistry
-
-__all__ = [
-    'MUV_PT_View3D_UVManipulation',
-]
+from ..utils import compatibility as compat
 
 
 @BlClassRegistry()
+@compat.ChangeRegionType(region_type='TOOLS')
 class MUV_PT_View3D_UVManipulation(bpy.types.Panel):
     """
     Panel class: UV Manipulation on Property Panel on View3D
@@ -69,7 +67,7 @@ class MUV_PT_View3D_UVManipulation(bpy.types.Panel):
 
     def draw_header(self, _):
         layout = self.layout
-        layout.label(text="", icon='IMAGE')
+        layout.label(text="", icon=compat.icon('IMAGE'))
 
     def draw(self, context):
         sc = context.scene
@@ -108,11 +106,11 @@ class MUV_PT_View3D_UVManipulation(bpy.types.Panel):
             box.prop(sc, "muv_world_scale_uv_mode", text="")
 
             if sc.muv_world_scale_uv_mode == 'MANUAL':
-                sp = box.split(factor=0.5)
+                sp = compat.layout_split(box, 0.5)
                 col = sp.column()
                 col.prop(sc, "muv_world_scale_uv_tgt_texture_size",
                          text="Texture Size")
-                sp = sp.split(factor=1.0)
+                sp = compat.layout_split(sp, 1.0)
                 col = sp.column()
                 col.label(text="Density:")
                 col.prop(sc, "muv_world_scale_uv_tgt_density", text="")
@@ -125,19 +123,19 @@ class MUV_PT_View3D_UVManipulation(bpy.types.Panel):
                 ops.show_dialog = False
 
             elif sc.muv_world_scale_uv_mode == 'SAME_DENSITY':
-                sp = box.split(factor=0.4)
+                sp = compat.layout_split(box, 0.4)
                 col = sp.column(align=True)
                 col.label(text="Source:")
-                sp = sp.split(factor=1.0)
+                sp = compat.layout_split(sp, 1.0)
                 col = sp.column(align=True)
                 col.operator(MUV_OT_WorldScaleUV_Measure.bl_idname,
                              text="Measure")
 
-                sp = box.split(factor=0.7)
+                sp = compat.layout_split(box, 0.7)
                 col = sp.column(align=True)
                 col.prop(sc, "muv_world_scale_uv_src_density", text="Density")
                 col.enabled = False
-                sp = sp.split(factor=1.0)
+                sp = compat.layout_split(sp, 1.0)
                 col = sp.column(align=True)
                 col.label(text="px2/cm2")
 
@@ -152,19 +150,19 @@ class MUV_PT_View3D_UVManipulation(bpy.types.Panel):
                 ops.show_dialog = False
 
             elif sc.muv_world_scale_uv_mode == 'SCALING_DENSITY':
-                sp = box.split(factor=0.4)
+                sp = compat.layout_split(box, 0.4)
                 col = sp.column(align=True)
                 col.label(text="Source:")
-                sp = sp.split(factor=1.0)
+                sp = compat.layout_split(sp, 1.0)
                 col = sp.column(align=True)
                 col.operator(MUV_OT_WorldScaleUV_Measure.bl_idname,
                              text="Measure")
 
-                sp = box.split(factor=0.7)
+                sp = compat.layout_split(box, 0.7)
                 col = sp.column(align=True)
                 col.prop(sc, "muv_world_scale_uv_src_density", text="Density")
                 col.enabled = False
-                sp = sp.split(factor=1.0)
+                sp = compat.layout_split(sp, 1.0)
                 col = sp.column(align=True)
                 col.label(text="px2/cm2")
 
@@ -183,22 +181,22 @@ class MUV_PT_View3D_UVManipulation(bpy.types.Panel):
                     sc.muv_world_scale_uv_tgt_scaling_factor
 
             elif sc.muv_world_scale_uv_mode == 'PROPORTIONAL_TO_MESH':
-                sp = box.split(factor=0.4)
+                sp = compat.layout_split(box, 0.4)
                 col = sp.column(align=True)
                 col.label(text="Source:")
-                sp = sp.split(factor=1.0)
+                sp = compat.layout_split(sp, 1.0)
                 col = sp.column(align=True)
                 col.operator(MUV_OT_WorldScaleUV_Measure.bl_idname,
                              text="Measure")
 
-                sp = box.split(factor=0.7)
+                sp = compat.layout_split(box, 0.7)
                 col = sp.column(align=True)
                 col.prop(sc, "muv_world_scale_uv_src_mesh_area",
                          text="Mesh Area")
                 col.prop(sc, "muv_world_scale_uv_src_uv_area", text="UV Area")
                 col.prop(sc, "muv_world_scale_uv_src_density", text="Density")
                 col.enabled = False
-                sp = sp.split(factor=1.0)
+                sp = compat.layout_split(sp, 1.0)
                 col = sp.column(align=True)
                 col.label(text="cm2")
                 col.label(text="px2")
diff --git a/uv_magic_uv/ui/view3d_uv_mapping.py b/uv_magic_uv/ui/view3d_uv_mapping.py
index e64a2ce183151819dacbfb4cb5edcdc6edacb239..9a75de4914fb10a709025909d574721574b9c7f4 100644
--- a/uv_magic_uv/ui/view3d_uv_mapping.py
+++ b/uv_magic_uv/ui/view3d_uv_mapping.py
@@ -34,13 +34,11 @@ from ..op.texture_projection import (
 )
 from ..op.unwrap_constraint import MUV_OT_UnwrapConstraint
 from ..utils.bl_class_registry import BlClassRegistry
-
-__all__ = [
-    'MUV_PT_View3D_UVMapping',
-]
+from ..utils import compatibility as compat
 
 
 @BlClassRegistry()
+@compat.ChangeRegionType(region_type='TOOLS')
 class MUV_PT_View3D_UVMapping(bpy.types.Panel):
     """
     Panel class: UV Mapping on Property Panel on View3D
@@ -55,7 +53,7 @@ class MUV_PT_View3D_UVMapping(bpy.types.Panel):
 
     def draw_header(self, _):
         layout = self.layout
-        layout.label(text="", icon='IMAGE')
+        layout.label(text="", icon=compat.icon('IMAGE'))
 
     def draw(self, context):
         sc = context.scene
diff --git a/uv_magic_uv/utils/__init__.py b/uv_magic_uv/utils/__init__.py
index 333a38738f753e12e5148b322122110d9930281a..01b1fc0020cdcb75611e96de503b81d090d3e8f5 100644
--- a/uv_magic_uv/utils/__init__.py
+++ b/uv_magic_uv/utils/__init__.py
@@ -27,10 +27,12 @@ if "bpy" in locals():
     import importlib
     importlib.reload(addon_updator)
     importlib.reload(bl_class_registry)
+    importlib.reload(compatibility)
     importlib.reload(property_class_registry)
 else:
     from . import addon_updator
     from . import bl_class_registry
+    from . import compatibility
     from . import property_class_registry
 
 import bpy
diff --git a/uv_magic_uv/utils/bl_class_registry.py b/uv_magic_uv/utils/bl_class_registry.py
index d173061566fd0369e68c57fec302d4f542325fe7..408e6fd6135844ec3df6b30b90a2516cdf05072f 100644
--- a/uv_magic_uv/utils/bl_class_registry.py
+++ b/uv_magic_uv/utils/bl_class_registry.py
@@ -27,10 +27,6 @@ import bpy
 
 from .. import common
 
-__all__ = [
-    'BlClassRegistry',
-]
-
 
 class BlClassRegistry:
     class_list = []
diff --git a/uv_magic_uv/utils/compatibility.py b/uv_magic_uv/utils/compatibility.py
new file mode 100644
index 0000000000000000000000000000000000000000..2ccd463cd7bf07283d3189cbf0a9156029240a6d
--- /dev/null
+++ b/uv_magic_uv/utils/compatibility.py
@@ -0,0 +1,189 @@
+# <pep8-80 compliant>
+
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software Foundation,
+#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+__author__ = "Nutti <nutti.metro@gmail.com>"
+__status__ = "production"
+__version__ = "5.2"
+__date__ = "17 Nov 2018"
+
+import bpy
+import bgl
+import blf
+
+
+def check_version(major, minor, _):
+    """
+    Check blender version
+    """
+
+    if bpy.app.version[0] == major and bpy.app.version[1] == minor:
+        return 0
+    if bpy.app.version[0] > major:
+        return 1
+    if bpy.app.version[1] > minor:
+        return 1
+    return -1
+
+
+def make_annotations(cls):
+    if check_version(2, 80, 0) < 0:
+        return cls
+
+    # make annotation from attributes
+    props = {k: v for k, v in cls.__dict__.items() if isinstance(v, tuple)}
+    if props:
+        if '__annotations__' not in cls.__dict__:
+            setattr(cls, '__annotations__', {})
+        annotations = cls.__dict__['__annotations__']
+        for k, v in props.items():
+            annotations[k] = v
+            delattr(cls, k)
+
+    return cls
+
+
+class ChangeRegionType:
+    def __init__(self, *_, **kwargs):
+        self.region_type = kwargs.get('region_type', False)
+
+    def __call__(self, cls):
+        if check_version(2, 80, 0) >= 0:
+            return cls
+
+        cls.bl_region_type = self.region_type
+
+        return cls
+
+
+def matmul(m1, m2):
+    if check_version(2, 80, 0) < 0:
+        return m1 * m2
+
+    return m1 @ m2
+
+
+def layout_split(layout, factor=0.0, align=False):
+    if check_version(2, 80, 0) < 0:
+        return layout.split(percentage=factor, align=align)
+
+    return layout.split(factor=factor, align=align)
+
+
+def get_user_preferences(context):
+    if hasattr(context, "user_preferences"):
+        return context.user_preferences
+
+    return context.preferences
+
+
+def get_object_select(obj):
+    if check_version(2, 80, 0) < 0:
+        return obj.select
+
+    return obj.select_get()
+
+
+def set_active_object(obj):
+    if check_version(2, 80, 0) < 0:
+        bpy.context.scene.objects.active = obj
+    else:
+        bpy.context.view_layer.objects.active = obj
+
+
+def get_active_object(context):
+    if check_version(2, 80, 0) >= 0:
+        return context.scene.active_object
+    else:
+        return context.active_object
+
+
+def object_has_uv_layers(obj):
+    if check_version(2, 80, 0) < 0:
+        return hasattr(obj.data, "uv_textures")
+    else:
+        return hasattr(obj.data, "uv_layers")
+
+
+def get_object_uv_layers(obj):
+    if check_version(2, 80, 0) < 0:
+        return obj.data.uv_textures
+    else:
+        return obj.data.uv_layers
+
+
+def icon(icon):
+    if icon == 'IMAGE':
+        if check_version(2, 80, 0) < 0:
+            return 'IMAGE_COL'
+
+    return icon
+
+
+def set_blf_font_color(font_id, r, g, b, a):
+    if check_version(2, 80, 0) >= 0:
+        blf.color(font_id, r, g, b, a)
+    else:
+        bgl.glColor4f(r, g, b, a)
+
+
+def set_blf_blur(font_id, radius):
+    if check_version(2, 80, 0) < 0:
+        blf.blur(font_id, radius)
+
+
+def get_all_space_types():
+    if check_version(2, 80, 0) >= 0:
+        return {
+            'CLIP_EDITOR': bpy.types.SpaceClipEditor,
+            'CONSOLE': bpy.types.SpaceConsole,
+            'DOPESHEET_EDITOR': bpy.types.SpaceDopeSheetEditor,
+            'FILE_BROWSER': bpy.types.SpaceFileBrowser,
+            'GRAPH_EDITOR': bpy.types.SpaceGraphEditor,
+            'IMAGE_EDITOR': bpy.types.SpaceImageEditor,
+            'INFO': bpy.types.SpaceInfo,
+            'NLA_EDITOR': bpy.types.SpaceNLA,
+            'NODE_EDITOR': bpy.types.SpaceNodeEditor,
+            'OUTLINER': bpy.types.SpaceOutliner,
+            'PROPERTIES': bpy.types.SpaceProperties,
+            'SEQUENCE_EDITOR': bpy.types.SpaceSequenceEditor,
+            'TEXT_EDITOR': bpy.types.SpaceTextEditor,
+            'USER_PREFERENCES': bpy.types.SpacePreferences,
+            'VIEW_3D': bpy.types.SpaceView3D,
+        }
+    else:
+        return {
+            'VIEW_3D': bpy.types.SpaceView3D,
+            'TIMELINE': bpy.types.SpaceTimeline,
+            'GRAPH_EDITOR': bpy.types.SpaceGraphEditor,
+            'DOPESHEET_EDITOR': bpy.types.SpaceDopeSheetEditor,
+            'NLA_EDITOR': bpy.types.SpaceNLA,
+            'IMAGE_EDITOR': bpy.types.SpaceImageEditor,
+            'SEQUENCE_EDITOR': bpy.types.SpaceSequenceEditor,
+            'CLIP_EDITOR': bpy.types.SpaceClipEditor,
+            'TEXT_EDITOR': bpy.types.SpaceTextEditor,
+            'NODE_EDITOR': bpy.types.SpaceNodeEditor,
+            'LOGIC_EDITOR': bpy.types.SpaceLogicEditor,
+            'PROPERTIES': bpy.types.SpaceProperties,
+            'OUTLINER': bpy.types.SpaceOutliner,
+            'USER_PREFERENCES': bpy.types.SpaceUserPreferences,
+            'INFO': bpy.types.SpaceInfo,
+            'FILE_BROWSER': bpy.types.SpaceFileBrowser,
+            'CONSOLE': bpy.types.SpaceConsole,
+        }
diff --git a/uv_magic_uv/utils/property_class_registry.py b/uv_magic_uv/utils/property_class_registry.py
index 20df03422af86198fba12c33d3d493b0a9fabd66..4e89da5409f0e773da79ed8f5782e9ddba96e52f 100644
--- a/uv_magic_uv/utils/property_class_registry.py
+++ b/uv_magic_uv/utils/property_class_registry.py
@@ -25,10 +25,6 @@ __date__ = "17 Nov 2018"
 
 from .. import common
 
-__all__ = [
-    'PropertyClassRegistry',
-]
-
 
 class PropertyClassRegistry:
     class_list = []