Beispiel #1
0
    def node_replacement_menu(self, context, layout):
        """
        Draw menu items with node replacement operators.
        This is called from `rclick_menu()' method by default.
        Items are defined by `replacement_nodes' class property.
        Expected format is

            replacement_nodes = [
                (new_node_bl_idname, inputs_mapping_dict, outputs_mapping_dict)
            ]

        where new_node_bl_idname is bl_idname of replacement node class,
        inputs_mapping_dict is a dictionary mapping names of inputs of this node
        to names of inputs to new node, and outputs_mapping_dict is a dictionary
        mapping names of outputs of this node to names of outputs of new node.
        inputs_mapping_dict and outputs_mapping_dict can be None.
        """
        if hasattr(self, "replacement_nodes"):
            for bl_idname, inputs_mapping, outputs_mapping in self.replacement_nodes:
                node_class = get_node_class_reference(bl_idname)
                text = "Replace with {}".format(node_class.bl_label)
                op = layout.operator("node.sv_replace_node", text=text)
                op.old_node_name = self.name
                op.new_bl_idname = bl_idname
                set_inputs_mapping(op, inputs_mapping)
                set_outputs_mapping(op, outputs_mapping)
Beispiel #2
0
    def node_replacement_menu(self, context, layout):
        """
        Draw menu items with node replacement operators.
        This is called from `rclick_menu()' method by default.
        Items are defined by `replacement_nodes' class property.
        Expected format is

            replacement_nodes = [
                (new_node_bl_idname, inputs_mapping_dict, outputs_mapping_dict)
            ]

        where new_node_bl_idname is bl_idname of replacement node class,
        inputs_mapping_dict is a dictionary mapping names of inputs of this node
        to names of inputs to new node, and outputs_mapping_dict is a dictionary
        mapping names of outputs of this node to names of outputs of new node.
        inputs_mapping_dict and outputs_mapping_dict can be None.
        """
        if hasattr(self, "replacement_nodes"):
            for bl_idname, inputs_mapping, outputs_mapping in self.replacement_nodes:
                node_class = get_node_class_reference(bl_idname)
                if node_class:
                    text = "Replace with {}".format(node_class.bl_label)
                    op = layout.operator("node.sv_replace_node", text=text)
                    op.old_node_name = self.name
                    op.new_bl_idname = bl_idname
                    set_inputs_mapping(op, inputs_mapping)
                    set_outputs_mapping(op, outputs_mapping)
                else:
                    self.error("Can't build replacement menu: no such node class: %s",bl_idname)
Beispiel #3
0
def layout_draw_categories(layout, node_details):

    for node_info in node_details:

        if node_info[0] == 'separator':
            layout.separator()
            continue

        if not node_info:
            print(repr(node_info), 'is incomplete, or unparsable')
            continue

        bl_idname = node_info[0]
        node_ref = get_node_class_reference(bl_idname)

        if hasattr(node_ref, "bl_label"):
            layout_params = dict(text=node_ref.bl_label, **node_icon(node_ref))
        elif bl_idname == 'NodeReroute':
            layout_params = dict(text='Reroute')
        else:
            continue

        node_op = draw_add_node_operator(layout,
                                         bl_idname,
                                         params=layout_params)
Beispiel #4
0
def make_categories():
    original_categories = make_node_cats()

    node_cats = juggle_and_join(original_categories)
    node_cats = include_submenus(node_cats)
    node_categories = []
    node_count = 0
    for category, nodes in node_cats.items():
        name_big = "SVERCHOK_" + category.replace(' ', '_')
        node_items = []
        for item in nodes:
            nodetype = item[0]
            if is_submenu_call(nodetype):
                continue
            rna = get_node_class_reference(nodetype)
            if not rna and not nodetype == 'separator':
                logger.info(
                    "Node `%s' is not available (probably due to missing dependencies).",
                    nodetype)
            else:
                node_item = SverchNodeItem.new(nodetype)
                node_items.append(node_item)

        if node_items:
            node_categories.append(
                SverchNodeCategory(name_big, category, items=node_items))
            node_count += len(nodes)
    node_categories.append(
        SverchNodeCategory("SVERCHOK_MONAD", "Monad", items=sv_group_items))
    SverchNodeItem.new('SvMonadInfoNode')
    return node_categories, node_count, original_categories
Beispiel #5
0
def draw_add_node_operator(layout, nodetype, label=None, icon_name=None, params=None):
    """
    Draw node adding operator button.
    This is to be used both in Shift-A menu and in T panel.
    """

    default_context = bpy.app.translations.contexts.default
    node_class = get_node_class_reference(nodetype)
    if node_class is None:
        info("cannot locate node class: %s", nodetype)
        return
    node_rna = node_class.bl_rna

    if label is None:
        if hasattr(node_rna, 'bl_label'):
            label = node_rna.bl_label
        elif nodetype == "NodeReroute":
            label = "Reroute"
        else:
            label = node_rna.name

    if params is None:
        params = dict(text=label)
    params['text_ctxt'] = default_context
    if icon_name is not None:
        params.update(**icon(icon_name))
    else:
        params.update(**node_icon(node_rna))

    add = layout.operator("node.sv_add_" + get_node_idname_for_operator(nodetype), **params)

    add.type = nodetype
    add.use_transform = True

    return add
