OverviewFilesCommitsIssuesDocsReleasesPeers

hardops / operators / modifiers / wireframe.py

261 lines · python ref:
import bpy, math
from mathutils import Vector
from ... utility import addon
from ... ui_framework.master import Master
from ... ui_framework.utils.mods_list import get_mods_list
from ... utility.base_modal_controls import Base_Modal_Controls

# Cursor Warp imports
from ... utils.toggle_view3d_panels import collapse_3D_view_panels
from ... utils.modal_frame_drawing import draw_modal_frame
from ... utils.cursor_warp import mouse_warp
from ... utility import method_handler


class HOPS_OT_MOD_Wireframe(bpy.types.Operator):
    bl_idname = "hops.mod_wireframe"
    bl_label = "Adjust Wireframe Modifier"
    bl_options = {"REGISTER", "UNDO", "BLOCKING"}
    bl_description = """
LMB - Adjust Wireframe Modifier
LMB + CTRL - Add new Wireframe Modifier

Press H for help
"""

    wireframe_objects = {}

    @classmethod
    def poll(cls, context):
        return any(o.type == 'MESH' for o in context.selected_objects)

    @staticmethod
    def wireframe_modifiers(object):
        return [modifier for modifier in object.modifiers if modifier.type == "WIREFRAME"]


    def invoke(self, context, event):

        self.modal_scale = addon.preference().ui.Hops_modal_scale
        self.wireframe_objects = {}

        for object in [o for o in context.selected_objects if o.type == 'MESH']:
            self.get_deform_modifier(object, event)

        self.active_wireframe_modifier = context.object.modifiers[self.wireframe_objects[context.object.name]["modifier"]]
        self.store_values()

        # Base Systems
        self.master = Master(context=context)
        self.master.only_use_fast_ui = True
        self.base_controls = Base_Modal_Controls(context, event)
        self.original_tool_shelf, self.original_n_panel = collapse_3D_view_panels()
        self.draw_handle = bpy.types.SpaceView3D.draw_handler_add(self.safe_draw_shader, (context,), 'WINDOW', 'POST_PIXEL')

        context.window_manager.modal_handler_add(self)
        return {"RUNNING_MODAL"}


    def modal(self, context, event):

        # Base Systems
        self.master.receive_event(event=event)
        self.base_controls.update(context, event)
        mouse_warp(context, event)

        if self.base_controls.pass_through:
            return {'PASS_THROUGH'}

        offset = self.base_controls.mouse
        context.area.header_text_set("Hardops Wireframe:      B : use_boundary - {}      C : use_crease - {}      Q : use_even_offset - {}      W : use_relative_offset - {}".format(self.active_wireframe_modifier.use_boundary, self.active_wireframe_modifier.use_crease, self.active_wireframe_modifier.use_even_offset, self.active_wireframe_modifier.use_relative_offset))

        for object_name in self.wireframe_objects:
            object = bpy.data.objects[object_name]
            modifier = object.modifiers[self.wireframe_objects[object_name]["modifier"]]

            if self.base_controls.scroll:
                if event.shift:
                    if self.base_controls.scroll ==1:
                        bpy.ops.object.modifier_move_up(modifier=modifier.name)
                    else:
                        bpy.ops.object.modifier_move_down(modifier=modifier.name)

            if event.ctrl:
                modifier.offset = modifier.offset + offset
            else:
                modifier.thickness = modifier.thickness + offset

            if event.type == "Q" and event.value == "PRESS":
                modifier.use_even_offset = not modifier.use_even_offset

            if event.type == "W" and event.value == "PRESS":
                modifier.use_relative_offset = not modifier.use_relative_offset

            if event.type == "E" and event.value == "PRESS":
                modifier.use_replace = not modifier.use_replace

            if event.type == "B" and event.value == "PRESS":
                modifier.use_boundary = not modifier.use_boundary

            if event.type == "C" and event.value == "PRESS":
                modifier.use_crease = not modifier.use_crease

            if event.type == "Q" and event.value == "PRESS":
                bpy.ops.object.modifier_move_up(modifier=modifier.name)

            if event.type == "W" and event.value == "PRESS":
                bpy.ops.object.modifier_move_down(modifier=modifier.name)

            if event.type == "H" and event.value == "PRESS":
                bpy.context.space_data.show_gizmo_navigate = True

            if self.base_controls.cancel:
                self.restore()
                context.area.header_text_set(text=None)
                self.remove_shader()
                collapse_3D_view_panels(self.original_tool_shelf, self.original_n_panel)
                self.master.run_fade()
                return {'CANCELLED'}

            if self.base_controls.confirm:
                context.area.header_text_set(text=None)
                self.remove_shader()
                collapse_3D_view_panels(self.original_tool_shelf, self.original_n_panel)
                self.master.run_fade()
                return {'FINISHED'}

        self.draw_master(context=context)
        context.area.tag_redraw()
        return {"RUNNING_MODAL"}


    def get_deform_modifier(self, object, event):
        if event.ctrl:
            self.add_deform_modifier(object)
        else:
            try: self.wireframe_objects.setdefault(object.name, {})["modifier"] = self.wireframe_modifiers(object)[-1].name
            except: self.add_deform_modifier(object)


    def add_deform_modifier(self, object):
        wireframe_modifier = object.modifiers.new(name="Wireframe", type="WIREFRAME")
        wireframe_modifier.thickness = 0.2
        wireframe_modifier.use_even_offset = True
        wireframe_modifier.use_relative_offset = False
        wireframe_modifier.use_replace = True
        wireframe_modifier.use_boundary = True

        self.wireframe_objects.setdefault(object.name, {})["modifier"] = wireframe_modifier.name
        self.wireframe_objects[object.name]["added_modifier"] = True


    def store_values(self):
        for object_name in self.wireframe_objects:
            object = bpy.data.objects[object_name]
            modifier = object.modifiers[self.wireframe_objects[object_name]["modifier"]]
            self.wireframe_objects[object_name]["show_viewport"] = modifier.show_viewport
            self.wireframe_objects[object_name]["thickness"] = modifier.thickness
            self.wireframe_objects[object_name]["offset"] = modifier.offset
            self.wireframe_objects[object_name]["use_even_offset"] = modifier.use_even_offset
            self.wireframe_objects[object_name]["use_relative_offset"] = modifier.use_relative_offset
            self.wireframe_objects[object_name]["use_replace"] = modifier.use_replace
            self.wireframe_objects[object_name]["use_boundary"] = modifier.use_boundary
            self.wireframe_objects[object_name]["use_crease"] = modifier.use_crease


    def restore(self):
        for object_name in self.wireframe_objects:
            object = bpy.data.objects[object_name]
            if "added_modifier" in self.wireframe_objects[object_name]:
                object.modifiers.remove(object.modifiers[self.wireframe_objects[object_name]["modifier"]])
            else:
                modifier = object.modifiers[self.wireframe_objects[object_name]["modifier"]]
                modifier.show_viewport = self.wireframe_objects[object_name]["show_viewport"]
                modifier.thickness = self.wireframe_objects[object_name]["thickness"]
                modifier.offset = self.wireframe_objects[object_name]["offset"]
                modifier.use_even_offset = self.wireframe_objects[object_name]["use_even_offset"]
                modifier.use_relative_offset = self.wireframe_objects[object_name]["use_relative_offset"]
                modifier.use_replace = self.wireframe_objects[object_name]["use_replace"]
                modifier.use_boundary = self.wireframe_objects[object_name]["use_boundary"]
                modifier.use_crease = self.wireframe_objects[object_name]["use_crease"]


    def draw_master(self, context):

        # Start
        self.master.setup()


        ########################
        #   Fast UI
        ########################


        if self.master.should_build_fast_ui():

            # Main
            win_list = []
            if addon.preference().ui.Hops_modal_fast_ui_loc_options != 1: #Fast Floating
                win_list.append("{:.3f}".format(self.active_wireframe_modifier.thickness))
                win_list.append("{:.3f}".format(self.active_wireframe_modifier.offset))
                win_list.append("{}".format(self.active_wireframe_modifier.use_replace))
            else:
                win_list.append("Wireframe")
                win_list.append("Thick: {:.3f}".format(self.active_wireframe_modifier.thickness))
                win_list.append("Offset: {:.3f}".format(self.active_wireframe_modifier.offset))
                win_list.append("Replace: {}".format(self.active_wireframe_modifier.use_replace))

            # Help
            help_items = {"GLOBAL" : [], "STANDARD" : []}

            help_items["GLOBAL"] = [
                ("M", "Toggle mods list"),
                ("H", "Toggle help"),
                ("~", "Toggle UI Display Type"),
                ("O", "Toggle viewport rendering")]

            help_items["STANDARD"] = [
                ("Move",           "set thickness"),
                ("Ctrl",           "set offset"),
                ("Q",              "Use even offset"),
                ("W",              "Use relative offset"),
                ("E",              "Use replace"),
                ("C",              "Use crease"),
                ("B",              "Use boundary"),
                ("Q",              "Move mod DOWN"),
                ("W",              "Move mod UP"),
                ("Shift + Scroll", "Move mod up/down")]

            # Mods
            active_mod = ""
            if self.active_wireframe_modifier != None:
                active_mod = self.active_wireframe_modifier.name
            mods_list = get_mods_list(mods=bpy.context.active_object.modifiers)

            self.master.receive_fast_ui(win_list=win_list, help_list=help_items, image="AdjustBevel", mods_list=mods_list, active_mod_name=active_mod)

        # Finished
        self.master.finished()

    ####################################################
    #   CURSOR WARP
    ####################################################

    def safe_draw_shader(self, context):
        method_handler(self.draw_shader,
            arguments = (context,),
            identifier = 'UI Framework',
            exit_method = self.remove_shader)


    def remove_shader(self):
        '''Remove shader handle.'''

        if self.draw_handle:
            self.draw_handle = bpy.types.SpaceView3D.draw_handler_remove(self.draw_handle, "WINDOW")


    def draw_shader(self, context):
        '''Draw shader handle.'''

        draw_modal_frame(context)