OverviewFilesCommitsIssuesDocsReleasesPeers

hardops / src / panel / button.py

537 lines · python ref:
import bpy

from bpy.types import Panel
from math import radians
from ... icons import get_icon_id
from ... ui.hops_helper.utility import draw_panel, init_panels
from ... utility import addon
from ... import bl_info

def menu():
    wm = bpy.context.window_manager
    option = wm.Hard_Ops_button_options

    if 'options' not in option.panels:
        option.name = 'HardOps Helper'

        new = option.panels.add()
        new.name = 'options'

        new.operators.add().name = 'Operators'
        # new.tool.add().name = 'Tool'

    return option


class HOPS_PT_Button(Panel):
    bl_label = f'''HOps: {bl_info['version'][0]}.{bl_info['version'][1]}.{bl_info['version'][2]}'''
    bl_description = f'''{bl_info['description']}'''
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = 'HardOps'

    panels: dict = {}
    label: bool = False
    mods: list = []

    def draw(self, context):
        layout = self.layout
        wm = bpy.context.window_manager
        button = wm.Hard_Ops_button_options

        if not button.context:
            button.context = 'OPERATORS'
        # option = options()

        # split = layout.split(factor=0.1, align=True)
        row = layout.column().row()

        # column = split.column(align=True)
        row.scale_x = 1.25
        row.scale_y = 1.25

        if self.is_popover:
            layout.ui_units_x = 8

        label = {
            'OPERATORS': ' ',
            'TOOL': 'Render',
            'OPT': 'Opt-ins',
            'KITOPS': ' ',
            'HELPER': f'''{bl_info['version'][0]}.{bl_info['version'][1]}{bl_info['version'][2]} Helper''',
            'BEVEL_HELPER': 'Bevel Helper',
            'HELP': ' ',
            'KEYMAP': 'Hops Keymap'}

        if button.context not in {'OPERATORS', 'KITOPS'}:
            row.label(text=label[button.context])

        else:
            row.alignment = 'RIGHT'

        row.prop(menu(), 'context', expand=True, icon_only=True)
        layout.separator()

        column = layout.column()

        if button.context == 'OPERATORS':

            #column.label(text=f"HOps: {bl_info['version'][1]}.{bl_info['version'][2]}")
            if addon.preference().needs_update == 'Connection Failed':
                column.label(text=f'''{bl_info['description']}''')
                column.operator("hops.about", text = f"HOps: {bl_info['version'][0]}.{bl_info['version'][1]}.{bl_info['version'][2]}",  icon_value=get_icon_id("logo_grey"))
            elif addon.preference().needs_update:# and not 'Connection Failed':
                column.label(text=f'''{bl_info['description']}''', icon='ERROR')
                column.operator("hops.about", text = f"HOps: {bl_info['version'][0]}.{bl_info['version'][1]}.{bl_info['version'][2]}",  icon_value=get_icon_id("logo_red"))

                split = column.row(align=True)
                row = split.row(align=True)
                col = row.column(align=True)
                col.scale_x = 1.5
                col.scale_y = 1.5

                row.operator("wm.url_open", text="", icon_value=get_icon_id("bmarket")).url = "https://www.blendermarket.com/account/orders"
                row.operator("wm.url_open", text="", icon_value=get_icon_id("artstation")).url = "https://www.artstation.com/marketplace/orders"
                row.operator("wm.url_open", text="", icon_value=get_icon_id("gumroad")).url = "https://gumroad.com/library"
                row.label(text="Update")
                row.operator("wm.url_open", text="", icon="INFO").url = "https://hardops-manual.readthedocs.io/en/latest/faq/#how-do-i-update-hard-ops-boxcutter"
            else:
                column.label(text=f'''{bl_info['description']}''')
                column.operator("hops.about", text = f"HOps: {bl_info['version'][0]}.{bl_info['version'][1]}.{bl_info['version'][2]}",  icon_value=get_icon_id("logo_green"))

            #column.label(text=f"{bl_info['description']}")


            object = context.active_object

            if object is None or len(bpy.context.selected_objects) == 0:
                column.label(text='No Selection')
                if addon.preference().property.accushape_type == 'V2':
                    column.operator("hops.accu_shape_v2", text="AccuShape V2", icon_value=get_icon_id("grey"))
                else:
                    column.operator("hops.accu_shape", text="AccuShape", icon_value=get_icon_id("grey"))

            elif object and object.mode == 'OBJECT' and object.type == 'MESH':
                column.separator()
                #box = column.box().column()
                column.label(text='Operators')
                box = column.box().column()
                #box.operator("hops.soft_sharpen", text="(S) Sharpen", icon_value=get_icon_id("Ssharpen"))
                #box.operator("hops.complex_sharpen", text="(C) Sharpen", icon_value=get_icon_id("CSharpen"))
                box.operator("hops.sharpen", text="Sharpen", icon_value=get_icon_id("Ssharpen"))
                box.operator("hops.adjust_bevel", text="Bevel", icon_value=get_icon_id("AdjustBevel"))
                #box.operator("hops.apply_modifiers", text="Smart Apply", icon_value=get_icon_id("Applyall"))
                #box.operator("hops.mirror_array", text="Mirror / Array", icon_value=get_icon_id("Mirror"))
                box.operator("hops.mirror_gizmo", text="Mirror", icon_value=get_icon_id("Mirror"))

                box = column.box().column()
                if addon.preference().property.accushape_type == 'V2':
                    box.operator("hops.accu_shape_v2", text="AccuShape V2", icon_value=get_icon_id("grey"))
                else:
                    box.operator("hops.accu_shape", text="AccuShape", icon_value=get_icon_id("grey"))

                column.separator()
                column.label(text='Modifiers')

                maincol = layout.box().column()
                split = maincol.row(align=True)
                row = split.row(align=True)
                col = row.column(align=True)
                col.scale_x = 1.25
                col.scale_y = 1.25

                col.operator("hops.adjust_tthick", text="", icon="MOD_SOLIDIFY")
                col.operator("hops.mod_screw", text="", icon="MOD_SCREW")
                col.operator("hops.mod_simple_deform", text="", icon="MOD_SIMPLEDEFORM")
                col.operator("hops.mod_shrinkwrap", text="", icon="MOD_SHRINKWRAP")
                row = split.row(align=True)
                col = row.column(align=True)
                col.scale_x = 1.25
                col.scale_y = 1.25

                col.operator("hops.st3_array", text="", icon_value=get_icon_id("GreyArrayX"))
                col.operator("hops.mod_triangulate", text="", icon="MOD_TRIANGULATE")
                col.operator("hops.mod_wireframe", text="", icon="MOD_WIREFRAME")
                col.operator("hops.mod_cast", text="", icon="MOD_CAST")
                row = split.row(align=True)
                col = row.column(align=True)
                col.scale_x = 1.25
                col.scale_y = 1.25

                col.operator("hops.mod_lattice", text="", icon="MOD_LATTICE")
                col.operator("hops.mod_weighted_normal", text="", icon="MOD_NORMALEDIT")
                col.operator("hops.mod_displace", text="", icon="MOD_DISPLACE")
                col.operator("hops.mod_decimate", text="", icon="MOD_DECIM")
                row = split.row(align=True)
                col = row.column(align=True)
                col.scale_x = 1.25
                col.scale_y = 1.25

                col.operator("hops.adjust_bevel", text="", icon="MOD_BEVEL")
                col.operator("hops.mod_subdivision", text="", icon="MOD_SUBSURF")
                # col.operator("hops.mod_displace", text="", icon="MOD_DISPLACE")
                col.operator("hops.mod_weld", text="", icon="AUTOMERGE_OFF")
                col.operator("hops.mod_apply", text="", icon="REC")

                split.separator()
                split.separator()
                split.separator()

                row = split.row(align=True)
                col = row.column(align=True)
                col.scale_x = 1.25
                col.scale_y = 1.25

                col.operator("hops.bool_difference", text="", icon_value=get_icon_id("red"))
                col.operator("hops.bool_union", text="", icon_value=get_icon_id("green"))
                #col.operator("hops.bool_intersect", text="", icon_value=get_icon_id("orange"))
                col.operator("hops.bool_inset", text="", icon_value=get_icon_id("purple"))
                col.operator("hops.slash", text="", icon_value=get_icon_id("yellow"))

                if context.active_object and context.active_object.type == "MESH":
                    column = self.layout.column()
                    column.label(text='Shading')
                    box = column.box().column()

                    mesh = bpy.context.object.data
                    box.prop(mesh, "use_auto_smooth", text="Autosmooth")

                    row = column.row(align=True)
                    box = column.row().column()
                    row.operator('hops.set_autosmoouth', text='10').angle = radians(10)
                    row.operator('hops.set_autosmoouth', text='15').angle = radians(15)
                    row.operator('hops.set_autosmoouth', text='30').angle = radians(30)
                    row.operator('hops.set_autosmoouth', text='45').angle = radians(45)
                    row.operator('hops.set_autosmoouth', text='60').angle = radians(60)

                    box = column.box().column()
                    if bpy.context.object.data.use_auto_smooth == True:
                        box.prop(mesh, "auto_smooth_angle", text="Angle")

                    box.operator("object.shade_smooth", text="Smooth")
                    box.operator("object.shade_flat", text="Flat")

                    column.label(text='Materials')
                    box = column.box().column()
                    box.operator("material.hops_new", text = 'Add Blank Material', icon="PLUS")
                    box.operator("hops.material_scroll", text = 'Material Scroll', icon_value=get_icon_id("StatusReset"))

                    #column.label(text='Lights')
                    box = column.box().column()
                    box.operator("hops.blank_light", text = 'Blank Light', icon='LIGHT')
                    box.operator("hops.xunwrap", text = 'Auto UV', icon='UV_DATA')


            elif object and object.mode == "EDIT" and object.type == "MESH":
                maincol = layout.box().column()
                split = maincol.row(align=True)
                row = split.row(align=True)
                col = row.column(align=True)
                col.scale_x = 1.25
                col.scale_y = 1.25

                box = column.box().column()
                row = split.row(align=True)
                box.operator_context = 'INVOKE_REGION_WIN'
                box.operator("hops.edit_multi_tool", text="Mark", icon_value=get_icon_id("MakeSharpE"))
                box.operator("hops.mirror_gizmo", text="Mirror", icon_value=get_icon_id("Mirror"))

                column.label(text='Modifiers / Booleans')
                box = column.box().column()

                row = split.row(align=True)
                box.menu("HOPS_MT_ModSubmenu", text = 'Add Modifier',  icon_value=get_icon_id("Tris"))
                box.menu("HOPS_MT_BoolSumbenu", text="Booleans", icon_value=get_icon_id("Booleans"))
                box.separator()

                column.label(text='Operations')
                box = column.box().column()

                box.operator("hops.edge2curve", text="Curve/Extract", icon_value=get_icon_id("Curve"))
                box.operator("view3d.vertcircle", text="Circle ", icon_value=get_icon_id("NthCircle"))

                box.operator("hops.bool_dice_v2", text="Dice V2", icon_value=get_icon_id("Dice"))

                box.operator("hops.flatten_align", text="Reset Axis/Align/Select", icon_value=get_icon_id("Xslap"))
                #box.operator("hops.to_shape", text="To_Shape", icon_value=get_icon_id("Display_boolshapes"))
                #box.operator("hops.reset_axis_modal", text="Flatten", icon_value=get_icon_id("Xslap"))

                box.separator()
                # if addon.preference().property.st3_meshtools:
                box.operator("hops.edit_mesh_macro", text="EM Macro", icon="RADIOBUT_OFF")
                box.menu("HOPS_MT_ST3MeshToolsSubmenu", text="Mesh Tools", icon="MESH_ICOSPHERE")
                box.separator()
                # else:
                #     box.prop(addon.preference().property, 'st3_meshtools', text='ST3 Meshtools Unlock')

                column.label(text='Menus')
                box = column.box().column()

                box.menu("HOPS_MT_MeshOperatorsSubmenu", text="Operations", icon_value=get_icon_id("StatusOveride"))
                if bpy.context.object and bpy.context.object.type == 'MESH':
                    box.menu("HOPS_MT_MaterialListMenu", text="Material List", icon_value=get_icon_id("StatusOveride"))

                row = split.row(align=True)
                column.label(text='Materials')
                box = column.box().column()
                box.operator("material.hops_new", text = 'Add Blank Material', icon="PLUS")
                box.operator("hops.material_scroll", text = 'Material Scroll', icon_value=get_icon_id("StatusReset"))

            elif object and object.mode == "SCULPT" and object.type == "MESH":
                box = column.box().column()
                if bpy.app.version[:2] < (4, 2):
                    box.operator("view3d.sculpt_ops_window", text="Brush", icon="BRUSH_DATA")
                else:
                    brush = context.tool_settings.sculpt.brush
                    bpy.types.VIEW3D_AST_brush_sculpt.draw_popup_selector(layout, context, brush, show_name=False)

                box.operator("sculpt.toggle_brush", text="Toggle Brush")
                layout.separator()
                box.operator_context = "INVOKE_DEFAULT"
                box.operator("sculpt.decimate_mesh", text="Decimate Mesh")
                box.prop(context.active_object.data, 'remesh_voxel_size', text='Voxel Size')
                box.operator("view3d.voxelizer", text = "Voxel Remesh")
                box.separator()
                box.operator_context = "INVOKE_DEFAULT"
                # box.operator("view3d.sculpt_ops_window", text="Brush", icon="BRUSH_DATA")
                # box.operator_context = 'INVOKE_DEFAULT'
                # box.operator("hops.sculpt_primitives", text = "Add Primitive", icon_value=get_icon_id("QGui"))
                box.separator()
            elif object.mode == "PAINT_GPENCIL":
                column.label(text='Grease')
                box = column.box().column()
                box.operator("hops.mirror_gizmo", text="Mirror", icon_value=get_icon_id("Mirror"))
                box.operator("hops.copy_move", text="Copy / Move", icon_value=get_icon_id("dots"))
                box.operator("hops.surfaceoffset", text="Surface OffSet", icon_value=get_icon_id("Display_dots"))
            else:
                column.label(text='No Selection')
                column.label(text='Lights')
                box = column.box().column()
                box.operator("hops.blank_light", text = 'Blank Light', icon='LIGHT')


        elif button.context == 'TOOL':
            if self.is_popover:
                layout.ui_units_x = 11
            # column.label(text='Render')

            scene = context.scene
            rd = scene.render
            props = scene.eevee
            box = column.box().column()

            if rd.has_multiple_engines:
                box.prop(rd, "engine")#, text="Render Engine")

            if bpy.context.scene.render.engine == 'CYCLES':
                box = column.box().column()
                box.operator("hops.renderb_setup", text="Cycles LQ")
                box.operator("render.setup", text="Cycles HQ")
                box = column.box().column()
                box.operator("hops.blank_light", text = 'Blank Light', icon='LIGHT')
                box.operator("hops.adjust_viewport", text="Lookdev+ ", icon_value=get_icon_id("RGui"))
                box = column.box().column()

                expandable_header(button, box, 'render_expand')

            elif bpy.context.scene.render.engine in {'BLENDER_EEVEE', 'BLENDER_EEVEE_NEXT'}:
                box = column.box().column()
                box.operator("hops.adjust_viewport", text="Lookdev+ / Adjust Lookdev", icon_value=get_icon_id("RGui"))
                box.operator("hops.blank_light", text = 'Blank Light', icon='LIGHT')
                box = column.box().column()
                box.operator("hops.renderb_setup", text="Eevee LQ")
                column2 = box.column(align=True)
                row2 = column2.row(align=True)
                row2.prop(addon.preference().property, "Eevee_preset_LQ", expand=True)
                box.operator("render.setup", text="Eevee HQ")
                column2 = box.column(align=True)
                row2 = column2.row(align=True)
                row2.prop(addon.preference().property, "Eevee_preset_HQ", expand=True)
                box = column.box().column()

                expandable_header(button, box, 'render_expand')

            if button.render_expand:
                if bpy.context.scene.render.engine in {'BLENDER_EEVEE', 'BLENDER_EEVEE_NEXT'}:
                    box.prop(props, "taa_render_samples", text="Render")
                    box.prop(props, "taa_samples", text="Viewport")
                    box.prop(props, "use_taa_reprojection")

                    # box = column.box().column()
                    box.separator()
                    box.prop(props, "use_gtao", text="Ambient Occlusion")

                    if scene.eevee.use_gtao == True:
                        box.prop(props, "gtao_distance")
                        box.prop(props, "gtao_factor")

                    box.prop(props, "use_ssr", text="Screen Space Reflections")

                    # if scene.eevee.use_ssr == True:
                    #     box.prop(props, "use_ssr_refraction", text="Refraction")

                    #     if scene.eevee.use_ssr_refraction == True:
                    #         box.prop(props, "use_ssr_halfres", text = "Half Res Trace")

                    box.prop(props, "use_motion_blur", text="Motion Blur")

                    # if scene.eevee.use_motion_blur == True:
                    #     box.prop(props, "motion_blur_samples")
                    #     box.prop(props, "motion_blur_shutter")
                    # box.prop(props, "use_bloom", text="Bloom")

                    # if scene.eevee.use_bloom == True:
                    #     box.prop(props, "bloom_threshold")
                    #     box.prop(props, "bloom_intensity")
                    #     box.prop(props, "bloom_radius")

                    box.prop(props, "use_volumetric_shadows", text="Volumetric Shadows")

                    if scene.eevee.use_volumetric_shadows == True:
                        box.prop(props, "volumetric_shadow_samples", text="Shadow Samples")

                    box.separator()
                    box.prop(rd, "film_transparent", text="Transparent")

                elif bpy.context.scene.render.engine == 'CYCLES':
                    column.label(text='TBD')

            # box = column.box().column()
            # expandable_header(button, box, 'bake_expand')

            # if button.bake_expand:
            #     box.operator("scene.light_cache_bake", text="Bake Indirect Lighting", icon='RENDER_STILL')
            #     box.operator("scene.light_cache_bake", text="Bake Cubemap Only", icon='LIGHTPROBE_CUBEMAP').subset = 'CUBEMAPS'
            #     box.label(text="Cube Size")
            #     box.prop(props, "shadow_cube_size", text="")
            #     box.label(text="Cascade Size")
            #     box.prop(props, "shadow_cascade_size", text="")
            #     box.prop(props, "gi_diffuse_bounces")

            box = column.box().column()

            expandable_header(button, box, 'export_expand')

            if button.export_expand:
                ot = box.operator("wm.obj_export", text="OBJ")
                ot.export_selected_objects = True
                ot.export_triangulated_mesh = True

                ot = box.operator("export_scene.fbx", text="FBX")
                ot.use_selection = True

                ot = box.operator("wm.alembic_export", text="ABC")
                ot.selected = True

        elif button.context == 'OPT':
            from ... ui.Panels.opt_ins import HOPS_PT_opt_ins as opt_helper

            if self.is_popover:
                layout.ui_units_x = 10

            opt_helper.draw(self, context)

        elif button.context == 'KITOPS':
            from ... ui_popup import HOPS_OT_InsertsPopupPreview as kitops_helper

            if self.is_popover:
                layout.ui_units_x = 8

            kitops_helper.draw(self, context)

        elif button.context == 'HELPER':
            from ... ui.hops_helper import HOPS_OT_helper as hops_helper

            if self.is_popover:
                layout.ui_units_x = 15

            hops_helper.draw(self, context)

        elif button.context == 'BEVEL_HELPER':
            from ... ui.bevel_helper import HOPS_OT_bevel_helper as bevel_helper

            if self.is_popover:
                layout.ui_units_x = 15

            # self.mods = [mod for mod in context.active_object.modifiers if mod.type in {'BEVEL', 'BOOLEAN'}]
            # self.draw_bevel = bevel_helper.draw_bevel
            bevel_helper.draw(self, context)

        elif button.context == 'HELP':
            # from .... ui_popup import HOPS_OT_LearningPopup as hops_help
            from ... ui_popup import weblinks

            if self.is_popover:
                layout.ui_units_x = 10

            if addon.preference().needs_update:# and not 'Connection Failed':
                text = "Needs Update"
                layout.label(text=f'''{bl_info['version'][0]}.{bl_info['version'][1]}.{bl_info['version'][2]} : {text}''', icon='ERROR')
            elif addon.preference().needs_update == 'Connection Failed':
                text = "Unknown"
                layout.label(text=f'''{bl_info['version'][0]}.{bl_info['version'][1]}.{bl_info['version'][2]} : {text}''', icon='ERROR')
            else:
                text = "Current"
                layout.label(text=f'''{bl_info['version'][0]}.{bl_info['version'][1]}.{bl_info['version'][2]} : {text}''', icon='FUND')

            layout.label(text="support@hopscutter.com")

            box = column.box().column(align=True)
            expandable_header(button, box, 'Help_expand')

            if button.Help_expand:

                split = column.row(align=True)
                row = split.row(align=True)
                col = row.column(align=True)
                col.scale_x = 1.5
                col.scale_y = 1.5
                row.operator("wm.url_open", text="", icon_value=get_icon_id("bmarket")).url = "https://www.blendermarket.com/account/orders"
                row.operator("wm.url_open", text="", icon_value=get_icon_id("artstation")).url = "https://www.artstation.com/marketplace/orders"
                row.operator("wm.url_open", text="", icon_value=get_icon_id("gumroad")).url = "https://gumroad.com/library"
                row.operator("wm.url_open", text="", icon="INFO").url = "https://hardops-manual.readthedocs.io/en/latest/faq/#how-do-i-update-hard-ops-boxcutter"

                for name, url in weblinks:
                    box.operator("wm.url_open", text=name).url = url


        elif button.context == 'KEYMAP':
            from .. property.preference.keymap import HOPS_PT_Keys_info as keymap_draw

            if self.is_popover:
                layout.ui_units_x = 10

            keymap_draw.draw(self, context)

    def draw_bevel(self, context, obj, mod):
        from ... ui.bevel_helper import HOPS_OT_bevel_helper as bevel_helper

        bevel_helper.draw_bevel(self, context, obj, mod)

    def draw_boolean(self, context, obj, mod):
        from ... ui.bevel_helper import HOPS_OT_bevel_helper as bevel_helper

        bevel_helper.draw_boolean(self, context, obj, mod)

    def expanded(self, context, layout, obj, mod):
        from ... ui.bevel_helper import HOPS_OT_bevel_helper as bevel_helper

        bevel_helper.expanded(self, context, layout, obj, mod)

    def label_row(self, context, layout, obj, path, prop, label='Label'):
        from ... ui.bevel_helper import HOPS_OT_bevel_helper as bevel_helper

        bevel_helper.label_row(self, context, layout, obj, path, prop, label=label)


def expandable_header(button, box, prop):
    row = box.row(align=True)

    sub = row.row(align=True)
    sub.alignment = 'LEFT'
    icon = 'TRIA_DOWN' if getattr(button, prop) else 'TRIA_RIGHT'
    sub.prop(button, prop, text='', icon=icon, emboss=False)
    sub.prop(button, prop, text=prop[:-7].title(), toggle=True, emboss=False)
    sub.prop(button, prop, text=' ', toggle=True, emboss=False)
    row.prop(button, prop, text=' ', toggle=True, emboss=False)