Beispiel #6
0
def gather_items(context):
    fx = []
    idx = 0
    for _, node_list in node_cats.items():
        for item in node_list:
            if item[0] in {'separator', 'NodeReroute'}:
                continue

            nodetype = get_node_class_reference(item[0])
            if not nodetype:
                continue

            docstring = ensure_valid_show_string(nodetype)
            if not docstring:
                continue

            fx.append((str(idx), docstring, '', idx))
            idx += 1

    for k, v in macros.items():
        fx.append((k, format_item(k, v), '', idx))
        idx += 1

    gather_extra_nodes(idx, fx, context)
    fx_extend(idx, fx)

    return fx
Beispiel #7
0
def draw_add_node_operator(layout, nodetype, label=None, icon_name=None, params=None):
    """
    Draw node adding operator button.
    This is to be used both in Shift-A menu and in T panel.
    """

    default_context = bpy.app.translations.contexts.default
    node_rna = get_node_class_reference(nodetype).bl_rna

    if label is None:
        if hasattr(node_rna, 'bl_label'):
            label = node_rna.bl_label
        elif nodetype == "NodeReroute":
            label = "Reroute"
        else:
            label = node_rna.name

    if params is None:
        params = dict(text=label)
    params['text_ctxt'] = default_context
    if icon_name is not None:
        params.update(**icon(icon_name))
    else:
        params.update(**node_icon(node_rna))

    add = layout.operator("node.sv_add_" + get_node_idname_for_operator(nodetype), **params)
                            
    add.type = nodetype
    add.use_transform = True

    return add
Beispiel #8
0
def make_categories():
    original_categories = make_node_cats()

    node_cats = juggle_and_join(original_categories)
    node_cats = include_submenus(node_cats)
    node_categories = []
    node_count = 0

    nodes_not_enabled = defaultdict(list)

    for category, nodes in node_cats.items():
        name_big = "SVERCHOK_" + category.replace(' ', '_')
        node_items = []
        for item in nodes:
            nodetype = item[0]
            if is_submenu_call(nodetype):
                continue
            rna = get_node_class_reference(nodetype)
            if not rna and not nodetype == 'separator':
                nodes_not_enabled[category].append(nodetype)
            else:
                node_item = SverchNodeItem.new(nodetype)
                node_items.append(node_item)

        if node_items:
            node_categories.append(
                SverchNodeCategory(name_big, category, items=node_items))
            node_count += len(nodes)

    # logger.info(f"The following nodes are not enabled (probably due to missing dependencies)\n{strformated_tree(nodes_not_enabled)}")
    temp_details['not_enabled_nodes'] = nodes_not_enabled

    return node_categories, node_count, original_categories
Beispiel #9
0
def make_categories():
    original_categories = make_node_cats()

    node_cats = juggle_and_join(original_categories)
    node_categories = []
    node_count = 0
    for category, nodes in node_cats.items():
        name_big = "SVERCHOK_" + category.replace(' ', '_')
        node_items = []
        for item in nodes:
            nodetype = item[0]
            rna = get_node_class_reference(nodetype)
            if not rna and not nodetype == 'separator':
                info(
                    "Node `%s' is not available (probably due to missing dependencies).",
                    nodetype)
            else:
                node_item = SverchNodeItem.new(nodetype)
                node_items.append(node_item)

        if node_items:
            node_categories.append(
                SverchNodeCategory(name_big, category, items=node_items))
            node_count += len(nodes)
    node_categories.append(
        SverchNodeCategory("SVERCHOK_GROUPS", "Groups", items=sv_group_items))

    return node_categories, node_count, original_categories
Beispiel #10
0
def category_has_nodes(cat_name):
    cat = node_cats[cat_name]
    for item in cat:
        rna = get_node_class_reference(item[0])
        if rna and not item[0] == 'separator':
            return True
    return False
Beispiel #11
0
def layout_draw_categories(layout, node_details):

    for node_info in node_details:

        if node_info[0] == 'separator':
            layout.separator()
            continue

        if not node_info:
            print(repr(node_info), 'is incomplete, or unparsable')
            continue

        bl_idname = node_info[0]

        # this is a node bl_idname that can be registered but shift+A can drop it from showing.
        if bl_idname == 'ScalarMathNode':
            continue

        node_ref = get_node_class_reference(bl_idname)

        if hasattr(node_ref, "bl_label"):
            layout_params = dict(text=node_ref.bl_label, **node_icon(node_ref))
        elif bl_idname == 'NodeReroute':
            layout_params = dict(text='Reroute',icon_value=custom_icon('SV_REROUTE'))
        else:
            continue

        node_op = draw_add_node_operator(layout, bl_idname, params=layout_params)
