diff --git a/src/customnodes/__init__.py b/src/customnodes/__init__.py index 65a062d..74fd83a 100644 --- a/src/customnodes/__init__.py +++ b/src/customnodes/__init__.py @@ -3,7 +3,7 @@ # Add the filename (without the .py extenstion) to the below list to make # your custom node(s) available for registering. -__all__ = ['example_custom_node'] +__all__ = ['example_custom_node', 'tut_custom_node'] diff --git a/src/customnodes/example_custom_node.py b/src/customnodes/example_custom_node.py index a2ddb0c..92a2064 100644 --- a/src/customnodes/example_custom_node.py +++ b/src/customnodes/example_custom_node.py @@ -51,12 +51,17 @@ def NodePropertiesUI(self, node, parent, sizer): pathlabel = wx.StaticText(parent, label="Path:") sizer.Add(pathlabel, flag=wx.LEFT|wx.TOP, border=5) + vbox = wx.BoxSizer(wx.VERTICAL) + hbox = wx.BoxSizer(wx.HORIZONTAL) + self.pathtxtctrl = wx.TextCtrl(parent) - sizer.Add(self.pathtxtctrl, flag=wx.TOP|wx.EXPAND, border=5) self.pathtxtctrl.ChangeValue(current_value) - + hbox.Add(self.pathtxtctrl, proportion=1) self.browsepathbtn = wx.Button(parent, label="Browse...") - sizer.Add(self.browsepathbtn, flag=wx.TOP|wx.RIGHT, border=5) + hbox.Add(self.browsepathbtn, flag=wx.LEFT, border=5) + vbox.Add(hbox, flag=wx.EXPAND) + + sizer.Add(vbox, flag=wx.ALL|wx.EXPAND, border=5) parent.Bind(wx.EVT_BUTTON, self.OnFilePathButton, self.browsepathbtn) diff --git a/src/customnodes/tut2_custom_node.py b/src/customnodes/tut2_custom_node.py new file mode 100644 index 0000000..aa35aca --- /dev/null +++ b/src/customnodes/tut2_custom_node.py @@ -0,0 +1,92 @@ +import wx +from PIL import Image, ImageFilter + +from GimelStudio.api import (Color, RenderImage, List, NodeBase, + Parameter, Property, RegisterNode) + + +class NodeDefinition(NodeBase): + + @property + def NodeIDName(self): + return "box_blur_node" + + @property + def NodeLabel(self): + return "Box Blur" + + @property + def NodeCategory(self): + return "FILTER" + + @property + def NodeDescription(self): + return "Blurs the given image using the specified blur radius with the Box algorithm." + + @property + def NodeVersion(self): + return "1.0" + + @property + def NodeAuthor(self): + return "Your name!" + + @property + def NodeProperties(self): + return [ + Property('Radius', + prop_type='INTEGER', + value=4 + ), + ] + + @property + def NodeParameters(self): + return [ + Parameter('Image', + param_type='RENDERIMAGE', + default_value=RenderImage('RGBA', (256, 256), (0, 0, 0, 1)) + ), + ] + + + def NodePropertiesUI(self, node, parent, sizer): + # Get the current property value + current_radius_value = self.NodeGetPropValue('Radius') + + # wxPython stuff... + radius_label = wx.StaticText(parent, label="Blur Radius:") + sizer.Add(radius_label, border=5) + + self.radius_slider = wx.Slider( + parent, 100, 25, 1, 100, + style=wx.SL_HORIZONTAL | wx.SL_AUTOTICKS | wx.SL_LABELS + ) + self.radius_slider.SetTickFreq(5) + self.radius_slider.SetRange(1, 100) + self.radius_slider.SetValue(current_radius_value) + sizer.Add(self.radius_slider, flag=wx.EXPAND|wx.ALL, border=5) + + parent.Bind(wx.EVT_SCROLL_THUMBRELEASE, self.OnRadiusChange, self.radius_slider) + + def OnRadiusChange(self, evt): + # Update the node property "Radius" to be the value that was set + self.NodePropertiesUpdate('Radius', self.radius_slider.GetValue()) + + def NodeEvaluation(self, eval_info): + # Get the parameter + image1 = eval_info.EvaluateParameter('Image') + # Get the property + radius = eval_info.EvaluateProperty('Radius') + + # Just like before, except we edit the image with + # Pillow's ImageFilter.BoxBlur method + image = RenderImage() + image.SetAsImage(image1.GetImage().filter( + ImageFilter.BoxBlur(radius) + ).convert('RGBA')) + self.NodeSetThumb(image.GetImage()) + return image + + +RegisterNode(NodeDefinition) diff --git a/src/customnodes/tut_custom_node.py b/src/customnodes/tut_custom_node.py new file mode 100644 index 0000000..0de3c03 --- /dev/null +++ b/src/customnodes/tut_custom_node.py @@ -0,0 +1,102 @@ +import os + +import wx +from PIL import Image + +from GimelStudio.api import (Color, RenderImage, NodeBase, + Parameter, Property, + RegisterNode) + + +class NodeDefinition(NodeBase): + + @property + def NodeIDName(self): + return "simple_input_node" + + @property + def NodeLabel(self): + return "Simple Input" + + @property + def NodeCategory(self): + return "INPUT" + + @property + def NodeDescription(self): + return "This is an example custom node showing how you can\n create a custom node with the Gimel Studio API" + + @property + def NodeVersion(self): + return "1.1" + + @property + def NodeAuthor(self): + return "[author's name]" + + @property + def NodeProperties(self): + return [ + Property('Path', + prop_type='FILEPATH', + value='' + ), + ] + + def NodePropertiesUI(self, node, parent, sizer): + self.parent = parent + + current_value = self.NodeGetPropValue('Path') + + pathlabel = wx.StaticText(parent, label="Path:") + sizer.Add(pathlabel, flag=wx.LEFT|wx.TOP, border=5) + + vbox = wx.BoxSizer(wx.VERTICAL) + hbox = wx.BoxSizer(wx.HORIZONTAL) + + self.pathtxtctrl = wx.TextCtrl(parent) + self.pathtxtctrl.ChangeValue(current_value) + hbox.Add(self.pathtxtctrl, proportion=1) + self.browsepathbtn = wx.Button(parent, label="Browse...") + hbox.Add(self.browsepathbtn, flag=wx.LEFT, border=5) + vbox.Add(hbox, flag=wx.EXPAND) + + sizer.Add(vbox, flag=wx.ALL|wx.EXPAND, border=5) + + parent.Bind(wx.EVT_BUTTON, self.OnFilePathButton, self.browsepathbtn) + + def OnFilePathButton(self, evt): + # We allow opening only .jpg files here (for fun!) + wildcard = "JPG file (*.jpg)|*.jpg|" + + dlg = wx.FileDialog( + self.parent, message="Choose an Image...", + defaultDir=os.getcwd(), + defaultFile="", + wildcard=wildcard, + style=wx.FD_OPEN | wx.FD_CHANGE_DIR | wx.FD_FILE_MUST_EXIST | wx.FD_PREVIEW + ) + + # Show the dialog and retrieve the user response. If it is the OK response, + # process the data. + if dlg.ShowModal() == wx.ID_OK: + # This returns a Python list of files that were selected. + paths = dlg.GetPaths() + + # Update the property and txtctrl with the new file path + self.NodePropertiesUpdate('Path', paths[0]) + self.pathtxtctrl.ChangeValue(paths[0]) + + def NodeEvaluation(self, eval_info): + # Get the file path from the property + path = eval_info.EvaluateProperty('Path') + + image = RenderImage() + if path != '': + image.SetAsOpenedImage(path) + image.SetAsImage(image.GetImage().convert('RGBA')) + self.NodeSetThumb(image.GetImage()) + return image + + +RegisterNode(NodeDefinition)