update addons (for 5.2)
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
if "bpy" in locals():
|
||||
import importlib
|
||||
for mod in [icons,
|
||||
lists,
|
||||
menus,
|
||||
panels,
|
||||
]:
|
||||
importlib.reload(mod)
|
||||
else:
|
||||
import bpy
|
||||
from . import (
|
||||
icons,
|
||||
lists,
|
||||
menus,
|
||||
panels,
|
||||
)
|
||||
|
||||
|
||||
#### ------------------------------ REGISTRATION ------------------------------ ####
|
||||
|
||||
modules = (
|
||||
icons,
|
||||
lists,
|
||||
menus,
|
||||
panels,
|
||||
)
|
||||
|
||||
def register():
|
||||
for module in modules:
|
||||
module.register()
|
||||
|
||||
def unregister():
|
||||
for module in reversed(modules):
|
||||
module.unregister()
|
||||
@@ -0,0 +1,96 @@
|
||||
import bpy
|
||||
from contextlib import contextmanager
|
||||
|
||||
from ..functions.canvas import (
|
||||
is_canvas,
|
||||
)
|
||||
from ..functions.modifier import (
|
||||
enumerate_boolean_modifiers,
|
||||
is_boolean_modifier,
|
||||
)
|
||||
|
||||
|
||||
#### ------------------------------ FUNCTIONS ------------------------------ ####
|
||||
|
||||
def get_modifier_from_list_index(obj, index: int):
|
||||
"""
|
||||
Returns the modifier of an object based on Cutters list index.
|
||||
Filters out non-Boolean modifiers to leave a list that matches Cutters one in length.
|
||||
"""
|
||||
|
||||
# Create a list of only Boolean modifiers.
|
||||
boolean_modifiers = []
|
||||
for mod in obj.modifiers:
|
||||
if is_boolean_modifier(mod):
|
||||
boolean_modifiers.append(mod)
|
||||
|
||||
if 0 <= index < len(boolean_modifiers):
|
||||
return boolean_modifiers[index]
|
||||
|
||||
return None
|
||||
|
||||
|
||||
@contextmanager
|
||||
def preserve_list_index(prop_owner, index_prop: str):
|
||||
"""Preserves index of active item in UI list."""
|
||||
|
||||
index = getattr(prop_owner, index_prop, 0)
|
||||
stored_index = index
|
||||
|
||||
try:
|
||||
yield
|
||||
|
||||
finally:
|
||||
new_index = stored_index - 1
|
||||
|
||||
if new_index < 0:
|
||||
new_index = 0
|
||||
|
||||
setattr(prop_owner, index_prop, new_index)
|
||||
|
||||
|
||||
|
||||
#### ------------------------------ /ui/ ------------------------------ ####
|
||||
|
||||
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, cutter_only=False):
|
||||
layout = self.layout
|
||||
layout.operator_context = 'INVOKE_DEFAULT'
|
||||
col = layout.column(align=True)
|
||||
obj = context.active_object
|
||||
|
||||
if not obj:
|
||||
return
|
||||
|
||||
# Canvas operators
|
||||
if is_canvas(obj) and not cutter_only:
|
||||
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 obj.booleans.cutter:
|
||||
if not cutter_only:
|
||||
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'
|
||||
@@ -0,0 +1,46 @@
|
||||
import bpy
|
||||
import os
|
||||
import bpy.utils.previews
|
||||
|
||||
|
||||
#### ------------------------------ FUNCTIONS ------------------------------ ####
|
||||
|
||||
def get_custom_icon(icon_name: str):
|
||||
"""Returns the ID of a custom icon registered by add-on."""
|
||||
|
||||
svg_icons = preview_collections["main"]
|
||||
if not svg_icons:
|
||||
return 0
|
||||
|
||||
icon = svg_icons[icon_name].icon_id
|
||||
if not icon:
|
||||
return 0
|
||||
|
||||
return icon
|
||||
|
||||
|
||||
|
||||
#### ------------------------------ REGISTRATION ------------------------------ ####
|
||||
|
||||
preview_collections = {}
|
||||
svg_icons_dir = os.path.join(os.path.dirname(__file__), "svg")
|
||||
|
||||
icons = {
|
||||
"MEASURE": "measure.svg",
|
||||
"CPU": "cpu.svg",
|
||||
}
|
||||
|
||||
|
||||
def register():
|
||||
svg_icons = bpy.utils.previews.new()
|
||||
|
||||
for key, file in icons.items():
|
||||
svg_icons.load(key, os.path.join(svg_icons_dir, file), 'IMAGE')
|
||||
|
||||
preview_collections["main"] = svg_icons
|
||||
|
||||
|
||||
def unregister():
|
||||
for pcoll in preview_collections.values():
|
||||
bpy.utils.previews.remove(pcoll)
|
||||
preview_collections.clear()
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="800" height="800" fill="#fff" viewBox="0 0 24 24"><g fill-rule="evenodd"><path d="M8.75 8a.75.75 0 0 0-.75.75v6.5c0 .414.336.75.75.75h6.5a.75.75 0 0 0 .75-.75v-6.5a.75.75 0 0 0-.75-.75h-6.5zm.75 6.5v-5h5v5h-5z"/><path d="M15.25 1a.75.75 0 0 1 .75.75V4h2.25c.966 0 1.75.784 1.75 1.75V8h2.25a.75.75 0 0 1 0 1.5H20v5h2.25a.75.75 0 0 1 0 1.5H20v2.25A1.75 1.75 0 0 1 18.25 20H16v2.25a.75.75 0 0 1-1.5 0V20h-5v2.25a.75.75 0 0 1-1.5 0V20H5.75A1.75 1.75 0 0 1 4 18.25V16H1.75a.75.75 0 0 1 0-1.5H4v-5H1.75a.75.75 0 0 1 0-1.5H4V5.75C4 4.784 4.784 4 5.75 4H8V1.75a.75.75 0 0 1 1.5 0V4h5V1.75a.75.75 0 0 1 .75-.75zm3 17.5a.25.25 0 0 0 .25-.25V5.75a.25.25 0 0 0-.25-.25H5.75a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h12.5z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 772 B |
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0"?>
|
||||
<svg width="23.999999999999996" height="23.999999999999996" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<g class="layer">
|
||||
<title>Layer 1</title>
|
||||
<path clip-rule="evenodd" d="m13.18,4.48l3.62,3.65a0.75,0.75 0 0 1 -1.16,1.09l-3.52,-3.59l-1.54,1.51l2.91,2.89a0.75,0.75 0 1 1 -1.06,1.06l-2.92,-2.88l-1.44,1.37l3.62,3.59a0.75,0.75 0 1 1 -1.06,1.06l-3.62,-3.59l-1.51,1.54l2.85,2.84a0.75,0.75 0 1 1 -1.06,1.06c-0.29,-0.3 -2.53,-2.51 -2.82,-2.81c-0.46,0.47 -1.18,1.23 -1.41,1.54c-0.29,0.38 -0.36,0.6 -0.36,0.8c0,0.19 0.07,0.41 0.36,0.79c0.3,0.4 0.77,0.87 1.47,1.57l1.44,1.44c0.7,0.7 1.17,1.17 1.57,1.47c0.38,0.29 0.6,0.36 0.79,0.36c0.2,0 0.42,-0.07 0.8,-0.36c0.4,-0.3 0.87,-0.77 1.57,-1.47l8.67,-8.67c0.7,-0.7 1.17,-1.17 1.47,-1.57c0.29,-0.38 0.36,-0.6 0.36,-0.8c0,-0.19 -0.07,-0.41 -0.36,-0.79c-0.3,-0.4 -0.77,-0.87 -1.47,-1.57l-1.44,-1.44c-0.7,-0.7 -1.17,-1.17 -1.57,-1.47c-0.38,-0.29 -0.6,-0.36 -0.79,-0.36c-0.2,0 -0.42,0.07 -0.8,0.36l-1.61,1.37zm0.7,-2.56c0.51,-0.4 1.05,-0.67 1.71,-0.67c0.65,0 1.19,0.27 1.7,0.67c0.49,0.37 1.03,0.91 1.68,1.56l1.52,1.52c0.65,0.65 1.19,1.19 1.56,1.68c0.4,0.51 0.67,1.05 0.67,1.7c0,0.66 -0.27,1.2 -0.67,1.71c-0.37,0.49 -0.91,1.03 -1.56,1.68l-8.75,8.75c-0.65,0.65 -1.19,1.19 -1.68,1.56c-0.51,0.4 -1.05,0.67 -1.71,0.67c-0.65,0 -1.19,-0.27 -1.7,-0.67c-0.49,-0.37 -1.03,-0.91 -1.68,-1.56l-1.52,-1.52c-0.65,-0.65 -1.19,-1.19 -1.57,-1.68c-0.39,-0.51 -0.66,-1.05 -0.66,-1.7c0,-0.66 0.27,-1.2 0.66,-1.71c0.38,-0.49 0.92,-1.03 1.57,-1.68l8.75,-8.75c0.65,-0.65 1.19,-1.19 1.68,-1.57l0,0.01z" fill="#ffffff" fill-rule="evenodd" id="svg_1"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
@@ -0,0 +1,92 @@
|
||||
import bpy
|
||||
|
||||
from ..functions.modifier import (
|
||||
is_boolean_modifier,
|
||||
)
|
||||
|
||||
|
||||
#### ------------------------------ /cutters_list/ ------------------------------ ####
|
||||
|
||||
class VIEW3D_UL_boolean_cutters(bpy.types.UIList):
|
||||
|
||||
def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
|
||||
canvas = context.active_object
|
||||
mod = item
|
||||
|
||||
# Pick Icon
|
||||
if mod.operation == 'DIFFERENCE':
|
||||
icon = 'SELECT_SUBTRACT'
|
||||
elif mod.operation == 'UNION':
|
||||
icon = 'SELECT_EXTEND'
|
||||
elif mod.operation == 'INTERSECT':
|
||||
icon = 'SELECT_INTERSECT'
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.prop(mod.object, "name", text="", icon=icon, emboss=False)
|
||||
|
||||
# Select Cutter
|
||||
op_select = row.operator("object.boolean_select_cutter", text="", icon='RESTRICT_SELECT_OFF', emboss=False)
|
||||
op_select.cutter = mod.object.name
|
||||
|
||||
# Toggle Cutter
|
||||
icon = 'HIDE_OFF' if mod.show_viewport else 'HIDE_ON'
|
||||
op_toggle = row.operator("object.boolean_toggle_cutter", text="", icon=icon, emboss=False)
|
||||
op_toggle.method = 'SPECIFIED'
|
||||
op_toggle.specified_cutter = mod.object.name
|
||||
op_toggle.specified_canvas = canvas.name
|
||||
op_toggle.specified_modifier = mod.name
|
||||
|
||||
|
||||
def filter_items(self, context, data, propname):
|
||||
flags = []
|
||||
indices = []
|
||||
|
||||
modifiers = getattr(data, propname)
|
||||
for mod in modifiers:
|
||||
if is_boolean_modifier(mod):
|
||||
flags.append(self.bitflag_filter_item)
|
||||
else:
|
||||
flags.append(0)
|
||||
|
||||
# Search Filter
|
||||
if self.filter_name:
|
||||
filter_name = self.filter_name.lower()
|
||||
for i, mod in enumerate(modifiers):
|
||||
if flags[i] != self.bitflag_filter_item:
|
||||
continue
|
||||
if filter_name not in mod.object.name.lower():
|
||||
flags[i] = 0
|
||||
|
||||
# Invert
|
||||
if self.use_filter_invert:
|
||||
for i, mod in enumerate(modifiers):
|
||||
if not is_boolean_modifier(mod):
|
||||
continue
|
||||
flags[i] ^= self.bitflag_filter_item
|
||||
|
||||
# Sort by Name
|
||||
indices = list(range(len(modifiers)))
|
||||
if self.use_filter_sort_alpha:
|
||||
sorted_indices = sorted(range(len(modifiers)),
|
||||
key=lambda i: modifiers[i].object.name if modifiers[i].object else "")
|
||||
indices = [0] * len(modifiers)
|
||||
for rank, original_i in enumerate(sorted_indices):
|
||||
indices[original_i] = rank
|
||||
|
||||
return flags, indices
|
||||
|
||||
|
||||
|
||||
#### ------------------------------ REGISTRATION ------------------------------ ####
|
||||
|
||||
classes = (
|
||||
VIEW3D_UL_boolean_cutters,
|
||||
)
|
||||
|
||||
def register():
|
||||
for cls in classes:
|
||||
bpy.utils.register_class(cls)
|
||||
|
||||
def unregister():
|
||||
for cls in reversed(classes):
|
||||
bpy.utils.unregister_class(cls)
|
||||
@@ -0,0 +1,129 @@
|
||||
import bpy
|
||||
|
||||
from ..functions.canvas import (
|
||||
is_canvas,
|
||||
)
|
||||
|
||||
from .common import (
|
||||
boolean_operators_menu,
|
||||
boolean_extras_menu,
|
||||
)
|
||||
|
||||
|
||||
#### ------------------------------ /boolean_menu/ ------------------------------ ####
|
||||
|
||||
# 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)
|
||||
|
||||
|
||||
def object_mode_menu(self, context):
|
||||
layout = self.layout
|
||||
layout.separator()
|
||||
layout.menu("VIEW3D_MT_boolean")
|
||||
|
||||
|
||||
|
||||
#### ------------------------------ /popup_menu/ ------------------------------ ####
|
||||
|
||||
# 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)
|
||||
|
||||
|
||||
|
||||
#### ------------------------------ /carve_menu/ ------------------------------ ####
|
||||
|
||||
class VIEW3D_MT_carve(bpy.types.Menu):
|
||||
bl_label = "Carve"
|
||||
bl_idname = "VIEW3D_MT_carve"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.operator("object.carve_box", text="Box Carve")
|
||||
layout.operator("object.carve_circle", text="Circle Carve")
|
||||
layout.operator("object.carve_polyline", text="Polyline Carve")
|
||||
|
||||
|
||||
# Separate "Carve" menu in Edit Mode (where we don't have "Boolean" menu).
|
||||
def edit_mode_menu(self, context):
|
||||
layout = self.layout
|
||||
layout.separator()
|
||||
layout.menu("VIEW3D_MT_carve")
|
||||
|
||||
|
||||
|
||||
#### ------------------------------ /select_menu/ ------------------------------ ####
|
||||
|
||||
def select_menu(self, context):
|
||||
layout = self.layout
|
||||
obj = context.active_object
|
||||
|
||||
if not obj:
|
||||
return
|
||||
|
||||
if is_canvas(obj) or obj.booleans.cutter:
|
||||
layout.separator()
|
||||
|
||||
if is_canvas(obj):
|
||||
layout.operator("object.boolean_select_all", text="Boolean Cutters")
|
||||
if obj.booleans.cutter:
|
||||
layout.operator("object.select_cutter_canvas", text="Boolean Canvases")
|
||||
|
||||
|
||||
|
||||
#### ------------------------------ REGISTRATION ------------------------------ ####
|
||||
|
||||
addon_keymaps = []
|
||||
|
||||
classes = (
|
||||
VIEW3D_MT_boolean,
|
||||
VIEW3D_MT_boolean_popup,
|
||||
VIEW3D_MT_carve,
|
||||
)
|
||||
|
||||
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_edit_mesh.append(edit_mode_menu)
|
||||
bpy.types.VIEW3D_MT_select_object.append(select_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_edit_mesh.remove(edit_mode_menu)
|
||||
bpy.types.VIEW3D_MT_select_object.remove(select_menu)
|
||||
|
||||
# KEYMAP
|
||||
for km, kmi in addon_keymaps:
|
||||
km.keymap_items.remove(kmi)
|
||||
addon_keymaps.clear()
|
||||
@@ -0,0 +1,182 @@
|
||||
import bpy
|
||||
from .. import __package__ as base_package
|
||||
|
||||
from ..functions.canvas import (
|
||||
is_canvas,
|
||||
)
|
||||
|
||||
from .common import (
|
||||
get_modifier_from_list_index,
|
||||
boolean_extras_menu,
|
||||
)
|
||||
|
||||
|
||||
#### ------------------------------ 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[base_package].preferences
|
||||
return prefs.show_in_sidebar
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.operator_context = 'INVOKE_DEFAULT'
|
||||
col = layout.column(align=True)
|
||||
|
||||
col.label(text="Auto Boolean")
|
||||
row = col.row(align=False)
|
||||
row.operator("object.boolean_auto_difference", text="Difference", icon='SELECT_SUBTRACT')
|
||||
row.operator("object.boolean_auto_difference", text="", icon='UV_SYNC_SELECT').flip=True
|
||||
row = col.row(align=False)
|
||||
row.operator("object.boolean_auto_union", text="Union", icon='SELECT_EXTEND')
|
||||
row.operator("object.boolean_auto_union", text="", icon='UV_SYNC_SELECT').flip=True
|
||||
row = col.row(align=False)
|
||||
row.operator("object.boolean_auto_intersect", text="Intersect", icon='SELECT_INTERSECT')
|
||||
row.operator("object.boolean_auto_intersect", text="", icon='UV_SYNC_SELECT').flip=True
|
||||
row = col.row(align=False)
|
||||
row.operator("object.boolean_auto_slice", text="Slice", icon='SELECT_DIFFERENCE')
|
||||
row.operator("object.boolean_auto_slice", text="", icon='UV_SYNC_SELECT').flip=True
|
||||
|
||||
col.separator()
|
||||
col.label(text="Brush Boolean")
|
||||
row = col.row(align=False)
|
||||
row.operator("object.boolean_brush_difference", text="Difference", icon='SELECT_SUBTRACT')
|
||||
row.operator("object.boolean_brush_difference", text="", icon='UV_SYNC_SELECT').flip=True
|
||||
row = col.row(align=False)
|
||||
row.operator("object.boolean_brush_union", text="Union", icon='SELECT_EXTEND')
|
||||
row.operator("object.boolean_brush_union", text="", icon='UV_SYNC_SELECT').flip=True
|
||||
row = col.row(align=False)
|
||||
row.operator("object.boolean_brush_intersect", text="Intersect", icon='SELECT_INTERSECT')
|
||||
row.operator("object.boolean_brush_intersect", text="", icon='UV_SYNC_SELECT').flip=True
|
||||
row = col.row(align=False)
|
||||
row.operator("object.boolean_brush_slice", text="Slice", icon='SELECT_DIFFERENCE')
|
||||
row.operator("object.boolean_brush_slice", text="", icon='UV_SYNC_SELECT').flip=True
|
||||
|
||||
|
||||
# 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[base_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
|
||||
|
||||
# Cutters List
|
||||
row = layout.row()
|
||||
col = row.column()
|
||||
col.template_list(
|
||||
"VIEW3D_UL_boolean_cutters",
|
||||
"",
|
||||
canvas, "modifiers",
|
||||
canvas.booleans, "modifiers_list_index",
|
||||
rows=5,
|
||||
)
|
||||
|
||||
# Filter & Operators
|
||||
col = row.column(align=True)
|
||||
cutters_list_index = canvas.booleans.modifiers_list_index
|
||||
mod = get_modifier_from_list_index(canvas, cutters_list_index)
|
||||
sub = col.column(align=True)
|
||||
|
||||
# Apply Cutter
|
||||
op_apply = sub.operator("object.boolean_apply_cutter", text="", icon='CHECKMARK')
|
||||
op_apply.method = 'SPECIFIED'
|
||||
op_apply.specified_cutter = mod.object.name if mod else ""
|
||||
op_apply.specified_canvas = canvas.name
|
||||
|
||||
# Remove Cutter
|
||||
op_remove = sub.operator("object.boolean_remove_cutter", text="", icon='X')
|
||||
op_remove.method = 'SPECIFIED'
|
||||
op_remove.specified_cutter = mod.object.name if mod else ""
|
||||
op_remove.specified_canvas = canvas.name
|
||||
op_remove.specified_modifier = mod.name if mod else ""
|
||||
|
||||
if cutters_list_index < 0 or not mod:
|
||||
sub.enabled = False
|
||||
|
||||
col.separator()
|
||||
col.menu("VIEW3D_MT_boolean_specials", icon='DOWNARROW_HLT', text="")
|
||||
|
||||
|
||||
# Helpers Panel
|
||||
class VIEW3D_PT_boolean_helpers(bpy.types.Panel):
|
||||
bl_label = "Helpers"
|
||||
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[base_package].preferences
|
||||
if not prefs.show_in_sidebar:
|
||||
return False
|
||||
if not context.active_object:
|
||||
return False
|
||||
if context.active_object.booleans.cutter:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def draw(self, context):
|
||||
boolean_extras_menu(self, context, cutter_only=True)
|
||||
|
||||
|
||||
|
||||
#### ------------------------------ MENUS ------------------------------ ####
|
||||
|
||||
# Specials
|
||||
class VIEW3D_MT_boolean_specials(bpy.types.Menu):
|
||||
bl_label = "Boolean Operators"
|
||||
bl_idname = "VIEW3D_MT_boolean_specials"
|
||||
|
||||
def draw(self, context):
|
||||
boolean_extras_menu(self, context)
|
||||
|
||||
|
||||
|
||||
#### ------------------------------ REGISTRATION ------------------------------ ####
|
||||
|
||||
classes = (
|
||||
VIEW3D_PT_boolean,
|
||||
VIEW3D_PT_boolean_cutters,
|
||||
VIEW3D_PT_boolean_helpers,
|
||||
VIEW3D_MT_boolean_specials,
|
||||
)
|
||||
|
||||
def register():
|
||||
for cls in classes:
|
||||
bpy.utils.register_class(cls)
|
||||
|
||||
def unregister():
|
||||
for cls in reversed(classes):
|
||||
bpy.utils.unregister_class(cls)
|
||||
Reference in New Issue
Block a user