def layout_draw_categories(layout, node_details):

    for node_info in node_details:

        if node_info[0] == 'separator':
            layout.separator()
            continue

        if not node_info:
            print(repr(node_info), 'is incomplete, or unparsable')
            continue

        bl_idname = node_info[0]

        # this is a node bl_idname that can be registered but shift+A can drop it from showing.
        if bl_idname == 'ScalarMathNode':
            continue

        node_ref = get_node_class_reference(bl_idname)

        if hasattr(node_ref, "bl_label"):
            layout_params = dict(text=node_ref.bl_label, **node_icon(node_ref))
        elif bl_idname == 'NodeReroute':
            layout_params = dict(text='Reroute')
        else:
            continue

        node_op = draw_add_node_operator(layout, bl_idname, params=layout_params)
Beispiel #13
0
    def draw(self, context):

        if context is None:
            return
        space = context.space_data
        if not space:
            return
        ntree = space.edit_tree
        if not ntree:
            return
        layout = self.layout

        monad_node_ops(self, layout, context)

        if ntree.bl_idname == "SverchGroupTreeType":
            draw_add_node_operator(layout, "SvMonadInfoNode")
            layout.separator()

        for monad in context.blend_data.node_groups:
            if monad.bl_idname != "SverchGroupTreeType":
                continue
            if monad.name == ntree.name:
                continue
            # make sure class exists
            cls_ref = get_node_class_reference(monad.cls_bl_idname)

            if cls_ref and monad.cls_bl_idname and monad.cls_bl_idname:
                op = layout.operator('node.add_node', text=monad.name)
                op.type = monad.cls_bl_idname
                op.use_transform = True
Beispiel #14
0
def add_nodes_to_sv():
    index = nodes_index()
    for _, items in index:
        for item in items:
            nodetype = item[1]
            rna = get_node_class_reference(nodetype)
            if not rna and nodetype != 'separator':
                info("Node `%s' is not available (probably due to missing dependencies).", nodetype)
            else:
                SverchNodeItem.new(nodetype)
Beispiel #15
0
def get_node_idname_for_operator(nodetype):
    """Select valid bl_idname for node to create node adding operator bl_idname."""
    rna = get_node_class_reference(nodetype)
    if not rna:
        raise Exception("Can't find registered node {}".format(nodetype))
    if hasattr(rna, 'bl_idname'):
        return rna.bl_idname.lower()
    elif nodetype == "NodeReroute":
        return "node_reroute"
    else:
        return rna.name.lower()
Beispiel #16
0
def get_node_idname_for_operator(nodetype):
    """Select valid bl_idname for node to create node adding operator bl_idname."""
    rna = get_node_class_reference(nodetype)
    if not rna:
        raise Exception("Can't find registered node {}".format(nodetype))
    if hasattr(rna, 'bl_idname'):
        return rna.bl_idname.lower()
    elif nodetype == "NodeReroute":
        return "node_reroute"
    else:
        return rna.name.lower()
Beispiel #17
0
    def add_prop_from(self, socket):
        """
        Add a property if possible
        """
        other = socket.other
        cls = get_node_class_reference(self.cls_bl_idname)
        cls_dict = cls.__dict__ if cls else {}

        if other.prop_name:
            prop_name = other.prop_name

            # prop_func, prop_dict = getattr(other.node.rna_type, prop_name, ("", {}))  # <-- in 2.79
            prop_func, prop_dict = other.node.__annotations__.get(
                prop_name, ("", {}))

            if prop_func.__name__ == "FloatProperty":
                self.get_current_as_default(prop_dict, other.node, prop_name)
                prop_settings = self.float_props.add()
            elif prop_func.__name__ == "IntProperty":
                self.get_current_as_default(prop_dict, other.node, prop_name)
                prop_settings = self.int_props.add()
            elif prop_func.__name__ == "FloatVectorProperty":
                info(
                    "FloatVectorProperty ignored (normal behaviour since day one). prop_func: %s, prop_dict: %s.",
                    prop_func, prop_dict)
                return None  # for now etc
            else:  # no way to handle it
                return None

            # print('dict')
            # pprint.pprint(prop_dict)
            new_name = generate_name(prop_name, cls_dict)
            prop_settings.prop_name = new_name
            prop_settings.set_settings(prop_dict)
            socket.prop_name = new_name
            return new_name

        elif hasattr(other, "prop_type"):
            if "float" in other.prop_type:
                prop_settings = self.float_props.add()
            elif "int" in other.prop_type:
                prop_settings = self.int_props.add()
            else:
                return None

            new_name = generate_name(make_valid_identifier(other.name),
                                     cls_dict)
            prop_settings.prop_name = new_name
            prop_settings.set_settings({"name": other.name})
            socket.prop_name = new_name
            return new_name

        return None
