techprotrade's picture
download
raw
21.8 kB
import bpy
import platform
from bl_ui.properties_paint_common import UnifiedPaintPanel
from bpy.types import Context
from .ops import Ops, Load_History, Copy_Tree, Load_Batch, Fetch_Node_Status, Clear_Node_Cache, SDNode_To_Image, Image_To_SDNode, Image_Set_Channel_Packed, Open_Log_Window, CleanVRam
from .translations import ctxt
from .SDNode import TaskManager, FakeServer
from .SDNode.tree import TREE_TYPE
from .SDNode.nodes import NodeBase
from .SDNode.rt_tracker import Tracker_Loop, is_looped
from .SDNode.operators import AIMatSolutionLoad, AIMatSolutionRun, AIMatSolutionSave, AIMatSolutionDel, AIMatSolutionApply, AIMatSolutionRestore
from .utils import Icon
from .preference import get_pref, AddonPreference
from .utils import get_addon_name, _T, get_ai_mat_tree
class Panel(bpy.types.Panel):
bl_idname = "SDN_PT_UI"
bl_translation_context = ctxt
bl_label = get_addon_name()
bl_description = ""
bl_space_type = "NODE_EDITOR"
bl_region_type = "UI"
bl_category = "ComfyUI"
@classmethod
def poll(cls, context):
return context.space_data.type == 'NODE_EDITOR' and context.space_data.tree_type == TREE_TYPE
def draw_header(self, context: Context):
row = self.layout.row(align=True)
if not hasattr(bpy.context.scene, "sdn"):
row.operator(Clear_Node_Cache.bl_idname, text="", icon="MODIFIER", text_ctxt=ctxt)
return
sdn = bpy.context.scene.sdn
row.prop(sdn, 'open_pref', text="", icon="PREFERENCES", text_ctxt=ctxt)
def draw_header_preset(self, context: Context):
row = self.layout.row(align=True)
if not hasattr(bpy.context.scene, "sdn"):
row.operator(Clear_Node_Cache.bl_idname, text="", icon="MODIFIER", text_ctxt=ctxt)
return
sdn = bpy.context.scene.sdn
if platform.system() not in ['Linux', 'Darwin']:
row.operator("wm.console_toggle", text="", icon="CONSOLE", text_ctxt=ctxt)
# row.prop(sdn, "restart_webui", text="", icon="RECOVER_LAST")
if TaskManager.server == FakeServer._instance:
row.operator(Ops.bl_idname, text="", icon="QUIT", text_ctxt=ctxt).action = "Launch"
else:
row.alert = True
row.operator(Ops.bl_idname, text="", icon="QUIT", text_ctxt=ctxt).action = "Close"
row.alert = False
row.operator(Fetch_Node_Status.bl_idname, text="", icon="FILE_REFRESH", text_ctxt=ctxt)
row.operator(Ops.bl_idname, text="", icon="RECOVER_LAST", text_ctxt=ctxt).action = "Restart"
row.prop(sdn, "open_webui", text="", icon="URL", text_ctxt=ctxt)
row.operator(Clear_Node_Cache.bl_idname, text="", icon="BRUSH_DATA", text_ctxt=ctxt)
def draw(self, context: bpy.types.Context):
layout = self.layout
if not hasattr(bpy.context.scene, "sdn"):
row = layout.row()
row.operator(Clear_Node_Cache.bl_idname, text="Clear Node Cache", icon="MODIFIER")
row.alert = True
row.scale_y = 2
return
if get_pref().debug:
self.show_debug(layout)
elif TaskManager.server == FakeServer._instance:
self.show_launch_cnn(layout)
return
elif TaskManager.is_launching():
box = layout.box()
box.alert = True
box.scale_y = 2
row = box.row()
row.alignment = "CENTER"
row.label(text="ComfyUI Launching/Connecting...", icon="INFO")
row = box.row()
row.alignment = "CENTER"
row.label(text=TaskManager.server.get_running_info(), icon="TIME")
return
self.show_common(layout)
self.show_custom(layout)
def show_common(self, layout: bpy.types.UILayout):
scale_popup = get_pref().popup_scale
col = layout.column()
row1 = col.row(align=True)
row1.alert = True
row1.scale_y = 2
if Ops.is_advanced_enable:
row1.operator(Ops.bl_idname, text="Stop Loop", icon="PAUSE").action = "StopLoop"
else:
row1.operator(Ops.bl_idname, text="Execute Node Tree", icon="PLAY").action = "Submit"
row1.prop(bpy.context.scene.sdn, "advanced_exe", text="", icon="SETTINGS")
row1.operator(CleanVRam.bl_idname, text="", icon="MEMORY")
if is_looped():
icon = "PAUSE"
action = "STOP"
else:
icon = "TIME"
action = "START"
layout.operator(Tracker_Loop.bl_idname, text="", icon=icon).action = action
if bpy.context.scene.sdn.advanced_exe:
adv_col = col.box().column(align=True)
adv_col.prop(bpy.context.scene.sdn, "loop_exec", text_ctxt=ctxt, toggle=True)
if not bpy.context.scene.sdn.loop_exec:
adv_col.prop(bpy.context.scene.sdn, "batch_count", text_ctxt=ctxt)
row = col.row(align=True)
row.scale_y = 1.3
row.operator(Ops.bl_idname, text="Cancel", icon="CANCEL").action = "Cancel"
row.operator(Ops.bl_idname, text="ClearTask", icon="TRASH").action = "ClearTask"
layout.operator(Load_Batch.bl_idname, text_ctxt=ctxt, icon="PLAY")
layout.prop(bpy.context.scene.sdn, "frame_mode", text="")
if bpy.context.scene.sdn.frame_mode == "Batch":
box = layout.box()
tree = bpy.context.space_data.edit_tree
box.prop(bpy.context.scene.sdn, "batch_dir", text="")
if tree and (select_node := tree.nodes.active):
box.label(text=_T("Selected Node: ") + select_node.name)
self.show_progress(layout)
box = layout.box()
row = box.row()
row.label(text="Node Tree", text_ctxt=ctxt)
row.prop(bpy.context.scene.sdn, "open_presets_dir", text="", icon="FILEBROWSER", text_ctxt=ctxt)
col = box.column(align=True)
col.prop(bpy.context.scene.sdn, "presets_dir", text="", text_ctxt=ctxt)
col.template_icon_view(bpy.context.scene.sdn, "presets", show_labels=True, scale_popup=scale_popup, scale=scale_popup)
# col.prop(bpy.context.scene.sdn, "presets", text="")
row = col.row(align=True)
row.operator(Ops.bl_idname, text="Save", text_ctxt=ctxt).action = "Save"
row.operator(Ops.bl_idname, text="Delete", text_ctxt=ctxt).action = "Del"
rrow = col.row(align=True)
rrow.operator(Ops.bl_idname, text="Replace Node Tree", text_ctxt=ctxt).action = "Load"
rrow.operator(Ops.bl_idname, text="", icon="TEXTURE", text_ctxt=ctxt).action = "PresetFromBookmark"
rrow.operator(Copy_Tree.bl_idname, text="", icon="COPYDOWN")
rrow.operator(Ops.bl_idname, text="", icon="PASTEDOWN", text_ctxt=ctxt).action = "PresetFromClipBoard"
box = layout.box()
row = box.row()
row.label(text="Node Group", text_ctxt=ctxt)
row.prop(bpy.context.scene.sdn, "open_groups_dir", text="", icon="FILEBROWSER", text_ctxt=ctxt)
col = box.column(align=True)
col.prop(bpy.context.scene.sdn, "groups_dir", text="", text_ctxt=ctxt)
col.template_icon_view(bpy.context.scene.sdn, "groups", show_labels=True, scale_popup=scale_popup, scale=scale_popup)
# col.prop(bpy.context.scene.sdn, "groups", text="")
row = col.row(align=True)
row.operator(Ops.bl_idname, text="Save", text_ctxt=ctxt).action = "SaveGroup"
row.operator(Ops.bl_idname, text="Delete", text_ctxt=ctxt).action = "DelGroup"
col.operator(Ops.bl_idname, text="Append Node Group", text_ctxt=ctxt).action = "LoadGroup"
sce = bpy.context.scene
if len(sce.sdn_history_item) == 0:
return
layout.template_list("HISTORY_UL_UIList", "", sce, "sdn_history_item", sce, "sdn_history_item_index")
def show_custom(self, layout: bpy.types.UILayout):
from .SDNode import crystools_monitor
crystools_monitor.draw(layout)
def show_launch_cnn(self, layout: bpy.types.UILayout):
if TaskManager.server != FakeServer._instance:
return
row = layout.row()
row.alignment = "CENTER"
row.label(text="↓↓ComfyUI Not Launched, Click to Launch↓↓")
row = layout.row(align=True)
row.alert = True
row.scale_y = 2
row.operator(Ops.bl_idname, text="Launch/Connect to ComfyUI", icon="PLAY").action = "Launch"
row.prop(bpy.context.scene.sdn, "show_pref_general", text="", icon="PREFERENCES")
if bpy.context.scene.sdn.show_pref_general:
AddonPreference.draw_general(get_pref(), layout.box())
self.show_error(layout)
def show_debug(self, layout: bpy.types.UILayout):
self.show_launch_cnn(layout)
return
rv3d = bpy.context.space_data.region_3d
layout.prop(rv3d, "view_camera_offset")
layout.prop(rv3d, "view_camera_zoom")
layout.prop(rv3d, "view_distance")
layout.prop(rv3d, "view_location")
layout.prop(rv3d, "view_matrix")
layout.prop(rv3d, "view_perspective")
layout.prop(rv3d, "window_matrix")
def show_progress(self, layout: bpy.types.UILayout):
layout = layout.box()
from .SDNode.custom_support import cup_monitor
cup_monitor.draw(layout)
self.show_error(layout)
if TaskManager.get_error_msg():
row = layout.box().row()
row.alignment = "CENTER"
row.alert = True
row.label(text="Adjust node tree and try again", text_ctxt=ctxt)
def show_error(self, layout: bpy.types.UILayout):
for error_msg in TaskManager.get_error_msg():
row = layout.row()
row.alert = True
row.label(text=error_msg, icon="ERROR", text_ctxt=ctxt)
def draw_header_button(self: bpy.types.Menu, context):
if context.space_data.tree_type == TREE_TYPE:
layout = self.layout
row = layout.row(align=True)
row.alert = True
row.operator(Ops.bl_idname, text="", text_ctxt=ctxt, icon="PLAY").action = "Submit"
row.operator(CleanVRam.bl_idname, text="", icon="MEMORY")
def draw_sdn_tofrom(self: bpy.types.Menu, context):
layout = self.layout
if context.space_data.tree_type == TREE_TYPE:
layout.separator()
layout.operator(SDNode_To_Image.bl_idname, text="To Image Editor", text_ctxt=ctxt, icon="EXPORT")
props = layout.operator(Image_To_SDNode.bl_idname, text="From Image Editor", text_ctxt=ctxt, icon="IMPORT")
props.force_centered = True
def draw_imeditor_tofrom(self: bpy.types.Menu, context):
layout = self.layout
layout.separator()
layout.operator(Image_Set_Channel_Packed.bl_idname, text_ctxt=ctxt) # , icon="MOD_MASK")
layout.operator(Image_To_SDNode.bl_idname, text="To ComfyUI Node Editor", text_ctxt=ctxt, icon="EXPORT")
layout.operator(SDNode_To_Image.bl_idname, text="From ComfyUI Node Editor", text_ctxt=ctxt, icon="IMPORT")
class HistoryItem(bpy.types.PropertyGroup):
name: bpy.props.StringProperty(default="")
class HISTORY_UL_UIList(bpy.types.UIList):
def draw_item(self,
context: bpy.types.Context,
layout: bpy.types.UILayout,
data, item, icon, active_data, active_property, index=0, flt_flag=0):
row = layout.row(align=True)
row.label(text=" " + item.name)
row.operator(Load_History.bl_idname, text="", icon="TIME").name = item.name
class AIMatPanel(bpy.types.Panel):
bl_idname = "SDN_AIMAT_PT_UI"
bl_translation_context = ctxt
bl_label = get_addon_name()
bl_description = ""
bl_space_type = "VIEW_3D"
bl_region_type = "UI"
bl_category = "AI"
bl_order = 0
def draw_header_preset(self, context: Context):
layout = self.layout
layout.prop(bpy.context.scene.sdn, "open_ai_sol_dir", text="", icon="FILE_FOLDER")
def draw(self, context: Context):
layout = self.layout
if not hasattr(bpy.context.scene, "sdn"):
row = layout.row()
row.operator(Clear_Node_Cache.bl_idname, text="Clear Node Cache", icon="MODIFIER")
row.alert = True
row.scale_y = 2
return
if TaskManager.server == FakeServer._instance:
self.show_launch_cnn(layout)
return
elif TaskManager.is_launching():
box = layout.box()
box.alert = True
box.scale_y = 2
row = box.row()
row.alignment = "CENTER"
row.label(text="ComfyUI Launching/Connecting...", icon="INFO")
row = box.row()
row.alignment = "CENTER"
row.label(text=TaskManager.server.get_running_info(), icon="TIME")
return
self.show_common(layout)
self.show_nodes(layout)
def show_common(self, layout: bpy.types.UILayout):
row = layout.row(align=True)
row.prop(bpy.context.scene.sdn, "ai_gen_solution", text="")
row.prop(bpy.context.scene.sdn, "clear_material_slots", text="", icon="CON_TRANSLIKE")
row.operator(AIMatSolutionSave.bl_idname, text="", icon="FILE_TICK")
row.operator(AIMatSolutionDel.bl_idname, text="", icon="TRASH")
layout.template_icon_view(bpy.context.scene.sdn, "ai_gen_solution", show_labels=True, scale_popup=5)
row = layout.row(align=True)
row.prop(bpy.context.scene.sdn, "ai_mat_tex_size", text="")
row.operator(AIMatSolutionLoad.bl_idname, text_ctxt=ctxt)
col = layout.column(align=True)
col.scale_y = 1.5
col.alert = bool(get_ai_mat_tree(bpy.context.object))
crow = col.row(align=True)
crow.operator(AIMatSolutionRun.bl_idname, text_ctxt=ctxt, icon="PLAY")
crcol = crow.column(align=True)
crcol.enabled = bool(get_ai_mat_tree(bpy.context.object))
crcol.prop(bpy.context.scene.sdn, "send_ai_tree_to_editor", text="", icon="FILE_REFRESH")
row = layout.row(align=True)
if bpy.context.object and bpy.context.object.get("AI_Mat_Gen_Applied", None):
row.alert = True
row.label(text="Applying...", icon="RECORD_ON")
row.label(text="", icon="RECORD_ON")
row.label(text="", icon="RECORD_ON")
row.label(text="", icon="RECORD_ON")
row.label(text="", icon="RECORD_ON")
row.label(text="", icon="RECORD_ON")
else:
row.operator(AIMatSolutionApply.bl_idname, text_ctxt=ctxt, icon="EVENT_RETURN") # KEY_RETURN_FILLED
row.operator(AIMatSolutionRestore.bl_idname, text_ctxt=ctxt, icon="LOOP_BACK") # KEY_BACKSPACE_FILLED
layout.prop(bpy.context.scene.sdn, "apply_bake_pass", text="")
self.show_progress(layout)
# if bpy.context.object and "AI_Mat_Gen_TexID" in bpy.context.object:
# layout.template_icon(bpy.context.object["AI_Mat_Gen_TexID"], scale=10)
# # layout.template_preview(bpy.context.object["AI_Mat_Gen_Tex"].preview.icon_id)
def show_launch_cnn(self, layout: bpy.types.UILayout):
if TaskManager.server != FakeServer._instance:
return
row = layout.row()
row.alignment = "CENTER"
row.label(text="↓↓ComfyUI Not Launched, Click to Launch↓↓")
row = layout.row(align=True)
row.alert = True
row.scale_y = 2
row.operator(Ops.bl_idname, text="Launch/Connect to ComfyUI", icon="PLAY").action = "Launch"
row.prop(bpy.context.scene.sdn, "show_pref_general", text="", icon="PREFERENCES")
if bpy.context.scene.sdn.show_pref_general:
AddonPreference.draw_general(get_pref(), layout.box())
self.show_error(layout)
def show_error(self, layout):
for error_msg in TaskManager.get_error_msg():
row = layout.row()
row.alert = True
row.label(text=error_msg, icon="ERROR", text_ctxt=ctxt)
def show_progress(self, layout: bpy.types.UILayout):
layout = layout.box()
from .SDNode.custom_support import cup_monitor
cup_monitor.draw(layout)
self.show_error(layout)
if TaskManager.get_error_msg():
row = layout.box().row()
row.alignment = "CENTER"
row.alert = True
row.label(text="Adjust node tree and try again", text_ctxt=ctxt)
def show_nodes(self, layout: bpy.types.UILayout):
tree = get_ai_mat_tree(bpy.context.object)
if not tree:
return
nodes: list[NodeBase] = []
for node in tree.nodes:
if len(node.label) != 3:
continue
# 判断 label 为 001 - 999 之间的字符串
if not node.label.isdigit() or int(node.label) < 1 or int(node.label) > 999:
continue
nodes.append(node)
nodes.sort(key=lambda x: x.label)
for node in nodes:
box = layout.box()
row = box.row()
row.prop(node, "ac_expand", icon="TRIA_DOWN" if node.ac_expand else "TRIA_RIGHT", text="", emboss=False)
if node.type != "GROUP":
row.label(text=node.name)
elif node.node_tree:
row.label(text=node.node_tree.name)
if node.ac_expand is False:
continue
if bpy.app.version >= (4, 2):
box.separator(type="LINE")
else:
box.separator()
node.draw_buttons(bpy.context, box)
def find_node_input(self, node: bpy.types.Node) -> list[bpy.types.NodeSocket]:
sockets = []
for inp in node.inputs:
if inp.is_linked:
continue
if inp.enabled is False or inp.hide:
continue
if inp.type == "RGBA" and inp.hide_value:
continue
sockets.append(inp)
return sockets
class PanelViewport(bpy.types.Panel):
bl_idname = "SDNV_PT_UI"
bl_translation_context = ctxt
bl_label = get_addon_name()
bl_description = ""
bl_space_type = "VIEW_3D"
bl_region_type = "UI"
bl_category = "圣杯节点"
def draw(self, context: Context):
rv3d = bpy.context.space_data.region_3d
self.layout.prop(rv3d, "view_camera_offset")
self.layout.prop(rv3d, "view_camera_zoom")
self.layout.prop(rv3d, "view_distance")
self.layout.prop(rv3d, "view_location")
self.layout.prop(rv3d, "view_matrix")
self.layout.prop(rv3d, "view_perspective")
self.layout.prop(rv3d, "window_matrix")
area = context.area
# zoom to fac powf((float(M_SQRT2) + camzoom / 50.0f), 2.0f) / 4.0f;
# max(area.width, area.height) * fac
fac = (2**0.5 + rv3d.view_camera_zoom / 50)**2 / 4
length = max(area.width, area.height) * fac
self.layout.prop(area, "width")
self.layout.prop(area, "height")
self.layout.prop(area, "x")
self.layout.prop(area, "y")
space_data = context.space_data
self.layout.label(text=f"{length:.2f}")
self.layout.label(text=f"{fac:.6f}")
settings = UnifiedPaintPanel.paint_settings(context)
brush = settings.brush # 可能报错 没brush(settings为空)
tex_slot = brush.texture_slot
col = self.layout.column()
col.template_ID_preview(tex_slot, "texture", new="texture.new", rows=3, cols=8)
# print(context.space_data.render_border_max_x)
from .timer import Timer
def f(brush, length, width, height):
if not brush:
return
offset_top = bpy.context.preferences.view.ui_scale * 26
enable_cam_offset = False
if enable_cam_offset:
coffx, coffy = rv3d.view_camera_offset
coffw = coffx * width
coffh = coffy * height
hwidth = width / 2
hheight = height / 2
fac = (2**0.5 + rv3d.view_camera_zoom / 50)**2 / 4
brush.stencil_pos = (hwidth - coffw, hheight - offset_top - coffh)
else:
rv3d.view_camera_offset = (0, 0)
brush.stencil_pos = (width / 2, (height) / 2 - offset_top)
brush.stencil_dimension = (length / 2, length / 2)
Timer.put((f, brush, length, area.width, area.height))
def status_bar_draw(self: bpy.types.Header, context: bpy.types.Context):
layout = self.layout
layout.label(text="[")
from .SDNode.custom_support import cup_monitor
cup_monitor.draw(layout, use_region_width=False)
layout.operator(Open_Log_Window.bl_idname, text="", icon="WORDWRAP_ON")
layout.label(text="]")
clss = (
AIMatPanel,
)
register, unregister = bpy.utils.register_classes_factory(clss)
def ui_reg():
register()
bpy.types.NODE_HT_header.append(draw_header_button)
bpy.types.IMAGE_MT_image.append(draw_imeditor_tofrom)
bpy.types.NODE_MT_node.append(draw_sdn_tofrom)
bpy.types.STATUSBAR_HT_header.append(status_bar_draw)
def ui_unreg():
bpy.types.STATUSBAR_HT_header.remove(status_bar_draw)
bpy.types.NODE_HT_header.remove(draw_header_button)
bpy.types.IMAGE_MT_image.remove(draw_imeditor_tofrom)
bpy.types.NODE_MT_node.remove(draw_sdn_tofrom)
unregister()

Xet Storage Details

Size:
21.8 kB
·
Xet hash:
f5584a9716d384c2a8bf9d622b71d818370c33f03bae2c4b21565426ad88cea8

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.