From ca71af4ae6c98738c227e8c7a10a536c41ff4d0a Mon Sep 17 00:00:00 2001 From: Durman Date: Sat, 15 Jun 2019 20:32:14 +0400 Subject: [PATCH 1/5] custom_switcher - prototype --- index.md | 1 + nodes/logic/custom_switcher.py | 60 ++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 nodes/logic/custom_switcher.py diff --git a/index.md b/index.md index 5bb556f3f..c87df3ce1 100644 --- a/index.md +++ b/index.md @@ -242,6 +242,7 @@ SvSwitchNode SvInputSwitchNode SvNeuroElman1LNode + SvCustomSwitcher ## Viz ViewerNode2 diff --git a/nodes/logic/custom_switcher.py b/nodes/logic/custom_switcher.py new file mode 100644 index 000000000..15f6942b1 --- /dev/null +++ b/nodes/logic/custom_switcher.py @@ -0,0 +1,60 @@ +# ##### 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 bpy + +from sverchok.node_tree import SverchCustomTreeNode +from sverchok.data_structure import updateNode + + +test = [('1', 'Box', ''), + ('2', 'Circle', ''), + ('3', 'Plane', '')] + + +class SvCustomSwitcher(bpy.types.Node, SverchCustomTreeNode): + """ + Triggers: project point to line + If there are point and line the node will find closest point on the line to point + + You can use number of points and lines as many as you wish + """ + bl_idname = 'SvCustomSwitcher' + bl_label = 'Switcher' + bl_icon = 'HAND' + + user_list = bpy.props.EnumProperty(name='Custom list', items=test, update=updateNode) + + def sv_init(self, context): + self.outputs.new('StringsSocket', 'Item') + + def draw_buttons(self, context, layout): + col = layout.column(align=True) + col.prop(self, "user_list", expand=True) + + def process(self): + self.outputs['Item'].sv_set([[int(self.user_list) - 1]]) + + +def register(): + bpy.utils.register_class(SvCustomSwitcher) + + +def unregister(): + bpy.utils.unregister_class(SvCustomSwitcher) \ No newline at end of file -- GitLab From 230e916456a5b6a9b1b886dfbf0764a437a59096 Mon Sep 17 00:00:00 2001 From: durman Date: Mon, 17 Jun 2019 11:27:35 +0400 Subject: [PATCH 2/5] approach with enum properties --- nodes/logic/custom_switcher.py | 59 ++++++++++++++++++++++++++++++---- ui/sv_panels.py | 9 ++++++ utils/sv_panels_tools.py | 13 ++++++-- 3 files changed, 71 insertions(+), 10 deletions(-) diff --git a/nodes/logic/custom_switcher.py b/nodes/logic/custom_switcher.py index 15f6942b1..796a7dee8 100644 --- a/nodes/logic/custom_switcher.py +++ b/nodes/logic/custom_switcher.py @@ -23,11 +23,6 @@ from sverchok.node_tree import SverchCustomTreeNode from sverchok.data_structure import updateNode -test = [('1', 'Box', ''), - ('2', 'Circle', ''), - ('3', 'Plane', '')] - - class SvCustomSwitcher(bpy.types.Node, SverchCustomTreeNode): """ Triggers: project point to line @@ -39,9 +34,40 @@ class SvCustomSwitcher(bpy.types.Node, SverchCustomTreeNode): bl_label = 'Switcher' bl_icon = 'HAND' - user_list = bpy.props.EnumProperty(name='Custom list', items=test, update=updateNode) + def draw_items_test1(self, context): + if self.inputs['Data'].is_linked: + data = self.inputs['Data'].sv_get() + counter = 0 + out = [] + if isinstance(data[0], (list, tuple)): + data = [i for l in data for i in l] + #return [(str(i), str(i), '') for i in range(len(data)) if i < 32] + return [(str(i), str(val), '') for i, val in enumerate(data) if i < 32] + #for val in data: + # if counter == 31: + # break + # if hasattr(val, 'name'): + # val = val.name + # if isinstance(val, str): + # out.append(('{}'.format(counter), '{}'.format(val), '')) + # counter += 1 + #return out + else: + return [('1', 'link something', '')] + + def draw_items(self, context): + if self.string_values: + return [(str(i), s.name, '') for i, s in enumerate(self.string_values)] + else: + return [('1', 'link something', '')] + + string_values = bpy.props.CollectionProperty(type=bpy.types.PropertyGroup) + user_list = bpy.props.EnumProperty(name='Custom list', items=draw_items, update=updateNode, options={'ENUM_FLAG'}) + show_in_3d = bpy.props.BoolProperty(name='show in panel', default=True, + description='Show properties in 3d panel or not') def sv_init(self, context): + self.inputs.new('StringsSocket', 'Data') self.outputs.new('StringsSocket', 'Item') def draw_buttons(self, context, layout): @@ -49,7 +75,26 @@ class SvCustomSwitcher(bpy.types.Node, SverchCustomTreeNode): col.prop(self, "user_list", expand=True) def process(self): - self.outputs['Item'].sv_set([[int(self.user_list) - 1]]) + if self.inputs['Data'].is_linked: + data = self.inputs['Data'].sv_get() + if isinstance(data[0], (list, tuple)): + data = [i for l in data for i in l] + if len(data) != len(self.string_values): + self.string_values.clear() + for i, val in enumerate(data): + if i == 32: + break + self.string_values.add().name = str(val) + else: + for val, str_val in zip(data, self.string_values): + str_val.name = str(val) + else: + self.string_values.clear() + + self.outputs['Item'].sv_set([sorted([int(i) for i in self.user_list])]) + + def process_test1(self): + self.outputs['Item'].sv_set([[int(i) for i in self.user_list]]) def register(): diff --git a/ui/sv_panels.py b/ui/sv_panels.py index f51ecd995..50a50f229 100644 --- a/ui/sv_panels.py +++ b/ui/sv_panels.py @@ -244,6 +244,15 @@ class Sv3DPanel(bpy.types.Panel): row.prop(node, node.mode, index=i, text=str(i)) row.scale_x = little_width * 2.5 + elif node.bl_idname in {'SvCustomSwitcher'}: + row = col.row(align=True) + switch_icon = 'DOWNARROW_HLT' if node.show_in_3d else 'RIGHTARROW' + row.prop(node, 'show_in_3d', text='', icon=switch_icon) + row.label(tex) + if node.show_in_3d: + col.column() + col.prop(node, ver, text='') + # Import/Export properties row = col.row(align=True) row.label(text='Export/Import:') diff --git a/utils/sv_panels_tools.py b/utils/sv_panels_tools.py index f4e976785..a378e234c 100644 --- a/utils/sv_panels_tools.py +++ b/utils/sv_panels_tools.py @@ -196,14 +196,15 @@ class SvLayoutScanProperties(bpy.types.Operator): templist = [] for node in tree.nodes: idname = node.bl_idname - + if idname in {'ObjectsNodeMK2', 'SvObjectsNodeMK3'}: debug('scans for get option %s %s', node.label, node.name) if any((s.links for s in node.outputs)): templist.append([node.label, node.name, ""]) - elif idname in {'SvNumberNode', 'IntegerNode', 'FloatNode', 'SvListInputNode', 'SvColorInputNode', 'SvBmeshViewerNodeMK2'}: - if idname != 'SvBmeshViewerNodeMK2': + elif idname in {'SvNumberNode', 'IntegerNode', 'FloatNode', 'SvListInputNode', 'SvColorInputNode', + 'SvBmeshViewerNodeMK2', 'SvCustomSwitcher'}: + if idname not in {'SvBmeshViewerNodeMK2', 'SvCustomSwitcher'}: if not node.outputs: debug("Node %s does not have outputs", node.name) continue @@ -213,6 +214,10 @@ class SvLayoutScanProperties(bpy.types.Operator): if (not node.outputs[0].is_linked) or (node.to3d != True): debug("Node %s: first output is not linked or to3d == False", node.name) continue + elif idname == 'SvCustomSwitcher': + if not node.inputs[0].is_linked and not node.outputs[0].is_linked: + debug("Node %s: output or input are not linked", node.name) + continue elif (node.to3d != True): debug("Node %s: first output is not linked or to3d == False", node.name) continue @@ -232,6 +237,8 @@ class SvLayoutScanProperties(bpy.types.Operator): templist.append([node.label, node.name, 'int_list']) elif node.mode == 'float_list': templist.append([node.label, node.name, 'float_list']) + elif 'SvCustomSwitcher' in idname: + templist.append([node.label, node.name, 'user_list']) else: kind = node.selected_mode templist.append([node.label, node.name, kind + '_']) -- GitLab From ee84886f962a6b53f88c79d808baf656340885ea Mon Sep 17 00:00:00 2001 From: durman Date: Mon, 17 Jun 2019 16:51:12 +0400 Subject: [PATCH 3/5] switch to Bool properties --- nodes/logic/custom_switcher.py | 85 ++++++++++++++++++++-------------- ui/sv_panels.py | 8 +--- utils/sv_panels_tools.py | 2 +- 3 files changed, 52 insertions(+), 43 deletions(-) diff --git a/nodes/logic/custom_switcher.py b/nodes/logic/custom_switcher.py index 796a7dee8..e68f90b49 100644 --- a/nodes/logic/custom_switcher.py +++ b/nodes/logic/custom_switcher.py @@ -25,54 +25,72 @@ from sverchok.data_structure import updateNode class SvCustomSwitcher(bpy.types.Node, SverchCustomTreeNode): """ - Triggers: project point to line - If there are point and line the node will find closest point on the line to point + Triggers: custom switcher + Convert input to buttons - You can use number of points and lines as many as you wish + Output shows selected items """ bl_idname = 'SvCustomSwitcher' bl_label = 'Switcher' bl_icon = 'HAND' - def draw_items_test1(self, context): - if self.inputs['Data'].is_linked: - data = self.inputs['Data'].sv_get() - counter = 0 - out = [] - if isinstance(data[0], (list, tuple)): - data = [i for l in data for i in l] - #return [(str(i), str(i), '') for i in range(len(data)) if i < 32] - return [(str(i), str(val), '') for i, val in enumerate(data) if i < 32] - #for val in data: - # if counter == 31: - # break - # if hasattr(val, 'name'): - # val = val.name - # if isinstance(val, str): - # out.append(('{}'.format(counter), '{}'.format(val), '')) - # counter += 1 - #return out - else: - return [('1', 'link something', '')] + def update_mode(self,context): + if not self.multiple_selection: + self['previous_user_list'] = [False for _ in range(32)] + self.user_list = [True] + [False for _ in range(31)] - def draw_items(self, context): - if self.string_values: - return [(str(i), s.name, '') for i, s in enumerate(self.string_values)] - else: - return [('1', 'link something', '')] + def get_user_list(self): + return self['user_list'] + + def set_user_list(self, values): + if not self.multiple_selection: + values = [True if not old and new or old and not new else False + for old, new in zip(self['previous_user_list'], values)] + self['previous_user_list'] = values + self['user_list'] = values + to3d = bpy.props.BoolProperty(name='Show in 3d panel', default=True) + multiple_selection = bpy.props.BoolProperty(name='Multiple selection', default=True, update=update_mode) + ui_scale = bpy.props.FloatProperty(name='Size of buttons', default=1.0, min=0.5, max=5) string_values = bpy.props.CollectionProperty(type=bpy.types.PropertyGroup) - user_list = bpy.props.EnumProperty(name='Custom list', items=draw_items, update=updateNode, options={'ENUM_FLAG'}) + user_list = bpy.props.BoolVectorProperty(name="User selection", size=32, update=updateNode, + set=set_user_list, get=get_user_list) show_in_3d = bpy.props.BoolProperty(name='show in panel', default=True, description='Show properties in 3d panel or not') def sv_init(self, context): + self['user_list'] = [False for _ in range(32)] + self['previous_user_list'] = [False for _ in range(32)] self.inputs.new('StringsSocket', 'Data') self.outputs.new('StringsSocket', 'Item') def draw_buttons(self, context, layout): col = layout.column(align=True) - col.prop(self, "user_list", expand=True) + col.scale_y = self.ui_scale + for i, val in enumerate(self.string_values): + col.prop(self, "user_list", toggle=True, index=i, text=val.name) + + def draw_buttons_ext(self, context, layout): + row = layout.row() + row.scale_y = 2 + row.prop(self, 'multiple_selection', toggle=True) + layout.prop(self, 'to3d', toggle=True) + layout.prop(self, 'ui_scale', text='Size of buttons') + + def draw_buttons_3dpanel(self, layout): + row = layout.row(align=True) + if self.label: + name = self.label + else: + name = self.name + row.label(name) + row.prop(self, 'multiple_selection', toggle=True) + switch_icon = 'DOWNARROW_HLT' if self.show_in_3d else 'RIGHTARROW' + row.prop(self, 'show_in_3d', text='', icon=switch_icon) + if self.show_in_3d: + col = layout.column(align=True) + for i, val in enumerate(self.string_values): + col.prop(self, "user_list", toggle=True, index=i, text=val.name) def process(self): if self.inputs['Data'].is_linked: @@ -91,10 +109,7 @@ class SvCustomSwitcher(bpy.types.Node, SverchCustomTreeNode): else: self.string_values.clear() - self.outputs['Item'].sv_set([sorted([int(i) for i in self.user_list])]) - - def process_test1(self): - self.outputs['Item'].sv_set([[int(i) for i in self.user_list]]) + self.outputs['Item'].sv_set([[i for i, b in enumerate(self.user_list) if b]]) def register(): @@ -102,4 +117,4 @@ def register(): def unregister(): - bpy.utils.unregister_class(SvCustomSwitcher) \ No newline at end of file + bpy.utils.unregister_class(SvCustomSwitcher) diff --git a/ui/sv_panels.py b/ui/sv_panels.py index 50a50f229..15d87582e 100644 --- a/ui/sv_panels.py +++ b/ui/sv_panels.py @@ -245,13 +245,7 @@ class Sv3DPanel(bpy.types.Panel): row.scale_x = little_width * 2.5 elif node.bl_idname in {'SvCustomSwitcher'}: - row = col.row(align=True) - switch_icon = 'DOWNARROW_HLT' if node.show_in_3d else 'RIGHTARROW' - row.prop(node, 'show_in_3d', text='', icon=switch_icon) - row.label(tex) - if node.show_in_3d: - col.column() - col.prop(node, ver, text='') + node.draw_buttons_3dpanel(col) # Import/Export properties row = col.row(align=True) diff --git a/utils/sv_panels_tools.py b/utils/sv_panels_tools.py index a378e234c..ace1d20d6 100644 --- a/utils/sv_panels_tools.py +++ b/utils/sv_panels_tools.py @@ -215,7 +215,7 @@ class SvLayoutScanProperties(bpy.types.Operator): debug("Node %s: first output is not linked or to3d == False", node.name) continue elif idname == 'SvCustomSwitcher': - if not node.inputs[0].is_linked and not node.outputs[0].is_linked: + if not node.inputs[0].is_linked and not node.outputs[0].is_linked or (node.to3d != True): debug("Node %s: output or input are not linked", node.name) continue elif (node.to3d != True): -- GitLab From 6972e92681019e9401ff25ee961abd23e9f2c861 Mon Sep 17 00:00:00 2001 From: Durman Date: Mon, 17 Jun 2019 22:10:29 +0400 Subject: [PATCH 4/5] code documentation and 3d panel improvement --- nodes/logic/custom_switcher.py | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/nodes/logic/custom_switcher.py b/nodes/logic/custom_switcher.py index e68f90b49..9cf400e49 100644 --- a/nodes/logic/custom_switcher.py +++ b/nodes/logic/custom_switcher.py @@ -34,7 +34,8 @@ class SvCustomSwitcher(bpy.types.Node, SverchCustomTreeNode): bl_label = 'Switcher' bl_icon = 'HAND' - def update_mode(self,context): + def update_mode(self, context): + # Select only one item in non multiple selection mode if not self.multiple_selection: self['previous_user_list'] = [False for _ in range(32)] self.user_list = [True] + [False for _ in range(31)] @@ -43,18 +44,21 @@ class SvCustomSwitcher(bpy.types.Node, SverchCustomTreeNode): return self['user_list'] def set_user_list(self, values): + # Implementation of single selection mode if not self.multiple_selection: values = [True if not old and new or old and not new else False for old, new in zip(self['previous_user_list'], values)] self['previous_user_list'] = values self['user_list'] = values - to3d = bpy.props.BoolProperty(name='Show in 3d panel', default=True) - multiple_selection = bpy.props.BoolProperty(name='Multiple selection', default=True, update=update_mode) + to3d = bpy.props.BoolProperty(name='Show in 3d panel', default=True, + description='Show items of this node in 3d panel of 3d view screen') + multiple_selection = bpy.props.BoolProperty(name='Multiple selection', default=True, update=update_mode, + description='Selection several items simultaneously') ui_scale = bpy.props.FloatProperty(name='Size of buttons', default=1.0, min=0.5, max=5) - string_values = bpy.props.CollectionProperty(type=bpy.types.PropertyGroup) - user_list = bpy.props.BoolVectorProperty(name="User selection", size=32, update=updateNode, - set=set_user_list, get=get_user_list) + string_values = bpy.props.CollectionProperty(type=bpy.types.PropertyGroup, description='Storage of items names') + user_list = bpy.props.BoolVectorProperty(name="User selection", size=32, update=updateNode, set=set_user_list, + get=get_user_list, description='Selection status of items') show_in_3d = bpy.props.BoolProperty(name='show in panel', default=True, description='Show properties in 3d panel or not') @@ -78,21 +82,27 @@ class SvCustomSwitcher(bpy.types.Node, SverchCustomTreeNode): layout.prop(self, 'ui_scale', text='Size of buttons') def draw_buttons_3dpanel(self, layout): - row = layout.row(align=True) + # I think it is moore appropriate place for coding layout of 3d panel + col = layout.column() + row = col.row(align=True) if self.label: name = self.label else: name = self.name - row.label(name) - row.prop(self, 'multiple_selection', toggle=True) switch_icon = 'DOWNARROW_HLT' if self.show_in_3d else 'RIGHTARROW' - row.prop(self, 'show_in_3d', text='', icon=switch_icon) + row.prop(self, 'show_in_3d', text=name, icon=switch_icon) + if self.multiple_selection: + mode_icon = 'COLLAPSEMENU' + else: + mode_icon = 'ZOOMOUT' + row.prop(self, 'multiple_selection', toggle=True, text='', icon=mode_icon) if self.show_in_3d: col = layout.column(align=True) for i, val in enumerate(self.string_values): col.prop(self, "user_list", toggle=True, index=i, text=val.name) def process(self): + # Storing names of items if self.inputs['Data'].is_linked: data = self.inputs['Data'].sv_get() if isinstance(data[0], (list, tuple)): -- GitLab From 2996ca91e58d1b00a40d7f76eddacba10db127d8 Mon Sep 17 00:00:00 2001 From: durman Date: Tue, 18 Jun 2019 16:03:20 +0400 Subject: [PATCH 5/5] user documentation --- docs/nodes/logic/custom_switcher.rst | 50 ++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 docs/nodes/logic/custom_switcher.rst diff --git a/docs/nodes/logic/custom_switcher.rst b/docs/nodes/logic/custom_switcher.rst new file mode 100644 index 000000000..fc17a8293 --- /dev/null +++ b/docs/nodes/logic/custom_switcher.rst @@ -0,0 +1,50 @@ +Custom switcher +=============== + +.. image:: https://user-images.githubusercontent.com/28003269/59678662-11dd6500-91de-11e9-9b28-a08aebaea8b8.png + +Functionality +------------- +Simple node which convert input sequence to buttons. It is useful for creating custom switcher. + +Inputs +------ + +- **Data** - any data you wish.There is no limitation of length of input data but all items above **32** will be ignored. + +Outputs +------- + +- **Item** - index of selected items. + +N panel +------- + ++--------------------+-------+--------------------------------------------------------------------------------+ +| Parameters | Type | Description | ++====================+=======+================================================================================+ +| Multiple selection | Bool | Allowed to select several items simultaneously | ++--------------------+-------+--------------------------------------------------------------------------------+ +| Show in 3d panel | Bool | Won't be ignored for adding parameter of the node to 3d panel | ++--------------------+-------+--------------------------------------------------------------------------------+ +| Size of buttons | float | controlling of size of buttons | ++--------------------+-------+--------------------------------------------------------------------------------+ + +3D panel +-------- + +It consists dropdown list of items and button for activation of multiple selection mode. + +Examples +-------- +**Controlling of light from 3d panel:** + +.. image:: https://user-images.githubusercontent.com/28003269/59653042-7deda800-91a1-11e9-892f-f3e927612d72.gif + +.. image:: https://user-images.githubusercontent.com/28003269/59653046-80500200-91a1-11e9-8314-3c7ebe98d3f8.png + +**controlling of material from 3d panel:** + +.. image:: https://user-images.githubusercontent.com/28003269/59654477-5d285100-91a7-11e9-8a9b-f436d6de57db.gif + +.. image:: https://user-images.githubusercontent.com/28003269/59654483-644f5f00-91a7-11e9-92cb-70da3cc641b0.png \ No newline at end of file -- GitLab