Beispiel #18
0
def idname_draw(self, context):
    if not displaying_sverchok_nodes(context):
        return
    layout = self.layout
    node = context.active_node
    if not node:
        return
    bl_idname = node.bl_idname
    box = layout.box()
    col = box.column(align=False)
    col.scale_y = 0.9
    row = col.row(align=True)
    colom = row.column(align=True)
    colom.scale_x = 3
    colom.label(text=bl_idname + ':')
    colom = row.column(align=True)
    colom.operator('node.copy_bl_idname', text='',
                   icon='COPY_ID').name = bl_idname

    # show these anyway, can fail and let us know..
    row = col.row(align=True)
    row.label(text='Help & Docs:')
    row = col.row(align=True)
    row.operator('node.view_node_help', text='Online').kind = 'online'
    row.operator('node.view_node_help', text='Offline').kind = 'offline'
    row.operator('node.view_node_help',
                 text='Github').kind = 'github'  #, icon='GHOST'
    col.separator()
    # view the source of the current node ( warning, some nodes rely on more than one file )
    row = col.row(align=True)
    row.label(text='Edit Source:')
    row = col.row(align=True)
    row.operator('node.sv_view_node_source',
                 text='Externally').kind = 'external'
    row.operator('node.sv_view_node_source',
                 text='Internally').kind = 'internal'

    if hasattr(node, 'replacement_nodes'):
        box = col.box()
        box.label(text="Replace with:")
        for new_bl_idname, inputs_mapping, outputs_mapping in node.replacement_nodes:
            node_class = get_node_class_reference(new_bl_idname)
            text = node_class.bl_label
            op = box.operator("node.sv_replace_node", text=text)
            op.old_node_name = node.name
            op.new_bl_idname = new_bl_idname
            set_inputs_mapping(op, inputs_mapping)
            set_outputs_mapping(op, outputs_mapping)

    row = col.row(align=True)
    op = row.operator('node.sv_replace_node', text='Re-Create Node')
    op.old_node_name = node.name
    op.new_bl_idname = bl_idname
Beispiel #19
0
    def update_cls(self):
        """
        create or update the corresponding class reference
        """

        if not all((self.input_node, self.output_node)):
            error("Monad %s not set up correctly", self.name)
            return None

        cls_dict = {}

        if not self.cls_bl_idname:

            # the monad cls_bl_idname needs to be unique and cannot change
            monad_base_name = make_valid_identifier(self.name)
            monad_itentifier = id(self) ^ random.randint(0, 4294967296)

            cls_name = "SvGroupNode{}_{}".format(monad_base_name,
                                                 monad_itentifier)
            # set the unique name for the class, depending on context this might fail
            # then we cannot do the setup of the class properly so abandon
            try:
                self.cls_bl_idname = cls_name
            except Exception:
                return None
        else:
            cls_name = self.cls_bl_idname

        self.verify_props()

        cls_dict["bl_idname"] = cls_name
        cls_dict["bl_label"] = self.name

        cls_dict["input_template"] = self.generate_inputs()
        cls_dict["output_template"] = self.generate_outputs()

        self.make_props(cls_dict)

        # done with setup

        old_cls_ref = get_node_class_reference(cls_name)

        bases = (SvGroupNodeExp, Node, SverchCustomTreeNode)

        cls_ref = type(cls_name, bases, cls_dict)

        if old_cls_ref:
            sverchok.utils.unregister_node_class(old_cls_ref)
        sverchok.utils.register_node_class(cls_ref)

        return cls_ref
Beispiel #20
0
    def add_node(self, tree):
        class SvSingleSocketNode():
            bl_idname = 'SvSingleSocketNode'
            bl_label = 'DO NOT USE'
            bl_icon = 'MOD_CURVE'

        # [x] define new node
        prop_dict = self.get_prop_dict()
        bases = (SvSingleSocketNode, Node, SverchCustomTreeNode)
        prop_func = IntProperty if self.new_prop_type == "int" else FloatProperty

        # [x] -- add prop if needed (only when inputs)
        cls_dict = {}
        cls_dict['__annotations__'] = {}
        cls_dict['__annotations__'][self.new_prop_name] = prop_func(
            **prop_dict)
        cls_name = SvSingleSocketNode.bl_idname
        cls_ref = type(cls_name, bases, cls_dict)

        # [x] register new node (but unregister first if needed..)
        old_cls_ref = get_node_class_reference(cls_name)
        if old_cls_ref:
            unregister_node_class(old_cls_ref)

        register_node_class(cls_ref)

        # [x] add node
        property_node = tree.nodes.new(cls_name)

        # [x] -- add socket to node (add both in the template)
        io_sockets = getattr(property_node, self.kind)
        if self.kind == 'outputs':
            io_sockets.new(self.socket_type, self.new_prop_name)
        else:
            io_sockets.new(self.socket_type,
                           prop_dict['name']).prop_name = prop_dict['name']

        # [x] link node
        io_node = tree.input_node if self.kind == 'inputs' else tree.output_node
        out2in = self.kind == 'inputs'
        AB_LINK = (io_node.outputs[-1],
                   io_sockets[-1]) if out2in else (io_sockets[-1],
                                                   io_node.inputs[-1])
        tree.links.new(*AB_LINK)

        # [x] unlink, remove node
        # tree.links.remove(*AB_LINK)
        tree.nodes.remove(property_node)

        # [x] unregister node
        unregister_node_class(cls_ref)
