427 lines
14 KiB
Python
427 lines
14 KiB
Python
import bpy
|
|
|
|
from .constants import MENU_ITEMS, VERSIONS
|
|
from .node_menu import NodeMenu
|
|
|
|
from .bioxelutils.common import (get_container_obj,
|
|
get_container_layer_objs, get_layer_label,
|
|
get_layer_prop_value, get_node_version, is_incompatible)
|
|
from .operators.layer import (FetchLayer, RelocateLayer, RetimeLayer, RenameLayer,
|
|
RemoveSelectedLayers, SaveSelectedLayersCache,
|
|
ResampleLayer, SignScalar, CombineLabels,
|
|
FillByLabel, FillByThreshold, FillByRange)
|
|
from .operators.container import (AddLocator, AddSlicer, ContainerProps,
|
|
SaveContainerLayersCache, RemoveContainerMissingLayers,
|
|
SaveContainer, LoadContainer,
|
|
AddPieCutter, AddPlaneCutter,
|
|
AddCylinderCutter, AddCubeCutter, AddSphereCutter,
|
|
ExtractBboxWire, ExtractMesh, ExtractShapeWire,
|
|
ExtractNodeMesh, ExtractNodeBboxWire, ExtractNodeShapeWire)
|
|
|
|
from .operators.io import (ImportAsLabel, ImportAsScalar, ImportAsColor)
|
|
from .operators.misc import (CleanTemp,
|
|
ReLinkNodeLib, RemoveAllMissingLayers,
|
|
RenderSettingPreset, SaveAllLayersCache,
|
|
SaveNodeLib, SliceViewer)
|
|
|
|
|
|
class IncompatibleMenu(bpy.types.Menu):
|
|
bl_idname = "BIOXELNODES_MT_INCOMPATIBLE"
|
|
bl_label = "Bioxel Nodes"
|
|
|
|
def draw(self, context):
|
|
tip_text = "please downgrade addon version."
|
|
node_version = get_node_version()
|
|
if node_version:
|
|
version_str = "v"+".".join([str(i) for i in list(node_version)])
|
|
tip_text = f"please downgrade addon version to {version_str}."
|
|
|
|
layout = self.layout
|
|
layout.label(text="Incompatible node version detected.")
|
|
layout.separator()
|
|
layout.label(
|
|
text="If you still want to edit this file with bioxel nodes, ")
|
|
layout.label(text=tip_text)
|
|
layout.separator()
|
|
layout.label(text="If this file is archived, "
|
|
"please relink node library, ")
|
|
layout.label(text="check if it still works, "
|
|
"then save node library.")
|
|
layout.separator()
|
|
layout.menu(ReLinkNodeLibMenu.bl_idname)
|
|
layout.operator(SaveNodeLib.bl_idname)
|
|
|
|
layout.separator()
|
|
layout.menu(DangerZoneMenu.bl_idname)
|
|
|
|
layout.separator()
|
|
layout.menu(RenderSettingMenu.bl_idname)
|
|
|
|
|
|
class FetchLayerMenu(bpy.types.Menu):
|
|
bl_idname = "BIOXELNODES_MT_ADD_LAYER"
|
|
bl_label = "Fetch Layer"
|
|
|
|
def draw(self, context):
|
|
container_obj = get_container_obj(bpy.context.active_object)
|
|
layer_objs = get_container_layer_objs(container_obj)
|
|
layout = self.layout
|
|
|
|
for layer_obj in layer_objs:
|
|
op = layout.operator(FetchLayer.bl_idname,
|
|
text=get_layer_label(layer_obj))
|
|
op.layer_obj_name = layer_obj.name
|
|
|
|
|
|
class ExtractFromContainerMenu(bpy.types.Menu):
|
|
bl_idname = "BIOXELNODES_MT_PICK"
|
|
bl_label = "Extract from Container"
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.operator(ExtractMesh.bl_idname)
|
|
layout.operator(ExtractShapeWire.bl_idname)
|
|
layout.operator(ExtractBboxWire.bl_idname)
|
|
|
|
|
|
class AddCutterMenu(bpy.types.Menu):
|
|
bl_idname = "BIOXELNODES_MT_CUTTERS"
|
|
bl_label = "Add a Cutter"
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.operator(AddPlaneCutter.bl_idname,
|
|
icon=AddPlaneCutter.bl_icon, text="Plane Cutter")
|
|
layout.operator(AddCylinderCutter.bl_idname,
|
|
icon=AddCylinderCutter.bl_icon, text="Cylinder Cutter")
|
|
layout.operator(AddCubeCutter.bl_idname,
|
|
icon=AddCubeCutter.bl_icon, text="Cube Cutter")
|
|
layout.operator(AddSphereCutter.bl_idname,
|
|
icon=AddSphereCutter.bl_icon, text="Sphere Cutter")
|
|
layout.operator(AddPieCutter.bl_idname,
|
|
icon=AddPieCutter.bl_icon, text="Pie Cutter")
|
|
|
|
|
|
class ImportLayerMenu(bpy.types.Menu):
|
|
bl_idname = "BIOXELNODES_MT_IMPORTLAYER"
|
|
bl_label = "Import Volumetric Data (Init)"
|
|
bl_icon = "FILE_NEW"
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.operator(ImportAsScalar.bl_idname,
|
|
text="as Scalar")
|
|
layout.operator(ImportAsLabel.bl_idname,
|
|
text="as Label")
|
|
layout.operator(ImportAsColor.bl_idname,
|
|
text="as Color")
|
|
|
|
|
|
class AddLayerMenu(bpy.types.Menu):
|
|
bl_idname = "BIOXELNODES_MT_ADDLAYER"
|
|
bl_label = "Import Volumetric Data (Add)"
|
|
bl_icon = "FILE_NEW"
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.operator(ImportAsScalar.bl_idname,
|
|
text="as Scalar")
|
|
layout.operator(ImportAsLabel.bl_idname,
|
|
text="as Label")
|
|
layout.operator(ImportAsColor.bl_idname,
|
|
text="as Color")
|
|
|
|
|
|
class ModifyLayerMenu(bpy.types.Menu):
|
|
bl_idname = "BIOXELNODES_MT_MODIFYLAYER"
|
|
bl_label = "Modify Layer"
|
|
bl_icon = "FILE_NEW"
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.operator(SignScalar.bl_idname,
|
|
icon=SignScalar.bl_icon)
|
|
layout.operator(FillByThreshold.bl_idname,
|
|
icon=FillByThreshold.bl_icon)
|
|
layout.operator(FillByRange.bl_idname,
|
|
icon=FillByRange.bl_icon)
|
|
layout.operator(FillByLabel.bl_idname,
|
|
icon=FillByLabel.bl_icon)
|
|
layout.operator(CombineLabels.bl_idname,
|
|
icon=CombineLabels.bl_icon)
|
|
|
|
|
|
class ReLinkNodeLibMenu(bpy.types.Menu):
|
|
bl_idname = "BIOXELNODES_MT_RELINK"
|
|
bl_label = "Relink Node Library"
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
|
|
for index, version in enumerate(VERSIONS):
|
|
op = layout.operator(ReLinkNodeLib.bl_idname,
|
|
text=version["label"])
|
|
op.index = index
|
|
|
|
|
|
class RenderSettingMenu(bpy.types.Menu):
|
|
bl_idname = "BIOXELNODES_MT_RENDER"
|
|
bl_label = "Render Setting Presets"
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
for k, v in RenderSettingPreset.PRESETS.items():
|
|
op = layout.operator(RenderSettingPreset.bl_idname,
|
|
text=v)
|
|
op.preset = k
|
|
|
|
|
|
class DangerZoneMenu(bpy.types.Menu):
|
|
bl_idname = "BIOXELNODES_MT_DANGER"
|
|
bl_label = "Danger Zone"
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.operator(CleanTemp.bl_idname)
|
|
|
|
|
|
class BioxelNodesTopbarMenu(bpy.types.Menu):
|
|
bl_idname = "BIOXELNODES_MT_TOPBAR"
|
|
bl_label = "Bioxel Nodes"
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
|
|
layout.menu(ImportLayerMenu.bl_idname,
|
|
icon=ImportLayerMenu.bl_icon)
|
|
layout.operator(LoadContainer.bl_idname)
|
|
|
|
layout.separator()
|
|
layout.operator(SaveAllLayersCache.bl_idname)
|
|
layout.operator(RemoveAllMissingLayers.bl_idname)
|
|
|
|
layout.separator()
|
|
layout.menu(ReLinkNodeLibMenu.bl_idname)
|
|
layout.operator(SaveNodeLib.bl_idname)
|
|
|
|
layout.separator()
|
|
layout.menu(DangerZoneMenu.bl_idname)
|
|
|
|
layout.separator()
|
|
layout.menu(RenderSettingMenu.bl_idname)
|
|
|
|
|
|
def TOPBAR(self, context):
|
|
layout = self.layout
|
|
|
|
if is_incompatible():
|
|
layout.menu(IncompatibleMenu.bl_idname)
|
|
else:
|
|
layout.menu(BioxelNodesTopbarMenu.bl_idname)
|
|
|
|
|
|
class NodeHeadMenu(bpy.types.Menu):
|
|
bl_idname = "BIOXELNODES_MT_NODE_HEAD"
|
|
bl_label = "Bioxel Nodes"
|
|
bl_icon = "FILE_VOLUME"
|
|
|
|
def draw(self, context):
|
|
|
|
layout = self.layout
|
|
layout.menu(AddLayerMenu.bl_idname,
|
|
icon=AddLayerMenu.bl_icon)
|
|
layout.operator(SaveContainer.bl_idname)
|
|
|
|
layout.separator()
|
|
layout.operator(ContainerProps.bl_idname)
|
|
layout.menu(ExtractFromContainerMenu.bl_idname)
|
|
|
|
layout.separator()
|
|
layout.operator(SaveContainerLayersCache.bl_idname,
|
|
icon=SaveContainerLayersCache.bl_icon)
|
|
layout.operator(RemoveContainerMissingLayers.bl_idname)
|
|
|
|
layout.separator()
|
|
layout.operator(AddLocator.bl_idname,
|
|
icon=AddLocator.bl_icon)
|
|
layout.operator(AddSlicer.bl_idname,
|
|
icon=AddSlicer.bl_icon)
|
|
layout.menu(AddCutterMenu.bl_idname)
|
|
|
|
layout.separator()
|
|
layout.menu(FetchLayerMenu.bl_idname)
|
|
|
|
|
|
class NodeContextMenu(bpy.types.Menu):
|
|
bl_idname = "BIOXELNODES_MT_NODE_CONTEXT"
|
|
bl_label = "Bioxel Nodes"
|
|
bl_icon = "FILE_VOLUME"
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.operator(ExtractNodeMesh.bl_idname)
|
|
layout.operator(ExtractNodeShapeWire.bl_idname)
|
|
layout.operator(ExtractNodeBboxWire.bl_idname)
|
|
|
|
layout.separator()
|
|
layout.operator(SaveSelectedLayersCache.bl_idname,
|
|
icon=SaveSelectedLayersCache.bl_icon)
|
|
layout.operator(RemoveSelectedLayers.bl_idname)
|
|
|
|
layout.separator()
|
|
layout.operator(RenameLayer.bl_idname,
|
|
icon=RenameLayer.bl_icon)
|
|
layout.operator(RetimeLayer.bl_idname)
|
|
layout.operator(RelocateLayer.bl_idname)
|
|
|
|
layout.separator()
|
|
layout.operator(ResampleLayer.bl_idname,
|
|
icon=ResampleLayer.bl_icon)
|
|
layout.operator(SignScalar.bl_idname)
|
|
layout.operator(FillByThreshold.bl_idname)
|
|
layout.operator(FillByRange.bl_idname)
|
|
layout.operator(FillByLabel.bl_idname)
|
|
layout.operator(CombineLabels.bl_idname)
|
|
|
|
|
|
def NODE_CONTEXT(self, context):
|
|
if is_incompatible():
|
|
return
|
|
|
|
container_obj = context.object
|
|
is_geo_nodes = context.area.ui_type == "GeometryNodeTree"
|
|
is_container = get_container_obj(container_obj)
|
|
|
|
if not is_geo_nodes or not is_container:
|
|
return
|
|
|
|
layout = self.layout
|
|
layout.separator()
|
|
layout.menu(NodeContextMenu.bl_idname)
|
|
|
|
|
|
def NODE_HEAD(self, context):
|
|
if is_incompatible():
|
|
return
|
|
|
|
container_obj = context.object
|
|
is_geo_nodes = context.area.ui_type == "GeometryNodeTree"
|
|
is_container = get_container_obj(container_obj)
|
|
|
|
if not is_geo_nodes or not is_container:
|
|
return
|
|
|
|
layout = self.layout
|
|
layout.separator()
|
|
layout.menu(NodeHeadMenu.bl_idname)
|
|
|
|
|
|
def NODE_PROP(self, context):
|
|
if is_incompatible():
|
|
return
|
|
|
|
container_obj = context.object
|
|
is_geo_nodes = context.area.ui_type == "GeometryNodeTree"
|
|
is_container = get_container_obj(container_obj)
|
|
self.bl_label = "Group"
|
|
|
|
if not is_geo_nodes or not is_container:
|
|
return
|
|
|
|
if container_obj.modifiers[0].node_group != context.space_data.edit_tree:
|
|
return
|
|
|
|
self.bl_label = "Bioxel Nodes"
|
|
|
|
layer_list_UL = bpy.context.window_manager.bioxelnodes_layer_list_UL
|
|
layer_list = layer_list_UL.layer_list
|
|
layer_list.clear()
|
|
|
|
for layer_obj in get_container_layer_objs(container_obj):
|
|
layer_item = layer_list.add()
|
|
layer_item.label = get_layer_label(layer_obj)
|
|
layer_item.obj_name = layer_obj.name
|
|
layer_item.info_text = "\n".join([f"{prop}: {get_layer_prop_value(layer_obj, prop)}"
|
|
for prop in ["kind",
|
|
"bioxel_size",
|
|
"shape",
|
|
"frame_count",
|
|
"channel_count",
|
|
"min", "max"]])
|
|
|
|
layout = self.layout
|
|
layout.label(text="Layer List")
|
|
split = layout.row()
|
|
split.template_list(listtype_name="BIOXELNODES_UL_layer_list",
|
|
list_id="layer_list",
|
|
dataptr=layer_list_UL,
|
|
propname="layer_list",
|
|
active_dataptr=layer_list_UL,
|
|
active_propname="layer_list_active",
|
|
item_dyntip_propname="info_text",
|
|
rows=20)
|
|
|
|
# sidebar = split.column(align=True)
|
|
# sidebar.menu(AddLayerMenu.bl_idname,
|
|
# icon=AddLayerMenu.bl_icon, text="")
|
|
|
|
# sidebar.operator(SaveContainerLayersCache.bl_idname,
|
|
# icon=SaveContainerLayersCache.bl_icon, text="")
|
|
# sidebar.operator(RemoveContainerMissingLayers.bl_idname,
|
|
# icon=RemoveContainerMissingLayers.bl_icon, text="")
|
|
|
|
# sidebar.separator()
|
|
# sidebar.operator(SaveSelectedLayersCache.bl_idname,
|
|
# icon=SaveSelectedLayersCache.bl_icon, text="")
|
|
# sidebar.operator(RemoveSelectedLayers.bl_idname,
|
|
# icon=RemoveSelectedLayers.bl_icon, text="")
|
|
|
|
# sidebar.separator()
|
|
# sidebar.operator(RenameLayer.bl_idname,
|
|
# icon=RenameLayer.bl_icon, text="")
|
|
# sidebar.operator(ResampleLayer.bl_idname,
|
|
# icon=ResampleLayer.bl_icon, text="")
|
|
# sidebar.operator(RetimeLayer.bl_idname,
|
|
# icon=RetimeLayer.bl_icon, text="")
|
|
|
|
# sidebar.separator()
|
|
# sidebar.operator(SignScalar.bl_idname,
|
|
# icon=SignScalar.bl_icon, text="")
|
|
# sidebar.operator(FillByThreshold.bl_idname,
|
|
# icon=FillByThreshold.bl_icon, text="")
|
|
# sidebar.operator(FillByRange.bl_idname,
|
|
# icon=FillByRange.bl_icon, text="")
|
|
# sidebar.operator(FillByLabel.bl_idname,
|
|
# icon=FillByLabel.bl_icon, text="")
|
|
|
|
# sidebar.separator()
|
|
# layout.separator()
|
|
|
|
|
|
def VIEW3D_TOPBAR(self, context):
|
|
layout = self.layout
|
|
layout.operator(SliceViewer.bl_idname)
|
|
|
|
|
|
node_menu = NodeMenu(
|
|
menu_items=MENU_ITEMS
|
|
)
|
|
|
|
|
|
def add():
|
|
node_menu.register()
|
|
bpy.types.VIEW3D_HT_header.append(VIEW3D_TOPBAR)
|
|
bpy.types.TOPBAR_MT_editor_menus.append(TOPBAR)
|
|
bpy.types.NODE_PT_node_tree_properties.prepend(NODE_PROP)
|
|
bpy.types.NODE_MT_editor_menus.append(NODE_HEAD)
|
|
bpy.types.NODE_MT_context_menu.append(NODE_CONTEXT)
|
|
|
|
|
|
def remove():
|
|
bpy.types.VIEW3D_HT_header.remove(VIEW3D_TOPBAR)
|
|
bpy.types.TOPBAR_MT_editor_menus.remove(TOPBAR)
|
|
bpy.types.NODE_PT_node_tree_properties.remove(NODE_PROP)
|
|
bpy.types.NODE_MT_editor_menus.remove(NODE_HEAD)
|
|
bpy.types.NODE_MT_context_menu.remove(NODE_CONTEXT)
|
|
node_menu.unregister()
|