271 lines
8.5 KiB
Python
271 lines
8.5 KiB
Python
import bpy
|
|
from .functions.poll import is_canvas
|
|
from .functions.list import list_canvas_cutters
|
|
|
|
|
|
#### ------------------------------ /ui/ ------------------------------ ####
|
|
|
|
def carve_menu(self, context):
|
|
layout = self.layout
|
|
layout.operator("object.carve_box", text="Box Carve").shape='BOX'
|
|
layout.operator("object.carve_box", text="Circle Carve").shape='CIRCLE'
|
|
layout.operator("object.carve_polyline", text="Polyline Carve")
|
|
|
|
|
|
def boolean_operators_menu(self, context):
|
|
layout = self.layout
|
|
layout.operator_context = 'INVOKE_DEFAULT'
|
|
col = layout.column(align=True)
|
|
|
|
col.label(text="Auto Boolean")
|
|
col.operator("object.boolean_auto_difference", text="Difference", icon='SELECT_SUBTRACT')
|
|
col.operator("object.boolean_auto_union", text="Union", icon='SELECT_EXTEND')
|
|
col.operator("object.boolean_auto_intersect", text="Intersect", icon='SELECT_INTERSECT')
|
|
col.operator("object.boolean_auto_slice", text="Slice", icon='SELECT_DIFFERENCE')
|
|
|
|
col.separator()
|
|
col.label(text="Brush Boolean")
|
|
col.operator("object.boolean_brush_difference", text="Difference", icon='SELECT_SUBTRACT')
|
|
col.operator("object.boolean_brush_union", text="Union", icon='SELECT_EXTEND')
|
|
col.operator("object.boolean_brush_intersect", text="Intersect", icon='SELECT_INTERSECT')
|
|
col.operator("object.boolean_brush_slice", text="Slice", icon='SELECT_DIFFERENCE')
|
|
|
|
|
|
def boolean_extras_menu(self, context):
|
|
layout = self.layout
|
|
layout.operator_context = 'INVOKE_DEFAULT'
|
|
col = layout.column(align=True)
|
|
|
|
if context.active_object:
|
|
# Canvas operators
|
|
active_object = context.active_object
|
|
if active_object.booleans.canvas == True and any(mod.name.startswith("boolean_") for mod in active_object.modifiers):
|
|
col.separator()
|
|
col.operator("object.boolean_toggle_all", text="Toggle All Cuters")
|
|
col.operator("object.boolean_apply_all", text="Apply All Cutters")
|
|
col.operator("object.boolean_remove_all", text="Remove All Cutters")
|
|
|
|
# Cutter operators
|
|
if active_object.booleans.cutter:
|
|
col.separator()
|
|
col.operator("object.boolean_toggle_cutter", text="Toggle Cutter").method='ALL'
|
|
col.operator("object.boolean_apply_cutter", text="Apply Cutter").method='ALL'
|
|
col.operator("object.boolean_remove_cutter", text="Remove Cutter").method='ALL'
|
|
|
|
|
|
|
|
#### ------------------------------ PANELS ------------------------------ ####
|
|
|
|
# Boolean Operators Panel
|
|
class VIEW3D_PT_boolean(bpy.types.Panel):
|
|
bl_label = "Boolean"
|
|
bl_space_type = "VIEW_3D"
|
|
bl_region_type = "UI"
|
|
bl_category = "Edit"
|
|
bl_context = "objectmode"
|
|
bl_options = {'DEFAULT_CLOSED'}
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
prefs = context.preferences.addons[__package__].preferences
|
|
return prefs.show_in_sidebar
|
|
|
|
def draw(self, context):
|
|
boolean_operators_menu(self, context)
|
|
|
|
|
|
# Properties Panel
|
|
class VIEW3D_PT_boolean_properties(bpy.types.Panel):
|
|
bl_label = "Properties"
|
|
bl_space_type = "VIEW_3D"
|
|
bl_region_type = "UI"
|
|
bl_category = "Edit"
|
|
bl_context = "objectmode"
|
|
bl_parent_id = "VIEW3D_PT_boolean"
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
prefs = context.preferences.addons[__package__].preferences
|
|
if prefs.show_in_sidebar:
|
|
if context.active_object:
|
|
if is_canvas(context.active_object) or context.active_object.booleans.cutter:
|
|
return True
|
|
else:
|
|
return False
|
|
else:
|
|
return False
|
|
else:
|
|
return False
|
|
|
|
def draw(self, context):
|
|
boolean_extras_menu(self, context)
|
|
|
|
|
|
# Cutters Panel
|
|
class VIEW3D_PT_boolean_cutters(bpy.types.Panel):
|
|
bl_label = "Cutters"
|
|
bl_space_type = "VIEW_3D"
|
|
bl_region_type = "UI"
|
|
bl_category = "Edit"
|
|
bl_context = "objectmode"
|
|
bl_parent_id = "VIEW3D_PT_boolean"
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
prefs = context.preferences.addons[__package__].preferences
|
|
if prefs.show_in_sidebar:
|
|
if context.active_object:
|
|
if is_canvas(context.active_object):
|
|
return True
|
|
else:
|
|
return False
|
|
else:
|
|
return False
|
|
else:
|
|
return False
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
canvas = context.active_object
|
|
__, modifiers = list_canvas_cutters([canvas])
|
|
|
|
for mod in modifiers:
|
|
col = layout.column(align=True)
|
|
row = col.row(align=True)
|
|
|
|
# icon
|
|
if mod.operation == 'DIFFERENCE':
|
|
icon = 'SELECT_SUBTRACT'
|
|
elif mod.operation == 'UNION':
|
|
icon = 'SELECT_EXTEND'
|
|
elif mod.operation == 'INTERSECT':
|
|
icon = 'SELECT_INTERSECT'
|
|
|
|
row.prop(mod.object, "name", text="", icon=icon)
|
|
|
|
# Toggle
|
|
op_toggle = row.operator("object.boolean_toggle_cutter", text="", icon='HIDE_OFF' if mod.show_viewport else 'HIDE_ON')
|
|
op_toggle.method = 'SPECIFIED'
|
|
op_toggle.specified_cutter = mod.object.name
|
|
op_toggle.specified_canvas = canvas.name
|
|
|
|
# Apply
|
|
op_apply = row.operator("object.boolean_apply_cutter", text="", icon='CHECKMARK')
|
|
op_apply.method = 'SPECIFIED'
|
|
op_apply.specified_cutter = mod.object.name
|
|
op_apply.specified_canvas = canvas.name
|
|
|
|
# Remove
|
|
op_remove = row.operator("object.boolean_remove_cutter", text="", icon='X')
|
|
op_remove.method = 'SPECIFIED'
|
|
op_remove.specified_cutter = mod.object.name
|
|
op_remove.specified_canvas = canvas.name
|
|
|
|
|
|
|
|
#### ------------------------------ MENUS ------------------------------ ####
|
|
|
|
# Carve Menu
|
|
class VIEW3D_MT_carve(bpy.types.Menu):
|
|
bl_label = "Carve"
|
|
bl_idname = "VIEW3D_MT_carve"
|
|
|
|
def draw(self, context):
|
|
carve_menu(self, context)
|
|
|
|
|
|
# 3D Viewport (Object Mode) -> Object
|
|
class VIEW3D_MT_boolean(bpy.types.Menu):
|
|
bl_label = "Boolean"
|
|
bl_idname = "VIEW3D_MT_boolean"
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.menu("VIEW3D_MT_carve")
|
|
layout.separator()
|
|
boolean_operators_menu(self, context)
|
|
boolean_extras_menu(self, context)
|
|
|
|
|
|
# Shift-Ctrl-B Menu
|
|
class VIEW3D_MT_boolean_popup(bpy.types.Menu):
|
|
bl_label = "Boolean"
|
|
bl_idname = "VIEW3D_MT_boolean_popup"
|
|
|
|
def draw(self, context):
|
|
boolean_operators_menu(self, context)
|
|
boolean_extras_menu(self, context)
|
|
|
|
|
|
def object_mode_menu(self, context):
|
|
layout = self.layout
|
|
layout.separator()
|
|
layout.menu("VIEW3D_MT_boolean")
|
|
|
|
|
|
def edit_mode_menu(self, context):
|
|
layout = self.layout
|
|
layout.separator()
|
|
layout.menu("VIEW3D_MT_carve")
|
|
|
|
|
|
def boolean_select_menu(self, context):
|
|
layout = self.layout
|
|
active_obj = context.active_object
|
|
if active_obj:
|
|
if active_obj.booleans.canvas == True or active_obj.booleans.cutter:
|
|
layout.separator()
|
|
|
|
if active_obj.booleans.canvas == True:
|
|
layout.operator("object.boolean_select_all", text="Boolean Cutters")
|
|
if active_obj.booleans.cutter:
|
|
layout.operator("object.select_cutter_canvas", text="Boolean Canvases")
|
|
|
|
|
|
|
|
#### ------------------------------ REGISTRATION ------------------------------ ####
|
|
|
|
addon_keymaps = []
|
|
|
|
classes = [
|
|
VIEW3D_MT_carve,
|
|
VIEW3D_MT_boolean,
|
|
VIEW3D_MT_boolean_popup,
|
|
VIEW3D_PT_boolean,
|
|
VIEW3D_PT_boolean_properties,
|
|
VIEW3D_PT_boolean_cutters,
|
|
]
|
|
|
|
def register():
|
|
for cls in classes:
|
|
bpy.utils.register_class(cls)
|
|
|
|
# MENU
|
|
bpy.types.VIEW3D_MT_object.append(object_mode_menu)
|
|
bpy.types.VIEW3D_MT_select_object.append(boolean_select_menu)
|
|
bpy.types.VIEW3D_MT_edit_mesh.append(edit_mode_menu)
|
|
|
|
# KEYMAP
|
|
addon = bpy.context.window_manager.keyconfigs.addon
|
|
km = addon.keymaps.new(name="Object Mode")
|
|
|
|
kmi = km.keymap_items.new("wm.call_menu", 'B', 'PRESS', ctrl=True, shift=True)
|
|
kmi.properties.name = "VIEW3D_MT_boolean_popup"
|
|
kmi.active = True
|
|
addon_keymaps.append((km, kmi))
|
|
|
|
|
|
def unregister():
|
|
for cls in reversed(classes):
|
|
bpy.utils.unregister_class(cls)
|
|
|
|
# MENU
|
|
bpy.types.VIEW3D_MT_object.remove(object_mode_menu)
|
|
bpy.types.VIEW3D_MT_select_object.remove(boolean_select_menu)
|
|
bpy.types.VIEW3D_MT_edit_mesh.remove(edit_mode_menu)
|
|
|
|
# KEYMAP
|
|
for km, kmi in addon_keymaps:
|
|
km.keymap_items.remove(kmi)
|
|
addon_keymaps.clear()
|