Beispiel #21
0
    def update_cls(self):
        """
        create or update the corresponding class reference
        """

        if not all((self.input_node, self.output_node)):
            error("Monad %s not set up correctly", self.name)
            return None

        cls_dict = {}

        if not self.cls_bl_idname:
            
            # the monad cls_bl_idname needs to be unique and cannot change
            monad_base_name = make_valid_identifier(self.name)
            monad_itentifier = id(self) ^ random.randint(0, 4294967296)

            cls_name = "SvGroupNode{}_{}".format(monad_base_name, monad_itentifier)
            # set the unique name for the class, depending on context this might fail
            # then we cannot do the setup of the class properly so abandon
            try:
                self.cls_bl_idname = cls_name
            except Exception:
                return None
        else:
            cls_name = self.cls_bl_idname

        self.verify_props()

        cls_dict["bl_idname"] = cls_name
        cls_dict["bl_label"] = self.name

        cls_dict["input_template"] = self.generate_inputs()
        cls_dict["output_template"] = self.generate_outputs()

        self.make_props(cls_dict)

        # done with setup

        old_cls_ref = get_node_class_reference(cls_name)

        bases = (SvGroupNodeExp, Node, SverchCustomTreeNode)

        cls_ref = type(cls_name, bases, cls_dict)

        if old_cls_ref:
            sverchok.utils.unregister_node_class(old_cls_ref)
        sverchok.utils.register_node_class(cls_ref)

        return cls_ref
Beispiel #22
0
    def add_prop_from(self, socket):
        """
        Add a property if possible
        """
        other = socket.other
        cls = get_node_class_reference(self.cls_bl_idname)
        cls_dict = cls.__dict__ if cls else {}

        if other.prop_name:
            prop_name = other.prop_name
            prop_func, prop_dict = getattr(other.node.rna_type, prop_name, ("", {}))


            if prop_func.__name__ == "FloatProperty":
                self.get_current_as_default(prop_dict, other.node, prop_name)
                prop_settings = self.float_props.add()
            elif prop_func.__name__ == "IntProperty":
                self.get_current_as_default(prop_dict, other.node, prop_name)
                prop_settings = self.int_props.add()
            elif prop_func.__name__ == "FloatVectorProperty":
                info("FloatVectorProperty ignored (normal behaviour since day one). prop_func: %s, prop_dict: %s.", prop_func, prop_dict)
                return None # for now etc
            else: # no way to handle it
                return None

            # print('dict')
            # pprint.pprint(prop_dict)
            new_name = generate_name(prop_name, cls_dict)
            prop_settings.prop_name = new_name
            prop_settings.set_settings(prop_dict)
            socket.prop_name = new_name
            return new_name

        elif hasattr(other, "prop_type"):
            if "float" in other.prop_type:
                prop_settings = self.float_props.add()
            elif "int" in other.prop_type:
                prop_settings = self.int_props.add()
            else:
                return None
            
            new_name = generate_name(make_valid_identifier(other.name), cls_dict)
            prop_settings.prop_name = new_name 
            prop_settings.set_settings({"name": other.name})
            socket.prop_name = new_name
            return new_name

        return None
Beispiel #23
0
def get_category_items(self, context):
    category_items = None
    category_items = [(GENERAL, "General", "Uncategorized presets", 0)]
    node_category_items = []
    for idx, category in enumerate(get_category_names()):
        node_class = get_node_class_reference(category)
        if node_class:
            title = "/Node/ {}".format(node_class.bl_label)
            node_category_items.append((category, title, category, idx+1))
        else:
            title = category
            category_items.append((category, title, category, idx+1))
    include_node_categories = not hasattr(self, 'include_node_categories') or self.include_node_categories
    if node_category_items and include_node_categories:
        category_items = category_items + [None] + node_category_items
    return category_items
Beispiel #24
0
def sv_group_items(context):
    """
    Based on the built in node_group_items in the blender distrubution
    somewhat edited to fit.
    """
    if context is None:
        return
    space = context.space_data
    if not space:
        return
    ntree = space.edit_tree
    if not ntree:
        return

    yield NodeItemCustom(draw=draw_node_ops)

    def contains_group(nodetree, group):
        if nodetree == group:
            return True
        else:
            for node in nodetree.nodes:
                if node.bl_idname in node_tree_group_type.values(
                ) and node.node_tree is not None:
                    if contains_group(node.node_tree, group):
                        return True
        return False

    if ntree.bl_idname == "SverchGroupTreeType":
        yield NodeItem("SvMonadInfoNode", "Monad Info")

    for monad in context.blend_data.node_groups:
        if monad.bl_idname != "SverchGroupTreeType":
            continue
        # make sure class exists
        cls_ref = get_node_class_reference(monad.cls_bl_idname)

        if cls_ref and monad.cls_bl_idname:
            yield NodeItem(monad.cls_bl_idname, monad.name)
        elif monad.cls_bl_idname:
            monad_cls_template_dict = {
                "cls_bl_idname": "str('{}')".format(monad.cls_bl_idname)
            }
            yield NodeItem("SvMonadGenericNode", monad.name,
                           monad_cls_template_dict)
