OverviewFilesCommitsIssuesDocsReleasesPeers

hardops / ui / legacy-hops_helper.py

543 lines · python ref:
import bpy
from bpy.types import PropertyGroup
from bpy.props import BoolProperty, EnumProperty
from .. utils.blender_ui import get_dpi_factor
from bl_ui.properties_data_modifier import DATA_PT_modifiers
from .. utility import addon


class HopsHelperOptions(PropertyGroup):

    operators_options: BoolProperty(
        name="Operators options",
        description="Display Hardops operator settings",
        default=False
    )

    sharp_options: BoolProperty(
        name="Sharp options",
        description="Display pre-sharp options",
        default=True
    )

    mesh_options: BoolProperty(
        name="Mesh options",
        description="General Mesh configuration settings",
        default=False
    )

    status: BoolProperty(
        name="Status",
        description="General sstatus behavioral options",
        default=False
    )

    surface: BoolProperty(
        name="Surface",
        description="Display surface settings",
        default=False
    )

    settings: BoolProperty(
        name="Settings",
        description="Display additional settings",
        default=False
    )

    preview: BoolProperty(
        name="Preview",
        description="Display preview",
        default=False
    )

    cutting_material: BoolProperty(
        name="Cutting Material",
        description="Display cutting material settings",
        default=True
    )

    meshclean_options: BoolProperty(
        name="Mesh clean Material",
        description="Display meshclean settings",
        default=False
    )

    mirror_options: BoolProperty(
        name="Mirror options",
        description="Display mirroring settings",
        default=True
    )


def find_node(material, nodetype):
    if material and material.node_tree:
        ntree = material.node_tree

        active_output_node = None
        for node in ntree.nodes:
            if getattr(node, "type", None) == nodetype:
                if getattr(node, "is_active_output", True):
                    return node
                if not active_output_node:
                    active_output_node = node
        return active_output_node

    return None


def find_node_input(node, name):
    for input in node.inputs:
        if input.name == name:
            return input

    return None


def panel_node_draw(layout, id_data, output_type, input_name):
    if not id_data.use_nodes:
        layout.operator("cycles.use_shading_nodes", icon='NODETREE')
        return False

    ntree = id_data.node_tree

    node = find_node(id_data, output_type)
    if not node:
        layout.label(text ="No output node")
    else:
        input = find_node_input(node, input_name)
        layout.template_node_view(ntree, node, input)

    return True

helper_tabs_items = [
    ("MODIFIERS", "Modifiers", ""),
    ("MATERIALS", "Materials", ""),
    ("MISC", "Misc", "")]

hops_status = [
    ("UNDEFINED", "Undefined", ""),
    ("BOOLSHAPE", "Boolshape", "")]


