OverviewFilesCommitsIssuesDocsReleasesPeers

hardops / operators / sharpeners / step.py

181 lines · python ref:
import bpy
import math
from bpy.props import EnumProperty, IntProperty, FloatProperty, BoolProperty
import bpy.utils.previews
from ... operators.utils import update_bevel_modifier_if_necessary
from ... utils.context import ExecutionContext
from ... utils.modifiers import apply_modifiers
from ... utility import addon
from ...ui_framework.operator_ui import Master

mod_types = [
    ("BOOLEAN", "Boolean", ""),
    ("MIRROR", "Mirror", ""),
    ("BEVEL", "Bevel", ""),
    ("SOLIDIFY", "Solidify", ""),
    ("ARRAY", "Array", "")]

def iterate_titled_as_string(iter, separator=','):
    applied_types = ''
    separator = f'{separator} '
    for i in iter:
        applied_types += i.title() + separator
    return applied_types[:-len(separator)]

class HOPS_OT_StepOperator(bpy.types.Operator):
    bl_idname = "hops.step"
    bl_label = "Hops Step Operator"
    bl_options = {"REGISTER", "UNDO"}
    bl_description = """HOPS Step

Non-Destructive: (newer)
Adds new bevel at 50% width of previous bevel (default)

Destructive: (classic)
Applies Csharp / Hides mesh in edit mode / Adds new BEVEL modifier
Typically used for booleans and should decrement

"""

    items = [(x.identifier, x.name, x.description, x.icon)
             for x in bpy.types.Modifier.bl_rna.properties['type'].enum_items]

    modifier_types: EnumProperty(name="Modifier Types", default={'BEVEL', 'BOOLEAN'},
                                 options={"ENUM_FLAG"}, items=mod_types)

    bevelwidth: FloatProperty(name="Bevel Width Amount", description="Set Bevel Width", default=0.01, min=0.002, max=0.25)

    segment_amount: IntProperty(name="Segments", description="Segments For Bevel", default=6, min=1, max=12)

    bevelwidth: FloatProperty(name="Bevel Width Amount",
                              description="Set Bevel Width",
                              default=0.0200,
                              min=0.002,
                              max=1.50)

    hide_mesh: BoolProperty(name="Hide Mesh",
                            description="Hide Mesh",
                            default=True)

    profile_value = 0.70

    called_ui = False

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        HOPS_OT_StepOperator.called_ui = False

    @classmethod
    def poll(cls, context):
        selected = context.selected_objects
        object = context.active_object
        if object is None: return False
        if object.mode == "OBJECT" and all(obj.type == "MESH" for obj in selected):
            return True

    def draw(self, context):
        layout = self.layout
        col = layout.column()

        if addon.preference().property.workflow_mode == "WEIGHT":
            col.label(text='Apply Mods')
            col.prop(self, 'modifier_types')
            col.separator()
            col.prop(self, 'bevelwidth')
            col.prop(self, 'segment_amount')
        else:
            col.label(text='Half Bevel Added')

    def execute(self, context):
        selected = context.selected_objects
        object = context.active_object

        for obj in selected:
            bpy.context.view_layer.objects.active = obj

            if addon.preference().property.workflow_mode == "WEIGHT":
                self.step_active_object(
                    object,
                    self.modifier_types)

                update_bevel_modifier_if_necessary(
                    context.active_object,
                    self.segment_amount,
                    self.bevelwidth,
                    self.profile_value)

            else:
                # self.step_active_object(
                #     object,
                #     self.modifier_types,
                #     mark_edges=False)

                bpy.ops.object.shade_smooth()
                bpy.ops.hops.bevel_half_add()

        self.report({'INFO'}, F'Step')
        bpy.context.view_layer.objects.active = object

        # Operator UI
        if not HOPS_OT_StepOperator.called_ui:
            HOPS_OT_StepOperator.called_ui = True

            ui = Master()
            if addon.preference().property.workflow_mode == "WEIGHT":
                draw_data = [
                    ["STEP - Destructive"],
                    ["Workflow : ", addon.preference().property.workflow_mode],
                    ["Modifiers Applied : ", iterate_titled_as_string(self.modifier_types)]]
            if addon.preference().property.workflow_mode == "ANGLE":
                draw_data = [
                    ["STEP - Non-Destructive"],
                    ["No Modifiers Were Applied"],
                    ["New Bevel Added at 50% of previous"],
                    ["Workflow :", addon.preference().property.workflow_mode]
                    ]
            ui.receive_draw_data(draw_data=draw_data)
            ui.draw(draw_bg=addon.preference().ui.Hops_operator_draw_bg, draw_border=addon.preference().ui.Hops_operator_draw_border)

        return {"FINISHED"}

    def step_active_object(self, object, modifier_types, mark_edges=True):
        with ExecutionContext(mode="OBJECT", active_object=object):
            active = [object]
            apply_modifiers(active, modifier_types)

        if mark_edges:
            with ExecutionContext(mode="EDIT", active_object=object):
                bpy.ops.mesh.reveal()
                bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='EDGE')
                bpy.ops.mesh.select_all(action='DESELECT')
                bpy.ops.mesh.select_all(action='SELECT')
                bpy.ops.transform.edge_bevelweight(value=-1)
                bpy.ops.transform.edge_crease(value=-1)
                bpy.ops.mesh.select_all(action='DESELECT')
                bpy.ops.mesh.select_all(action='SELECT')

                if self.hide_mesh:
                    bpy.ops.mesh.hide()

    def bevel(self, object, segment_amount, bevelwidth, profile_value):
        bevel = object.modifiers.new("Bevel", "BEVEL")
        bevel.use_clamp_overlap = False
        bevel.show_in_editmode = False
        bevel.width = bevelwidth
        bevel.profile = profile_value
        bevel.limit_method = addon.preference().property.workflow_mode
        bevel.show_in_editmode = True
        bevel.harden_normals = False
        bevel.miter_outer = 'MITER_ARC'
        bevel.segments = segment_amount
        bevel.loop_slide = addon.preference().property.bevel_loop_slide
        bevel.angle_limit = math.radians(60)

    def titled_list_as_string(list, separator=','):
        applied_types = ''
        separator = f'{separator} '
        for i in self.modifier_types:
            applied_types += i.title() + separator
        return applied_types[:-len(separator)]