Beispiel #25
0
def make_menu():
    menu = []
    index = nodes_index()
    for category, items in index:
        identifier = "IFCSVERCHOK_" + category.replace(" ", "_")
        node_items = []
        for item in items:
            nodetype = item[1]
            rna = get_node_class_reference(nodetype)
            if not rna:
                info(
                    "Node `%s' is not available (probably due to missing dependencies).",
                    nodetype)
            else:
                node_item = SverchNodeItem.new(nodetype)
                node_items.append(node_item)
        if node_items:
            cat = SverchNodeCategory(identifier, category, items=node_items)
            menu.append(cat)
    return menu
Beispiel #26
0
def layout_draw_categories(layout, category_name, node_details):

    global menu_class_by_title

    for node_info in node_details:

        if node_info[0] == 'separator':
            layout.separator()
            continue

        if not node_info:
            print(repr(node_info), 'is incomplete, or unparsable')
            continue

        bl_idname = node_info[0]

        if is_submenu_call(bl_idname):
            submenu_title = get_submenu_call_name(bl_idname)
            menu_title = compose_submenu_name(category_name, bl_idname)
            menu_class = menu_class_by_title[menu_title]
            layout.menu(menu_class.__name__, text=submenu_title)
            continue

        # this is a node bl_idname that can be registered but shift+A can drop it from showing.
        if bl_idname == 'ScalarMathNode':
            continue

        node_ref = get_node_class_reference(bl_idname)

        if hasattr(node_ref, "bl_label"):
            layout_params = dict(text=node_ref.bl_label, **node_icon(node_ref))
        elif bl_idname == 'NodeReroute':
            layout_params = dict(text='Reroute',
                                 icon_value=custom_icon('SV_REROUTE'))
        else:
            continue

        node_op = draw_add_node_operator(layout,
                                         bl_idname,
                                         params=layout_params)
Beispiel #27
0
def sv_group_items(context):
    """
    Based on the built in node_group_items in the blender distrubution
    somewhat edited to fit.
    """
    if context is None:
        return
    space = context.space_data
    if not space:
        return
    ntree = space.edit_tree
    if not ntree:
        return

    yield NodeItemCustom(draw=draw_node_ops)

    def contains_group(nodetree, group):
        if nodetree == group:
            return True
        else:
            for node in nodetree.nodes:
                if node.bl_idname in node_tree_group_type.values() and node.node_tree is not None:
                    if contains_group(node.node_tree, group):
                        return True
        return False

    if ntree.bl_idname == "SverchGroupTreeType":
        yield NodeItem("SvMonadInfoNode", "Monad Info")

    for monad in context.blend_data.node_groups:
        if monad.bl_idname != "SverchGroupTreeType":
            continue
        # make sure class exists
        cls_ref = get_node_class_reference(monad.cls_bl_idname)

        if cls_ref and monad.cls_bl_idname:
            yield NodeItem(monad.cls_bl_idname, monad.name)
        elif monad.cls_bl_idname:
            monad_cls_template_dict = {"cls_bl_idname": "str('{}')".format(monad.cls_bl_idname)}
            yield NodeItem("SvMonadGenericNode", monad.name, monad_cls_template_dict)
Beispiel #28
0
def make_categories():
    menu_cats = []
    index = nodes_index()
    for category, items in index:
        identifier = "SVERCHOK_OPEN3D_" + category.replace(' ', '_')
        node_items = []
        for item in items:
            nodetype = item[1]
            rna = get_node_class_reference(nodetype)
            if not rna and nodetype != 'separator':
                info("Node `%s' is not available (probably due to missing dependencies).", nodetype)
            else:
                node_item = SverchNodeItem.new(nodetype)
                node_items.append(node_item)
        if node_items:
            cat = SverchNodeCategory(
                        identifier,
                        category,
                        items=node_items
                    )
            menu_cats.append(cat)
    return menu_cats
Beispiel #29
0
def idname_draw(self, context):
    if not displaying_sverchok_nodes(context):
        return
    layout = self.layout
    node = context.active_node
    ntree = node.id_data
    if not node:
        return
    bl_idname = node.bl_idname
    box = layout.box()
    col = box.column(align=False)
    col.scale_y = 0.9
    row = col.row(align=True)
    colom = row.column(align=True)
    colom.scale_x = 3
    colom.label(text=bl_idname + ':')
    colom = row.column(align=True)
    colom.operator('node.copy_bl_idname', text='',
                   icon='COPY_ID').name = bl_idname

    if node_supports_presets(node):
        box = col.box()
        box.label(text="Presets:")
        box.menu("SV_MT_LoadPresetMenu")
        save_row = box.row()
        save = save_row.operator(SvSaveSelected.bl_idname,
                                 text="Save Node Preset",
                                 icon='SOLO_ON')
        save.id_tree = ntree.name
        save.category = node.bl_idname
        save.save_defaults = True
        selected_nodes = [node for node in ntree.nodes if node.select]
        save_row.enabled = len(selected_nodes) == 1

    # show these anyway, can fail and let us know..
    row = col.row(align=True)
    row.label(text='Help & Docs:')
    row = col.row(align=True)
    row.operator('node.view_node_help', text='Online').kind = 'online'
    row.operator('node.view_node_help', text='Offline').kind = 'offline'
    row.operator('node.view_node_help',
                 text='Github').kind = 'github'  #, icon='GHOST'
    col.separator()
    # view the source of the current node ( warning, some nodes rely on more than one file )
    row = col.row(align=True)
    row.label(text='Edit Source:')
    row = col.row(align=True)
    row.operator('node.sv_view_node_source',
                 text='Externally').kind = 'external'
    row.operator('node.sv_view_node_source',
                 text='Internally').kind = 'internal'

    if hasattr(node, 'replacement_nodes'):
        box = col.box()
        box.label(text="Replace with:")
        for new_bl_idname, inputs_mapping, outputs_mapping in node.replacement_nodes:
            node_class = get_node_class_reference(new_bl_idname)
            text = node_class.bl_label
            op = box.operator("node.sv_replace_node", text=text)
            op.old_node_name = node.name
            op.new_bl_idname = new_bl_idname
            set_inputs_mapping(op, inputs_mapping)
            set_outputs_mapping(op, outputs_mapping)

    row = col.row(align=True)
    op = row.operator('node.sv_replace_node', text='Re-Create Node')
    op.old_node_name = node.name
    op.new_bl_idname = bl_idname
