Module sverchok.core.sockets
Expand source code
# -*- coding: utf-8 -*-
# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
import inspect
import sys
from typing import Set
from mathutils import Matrix, Quaternion
import bpy
from bpy.props import StringProperty, BoolProperty, FloatVectorProperty, IntProperty, FloatProperty, EnumProperty, \
PointerProperty
from bpy.types import NodeTree, NodeSocket
from sverchok.core.socket_conversions import ConversionPolicies
from sverchok.core.socket_data import sv_get_socket, sv_set_socket, sv_forget_socket
from sverchok.core.sv_custom_exceptions import SvNoDataError
from sverchok.data_structure import (
enum_item_4,
get_other_socket, replace_socket,
SIMPLE_DATA_TYPES,
flatten_data, graft_data, map_at_level, wrap_data, unwrap_data)
from sverchok.settings import get_param
from sverchok.utils.handle_blender_data import get_func_and_args, BlDomains
from sverchok.utils.socket_utils import format_bpy_property, setup_new_node_location
from sverchok.utils.field.scalar import SvScalarField
from sverchok.utils.field.vector import SvVectorField
from sverchok.utils.curve import SvCurve
from sverchok.utils.curve.algorithms import reparametrize_curve
from sverchok.utils.surface import SvSurface
from sverchok.dependencies import FreeCAD
STANDARD_TYPES = SIMPLE_DATA_TYPES + (SvCurve, SvSurface)
if FreeCAD is not None:
import Part
STANDARD_TYPES = STANDARD_TYPES + (Part.Shape,)
def process_from_socket(self, context):
"""Update function of exposed properties in Sockets"""
if self.node is not None: # https://developer.blender.org/T88587
self.node.process_node(context)
def update_interface(self, context):
"""Update group node sockets and update it"""
# For now I don't think that `hide value` property should call this function, but in some cases it could be useful
# if interface socket will get min and max value parameter then probably Sv sockets also should get it
if not self.id_data.group_node_name: # initialization tree
return
self.id_data.update_sockets()
group_tree = self.id_data
group_node = group_tree.get_update_path()[-1]
input_node = group_node.active_input()
if input_node:
group_tree.update_nodes([input_node])
def socket_type_names() -> Set[str]:
names = set()
for name, member in inspect.getmembers(sys.modules[__name__]):
is_module_cls = inspect.isclass(member) and member.__module__ == __name__
if is_module_cls:
if NodeSocket in member.__bases__:
names.add(member.bl_idname)
return names
class SV_MT_AllSocketsOptionsMenu(bpy.types.Menu):
bl_label = "Sockets Options"
@classmethod
def poll(cls, context):
return hasattr(context, 'node')# and hasattr(context, 'socket')
def draw(self, context):
node = context.active_node
if not node:
return
layout = self.layout
for s in node.outputs:
if hasattr(s, 'draw_menu_items'):
layout.context_pointer_set("socket", s)
layout.context_pointer_set("node", node)
layout.menu('SV_MT_SocketOptionsMenu', text=s.name)
class SV_MT_SocketOptionsMenu(bpy.types.Menu):
bl_label = "Socket Options"
def draw(self, context):
node = context.node
if not node:
return
layout = self.layout
if hasattr(context.socket, 'draw_menu_items'):
context.socket.draw_menu_items(context, layout)
class SvSocketProcessing():
"""
Mixin class for data processing logic of a socket.
"""
# These properties are to be set explicitly by node classes
# for input sockets, if the node knows it can handle simplified data.
# For outputs, these properties are not used.
allow_flatten : BoolProperty(default = False)
allow_flatten_topology : BoolProperty(default = False)
allow_simplify : BoolProperty(default = False)
allow_graft : BoolProperty(default = False)
allow_unwrap : BoolProperty(default = False)
allow_wrap : BoolProperty(default = False)
# technical property
skip_simplify_mode_update: BoolProperty(default=False)
skip_wrap_mode_update: BoolProperty(default=False)
use_graft : BoolProperty(
name = "Graft",
default = False,
update = process_from_socket)
def update_unwrap_flag(self, context):
if self.skip_wrap_mode_update:
return
try:
self.skip_wrap_mode_update = True
if self.use_unwrap:
self.use_wrap = False
finally:
self.skip_wrap_mode_update = False
process_from_socket(self, context)
def update_wrap_flag(self, context):
if self.skip_wrap_mode_update:
return
try:
self.skip_wrap_mode_update = True
if self.use_wrap:
self.use_unwrap = False
finally:
self.skip_wrap_mode_update = False
process_from_socket(self, context)
use_unwrap : BoolProperty(
name = "Unwrap",
default = False,
update = update_unwrap_flag)
use_wrap : BoolProperty(
name = "Wrap",
default = False,
update = update_wrap_flag)
def update_flatten_flag(self, context):
if self.skip_simplify_mode_update:
return
try:
self.skip_simplify_mode_update = True
if self.use_flatten:
self.use_simplify = False
finally:
self.skip_simplify_mode_update = False
process_from_socket(self, context)
def update_simplify_flag(self, context):
if self.skip_simplify_mode_update:
return
try:
self.skip_simplify_mode_update = True
if self.use_simplify:
self.use_flatten = False
finally:
self.skip_simplify_mode_update = False
process_from_socket(self, context)
use_flatten_topology : BoolProperty(
name = "Flatten Topology",
default = False,
update = process_from_socket)
# Only one of properties can be set to true: use_flatten or use_simplfy
use_flatten : BoolProperty(
name = "Flatten",
default = False,
update = update_flatten_flag)
use_simplify : BoolProperty(
name = "Simplify",
default = False,
update = update_simplify_flag)
def get_mode_flags(self):
flags = []
if self.use_flatten:
flags.append('F')
if self.use_flatten_topology:
flags.append('FT')
if self.use_simplify:
flags.append('S')
if self.use_graft:
flags.append('G')
if self.use_unwrap:
flags.append('U')
if self.use_wrap:
flags.append('W')
return flags
def can_flatten(self):
return hasattr(self, 'do_flatten') and (self.allow_flatten or self.is_output)
def can_flatten_topology(self):
return hasattr(self, 'do_flat_topology') and (self.allow_flatten_topology or self.is_output)
def can_simplify(self):
return hasattr(self, 'do_simplify') and (self.allow_simplify or self.is_output)
def can_graft(self):
return hasattr(self, 'do_graft') and (self.is_output or self.allow_graft)
def can_unwrap(self):
return self.is_output or self.allow_unwrap
def can_wrap(self):
return self.is_output or self.allow_wrap
def draw_simplify_modes(self, layout):
if self.can_flatten():
layout.prop(self, 'use_flatten')
if self.can_simplify():
layout.prop(self, 'use_simplify')
def preprocess_input(self, data):
result = data
if self.use_flatten:
result = self.do_flatten(data)
elif self.use_simplify:
result = self.do_simplify(data)
if self.use_graft:
result = self.do_graft(result)
if self.use_unwrap:
result = unwrap_data(result, socket=self)
if self.use_wrap:
result = wrap_data(result)
return result
def postprocess_output(self, data):
result = data
if self.use_flatten_topology:
result = self.do_flat_topology(data)
if self.use_flatten:
result = self.do_flatten(data)
elif self.use_simplify:
result = self.do_simplify(data)
if self.use_graft:
result = self.do_graft(result)
if self.use_unwrap:
result = unwrap_data(result, socket=self)
if self.use_wrap:
result = wrap_data(result)
return result
def has_simplify_modes(self, context):
return self.can_flatten() or self.can_simplify()
def has_menu(self, context):
return self.has_simplify_modes(context) or self.can_graft() or self.can_wrap()
def draw_menu_button(self, context, layout, node, text):
if hasattr(node.id_data, 'sv_show_socket_menus') and node.id_data.sv_show_socket_menus:
if (self.is_output or self.is_linked or not self.use_prop):
layout.menu('SV_MT_SocketOptionsMenu', text='', icon='TRIA_DOWN')
def draw_menu_items(self, context, layout):
if self.can_flatten_topology():
layout.prop(self, 'use_flatten_topology')
self.draw_simplify_modes(layout)
if self.can_graft():
layout.prop(self, 'use_graft')
if self.can_unwrap():
layout.prop(self, 'use_unwrap')
if self.can_wrap():
layout.prop(self, 'use_wrap')
def copy_options(self, other):
for identifier, prop in SvSocketProcessing.__annotations__.items():
if isinstance(prop, bpy.props._PropertyDeferred):
setattr(self, identifier, getattr(other, identifier))
class SocketDomain:
"""Socket mix-in class to define domain options
The option is shown when socket is connected
and can be used for transferring data to certain elements of an object."""
domain: EnumProperty(items=[(d.name, d.value, '') for d in BlDomains],
update=process_from_socket)
show_domain: BoolProperty()
class SvSocketCommon(SvSocketProcessing):
"""
Base class for all Sockets
'SKIP_SAVE' in properties means skipping them during saving in JSON format
some of the properties can be skipped because they are static, they are always set only in sv_init method
"""
color = (1, 0, 0, 1) # base color, other sockets should override the property, use FloatProperty for dynamic
default_conversion_name = ConversionPolicies.DEFAULT.conversion_name
label: StringProperty() # It will be drawn instead of name if given
quick_link_to_node = str() # sockets which often used with other nodes can fill its `bl_idname` here
link_menu_handler : StringProperty(default='') # To specify additional entries in the socket link menu
enable_input_link_menu : BoolProperty(default = True)
# set True to use default socket property if it has got it
use_prop: BoolProperty(default=False)
custom_draw: StringProperty(description="For name of method which will draw socket UI (optionally)")
prop_name: StringProperty(default='', description="For displaying node property in socket UI")
# utility field for showing number of objects in sockets data
objects_number: IntProperty(min=0, options={'SKIP_SAVE'})
description : StringProperty()
is_mandatory: BoolProperty(default=False)
nesting_level: IntProperty(default=2)
default_mode: EnumProperty(items=enum_item_4(['NONE', 'EMPTY_LIST', 'MATRIX', 'MASK']), default='EMPTY_LIST')
pre_processing: EnumProperty(items=enum_item_4(['NONE', 'ONE_ITEM']), default='NONE')
s_id: StringProperty(options={'SKIP_SAVE'})
def get_link_parameter_node(self):
return self.quick_link_to_node
def setup_parameter_node(self, param_node):
pass
def get_prop_name(self):
"""
Intended to return name of property related with socket owned by its node
Name can be replaced by twin property name in draft mode of a tree
"""
node = self.node
if node and hasattr(node, 'does_support_draft_mode') and node.does_support_draft_mode() and hasattr(node.id_data, 'sv_draft') and node.id_data.sv_draft:
prop_name_draft = self.node.draft_properties_mapping.get(self.prop_name, None)
if prop_name_draft:
return prop_name_draft
return self.prop_name
return self.prop_name
@property
def other(self):
"""Returns opposite linked socket, if socket is outputs it will return one random opposite linked socket"""
return get_other_socket(self)
@property
def socket_id(self):
"""Id of socket used by data_cache"""
_id = self.s_id
if not _id:
self.s_id = str(hash(self.node.node_id + self.identifier + ('o' if self.is_output else 'i')))
_id = self.s_id
return _id
@property
def index(self):
"""Index of socket, hidden sockets are also taken into account"""
node = self.node
sockets = node.outputs if self.is_output else node.inputs
for i, s in enumerate(sockets):
if s == self:
return i
@property
def hide_safe(self):
"""It will hide even linked sockets"""
return self.hide
@hide_safe.setter
def hide_safe(self, value):
# handles both input and output.
if self.is_linked and value:
for link in self.links:
self.id_data.links.remove(link)
self.hide = value
def sv_get(self, default=..., deepcopy=True):
"""
The method is used for getting socket data
In most cases the method should not be overridden
Also a socket can use its default_property
Order of getting data (if available):
1. written socket data
2. node default property
3. socket default property
4. script default property
5. Raise no data error
:param default: script default property
:param deepcopy: in most cases should be False for efficiency but not in cases if input data will be modified
:return: data bound to the socket
"""
if self.is_output:
return sv_get_socket(self, False)
if self.is_linked:
return sv_get_socket(self, deepcopy)
prop_name = self.get_prop_name()
if prop_name:
prop = getattr(self.node, prop_name)
return format_bpy_property(prop)
if self.use_prop and hasattr(self, 'default_property') and self.default_property is not None:
default_property = self.default_property
return format_bpy_property(default_property)
if default is not ...:
return default
raise SvNoDataError(self)
def sv_set(self, data):
"""Set data, provide context in case the node can be evaluated several times in different context"""
if self.is_output:
data = self.postprocess_output(data)
# it's expensive to call sv_get method to update the number in other places
self.objects_number = len(data)
sv_set_socket(self, data)
def sv_forget(self):
"""Delete socket memory"""
sv_forget_socket(self)
def replace_socket(self, new_type, new_name=None):
"""Replace a socket with a socket of new_type and keep links,
return the new socket, the old reference might be invalid"""
self.sv_forget()
return replace_socket(self, new_type, new_name)
def draw_property(self, layout, prop_origin=None, prop_name='default_property'):
"""
This method can be overridden for showing property in another way
Property will be shown only if socket is unconnected input
If prop_origin is None then the default socket property should be shown
"""
if prop_origin is None and hasattr(self, prop_name):
layout.prop(self, 'default_property')
else:
layout.prop(prop_origin, prop_name)
def draw_quick_link(self, context, layout, node):
"""
Will draw button for creating new node which is often used with such type of sockets
The socket should have `bl_idname` of other node in `quick_link_to_node` attribute for using this UI
"""
if self.quick_link_to_node:
layout.operator('node.sv_quicklink_new_node_input', text="", icon="PLUGIN")
def does_support_link_input_menu(self, context, layout, node):
if not self.enable_input_link_menu:
return False
param_node = self.get_link_parameter_node()
if not param_node:
return False
return True
def draw_link_input_menu(self, context, layout, node):
if not self.does_support_link_input_menu(context, layout, node):
return
op = layout.operator('node.sv_input_link_menu_popup', text="", icon="PLUGIN")
op.tree_name = node.id_data.name
op.node_name = node.name
op.input_name = self.name
def draw(self, context, layout, node, text):
def draw_label(text):
flags = self.get_mode_flags()
if flags:
text = text + " [" + ",".join(flags) + "]"
if self.description:
layout.operator('node.sv_socket_show_help', text=text, emboss=False).text = self.description
else:
if hasattr(self, 'show_domain') and self.show_domain:
row = layout.row()
row.label(text=text)
row.prop(self, 'domain', text='')
else:
layout.label(text=text)
menu_option = get_param('show_input_menus', 'QUICKLINK')
# just handle custom draw..be it input or output.
if self.custom_draw:
# does the node have the draw function referred to by
# the string stored in socket's custom_draw attribute
if hasattr(node, self.custom_draw):
getattr(node, self.custom_draw)(self, context, layout)
elif self.is_linked: # linked INPUT or OUTPUT
draw_label((self.label or text) + f". {self.objects_number or ''}")
elif self.is_output: # unlinked OUTPUT
draw_label(self.label or text)
else: # unlinked INPUT
prop_name = self.get_prop_name()
if prop_name: # has property
if menu_option == 'ALL':
self.draw_link_input_menu(context, layout, node)
self.draw_property(layout, prop_origin=node, prop_name=prop_name)
elif node.bl_idname == 'SvGroupTreeNode' and hasattr(self, 'draw_group_property'): # group node
if node.node_tree: # when tree is removed from node sockets still exist
interface_socket = node.node_tree.inputs[self.index]
self.draw_group_property(layout, text, interface_socket)
elif node.bl_idname == 'NodeGroupOutput' and hasattr(self, 'draw_group_property'): # group out node
if self.index < len(node.outputs): # in case of last socket of the node which is virtual
interface_socket = node.outputs[self.index]
self.draw_group_property(layout, text, interface_socket)
elif self.use_prop: # no property but use default prop
if menu_option == 'ALL':
self.draw_link_input_menu(context, layout, node)
self.draw_property(layout)
else: # no property and not use default prop
if menu_option == 'QUICKLINK':
self.draw_quick_link(context, layout, node)
elif menu_option == 'ALL':
self.draw_link_input_menu(context, layout, node)
draw_label(self.label or text)
if self.has_menu(context):
self.draw_menu_button(context, layout, node, text)
def draw_color(self, context, node):
return self.color
class SvObjectSocket(NodeSocket, SvSocketCommon):
bl_idname = "SvObjectSocket"
bl_label = "Object Socket"
def filter_kinds(self, objs):
"""
object_kinds could be any of these:
[‘MESH’, ‘CURVE’, ‘SURFACE’, ‘META’, ‘FONT’, ‘VOLUME’, ‘ARMATURE’, ‘LATTICE’,
‘EMPTY’, ‘GPENCIL’, ‘CAMERA’, ‘LIGHT’, ‘SPEAKER’, ‘LIGHT_PROBE’, ‘EMPTY’
for example
socket.object_kinds = "MESH"
or if you want various kinds
socket.object_kinds = "MESH,CURVE"
"""
if self.object_kinds in {'ALL', ''}:
return True
if not self.object_kinds:
return True
kind = self.object_kinds
if "," in kind:
kinds = kind.split(',')
if objs.type in set(kinds):
return True
if objs.type == kind:
return True
color = (0.69, 0.74, 0.73, 1.0)
use_prop: BoolProperty(default=True)
object_kinds: StringProperty(default='ALL') # use for filtering objects, see filter_kinds method
object_ref: StringProperty(update=process_from_socket)
object_ref_pointer: bpy.props.PointerProperty(
name="Object Reference",
poll=filter_kinds, # seld.object_kinds can be "MESH" or "MESH,CURVE,.."
type=bpy.types.Object, # what kind of objects are we showing
update=process_from_socket)
@property
def default_property(self):
# this can be more granular and even attempt to set object_ref_points from object_ref, and then wipe object_ref
return self.node.get_bpy_data_from_name(self.object_ref or self.object_ref_pointer, bpy.data.objects)
def draw_property(self, layout, prop_origin=None, prop_name='default_property'):
if prop_origin:
layout.prop(prop_origin, prop_name) # need for consistency, probably will never be used
else:
layout.prop_search(self, 'object_ref_pointer', bpy.data, 'objects', text=self.name)
class SvFormulaSocket(NodeSocket, SvSocketCommon):
bl_idname = "SvFormulaSocket"
bl_label = "Formula Socket"
color = (0.68, 0.85, 0.90, 1)
depth: IntProperty(
description="Depth exposed to the formula",
update=process_from_socket,
default=1,
min=1)
def update_depth(self, context):
if self.transform == 'Vector' and self.depth < 2:
self.depth = 2
else:
process_from_socket(self, context)
transform: EnumProperty(
description='Transform before exposing to the formula',
items=enum_item_4(['As is', 'Vector', 'Array', 'Set', 'String']),
update=update_depth)
default_conversion_name = ConversionPolicies.LENIENT.conversion_name
def draw(self, context, layout, node, text):
layout.label(text=self.name+ '. ' + str(self.objects_number))
layout.prop(self,'depth',text='Depth')
layout.prop(self,'transform',text='')
class SvTextSocket(NodeSocket, SvSocketCommon):
bl_idname = "SvTextSocket"
bl_label = "Text Socket"
color = (0.68, 0.85, 0.90, 1)
quick_link_to_node: StringProperty()
default_property: StringProperty(update=process_from_socket)
default_conversion_name = ConversionPolicies.LENIENT.conversion_name
class SvMatrixSocket(NodeSocket, SvSocketCommon):
'''4x4 matrix Socket type'''
bl_idname = "SvMatrixSocket"
bl_label = "Matrix Socket"
color = (0.2, 0.8, 0.8, 1.0)
quick_link_to_node = 'SvMatrixInNodeMK4'
nesting_level: IntProperty(default=1)
def do_flatten(self, data):
return flatten_data(data, 1, data_types=(Matrix,))
def do_graft(self, data):
return graft_data(data, item_level=0, data_types=(Matrix,))
class SvVerticesSocket(SocketDomain, NodeSocket, SvSocketCommon):
'''For vertex data'''
bl_idname = "SvVerticesSocket"
bl_label ="Vertices Socket"
color = (0.9, 0.6, 0.2, 1.0)
quick_link_to_node = 'GenVectorsNode'
nesting_level: IntProperty(default=3)
def setup_parameter_node(self, param_node):
if self.use_prop or self.get_prop_name():
value = self.sv_get()[0][0]
param_node.x_ = value[0]
param_node.y_ = value[1]
param_node.z_ = value[2]
# this property is needed for back capability, after renaming prop to default_property
# should be removed after https://github.com/nortikin/sverchok/issues/3514
# using via default_property property
prop: FloatVectorProperty(default=(0, 0, 0), size=3, update=process_from_socket)
expanded: BoolProperty(default=False) # for minimizing showing socket property
def do_simplify(self, data):
return flatten_data(data, 2)
def do_flat_topology(self, data):
return flatten_data(data, 3)
@property
def default_property(self):
return self.prop
@default_property.setter
def default_property(self, value):
self.prop = value
def draw_property(self, layout, prop_origin=None, prop_name='prop'):
if prop_origin is None:
prop_origin = self
split = layout.split(factor=.2, align=True)
c1 = split.column(align=True)
c2 = split.column(align=True)
if self.expanded:
c1.prop(self, "expanded", icon='TRIA_UP', text='')
c1.label(text=self.name[0])
c2.prop(prop_origin, prop_name, text="", expand=True)
else:
c1.prop(self, "expanded", icon='TRIA_DOWN', text="")
row = c2.row(align=True)
row.template_component_menu(prop_origin, prop_name, name=self.name)
def do_graft(self, data):
return graft_data(data, item_level=1)
def draw_group_property(self, layout, text, interface_socket):
if not interface_socket.hide_value:
layout.template_component_menu(self, 'prop', name=text)
else:
layout.label(text=text)
def does_support_link_input_menu(self, context, layout, node):
ok = super().does_support_link_input_menu(context, layout, node)
if not ok:
return False
return self.name not in {'Vertices', 'Verts'}
class SvVerticesSocketInterface(bpy.types.NodeSocketInterface):
"""
This socket will be created in tree.inputs to tree.outputs collection
when normal socket will be connected to input or output group nodes
"""
# The only reason of existing this class
# is that `prop` attribute of VerticesSocket can't be renamed to `default_property
bl_idname = "SvVerticesSocketInterface"
bl_socket_idname = "SvVerticesSocket"
bl_label = "Vertices"
color = SvVerticesSocket.color
default_value: FloatVectorProperty(name="Default value", default=(0, 0, 0), size=3)
def draw_color(self, context):
return self.color
def draw(self, context, layout):
col = layout.column()
col.prop(self, 'default_value')
col.prop(self, 'hide_value')
class SvQuaternionSocket(NodeSocket, SvSocketCommon):
'''For quaternion data'''
bl_idname = "SvQuaternionSocket"
bl_label = "Quaternion Socket"
color = (0.9, 0.4, 0.7, 1.0)
default_property: FloatVectorProperty(default=(1, 0, 0, 0), size=4, subtype='QUATERNION',
update=process_from_socket)
expanded: BoolProperty(default=False) # for minimizing showing socket property
def draw_property(self, layout, prop_origin=None, prop_name='prop'):
if prop_origin is None:
prop_origin = self
split = layout.split(factor=.2, align=True)
c1 = split.column(align=True)
c2 = split.column(align=True)
if self.expanded:
c1.prop(self, "expanded", icon='TRIA_UP', text='')
c1.label(text=self.name[0])
c2.prop(prop_origin, prop_name, text="", expand=True)
else:
c1.prop(self, "expanded", icon='TRIA_DOWN', text="")
row = c2.row(align=True)
row.template_component_menu(prop_origin, prop_name, name=self.name)
def do_flatten(self, data):
return flatten_data(data, 1, data_types=(Quaternion,))
def do_graft(self, data):
return graft_data(data, item_level=0, data_types=(Quaternion,))
def draw_group_property(self, layout, text, interface_socket):
if not interface_socket.hide_value:
layout.template_component_menu(self, 'default_property', name=text)
else:
layout.label(text=text)
class SvColorSocket(SocketDomain, NodeSocket, SvSocketCommon):
'''For color data'''
bl_idname = "SvColorSocket"
bl_label = "Color Socket"
color = (0.9, 0.8, 0.0, 1.0)
default_property: FloatVectorProperty(default=(0, 0, 0, 1), size=4, subtype='COLOR', min=0, max=1,
update=process_from_socket)
expanded: BoolProperty(default=False) # for minimizing showing socket property
nesting_level: IntProperty(default=3)
def draw_property(self, layout, prop_origin=None, prop_name='default_property'):
if prop_origin is None:
prop_origin = self
split = layout.split(factor=.2, align=True)
c1 = split.column(align=True)
c2 = split.column(align=True)
if self.expanded:
c1.prop(self, "expanded", icon='TRIA_UP', text='')
c1.label(text=self.name[0])
c2.prop(prop_origin, prop_name, text="", expand=True)
else:
c1.prop(self, "expanded", icon='TRIA_DOWN', text="")
row = c2.row(align=True)
row.prop(prop_origin, prop_name)
def draw_group_property(self, layout, text, interface_socket):
if not interface_socket.hide_value:
layout.prop(self, 'default_property', text=text)
else:
layout.label(text=text)
def do_flat_topology(self, data):
return flatten_data(data, 3)
class SvDummySocket(NodeSocket, SvSocketCommon):
'''Dummy Socket for sockets awaiting assignment of type'''
bl_idname = "SvDummySocket"
bl_label = "Dummys Socket"
color = (0.8, 0.8, 0.8, 0.3)
def sv_get(self, deepcopy=False, default=[]):
if self.is_linked:
return self.links[0].bl_idname
class SvSeparatorSocket(NodeSocket, SvSocketCommon):
''' Separator Socket used to separate groups of sockets '''
bl_idname = "SvSeparatorSocket"
bl_label = "Separator Socket"
color = (0.0, 0.0, 0.0, 0.0)
def draw(self, context, layout, node, text):
# layout.label("")
layout.label(text="——————")
class SvStringsSocket(SocketDomain, NodeSocket, SvSocketCommon):
'''Generic, mostly numbers, socket type'''
bl_idname = "SvStringsSocket"
bl_label = "Strings Socket"
color = (0.6, 1.0, 0.6, 1.0)
use_graft_2: BoolProperty(
name="Graft Topology",
default=False,
update=process_from_socket)
def get_mode_flags(self):
flags = super().get_mode_flags()
if self.use_graft_2:
flags.append('G2')
return flags
def get_prop_data(self):
prop_name = self.get_prop_name()
if prop_name:
return {"prop_name": prop_name}
elif self.prop_type:
return {"prop_type": self.prop_type,
"prop_index": self.prop_index}
else:
return {}
quick_link_to_node: StringProperty() # this can be overridden by socket instances
default_property_type: bpy.props.EnumProperty( # for internal usage
description="Switch between float and int without node updating",
items=[(i, i, '') for i in ['float', 'int']])
default_float_property: bpy.props.FloatProperty(update=process_from_socket)
default_int_property: bpy.props.IntProperty(update=process_from_socket)
show_property_type: BoolProperty(
description="Add icon to switch default type")
def get_link_parameter_node(self):
if self.quick_link_to_node:
return self.quick_link_to_node
return 'SvNumberNode'
def does_support_link_input_menu(self, context, layout, node):
ok = super().does_support_link_input_menu(context, layout, node)
if not ok:
return False
return self.name not in {'Edges', 'Polygons', 'Edgs', 'Polys', 'Faces', 'EdgPol', 'Mask', 'EdgesMask', 'FaceMask'}
def setup_parameter_node(self, param_node):
if param_node.bl_idname == 'SvNumberNode':
if self.use_prop or self.get_prop_name():
value = self.sv_get()[0][0]
print("V", value)
if isinstance(value, int):
param_node.selected_mode = 'int'
param_node.int_ = value
elif isinstance(value, float):
param_node.selected_mode = 'float'
param_node.float_ = value
@property
def default_property(self):
return self.default_float_property if self.default_property_type == 'float' else self.default_int_property
@default_property.setter
def default_property(self, value):
if hasattr(self.node, 'node_tree'): # belong to group node
interface_socket = self.node.node_tree.inputs[self.index]
if interface_socket.default_type == 'float':
self.default_float_property = value
elif interface_socket.default_type == 'int':
self.default_int_property = value
else:
if self.default_property_type == 'float':
self.default_float_property = value
else:
self.default_int_property = value
def draw_property(self, layout, prop_origin=None, prop_name=None):
if prop_origin and prop_name:
layout.prop(prop_origin, prop_name)
elif self.use_prop:
row = layout.row(align=True)
if self.default_property_type == 'float':
row.prop(self, 'default_float_property', text=self.name)
elif self.default_property_type == 'int':
row.prop(self, 'default_int_property', text=self.name)
if self.show_property_type:
icon = 'IPO_LINEAR' if self.default_property_type == 'float' else 'IPO_CONSTANT'
row.operator(SvSwitchDefaultOp.bl_idname, icon=icon, text='')
def draw_menu_items(self, context, layout):
self.draw_simplify_modes(layout)
if self.can_flatten_topology():
layout.prop(self, 'use_flatten_topology')
if self.can_graft():
layout.prop(self, 'use_graft')
if not self.use_flatten:
layout.prop(self, 'use_graft_2')
if self.can_unwrap():
layout.prop(self, 'use_unwrap')
if self.can_wrap():
layout.prop(self, 'use_wrap')
def do_flat_topology(self, data):
return flatten_data(data, 3)
def do_flatten(self, data):
return flatten_data(data, 1)
def do_simplify(self, data):
return flatten_data(data, 2)
def do_graft(self, data):
return graft_data(data, item_level=0, data_types = STANDARD_TYPES)
def do_graft_2(self, data):
def to_zero_base(lst):
m = min(lst)
return [x - m for x in lst]
result = map_at_level(to_zero_base, data, item_level=1, data_types = STANDARD_TYPES)
result = graft_data(result, item_level=1, data_types = STANDARD_TYPES)
return result
def preprocess_input(self, data):
result = data
if self.use_flatten:
result = self.do_flatten(data)
elif self.use_simplify:
result = self.do_simplify(data)
if self.use_graft:
result = self.do_graft(result)
elif not self.use_flatten and self.use_graft_2:
result = self.do_graft_2(result)
if self.use_unwrap:
result = unwrap_data(result, socket=self)
if self.use_wrap:
result = wrap_data(result)
return result
def postprocess_output(self, data):
result = data
if self.use_flatten_topology:
result = self.do_flat_topology(data)
if self.use_flatten:
result = self.do_flatten(data)
elif self.use_simplify:
result = self.do_simplify(data)
if self.use_graft:
result = self.do_graft(result)
elif self.use_graft_2:
result = self.do_graft_2(result)
if self.use_unwrap:
result = unwrap_data(result, socket=self)
if self.use_wrap:
result = wrap_data(result)
return result
def draw_group_property(self, layout, text, interface_socket):
# only for input sockets group node nodes with sub trees
if not interface_socket.hide_value:
if interface_socket.default_type == 'float':
layout.prop(self, 'default_float_property', text=text)
elif interface_socket.default_type == 'int':
layout.prop(self, 'default_int_property', text=text)
else:
layout.label(text=text)
class SvStringsSocketInterface(bpy.types.NodeSocketInterface):
"""
This socket will be created in tree.inputs to tree.outputs collection
when normal socket will be connected to input or output group nodes
"""
bl_idname = "SvStringsSocketInterface"
bl_socket_idname = "SvStringsSocket"
bl_label = "Number"
color = SvStringsSocket.color
default_float_value: bpy.props.FloatProperty(name='Default value')
default_int_value: bpy.props.IntProperty(name='Default value')
default_type: bpy.props.EnumProperty(items=[(i, i, '') for i in ['float', 'int']], update=update_interface)
@property
def default_value(self):
return self.default_float_value if self.default_type == 'float' else self.default_int_value
def draw_color(self, context):
return self.color
def draw(self, context, layout):
layout.prop(self, 'hide_value')
layout.prop(self, 'default_type', expand=True)
if self.default_type == 'float':
layout.prop(self, 'default_float_value')
elif self.default_type == 'int':
layout.prop(self, 'default_int_value')
class SvFilePathSocket(NodeSocket, SvSocketCommon):
'''For file path data'''
bl_idname = "SvFilePathSocket"
bl_label = "File Path Socket"
color = (0.9, 0.9, 0.3, 1.0)
quick_link_to_node = 'SvFilePathNode'
class SvSvgSocket(NodeSocket, SvSocketCommon):
'''For file path data'''
bl_idname = "SvSvgSocket"
bl_label = "SVG Data Socket"
color = (0.1, 0.5, 1, 1.0)
@property
def quick_link_to_node(self):
if "Fill / Stroke" in self.name:
return "SvSvgFillStrokeNodeMk2"
if "Pattern" in self.name:
return "SvSvgPatternNode"
return
class SvPulgaForceSocket(NodeSocket, SvSocketCommon):
'''For Pulga forces data'''
bl_idname = "SvPulgaForceSocket"
bl_label = "Pulga Force Socket"
color = (0.4, 0.3, 0.6, 1.0)
class SvLoopControlSocket(NodeSocket, SvSocketCommon):
'''For loop in-loop out node pair'''
bl_idname = "SvLoopControlSocket"
bl_label = "Loop Control Socket"
color = (0.1, 0.1, 0.1, 1.0)
quick_link_to_node = 'SvLoopInNode'
class SvDictionarySocket(NodeSocket, SvSocketCommon):
'''For dictionary data'''
bl_idname = "SvDictionarySocket"
bl_label = "Dictionary Socket"
color = (1.0, 1.0, 1.0, 1.0)
quick_link_to_node = 'SvDictionaryIn'
def do_flatten(self, data):
return flatten_data(data, 1, data_types=(dict,))
def do_simplify(self, data):
return flatten_data(data, 2, data_types=(dict,))
class SvChameleonSocket(NodeSocket, SvSocketCommon):
'''Using as input socket with color of other connected socket'''
bl_idname = "SvChameleonSocket"
bl_label = "Chameleon Socket"
color: FloatVectorProperty(default=(0.0, 0.0, 0.0, 0.0), size=4,
description="For storing color of other socket via catch_props method")
dynamic_type: StringProperty(default='SvChameleonSocket',
description="For storing type of other socket via catch_props method")
def catch_props(self):
# should be called during update event of a node for catching its property
other = self.other
if other:
self.color = other.color
self.dynamic_type = other.bl_idname
else:
self.color = (0.0, 0.0, 0.0, 0.0)
self.dynamic_type = self.bl_idname
default_conversion_name = ConversionPolicies.LENIENT.conversion_name
class SvSurfaceSocket(NodeSocket, SvSocketCommon):
bl_idname = "SvSurfaceSocket"
bl_label = "Surface Socket"
color = (0.4, 0.2, 1.0, 1.0)
def do_flatten(self, data):
return flatten_data(data, 1, data_types=(SvSurface,))
def do_graft(self, data):
return graft_data(data, item_level=0, data_types=(SvSurface,))
class SvCurveSocket(NodeSocket, SvSocketCommon):
bl_idname = "SvCurveSocket"
bl_label = "Curve Socket"
color = (0.5, 0.6, 1.0, 1.0)
reparametrize: BoolProperty(
name = "Reparametrize",
default = False,
update = process_from_socket)
def get_mode_flags(self):
flags = super().get_mode_flags()
if self.reparametrize:
flags.append('R')
return flags
def draw_menu_items(self, context, layout):
super().draw_menu_items(context, layout)
layout.prop(self, 'reparametrize')
def do_flatten(self, data):
return flatten_data(data, 1, data_types=(SvCurve,))
def do_graft(self, data):
return graft_data(data, item_level=0, data_types=(SvCurve,))
def preprocess_input(self, data):
data = SvSocketCommon.preprocess_input(self, data)
if self.reparametrize:
data = map_at_level(reparametrize_curve, data, data_types=(SvCurve,))
return data
def postprocess_output(self, data):
data = SvSocketCommon.postprocess_output(self, data)
if self.reparametrize:
data = map_at_level(reparametrize_curve, data, data_types=(SvCurve,))
return data
class SvScalarFieldSocket(NodeSocket, SvSocketCommon):
bl_idname = "SvScalarFieldSocket"
bl_label = "Scalar Field Socket"
quick_link_to_node = 'SvNumberNode'
color = (0.9, 0.4, 0.1, 1.0)
default_conversion_name = ConversionPolicies.FIELD.conversion_name
def do_flatten(self, data):
return flatten_data(data, 1, data_types=(SvScalarField,))
def do_graft(self, data):
return graft_data(data, item_level=0, data_types=(SvScalarField,))
class SvVectorFieldSocket(NodeSocket, SvSocketCommon):
bl_idname = "SvVectorFieldSocket"
bl_label = "Vector Field Socket"
quick_link_to_node = 'GenVectorsNode'
color = (0.1, 0.1, 0.9, 1.0)
default_conversion_name = ConversionPolicies.FIELD.conversion_name
def do_flatten(self, data):
return flatten_data(data, 1, data_types=(SvVectorField,))
def do_graft(self, data):
return graft_data(data, item_level=0, data_types=(SvVectorField,))
class SvSolidSocket(NodeSocket, SvSocketCommon):
bl_idname = "SvSolidSocket"
bl_label = "Solid Socket"
color = (0.0, 0.65, 0.3, 1.0)
default_conversion_name = ConversionPolicies.SOLID.conversion_name
def do_flatten(self, data):
from sverchok.dependencies import FreeCAD
import Part
return flatten_data(data, 1, data_types=(Part.Shape,))
def do_graft(self, data):
from sverchok.dependencies import FreeCAD
import Part
return graft_data(data, item_level=0, data_types=(Part.Shape,))
class SvCollectionSocket(NodeSocket, SvSocketCommon):
bl_idname = "SvCollectionSocket"
bl_label = "Collection Socket"
color = (0.96, 0.96, 0.96, 1.0)
default_property: PointerProperty(
name="Collection",
type=bpy.types.Collection,
update=process_from_socket)
class SvMaterialSocket(NodeSocket, SvSocketCommon):
bl_idname = "SvMaterialSocket"
bl_label = "Material Socket"
color = (0.92, 0.46, 0.51, 1.0)
default_property: PointerProperty(
name="Material",
type=bpy.types.Material,
update=process_from_socket)
class SvTextureSocket(NodeSocket, SvSocketCommon):
bl_idname = "SvTextureSocket"
bl_label = "Texture Socket"
color = (0.62, 0.31, 0.64, 1.0)
default_property: PointerProperty(
name="Texture",
type=bpy.types.Texture,
update=process_from_socket)
class SvImageSocket(NodeSocket, SvSocketCommon):
bl_idname = "SvImageSocket"
bl_label = "Image Socket"
color = (0.39, 0.22, 0.39, 1.0)
default_property: PointerProperty(
name="Image",
type=bpy.types.Image,
update=process_from_socket)
class SvLinkNewNodeInput(bpy.types.Operator):
''' Spawn and link new node to the left of the caller node'''
bl_idname = "node.sv_quicklink_new_node_input"
bl_label = "Add a new node to the left"
@classmethod
def poll(cls, context):
return hasattr(context, 'socket')
def execute(self, context):
tree, node, socket = context.node.id_data, context.node, context.socket
new_node = tree.nodes.new(socket.quick_link_to_node)
links_number = len([s for s in node.inputs if s.is_linked])
new_node.location = (node.location[0] - 200, node.location[1] - 100 * links_number)
tree.links.new(new_node.outputs[0], socket)
if node.parent:
new_node.parent = node.parent
new_node.location = new_node.absolute_location
new_node.process_node(context)
return {'FINISHED'}
class SvSocketHelpOp(bpy.types.Operator):
bl_idname = "node.sv_socket_show_help"
bl_label = "Socket description"
bl_options = {'INTERNAL', 'REGISTER'}
text : StringProperty()
@classmethod
def description(cls, context, properties):
return properties.text
def execute(self, context):
def draw(menu, context):
col = menu.layout.column(align=True)
for line in self.text.split('\n'):
col.label(text=line)
bpy.context.window_manager.popup_menu(draw, title="Socket description", icon='QUESTION')
return {'FINISHED'}
class SvInputLinkMenuOp(bpy.types.Operator):
"Opens a menu"
bl_idname = "node.sv_input_link_menu_popup"
bl_label = "Link to existing parameter or add a new one"
bl_options = {'INTERNAL', 'REGISTER'}
bl_property = "option"
def get_items(self, context):
tree = context.space_data.node_tree
node = tree.nodes[self.node_name]
socket = node.inputs[self.input_name]
items = []
link_param_node = socket.get_link_parameter_node()
i = 0
if link_param_node:
items.append(
('__SV_PARAM_CREATE__', "Create new parameter", "Create new parameter node", i)
)
i += 1
items.append(
('__SV_WIFI_CREATE__', "Create new parameter via WiFi", "Create new parameter node and link it via WiFi pair", 1)
)
i += 1
for name, other_node in tree.nodes.items():
if other_node.bl_idname == link_param_node:
item = ('PARAM_' + other_node.name, f"Link to parameter: {other_node.label or other_node.name}", "Link to existing input node", i)
items.append(item)
i += 1
for name, other_node in tree.nodes.items():
if other_node.bl_idname == 'WifiInNode':
for input_idx, wifi_input in enumerate(other_node.inputs):
linked = get_other_socket(wifi_input)
if linked is None:
continue
if linked.bl_idname != socket.bl_idname:
continue
item = (f"WIFI_{input_idx}_{other_node.var_name}", f"Link to WiFi: {other_node.label or other_node.name} - {other_node.var_name}[{input_idx}]", "Link to existing WiFi input node", i)
items.append(item)
i += 1
# In the node class, it is possible to define
# additional menu entries by specifying `link_menu_handler`
# property of the socket. It should be name of a class with
# two classmethods: get_items() and on_selected():
#
# class MyNode(...):
# class MenuHandler:
# @classmethod
# def get_items(cls, context):
# return [('MY_ENTRY', "My entry", "My entry description")]
#
# @classmethod
# def on_selected(cls, tree, node, item, context):
# if item == 'MY_ENTRY':
# print("Hello world!")
#
# def sv_init(self):
# self.inputs.new('SvVerticesSocket', 'Vertices').link_menu_handler = 'MenuHandler'
#
handler_name = socket.link_menu_handler
if handler_name:
handler = getattr(node, handler_name)
for id, title, description in handler.get_items(socket, context):
items.append((id, title, description, i))
i += 1
return items
option : EnumProperty(name = "Action", description = "Action to be executed", items = get_items)
tree_name : StringProperty()
node_name : StringProperty()
input_name : StringProperty()
def execute(self, context):
tree = bpy.data.node_groups[self.tree_name]
node = tree.nodes[self.node_name]
socket = node.inputs[self.input_name]
def is_linked(node1, node2):
for link in tree.links:
if link.from_node == node1 and link.to_node == node2:
return True
return False
if self.option == '__SV_PARAM_CREATE__':
new_node = tree.nodes.new(socket.get_link_parameter_node())
new_node.label = socket.label or socket.name
socket.setup_parameter_node(new_node)
links_number = len([s for s in node.inputs if s.is_linked])
new_node.location = (node.location[0] - 200, node.location[1] - 100 * links_number)
tree.links.new(new_node.outputs[0], socket)
if node.parent:
new_node.parent = node.parent
new_node.location = new_node.absolute_location
new_node.process_node(context)
elif self.option == '__SV_WIFI_CREATE__':
label = socket.label or socket.name
param_node = tree.nodes.new(socket.get_link_parameter_node())
param_node.label = label
wifi_in_node = tree.nodes.new('WifiInNode')
wifi_in_node.label = f"WiFi In - {label}"
wifi_in_node.gen_var_name()
wifi_var = wifi_in_node.var_name
wifi_out_node = tree.nodes.new('WifiOutNode')
wifi_out_node.label = f"WiFi Out - {label}"
wifi_out_node.var_name = wifi_var
socket.setup_parameter_node(param_node)
tree.links.new(param_node.outputs[0], wifi_in_node.inputs[0])
tree.links.new(wifi_out_node.outputs[0], socket)
setup_new_node_location(wifi_out_node, node)
setup_new_node_location(wifi_in_node, wifi_out_node)
setup_new_node_location(param_node, wifi_in_node)
param_node.process_node(context)
elif self.option.startswith('PARAM_'):
input_name = self.option[6:]
param_node = tree.nodes[input_name]
tree.links.new(param_node.outputs[0], socket)
elif self.option.startswith('WIFI_'):
prefix, socket_idx, wifi_var = self.option.split('_', maxsplit=2)
socket_idx = int(socket_idx)
found_existing = False
for name, wifi_node in tree.nodes.items():
if wifi_node.bl_idname == 'WifiOutNode' and is_linked(wifi_node, node):
if wifi_node.var_name == wifi_var:
tree.links.new(wifi_node.outputs[socket_idx], socket)
found_existing = True
break
if not found_existing:
new_node = tree.nodes.new('WifiOutNode')
new_node.var_name = wifi_var
new_node.set_var_name()
links_number = len([s for s in node.inputs if s.is_linked])
new_node.location = (node.location[0] - 200, node.location[1] - 100 * links_number)
tree.links.new(new_node.outputs[socket_idx], socket)
if node.parent:
new_node.parent = node.parent
new_node.location = new_node.absolute_location
new_node.process_node(context)
elif socket.link_menu_handler:
handler = getattr(node, socket.link_menu_handler)
handler.on_selected(tree, node, socket, self.option, context)
return {'FINISHED'}
def invoke(self, context, event):
context.space_data.cursor_location_from_region(event.mouse_region_x, event.mouse_region_y)
wm = context.window_manager
wm.invoke_search_popup(self)
return {'FINISHED'}
class SvSwitchDefaultOp(bpy.types.Operator):
"""Either Float or Integer"""
bl_idname = "node.sv_switch_default"
bl_label = "Switch default value of string socket"
bl_options = {'INTERNAL', 'REGISTER'}
@classmethod
def poll(cls, context):
return hasattr(context, 'socket')
def execute(self, context):
s = context.socket
s.default_property_type = 'float' if s.default_property_type == 'int' else 'int'
process_from_socket(s, context)
return {'FINISHED'}
classes = [
SV_MT_SocketOptionsMenu, SV_MT_AllSocketsOptionsMenu,
SvVerticesSocket, SvMatrixSocket, SvStringsSocket, SvFilePathSocket,
SvColorSocket, SvQuaternionSocket, SvDummySocket, SvSeparatorSocket,
SvTextSocket, SvObjectSocket, SvDictionarySocket, SvChameleonSocket,
SvSurfaceSocket, SvCurveSocket, SvScalarFieldSocket, SvVectorFieldSocket,
SvSolidSocket, SvSvgSocket, SvPulgaForceSocket, SvFormulaSocket,
SvLoopControlSocket, SvLinkNewNodeInput,
SvStringsSocketInterface, SvVerticesSocketInterface,
SvCollectionSocket,
SvMaterialSocket,
SvTextureSocket,
SvImageSocket,
SvSocketHelpOp, SvInputLinkMenuOp,
SvSwitchDefaultOp,
]
def socket_interface_classes():
"""
All sockets should have their twins - SocketInterface
Tis function generate SocketInterface classes for Sockets for which interface sockets was not coded manually
This function assume to find all socket and interface classes in classes variable of the current module
If socket class has default property interface will also have this property named `default value`
This value will be used for setting it to `default property` during connecting group tree to group node
Also interface will get `show property` attribute which should hide property from group node
Socket itself should track status of this property
"""
sockets = {cls for cls in classes if hasattr(cls, 'links')} # best test for now
with_interface_sockets = {globals()[cls.bl_socket_idname] for cls in classes if hasattr(cls, 'bl_socket_idname')}
for socket_cls in sockets - with_interface_sockets:
socket_interface_attributes = {
'bl_idname': f'{socket_cls.__name__}Interface',
'bl_socket_idname': socket_cls.__name__,
'bl_label': socket_cls.bl_label,
'color': socket_cls.color,
'draw_color': lambda self, context: self.color
}
if 'default_property' in socket_cls.__annotations__:
prop_func, prop_args = get_func_and_args(socket_cls.__annotations__['default_property'])
prop_args = {k: prop_args[k] for k in prop_args if k not in {'update', 'name'}}
prop_args['name'] = "Default value"
prop_args['update'] = lambda s, c: s.id_data.update_sockets()
socket_interface_attributes['__annotations__'] = {}
socket_interface_attributes['__annotations__']['default_value'] = socket_cls.__annotations__['default_property']
def draw(self, context, layout):
col = layout.column()
col.prop(self, 'default_value')
col.prop(self, 'hide_value')
else:
def draw(self, context, layout):
pass
socket_interface_attributes['draw'] = draw
yield type(
f'{socket_cls.__name__}Interface', (bpy.types.NodeSocketInterface,), socket_interface_attributes)
register, unregister = bpy.utils.register_classes_factory(classes + list(socket_interface_classes()))
Functions
def process_from_socket(self, context)
-
Update function of exposed properties in Sockets
Expand source code
def process_from_socket(self, context): """Update function of exposed properties in Sockets""" if self.node is not None: # https://developer.blender.org/T88587 self.node.process_node(context)
def socket_interface_classes()
-
All sockets should have their twins - SocketInterface Tis function generate SocketInterface classes for Sockets for which interface sockets was not coded manually This function assume to find all socket and interface classes in classes variable of the current module
If socket class has default property interface will also have this property named
default value
This value will be used for setting it todefault property
during connecting group tree to group node Also interface will getshow property
attribute which should hide property from group node Socket itself should track status of this propertyExpand source code
def socket_interface_classes(): """ All sockets should have their twins - SocketInterface Tis function generate SocketInterface classes for Sockets for which interface sockets was not coded manually This function assume to find all socket and interface classes in classes variable of the current module If socket class has default property interface will also have this property named `default value` This value will be used for setting it to `default property` during connecting group tree to group node Also interface will get `show property` attribute which should hide property from group node Socket itself should track status of this property """ sockets = {cls for cls in classes if hasattr(cls, 'links')} # best test for now with_interface_sockets = {globals()[cls.bl_socket_idname] for cls in classes if hasattr(cls, 'bl_socket_idname')} for socket_cls in sockets - with_interface_sockets: socket_interface_attributes = { 'bl_idname': f'{socket_cls.__name__}Interface', 'bl_socket_idname': socket_cls.__name__, 'bl_label': socket_cls.bl_label, 'color': socket_cls.color, 'draw_color': lambda self, context: self.color } if 'default_property' in socket_cls.__annotations__: prop_func, prop_args = get_func_and_args(socket_cls.__annotations__['default_property']) prop_args = {k: prop_args[k] for k in prop_args if k not in {'update', 'name'}} prop_args['name'] = "Default value" prop_args['update'] = lambda s, c: s.id_data.update_sockets() socket_interface_attributes['__annotations__'] = {} socket_interface_attributes['__annotations__']['default_value'] = socket_cls.__annotations__['default_property'] def draw(self, context, layout): col = layout.column() col.prop(self, 'default_value') col.prop(self, 'hide_value') else: def draw(self, context, layout): pass socket_interface_attributes['draw'] = draw yield type( f'{socket_cls.__name__}Interface', (bpy.types.NodeSocketInterface,), socket_interface_attributes)
def socket_type_names() ‑> Set[str]
-
Expand source code
def socket_type_names() -> Set[str]: names = set() for name, member in inspect.getmembers(sys.modules[__name__]): is_module_cls = inspect.isclass(member) and member.__module__ == __name__ if is_module_cls: if NodeSocket in member.__bases__: names.add(member.bl_idname) return names
def update_interface(self, context)
-
Update group node sockets and update it
Expand source code
def update_interface(self, context): """Update group node sockets and update it""" # For now I don't think that `hide value` property should call this function, but in some cases it could be useful # if interface socket will get min and max value parameter then probably Sv sockets also should get it if not self.id_data.group_node_name: # initialization tree return self.id_data.update_sockets() group_tree = self.id_data group_node = group_tree.get_update_path()[-1] input_node = group_node.active_input() if input_node: group_tree.update_nodes([input_node])
Classes
class SV_MT_AllSocketsOptionsMenu (...)
-
Expand source code
class SV_MT_AllSocketsOptionsMenu(bpy.types.Menu): bl_label = "Sockets Options" @classmethod def poll(cls, context): return hasattr(context, 'node')# and hasattr(context, 'socket') def draw(self, context): node = context.active_node if not node: return layout = self.layout for s in node.outputs: if hasattr(s, 'draw_menu_items'): layout.context_pointer_set("socket", s) layout.context_pointer_set("node", node) layout.menu('SV_MT_SocketOptionsMenu', text=s.name)
Ancestors
- bpy_types.Menu
- builtins.bpy_struct
- bpy_types._GenericUI
Class variables
var bl_label
var bl_rna
Static methods
def poll(context)
-
Expand source code
@classmethod def poll(cls, context): return hasattr(context, 'node')# and hasattr(context, 'socket')
Methods
def draw(self, context)
-
Expand source code
def draw(self, context): node = context.active_node if not node: return layout = self.layout for s in node.outputs: if hasattr(s, 'draw_menu_items'): layout.context_pointer_set("socket", s) layout.context_pointer_set("node", node) layout.menu('SV_MT_SocketOptionsMenu', text=s.name)
class SV_MT_SocketOptionsMenu (...)
-
Expand source code
class SV_MT_SocketOptionsMenu(bpy.types.Menu): bl_label = "Socket Options" def draw(self, context): node = context.node if not node: return layout = self.layout if hasattr(context.socket, 'draw_menu_items'): context.socket.draw_menu_items(context, layout)
Ancestors
- bpy_types.Menu
- builtins.bpy_struct
- bpy_types._GenericUI
Class variables
var bl_label
var bl_rna
Methods
def draw(self, context)
-
Expand source code
def draw(self, context): node = context.node if not node: return layout = self.layout if hasattr(context.socket, 'draw_menu_items'): context.socket.draw_menu_items(context, layout)
class SocketDomain
-
Socket mix-in class to define domain options The option is shown when socket is connected and can be used for transferring data to certain elements of an object.
Expand source code
class SocketDomain: """Socket mix-in class to define domain options The option is shown when socket is connected and can be used for transferring data to certain elements of an object.""" domain: EnumProperty(items=[(d.name, d.value, '') for d in BlDomains], update=process_from_socket) show_domain: BoolProperty()
Subclasses
Class variables
var domain : <_PropertyDeferred,
, {'items': [('POINT', 'Point', ''), ('EDGE', 'Edge', ''), ('FACE', 'Face', ''), ('CORNER', 'Face Corner', '')], 'update': process_from_socket() at 0x7f2f1d910e50>, 'attr': 'domain'}> var show_domain : <_PropertyDeferred,
, {'attr': 'show_domain'}>
class SvChameleonSocket (...)
-
Using as input socket with color of other connected socket
Expand source code
class SvChameleonSocket(NodeSocket, SvSocketCommon): '''Using as input socket with color of other connected socket''' bl_idname = "SvChameleonSocket" bl_label = "Chameleon Socket" color: FloatVectorProperty(default=(0.0, 0.0, 0.0, 0.0), size=4, description="For storing color of other socket via catch_props method") dynamic_type: StringProperty(default='SvChameleonSocket', description="For storing type of other socket via catch_props method") def catch_props(self): # should be called during update event of a node for catching its property other = self.other if other: self.color = other.color self.dynamic_type = other.bl_idname else: self.color = (0.0, 0.0, 0.0, 0.0) self.dynamic_type = self.bl_idname default_conversion_name = ConversionPolicies.LENIENT.conversion_name
Ancestors
- bpy_types.NodeSocket
- builtins.bpy_struct
- SvSocketCommon
- SvSocketProcessing
Class variables
var bl_idname
var bl_label
var bl_rna
var color : <_PropertyDeferred,
, {'default': (0.0, 0.0, 0.0, 0.0), 'size': 4, 'description': 'For storing color of other socket via catch_props method', 'attr': 'color'}> var default_conversion_name
var dynamic_type : <_PropertyDeferred,
, {'default': 'SvChameleonSocket', 'description': 'For storing type of other socket via catch_props method', 'attr': 'dynamic_type'}>
Methods
def catch_props(self)
-
Expand source code
def catch_props(self): # should be called during update event of a node for catching its property other = self.other if other: self.color = other.color self.dynamic_type = other.bl_idname else: self.color = (0.0, 0.0, 0.0, 0.0) self.dynamic_type = self.bl_idname
Inherited members
class SvCollectionSocket (...)
-
Base class for all Sockets
'SKIP_SAVE' in properties means skipping them during saving in JSON format some of the properties can be skipped because they are static, they are always set only in sv_init method
Expand source code
class SvCollectionSocket(NodeSocket, SvSocketCommon): bl_idname = "SvCollectionSocket" bl_label = "Collection Socket" color = (0.96, 0.96, 0.96, 1.0) default_property: PointerProperty( name="Collection", type=bpy.types.Collection, update=process_from_socket)
Ancestors
- bpy_types.NodeSocket
- builtins.bpy_struct
- SvSocketCommon
- SvSocketProcessing
Class variables
var bl_idname
var bl_label
var bl_rna
var color
var default_property : <_PropertyDeferred,
, {'name': 'Collection', 'type': , 'update': process_from_socket() at 0x7f2f1d910e50>, 'attr': 'default_value'}>
Inherited members
class SvColorSocket (...)
-
For color data
Expand source code
class SvColorSocket(SocketDomain, NodeSocket, SvSocketCommon): '''For color data''' bl_idname = "SvColorSocket" bl_label = "Color Socket" color = (0.9, 0.8, 0.0, 1.0) default_property: FloatVectorProperty(default=(0, 0, 0, 1), size=4, subtype='COLOR', min=0, max=1, update=process_from_socket) expanded: BoolProperty(default=False) # for minimizing showing socket property nesting_level: IntProperty(default=3) def draw_property(self, layout, prop_origin=None, prop_name='default_property'): if prop_origin is None: prop_origin = self split = layout.split(factor=.2, align=True) c1 = split.column(align=True) c2 = split.column(align=True) if self.expanded: c1.prop(self, "expanded", icon='TRIA_UP', text='') c1.label(text=self.name[0]) c2.prop(prop_origin, prop_name, text="", expand=True) else: c1.prop(self, "expanded", icon='TRIA_DOWN', text="") row = c2.row(align=True) row.prop(prop_origin, prop_name) def draw_group_property(self, layout, text, interface_socket): if not interface_socket.hide_value: layout.prop(self, 'default_property', text=text) else: layout.label(text=text) def do_flat_topology(self, data): return flatten_data(data, 3)
Ancestors
- SocketDomain
- bpy_types.NodeSocket
- builtins.bpy_struct
- SvSocketCommon
- SvSocketProcessing
Class variables
var bl_idname
var bl_label
var bl_rna
var color
var default_property : <_PropertyDeferred,
, {'default': (0, 0, 0, 1), 'size': 4, 'subtype': 'COLOR', 'min': 0, 'max': 1, 'update': process_from_socket() at 0x7f2f1d910e50>, 'attr': 'default_value'}> var expanded : <_PropertyDeferred,
, {'default': False, 'attr': 'expanded'}> var nesting_level : <_PropertyDeferred,
, {'default': 3, 'attr': 'nesting_level'}>
Methods
def do_flat_topology(self, data)
-
Expand source code
def do_flat_topology(self, data): return flatten_data(data, 3)
def draw_group_property(self, layout, text, interface_socket)
-
Expand source code
def draw_group_property(self, layout, text, interface_socket): if not interface_socket.hide_value: layout.prop(self, 'default_property', text=text) else: layout.label(text=text)
Inherited members
class SvCurveSocket (...)
-
Base class for all Sockets
'SKIP_SAVE' in properties means skipping them during saving in JSON format some of the properties can be skipped because they are static, they are always set only in sv_init method
Expand source code
class SvCurveSocket(NodeSocket, SvSocketCommon): bl_idname = "SvCurveSocket" bl_label = "Curve Socket" color = (0.5, 0.6, 1.0, 1.0) reparametrize: BoolProperty( name = "Reparametrize", default = False, update = process_from_socket) def get_mode_flags(self): flags = super().get_mode_flags() if self.reparametrize: flags.append('R') return flags def draw_menu_items(self, context, layout): super().draw_menu_items(context, layout) layout.prop(self, 'reparametrize') def do_flatten(self, data): return flatten_data(data, 1, data_types=(SvCurve,)) def do_graft(self, data): return graft_data(data, item_level=0, data_types=(SvCurve,)) def preprocess_input(self, data): data = SvSocketCommon.preprocess_input(self, data) if self.reparametrize: data = map_at_level(reparametrize_curve, data, data_types=(SvCurve,)) return data def postprocess_output(self, data): data = SvSocketCommon.postprocess_output(self, data) if self.reparametrize: data = map_at_level(reparametrize_curve, data, data_types=(SvCurve,)) return data
Ancestors
- bpy_types.NodeSocket
- builtins.bpy_struct
- SvSocketCommon
- SvSocketProcessing
Class variables
var bl_idname
var bl_label
var bl_rna
var color
var reparametrize : <_PropertyDeferred,
, {'name': 'Reparametrize', 'default': False, 'update': process_from_socket() at 0x7f2f1d910e50>, 'attr': 'reparametrize'}>
Methods
def do_flatten(self, data)
-
Expand source code
def do_flatten(self, data): return flatten_data(data, 1, data_types=(SvCurve,))
def do_graft(self, data)
-
Expand source code
def do_graft(self, data): return graft_data(data, item_level=0, data_types=(SvCurve,))
-
Expand source code
def draw_menu_items(self, context, layout): super().draw_menu_items(context, layout) layout.prop(self, 'reparametrize')
def get_mode_flags(self)
-
Expand source code
def get_mode_flags(self): flags = super().get_mode_flags() if self.reparametrize: flags.append('R') return flags
def postprocess_output(self, data)
-
Expand source code
def postprocess_output(self, data): data = SvSocketCommon.postprocess_output(self, data) if self.reparametrize: data = map_at_level(reparametrize_curve, data, data_types=(SvCurve,)) return data
def preprocess_input(self, data)
-
Expand source code
def preprocess_input(self, data): data = SvSocketCommon.preprocess_input(self, data) if self.reparametrize: data = map_at_level(reparametrize_curve, data, data_types=(SvCurve,)) return data
Inherited members
class SvDictionarySocket (...)
-
For dictionary data
Expand source code
class SvDictionarySocket(NodeSocket, SvSocketCommon): '''For dictionary data''' bl_idname = "SvDictionarySocket" bl_label = "Dictionary Socket" color = (1.0, 1.0, 1.0, 1.0) quick_link_to_node = 'SvDictionaryIn' def do_flatten(self, data): return flatten_data(data, 1, data_types=(dict,)) def do_simplify(self, data): return flatten_data(data, 2, data_types=(dict,))
Ancestors
- bpy_types.NodeSocket
- builtins.bpy_struct
- SvSocketCommon
- SvSocketProcessing
Class variables
var bl_idname
var bl_label
var bl_rna
var color
var custom_draw : <_PropertyDeferred,
, {'description': 'For name of method which will draw socket UI (optionally)', 'attr': 'custom_draw'}> var default_mode : <_PropertyDeferred,
, {'items': [('NONE', 'NONE', '', 0), ('EMPTY_LIST', 'EMPTY_LIST', '', 1), ('MATRIX', 'MATRIX', '', 2), ('MASK', 'MASK', '', 3)], 'default': 'EMPTY_LIST', 'attr': 'default_mode'}> var description : <_PropertyDeferred,
, {'attr': 'description'}> var is_mandatory : <_PropertyDeferred,
, {'default': False, 'attr': 'is_mandatory'}> var label : <_PropertyDeferred,
, {'attr': 'label'}> var nesting_level : <_PropertyDeferred,
, {'default': 2, 'attr': 'nesting_level'}> var objects_number : <_PropertyDeferred,
, {'min': 0, 'options': {'SKIP_SAVE'}, 'attr': 'objects_number'}> var pre_processing : <_PropertyDeferred,
, {'items': [('NONE', 'NONE', '', 0), ('ONE_ITEM', 'ONE_ITEM', '', 1)], 'default': 'NONE', 'attr': 'pre_processing'}> var prop_name : <_PropertyDeferred,
, {'default': '', 'description': 'For displaying node property in socket UI', 'attr': 'prop_name'}> var quick_link_to_node
var s_id : <_PropertyDeferred,
, {'options': {'SKIP_SAVE'}, 'attr': 's_id'}> var use_prop : <_PropertyDeferred,
, {'default': False, 'attr': 'use_prop'}>
Methods
def do_flatten(self, data)
-
Expand source code
def do_flatten(self, data): return flatten_data(data, 1, data_types=(dict,))
def do_simplify(self, data)
-
Expand source code
def do_simplify(self, data): return flatten_data(data, 2, data_types=(dict,))
Inherited members
class SvDummySocket (...)
-
Dummy Socket for sockets awaiting assignment of type
Expand source code
class SvDummySocket(NodeSocket, SvSocketCommon): '''Dummy Socket for sockets awaiting assignment of type''' bl_idname = "SvDummySocket" bl_label = "Dummys Socket" color = (0.8, 0.8, 0.8, 0.3) def sv_get(self, deepcopy=False, default=[]): if self.is_linked: return self.links[0].bl_idname
Ancestors
- bpy_types.NodeSocket
- builtins.bpy_struct
- SvSocketCommon
- SvSocketProcessing
Class variables
var bl_idname
var bl_label
var bl_rna
var color
var custom_draw : <_PropertyDeferred,
, {'description': 'For name of method which will draw socket UI (optionally)', 'attr': 'custom_draw'}> var default_mode : <_PropertyDeferred,
, {'items': [('NONE', 'NONE', '', 0), ('EMPTY_LIST', 'EMPTY_LIST', '', 1), ('MATRIX', 'MATRIX', '', 2), ('MASK', 'MASK', '', 3)], 'default': 'EMPTY_LIST', 'attr': 'default_mode'}> var description : <_PropertyDeferred,
, {'attr': 'description'}> var is_mandatory : <_PropertyDeferred,
, {'default': False, 'attr': 'is_mandatory'}> var label : <_PropertyDeferred,
, {'attr': 'label'}> var nesting_level : <_PropertyDeferred,
, {'default': 2, 'attr': 'nesting_level'}> var objects_number : <_PropertyDeferred,
, {'min': 0, 'options': {'SKIP_SAVE'}, 'attr': 'objects_number'}> var pre_processing : <_PropertyDeferred,
, {'items': [('NONE', 'NONE', '', 0), ('ONE_ITEM', 'ONE_ITEM', '', 1)], 'default': 'NONE', 'attr': 'pre_processing'}> var prop_name : <_PropertyDeferred,
, {'default': '', 'description': 'For displaying node property in socket UI', 'attr': 'prop_name'}> var s_id : <_PropertyDeferred,
, {'options': {'SKIP_SAVE'}, 'attr': 's_id'}> var use_prop : <_PropertyDeferred,
, {'default': False, 'attr': 'use_prop'}>
Inherited members
class SvFilePathSocket (...)
-
For file path data
Expand source code
class SvFilePathSocket(NodeSocket, SvSocketCommon): '''For file path data''' bl_idname = "SvFilePathSocket" bl_label = "File Path Socket" color = (0.9, 0.9, 0.3, 1.0) quick_link_to_node = 'SvFilePathNode'
Ancestors
- bpy_types.NodeSocket
- builtins.bpy_struct
- SvSocketCommon
- SvSocketProcessing
Class variables
var bl_idname
var bl_label
var bl_rna
var color
var custom_draw : <_PropertyDeferred,
, {'description': 'For name of method which will draw socket UI (optionally)', 'attr': 'custom_draw'}> var default_mode : <_PropertyDeferred,
, {'items': [('NONE', 'NONE', '', 0), ('EMPTY_LIST', 'EMPTY_LIST', '', 1), ('MATRIX', 'MATRIX', '', 2), ('MASK', 'MASK', '', 3)], 'default': 'EMPTY_LIST', 'attr': 'default_mode'}> var description : <_PropertyDeferred,
, {'attr': 'description'}> var is_mandatory : <_PropertyDeferred,
, {'default': False, 'attr': 'is_mandatory'}> var label : <_PropertyDeferred,
, {'attr': 'label'}> var nesting_level : <_PropertyDeferred,
, {'default': 2, 'attr': 'nesting_level'}> var objects_number : <_PropertyDeferred,
, {'min': 0, 'options': {'SKIP_SAVE'}, 'attr': 'objects_number'}> var pre_processing : <_PropertyDeferred,
, {'items': [('NONE', 'NONE', '', 0), ('ONE_ITEM', 'ONE_ITEM', '', 1)], 'default': 'NONE', 'attr': 'pre_processing'}> var prop_name : <_PropertyDeferred,
, {'default': '', 'description': 'For displaying node property in socket UI', 'attr': 'prop_name'}> var quick_link_to_node
var s_id : <_PropertyDeferred,
, {'options': {'SKIP_SAVE'}, 'attr': 's_id'}> var use_prop : <_PropertyDeferred,
, {'default': False, 'attr': 'use_prop'}>
Inherited members
class SvFormulaSocket (...)
-
Base class for all Sockets
'SKIP_SAVE' in properties means skipping them during saving in JSON format some of the properties can be skipped because they are static, they are always set only in sv_init method
Expand source code
class SvFormulaSocket(NodeSocket, SvSocketCommon): bl_idname = "SvFormulaSocket" bl_label = "Formula Socket" color = (0.68, 0.85, 0.90, 1) depth: IntProperty( description="Depth exposed to the formula", update=process_from_socket, default=1, min=1) def update_depth(self, context): if self.transform == 'Vector' and self.depth < 2: self.depth = 2 else: process_from_socket(self, context) transform: EnumProperty( description='Transform before exposing to the formula', items=enum_item_4(['As is', 'Vector', 'Array', 'Set', 'String']), update=update_depth) default_conversion_name = ConversionPolicies.LENIENT.conversion_name def draw(self, context, layout, node, text): layout.label(text=self.name+ '. ' + str(self.objects_number)) layout.prop(self,'depth',text='Depth') layout.prop(self,'transform',text='')
Ancestors
- bpy_types.NodeSocket
- builtins.bpy_struct
- SvSocketCommon
- SvSocketProcessing
Class variables
var bl_idname
var bl_label
var bl_rna
var color
var default_conversion_name
var depth : <_PropertyDeferred,
, {'description': 'Depth exposed to the formula', 'update': process_from_socket() at 0x7f2f1d910e50>, 'default': 1, 'min': 1, 'attr': 'depth'}> var transform : <_PropertyDeferred,
, {'description': 'Transform before exposing to the formula', 'items': [('As_is', 'As is', '', 0), ('Vector', 'Vector', '', 1), ('Array', 'Array', '', 2), ('Set', 'Set', '', 3), ('String', 'String', '', 4)], 'update': SvFormulaSocket.update_depth() at 0x7f2f1d8f7c10>, 'attr': 'transform'}>
Methods
def draw(self, context, layout, node, text)
-
Expand source code
def draw(self, context, layout, node, text): layout.label(text=self.name+ '. ' + str(self.objects_number)) layout.prop(self,'depth',text='Depth') layout.prop(self,'transform',text='')
def update_depth(self, context)
-
Expand source code
def update_depth(self, context): if self.transform == 'Vector' and self.depth < 2: self.depth = 2 else: process_from_socket(self, context)
Inherited members
class SvImageSocket (...)
-
Base class for all Sockets
'SKIP_SAVE' in properties means skipping them during saving in JSON format some of the properties can be skipped because they are static, they are always set only in sv_init method
Expand source code
class SvImageSocket(NodeSocket, SvSocketCommon): bl_idname = "SvImageSocket" bl_label = "Image Socket" color = (0.39, 0.22, 0.39, 1.0) default_property: PointerProperty( name="Image", type=bpy.types.Image, update=process_from_socket)
Ancestors
- bpy_types.NodeSocket
- builtins.bpy_struct
- SvSocketCommon
- SvSocketProcessing
Class variables
var bl_idname
var bl_label
var bl_rna
var color
var default_property : <_PropertyDeferred,
, {'name': 'Image', 'type': , 'update': process_from_socket() at 0x7f2f1d910e50>, 'attr': 'default_value'}>
Inherited members
class SvInputLinkMenuOp (...)
-
Opens a menu
Expand source code
class SvInputLinkMenuOp(bpy.types.Operator): "Opens a menu" bl_idname = "node.sv_input_link_menu_popup" bl_label = "Link to existing parameter or add a new one" bl_options = {'INTERNAL', 'REGISTER'} bl_property = "option" def get_items(self, context): tree = context.space_data.node_tree node = tree.nodes[self.node_name] socket = node.inputs[self.input_name] items = [] link_param_node = socket.get_link_parameter_node() i = 0 if link_param_node: items.append( ('__SV_PARAM_CREATE__', "Create new parameter", "Create new parameter node", i) ) i += 1 items.append( ('__SV_WIFI_CREATE__', "Create new parameter via WiFi", "Create new parameter node and link it via WiFi pair", 1) ) i += 1 for name, other_node in tree.nodes.items(): if other_node.bl_idname == link_param_node: item = ('PARAM_' + other_node.name, f"Link to parameter: {other_node.label or other_node.name}", "Link to existing input node", i) items.append(item) i += 1 for name, other_node in tree.nodes.items(): if other_node.bl_idname == 'WifiInNode': for input_idx, wifi_input in enumerate(other_node.inputs): linked = get_other_socket(wifi_input) if linked is None: continue if linked.bl_idname != socket.bl_idname: continue item = (f"WIFI_{input_idx}_{other_node.var_name}", f"Link to WiFi: {other_node.label or other_node.name} - {other_node.var_name}[{input_idx}]", "Link to existing WiFi input node", i) items.append(item) i += 1 # In the node class, it is possible to define # additional menu entries by specifying `link_menu_handler` # property of the socket. It should be name of a class with # two classmethods: get_items() and on_selected(): # # class MyNode(...): # class MenuHandler: # @classmethod # def get_items(cls, context): # return [('MY_ENTRY', "My entry", "My entry description")] # # @classmethod # def on_selected(cls, tree, node, item, context): # if item == 'MY_ENTRY': # print("Hello world!") # # def sv_init(self): # self.inputs.new('SvVerticesSocket', 'Vertices').link_menu_handler = 'MenuHandler' # handler_name = socket.link_menu_handler if handler_name: handler = getattr(node, handler_name) for id, title, description in handler.get_items(socket, context): items.append((id, title, description, i)) i += 1 return items option : EnumProperty(name = "Action", description = "Action to be executed", items = get_items) tree_name : StringProperty() node_name : StringProperty() input_name : StringProperty() def execute(self, context): tree = bpy.data.node_groups[self.tree_name] node = tree.nodes[self.node_name] socket = node.inputs[self.input_name] def is_linked(node1, node2): for link in tree.links: if link.from_node == node1 and link.to_node == node2: return True return False if self.option == '__SV_PARAM_CREATE__': new_node = tree.nodes.new(socket.get_link_parameter_node()) new_node.label = socket.label or socket.name socket.setup_parameter_node(new_node) links_number = len([s for s in node.inputs if s.is_linked]) new_node.location = (node.location[0] - 200, node.location[1] - 100 * links_number) tree.links.new(new_node.outputs[0], socket) if node.parent: new_node.parent = node.parent new_node.location = new_node.absolute_location new_node.process_node(context) elif self.option == '__SV_WIFI_CREATE__': label = socket.label or socket.name param_node = tree.nodes.new(socket.get_link_parameter_node()) param_node.label = label wifi_in_node = tree.nodes.new('WifiInNode') wifi_in_node.label = f"WiFi In - {label}" wifi_in_node.gen_var_name() wifi_var = wifi_in_node.var_name wifi_out_node = tree.nodes.new('WifiOutNode') wifi_out_node.label = f"WiFi Out - {label}" wifi_out_node.var_name = wifi_var socket.setup_parameter_node(param_node) tree.links.new(param_node.outputs[0], wifi_in_node.inputs[0]) tree.links.new(wifi_out_node.outputs[0], socket) setup_new_node_location(wifi_out_node, node) setup_new_node_location(wifi_in_node, wifi_out_node) setup_new_node_location(param_node, wifi_in_node) param_node.process_node(context) elif self.option.startswith('PARAM_'): input_name = self.option[6:] param_node = tree.nodes[input_name] tree.links.new(param_node.outputs[0], socket) elif self.option.startswith('WIFI_'): prefix, socket_idx, wifi_var = self.option.split('_', maxsplit=2) socket_idx = int(socket_idx) found_existing = False for name, wifi_node in tree.nodes.items(): if wifi_node.bl_idname == 'WifiOutNode' and is_linked(wifi_node, node): if wifi_node.var_name == wifi_var: tree.links.new(wifi_node.outputs[socket_idx], socket) found_existing = True break if not found_existing: new_node = tree.nodes.new('WifiOutNode') new_node.var_name = wifi_var new_node.set_var_name() links_number = len([s for s in node.inputs if s.is_linked]) new_node.location = (node.location[0] - 200, node.location[1] - 100 * links_number) tree.links.new(new_node.outputs[socket_idx], socket) if node.parent: new_node.parent = node.parent new_node.location = new_node.absolute_location new_node.process_node(context) elif socket.link_menu_handler: handler = getattr(node, socket.link_menu_handler) handler.on_selected(tree, node, socket, self.option, context) return {'FINISHED'} def invoke(self, context, event): context.space_data.cursor_location_from_region(event.mouse_region_x, event.mouse_region_y) wm = context.window_manager wm.invoke_search_popup(self) return {'FINISHED'}
Ancestors
- bpy_types.Operator
- builtins.bpy_struct
Class variables
var bl_idname
var bl_label
var bl_options
var bl_property
var bl_rna
var input_name : <_PropertyDeferred,
, {'attr': 'input_name'}> var node_name : <_PropertyDeferred,
, {'attr': 'node_name'}> var option : <_PropertyDeferred,
, {'name': 'Action', 'description': 'Action to be executed', 'items': SvInputLinkMenuOp.get_items() at 0x7f2f1d8f61f0>, 'attr': 'option'}> var tree_name : <_PropertyDeferred,
, {'attr': 'tree_name'}>
Methods
def execute(self, context)
-
Expand source code
def execute(self, context): tree = bpy.data.node_groups[self.tree_name] node = tree.nodes[self.node_name] socket = node.inputs[self.input_name] def is_linked(node1, node2): for link in tree.links: if link.from_node == node1 and link.to_node == node2: return True return False if self.option == '__SV_PARAM_CREATE__': new_node = tree.nodes.new(socket.get_link_parameter_node()) new_node.label = socket.label or socket.name socket.setup_parameter_node(new_node) links_number = len([s for s in node.inputs if s.is_linked]) new_node.location = (node.location[0] - 200, node.location[1] - 100 * links_number) tree.links.new(new_node.outputs[0], socket) if node.parent: new_node.parent = node.parent new_node.location = new_node.absolute_location new_node.process_node(context) elif self.option == '__SV_WIFI_CREATE__': label = socket.label or socket.name param_node = tree.nodes.new(socket.get_link_parameter_node()) param_node.label = label wifi_in_node = tree.nodes.new('WifiInNode') wifi_in_node.label = f"WiFi In - {label}" wifi_in_node.gen_var_name() wifi_var = wifi_in_node.var_name wifi_out_node = tree.nodes.new('WifiOutNode') wifi_out_node.label = f"WiFi Out - {label}" wifi_out_node.var_name = wifi_var socket.setup_parameter_node(param_node) tree.links.new(param_node.outputs[0], wifi_in_node.inputs[0]) tree.links.new(wifi_out_node.outputs[0], socket) setup_new_node_location(wifi_out_node, node) setup_new_node_location(wifi_in_node, wifi_out_node) setup_new_node_location(param_node, wifi_in_node) param_node.process_node(context) elif self.option.startswith('PARAM_'): input_name = self.option[6:] param_node = tree.nodes[input_name] tree.links.new(param_node.outputs[0], socket) elif self.option.startswith('WIFI_'): prefix, socket_idx, wifi_var = self.option.split('_', maxsplit=2) socket_idx = int(socket_idx) found_existing = False for name, wifi_node in tree.nodes.items(): if wifi_node.bl_idname == 'WifiOutNode' and is_linked(wifi_node, node): if wifi_node.var_name == wifi_var: tree.links.new(wifi_node.outputs[socket_idx], socket) found_existing = True break if not found_existing: new_node = tree.nodes.new('WifiOutNode') new_node.var_name = wifi_var new_node.set_var_name() links_number = len([s for s in node.inputs if s.is_linked]) new_node.location = (node.location[0] - 200, node.location[1] - 100 * links_number) tree.links.new(new_node.outputs[socket_idx], socket) if node.parent: new_node.parent = node.parent new_node.location = new_node.absolute_location new_node.process_node(context) elif socket.link_menu_handler: handler = getattr(node, socket.link_menu_handler) handler.on_selected(tree, node, socket, self.option, context) return {'FINISHED'}
def get_items(self, context)
-
Expand source code
def get_items(self, context): tree = context.space_data.node_tree node = tree.nodes[self.node_name] socket = node.inputs[self.input_name] items = [] link_param_node = socket.get_link_parameter_node() i = 0 if link_param_node: items.append( ('__SV_PARAM_CREATE__', "Create new parameter", "Create new parameter node", i) ) i += 1 items.append( ('__SV_WIFI_CREATE__', "Create new parameter via WiFi", "Create new parameter node and link it via WiFi pair", 1) ) i += 1 for name, other_node in tree.nodes.items(): if other_node.bl_idname == link_param_node: item = ('PARAM_' + other_node.name, f"Link to parameter: {other_node.label or other_node.name}", "Link to existing input node", i) items.append(item) i += 1 for name, other_node in tree.nodes.items(): if other_node.bl_idname == 'WifiInNode': for input_idx, wifi_input in enumerate(other_node.inputs): linked = get_other_socket(wifi_input) if linked is None: continue if linked.bl_idname != socket.bl_idname: continue item = (f"WIFI_{input_idx}_{other_node.var_name}", f"Link to WiFi: {other_node.label or other_node.name} - {other_node.var_name}[{input_idx}]", "Link to existing WiFi input node", i) items.append(item) i += 1 # In the node class, it is possible to define # additional menu entries by specifying `link_menu_handler` # property of the socket. It should be name of a class with # two classmethods: get_items() and on_selected(): # # class MyNode(...): # class MenuHandler: # @classmethod # def get_items(cls, context): # return [('MY_ENTRY', "My entry", "My entry description")] # # @classmethod # def on_selected(cls, tree, node, item, context): # if item == 'MY_ENTRY': # print("Hello world!") # # def sv_init(self): # self.inputs.new('SvVerticesSocket', 'Vertices').link_menu_handler = 'MenuHandler' # handler_name = socket.link_menu_handler if handler_name: handler = getattr(node, handler_name) for id, title, description in handler.get_items(socket, context): items.append((id, title, description, i)) i += 1 return items
def invoke(self, context, event)
-
Expand source code
def invoke(self, context, event): context.space_data.cursor_location_from_region(event.mouse_region_x, event.mouse_region_y) wm = context.window_manager wm.invoke_search_popup(self) return {'FINISHED'}
class SvLinkNewNodeInput (...)
-
Spawn and link new node to the left of the caller node
Expand source code
class SvLinkNewNodeInput(bpy.types.Operator): ''' Spawn and link new node to the left of the caller node''' bl_idname = "node.sv_quicklink_new_node_input" bl_label = "Add a new node to the left" @classmethod def poll(cls, context): return hasattr(context, 'socket') def execute(self, context): tree, node, socket = context.node.id_data, context.node, context.socket new_node = tree.nodes.new(socket.quick_link_to_node) links_number = len([s for s in node.inputs if s.is_linked]) new_node.location = (node.location[0] - 200, node.location[1] - 100 * links_number) tree.links.new(new_node.outputs[0], socket) if node.parent: new_node.parent = node.parent new_node.location = new_node.absolute_location new_node.process_node(context) return {'FINISHED'}
Ancestors
- bpy_types.Operator
- builtins.bpy_struct
Class variables
var bl_idname
var bl_label
var bl_rna
Static methods
def poll(context)
-
Expand source code
@classmethod def poll(cls, context): return hasattr(context, 'socket')
Methods
def execute(self, context)
-
Expand source code
def execute(self, context): tree, node, socket = context.node.id_data, context.node, context.socket new_node = tree.nodes.new(socket.quick_link_to_node) links_number = len([s for s in node.inputs if s.is_linked]) new_node.location = (node.location[0] - 200, node.location[1] - 100 * links_number) tree.links.new(new_node.outputs[0], socket) if node.parent: new_node.parent = node.parent new_node.location = new_node.absolute_location new_node.process_node(context) return {'FINISHED'}
class SvLoopControlSocket (...)
-
For loop in-loop out node pair
Expand source code
class SvLoopControlSocket(NodeSocket, SvSocketCommon): '''For loop in-loop out node pair''' bl_idname = "SvLoopControlSocket" bl_label = "Loop Control Socket" color = (0.1, 0.1, 0.1, 1.0) quick_link_to_node = 'SvLoopInNode'
Ancestors
- bpy_types.NodeSocket
- builtins.bpy_struct
- SvSocketCommon
- SvSocketProcessing
Class variables
var bl_idname
var bl_label
var bl_rna
var color
var custom_draw : <_PropertyDeferred,
, {'description': 'For name of method which will draw socket UI (optionally)', 'attr': 'custom_draw'}> var default_mode : <_PropertyDeferred,
, {'items': [('NONE', 'NONE', '', 0), ('EMPTY_LIST', 'EMPTY_LIST', '', 1), ('MATRIX', 'MATRIX', '', 2), ('MASK', 'MASK', '', 3)], 'default': 'EMPTY_LIST', 'attr': 'default_mode'}> var description : <_PropertyDeferred,
, {'attr': 'description'}> var is_mandatory : <_PropertyDeferred,
, {'default': False, 'attr': 'is_mandatory'}> var label : <_PropertyDeferred,
, {'attr': 'label'}> var nesting_level : <_PropertyDeferred,
, {'default': 2, 'attr': 'nesting_level'}> var objects_number : <_PropertyDeferred,
, {'min': 0, 'options': {'SKIP_SAVE'}, 'attr': 'objects_number'}> var pre_processing : <_PropertyDeferred,
, {'items': [('NONE', 'NONE', '', 0), ('ONE_ITEM', 'ONE_ITEM', '', 1)], 'default': 'NONE', 'attr': 'pre_processing'}> var prop_name : <_PropertyDeferred,
, {'default': '', 'description': 'For displaying node property in socket UI', 'attr': 'prop_name'}> var quick_link_to_node
var s_id : <_PropertyDeferred,
, {'options': {'SKIP_SAVE'}, 'attr': 's_id'}> var use_prop : <_PropertyDeferred,
, {'default': False, 'attr': 'use_prop'}>
Inherited members
class SvMaterialSocket (...)
-
Base class for all Sockets
'SKIP_SAVE' in properties means skipping them during saving in JSON format some of the properties can be skipped because they are static, they are always set only in sv_init method
Expand source code
class SvMaterialSocket(NodeSocket, SvSocketCommon): bl_idname = "SvMaterialSocket" bl_label = "Material Socket" color = (0.92, 0.46, 0.51, 1.0) default_property: PointerProperty( name="Material", type=bpy.types.Material, update=process_from_socket)
Ancestors
- bpy_types.NodeSocket
- builtins.bpy_struct
- SvSocketCommon
- SvSocketProcessing
Class variables
var bl_idname
var bl_label
var bl_rna
var color
var default_property : <_PropertyDeferred,
, {'name': 'Material', 'type': , 'update': process_from_socket() at 0x7f2f1d910e50>, 'attr': 'default_value'}>
Inherited members
class SvMatrixSocket (...)
-
4x4 matrix Socket type
Expand source code
class SvMatrixSocket(NodeSocket, SvSocketCommon): '''4x4 matrix Socket type''' bl_idname = "SvMatrixSocket" bl_label = "Matrix Socket" color = (0.2, 0.8, 0.8, 1.0) quick_link_to_node = 'SvMatrixInNodeMK4' nesting_level: IntProperty(default=1) def do_flatten(self, data): return flatten_data(data, 1, data_types=(Matrix,)) def do_graft(self, data): return graft_data(data, item_level=0, data_types=(Matrix,))
Ancestors
- bpy_types.NodeSocket
- builtins.bpy_struct
- SvSocketCommon
- SvSocketProcessing
Class variables
var bl_idname
var bl_label
var bl_rna
var color
var nesting_level : <_PropertyDeferred,
, {'default': 1, 'attr': 'nesting_level'}> var quick_link_to_node
Methods
def do_flatten(self, data)
-
Expand source code
def do_flatten(self, data): return flatten_data(data, 1, data_types=(Matrix,))
def do_graft(self, data)
-
Expand source code
def do_graft(self, data): return graft_data(data, item_level=0, data_types=(Matrix,))
Inherited members
class SvObjectSocket (...)
-
Base class for all Sockets
'SKIP_SAVE' in properties means skipping them during saving in JSON format some of the properties can be skipped because they are static, they are always set only in sv_init method
Expand source code
class SvObjectSocket(NodeSocket, SvSocketCommon): bl_idname = "SvObjectSocket" bl_label = "Object Socket" def filter_kinds(self, objs): """ object_kinds could be any of these: [‘MESH’, ‘CURVE’, ‘SURFACE’, ‘META’, ‘FONT’, ‘VOLUME’, ‘ARMATURE’, ‘LATTICE’, ‘EMPTY’, ‘GPENCIL’, ‘CAMERA’, ‘LIGHT’, ‘SPEAKER’, ‘LIGHT_PROBE’, ‘EMPTY’ for example socket.object_kinds = "MESH" or if you want various kinds socket.object_kinds = "MESH,CURVE" """ if self.object_kinds in {'ALL', ''}: return True if not self.object_kinds: return True kind = self.object_kinds if "," in kind: kinds = kind.split(',') if objs.type in set(kinds): return True if objs.type == kind: return True color = (0.69, 0.74, 0.73, 1.0) use_prop: BoolProperty(default=True) object_kinds: StringProperty(default='ALL') # use for filtering objects, see filter_kinds method object_ref: StringProperty(update=process_from_socket) object_ref_pointer: bpy.props.PointerProperty( name="Object Reference", poll=filter_kinds, # seld.object_kinds can be "MESH" or "MESH,CURVE,.." type=bpy.types.Object, # what kind of objects are we showing update=process_from_socket) @property def default_property(self): # this can be more granular and even attempt to set object_ref_points from object_ref, and then wipe object_ref return self.node.get_bpy_data_from_name(self.object_ref or self.object_ref_pointer, bpy.data.objects) def draw_property(self, layout, prop_origin=None, prop_name='default_property'): if prop_origin: layout.prop(prop_origin, prop_name) # need for consistency, probably will never be used else: layout.prop_search(self, 'object_ref_pointer', bpy.data, 'objects', text=self.name)
Ancestors
- bpy_types.NodeSocket
- builtins.bpy_struct
- SvSocketCommon
- SvSocketProcessing
Class variables
var bl_idname
var bl_label
var bl_rna
var color
var object_kinds : <_PropertyDeferred,
, {'default': 'ALL', 'attr': 'object_kinds'}> var object_ref : <_PropertyDeferred,
, {'update': process_from_socket() at 0x7f2f1d910e50>, 'attr': 'object_ref'}> var object_ref_pointer : <_PropertyDeferred,
, {'name': 'Object Reference', 'poll': SvObjectSocket.filter_kinds() at 0x7f2f1d8f7a60>, 'type': , 'update': process_from_socket() at 0x7f2f1d910e50>, 'attr': 'object_ref_pointer'}> var use_prop : <_PropertyDeferred,
, {'default': True, 'attr': 'use_prop'}>
Instance variables
var default_property
-
Expand source code
@property def default_property(self): # this can be more granular and even attempt to set object_ref_points from object_ref, and then wipe object_ref return self.node.get_bpy_data_from_name(self.object_ref or self.object_ref_pointer, bpy.data.objects)
Methods
def filter_kinds(self, objs)
-
object_kinds could be any of these: [‘MESH’, ‘CURVE’, ‘SURFACE’, ‘META’, ‘FONT’, ‘VOLUME’, ‘ARMATURE’, ‘LATTICE’, ‘EMPTY’, ‘GPENCIL’, ‘CAMERA’, ‘LIGHT’, ‘SPEAKER’, ‘LIGHT_PROBE’, ‘EMPTY’
for example socket.object_kinds = "MESH" or if you want various kinds socket.object_kinds = "MESH,CURVE"
Expand source code
def filter_kinds(self, objs): """ object_kinds could be any of these: [‘MESH’, ‘CURVE’, ‘SURFACE’, ‘META’, ‘FONT’, ‘VOLUME’, ‘ARMATURE’, ‘LATTICE’, ‘EMPTY’, ‘GPENCIL’, ‘CAMERA’, ‘LIGHT’, ‘SPEAKER’, ‘LIGHT_PROBE’, ‘EMPTY’ for example socket.object_kinds = "MESH" or if you want various kinds socket.object_kinds = "MESH,CURVE" """ if self.object_kinds in {'ALL', ''}: return True if not self.object_kinds: return True kind = self.object_kinds if "," in kind: kinds = kind.split(',') if objs.type in set(kinds): return True if objs.type == kind: return True
Inherited members
class SvPulgaForceSocket (...)
-
For Pulga forces data
Expand source code
class SvPulgaForceSocket(NodeSocket, SvSocketCommon): '''For Pulga forces data''' bl_idname = "SvPulgaForceSocket" bl_label = "Pulga Force Socket" color = (0.4, 0.3, 0.6, 1.0)
Ancestors
- bpy_types.NodeSocket
- builtins.bpy_struct
- SvSocketCommon
- SvSocketProcessing
Class variables
var bl_idname
var bl_label
var bl_rna
var color
var custom_draw : <_PropertyDeferred,
, {'description': 'For name of method which will draw socket UI (optionally)', 'attr': 'custom_draw'}> var default_mode : <_PropertyDeferred,
, {'items': [('NONE', 'NONE', '', 0), ('EMPTY_LIST', 'EMPTY_LIST', '', 1), ('MATRIX', 'MATRIX', '', 2), ('MASK', 'MASK', '', 3)], 'default': 'EMPTY_LIST', 'attr': 'default_mode'}> var description : <_PropertyDeferred,
, {'attr': 'description'}> var is_mandatory : <_PropertyDeferred,
, {'default': False, 'attr': 'is_mandatory'}> var label : <_PropertyDeferred,
, {'attr': 'label'}> var nesting_level : <_PropertyDeferred,
, {'default': 2, 'attr': 'nesting_level'}> var objects_number : <_PropertyDeferred,
, {'min': 0, 'options': {'SKIP_SAVE'}, 'attr': 'objects_number'}> var pre_processing : <_PropertyDeferred,
, {'items': [('NONE', 'NONE', '', 0), ('ONE_ITEM', 'ONE_ITEM', '', 1)], 'default': 'NONE', 'attr': 'pre_processing'}> var prop_name : <_PropertyDeferred,
, {'default': '', 'description': 'For displaying node property in socket UI', 'attr': 'prop_name'}> var s_id : <_PropertyDeferred,
, {'options': {'SKIP_SAVE'}, 'attr': 's_id'}> var use_prop : <_PropertyDeferred,
, {'default': False, 'attr': 'use_prop'}>
Inherited members
class SvQuaternionSocket (...)
-
For quaternion data
Expand source code
class SvQuaternionSocket(NodeSocket, SvSocketCommon): '''For quaternion data''' bl_idname = "SvQuaternionSocket" bl_label = "Quaternion Socket" color = (0.9, 0.4, 0.7, 1.0) default_property: FloatVectorProperty(default=(1, 0, 0, 0), size=4, subtype='QUATERNION', update=process_from_socket) expanded: BoolProperty(default=False) # for minimizing showing socket property def draw_property(self, layout, prop_origin=None, prop_name='prop'): if prop_origin is None: prop_origin = self split = layout.split(factor=.2, align=True) c1 = split.column(align=True) c2 = split.column(align=True) if self.expanded: c1.prop(self, "expanded", icon='TRIA_UP', text='') c1.label(text=self.name[0]) c2.prop(prop_origin, prop_name, text="", expand=True) else: c1.prop(self, "expanded", icon='TRIA_DOWN', text="") row = c2.row(align=True) row.template_component_menu(prop_origin, prop_name, name=self.name) def do_flatten(self, data): return flatten_data(data, 1, data_types=(Quaternion,)) def do_graft(self, data): return graft_data(data, item_level=0, data_types=(Quaternion,)) def draw_group_property(self, layout, text, interface_socket): if not interface_socket.hide_value: layout.template_component_menu(self, 'default_property', name=text) else: layout.label(text=text)
Ancestors
- bpy_types.NodeSocket
- builtins.bpy_struct
- SvSocketCommon
- SvSocketProcessing
Class variables
var bl_idname
var bl_label
var bl_rna
var color
var default_property : <_PropertyDeferred,
, {'default': (1, 0, 0, 0), 'size': 4, 'subtype': 'QUATERNION', 'update': process_from_socket() at 0x7f2f1d910e50>, 'attr': 'default_value'}> var expanded : <_PropertyDeferred,
, {'default': False, 'attr': 'expanded'}>
Methods
def do_flatten(self, data)
-
Expand source code
def do_flatten(self, data): return flatten_data(data, 1, data_types=(Quaternion,))
def do_graft(self, data)
-
Expand source code
def do_graft(self, data): return graft_data(data, item_level=0, data_types=(Quaternion,))
def draw_group_property(self, layout, text, interface_socket)
-
Expand source code
def draw_group_property(self, layout, text, interface_socket): if not interface_socket.hide_value: layout.template_component_menu(self, 'default_property', name=text) else: layout.label(text=text)
Inherited members
class SvScalarFieldSocket (...)
-
Base class for all Sockets
'SKIP_SAVE' in properties means skipping them during saving in JSON format some of the properties can be skipped because they are static, they are always set only in sv_init method
Expand source code
class SvScalarFieldSocket(NodeSocket, SvSocketCommon): bl_idname = "SvScalarFieldSocket" bl_label = "Scalar Field Socket" quick_link_to_node = 'SvNumberNode' color = (0.9, 0.4, 0.1, 1.0) default_conversion_name = ConversionPolicies.FIELD.conversion_name def do_flatten(self, data): return flatten_data(data, 1, data_types=(SvScalarField,)) def do_graft(self, data): return graft_data(data, item_level=0, data_types=(SvScalarField,))
Ancestors
- bpy_types.NodeSocket
- builtins.bpy_struct
- SvSocketCommon
- SvSocketProcessing
Class variables
var bl_idname
var bl_label
var bl_rna
var color
var custom_draw : <_PropertyDeferred,
, {'description': 'For name of method which will draw socket UI (optionally)', 'attr': 'custom_draw'}> var default_conversion_name
var default_mode : <_PropertyDeferred,
, {'items': [('NONE', 'NONE', '', 0), ('EMPTY_LIST', 'EMPTY_LIST', '', 1), ('MATRIX', 'MATRIX', '', 2), ('MASK', 'MASK', '', 3)], 'default': 'EMPTY_LIST', 'attr': 'default_mode'}> var description : <_PropertyDeferred,
, {'attr': 'description'}> var is_mandatory : <_PropertyDeferred,
, {'default': False, 'attr': 'is_mandatory'}> var label : <_PropertyDeferred,
, {'attr': 'label'}> var nesting_level : <_PropertyDeferred,
, {'default': 2, 'attr': 'nesting_level'}> var objects_number : <_PropertyDeferred,
, {'min': 0, 'options': {'SKIP_SAVE'}, 'attr': 'objects_number'}> var pre_processing : <_PropertyDeferred,
, {'items': [('NONE', 'NONE', '', 0), ('ONE_ITEM', 'ONE_ITEM', '', 1)], 'default': 'NONE', 'attr': 'pre_processing'}> var prop_name : <_PropertyDeferred,
, {'default': '', 'description': 'For displaying node property in socket UI', 'attr': 'prop_name'}> var quick_link_to_node
var s_id : <_PropertyDeferred,
, {'options': {'SKIP_SAVE'}, 'attr': 's_id'}> var use_prop : <_PropertyDeferred,
, {'default': False, 'attr': 'use_prop'}>
Methods
def do_flatten(self, data)
-
Expand source code
def do_flatten(self, data): return flatten_data(data, 1, data_types=(SvScalarField,))
def do_graft(self, data)
-
Expand source code
def do_graft(self, data): return graft_data(data, item_level=0, data_types=(SvScalarField,))
Inherited members
class SvSeparatorSocket (...)
-
Separator Socket used to separate groups of sockets
Expand source code
class SvSeparatorSocket(NodeSocket, SvSocketCommon): ''' Separator Socket used to separate groups of sockets ''' bl_idname = "SvSeparatorSocket" bl_label = "Separator Socket" color = (0.0, 0.0, 0.0, 0.0) def draw(self, context, layout, node, text): # layout.label("") layout.label(text="——————")
Ancestors
- bpy_types.NodeSocket
- builtins.bpy_struct
- SvSocketCommon
- SvSocketProcessing
Class variables
var bl_idname
var bl_label
var bl_rna
var color
var custom_draw : <_PropertyDeferred,
, {'description': 'For name of method which will draw socket UI (optionally)', 'attr': 'custom_draw'}> var default_mode : <_PropertyDeferred,
, {'items': [('NONE', 'NONE', '', 0), ('EMPTY_LIST', 'EMPTY_LIST', '', 1), ('MATRIX', 'MATRIX', '', 2), ('MASK', 'MASK', '', 3)], 'default': 'EMPTY_LIST', 'attr': 'default_mode'}> var description : <_PropertyDeferred,
, {'attr': 'description'}> var is_mandatory : <_PropertyDeferred,
, {'default': False, 'attr': 'is_mandatory'}> var label : <_PropertyDeferred,
, {'attr': 'label'}> var nesting_level : <_PropertyDeferred,
, {'default': 2, 'attr': 'nesting_level'}> var objects_number : <_PropertyDeferred,
, {'min': 0, 'options': {'SKIP_SAVE'}, 'attr': 'objects_number'}> var pre_processing : <_PropertyDeferred,
, {'items': [('NONE', 'NONE', '', 0), ('ONE_ITEM', 'ONE_ITEM', '', 1)], 'default': 'NONE', 'attr': 'pre_processing'}> var prop_name : <_PropertyDeferred,
, {'default': '', 'description': 'For displaying node property in socket UI', 'attr': 'prop_name'}> var s_id : <_PropertyDeferred,
, {'options': {'SKIP_SAVE'}, 'attr': 's_id'}> var use_prop : <_PropertyDeferred,
, {'default': False, 'attr': 'use_prop'}>
Methods
def draw(self, context, layout, node, text)
-
Expand source code
def draw(self, context, layout, node, text): # layout.label("") layout.label(text="——————")
Inherited members
class SvSocketCommon
-
Base class for all Sockets
'SKIP_SAVE' in properties means skipping them during saving in JSON format some of the properties can be skipped because they are static, they are always set only in sv_init method
Expand source code
class SvSocketCommon(SvSocketProcessing): """ Base class for all Sockets 'SKIP_SAVE' in properties means skipping them during saving in JSON format some of the properties can be skipped because they are static, they are always set only in sv_init method """ color = (1, 0, 0, 1) # base color, other sockets should override the property, use FloatProperty for dynamic default_conversion_name = ConversionPolicies.DEFAULT.conversion_name label: StringProperty() # It will be drawn instead of name if given quick_link_to_node = str() # sockets which often used with other nodes can fill its `bl_idname` here link_menu_handler : StringProperty(default='') # To specify additional entries in the socket link menu enable_input_link_menu : BoolProperty(default = True) # set True to use default socket property if it has got it use_prop: BoolProperty(default=False) custom_draw: StringProperty(description="For name of method which will draw socket UI (optionally)") prop_name: StringProperty(default='', description="For displaying node property in socket UI") # utility field for showing number of objects in sockets data objects_number: IntProperty(min=0, options={'SKIP_SAVE'}) description : StringProperty() is_mandatory: BoolProperty(default=False) nesting_level: IntProperty(default=2) default_mode: EnumProperty(items=enum_item_4(['NONE', 'EMPTY_LIST', 'MATRIX', 'MASK']), default='EMPTY_LIST') pre_processing: EnumProperty(items=enum_item_4(['NONE', 'ONE_ITEM']), default='NONE') s_id: StringProperty(options={'SKIP_SAVE'}) def get_link_parameter_node(self): return self.quick_link_to_node def setup_parameter_node(self, param_node): pass def get_prop_name(self): """ Intended to return name of property related with socket owned by its node Name can be replaced by twin property name in draft mode of a tree """ node = self.node if node and hasattr(node, 'does_support_draft_mode') and node.does_support_draft_mode() and hasattr(node.id_data, 'sv_draft') and node.id_data.sv_draft: prop_name_draft = self.node.draft_properties_mapping.get(self.prop_name, None) if prop_name_draft: return prop_name_draft return self.prop_name return self.prop_name @property def other(self): """Returns opposite linked socket, if socket is outputs it will return one random opposite linked socket""" return get_other_socket(self) @property def socket_id(self): """Id of socket used by data_cache""" _id = self.s_id if not _id: self.s_id = str(hash(self.node.node_id + self.identifier + ('o' if self.is_output else 'i'))) _id = self.s_id return _id @property def index(self): """Index of socket, hidden sockets are also taken into account""" node = self.node sockets = node.outputs if self.is_output else node.inputs for i, s in enumerate(sockets): if s == self: return i @property def hide_safe(self): """It will hide even linked sockets""" return self.hide @hide_safe.setter def hide_safe(self, value): # handles both input and output. if self.is_linked and value: for link in self.links: self.id_data.links.remove(link) self.hide = value def sv_get(self, default=..., deepcopy=True): """ The method is used for getting socket data In most cases the method should not be overridden Also a socket can use its default_property Order of getting data (if available): 1. written socket data 2. node default property 3. socket default property 4. script default property 5. Raise no data error :param default: script default property :param deepcopy: in most cases should be False for efficiency but not in cases if input data will be modified :return: data bound to the socket """ if self.is_output: return sv_get_socket(self, False) if self.is_linked: return sv_get_socket(self, deepcopy) prop_name = self.get_prop_name() if prop_name: prop = getattr(self.node, prop_name) return format_bpy_property(prop) if self.use_prop and hasattr(self, 'default_property') and self.default_property is not None: default_property = self.default_property return format_bpy_property(default_property) if default is not ...: return default raise SvNoDataError(self) def sv_set(self, data): """Set data, provide context in case the node can be evaluated several times in different context""" if self.is_output: data = self.postprocess_output(data) # it's expensive to call sv_get method to update the number in other places self.objects_number = len(data) sv_set_socket(self, data) def sv_forget(self): """Delete socket memory""" sv_forget_socket(self) def replace_socket(self, new_type, new_name=None): """Replace a socket with a socket of new_type and keep links, return the new socket, the old reference might be invalid""" self.sv_forget() return replace_socket(self, new_type, new_name) def draw_property(self, layout, prop_origin=None, prop_name='default_property'): """ This method can be overridden for showing property in another way Property will be shown only if socket is unconnected input If prop_origin is None then the default socket property should be shown """ if prop_origin is None and hasattr(self, prop_name): layout.prop(self, 'default_property') else: layout.prop(prop_origin, prop_name) def draw_quick_link(self, context, layout, node): """ Will draw button for creating new node which is often used with such type of sockets The socket should have `bl_idname` of other node in `quick_link_to_node` attribute for using this UI """ if self.quick_link_to_node: layout.operator('node.sv_quicklink_new_node_input', text="", icon="PLUGIN") def does_support_link_input_menu(self, context, layout, node): if not self.enable_input_link_menu: return False param_node = self.get_link_parameter_node() if not param_node: return False return True def draw_link_input_menu(self, context, layout, node): if not self.does_support_link_input_menu(context, layout, node): return op = layout.operator('node.sv_input_link_menu_popup', text="", icon="PLUGIN") op.tree_name = node.id_data.name op.node_name = node.name op.input_name = self.name def draw(self, context, layout, node, text): def draw_label(text): flags = self.get_mode_flags() if flags: text = text + " [" + ",".join(flags) + "]" if self.description: layout.operator('node.sv_socket_show_help', text=text, emboss=False).text = self.description else: if hasattr(self, 'show_domain') and self.show_domain: row = layout.row() row.label(text=text) row.prop(self, 'domain', text='') else: layout.label(text=text) menu_option = get_param('show_input_menus', 'QUICKLINK') # just handle custom draw..be it input or output. if self.custom_draw: # does the node have the draw function referred to by # the string stored in socket's custom_draw attribute if hasattr(node, self.custom_draw): getattr(node, self.custom_draw)(self, context, layout) elif self.is_linked: # linked INPUT or OUTPUT draw_label((self.label or text) + f". {self.objects_number or ''}") elif self.is_output: # unlinked OUTPUT draw_label(self.label or text) else: # unlinked INPUT prop_name = self.get_prop_name() if prop_name: # has property if menu_option == 'ALL': self.draw_link_input_menu(context, layout, node) self.draw_property(layout, prop_origin=node, prop_name=prop_name) elif node.bl_idname == 'SvGroupTreeNode' and hasattr(self, 'draw_group_property'): # group node if node.node_tree: # when tree is removed from node sockets still exist interface_socket = node.node_tree.inputs[self.index] self.draw_group_property(layout, text, interface_socket) elif node.bl_idname == 'NodeGroupOutput' and hasattr(self, 'draw_group_property'): # group out node if self.index < len(node.outputs): # in case of last socket of the node which is virtual interface_socket = node.outputs[self.index] self.draw_group_property(layout, text, interface_socket) elif self.use_prop: # no property but use default prop if menu_option == 'ALL': self.draw_link_input_menu(context, layout, node) self.draw_property(layout) else: # no property and not use default prop if menu_option == 'QUICKLINK': self.draw_quick_link(context, layout, node) elif menu_option == 'ALL': self.draw_link_input_menu(context, layout, node) draw_label(self.label or text) if self.has_menu(context): self.draw_menu_button(context, layout, node, text) def draw_color(self, context, node): return self.color
Ancestors
Subclasses
- SvChameleonSocket
- SvCollectionSocket
- SvColorSocket
- SvCurveSocket
- SvDictionarySocket
- SvDummySocket
- SvFilePathSocket
- SvFormulaSocket
- SvImageSocket
- SvLoopControlSocket
- SvMaterialSocket
- SvMatrixSocket
- SvObjectSocket
- SvPulgaForceSocket
- SvQuaternionSocket
- SvScalarFieldSocket
- SvSeparatorSocket
- SvSolidSocket
- SvStringsSocket
- SvSurfaceSocket
- SvSvgSocket
- SvTextSocket
- SvTextureSocket
- SvVectorFieldSocket
- SvVerticesSocket
Class variables
var color
var custom_draw : <_PropertyDeferred,
, {'description': 'For name of method which will draw socket UI (optionally)', 'attr': 'custom_draw'}> var default_conversion_name
var default_mode : <_PropertyDeferred,
, {'items': [('NONE', 'NONE', '', 0), ('EMPTY_LIST', 'EMPTY_LIST', '', 1), ('MATRIX', 'MATRIX', '', 2), ('MASK', 'MASK', '', 3)], 'default': 'EMPTY_LIST', 'attr': 'default_mode'}> var description : <_PropertyDeferred,
, {'attr': 'description'}> var is_mandatory : <_PropertyDeferred,
, {'default': False, 'attr': 'is_mandatory'}> var label : <_PropertyDeferred,
, {'attr': 'label'}> var nesting_level : <_PropertyDeferred,
, {'default': 2, 'attr': 'nesting_level'}> var objects_number : <_PropertyDeferred,
, {'min': 0, 'options': {'SKIP_SAVE'}, 'attr': 'objects_number'}> var pre_processing : <_PropertyDeferred,
, {'items': [('NONE', 'NONE', '', 0), ('ONE_ITEM', 'ONE_ITEM', '', 1)], 'default': 'NONE', 'attr': 'pre_processing'}> var prop_name : <_PropertyDeferred,
, {'default': '', 'description': 'For displaying node property in socket UI', 'attr': 'prop_name'}> var quick_link_to_node
var s_id : <_PropertyDeferred,
, {'options': {'SKIP_SAVE'}, 'attr': 's_id'}> var use_prop : <_PropertyDeferred,
, {'default': False, 'attr': 'use_prop'}>
Instance variables
var hide_safe
-
It will hide even linked sockets
Expand source code
@property def hide_safe(self): """It will hide even linked sockets""" return self.hide
var index
-
Index of socket, hidden sockets are also taken into account
Expand source code
@property def index(self): """Index of socket, hidden sockets are also taken into account""" node = self.node sockets = node.outputs if self.is_output else node.inputs for i, s in enumerate(sockets): if s == self: return i
var other
-
Returns opposite linked socket, if socket is outputs it will return one random opposite linked socket
Expand source code
@property def other(self): """Returns opposite linked socket, if socket is outputs it will return one random opposite linked socket""" return get_other_socket(self)
var socket_id
-
Id of socket used by data_cache
Expand source code
@property def socket_id(self): """Id of socket used by data_cache""" _id = self.s_id if not _id: self.s_id = str(hash(self.node.node_id + self.identifier + ('o' if self.is_output else 'i'))) _id = self.s_id return _id
Methods
-
Expand source code
def does_support_link_input_menu(self, context, layout, node): if not self.enable_input_link_menu: return False param_node = self.get_link_parameter_node() if not param_node: return False return True
def draw(self, context, layout, node, text)
-
Expand source code
def draw(self, context, layout, node, text): def draw_label(text): flags = self.get_mode_flags() if flags: text = text + " [" + ",".join(flags) + "]" if self.description: layout.operator('node.sv_socket_show_help', text=text, emboss=False).text = self.description else: if hasattr(self, 'show_domain') and self.show_domain: row = layout.row() row.label(text=text) row.prop(self, 'domain', text='') else: layout.label(text=text) menu_option = get_param('show_input_menus', 'QUICKLINK') # just handle custom draw..be it input or output. if self.custom_draw: # does the node have the draw function referred to by # the string stored in socket's custom_draw attribute if hasattr(node, self.custom_draw): getattr(node, self.custom_draw)(self, context, layout) elif self.is_linked: # linked INPUT or OUTPUT draw_label((self.label or text) + f". {self.objects_number or ''}") elif self.is_output: # unlinked OUTPUT draw_label(self.label or text) else: # unlinked INPUT prop_name = self.get_prop_name() if prop_name: # has property if menu_option == 'ALL': self.draw_link_input_menu(context, layout, node) self.draw_property(layout, prop_origin=node, prop_name=prop_name) elif node.bl_idname == 'SvGroupTreeNode' and hasattr(self, 'draw_group_property'): # group node if node.node_tree: # when tree is removed from node sockets still exist interface_socket = node.node_tree.inputs[self.index] self.draw_group_property(layout, text, interface_socket) elif node.bl_idname == 'NodeGroupOutput' and hasattr(self, 'draw_group_property'): # group out node if self.index < len(node.outputs): # in case of last socket of the node which is virtual interface_socket = node.outputs[self.index] self.draw_group_property(layout, text, interface_socket) elif self.use_prop: # no property but use default prop if menu_option == 'ALL': self.draw_link_input_menu(context, layout, node) self.draw_property(layout) else: # no property and not use default prop if menu_option == 'QUICKLINK': self.draw_quick_link(context, layout, node) elif menu_option == 'ALL': self.draw_link_input_menu(context, layout, node) draw_label(self.label or text) if self.has_menu(context): self.draw_menu_button(context, layout, node, text)
def draw_color(self, context, node)
-
Expand source code
def draw_color(self, context, node): return self.color
-
Expand source code
def draw_link_input_menu(self, context, layout, node): if not self.does_support_link_input_menu(context, layout, node): return op = layout.operator('node.sv_input_link_menu_popup', text="", icon="PLUGIN") op.tree_name = node.id_data.name op.node_name = node.name op.input_name = self.name
def draw_property(self, layout, prop_origin=None, prop_name='default_property')
-
This method can be overridden for showing property in another way Property will be shown only if socket is unconnected input If prop_origin is None then the default socket property should be shown
Expand source code
def draw_property(self, layout, prop_origin=None, prop_name='default_property'): """ This method can be overridden for showing property in another way Property will be shown only if socket is unconnected input If prop_origin is None then the default socket property should be shown """ if prop_origin is None and hasattr(self, prop_name): layout.prop(self, 'default_property') else: layout.prop(prop_origin, prop_name)
def draw_quick_link(self, context, layout, node)
-
Will draw button for creating new node which is often used with such type of sockets The socket should have
bl_idname
of other node inquick_link_to_node
attribute for using this UIExpand source code
def draw_quick_link(self, context, layout, node): """ Will draw button for creating new node which is often used with such type of sockets The socket should have `bl_idname` of other node in `quick_link_to_node` attribute for using this UI """ if self.quick_link_to_node: layout.operator('node.sv_quicklink_new_node_input', text="", icon="PLUGIN")
def get_link_parameter_node(self)
-
Expand source code
def get_link_parameter_node(self): return self.quick_link_to_node
def get_prop_name(self)
-
Intended to return name of property related with socket owned by its node Name can be replaced by twin property name in draft mode of a tree
Expand source code
def get_prop_name(self): """ Intended to return name of property related with socket owned by its node Name can be replaced by twin property name in draft mode of a tree """ node = self.node if node and hasattr(node, 'does_support_draft_mode') and node.does_support_draft_mode() and hasattr(node.id_data, 'sv_draft') and node.id_data.sv_draft: prop_name_draft = self.node.draft_properties_mapping.get(self.prop_name, None) if prop_name_draft: return prop_name_draft return self.prop_name return self.prop_name
def replace_socket(self, new_type, new_name=None)
-
Replace a socket with a socket of new_type and keep links, return the new socket, the old reference might be invalid
Expand source code
def replace_socket(self, new_type, new_name=None): """Replace a socket with a socket of new_type and keep links, return the new socket, the old reference might be invalid""" self.sv_forget() return replace_socket(self, new_type, new_name)
def setup_parameter_node(self, param_node)
-
Expand source code
def setup_parameter_node(self, param_node): pass
def sv_forget(self)
-
Delete socket memory
Expand source code
def sv_forget(self): """Delete socket memory""" sv_forget_socket(self)
def sv_get(self, default=Ellipsis, deepcopy=True)
-
The method is used for getting socket data In most cases the method should not be overridden Also a socket can use its default_property Order of getting data (if available): 1. written socket data 2. node default property 3. socket default property 4. script default property 5. Raise no data error :param default: script default property :param deepcopy: in most cases should be False for efficiency but not in cases if input data will be modified :return: data bound to the socket
Expand source code
def sv_get(self, default=..., deepcopy=True): """ The method is used for getting socket data In most cases the method should not be overridden Also a socket can use its default_property Order of getting data (if available): 1. written socket data 2. node default property 3. socket default property 4. script default property 5. Raise no data error :param default: script default property :param deepcopy: in most cases should be False for efficiency but not in cases if input data will be modified :return: data bound to the socket """ if self.is_output: return sv_get_socket(self, False) if self.is_linked: return sv_get_socket(self, deepcopy) prop_name = self.get_prop_name() if prop_name: prop = getattr(self.node, prop_name) return format_bpy_property(prop) if self.use_prop and hasattr(self, 'default_property') and self.default_property is not None: default_property = self.default_property return format_bpy_property(default_property) if default is not ...: return default raise SvNoDataError(self)
def sv_set(self, data)
-
Set data, provide context in case the node can be evaluated several times in different context
Expand source code
def sv_set(self, data): """Set data, provide context in case the node can be evaluated several times in different context""" if self.is_output: data = self.postprocess_output(data) # it's expensive to call sv_get method to update the number in other places self.objects_number = len(data) sv_set_socket(self, data)
class SvSocketHelpOp (...)
-
Expand source code
class SvSocketHelpOp(bpy.types.Operator): bl_idname = "node.sv_socket_show_help" bl_label = "Socket description" bl_options = {'INTERNAL', 'REGISTER'} text : StringProperty() @classmethod def description(cls, context, properties): return properties.text def execute(self, context): def draw(menu, context): col = menu.layout.column(align=True) for line in self.text.split('\n'): col.label(text=line) bpy.context.window_manager.popup_menu(draw, title="Socket description", icon='QUESTION') return {'FINISHED'}
Ancestors
- bpy_types.Operator
- builtins.bpy_struct
Class variables
var bl_idname
var bl_label
var bl_options
var bl_rna
var text : <_PropertyDeferred,
, {'attr': 'text'}>
Static methods
def description(context, properties)
-
Expand source code
@classmethod def description(cls, context, properties): return properties.text
Methods
def execute(self, context)
-
Expand source code
def execute(self, context): def draw(menu, context): col = menu.layout.column(align=True) for line in self.text.split('\n'): col.label(text=line) bpy.context.window_manager.popup_menu(draw, title="Socket description", icon='QUESTION') return {'FINISHED'}
class SvSocketProcessing
-
Mixin class for data processing logic of a socket.
Expand source code
class SvSocketProcessing(): """ Mixin class for data processing logic of a socket. """ # These properties are to be set explicitly by node classes # for input sockets, if the node knows it can handle simplified data. # For outputs, these properties are not used. allow_flatten : BoolProperty(default = False) allow_flatten_topology : BoolProperty(default = False) allow_simplify : BoolProperty(default = False) allow_graft : BoolProperty(default = False) allow_unwrap : BoolProperty(default = False) allow_wrap : BoolProperty(default = False) # technical property skip_simplify_mode_update: BoolProperty(default=False) skip_wrap_mode_update: BoolProperty(default=False) use_graft : BoolProperty( name = "Graft", default = False, update = process_from_socket) def update_unwrap_flag(self, context): if self.skip_wrap_mode_update: return try: self.skip_wrap_mode_update = True if self.use_unwrap: self.use_wrap = False finally: self.skip_wrap_mode_update = False process_from_socket(self, context) def update_wrap_flag(self, context): if self.skip_wrap_mode_update: return try: self.skip_wrap_mode_update = True if self.use_wrap: self.use_unwrap = False finally: self.skip_wrap_mode_update = False process_from_socket(self, context) use_unwrap : BoolProperty( name = "Unwrap", default = False, update = update_unwrap_flag) use_wrap : BoolProperty( name = "Wrap", default = False, update = update_wrap_flag) def update_flatten_flag(self, context): if self.skip_simplify_mode_update: return try: self.skip_simplify_mode_update = True if self.use_flatten: self.use_simplify = False finally: self.skip_simplify_mode_update = False process_from_socket(self, context) def update_simplify_flag(self, context): if self.skip_simplify_mode_update: return try: self.skip_simplify_mode_update = True if self.use_simplify: self.use_flatten = False finally: self.skip_simplify_mode_update = False process_from_socket(self, context) use_flatten_topology : BoolProperty( name = "Flatten Topology", default = False, update = process_from_socket) # Only one of properties can be set to true: use_flatten or use_simplfy use_flatten : BoolProperty( name = "Flatten", default = False, update = update_flatten_flag) use_simplify : BoolProperty( name = "Simplify", default = False, update = update_simplify_flag) def get_mode_flags(self): flags = [] if self.use_flatten: flags.append('F') if self.use_flatten_topology: flags.append('FT') if self.use_simplify: flags.append('S') if self.use_graft: flags.append('G') if self.use_unwrap: flags.append('U') if self.use_wrap: flags.append('W') return flags def can_flatten(self): return hasattr(self, 'do_flatten') and (self.allow_flatten or self.is_output) def can_flatten_topology(self): return hasattr(self, 'do_flat_topology') and (self.allow_flatten_topology or self.is_output) def can_simplify(self): return hasattr(self, 'do_simplify') and (self.allow_simplify or self.is_output) def can_graft(self): return hasattr(self, 'do_graft') and (self.is_output or self.allow_graft) def can_unwrap(self): return self.is_output or self.allow_unwrap def can_wrap(self): return self.is_output or self.allow_wrap def draw_simplify_modes(self, layout): if self.can_flatten(): layout.prop(self, 'use_flatten') if self.can_simplify(): layout.prop(self, 'use_simplify') def preprocess_input(self, data): result = data if self.use_flatten: result = self.do_flatten(data) elif self.use_simplify: result = self.do_simplify(data) if self.use_graft: result = self.do_graft(result) if self.use_unwrap: result = unwrap_data(result, socket=self) if self.use_wrap: result = wrap_data(result) return result def postprocess_output(self, data): result = data if self.use_flatten_topology: result = self.do_flat_topology(data) if self.use_flatten: result = self.do_flatten(data) elif self.use_simplify: result = self.do_simplify(data) if self.use_graft: result = self.do_graft(result) if self.use_unwrap: result = unwrap_data(result, socket=self) if self.use_wrap: result = wrap_data(result) return result def has_simplify_modes(self, context): return self.can_flatten() or self.can_simplify() def has_menu(self, context): return self.has_simplify_modes(context) or self.can_graft() or self.can_wrap() def draw_menu_button(self, context, layout, node, text): if hasattr(node.id_data, 'sv_show_socket_menus') and node.id_data.sv_show_socket_menus: if (self.is_output or self.is_linked or not self.use_prop): layout.menu('SV_MT_SocketOptionsMenu', text='', icon='TRIA_DOWN') def draw_menu_items(self, context, layout): if self.can_flatten_topology(): layout.prop(self, 'use_flatten_topology') self.draw_simplify_modes(layout) if self.can_graft(): layout.prop(self, 'use_graft') if self.can_unwrap(): layout.prop(self, 'use_unwrap') if self.can_wrap(): layout.prop(self, 'use_wrap') def copy_options(self, other): for identifier, prop in SvSocketProcessing.__annotations__.items(): if isinstance(prop, bpy.props._PropertyDeferred): setattr(self, identifier, getattr(other, identifier))
Subclasses
Class variables
var allow_flatten : <_PropertyDeferred,
, {'default': False, 'attr': 'allow_flatten'}> var allow_flatten_topology : <_PropertyDeferred,
, {'default': False, 'attr': 'allow_flatten_topology'}> var allow_graft : <_PropertyDeferred,
, {'default': False, 'attr': 'allow_graft'}> var allow_simplify : <_PropertyDeferred,
, {'default': False, 'attr': 'allow_simplify'}> var allow_unwrap : <_PropertyDeferred,
, {'default': False, 'attr': 'allow_unwrap'}> var allow_wrap : <_PropertyDeferred,
, {'default': False, 'attr': 'allow_wrap'}> var skip_simplify_mode_update : <_PropertyDeferred,
, {'default': False, 'attr': 'skip_simplify_mode_update'}> var skip_wrap_mode_update : <_PropertyDeferred,
, {'default': False, 'attr': 'skip_wrap_mode_update'}> var use_flatten : <_PropertyDeferred,
, {'name': 'Flatten', 'default': False, 'update': SvSocketProcessing.update_flatten_flag() at 0x7f2f1d8ec670>, 'attr': 'use_flatten'}> var use_flatten_topology : <_PropertyDeferred,
, {'name': 'Flatten Topology', 'default': False, 'update': process_from_socket() at 0x7f2f1d910e50>, 'attr': 'use_flatten_topology'}> var use_graft : <_PropertyDeferred,
, {'name': 'Graft', 'default': False, 'update': process_from_socket() at 0x7f2f1d910e50>, 'attr': 'use_graft'}> var use_simplify : <_PropertyDeferred,
, {'name': 'Simplify', 'default': False, 'update': SvSocketProcessing.update_simplify_flag() at 0x7f2f1d8ec700>, 'attr': 'use_simplify'}> var use_unwrap : <_PropertyDeferred,
, {'name': 'Unwrap', 'default': False, 'update': SvSocketProcessing.update_unwrap_flag() at 0x7f2f1d8ec550>, 'attr': 'use_unwrap'}> var use_wrap : <_PropertyDeferred,
, {'name': 'Wrap', 'default': False, 'update': SvSocketProcessing.update_wrap_flag() at 0x7f2f1d8ec5e0>, 'attr': 'use_wrap'}>
Methods
def can_flatten(self)
-
Expand source code
def can_flatten(self): return hasattr(self, 'do_flatten') and (self.allow_flatten or self.is_output)
def can_flatten_topology(self)
-
Expand source code
def can_flatten_topology(self): return hasattr(self, 'do_flat_topology') and (self.allow_flatten_topology or self.is_output)
def can_graft(self)
-
Expand source code
def can_graft(self): return hasattr(self, 'do_graft') and (self.is_output or self.allow_graft)
def can_simplify(self)
-
Expand source code
def can_simplify(self): return hasattr(self, 'do_simplify') and (self.allow_simplify or self.is_output)
def can_unwrap(self)
-
Expand source code
def can_unwrap(self): return self.is_output or self.allow_unwrap
def can_wrap(self)
-
Expand source code
def can_wrap(self): return self.is_output or self.allow_wrap
def copy_options(self, other)
-
Expand source code
def copy_options(self, other): for identifier, prop in SvSocketProcessing.__annotations__.items(): if isinstance(prop, bpy.props._PropertyDeferred): setattr(self, identifier, getattr(other, identifier))
-
Expand source code
def draw_menu_button(self, context, layout, node, text): if hasattr(node.id_data, 'sv_show_socket_menus') and node.id_data.sv_show_socket_menus: if (self.is_output or self.is_linked or not self.use_prop): layout.menu('SV_MT_SocketOptionsMenu', text='', icon='TRIA_DOWN')
-
Expand source code
def draw_menu_items(self, context, layout): if self.can_flatten_topology(): layout.prop(self, 'use_flatten_topology') self.draw_simplify_modes(layout) if self.can_graft(): layout.prop(self, 'use_graft') if self.can_unwrap(): layout.prop(self, 'use_unwrap') if self.can_wrap(): layout.prop(self, 'use_wrap')
def draw_simplify_modes(self, layout)
-
Expand source code
def draw_simplify_modes(self, layout): if self.can_flatten(): layout.prop(self, 'use_flatten') if self.can_simplify(): layout.prop(self, 'use_simplify')
def get_mode_flags(self)
-
Expand source code
def get_mode_flags(self): flags = [] if self.use_flatten: flags.append('F') if self.use_flatten_topology: flags.append('FT') if self.use_simplify: flags.append('S') if self.use_graft: flags.append('G') if self.use_unwrap: flags.append('U') if self.use_wrap: flags.append('W') return flags
-
Expand source code
def has_menu(self, context): return self.has_simplify_modes(context) or self.can_graft() or self.can_wrap()
def has_simplify_modes(self, context)
-
Expand source code
def has_simplify_modes(self, context): return self.can_flatten() or self.can_simplify()
def postprocess_output(self, data)
-
Expand source code
def postprocess_output(self, data): result = data if self.use_flatten_topology: result = self.do_flat_topology(data) if self.use_flatten: result = self.do_flatten(data) elif self.use_simplify: result = self.do_simplify(data) if self.use_graft: result = self.do_graft(result) if self.use_unwrap: result = unwrap_data(result, socket=self) if self.use_wrap: result = wrap_data(result) return result
def preprocess_input(self, data)
-
Expand source code
def preprocess_input(self, data): result = data if self.use_flatten: result = self.do_flatten(data) elif self.use_simplify: result = self.do_simplify(data) if self.use_graft: result = self.do_graft(result) if self.use_unwrap: result = unwrap_data(result, socket=self) if self.use_wrap: result = wrap_data(result) return result
def update_flatten_flag(self, context)
-
Expand source code
def update_flatten_flag(self, context): if self.skip_simplify_mode_update: return try: self.skip_simplify_mode_update = True if self.use_flatten: self.use_simplify = False finally: self.skip_simplify_mode_update = False process_from_socket(self, context)
def update_simplify_flag(self, context)
-
Expand source code
def update_simplify_flag(self, context): if self.skip_simplify_mode_update: return try: self.skip_simplify_mode_update = True if self.use_simplify: self.use_flatten = False finally: self.skip_simplify_mode_update = False process_from_socket(self, context)
def update_unwrap_flag(self, context)
-
Expand source code
def update_unwrap_flag(self, context): if self.skip_wrap_mode_update: return try: self.skip_wrap_mode_update = True if self.use_unwrap: self.use_wrap = False finally: self.skip_wrap_mode_update = False process_from_socket(self, context)
def update_wrap_flag(self, context)
-
Expand source code
def update_wrap_flag(self, context): if self.skip_wrap_mode_update: return try: self.skip_wrap_mode_update = True if self.use_wrap: self.use_unwrap = False finally: self.skip_wrap_mode_update = False process_from_socket(self, context)
class SvSolidSocket (...)
-
Base class for all Sockets
'SKIP_SAVE' in properties means skipping them during saving in JSON format some of the properties can be skipped because they are static, they are always set only in sv_init method
Expand source code
class SvSolidSocket(NodeSocket, SvSocketCommon): bl_idname = "SvSolidSocket" bl_label = "Solid Socket" color = (0.0, 0.65, 0.3, 1.0) default_conversion_name = ConversionPolicies.SOLID.conversion_name def do_flatten(self, data): from sverchok.dependencies import FreeCAD import Part return flatten_data(data, 1, data_types=(Part.Shape,)) def do_graft(self, data): from sverchok.dependencies import FreeCAD import Part return graft_data(data, item_level=0, data_types=(Part.Shape,))
Ancestors
- bpy_types.NodeSocket
- builtins.bpy_struct
- SvSocketCommon
- SvSocketProcessing
Class variables
var bl_idname
var bl_label
var bl_rna
var color
var custom_draw : <_PropertyDeferred,
, {'description': 'For name of method which will draw socket UI (optionally)', 'attr': 'custom_draw'}> var default_conversion_name
var default_mode : <_PropertyDeferred,
, {'items': [('NONE', 'NONE', '', 0), ('EMPTY_LIST', 'EMPTY_LIST', '', 1), ('MATRIX', 'MATRIX', '', 2), ('MASK', 'MASK', '', 3)], 'default': 'EMPTY_LIST', 'attr': 'default_mode'}> var description : <_PropertyDeferred,
, {'attr': 'description'}> var is_mandatory : <_PropertyDeferred,
, {'default': False, 'attr': 'is_mandatory'}> var label : <_PropertyDeferred,
, {'attr': 'label'}> var nesting_level : <_PropertyDeferred,
, {'default': 2, 'attr': 'nesting_level'}> var objects_number : <_PropertyDeferred,
, {'min': 0, 'options': {'SKIP_SAVE'}, 'attr': 'objects_number'}> var pre_processing : <_PropertyDeferred,
, {'items': [('NONE', 'NONE', '', 0), ('ONE_ITEM', 'ONE_ITEM', '', 1)], 'default': 'NONE', 'attr': 'pre_processing'}> var prop_name : <_PropertyDeferred,
, {'default': '', 'description': 'For displaying node property in socket UI', 'attr': 'prop_name'}> var s_id : <_PropertyDeferred,
, {'options': {'SKIP_SAVE'}, 'attr': 's_id'}> var use_prop : <_PropertyDeferred,
, {'default': False, 'attr': 'use_prop'}>
Methods
def do_flatten(self, data)
-
Expand source code
def do_flatten(self, data): from sverchok.dependencies import FreeCAD import Part return flatten_data(data, 1, data_types=(Part.Shape,))
def do_graft(self, data)
-
Expand source code
def do_graft(self, data): from sverchok.dependencies import FreeCAD import Part return graft_data(data, item_level=0, data_types=(Part.Shape,))
Inherited members
class SvStringsSocket (...)
-
Generic, mostly numbers, socket type
Expand source code
class SvStringsSocket(SocketDomain, NodeSocket, SvSocketCommon): '''Generic, mostly numbers, socket type''' bl_idname = "SvStringsSocket" bl_label = "Strings Socket" color = (0.6, 1.0, 0.6, 1.0) use_graft_2: BoolProperty( name="Graft Topology", default=False, update=process_from_socket) def get_mode_flags(self): flags = super().get_mode_flags() if self.use_graft_2: flags.append('G2') return flags def get_prop_data(self): prop_name = self.get_prop_name() if prop_name: return {"prop_name": prop_name} elif self.prop_type: return {"prop_type": self.prop_type, "prop_index": self.prop_index} else: return {} quick_link_to_node: StringProperty() # this can be overridden by socket instances default_property_type: bpy.props.EnumProperty( # for internal usage description="Switch between float and int without node updating", items=[(i, i, '') for i in ['float', 'int']]) default_float_property: bpy.props.FloatProperty(update=process_from_socket) default_int_property: bpy.props.IntProperty(update=process_from_socket) show_property_type: BoolProperty( description="Add icon to switch default type") def get_link_parameter_node(self): if self.quick_link_to_node: return self.quick_link_to_node return 'SvNumberNode' def does_support_link_input_menu(self, context, layout, node): ok = super().does_support_link_input_menu(context, layout, node) if not ok: return False return self.name not in {'Edges', 'Polygons', 'Edgs', 'Polys', 'Faces', 'EdgPol', 'Mask', 'EdgesMask', 'FaceMask'} def setup_parameter_node(self, param_node): if param_node.bl_idname == 'SvNumberNode': if self.use_prop or self.get_prop_name(): value = self.sv_get()[0][0] print("V", value) if isinstance(value, int): param_node.selected_mode = 'int' param_node.int_ = value elif isinstance(value, float): param_node.selected_mode = 'float' param_node.float_ = value @property def default_property(self): return self.default_float_property if self.default_property_type == 'float' else self.default_int_property @default_property.setter def default_property(self, value): if hasattr(self.node, 'node_tree'): # belong to group node interface_socket = self.node.node_tree.inputs[self.index] if interface_socket.default_type == 'float': self.default_float_property = value elif interface_socket.default_type == 'int': self.default_int_property = value else: if self.default_property_type == 'float': self.default_float_property = value else: self.default_int_property = value def draw_property(self, layout, prop_origin=None, prop_name=None): if prop_origin and prop_name: layout.prop(prop_origin, prop_name) elif self.use_prop: row = layout.row(align=True) if self.default_property_type == 'float': row.prop(self, 'default_float_property', text=self.name) elif self.default_property_type == 'int': row.prop(self, 'default_int_property', text=self.name) if self.show_property_type: icon = 'IPO_LINEAR' if self.default_property_type == 'float' else 'IPO_CONSTANT' row.operator(SvSwitchDefaultOp.bl_idname, icon=icon, text='') def draw_menu_items(self, context, layout): self.draw_simplify_modes(layout) if self.can_flatten_topology(): layout.prop(self, 'use_flatten_topology') if self.can_graft(): layout.prop(self, 'use_graft') if not self.use_flatten: layout.prop(self, 'use_graft_2') if self.can_unwrap(): layout.prop(self, 'use_unwrap') if self.can_wrap(): layout.prop(self, 'use_wrap') def do_flat_topology(self, data): return flatten_data(data, 3) def do_flatten(self, data): return flatten_data(data, 1) def do_simplify(self, data): return flatten_data(data, 2) def do_graft(self, data): return graft_data(data, item_level=0, data_types = STANDARD_TYPES) def do_graft_2(self, data): def to_zero_base(lst): m = min(lst) return [x - m for x in lst] result = map_at_level(to_zero_base, data, item_level=1, data_types = STANDARD_TYPES) result = graft_data(result, item_level=1, data_types = STANDARD_TYPES) return result def preprocess_input(self, data): result = data if self.use_flatten: result = self.do_flatten(data) elif self.use_simplify: result = self.do_simplify(data) if self.use_graft: result = self.do_graft(result) elif not self.use_flatten and self.use_graft_2: result = self.do_graft_2(result) if self.use_unwrap: result = unwrap_data(result, socket=self) if self.use_wrap: result = wrap_data(result) return result def postprocess_output(self, data): result = data if self.use_flatten_topology: result = self.do_flat_topology(data) if self.use_flatten: result = self.do_flatten(data) elif self.use_simplify: result = self.do_simplify(data) if self.use_graft: result = self.do_graft(result) elif self.use_graft_2: result = self.do_graft_2(result) if self.use_unwrap: result = unwrap_data(result, socket=self) if self.use_wrap: result = wrap_data(result) return result def draw_group_property(self, layout, text, interface_socket): # only for input sockets group node nodes with sub trees if not interface_socket.hide_value: if interface_socket.default_type == 'float': layout.prop(self, 'default_float_property', text=text) elif interface_socket.default_type == 'int': layout.prop(self, 'default_int_property', text=text) else: layout.label(text=text)
Ancestors
- SocketDomain
- bpy_types.NodeSocket
- builtins.bpy_struct
- SvSocketCommon
- SvSocketProcessing
Class variables
var bl_idname
var bl_label
var bl_rna
var color
var default_float_property : <_PropertyDeferred,
, {'update': process_from_socket() at 0x7f2f1d910e50>, 'attr': 'default_float_property'}> var default_int_property : <_PropertyDeferred,
, {'update': process_from_socket() at 0x7f2f1d910e50>, 'attr': 'default_int_property'}> var default_property_type : <_PropertyDeferred,
, {'description': 'Switch between float and int without node updating', 'items': [('float', 'float', ''), ('int', 'int', '')], 'attr': 'default_property_type'}> var quick_link_to_node : <_PropertyDeferred,
, {'attr': 'quick_link_to_node'}> var show_property_type : <_PropertyDeferred,
, {'description': 'Add icon to switch default type', 'attr': 'show_property_type'}> var use_graft_2 : <_PropertyDeferred,
, {'name': 'Graft Topology', 'default': False, 'update': process_from_socket() at 0x7f2f1d910e50>, 'attr': 'use_graft_2'}>
Instance variables
var default_property
-
Expand source code
@property def default_property(self): return self.default_float_property if self.default_property_type == 'float' else self.default_int_property
Methods
def do_flat_topology(self, data)
-
Expand source code
def do_flat_topology(self, data): return flatten_data(data, 3)
def do_flatten(self, data)
-
Expand source code
def do_flatten(self, data): return flatten_data(data, 1)
def do_graft(self, data)
-
Expand source code
def do_graft(self, data): return graft_data(data, item_level=0, data_types = STANDARD_TYPES)
def do_graft_2(self, data)
-
Expand source code
def do_graft_2(self, data): def to_zero_base(lst): m = min(lst) return [x - m for x in lst] result = map_at_level(to_zero_base, data, item_level=1, data_types = STANDARD_TYPES) result = graft_data(result, item_level=1, data_types = STANDARD_TYPES) return result
def do_simplify(self, data)
-
Expand source code
def do_simplify(self, data): return flatten_data(data, 2)
-
Expand source code
def does_support_link_input_menu(self, context, layout, node): ok = super().does_support_link_input_menu(context, layout, node) if not ok: return False return self.name not in {'Edges', 'Polygons', 'Edgs', 'Polys', 'Faces', 'EdgPol', 'Mask', 'EdgesMask', 'FaceMask'}
def draw_group_property(self, layout, text, interface_socket)
-
Expand source code
def draw_group_property(self, layout, text, interface_socket): # only for input sockets group node nodes with sub trees if not interface_socket.hide_value: if interface_socket.default_type == 'float': layout.prop(self, 'default_float_property', text=text) elif interface_socket.default_type == 'int': layout.prop(self, 'default_int_property', text=text) else: layout.label(text=text)
-
Expand source code
def draw_menu_items(self, context, layout): self.draw_simplify_modes(layout) if self.can_flatten_topology(): layout.prop(self, 'use_flatten_topology') if self.can_graft(): layout.prop(self, 'use_graft') if not self.use_flatten: layout.prop(self, 'use_graft_2') if self.can_unwrap(): layout.prop(self, 'use_unwrap') if self.can_wrap(): layout.prop(self, 'use_wrap')
def get_link_parameter_node(self)
-
Expand source code
def get_link_parameter_node(self): if self.quick_link_to_node: return self.quick_link_to_node return 'SvNumberNode'
def get_mode_flags(self)
-
Expand source code
def get_mode_flags(self): flags = super().get_mode_flags() if self.use_graft_2: flags.append('G2') return flags
def get_prop_data(self)
-
Expand source code
def get_prop_data(self): prop_name = self.get_prop_name() if prop_name: return {"prop_name": prop_name} elif self.prop_type: return {"prop_type": self.prop_type, "prop_index": self.prop_index} else: return {}
def postprocess_output(self, data)
-
Expand source code
def postprocess_output(self, data): result = data if self.use_flatten_topology: result = self.do_flat_topology(data) if self.use_flatten: result = self.do_flatten(data) elif self.use_simplify: result = self.do_simplify(data) if self.use_graft: result = self.do_graft(result) elif self.use_graft_2: result = self.do_graft_2(result) if self.use_unwrap: result = unwrap_data(result, socket=self) if self.use_wrap: result = wrap_data(result) return result
def preprocess_input(self, data)
-
Expand source code
def preprocess_input(self, data): result = data if self.use_flatten: result = self.do_flatten(data) elif self.use_simplify: result = self.do_simplify(data) if self.use_graft: result = self.do_graft(result) elif not self.use_flatten and self.use_graft_2: result = self.do_graft_2(result) if self.use_unwrap: result = unwrap_data(result, socket=self) if self.use_wrap: result = wrap_data(result) return result
def setup_parameter_node(self, param_node)
-
Expand source code
def setup_parameter_node(self, param_node): if param_node.bl_idname == 'SvNumberNode': if self.use_prop or self.get_prop_name(): value = self.sv_get()[0][0] print("V", value) if isinstance(value, int): param_node.selected_mode = 'int' param_node.int_ = value elif isinstance(value, float): param_node.selected_mode = 'float' param_node.float_ = value
Inherited members
class SvStringsSocketInterface (...)
-
This socket will be created in tree.inputs to tree.outputs collection when normal socket will be connected to input or output group nodes
Expand source code
class SvStringsSocketInterface(bpy.types.NodeSocketInterface): """ This socket will be created in tree.inputs to tree.outputs collection when normal socket will be connected to input or output group nodes """ bl_idname = "SvStringsSocketInterface" bl_socket_idname = "SvStringsSocket" bl_label = "Number" color = SvStringsSocket.color default_float_value: bpy.props.FloatProperty(name='Default value') default_int_value: bpy.props.IntProperty(name='Default value') default_type: bpy.props.EnumProperty(items=[(i, i, '') for i in ['float', 'int']], update=update_interface) @property def default_value(self): return self.default_float_value if self.default_type == 'float' else self.default_int_value def draw_color(self, context): return self.color def draw(self, context, layout): layout.prop(self, 'hide_value') layout.prop(self, 'default_type', expand=True) if self.default_type == 'float': layout.prop(self, 'default_float_value') elif self.default_type == 'int': layout.prop(self, 'default_int_value')
Ancestors
- bpy_types.NodeSocketInterface
- builtins.bpy_struct
Class variables
var bl_idname
var bl_label
var bl_rna
var bl_socket_idname
var color
var default_float_value : <_PropertyDeferred,
, {'name': 'Default value', 'attr': 'default_float_value'}> var default_int_value : <_PropertyDeferred,
, {'name': 'Default value', 'attr': 'default_int_value'}> var default_type : <_PropertyDeferred,
, {'items': [('float', 'float', ''), ('int', 'int', '')], 'update': update_interface() at 0x7f2f1d8ec1f0>, 'attr': 'default_type'}>
Instance variables
var default_value
-
Expand source code
@property def default_value(self): return self.default_float_value if self.default_type == 'float' else self.default_int_value
Methods
def draw(self, context, layout)
-
Expand source code
def draw(self, context, layout): layout.prop(self, 'hide_value') layout.prop(self, 'default_type', expand=True) if self.default_type == 'float': layout.prop(self, 'default_float_value') elif self.default_type == 'int': layout.prop(self, 'default_int_value')
def draw_color(self, context)
-
Expand source code
def draw_color(self, context): return self.color
class SvSurfaceSocket (...)
-
Base class for all Sockets
'SKIP_SAVE' in properties means skipping them during saving in JSON format some of the properties can be skipped because they are static, they are always set only in sv_init method
Expand source code
class SvSurfaceSocket(NodeSocket, SvSocketCommon): bl_idname = "SvSurfaceSocket" bl_label = "Surface Socket" color = (0.4, 0.2, 1.0, 1.0) def do_flatten(self, data): return flatten_data(data, 1, data_types=(SvSurface,)) def do_graft(self, data): return graft_data(data, item_level=0, data_types=(SvSurface,))
Ancestors
- bpy_types.NodeSocket
- builtins.bpy_struct
- SvSocketCommon
- SvSocketProcessing
Class variables
var bl_idname
var bl_label
var bl_rna
var color
var custom_draw : <_PropertyDeferred,
, {'description': 'For name of method which will draw socket UI (optionally)', 'attr': 'custom_draw'}> var default_mode : <_PropertyDeferred,
, {'items': [('NONE', 'NONE', '', 0), ('EMPTY_LIST', 'EMPTY_LIST', '', 1), ('MATRIX', 'MATRIX', '', 2), ('MASK', 'MASK', '', 3)], 'default': 'EMPTY_LIST', 'attr': 'default_mode'}> var description : <_PropertyDeferred,
, {'attr': 'description'}> var is_mandatory : <_PropertyDeferred,
, {'default': False, 'attr': 'is_mandatory'}> var label : <_PropertyDeferred,
, {'attr': 'label'}> var nesting_level : <_PropertyDeferred,
, {'default': 2, 'attr': 'nesting_level'}> var objects_number : <_PropertyDeferred,
, {'min': 0, 'options': {'SKIP_SAVE'}, 'attr': 'objects_number'}> var pre_processing : <_PropertyDeferred,
, {'items': [('NONE', 'NONE', '', 0), ('ONE_ITEM', 'ONE_ITEM', '', 1)], 'default': 'NONE', 'attr': 'pre_processing'}> var prop_name : <_PropertyDeferred,
, {'default': '', 'description': 'For displaying node property in socket UI', 'attr': 'prop_name'}> var s_id : <_PropertyDeferred,
, {'options': {'SKIP_SAVE'}, 'attr': 's_id'}> var use_prop : <_PropertyDeferred,
, {'default': False, 'attr': 'use_prop'}>
Methods
def do_flatten(self, data)
-
Expand source code
def do_flatten(self, data): return flatten_data(data, 1, data_types=(SvSurface,))
def do_graft(self, data)
-
Expand source code
def do_graft(self, data): return graft_data(data, item_level=0, data_types=(SvSurface,))
Inherited members
class SvSvgSocket (...)
-
For file path data
Expand source code
class SvSvgSocket(NodeSocket, SvSocketCommon): '''For file path data''' bl_idname = "SvSvgSocket" bl_label = "SVG Data Socket" color = (0.1, 0.5, 1, 1.0) @property def quick_link_to_node(self): if "Fill / Stroke" in self.name: return "SvSvgFillStrokeNodeMk2" if "Pattern" in self.name: return "SvSvgPatternNode" return
Ancestors
- bpy_types.NodeSocket
- builtins.bpy_struct
- SvSocketCommon
- SvSocketProcessing
Class variables
var bl_idname
var bl_label
var bl_rna
var color
var custom_draw : <_PropertyDeferred,
, {'description': 'For name of method which will draw socket UI (optionally)', 'attr': 'custom_draw'}> var default_mode : <_PropertyDeferred,
, {'items': [('NONE', 'NONE', '', 0), ('EMPTY_LIST', 'EMPTY_LIST', '', 1), ('MATRIX', 'MATRIX', '', 2), ('MASK', 'MASK', '', 3)], 'default': 'EMPTY_LIST', 'attr': 'default_mode'}> var description : <_PropertyDeferred,
, {'attr': 'description'}> var is_mandatory : <_PropertyDeferred,
, {'default': False, 'attr': 'is_mandatory'}> var label : <_PropertyDeferred,
, {'attr': 'label'}> var nesting_level : <_PropertyDeferred,
, {'default': 2, 'attr': 'nesting_level'}> var objects_number : <_PropertyDeferred,
, {'min': 0, 'options': {'SKIP_SAVE'}, 'attr': 'objects_number'}> var pre_processing : <_PropertyDeferred,
, {'items': [('NONE', 'NONE', '', 0), ('ONE_ITEM', 'ONE_ITEM', '', 1)], 'default': 'NONE', 'attr': 'pre_processing'}> var prop_name : <_PropertyDeferred,
, {'default': '', 'description': 'For displaying node property in socket UI', 'attr': 'prop_name'}> var s_id : <_PropertyDeferred,
, {'options': {'SKIP_SAVE'}, 'attr': 's_id'}> var use_prop : <_PropertyDeferred,
, {'default': False, 'attr': 'use_prop'}>
Instance variables
var quick_link_to_node
-
str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.str() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to 'strict'.
Expand source code
@property def quick_link_to_node(self): if "Fill / Stroke" in self.name: return "SvSvgFillStrokeNodeMk2" if "Pattern" in self.name: return "SvSvgPatternNode" return
Inherited members
class SvSwitchDefaultOp (...)
-
Either Float or Integer
Expand source code
class SvSwitchDefaultOp(bpy.types.Operator): """Either Float or Integer""" bl_idname = "node.sv_switch_default" bl_label = "Switch default value of string socket" bl_options = {'INTERNAL', 'REGISTER'} @classmethod def poll(cls, context): return hasattr(context, 'socket') def execute(self, context): s = context.socket s.default_property_type = 'float' if s.default_property_type == 'int' else 'int' process_from_socket(s, context) return {'FINISHED'}
Ancestors
- bpy_types.Operator
- builtins.bpy_struct
Class variables
var bl_idname
var bl_label
var bl_options
var bl_rna
Static methods
def poll(context)
-
Expand source code
@classmethod def poll(cls, context): return hasattr(context, 'socket')
Methods
def execute(self, context)
-
Expand source code
def execute(self, context): s = context.socket s.default_property_type = 'float' if s.default_property_type == 'int' else 'int' process_from_socket(s, context) return {'FINISHED'}
class SvTextSocket (...)
-
Base class for all Sockets
'SKIP_SAVE' in properties means skipping them during saving in JSON format some of the properties can be skipped because they are static, they are always set only in sv_init method
Expand source code
class SvTextSocket(NodeSocket, SvSocketCommon): bl_idname = "SvTextSocket" bl_label = "Text Socket" color = (0.68, 0.85, 0.90, 1) quick_link_to_node: StringProperty() default_property: StringProperty(update=process_from_socket) default_conversion_name = ConversionPolicies.LENIENT.conversion_name
Ancestors
- bpy_types.NodeSocket
- builtins.bpy_struct
- SvSocketCommon
- SvSocketProcessing
Class variables
var bl_idname
var bl_label
var bl_rna
var color
var default_conversion_name
var default_property : <_PropertyDeferred,
, {'update': process_from_socket() at 0x7f2f1d910e50>, 'attr': 'default_value'}> var quick_link_to_node : <_PropertyDeferred,
, {'attr': 'quick_link_to_node'}>
Inherited members
class SvTextureSocket (...)
-
Base class for all Sockets
'SKIP_SAVE' in properties means skipping them during saving in JSON format some of the properties can be skipped because they are static, they are always set only in sv_init method
Expand source code
class SvTextureSocket(NodeSocket, SvSocketCommon): bl_idname = "SvTextureSocket" bl_label = "Texture Socket" color = (0.62, 0.31, 0.64, 1.0) default_property: PointerProperty( name="Texture", type=bpy.types.Texture, update=process_from_socket)
Ancestors
- bpy_types.NodeSocket
- builtins.bpy_struct
- SvSocketCommon
- SvSocketProcessing
Class variables
var bl_idname
var bl_label
var bl_rna
var color
var default_property : <_PropertyDeferred,
, {'name': 'Texture', 'type': , 'update': process_from_socket() at 0x7f2f1d910e50>, 'attr': 'default_value'}>
Inherited members
class SvVectorFieldSocket (...)
-
Base class for all Sockets
'SKIP_SAVE' in properties means skipping them during saving in JSON format some of the properties can be skipped because they are static, they are always set only in sv_init method
Expand source code
class SvVectorFieldSocket(NodeSocket, SvSocketCommon): bl_idname = "SvVectorFieldSocket" bl_label = "Vector Field Socket" quick_link_to_node = 'GenVectorsNode' color = (0.1, 0.1, 0.9, 1.0) default_conversion_name = ConversionPolicies.FIELD.conversion_name def do_flatten(self, data): return flatten_data(data, 1, data_types=(SvVectorField,)) def do_graft(self, data): return graft_data(data, item_level=0, data_types=(SvVectorField,))
Ancestors
- bpy_types.NodeSocket
- builtins.bpy_struct
- SvSocketCommon
- SvSocketProcessing
Class variables
var bl_idname
var bl_label
var bl_rna
var color
var custom_draw : <_PropertyDeferred,
, {'description': 'For name of method which will draw socket UI (optionally)', 'attr': 'custom_draw'}> var default_conversion_name
var default_mode : <_PropertyDeferred,
, {'items': [('NONE', 'NONE', '', 0), ('EMPTY_LIST', 'EMPTY_LIST', '', 1), ('MATRIX', 'MATRIX', '', 2), ('MASK', 'MASK', '', 3)], 'default': 'EMPTY_LIST', 'attr': 'default_mode'}> var description : <_PropertyDeferred,
, {'attr': 'description'}> var is_mandatory : <_PropertyDeferred,
, {'default': False, 'attr': 'is_mandatory'}> var label : <_PropertyDeferred,
, {'attr': 'label'}> var nesting_level : <_PropertyDeferred,
, {'default': 2, 'attr': 'nesting_level'}> var objects_number : <_PropertyDeferred,
, {'min': 0, 'options': {'SKIP_SAVE'}, 'attr': 'objects_number'}> var pre_processing : <_PropertyDeferred,
, {'items': [('NONE', 'NONE', '', 0), ('ONE_ITEM', 'ONE_ITEM', '', 1)], 'default': 'NONE', 'attr': 'pre_processing'}> var prop_name : <_PropertyDeferred,
, {'default': '', 'description': 'For displaying node property in socket UI', 'attr': 'prop_name'}> var quick_link_to_node
var s_id : <_PropertyDeferred,
, {'options': {'SKIP_SAVE'}, 'attr': 's_id'}> var use_prop : <_PropertyDeferred,
, {'default': False, 'attr': 'use_prop'}>
Methods
def do_flatten(self, data)
-
Expand source code
def do_flatten(self, data): return flatten_data(data, 1, data_types=(SvVectorField,))
def do_graft(self, data)
-
Expand source code
def do_graft(self, data): return graft_data(data, item_level=0, data_types=(SvVectorField,))
Inherited members
class SvVerticesSocket (...)
-
For vertex data
Expand source code
class SvVerticesSocket(SocketDomain, NodeSocket, SvSocketCommon): '''For vertex data''' bl_idname = "SvVerticesSocket" bl_label ="Vertices Socket" color = (0.9, 0.6, 0.2, 1.0) quick_link_to_node = 'GenVectorsNode' nesting_level: IntProperty(default=3) def setup_parameter_node(self, param_node): if self.use_prop or self.get_prop_name(): value = self.sv_get()[0][0] param_node.x_ = value[0] param_node.y_ = value[1] param_node.z_ = value[2] # this property is needed for back capability, after renaming prop to default_property # should be removed after https://github.com/nortikin/sverchok/issues/3514 # using via default_property property prop: FloatVectorProperty(default=(0, 0, 0), size=3, update=process_from_socket) expanded: BoolProperty(default=False) # for minimizing showing socket property def do_simplify(self, data): return flatten_data(data, 2) def do_flat_topology(self, data): return flatten_data(data, 3) @property def default_property(self): return self.prop @default_property.setter def default_property(self, value): self.prop = value def draw_property(self, layout, prop_origin=None, prop_name='prop'): if prop_origin is None: prop_origin = self split = layout.split(factor=.2, align=True) c1 = split.column(align=True) c2 = split.column(align=True) if self.expanded: c1.prop(self, "expanded", icon='TRIA_UP', text='') c1.label(text=self.name[0]) c2.prop(prop_origin, prop_name, text="", expand=True) else: c1.prop(self, "expanded", icon='TRIA_DOWN', text="") row = c2.row(align=True) row.template_component_menu(prop_origin, prop_name, name=self.name) def do_graft(self, data): return graft_data(data, item_level=1) def draw_group_property(self, layout, text, interface_socket): if not interface_socket.hide_value: layout.template_component_menu(self, 'prop', name=text) else: layout.label(text=text) def does_support_link_input_menu(self, context, layout, node): ok = super().does_support_link_input_menu(context, layout, node) if not ok: return False return self.name not in {'Vertices', 'Verts'}
Ancestors
- SocketDomain
- bpy_types.NodeSocket
- builtins.bpy_struct
- SvSocketCommon
- SvSocketProcessing
Class variables
var bl_idname
var bl_label
var bl_rna
var color
var expanded : <_PropertyDeferred,
, {'default': False, 'attr': 'expanded'}> var nesting_level : <_PropertyDeferred,
, {'default': 3, 'attr': 'nesting_level'}> var prop : <_PropertyDeferred,
, {'default': (0, 0, 0), 'size': 3, 'update': process_from_socket() at 0x7f2f1d910e50>, 'attr': 'prop'}> var quick_link_to_node
Instance variables
var default_property
-
Expand source code
@property def default_property(self): return self.prop
Methods
def do_flat_topology(self, data)
-
Expand source code
def do_flat_topology(self, data): return flatten_data(data, 3)
def do_graft(self, data)
-
Expand source code
def do_graft(self, data): return graft_data(data, item_level=1)
def do_simplify(self, data)
-
Expand source code
def do_simplify(self, data): return flatten_data(data, 2)
-
Expand source code
def does_support_link_input_menu(self, context, layout, node): ok = super().does_support_link_input_menu(context, layout, node) if not ok: return False return self.name not in {'Vertices', 'Verts'}
def draw_group_property(self, layout, text, interface_socket)
-
Expand source code
def draw_group_property(self, layout, text, interface_socket): if not interface_socket.hide_value: layout.template_component_menu(self, 'prop', name=text) else: layout.label(text=text)
def setup_parameter_node(self, param_node)
-
Expand source code
def setup_parameter_node(self, param_node): if self.use_prop or self.get_prop_name(): value = self.sv_get()[0][0] param_node.x_ = value[0] param_node.y_ = value[1] param_node.z_ = value[2]
Inherited members
class SvVerticesSocketInterface (...)
-
This socket will be created in tree.inputs to tree.outputs collection when normal socket will be connected to input or output group nodes
Expand source code
class SvVerticesSocketInterface(bpy.types.NodeSocketInterface): """ This socket will be created in tree.inputs to tree.outputs collection when normal socket will be connected to input or output group nodes """ # The only reason of existing this class # is that `prop` attribute of VerticesSocket can't be renamed to `default_property bl_idname = "SvVerticesSocketInterface" bl_socket_idname = "SvVerticesSocket" bl_label = "Vertices" color = SvVerticesSocket.color default_value: FloatVectorProperty(name="Default value", default=(0, 0, 0), size=3) def draw_color(self, context): return self.color def draw(self, context, layout): col = layout.column() col.prop(self, 'default_value') col.prop(self, 'hide_value')
Ancestors
- bpy_types.NodeSocketInterface
- builtins.bpy_struct
Class variables
var bl_idname
var bl_label
var bl_rna
var bl_socket_idname
var color
var default_value : <_PropertyDeferred,
, {'name': 'Default value', 'default': (0, 0, 0), 'size': 3, 'attr': 'default_value'}>
Methods
def draw(self, context, layout)
-
Expand source code
def draw(self, context, layout): col = layout.column() col.prop(self, 'default_value') col.prop(self, 'hide_value')
def draw_color(self, context)
-
Expand source code
def draw_color(self, context): return self.color