Node Wrangler: Remove Switch Type operator #104957
@ -20,10 +20,6 @@ def drawlayout(context, layout, mode='non-panel'):
|
||||
col.menu(NWMergeNodesMenu.bl_idname)
|
||||
col.separator()
|
||||
|
||||
col = layout.column(align=True)
|
||||
col.menu(NWSwitchNodeTypeMenu.bl_idname, text="Switch Node Type")
|
||||
col.separator()
|
||||
|
||||
if tree_type == 'ShaderNodeTree':
|
||||
col = layout.column(align=True)
|
||||
col.operator(operators.NWAddTextureSetup.bl_idname, text="Add Texture Setup", icon='NODE_SEL')
|
||||
@ -385,32 +381,8 @@ class NWSwitchNodeTypeMenu(Menu, NWBase):
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
categories = [c for c in node_categories_iter(context)
|
||||
if c.name not in ['Group', 'Script']]
|
||||
for cat in categories:
|
||||
idname = f"NODE_MT_nw_switch_{cat.identifier}_submenu"
|
||||
if hasattr(bpy.types, idname):
|
||||
layout.menu(idname)
|
||||
else:
|
||||
layout.label(text="Unable to load altered node lists.")
|
||||
layout.label(text="Please re-enable Node Wrangler.")
|
||||
break
|
||||
|
||||
|
||||
def draw_switch_category_submenu(self, context):
|
||||
layout = self.layout
|
||||
if self.category.name == 'Layout':
|
||||
for node in self.category.items(context):
|
||||
if node.nodetype != 'NodeFrame':
|
||||
props = layout.operator(operators.NWSwitchNodeType.bl_idname, text=node.label)
|
||||
props.to_type = node.nodetype
|
||||
else:
|
||||
for node in self.category.items(context):
|
||||
if isinstance(node, NodeItemCustom):
|
||||
node.draw(self, layout, context)
|
||||
continue
|
||||
props = layout.operator(operators.NWSwitchNodeType.bl_idname, text=node.label)
|
||||
props.to_type = node.nodetype
|
||||
layout.label(text="This operator is removed due to the changes of node menus.", icon='ERROR')
|
||||
layout.label(text="A native implementation of the function is expected in the future.")
|
||||
|
||||
#
|
||||
# APPENDAGES TO EXISTING UI
|
||||
|
@ -914,195 +914,6 @@ class NWReloadImages(Operator):
|
||||
return {'CANCELLED'}
|
||||
|
||||
|
||||
class NWSwitchNodeType(Operator, NWBase):
|
||||
"""Switch type of selected nodes """
|
||||
bl_idname = "node.nw_swtch_node_type"
|
||||
bl_label = "Switch Node Type"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
to_type: StringProperty(
|
||||
name="Switch to type",
|
||||
default='',
|
||||
)
|
||||
|
||||
def execute(self, context):
|
||||
to_type = self.to_type
|
||||
if len(to_type) == 0:
|
||||
return {'CANCELLED'}
|
||||
|
||||
nodes, links = get_nodes_links(context)
|
||||
# Those types of nodes will not swap.
|
||||
src_excludes = ('NodeFrame')
|
||||
# Those attributes of nodes will be copied if possible
|
||||
attrs_to_pass = ('color', 'hide', 'label', 'mute', 'parent',
|
||||
'show_options', 'show_preview', 'show_texture',
|
||||
'use_alpha', 'use_clamp', 'use_custom_color', 'location'
|
||||
)
|
||||
selected = [n for n in nodes if n.select]
|
||||
reselect = []
|
||||
for node in [n for n in selected if
|
||||
n.rna_type.identifier not in src_excludes and
|
||||
n.rna_type.identifier != to_type]:
|
||||
new_node = nodes.new(to_type)
|
||||
for attr in attrs_to_pass:
|
||||
if hasattr(node, attr) and hasattr(new_node, attr):
|
||||
setattr(new_node, attr, getattr(node, attr))
|
||||
# set image datablock of dst to image of src
|
||||
if hasattr(node, 'image') and hasattr(new_node, 'image'):
|
||||
if node.image:
|
||||
new_node.image = node.image
|
||||
# Special cases
|
||||
if new_node.type == 'SWITCH':
|
||||
new_node.hide = True
|
||||
# Dictionaries: src_sockets and dst_sockets:
|
||||
# 'INPUTS': input sockets ordered by type (entry 'MAIN' main type of inputs).
|
||||
# 'OUTPUTS': output sockets ordered by type (entry 'MAIN' main type of outputs).
|
||||
# in 'INPUTS' and 'OUTPUTS':
|
||||
# 'SHADER', 'RGBA', 'VECTOR', 'VALUE' - sockets of those types.
|
||||
# socket entry:
|
||||
# (index_in_type, socket_index, socket_name, socket_default_value, socket_links)
|
||||
src_sockets = {
|
||||
'INPUTS': {'SHADER': [], 'RGBA': [], 'VECTOR': [], 'VALUE': [], 'MAIN': None},
|
||||
'OUTPUTS': {'SHADER': [], 'RGBA': [], 'VECTOR': [], 'VALUE': [], 'MAIN': None},
|
||||
}
|
||||
dst_sockets = {
|
||||
'INPUTS': {'SHADER': [], 'RGBA': [], 'VECTOR': [], 'VALUE': [], 'MAIN': None},
|
||||
'OUTPUTS': {'SHADER': [], 'RGBA': [], 'VECTOR': [], 'VALUE': [], 'MAIN': None},
|
||||
}
|
||||
types_order_one = 'SHADER', 'RGBA', 'VECTOR', 'VALUE'
|
||||
types_order_two = 'SHADER', 'VECTOR', 'RGBA', 'VALUE'
|
||||
# check src node to set src_sockets values and dst node to set dst_sockets dict values
|
||||
for sockets, nd in ((src_sockets, node), (dst_sockets, new_node)):
|
||||
# Check node's inputs and outputs and fill proper entries in "sockets" dict
|
||||
for in_out, in_out_name in ((nd.inputs, 'INPUTS'), (nd.outputs, 'OUTPUTS')):
|
||||
# enumerate in inputs, then in outputs
|
||||
# find name, default value and links of socket
|
||||
for i, socket in enumerate(in_out):
|
||||
the_name = socket.name
|
||||
dval = None
|
||||
# Not every socket, especially in outputs has "default_value"
|
||||
if hasattr(socket, 'default_value'):
|
||||
dval = socket.default_value
|
||||
socket_links = []
|
||||
for lnk in socket.links:
|
||||
socket_links.append(lnk)
|
||||
# check type of socket to fill proper keys.
|
||||
for the_type in types_order_one:
|
||||
if socket.type == the_type:
|
||||
# create values for sockets['INPUTS'][the_type] and sockets['OUTPUTS'][the_type]
|
||||
# entry structure: (index_in_type, socket_index, socket_name,
|
||||
# socket_default_value, socket_links)
|
||||
sockets[in_out_name][the_type].append(
|
||||
(len(sockets[in_out_name][the_type]), i, the_name, dval, socket_links))
|
||||
# Check which of the types in inputs/outputs is considered to be "main".
|
||||
# Set values of sockets['INPUTS']['MAIN'] and sockets['OUTPUTS']['MAIN']
|
||||
for type_check in types_order_one:
|
||||
if sockets[in_out_name][type_check]:
|
||||
sockets[in_out_name]['MAIN'] = type_check
|
||||
break
|
||||
|
||||
matches = {
|
||||
'INPUTS': {'SHADER': [], 'RGBA': [], 'VECTOR': [], 'VALUE_NAME': [], 'VALUE': [], 'MAIN': []},
|
||||
'OUTPUTS': {'SHADER': [], 'RGBA': [], 'VECTOR': [], 'VALUE_NAME': [], 'VALUE': [], 'MAIN': []},
|
||||
}
|
||||
|
||||
for inout, soctype in (
|
||||
('INPUTS', 'MAIN',),
|
||||
('INPUTS', 'SHADER',),
|
||||
('INPUTS', 'RGBA',),
|
||||
('INPUTS', 'VECTOR',),
|
||||
('INPUTS', 'VALUE',),
|
||||
('OUTPUTS', 'MAIN',),
|
||||
('OUTPUTS', 'SHADER',),
|
||||
('OUTPUTS', 'RGBA',),
|
||||
('OUTPUTS', 'VECTOR',),
|
||||
('OUTPUTS', 'VALUE',),
|
||||
):
|
||||
if src_sockets[inout][soctype] and dst_sockets[inout][soctype]:
|
||||
if soctype == 'MAIN':
|
||||
sc = src_sockets[inout][src_sockets[inout]['MAIN']]
|
||||
dt = dst_sockets[inout][dst_sockets[inout]['MAIN']]
|
||||
else:
|
||||
sc = src_sockets[inout][soctype]
|
||||
dt = dst_sockets[inout][soctype]
|
||||
# start with 'dt' to determine number of possibilities.
|
||||
for i, soc in enumerate(dt):
|
||||
# if src main has enough entries - match them with dst main sockets by indexes.
|
||||
if len(sc) > i:
|
||||
matches[inout][soctype].append(((sc[i][1], sc[i][3]), (soc[1], soc[3])))
|
||||
# add 'VALUE_NAME' criterion to inputs.
|
||||
if inout == 'INPUTS' and soctype == 'VALUE':
|
||||
for s in sc:
|
||||
if s[2] == soc[2]: # if names match
|
||||
# append src (index, dval), dst (index, dval)
|
||||
matches['INPUTS']['VALUE_NAME'].append(((s[1], s[3]), (soc[1], soc[3])))
|
||||
|
||||
# When src ['INPUTS']['MAIN'] is 'VECTOR' replace 'MAIN' with matches VECTOR if possible.
|
||||
# This creates better links when relinking textures.
|
||||
if src_sockets['INPUTS']['MAIN'] == 'VECTOR' and matches['INPUTS']['VECTOR']:
|
||||
matches['INPUTS']['MAIN'] = matches['INPUTS']['VECTOR']
|
||||
|
||||
# Pass default values and RELINK:
|
||||
for tp in ('MAIN', 'SHADER', 'RGBA', 'VECTOR', 'VALUE_NAME', 'VALUE'):
|
||||
# INPUTS: Base on matches in proper order.
|
||||
for (src_i, src_dval), (dst_i, dst_dval) in matches['INPUTS'][tp]:
|
||||
# pass dvals
|
||||
if src_dval and dst_dval and tp in {'RGBA', 'VALUE_NAME'}:
|
||||
new_node.inputs[dst_i].default_value = src_dval
|
||||
# Special case: switch to math
|
||||
if node.type in {'MIX_RGB', 'ALPHAOVER', 'ZCOMBINE'} and\
|
||||
new_node.type == 'MATH' and\
|
||||
tp == 'MAIN':
|
||||
new_dst_dval = max(src_dval[0], src_dval[1], src_dval[2])
|
||||
new_node.inputs[dst_i].default_value = new_dst_dval
|
||||
if node.type == 'MIX_RGB':
|
||||
if node.blend_type in [o[0] for o in operations]:
|
||||
new_node.operation = node.blend_type
|
||||
# Special case: switch from math to some types
|
||||
if node.type == 'MATH' and\
|
||||
new_node.type in {'MIX_RGB', 'ALPHAOVER', 'ZCOMBINE'} and\
|
||||
tp == 'MAIN':
|
||||
for i in range(3):
|
||||
new_node.inputs[dst_i].default_value[i] = src_dval
|
||||
if new_node.type == 'MIX_RGB':
|
||||
if node.operation in [t[0] for t in blend_types]:
|
||||
new_node.blend_type = node.operation
|
||||
# Set Fac of MIX_RGB to 1.0
|
||||
new_node.inputs[0].default_value = 1.0
|
||||
# make link only when dst matching input is not linked already.
|
||||
if node.inputs[src_i].links and not new_node.inputs[dst_i].links:
|
||||
in_src_link = node.inputs[src_i].links[0]
|
||||
in_dst_socket = new_node.inputs[dst_i]
|
||||
connect_sockets(in_src_link.from_socket, in_dst_socket)
|
||||
links.remove(in_src_link)
|
||||
# OUTPUTS: Base on matches in proper order.
|
||||
for (src_i, src_dval), (dst_i, dst_dval) in matches['OUTPUTS'][tp]:
|
||||
for out_src_link in node.outputs[src_i].links:
|
||||
out_dst_socket = new_node.outputs[dst_i]
|
||||
connect_sockets(out_dst_socket, out_src_link.to_socket)
|
||||
# relink rest inputs if possible, no criteria
|
||||
for src_inp in node.inputs:
|
||||
for dst_inp in new_node.inputs:
|
||||
if src_inp.links and not dst_inp.links:
|
||||
src_link = src_inp.links[0]
|
||||
connect_sockets(src_link.from_socket, dst_inp)
|
||||
links.remove(src_link)
|
||||
# relink rest outputs if possible, base on node kind if any left.
|
||||
for src_o in node.outputs:
|
||||
for out_src_link in src_o.links:
|
||||
for dst_o in new_node.outputs:
|
||||
if src_o.type == dst_o.type:
|
||||
connect_sockets(dst_o, out_src_link.to_socket)
|
||||
# relink rest outputs no criteria if any left. Link all from first output.
|
||||
for src_o in node.outputs:
|
||||
for out_src_link in src_o.links:
|
||||
if new_node.outputs:
|
||||
connect_sockets(new_node.outputs[0], out_src_link.to_socket)
|
||||
nodes.remove(node)
|
||||
force_update(context)
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class NWMergeNodes(Operator, NWBase):
|
||||
bl_idname = "node.nw_merge_nodes"
|
||||
bl_label = "Merge Nodes"
|
||||
@ -2976,7 +2787,6 @@ classes = (
|
||||
NWPreviewNode,
|
||||
NWFrameSelected,
|
||||
NWReloadImages,
|
||||
NWSwitchNodeType,
|
||||
NWMergeNodes,
|
||||
NWBatchChangeNodes,
|
||||
NWChangeMixFactor,
|
||||
|
@ -162,7 +162,6 @@ class NWNodeWrangler(bpy.types.AddonPreferences):
|
||||
#
|
||||
# REGISTER/UNREGISTER CLASSES AND KEYMAP ITEMS
|
||||
#
|
||||
switch_category_menus = []
|
||||
addon_keymaps = []
|
||||
# kmi_defs entry: (identifier, key, action, CTRL, SHIFT, ALT, props, nice name)
|
||||
# props entry: (property name, property value)
|
||||
@ -392,28 +391,8 @@ def register():
|
||||
setattr(kmi.properties, prop, value)
|
||||
addon_keymaps.append((km, kmi))
|
||||
|
||||
# switch submenus
|
||||
switch_category_menus.clear()
|
||||
for cat in node_categories_iter(None):
|
||||
if cat.name not in ['Group', 'Script']:
|
||||
idname = f"NODE_MT_nw_switch_{cat.identifier}_submenu"
|
||||
switch_category_type = type(idname, (bpy.types.Menu,), {
|
||||
"bl_space_type": 'NODE_EDITOR',
|
||||
"bl_label": cat.name,
|
||||
"category": cat,
|
||||
"poll": cat.poll,
|
||||
"draw": interface.draw_switch_category_submenu,
|
||||
})
|
||||
|
||||
switch_category_menus.append(switch_category_type)
|
||||
|
||||
bpy.utils.register_class(switch_category_type)
|
||||
|
||||
|
||||
def unregister():
|
||||
for cat_types in switch_category_menus:
|
||||
bpy.utils.unregister_class(cat_types)
|
||||
switch_category_menus.clear()
|
||||
|
||||
# keymaps
|
||||
for km, kmi in addon_keymaps:
|
||||
|
Loading…
Reference in New Issue
Block a user