Beispiel #30
0
 def get_node_class(self):
     return get_node_class_reference(self.nodetype)
Beispiel #31
0
 def get_node_class(self):
     return get_node_class_reference(self.nodetype)
Beispiel #32
0
def ensure_valid_show_string(item):
    # nodetype = getattr(bpy.types, item[0])
    nodetype = get_node_class_reference(item[0])
    loop_reverse[nodetype.bl_label] = item[0]
    description = nodetype.bl_rna.get_shorthand()
    return nodetype.bl_label + ensure_short_description(description)
Beispiel #33
0
    def add_prop_from(self, socket):
        """
        Add a property if possible
        """
        other = socket.other
        cls = get_node_class_reference(self.cls_bl_idname)
        cls_dict = cls.__dict__ if cls else {}

        local_debug = False
        # reference_obj_id = cls.instances[0]
        # print(reference_obj_id.__annotations__)

        try:
            monad_prop_names = self.get_stored_prop_names()
            has_monad_prop_names = True
            print(monad_prop_names)
        except:
            print('no prop names yet in : add_prop_from call')
            has_monad_prop_names = False


        if other.prop_name:

            prop_name = other.prop_name
            prop_func, prop_dict = other.node.__annotations__.get(prop_name, ("", {}))

            if 'attr' in prop_dict:
                prop_dict.pop('attr')  # this we store in prop_name anyway
            
            if 'update' in prop_dict:
                """
                the node may be doing a tonne of stuff in a wrapped update,
                but because this property will be on a shell node (the monad outside) we can
                replace it with a reference to updateNode. i think this is a sane thing to ensure.
                """
                prop_dict['update'] = updateNode
            
            if not 'name' in prop_dict:
                """ 
                name is used exclusively for displaying name on the slider or label 
                most properties will have this defined anyway, but just in case.
                """ 
                regex = re.compile('[^a-z A-Z0-9]')
                prop_dict['name'] = regex.sub('', prop_name)
                print(f"monad: generated name for property function: {prop_name} -> {prop_dict['name']}")

            if local_debug:
                print("prop_func:", prop_func)   # tells us the kind of property to make
                print("prop_dict:", prop_dict)   # tells us the attributes of the property
                print("prop_name:", prop_name)   # tells the socket / slider ui which prop to display
                #                                # and its associated 'name' attribute from the prop_dict
            
            if prop_func.__name__ == "FloatProperty":
                self.get_current_as_default(prop_dict, other.node, prop_name)
                prop_settings = self.float_props.add()
                prop_name_prefix = f"floats_{len(self.float_props)}_"
            elif prop_func.__name__ == "IntProperty":
                self.get_current_as_default(prop_dict, other.node, prop_name)
                prop_settings = self.int_props.add()
                prop_name_prefix = f"ints_{len(self.int_props)}_"
            elif prop_func.__name__ == "FloatVectorProperty":
                info("FloatVectorProperty ignored (normal behaviour since day one). prop_func: %s, prop_dict: %s.", prop_func, prop_dict)
                return None
            else: # no way to handle it
                return None

            if other.node.bl_idname == "SvNumberNode":
                if "float" in prop_name:
                    prop_dict['min'] = other.node.float_min
                    prop_dict['max'] = other.node.float_max
                elif "int" in prop_name:
                    prop_dict['min'] = other.node.int_min
                    prop_dict['max'] = other.node.int_max

            new_name = prop_name_prefix + prop_name
            if has_monad_prop_names:
                new_name = ensure_unique(monad_prop_names, new_name)
            
            prop_settings.prop_name = new_name
            prop_settings.set_settings(prop_dict)
            socket.prop_name = new_name
            return new_name

        elif hasattr(other, "prop_type"):
            
            # if you are seeing errors with this and the other.node.bl_idname is not scriptnodelite
            # the fix will be here somewhere.
            print(f'{other.node} = other.node')
            print(f'{other.prop_type} = other.prop_type')
            
            if not any(substring in other.prop_type for substring in ["float", "int"]): 
                return None    
        
            if "float" in other.prop_type:
                prop_settings = self.float_props.add()
                prop_name_prefix = f"floats_{len(self.float_props)}_"
            elif "int" in other.prop_type:
                prop_settings = self.int_props.add()
                prop_name_prefix = f"ints_{len(self.int_props)}_"

            new_name = prop_name_prefix + other.name
            if has_monad_prop_names:
                new_name = ensure_unique(monad_prop_names, new_name)
            
            # this name will be used as the attr name of the newly generated property for the shellnode
            # essentially this is 
            #       __annotations__[prop_name] = new property function
            prop_settings.prop_name = new_name
      
            custom_prop_dict = {
                "name": nice_ui_name(other.name),
                "update": updateNode
            }

            # there are other nodes that use this technique, 
            if other.node.bl_idname == "SvScriptNodeLite":
                prop_list = other.node.float_list if "float" in other.prop_type else other.node.int_list
                default = prop_list[other.prop_index]
                custom_prop_dict["default"] = default

            prop_settings.set_settings(custom_prop_dict)
            socket.prop_name = new_name
            return new_name

        return None