class HOPS_OT_HelperPopup(bpy.types.Operator):
    """
    Displays modifers / material / hardops popup helper.

    """
    bl_idname = "view3d.hops_helper_popup"
    bl_label = "HOps Helper"

    tab: EnumProperty(name="Tab", default="MODIFIERS",
                      options={"SKIP_SAVE"}, items=helper_tabs_items)

    status: EnumProperty(name="Status", default="UNDEFINED",
                         options={"SKIP_SAVE"}, items=hops_status)

    # mesh_tools = BoolProperty(name = "Z Axis", description = "Z Axis", default = False)

    def execute(self, context):
        self.set_helper_default(context)
        self.set_hops_status(context)
        return {'FINISHED'}

    def cancel(self, context):
        self.set_helper_default(context)
        self.set_hops_status(context)

    def check(self, context):
        return True

    def invoke(self, context, event):
        object = bpy.context.active_object
        if object is not None:
            if object.type == "MESH":
                self.status = object.hops.status
        self.tab = addon.preference().property.helper_tab
        return context.window_manager.invoke_props_dialog(self, width=int(300 * get_dpi_factor(force=False)))

    def set_helper_default(self, context):
        if self.tab == "MODIFIERS":
            addon.preference().property.helper_tab = "MODIFIERS"
        elif self.tab == "MATERIALS":
            addon.preference().property.helper_tab = "MATERIALS"
        elif self.tab == "MISC":
            addon.preference().property.helper_tab = "MISC"

    def set_hops_status(self, context):
        object = bpy.context.active_object
        if object is not None:
            if object.type == "MESH":
                if self.status == "UNDEFINED":
                    object.hops.status = "UNDEFINED"
                elif self.status == "BOOLSHAPE":
                    object.hops.status = "BOOLSHAPE"


    def draw(self, context):
        layout = self.layout
        self.draw_tab_bar(layout)

        if self.tab == "MODIFIERS":
            self.draw_modifier_tab(layout)
        elif self.tab == "MATERIALS":
            self.draw_material_tab(context, layout)
        elif self.tab == "MISC":
            self.draw_misc_tab(context, layout)

    def draw_tab_bar(self, layout):
        row = layout.row()
        row.prop(self, "tab", expand=True)
        layout.separator()

    def draw_modifier_tab(self, layout):

        col = layout.column(align=True)
        object = bpy.context.active_object
        if object is None:
            colrow = col.row(align=True)
            colrow.alignment = "CENTER"
            colrow.label(text="No active object", icon="INFO")
            return

        colrow = col.row(align=True)
        colrow.operator_menu_enum("object.modifier_add", "type")
        colrow.operator("object.make_links_data", text="Copy Modifiers").type = "MODIFIERS"
        colrow.operator("hops.open_modifiers", text="", icon="TRIA_DOWN")
        colrow.operator("hops.collapse_modifiers", text="", icon="TRIA_UP")

        modifiers_panel = DATA_PT_modifiers(bpy.context)
        for modifier in object.modifiers:
            box = layout.template_modifier(modifier)
            if box:
                getattr(modifiers_panel, modifier.type)(box, object, modifier)

    def draw_material_tab(self, context, layout):

        object = context.active_object
        option = context.window_manager.Hard_Ops_helper_options

        if object:
            is_sortable = len(object.material_slots) > 1
            rows = 2

            if (is_sortable):
                rows = 4
            row = layout.row()
            row.context_pointer_set('material', object.active_material)

            row.template_list("MATERIAL_UL_matslots", "", object, "material_slots", object, "active_material_index", rows=rows)

            col = row.column(align=True)
            col.operator("object.material_slot_add", icon='ADD', text="")
            col.operator("object.material_slot_remove", icon='REMOVE', text="")

            col.menu("MATERIAL_MT_specials", icon='DOWNARROW_HLT', text="")

            if is_sortable:
                col.separator()
                col.operator("object.material_slot_move", icon='TRIA_UP', text="").direction = 'UP'
                col.operator("object.material_slot_move", icon='TRIA_DOWN', text="").direction = 'DOWN'

            if object.mode == 'EDIT':
                row = layout.row(align=True)
                row.operator("object.material_slot_assign", text="Assign")
                row.operator("object.material_slot_select", text="Select")
                row.operator("object.material_slot_deselect", text="Deselect")

        if object:
            split = layout.split(factor=0.65)
            slot = object.material_slots[object.active_material_index] if object.material_slots else None
            split.template_ID(object, "active_material", new="material.hops_new")
            row = split.row()

            if slot:
                row.prop(slot, "link", text="")

            else:
                row.label(text="")

        column = layout.column(align=True)
        if object and object.material_slots and object.active_material:

            box = column.box()
            row = box.row(align=True)
            row.alignment = 'LEFT'
            sub = row.row(align=True)
            # sub.scale_x = 0.5
            sub.prop(option, "preview", icon="TRIA_DOWN" if option.settings else "TRIA_RIGHT", text="", emboss=False)
            row.prop(option, "preview", text="Preview", toggle=True, emboss=False)
            sub = row.row(align=True)
            sub.prop(option, "preview", text=" ", toggle=True, emboss=False)

            if option.preview:
                box = column.box()
                col = box.column()
                split = col.split()
                col = split.column(align=True)
                col.label(text="Preview:")
                #self.layout.template_preview(context.material)
                col.template_preview(context.active_object.active_material)

            column.separator()
            box = column.box()
            row = box.row(align=True)
            row.alignment = 'LEFT'
            sub = row.row(align=True)
            # sub.scale_x = 0.5
            sub.prop(option, "surface", icon="TRIA_DOWN" if option.surface else "TRIA_RIGHT", text="", emboss=False)
            row.prop(option, "surface", text="Surface", toggle=True, emboss=False)
            sub = row.row(align=True)
            sub.prop(option, "surface", text=" ", toggle=True, emboss=False)

            if option.surface:
                box = column.box()

                if not panel_node_draw(box, object.active_material, 'OUTPUT_MATERIAL', 'Surface'):
                    row = layout.row()
                    row.prop(object.active_material, "diffuse_color")

            column.separator()
            box = column.box()
            row = box.row(align=True)
            row.alignment = 'LEFT'
            sub = row.row(align=True)
            # sub.scale_x = 0.5
            sub.prop(option, "settings", icon="TRIA_DOWN" if option.settings else "TRIA_RIGHT", text="", emboss=False)
            row.prop(option, "settings", text="Settings", toggle=True, emboss=False)
            sub = row.row(align=True)
            sub.prop(option, "settings", text=" ", toggle=True, emboss=False)

            if option.settings:
                box = column.box()
                col = box.column()
                split = col.split()
                col = split.column(align=True)
                col.label(text="Viewport Color:")
                col.prop(object.active_material, "diffuse_color", text="")
                #col.prop(object.active_material, "specular_color", text="")
                #col.prop(object.active_material, "roughness")
                col.label(text="Transparency Type:")
                col.prop(object.active_material, "blend_method", text="")
                col.prop(object, "show_transparent", text="Transparency")
                col.label(text="Pass Index:")
                col.prop(object.active_material, "pass_index", text ='')
            column.separator()

        box = column.box()
        row = box.row(align=True)
        row.alignment = 'LEFT'
        sub = row.row(align=True)
        sub.prop(option, "cutting_material", icon="TRIA_DOWN" if option.cutting_material else "TRIA_RIGHT", text="", emboss=False)
        row.prop(option, "cutting_material", text="Cutting Material", toggle=True, emboss=False)
        sub = row.row(align=True)
        sub.prop(option, "cutting_material", text=" ", toggle=True, emboss=False)

        if option.cutting_material:
            box = column.box()

            material_option = context.window_manager.Hard_Ops_material_options

            col = box.column(align=True)
            row = col.row(align=True)
            row.prop(material_option, "material_mode", expand=True)
            row = col.row(align=True)

            if material_option.material_mode == "ALL":
                row.prop_search(material_option, "active_material", bpy.data, "materials", text="")

            else:
                row.prop_search(material_option, "active_material", context.active_object, "material_slots", text="")

            row.prop(material_option, "force", text="", icon="FORCE_FORCE")

    def draw_misc_tab(self, context, layout):
        # layout.label(text="Coming To 008!", icon="INFO")

        ob = context.object
        active_object = context.active_object
        option = context.window_manager.Hard_Ops_helper_options

        layout = self.layout

        # box = layout.box().column(1)
        # row = box.row(1)

        col = layout.box().column(align=True)

        col.separator()
        colrow = col.row(align=True)
        colrow.prop(addon.preference().property, "workflow", expand=True)
        # colrow = col.row(align=True).split(factor=0.1, align=True)
        # colrow.prop(addon.preference().property, "add_weighten_normals_mod", toggle=True)
        # colrow = col.row(align=True).split(factor=0.1, align=True)
        # colrow.prop(addon.preference().property, "use_harden_normals", toggle=True)
        colrow2 = colrow.row(align=True)
        colrow2.prop(addon.preference().property, "workflow_mode", expand=True)
        col.separator()

        col = layout.box().column(align=True)
        col.prop(option, "sharp_options", icon="TRIA_DOWN" if option.sharp_options else "TRIA_RIGHT", text="Sharps", emboss=False)

        if option.sharp_options:
            col = layout.column(align=True)

            col.separator()
            colrow = col.row(align=True)
            colrow.prop(addon.preference().property, "sharp_use_crease", text="Apply crease")
            colrow.prop(addon.preference().property, "sharp_use_bweight", text="Apply bweight")

            colrow = col.row(align=True)
            colrow.prop(addon.preference().property, "sharp_use_seam", text="Apply seam")
            colrow.prop(addon.preference().property, "sharp_use_sharp", text="Apply sharp")

            col.separator()
            colrow = col.row(align=True)
            colrow.operator("hops.set_sharpness_30", text="30")
            colrow.operator("hops.set_sharpness_45", text="45")
            colrow.operator("hops.set_sharpness_60", text="60")

            col.prop(addon.preference().property, "sharpness", text="Sharpness")
            col = layout.box().column(align=True)

        col.prop(option, "mirror_options", icon="TRIA_DOWN" if option.mirror_options else "TRIA_RIGHT", text="Mirror Options", emboss=False)

        if option.mirror_options:
            col = layout.column(align=True)

            col.separator()
            colrow = col.row(align=True)
            colrow.prop(addon.preference().property, "Hops_mirror_modes", text="aa", expand=True)
            if addon.preference().property.property.Hops_mirror_modes in {"BISECT", "SYMMETRY"}:
                colrow = col.row(align=True)
                colrow.prop(addon.preference().property, "Hops_mirror_direction", text="vv", expand=True)

            col = layout.box().column(align=True)

        col.prop(option, "operators_options", icon="TRIA_DOWN" if option.operators_options else "TRIA_RIGHT", text="Operators Options", emboss=False)

        if option.operators_options:
            col = layout.column(align=True)

            col.separator()
            colrow = col.row(align=True)
            colrow.label(text='Modals :')

            col.separator()
            colrow = col.row(align=True)
            colrow.prop(addon.preference().property, "Hops_modal_scale", text="Modal Scale")
            colrow.prop(addon.preference().property, "adaptivewidth", text="Adapitve")

            col.separator()
            colrow = col.row(align=True)
            colrow.label(text='CSharpen :')
            col.separator()
            colrow = col.row(align=True)
            colrow.prop(addon.preference().property, "bevel_loop_slide", text="use Loop slide")
            colrow.prop(addon.preference().property, "auto_bweight", text="jump to (B)Width")

            col.separator()
            colrow = col.row(align=True)
            colrow.label(text='Mirror :')
            colrow = col.row(align=True)
            colrow.prop(addon.preference().operator.mirror, "scale", text="Mirror Scale")
            colrow.prop(addon.preference().operator.mirror, "width", text="Mirror Width")
            colrow = col.row(align=True)
            colrow.prop(addon.preference().property, "Hops_mirror_modal_Interface_scale", text="Mirror Interface Scale")
            colrow.prop(addon.preference().property, "Hops_mirror_modal_revert", text="Revert")
            col.separator()

            col.separator()
            colrow = col.row(align=True)
            colrow.label(text='CutIn :')
            colrow.prop(addon.preference().property, "keep_cutin_bevel", expand=True)
            col.separator()

            colrow = col.row(align=True)
            colrow.label(text='Array :')
            colrow.prop(addon.preference().property, "force_array_reset_on_init", expand=True)
            colrow = col.row(align=True)
            colrow.label(text='')
            colrow.prop(addon.preference().property, "force_array_apply_scale_on_init", expand=True)
            col.separator()

            col.separator()
            colrow = col.row(align=True)
            colrow.label(text='Thick :')
            colrow.prop(addon.preference().property, "force_thick_reset_solidify_init", expand=True)
            col.separator()

            col = layout.box().column(align=True)

        col.prop(option, "status", icon="TRIA_DOWN" if option.status else "TRIA_RIGHT", text="Status", emboss=False)

        if option.status:
            col = layout.column(align=True)
            colrow = col.row(align=True)
            colrow.prop(self, "status", expand=True)
            col = layout.box().column(align=True)

        col.prop(option, "mesh_options", icon="TRIA_DOWN" if option.mesh_options else "TRIA_RIGHT", text="Mesh Options", emboss=False)

        if option.mesh_options:
            col = layout.column(align=True)
            if ob:
                if active_object.type == "MESH":

                    colrow = col.row(align=True)
                    obj = bpy.context.object
                    # colrow.label(text ="Name:")
                    colrow.prop(obj, "name", text="")

                    col.separator()

                    colrow = col.row(align=True)
                    colrow.operator("object.shade_smooth", text="Set Smooth")
                    colrow.operator("object.shade_flat", text="Shade Flat")

                    colrow = col.row(align=True)
                    asmooth = bpy.context.object.data
                    colrow.prop(asmooth, "auto_smooth_angle", text="Auto Smooth Angle")
                    colrow.prop(asmooth, "use_auto_smooth", text="Auto Smooth")

                    col.separator()

                    colrow = col.row(align=True)
                    swire = bpy.context.object
                    colrow.prop(swire, "show_wire", text="Show Wire")
                    colrow.prop(swire, "show_all_edges", text="Show All Edges")

                    col.separator()

                    colrow = col.row(align=True)
                    colrow.label(text ="Parent:")
                    colrow.prop(ob, "parent", text="")

                    col.separator()

                elif active_object.type == "CURVE":
                    layout.label(text="Curve Stuff Soon", icon="INFO")

                    # the idea is that curve stuff will be here for quick options for things the q menu cant do.
            else:
                col.label(text="add object first", icon="INFO")

        col.prop(option, "meshclean_options", icon="TRIA_DOWN" if option.meshclean_options else "TRIA_RIGHT", text="Mesh Clean Options", emboss=False)

        if option.meshclean_options:
            col = layout.column(align=True)

            col.separator()
            colrow = col.row(align=True)
            colrow.prop(addon.preference().property, 'meshclean_mode', expand=True)
            colrow = col.row(align=True)
            colrow.prop(addon.preference().property, 'meshclean_dissolve_angle', text="Limited Dissolve Angle")
            colrow = col.row(align=True)
            colrow.prop(addon.preference().property, 'meshclean_remove_threshold', text="Remove Threshold")
            colrow = col.row(align=True)
            colrow.prop(addon.preference().property, 'meshclean_unhide_behavior', text="Unhide Mesh")
            colrow = col.row(align=True)
            colrow.prop(addon.preference().property, 'meshclean_delete_interior', text="Delete Interior Faces")


        layout.separator()