Beispiel #34
0
    def draw(self, context):
        layout = self.layout
        if len(context.space_data.path) > 1:
            layout.label(text="Is not supported inside node groups")
            return
        ntree = context.space_data.node_tree
        panel_props = ntree.preset_panel_properties

        layout.prop(panel_props,
                    'manage_mode',
                    toggle=True,
                    icon='PREFERENCES')

        needle = None
        if not panel_props.manage_mode:
            row = layout.row(align=True)
            row.prop(panel_props, "search_text", text="")
            row.operator("node.sv_reset_preset_search", icon="X", text="")
            needle = panel_props.search_text

        if not panel_props.search_text:
            layout.prop(panel_props, 'category', text='')

        row = layout.row()
        op = row.operator('node.sv_save_selected',
                          text="Save Preset",
                          icon='SOLO_ON')
        op.id_tree = ntree.name
        op.category = panel_props.category
        op.is_node_preset = False

        selected_nodes = [node for node in ntree.nodes if node.select]
        can_save_preset = len(selected_nodes) > 0
        category_node_class = get_node_class_reference(op.category)
        if category_node_class is not None:
            if len(selected_nodes) == 1:
                selected_node = selected_nodes[0]
                can_save_preset = can_save_preset and hasattr(
                    selected_node,
                    'bl_idname') and selected_node.bl_idname == op.category
            else:
                can_save_preset = False
        row.enabled = can_save_preset

        layout.separator()

        presets = get_presets(panel_props.category, search=needle)
        layout.separator()

        if panel_props.manage_mode:
            col = layout.column(align=True)
            col.operator("node.sv_preset_from_gist",
                         icon='URL').category = panel_props.category
            col.operator("node.sv_preset_from_file",
                         icon='IMPORT').category = panel_props.category

            col.operator('node.sv_preset_category_new', icon='NEWFOLDER')
            if panel_props.category != GENERAL:
                remove = col.operator('node.sv_preset_category_remove',
                                      text="Delete category {}".format(
                                          panel_props.category),
                                      icon='CANCEL')
                remove.category = panel_props.category

            if len(presets):
                layout.label(text="Manage presets:")
                for preset in presets:
                    name = preset.name

                    row = layout.row(align=True)
                    row.label(text=name)

                    gist = row.operator('node.sv_preset_to_gist',
                                        text="",
                                        icon='URL')
                    gist.preset_name = name
                    gist.category = panel_props.category

                    export = row.operator('node.sv_preset_to_file',
                                          text="",
                                          icon="EXPORT")
                    export.preset_name = name
                    export.category = panel_props.category

                    if not preset.standard:
                        rename = row.operator('node.sv_preset_props',
                                              text="",
                                              icon="GREASEPENCIL")
                        rename.old_name = name
                        rename.old_category = panel_props.category
                        rename.allow_change_category = (category_node_class is
                                                        None)
                        if rename.allow_change_category:
                            rename.new_category = rename.old_category

                        delete = row.operator('node.sv_preset_delete',
                                              text="",
                                              icon='CANCEL')
                        delete.preset_name = name
                        delete.category = panel_props.category
            else:
                layout.label(text="You do not have any presets")
                layout.label(
                    text="under `{}` category.".format(panel_props.category))
                layout.label(text="You can import some presets")
                layout.label(text="from Gist or from file.")

        else:
            if len(presets):
                layout.label(text="Use preset:")
                draw_presets_ops(layout, panel_props.category, ntree.name,
                                 presets)
            elif needle:
                layout.label(text="There are no presets matching")
                layout.label(text="the search terms.")
            else:
                layout.label(text="You do not have any presets")
                layout.label(
                    text="under `{}` category.".format(panel_props.category))
                layout.label(text="Select some nodes and")
                layout.label(text="Use the `Save Preset' button.")