├── package ├── __init__.py ├── parallel.py └── components.py ├── Images ├── checked.png ├── python.ico ├── python.png └── unchecked.png ├── Samples ├── recursion.gh ├── quickUpdater.gh ├── pygha │ ├── compile.py │ └── makeLine.py ├── testDefinition.gh ├── smoothingPolyline.gh ├── sampleScript.py ├── sampleCommon.py └── helpText.html ├── DocReplacement ├── DocStorage.cs ├── AttributedGeometry.cs └── GrasshopperDocument.cs ├── .gitignore ├── references └── readme.txt ├── Properties ├── AssemblyInfo.cs ├── Resources.Designer.cs └── Resources.resx ├── Component ├── SpecialHints │ ├── SpecialLineHint.cs │ ├── SpecialBoxHint.cs │ ├── SpecialCircleHint.cs │ ├── SpecialPolylineHint.cs │ ├── SpecialArcHint.cs │ ├── DynamicHint.cs │ └── AllNewHints.cs ├── StringList.cs ├── PyUpgrader.cs ├── GHComponentsLoader.cs ├── ZUIPythonComponent.cs ├── PythonEnvironment.cs ├── SafeComponent.cs ├── PythonComponentAttributes.cs ├── DocStringUtils.cs ├── PythonComponent.cs └── ComponentIOMarshal.cs ├── app.config ├── PythonPluginInfo.cs ├── GhPython.sln ├── ScriptHelpers ├── Parallel.cs ├── FastComponent.cs └── GhPyDataAccess.cs ├── README.md ├── Assemblies ├── PythonInstantiatorProxy.cs └── PyghaLoader.cs ├── GhPython.csproj └── Forms ├── PythonScriptForm.resx ├── PythonScriptForm.cs └── PythonScriptForm.Designer.cs /package/__init__.py: -------------------------------------------------------------------------------- 1 | # GhPython package 2 | __all__ = ["components", "parallel"] 3 | -------------------------------------------------------------------------------- /Images/checked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcneel/ghpython/HEAD/Images/checked.png -------------------------------------------------------------------------------- /Images/python.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcneel/ghpython/HEAD/Images/python.ico -------------------------------------------------------------------------------- /Images/python.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcneel/ghpython/HEAD/Images/python.png -------------------------------------------------------------------------------- /Images/unchecked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcneel/ghpython/HEAD/Images/unchecked.png -------------------------------------------------------------------------------- /Samples/recursion.gh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcneel/ghpython/HEAD/Samples/recursion.gh -------------------------------------------------------------------------------- /Samples/quickUpdater.gh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcneel/ghpython/HEAD/Samples/quickUpdater.gh -------------------------------------------------------------------------------- /Samples/pygha/compile.py: -------------------------------------------------------------------------------- 1 | import clr 2 | 3 | clr.CompileModules("lineComponent.pygha", "makeLine.py") -------------------------------------------------------------------------------- /Samples/testDefinition.gh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcneel/ghpython/HEAD/Samples/testDefinition.gh -------------------------------------------------------------------------------- /Samples/smoothingPolyline.gh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcneel/ghpython/HEAD/Samples/smoothingPolyline.gh -------------------------------------------------------------------------------- /DocReplacement/DocStorage.cs: -------------------------------------------------------------------------------- 1 | 2 | namespace GhPython.DocReplacement 3 | { 4 | enum DocStorage : int 5 | { 6 | AutomaticMarshal = -10, 7 | InGrasshopperMemory = 0, 8 | InRhinoDoc = 10, 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | GhPython.csproj.user 2 | GhPython.suo 3 | /bin 4 | /obj 5 | /references/RhinoCommon.xml 6 | /references/GH_IO.dll 7 | /references/GH_IO.xml 8 | /references/Grasshopper.dll 9 | /references/Grasshopper.xml 10 | /references/RhinoCommon.dll 11 | /references/GH_Util.dll 12 | /references/Grasshopper.pdb 13 | /*.suo 14 | -------------------------------------------------------------------------------- /references/readme.txt: -------------------------------------------------------------------------------- 1 | Copy reference DLL and XML files to this directory. 2 | You need to use the RhinoCommon version (not Grasshopper) 3 | that comes with Rhino5, and is to find inside the 4 | Rhinoceros 5.0\System folder 5 | 6 | - GH_IO.dll 7 | - GH_IO.xml 8 | - Grasshopper.dll 9 | - Grasshopper.xml 10 | - RhinoCommon.dll 11 | - RhinoCommon.xml -------------------------------------------------------------------------------- /Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | 5 | [assembly: AssemblyTitle("GhPython")] 6 | [assembly: AssemblyDescription("Python component for grasshopper")] 7 | [assembly: AssemblyConfiguration("")] 8 | [assembly: AssemblyCompany("Robert McNeel & Associates")] 9 | [assembly: AssemblyProduct("GhPython")] 10 | [assembly: AssemblyCopyright("Copyright © 2012")] 11 | [assembly: AssemblyTrademark("")] 12 | [assembly: AssemblyCulture("")] 13 | 14 | [assembly: ComVisible(false)] 15 | 16 | [assembly: Guid("cd5bee67-20ef-4d9a-8b5e-3bce76011560")] 17 | 18 | 19 | // [0.5.1.0] 6 August 2012 S. Baer - updated version numbers as minor update to be compatible with GH 0.9 20 | [assembly: AssemblyVersion("0.6.0.3")] 21 | [assembly: AssemblyFileVersion("0.6.0.3")] 22 | -------------------------------------------------------------------------------- /Component/SpecialHints/SpecialLineHint.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Grasshopper.Kernel.Parameters; 3 | using Grasshopper.Kernel.Parameters.Hints; 4 | using Rhino.Geometry; 5 | 6 | namespace GhPython.Component 7 | { 8 | class SpecialLineHint : GH_LineHint, IGH_TypeHint 9 | { 10 | private readonly PythonComponent_OBSOLETE _component; 11 | 12 | public SpecialLineHint(PythonComponent_OBSOLETE component) 13 | { 14 | if (component == null) 15 | throw new ArgumentNullException("component"); 16 | 17 | _component = component; 18 | } 19 | 20 | bool IGH_TypeHint.Cast(object data, out object target) 21 | { 22 | bool toReturn = base.Cast(data, out target); 23 | 24 | if (toReturn && 25 | _component.DocStorageMode == DocReplacement.DocStorage.AutomaticMarshal && 26 | target != null) 27 | { 28 | Type t = target.GetType(); 29 | 30 | if (t == typeof (Line)) 31 | target = new LineCurve((Line) target); 32 | } 33 | 34 | return toReturn; 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 30, 30 12 | 13 | 14 | 600, 700 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /Component/SpecialHints/SpecialBoxHint.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Grasshopper.Kernel.Parameters; 3 | using Grasshopper.Kernel.Parameters.Hints; 4 | using Rhino.Geometry; 5 | 6 | namespace GhPython.Component 7 | { 8 | class SpecialBoxHint : GH_BoxHint, IGH_TypeHint 9 | { 10 | private readonly PythonComponent_OBSOLETE _component; 11 | 12 | public SpecialBoxHint(PythonComponent_OBSOLETE component) 13 | { 14 | if (component == null) 15 | throw new ArgumentNullException("component"); 16 | 17 | _component = component; 18 | } 19 | 20 | bool IGH_TypeHint.Cast(object data, out object target) 21 | { 22 | bool toReturn = base.Cast(data, out target); 23 | 24 | if (toReturn && 25 | _component.DocStorageMode == DocReplacement.DocStorage.AutomaticMarshal && 26 | target != null) 27 | { 28 | Type t = target.GetType(); 29 | 30 | if (t == typeof (Box)) 31 | target = Brep.CreateFromBox((Box) target); 32 | 33 | } 34 | 35 | return toReturn; 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /Component/SpecialHints/SpecialCircleHint.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Grasshopper.Kernel.Parameters; 3 | using Grasshopper.Kernel.Parameters.Hints; 4 | using Rhino.Geometry; 5 | 6 | namespace GhPython.Component 7 | { 8 | class SpecialCircleHint : GH_CircleHint, IGH_TypeHint 9 | { 10 | private readonly PythonComponent_OBSOLETE _component; 11 | 12 | public SpecialCircleHint(PythonComponent_OBSOLETE component) 13 | { 14 | if (component == null) 15 | throw new ArgumentNullException("component"); 16 | 17 | _component = component; 18 | } 19 | 20 | bool IGH_TypeHint.Cast(object data, out object target) 21 | { 22 | bool toReturn = base.Cast(data, out target); 23 | 24 | if (toReturn && 25 | _component.DocStorageMode == DocReplacement.DocStorage.AutomaticMarshal && 26 | target != null) 27 | { 28 | Type t = target.GetType(); 29 | 30 | if (t == typeof (Circle)) 31 | target = new ArcCurve((Circle) target); 32 | } 33 | 34 | return toReturn; 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /Samples/sampleScript.py: -------------------------------------------------------------------------------- 1 | # sample script to show how to use this component and the rhinoscriptsyntax 2 | """Constructs a sinusoidal series of circles. 3 | Inputs: 4 | x: The number of circles. (integer) 5 | y: The radius of each circle. (float) 6 | Outputs: 7 | a: The list of circles. (list of circle) 8 | b: The list of radii. (list of float) 9 | """ 10 | import math 11 | import rhinoscriptsyntax as rs 12 | 13 | if x is None: 14 | x = 24 # if nothing is connected to x, set x to something (24). 15 | if y is None: 16 | y = 0.3 # if nothing is connected to y, set y to 0.3. 17 | 18 | circles = [] # create a list. We will add IDs to it later on. 19 | radii = [] # ...and create another one. 20 | 21 | for i in range(int(x)): 22 | pt = (i, math.cos(i), 0) # a tuple (here for a point). 23 | id1 = rs.AddCircle(pt, y) 24 | circles.append(id1) 25 | endPt = rs.PointAdd(pt, (0, 0.3, 0)) # move the point by the vector. 26 | id2 = rs.AddLine(pt, endPt) 27 | radii.append(id2) 28 | 29 | a = circles 30 | b = radii -------------------------------------------------------------------------------- /Component/SpecialHints/SpecialPolylineHint.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Grasshopper.Kernel.Parameters; 3 | using Grasshopper.Kernel.Parameters.Hints; 4 | using Rhino.Geometry; 5 | 6 | namespace GhPython.Component 7 | { 8 | class SpecialPolylineHint : GH_PolylineHint, IGH_TypeHint 9 | { 10 | private readonly PythonComponent_OBSOLETE _component; 11 | 12 | public SpecialPolylineHint(PythonComponent_OBSOLETE component) 13 | { 14 | if (component == null) 15 | throw new ArgumentNullException("component"); 16 | 17 | _component = component; 18 | } 19 | 20 | bool IGH_TypeHint.Cast(object data, out object target) 21 | { 22 | bool toReturn = base.Cast(data, out target); 23 | 24 | if (toReturn && 25 | _component.DocStorageMode == DocReplacement.DocStorage.AutomaticMarshal && 26 | target != null) 27 | { 28 | Type t = target.GetType(); 29 | 30 | if (t == typeof (Polyline)) 31 | target = new PolylineCurve((Polyline) target); 32 | } 33 | 34 | return toReturn; 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /PythonPluginInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Drawing; 2 | using System.Reflection; 3 | using GhPython.Properties; 4 | using Grasshopper.Kernel; 5 | 6 | namespace GhPython 7 | { 8 | public class PythonPluginInfo : GH_AssemblyInfo 9 | { 10 | public override string Description 11 | { 12 | get { return "Python interpreter component for grasshopper"; } 13 | } 14 | 15 | public override Bitmap Icon 16 | { 17 | get { return Resources.python; } 18 | } 19 | 20 | public override string Name 21 | { 22 | get { return "Python Interpreter"; } 23 | } 24 | 25 | public override string Version 26 | { 27 | get { return Assembly.GetExecutingAssembly().GetName().Version.ToString(); } 28 | } 29 | 30 | public override string AuthorName 31 | { 32 | get { return "Robert McNeel and Associates"; } 33 | } 34 | 35 | public override string AuthorContact 36 | { 37 | get { return "giulio@mcneel.com"; } 38 | } 39 | 40 | public override GH_LibraryLicense License 41 | { 42 | get { return GH_LibraryLicense.opensource; } 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /Component/SpecialHints/SpecialArcHint.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Grasshopper.Kernel.Parameters; 3 | using Grasshopper.Kernel.Parameters.Hints; 4 | using Rhino.Geometry; 5 | 6 | namespace GhPython.Component 7 | { 8 | class SpecialArcHint : GH_ArcHint, IGH_TypeHint 9 | { 10 | readonly PythonComponent_OBSOLETE _component; 11 | 12 | public SpecialArcHint(PythonComponent_OBSOLETE component) 13 | { 14 | if (component == null) 15 | throw new ArgumentNullException("component"); 16 | 17 | _component = component; 18 | } 19 | 20 | bool IGH_TypeHint.Cast(object data, out object target) 21 | { 22 | bool toReturn = base.Cast(data, out target); 23 | 24 | if (toReturn && 25 | _component.DocStorageMode == DocReplacement.DocStorage.AutomaticMarshal && 26 | target != null) 27 | { 28 | Type t = target.GetType(); 29 | 30 | if (t == typeof(Arc)) 31 | target = new ArcCurve((Arc)target); 32 | 33 | else if (t == typeof(Circle)) 34 | target = new ArcCurve((Circle)target); 35 | } 36 | 37 | return toReturn; 38 | } 39 | } 40 | } 41 | 42 | -------------------------------------------------------------------------------- /Component/StringList.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Text; 3 | 4 | namespace GhPython.Component 5 | { 6 | /// 7 | /// Used to capture the output stream from an executing python script 8 | /// 9 | class StringList 10 | { 11 | private readonly List m_txts = new List(); 12 | 13 | public void Write(string s) 14 | { 15 | if (s == null) s = string.Empty; 16 | 17 | // print() seems to always adds a \n char at the end of the string 18 | // we want to counteract that 19 | if (s.EndsWith("\n")) s = s.Remove(s.Length - 1); 20 | 21 | m_txts.Add(s); 22 | } 23 | 24 | public void Reset() 25 | { 26 | m_txts.Clear(); 27 | } 28 | 29 | public IList Result 30 | { 31 | get { return new System.Collections.ObjectModel.ReadOnlyCollection(m_txts); } 32 | } 33 | 34 | public override string ToString() 35 | { 36 | if (m_txts.Count == 0) return string.Empty; 37 | 38 | var sb = new StringBuilder(m_txts[0]); 39 | for (int i = 1; i < m_txts.Count; i++) 40 | { 41 | sb.AppendLine().Append(m_txts[i]); 42 | } 43 | 44 | return sb.ToString(); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /GhPython.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2012 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GhPython", "GhPython.csproj", "{8955361B-7612-44DE-9B12-C081EC8C6F2E}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Any CPU = Debug|Any CPU 9 | Debug32|Any CPU = Debug32|Any CPU 10 | Mono|Any CPU = Mono|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {8955361B-7612-44DE-9B12-C081EC8C6F2E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {8955361B-7612-44DE-9B12-C081EC8C6F2E}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {8955361B-7612-44DE-9B12-C081EC8C6F2E}.Debug32|Any CPU.ActiveCfg = Debug32|Any CPU 17 | {8955361B-7612-44DE-9B12-C081EC8C6F2E}.Debug32|Any CPU.Build.0 = Debug32|Any CPU 18 | {8955361B-7612-44DE-9B12-C081EC8C6F2E}.Mono|Any CPU.ActiveCfg = Release|Any CPU 19 | {8955361B-7612-44DE-9B12-C081EC8C6F2E}.Mono|Any CPU.Build.0 = Release|Any CPU 20 | {8955361B-7612-44DE-9B12-C081EC8C6F2E}.Release|Any CPU.ActiveCfg = Release|Any CPU 21 | {8955361B-7612-44DE-9B12-C081EC8C6F2E}.Release|Any CPU.Build.0 = Release|Any CPU 22 | EndGlobalSection 23 | GlobalSection(SolutionProperties) = preSolution 24 | HideSolutionNode = FALSE 25 | EndGlobalSection 26 | EndGlobal 27 | -------------------------------------------------------------------------------- /Samples/sampleCommon.py: -------------------------------------------------------------------------------- 1 | """Constructs a recursive Koch curve. 2 | Inputs: 3 | x: The original line. (Line) 4 | y: The the number of subdivisions. (int) 5 | Outputs: 6 | a: The Koch curve, as a list of lines. 7 | """ 8 | import Rhino.Geometry as rg 9 | import math 10 | 11 | 12 | def Main(): 13 | global a # as usual, you can assign to the global scope with the "global" keyword 14 | a = [] 15 | SubdivideAndRotate(x, 0) 16 | 17 | def WeightedAvaragePts(pt1, pt2, pt1_part): 18 | rest = 1 - pt1_part 19 | return pt1 * rest + pt2 * pt1_part 20 | 21 | def SubdivideAndRotate(line, level): 22 | if level == y: 23 | a.append(line) 24 | return 25 | 26 | f = line.From #you can use "rg.Line." for exploring methods 27 | t = line.To 28 | b = WeightedAvaragePts(f, t, 1.0 / 3.0) 29 | c = WeightedAvaragePts(f, t, 2.0 / 3.0) 30 | 31 | m = WeightedAvaragePts(f, t, 0.5) 32 | bm = m - b 33 | 34 | e1 = bm / math.cos(angle) 35 | e1.Rotate(angle, rg.Vector3d(0,0,1)) 36 | e = e1 + b 37 | 38 | level += 1 39 | 40 | SubdivideAndRotate(rg.Line(f, b), level) 41 | SubdivideAndRotate(rg.Line(b, e), level) 42 | SubdivideAndRotate(rg.Line(e, c), level) 43 | SubdivideAndRotate(rg.Line(c, t), level) 44 | 45 | if x is None: x = rg.Line(rg.Point3d(0,0,0), rg.Point3d(10,10,0)) 46 | if y is None: y = 4 47 | angle = math.pi / 3 48 | 49 | Main() -------------------------------------------------------------------------------- /ScriptHelpers/Parallel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace GhPython.ScriptHelpers 6 | { 7 | public static class Parallel 8 | { 9 | public static IEnumerable Run(Func function, IList data, bool flatten) 10 | { 11 | if (data == null || data.Count < 1) 12 | return null; 13 | object[] rc = new object[data.Count]; 14 | // Run the first operation serial to account for classes attempting to lazily create data 15 | rc[0] = function(data[0]); 16 | if( rc.Length>1 ) 17 | System.Threading.Tasks.Parallel.For(1, rc.Length, (i) => { rc[i] = function(data[i]); }); 18 | if (!flatten) 19 | return rc; 20 | List flat = null; 21 | // see if the results are lists 22 | foreach (object obj in rc) 23 | { 24 | if (obj == null) 25 | continue; 26 | System.Collections.IEnumerable e = obj as System.Collections.IEnumerable; 27 | if (e == null) 28 | break; 29 | int sub_length = e.Cast().Count(); 30 | flat = new List(rc.Length * sub_length); //good guess 31 | break; 32 | } 33 | 34 | if (flat == null) 35 | return rc; 36 | foreach (object obj in rc) 37 | { 38 | if (obj == null) 39 | continue; 40 | System.Collections.IEnumerable e = obj as System.Collections.IEnumerable; 41 | if (e == null) 42 | { 43 | flat.Add(obj); 44 | } 45 | else 46 | { 47 | foreach (object subitem in e) 48 | flat.Add(subitem); 49 | } 50 | } 51 | return flat; 52 | } 53 | 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Component/SpecialHints/DynamicHint.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Grasshopper.Kernel.Parameters; 3 | using Grasshopper.Kernel.Parameters.Hints; 4 | using Rhino.Geometry; 5 | using System.Runtime.InteropServices; 6 | 7 | namespace GhPython.Component 8 | { 9 | [Guid("C1C11093-4F61-4E99-90C7-113C6421CC73")] 10 | class DynamicHint : GH_NullHint, IGH_TypeHint 11 | { 12 | private readonly PythonComponent_OBSOLETE m_component; 13 | 14 | public DynamicHint(PythonComponent_OBSOLETE component) 15 | { 16 | if (component == null) 17 | throw new ArgumentNullException("component"); 18 | 19 | m_component = component; 20 | } 21 | 22 | Guid IGH_TypeHint.HintID { get { return GetType().GUID; } } 23 | 24 | string IGH_TypeHint.TypeName { get { return "dynamic"; } } 25 | 26 | bool IGH_TypeHint.Cast(object data, out object target) 27 | { 28 | bool toReturn = base.Cast(data, out target); 29 | 30 | if (m_component.DocStorageMode == DocReplacement.DocStorage.AutomaticMarshal && target != null) 31 | { 32 | Type t = target.GetType(); 33 | 34 | if (t == typeof (Line)) 35 | target = new LineCurve((Line) target); 36 | 37 | else if (t == typeof (Arc)) 38 | target = new ArcCurve((Arc) target); 39 | 40 | else if (t == typeof (Circle)) 41 | target = new ArcCurve((Circle) target); 42 | 43 | else if (t == typeof (Ellipse)) 44 | target = ((Ellipse) target).ToNurbsCurve(); 45 | 46 | else if (t == typeof (Box)) 47 | target = Brep.CreateFromBox((Box) target); 48 | 49 | else if (t == typeof (BoundingBox)) 50 | target = Brep.CreateFromBox((BoundingBox) target); 51 | 52 | else if (t == typeof (Rectangle3d)) 53 | target = ((Rectangle3d) target).ToNurbsCurve(); 54 | 55 | else if (t == typeof (Polyline)) 56 | target = new PolylineCurve((Polyline) target); 57 | } 58 | 59 | return toReturn; 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /package/parallel.py: -------------------------------------------------------------------------------- 1 | import System.Threading.Tasks as tasks 2 | from System import Exception, AggregateException 3 | 4 | __run_native = None 5 | 6 | def run(function, data_list, flatten_results = False): 7 | """for each item in data_list execute the input function. Execution is 8 | done on as many threads as there are CPUs on the computer. 9 | Parameters: 10 | function: function to execute for each item in the data_list 11 | data_list: list, tuple, or other enumerable data structure 12 | flatten_list [opt]: if True, when results are lists of lists the 13 | results are flattened into a single list of results. If this is True, 14 | you cannot depend on the result list being the same size as the input list 15 | Returns: 16 | list of results containing the return from each call to the input function 17 | """ 18 | if __run_native!=None: 19 | return __run_native(function, data_list, flatten_results) 20 | pieces = [(i,data) for i,data in enumerate(data_list)] 21 | results = range(len(pieces)) 22 | 23 | def helper(piece): 24 | i, data = piece 25 | local_result = function(data) 26 | results[i] = local_result 27 | # Run first piece serial in case there is "set up" code in the function 28 | # that needs to be done once. All other iterations are done parallel 29 | helper(pieces[0]) 30 | pieces = pieces[1:] 31 | if pieces: tasks.Parallel.ForEach(pieces, helper) 32 | if flatten_results: 33 | temp = [] 34 | for result in results: 35 | if type(result) is list: 36 | for r in result: temp.append(r) 37 | else: 38 | temp.append(result) 39 | results = temp 40 | return results 41 | 42 | 43 | def __build_module(): 44 | global __run_native 45 | __run_native = None 46 | try: 47 | import GhPython 48 | __run_native = GhPython.ScriptHelpers.Parallel.Run 49 | except: 50 | __run_native = None 51 | 52 | 53 | __build_module() -------------------------------------------------------------------------------- /Component/PyUpgrader.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Grasshopper.Kernel; 3 | using Grasshopper.Kernel.Parameters; 4 | 5 | namespace GhPython.Component 6 | { 7 | public class PyUpgrader : IGH_UpgradeObject 8 | { 9 | public IGH_DocumentObject Upgrade(IGH_DocumentObject target, GH_Document document) 10 | { 11 | PythonComponent_OBSOLETE component_OBSOLETE = target as PythonComponent_OBSOLETE; 12 | if (component_OBSOLETE == null) 13 | return null; 14 | 15 | ZuiPythonComponent component_new = new ZuiPythonComponent(); 16 | 17 | component_new.HiddenCodeInput = component_OBSOLETE.HiddenCodeInput; 18 | component_new.HiddenOutOutput = component_OBSOLETE.HiddenOutOutput; 19 | 20 | if (component_new.HiddenCodeInput) 21 | component_new.Code = component_OBSOLETE.Code; 22 | 23 | if (GH_UpgradeUtil.SwapComponents(component_OBSOLETE, component_new)) 24 | { 25 | bool toRhinoScript = (component_OBSOLETE.DocStorageMode == DocReplacement.DocStorage.AutomaticMarshal); 26 | { 27 | foreach (var c in component_new.Params.Input) 28 | { 29 | var sc = c as Param_ScriptVariable; 30 | if (sc == null) continue; 31 | 32 | if (toRhinoScript) 33 | { 34 | IGH_TypeHint newHint; 35 | if (PythonHints.ToNewRhinoscriptHint(sc.TypeHint, out newHint)) 36 | sc.TypeHint = newHint; 37 | } 38 | else 39 | { 40 | PythonHints.ToNewRhinoCommonHint(sc); 41 | } 42 | } 43 | } 44 | 45 | component_OBSOLETE.Dispose(); 46 | 47 | return component_new; 48 | } 49 | return null; 50 | } 51 | 52 | public Guid UpgradeFrom 53 | { 54 | get { return typeof(PythonComponent_OBSOLETE).GUID; } 55 | } 56 | 57 | public Guid UpgradeTo 58 | { 59 | get { return typeof(ZuiPythonComponent).GUID; } 60 | } 61 | 62 | public DateTime Version 63 | { 64 | get { return new DateTime(2013, 10, 14, 0, 0, 0); } 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /DocReplacement/AttributedGeometry.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Grasshopper.Kernel.Types; 3 | using Rhino.DocObjects; 4 | using Rhino.Geometry; 5 | 6 | namespace GhPython.DocReplacement 7 | { 8 | public struct AttributedGeometry : IEquatable 9 | { 10 | IGH_GeometricGoo _geometry; 11 | ObjectAttributes _attributes; 12 | 13 | public AttributedGeometry(IGH_GeometricGoo item, ObjectAttributes attr) 14 | { 15 | _geometry = item; 16 | _attributes = attr; 17 | } 18 | 19 | internal IGH_GeometricGoo GhGeometry 20 | { 21 | get 22 | { 23 | return _geometry; 24 | } 25 | set 26 | { 27 | _geometry = value; 28 | } 29 | } 30 | 31 | public object Geometry 32 | { 33 | get 34 | { 35 | if (object.ReferenceEquals(_geometry, null)) 36 | return null; 37 | 38 | var toReturn = _geometry.ScriptVariable(); 39 | 40 | if (toReturn is Point3d) 41 | toReturn = new Point((Point3d)toReturn); 42 | 43 | return toReturn; 44 | } 45 | } 46 | 47 | public ObjectAttributes Attributes 48 | { 49 | get 50 | { 51 | return _attributes; 52 | } 53 | set 54 | { 55 | if (_attributes == null) 56 | throw new ArgumentNullException(); 57 | 58 | _attributes = value; 59 | } 60 | } 61 | 62 | public string Name 63 | { 64 | get 65 | { 66 | return object.ReferenceEquals(_attributes, null) ? null : _attributes.Name; 67 | } 68 | set 69 | { 70 | _attributes.Name = value; 71 | } 72 | } 73 | 74 | public override string ToString() 75 | { 76 | return string.Format("{0}, {1}", Geometry, (object)Attributes ?? "(default)"); 77 | } 78 | 79 | public override int GetHashCode() 80 | { 81 | int val; 82 | if (Geometry == null) 83 | val = 0; 84 | else if (Attributes == null) 85 | val = Geometry.GetHashCode(); 86 | else 87 | val = Geometry.GetHashCode() ^ (Attributes.GetHashCode() << 5); 88 | return val; 89 | } 90 | 91 | public bool Equals(AttributedGeometry other) 92 | { 93 | return Geometry == other.Geometry && 94 | Attributes == other.Attributes; 95 | } 96 | 97 | public override bool Equals(object obj) 98 | { 99 | return (obj is AttributedGeometry) && Equals((AttributedGeometry)obj); 100 | } 101 | 102 | public static bool operator ==(AttributedGeometry one, AttributedGeometry other) 103 | { 104 | return one.Equals(other); 105 | } 106 | 107 | public static bool operator !=(AttributedGeometry one, AttributedGeometry other) 108 | { 109 | return !one.Equals(other); 110 | } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /Component/GHComponentsLoader.cs: -------------------------------------------------------------------------------- 1 | /* 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.IO; 7 | using Rhino.Runtime; 8 | using Grasshopper.Kernel; 9 | using System.Reflection; 10 | using System.Collections.ObjectModel; 11 | 12 | namespace GhPython.Component 13 | { 14 | // Giulio Piacentino, 2011-9-19 15 | // This is experimental code to load Grasshopper "gha"s that needs to be reviewed 16 | class GHComponentsLoader 17 | { 18 | internal static void LoadAllLibraries() 19 | { 20 | var appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); 21 | 22 | var ghLibrariesPath = Path.Combine(appDataPath, "Grasshopper", "Libraries"); 23 | 24 | var files = Directory.EnumerateFiles(ghLibrariesPath, "*.gha.py"); 25 | var exceptions = new List(); 26 | 27 | PythonScript script = null; 28 | 29 | foreach (var file in files) 30 | { 31 | try 32 | { 33 | if (script == null) 34 | script = PythonScript.Create(); 35 | 36 | script.ExecuteScript( 37 | string.Format("from clr import AddReference\nAddReference(\"{0}\")\nAddReference(\"{1}\")", 38 | Assembly.GetExecutingAssembly().FullName, 39 | typeof(IGH_Component).Assembly.FullName 40 | )); 41 | 42 | 43 | if (!script.ExecuteFile(file)) 44 | throw new InvalidOperationException(string.Format("File {0} cannot be executed", file)); 45 | } 46 | catch(Exception ex) 47 | { 48 | exceptions.Add(ex); 49 | } 50 | } 51 | 52 | //TODO: Say something in case of bad loadings 53 | //TODO: chaeck & install 54 | 55 | var l = Plugins.List; 56 | } 57 | } 58 | } 59 | 60 | namespace GhPython 61 | { 62 | public static class Plugins 63 | { 64 | static List list = new List(); 65 | 66 | public static void Add(IGH_Component component) 67 | { 68 | Type t = component.GetType(); 69 | var ctors = t.GetConstructors(BindingFlags.NonPublic); 70 | 71 | try 72 | { 73 | object newobj = System.Activator.CreateInstance(t); 74 | } 75 | 76 | * (Exception ex) 77 | { 78 | int h = 0; 79 | 80 | } 81 | list.Add(component); 82 | } 83 | 84 | public static IList List 85 | { 86 | get { 87 | 88 | return new ReadOnlyCollection(list); 89 | } 90 | } 91 | } 92 | } 93 | */ -------------------------------------------------------------------------------- /ScriptHelpers/FastComponent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Grasshopper.Kernel; 4 | 5 | namespace GhPython.ScriptHelpers 6 | { 7 | public static class FastComponent 8 | { 9 | public static List Run(GH_Component component, IList data, System.Collections.IDictionary kwargs) 10 | { 11 | Type t = component.GetType(); 12 | var method = t.GetMethod("SolveInstance", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); 13 | 14 | List input = BuildInputList(data); 15 | 16 | int output_count = component.Params.Output.Count; 17 | int iterations = input.Count; 18 | List output = new List(output_count); 19 | for (int i = 0; i < output_count; i++) 20 | output.Add(new object[iterations]); 21 | 22 | bool run_parallel = false; 23 | if (kwargs != null && kwargs.Contains("multithreaded")) 24 | run_parallel = (bool)kwargs["multithreaded"]; 25 | 26 | if (run_parallel) 27 | { 28 | System.Threading.Tasks.Parallel.For(0, input.Count, (iteration) => SolveIteration(iteration, component, input, output, method)); 29 | } 30 | else 31 | { 32 | for( int iteration=0; iteration input, List output, System.Reflection.MethodInfo method) 41 | { 42 | var da = new GhPyDataAccess(component, input[iteration]); 43 | method.Invoke(component, new object[] { da }); 44 | object[] solve_results = da.Output; 45 | if (solve_results != null) 46 | { 47 | for (int j = 0; j < solve_results.Length; j++) 48 | { 49 | output[j][iteration] = solve_results[j]; 50 | } 51 | } 52 | } 53 | 54 | static List BuildInputList(IList data) 55 | { 56 | List data_list = new List(data); 57 | List rc = new List(); 58 | BuildInputHelper(0, data_list, ref rc); 59 | return rc; 60 | } 61 | static void BuildInputHelper(int column, IList data, ref List input) 62 | { 63 | if (column == data.Count) 64 | { 65 | object[] items= new object[data.Count]; 66 | data.CopyTo(items,0); 67 | input.Add(items); 68 | return; 69 | } 70 | var list = data[column] as System.Collections.IList; 71 | if (list != null) 72 | { 73 | foreach (var item in list) 74 | { 75 | data[column] = item; 76 | BuildInputHelper(column + 1, data, ref input); 77 | } 78 | data[column] = list; 79 | } 80 | else 81 | BuildInputHelper(column + 1, data, ref input); 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Python interpreter addon for Grasshopper 2 | ======================================== 3 | 4 | We are having fun building this Grasshopper-Python component, you are welcome to join us. 5 | 6 | Discussions for help on using or configuring this addon can be found at: 7 | 8 | * http://www.grasshopper3d.com/forum/categories/vb-c-and-python-coding/listForCategory 9 | * http://python.rhino3d.com/ 10 | 11 | ![Screenshot](http://api.ning.com/files/RHCoSpQhwe5lBPPJoOrqxzO2qHwzRZ8l7WIIXCo*CKez7e92Bkbs4rw83hAt*YNukQKytSKXwKAHsATYZ9MXZaLtdoFweG-e/pythoncomp.png) 12 | 13 | Installation / Configuration 14 | ---------------------------- 15 | You can get a version of this addon ready for installation from http://www.food4rhino.com/project/ghpython 16 | 17 | If you are building this addon from source, use the _GrasshopperDeveloperSettings command to add the output directory for your .gha to the list of directories Grasshopper pays attention to. 18 | 19 | 20 | Contributing to GhPython 21 | ------------------------ 22 | There are many ways to contribute to this project: 23 | 24 | * Test the addon and report bugs/wishes to the issue list at https://github.com/mcneel/ghpython/issues 25 | * Create sample python scripts that we can embed in the addon to help others learn 26 | * Create sample ghx files for using this addon to help others learn 27 | * Directly edit the source code using git. If you need help with this, please let us know. 28 | 29 | Compiling the Source 30 | -------------------- 31 | You are going to need: 32 | 33 | * The latest Rhino5 WIP (http://www.rhino3d.com/nr.htm) 34 | * Grasshopper (http://www.grasshopper3d.com) 35 | * Visual C# 2012 36 | 37 | Steps: 38 | 39 | * Get the source code by downloading everything as a zip or using git 40 | * Copy the appropriate DLLs to the references directory (read the readme.txt in the references directory for a list of DLLs) 41 | * Start GhPython.sln and build!!! 42 | 43 | Authors 44 | ------- 45 | Steve Baer - https://github.com/sbaer steve@mcneel.com 46 | 47 | Giulio Piacentino - https://github.com/piac giulio@mcneel.com 48 | 49 | Legal Stuff 50 | ----------- 51 | Copyright (c) 2011-2013 Robert McNeel & Associates. All Rights Reserved. 52 | 53 | Permission is hereby granted, free of charge, to any person obtaining a copy of 54 | this software and associated documentation files (the "Software"), to deal in 55 | the Software without restriction, including without limitation the rights to use, 56 | copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 57 | Software. 58 | 59 | THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY. ALL IMPLIED 60 | WARRANTIES OF FITNESS FOR ANY PARTICULAR PURPOSE AND OF MERCHANTABILITY ARE HEREBY 61 | DISCLAIMED. 62 | 63 | Rhinoceros is a registered trademark of Robert McNeel & Associates. 64 | 65 | ![Rhino](https://lh6.googleusercontent.com/-pQtuyrwmcmg/TYtWECHGYNI/AAAAAAAAA7Y/rphjSmq1cuo/s200/Rhino_logo_wire.jpg) ![Python](http://www.food4rhino.com/sites/default/files/imagecache/Thumbnail-project-node/pythonlogo.png.pagespeed.ce.eP1CQxaAba.png) 66 | -------------------------------------------------------------------------------- /Samples/pygha/makeLine.py: -------------------------------------------------------------------------------- 1 | import clr 2 | 3 | ############################################################### 4 | # 1. This is a sample of the code to create a Line component in Python. 5 | # David can make this slightly simpler by never using protected nested types. 6 | 7 | clr.AddReference("Grasshopper") 8 | import Grasshopper 9 | 10 | import System, Rhino 11 | clr.AddReference("RhinoCommon") 12 | import Rhino.Geometry as rh 13 | 14 | class MyLineComponent(Grasshopper.Kernel.GH_Component): 15 | 16 | def __new__(cls): 17 | 18 | # Information is: Name, Nickname, Description, Category, Subcategory 19 | instance = Grasshopper.Kernel.GH_Component.__new__(cls, "Line from ends", "Line", "Makes a line from two points.", "PYTHON", "Py") 20 | return instance 21 | 22 | def get_ComponentGuid(self): 23 | return System.Guid("8549a015-74c5-479f-8633-c01a9d06a7fa") 24 | 25 | def SetUpParam(self, p, name, nickname, description): 26 | p.Name = name 27 | p.NickName = nickname 28 | p.Description = description 29 | 30 | 31 | def RegisterInputParams(self, pManager): 32 | p0 = Grasshopper.Kernel.Parameters.Param_Point() 33 | self.SetUpParam(p0, "Point A", "A", "The first point") 34 | p0.Access = Grasshopper.Kernel.GH_ParamAccess.item 35 | self.Params.Input.Add(p0) 36 | 37 | p1 = Grasshopper.Kernel.Parameters.Param_Point() 38 | self.SetUpParam(p1, "Point B", "B", "The second point") 39 | p1.Access = Grasshopper.Kernel.GH_ParamAccess.item 40 | self.Params.Input.Add(p1) 41 | 42 | 43 | def RegisterOutputParams(self, pManager): 44 | l0 = Grasshopper.Kernel.Parameters.Param_Line() 45 | self.SetUpParam(l0, "Line", "L", "The resulting line") 46 | self.Params.Output.Add(l0) 47 | 48 | def SolveInstance(self, DA): 49 | pointA = Rhino.Geometry.Point3d(0,0,0) 50 | pointB = Rhino.Geometry.Point3d(0,0,0) 51 | 52 | v0 = DA.GetData(0, pointA) 53 | v1 = DA.GetData(1, pointB) 54 | if v0[0] and v1[1]: 55 | line = rh.Line(v0[1], v1[1]) 56 | DA.SetData(0, line) 57 | 58 | def get_Internal_Icon_24x24(self): 59 | import base64 60 | o = """iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACx 61 | jwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41 62 | LjEwMPRyoQAAAalJREFUSEvVlD1Lw1AYhZsPWhpiCzFYEGsoCKVGsB2ySUZJwWy1hLahoVTUXVBx 63 | sk466eLg6CD+gY7+AhcdnHQQdLSToGDx47ylgbSb3rt44XATwvuccz/yxmL/cMwgs8M7twpgAF1B 64 | n+l0+rDdbk+wmsgArECX0Dv0HapcLp/CQGQxoOJuFBo+J5PJHuANFvig1nEcM5VKPY2bGIZxDYMi 65 | swEBTNNcxfQVNbFt+wIGSS4GgGiqqt5omvZAJrIsv7VarQ0ecGV4uHNIazWbTT+TydxCd3hf4mFQ 66 | FAShl8/n90KY7/uG67onMJhkNfAAUKrVagOwTUgKgTzg8/Qj4fYcERTABGvaaP3g6lmW1QmCYJ8V 67 | ro0lI3hfUZQdAkPUb/48qAU8SpJkDwk6zblc7rxWq3UAp+9MY5nuNG4J9Zdd6DUej7sAT0ELTORh 68 | 8RkZhEokEs+VSmULcIEHnJb/EjUQRfGjUCis84ATY7A946LtipwJk9fI9gDc13X9vlQqdT3PW2Pt 69 | 8YPtiULr9foxoNuQA00zRUfxbDabPeANHQmFlIs8krKu9Ff1P/WNhQUWh+7RAAAAAElFTkSuQmCC""" 70 | return System.Drawing.Bitmap(System.IO.MemoryStream(System.Convert.FromBase64String(o))) -------------------------------------------------------------------------------- /Samples/helpText.html: -------------------------------------------------------------------------------- 1 |

This component allows to use both RhinoCommon and RhinoScript from within 2 | Grasshopper. Here some Q&As.

3 | 4 |

How can I use the rhinoscriptsyntax?

5 |

By importing RhinoScript, for example by writing:

6 |
import rhinoscriptsyntax as rs
7 |

...and then calling some rhinoscript functions...

8 |
line = rs.AddLine((1, 2, 3), (10, 11, 12))
 9 | a = line
10 | 11 |

How can I use RhinoCommon?

12 |

By importing from the Rhino module, for example by writing:

13 |
from Rhino.Geometry import Point3d, Line
14 |

...and then assigning some new geometry to the results

15 |
a = Line(Point3d(1, 2, 3), Point3d(10, 11, 12))
16 | 17 |

What is "ghdoc" and how does it relate to the rhinoscriptsyntax?

18 |

The ghdoc variable is provided by the component for better RhinoScript 19 | library support.
20 | This library is imperative, and it is build from a set of 21 | functions that act on geometrical types through one level of indirection: 22 | most of the time, the user does not work with the geometry itself 23 | but with an identifier (Guid) of geometry that is present in a document.
24 | This is exactly what ghdoc is: it is a reference to the document that the RhinoScript 25 | library implicitly targets with all Add__() calls (for example, AddLine()).
26 | The scriptcontext module has a doc variable with the currenly active document, 27 | that can be assigned by you to ghdoc, or RhinoDoc.ActiveDoc, the Rhino document. 28 |

29 | 30 |

Is RhinoScript use within GhPython less ideal than RhinoCommon?

31 |

While targeting the ghdoc variable, the special Grasshopper document 32 | is used, therefore we can use Grasshopper while leaving the Rhino document unchanged. 33 | This saves uncountable Undo's, and makes it easy to structure ideas 34 | through the Grasshopper definition.
35 | This means that both RhinoCommon or RhinoScript are good in practice.

36 | 37 |

Is the rhinoscriptsyntax target irrelevant if using solely RhinoCommon 38 | classes?

39 |

Yes. If you create class instances (objects), you will need to create 40 | also your own collection objects to store them (mostly lists, trees). You 41 | can imagine the ghdoc as being an alternative to them, just that you do 42 | not access data by index (number), but by Guid. So you can use the 43 | RhinoScript or the RhinoCommon libraries independently or mix them. 44 | The RhinoScript implementation in Rhino is open-source and is all written 45 | in RhinoCommon. Also the ghdoc implementation is open-source, and is 46 | here. 47 |

48 | 49 |

Are there RhinoScript and/or RhinoCommon objects which are not 50 | recognized as valid Grasshopper geometry?

51 |

Yes, sure, Grasshopper handles only a portion of all available types.
52 | Basically, unhandled types are all the types that do not exists in the 53 | 'Params' tab.
54 | For example, there is no textdot and no leader. When/if Grasshopper one day 55 | will support these types, these calls will be implemented.

56 | 57 |

How do I use DataTree's?

58 |

Here 59 | is a small sample.
60 | However, 80% of the times it is not necessary to program for 61 | DataTrees, as the logic itself can be applied per-list and Grasshopper handles 62 | list-iteration.

63 | 64 |

Any more tips?

65 |

It's probably quite easy to get started, but then you might need to know some more tips to be 66 | proficient. Many tricks have to do with Python (for example, do you know the type() and dir() functions)? 67 | Other might have more to do with the component setup. (There's even a secret ghenv variable).

68 | 69 |

Can I ask more questions?

70 | Yes, on the forum... -------------------------------------------------------------------------------- /Assemblies/PythonInstantiatorProxy.cs: -------------------------------------------------------------------------------- 1 | #if GH_0_9 2 | 3 | using System; 4 | using System.Drawing; 5 | using System.IO; 6 | using System.Reflection; 7 | using System.Security.Cryptography; 8 | using System.Text; 9 | using Grasshopper; 10 | using Grasshopper.Kernel; 11 | using Rhino; 12 | 13 | namespace GhPython.Assemblies 14 | { 15 | class PythonInstantiatorProxy : IGH_ObjectProxy 16 | { 17 | dynamic _operations; 18 | object _pythonType; 19 | 20 | private Bitmap _icon; 21 | private bool _obsolete; 22 | private bool _compliant; 23 | private GH_Exposure _exposure; 24 | private string _location; 25 | private IGH_InstanceDescription _description; 26 | 27 | internal PythonInstantiatorProxy(IGH_DocumentObject obj, object pythonType, dynamic operations, string location) 28 | { 29 | _operations = operations; 30 | _pythonType = pythonType; 31 | 32 | _location = string.Empty; 33 | _description = new GH_InstanceDescription(obj); 34 | Guid = obj.ComponentGuid; 35 | _icon = obj.Icon_24x24; 36 | _exposure = obj.Exposure; 37 | _obsolete = obj.Obsolete; 38 | _compliant = true; 39 | if (obj is IGH_ActiveObject) 40 | { 41 | IGH_ActiveObject actobj = (IGH_ActiveObject)obj; 42 | if (!actobj.SDKCompliancy(RhinoApp.ExeVersion, RhinoApp.ExeServiceRelease)) 43 | { 44 | this._compliant = false; 45 | } 46 | } 47 | Type = obj.GetType(); 48 | this.LibraryGuid = GH_Convert.StringToGuid(location); 49 | this._location = location; 50 | if (this._location.Length > 0) 51 | { 52 | this._location = this._location.Replace("file:///", string.Empty); 53 | this._location = this._location.Replace("/", Convert.ToString(Path.DirectorySeparatorChar)); 54 | } 55 | } 56 | 57 | private PythonInstantiatorProxy() { } 58 | 59 | public string Location 60 | { 61 | get 62 | { 63 | return this._location; 64 | } 65 | } 66 | 67 | public Guid LibraryGuid 68 | { 69 | get; 70 | private set; 71 | } 72 | 73 | public Bitmap Icon 74 | { 75 | get 76 | { 77 | if (this._icon == null && GH_InstanceServer.IsComponentServer) 78 | { 79 | IGH_DocumentObject obj = GH_InstanceServer.ComponentServer.EmitObject(this.Guid); 80 | if (obj != null) 81 | { 82 | this._icon = obj.Icon_24x24; 83 | } 84 | if (this._icon == null) 85 | { 86 | this._icon = Grasshopper.GUI.GH_StandardIcons.BlankObjectIcon_24x24; 87 | } 88 | } 89 | return this._icon; 90 | } 91 | } 92 | 93 | public IGH_InstanceDescription Desc 94 | { 95 | get 96 | { 97 | return this._description; 98 | } 99 | } 100 | 101 | public Type Type 102 | { 103 | get; 104 | private set; 105 | } 106 | 107 | public GH_ObjectType Kind 108 | { 109 | get 110 | { 111 | return GH_ObjectType.CompiledObject; 112 | } 113 | } 114 | 115 | public Guid Guid 116 | { 117 | get; 118 | private set; 119 | } 120 | 121 | public GH_Exposure Exposure 122 | { 123 | get 124 | { 125 | return this._exposure; 126 | } 127 | set 128 | { 129 | this._exposure = value; 130 | } 131 | } 132 | 133 | public bool SDKCompliant 134 | { 135 | get 136 | { 137 | return this._compliant; 138 | } 139 | } 140 | 141 | public bool Obsolete 142 | { 143 | get 144 | { 145 | return this._obsolete; 146 | } 147 | } 148 | 149 | public IGH_ObjectProxy DuplicateProxy() 150 | { 151 | PythonInstantiatorProxy dup = new PythonInstantiatorProxy(); 152 | dup._description = new GH_InstanceDescription(this.Desc); 153 | dup.Guid = this.Guid; 154 | dup.Type = this.Type; 155 | dup._location = this.Location; 156 | dup._exposure = this.Exposure; 157 | dup.LibraryGuid = this.LibraryGuid; 158 | dup._compliant = this.SDKCompliant; 159 | dup._obsolete = this.Obsolete; 160 | if (this._icon != null) 161 | { 162 | dup._icon = (Bitmap)this._icon.Clone(); 163 | } 164 | return dup; 165 | } 166 | 167 | public IGH_DocumentObject CreateInstance() 168 | { 169 | try 170 | { 171 | object docObject = _operations.Invoke(_pythonType); 172 | if (docObject != null) 173 | { 174 | return (docObject as IGH_DocumentObject); 175 | } 176 | } 177 | catch 178 | { 179 | } 180 | return null; 181 | } 182 | } 183 | } 184 | #endif -------------------------------------------------------------------------------- /Component/ZUIPythonComponent.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using Grasshopper.Kernel; 3 | using Grasshopper.Kernel.Parameters; 4 | using Grasshopper.Kernel.Parameters.Hints; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Runtime.InteropServices; 8 | 9 | namespace GhPython.Component 10 | { 11 | [Guid("410755B1-224A-4C1E-A407-BF32FB45EA7E")] 12 | public class ZuiPythonComponent : ScriptingAncestorComponent, IGH_VariableParameterComponent 13 | { 14 | protected override void AddDefaultInput(GH_InputParamManager pManager) 15 | { 16 | pManager.AddParameter(CreateParameter(GH_ParameterSide.Input, pManager.ParamCount)); 17 | pManager.AddParameter(CreateParameter(GH_ParameterSide.Input, pManager.ParamCount)); 18 | } 19 | 20 | protected override void AddDefaultOutput(GH_OutputParamManager pManager) 21 | { 22 | pManager.RegisterParam(CreateParameter(GH_ParameterSide.Output, pManager.ParamCount)); 23 | } 24 | 25 | internal override void FixGhInput(Param_ScriptVariable i, bool alsoSetIfNecessary = true) 26 | { 27 | i.Name = i.NickName; 28 | 29 | if (string.IsNullOrEmpty(i.Description)) 30 | i.Description = string.Format("Script variable {0}", i.NickName); 31 | i.AllowTreeAccess = true; 32 | i.Optional = true; 33 | i.ShowHints = true; 34 | i.Hints = GetHints(); 35 | 36 | if (alsoSetIfNecessary && i.TypeHint == null) 37 | i.TypeHint = i.Hints[1]; 38 | } 39 | 40 | static readonly List g_hints = new List(); 41 | static List GetHints() 42 | { 43 | lock (g_hints) 44 | { 45 | if (g_hints.Count == 0) 46 | { 47 | g_hints.Add(new NoChangeHint()); 48 | g_hints.Add(new GhDocGuidHint()); 49 | 50 | g_hints.AddRange(PossibleHints); 51 | 52 | g_hints.RemoveAll(t => 53 | { 54 | var y = t.GetType(); 55 | return (y == typeof (GH_DoubleHint_CS) || y == typeof (GH_StringHint_CS)); 56 | }); 57 | g_hints.Insert(4, new NewFloatHint()); 58 | g_hints.Insert(6, new NewStrHint()); 59 | 60 | g_hints.Add(new GH_BoxHint()); 61 | 62 | g_hints.Add(new GH_HintSeparator()); 63 | 64 | g_hints.Add(new GH_LineHint()); 65 | g_hints.Add(new GH_CircleHint()); 66 | g_hints.Add(new GH_ArcHint()); 67 | g_hints.Add(new GH_PolylineHint()); 68 | 69 | g_hints.Add(new GH_HintSeparator()); 70 | 71 | g_hints.Add(new GH_CurveHint()); 72 | g_hints.Add(new GH_MeshHint()); 73 | g_hints.Add(new GH_SurfaceHint()); 74 | g_hints.Add(new GH_BrepHint()); 75 | g_hints.Add(new GH_GeometryBaseHint()); 76 | } 77 | } 78 | return g_hints; 79 | } 80 | 81 | #region IGH_VariableParameterComponent implementation 82 | 83 | public IGH_Param CreateParameter(GH_ParameterSide side, int index) 84 | { 85 | switch (side) 86 | { 87 | case GH_ParameterSide.Input: 88 | { 89 | return new Param_ScriptVariable 90 | { 91 | NickName = GH_ComponentParamServer.InventUniqueNickname("xyzuvwst", this.Params.Input), 92 | Name = NickName, 93 | Description = "Script variable " + NickName, 94 | }; 95 | } 96 | case GH_ParameterSide.Output: 97 | { 98 | return new Param_GenericObject 99 | { 100 | NickName = GH_ComponentParamServer.InventUniqueNickname("abcdefghijklmn", this.Params.Output), 101 | Name = NickName, 102 | Description = "Script variable " + NickName, 103 | }; 104 | } 105 | default: 106 | { 107 | return null; 108 | } 109 | } 110 | } 111 | 112 | bool IGH_VariableParameterComponent.DestroyParameter(GH_ParameterSide side, int index) 113 | { 114 | if(side == GH_ParameterSide.Input && !HiddenCodeInput && index == 0) 115 | m_inner_codeInput = Code; 116 | 117 | return true; 118 | } 119 | 120 | bool IGH_VariableParameterComponent.CanInsertParameter(GH_ParameterSide side, int index) 121 | { 122 | return index > -1; 123 | } 124 | 125 | bool IGH_VariableParameterComponent.CanRemoveParameter(GH_ParameterSide side, int index) 126 | { 127 | return (this as IGH_VariableParameterComponent).CanInsertParameter(side, index); 128 | } 129 | 130 | public override void VariableParameterMaintenance() 131 | { 132 | foreach (Param_ScriptVariable variable in Params.Input.OfType()) 133 | FixGhInput(variable); 134 | 135 | foreach (Param_GenericObject i in Params.Output.OfType()) 136 | { 137 | i.Name = i.NickName; 138 | if (string.IsNullOrEmpty(i.Description)) 139 | i.Description = i.NickName; 140 | } 141 | } 142 | 143 | protected override void SetScriptTransientGlobals() 144 | { 145 | base.SetScriptTransientGlobals(); 146 | 147 | m_py.ScriptContextDoc = g_document; 148 | m_marshal = new NewComponentIOMarshal(g_document, this); 149 | m_py.SetVariable(DOCUMENT_NAME, g_document); 150 | m_py.SetIntellisenseVariable(DOCUMENT_NAME, g_document); 151 | } 152 | 153 | public override Guid ComponentGuid 154 | { 155 | get { return typeof(ZuiPythonComponent).GUID; } 156 | } 157 | 158 | #endregion 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /Component/PythonEnvironment.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Grasshopper.Kernel; 3 | using Rhino.Runtime; 4 | using System.Reflection; 5 | using System.Linq; 6 | using System.Collections.Generic; 7 | using System.Collections; 8 | 9 | namespace GhPython.Component 10 | { 11 | public class PythonEnvironment 12 | { 13 | internal const string GHPYTHONLIB_NAME = "ghpythonlib"; 14 | 15 | internal PythonEnvironment(GH_Component component, PythonScript script) 16 | { 17 | Component = component; 18 | Script = script; 19 | 20 | if (script != null) 21 | { 22 | Type scriptType = script.GetType(); 23 | 24 | var scopeField = scriptType.GetField("m_scope"); 25 | if (scopeField != null) 26 | { 27 | LocalScope = scopeField.GetValue(script); 28 | } 29 | 30 | var intellisenseField = scriptType.GetField("m_intellisense", 31 | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.GetField); 32 | if (intellisenseField != null) 33 | { 34 | Intellisense = intellisenseField.GetValue(script); 35 | if (Intellisense != null) 36 | { 37 | var intellisenseType = Intellisense.GetType(); 38 | var scopeProperty = intellisenseType.GetProperty("Scope"); 39 | IntellisenseScope = scopeProperty.GetValue(Intellisense, null); 40 | } 41 | } 42 | 43 | var baseType = scriptType.BaseType; 44 | if (baseType != null && baseType != typeof(object)) 45 | { 46 | var hostType = baseType.Assembly.GetType("RhinoPython.Host"); 47 | if (hostType != null) 48 | { 49 | var engineInfo = hostType.GetProperty("Engine"); 50 | if (engineInfo != null) 51 | { 52 | Engine = engineInfo.GetValue(null, null); 53 | 54 | if (Engine != null) 55 | { 56 | var runtimeInfo = Engine.GetType().GetProperty("Runtime"); 57 | Runtime = runtimeInfo.GetValue(Engine, null); 58 | } 59 | } 60 | 61 | var scopeInfo = hostType.GetProperty("Scope", BindingFlags.NonPublic | 62 | BindingFlags.GetProperty | 63 | BindingFlags.Static); 64 | if (scopeInfo != null) 65 | ScriptScope = scopeInfo.GetValue(null, null); 66 | } 67 | } 68 | } 69 | } 70 | 71 | public GH_Component Component { get; internal set; } 72 | 73 | public PythonScript Script { get; internal set; } 74 | 75 | public object LocalScope { get; internal set; } 76 | 77 | public object ScriptScope { get; internal set; } 78 | 79 | public object Intellisense { get; internal set; } 80 | 81 | public object IntellisenseScope { get; internal set; } 82 | 83 | public object Engine { get; internal set; } 84 | 85 | public object Runtime { get; internal set; } 86 | 87 | public Version Version { get { return Assembly.GetExecutingAssembly().GetName().Version; } } 88 | 89 | public IGH_DataAccess DataAccessManager { get; internal set; } 90 | 91 | public void LoadAssembly(Assembly assembly) 92 | { 93 | FunctionalityLoad(assembly); 94 | 95 | IList list = GetIntellisenseList(); 96 | if (list == null) return; 97 | 98 | foreach (var namesp in GetToplevelNamespacesForAssembly(assembly)) 99 | { 100 | if (!list.Contains(namesp)) 101 | list.Add(namesp); 102 | } 103 | } 104 | 105 | public void AddGhPythonPackage() 106 | { 107 | IList list = GetIntellisenseList(); 108 | if (list == null) return; 109 | 110 | bool contained = false; 111 | for (int i = 0; i < list.Count; i++) 112 | { 113 | var itemString = list[i] as string; 114 | if (itemString == null) continue; 115 | 116 | if (itemString.Equals(GHPYTHONLIB_NAME, StringComparison.InvariantCulture)) 117 | contained = true; 118 | } 119 | 120 | // adds package 121 | if (!contained) 122 | list.Add(GHPYTHONLIB_NAME); 123 | } 124 | 125 | private IList GetIntellisenseList() 126 | { 127 | IList list = null; 128 | 129 | // now intellisense 130 | if (IntellisenseScope == null) return list; 131 | 132 | // we really want to get intellisense right away. No matter what 133 | // so, we first make it cache, then add to it 134 | 135 | var intellisense_type = Intellisense.GetType(); 136 | var m = intellisense_type.GetMethod("GetModuleList", BindingFlags.Public | BindingFlags.Instance | BindingFlags.InvokeMethod); 137 | m.Invoke(Intellisense, null); 138 | 139 | var ex_m_autocomplete_modules = intellisense_type.GetField("m_autocomplete_modules", 140 | BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance); 141 | 142 | if (ex_m_autocomplete_modules == null) return list; 143 | return ex_m_autocomplete_modules.GetValue(Intellisense) as IList; 144 | } 145 | 146 | private void FunctionalityLoad(Assembly assembly) 147 | { 148 | var runtime = Runtime as dynamic; 149 | runtime.LoadAssembly(assembly); 150 | } 151 | 152 | private static IEnumerable GetToplevelNamespacesForAssembly(Assembly assembly) 153 | { 154 | return assembly.GetTypes().Select(GetTopLevelNamespace) 155 | .Where(s => !string.IsNullOrEmpty(s)).Distinct(); 156 | } 157 | 158 | // question by David here: 159 | // http://stackoverflow.com/questions/1549198/finding-all-namespaces-in-an-assembly-using-reflection-dotnet 160 | static string GetTopLevelNamespace(Type t) 161 | { 162 | string ns = t.Namespace ?? ""; 163 | int firstDot = ns.IndexOf('.'); 164 | return firstDot == -1 ? ns : ns.Substring(0, firstDot); 165 | } 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /Component/SpecialHints/AllNewHints.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Grasshopper.Kernel.Parameters; 3 | using Grasshopper.Kernel.Parameters.Hints; 4 | using Rhino.Geometry; 5 | using System.Collections.Generic; 6 | using System.Runtime.InteropServices; 7 | 8 | namespace GhPython.Component 9 | { 10 | [Guid("39FBC626-7A01-46AB-A18E-EC1C0C41685B")] 11 | public class NewFloatHint : GH_DoubleHint_CS, IGH_TypeHint 12 | { 13 | Guid IGH_TypeHint.HintID { get { return this.GetType().GUID; } } 14 | 15 | string IGH_TypeHint.TypeName { get { return "float"; } } 16 | } 17 | 18 | [Guid("37261734-EEC7-4F50-B6A8-B8D1F3C4396B")] 19 | public class NewStrHint : GH_StringHint_CS, IGH_TypeHint 20 | { 21 | Guid IGH_TypeHint.HintID { get { return this.GetType().GUID; } } 22 | 23 | string IGH_TypeHint.TypeName { get { return "str"; } } 24 | } 25 | 26 | [Guid("87F87F55-5B71-41F4-8AEA-21D494016F81")] 27 | public class GhDocGuidHint : GH_NullHint, IGH_TypeHint 28 | { 29 | Guid IGH_TypeHint.HintID { get { return this.GetType().GUID; } } 30 | bool IGH_TypeHint.Cast(object data, out object target) 31 | { 32 | bool toReturn = base.Cast(data, out target); 33 | 34 | if (toReturn && target != null) 35 | { 36 | Type t = target.GetType(); 37 | 38 | if (t == typeof(Line)) 39 | target = new LineCurve((Line)target); 40 | 41 | else if (t == typeof(Arc)) 42 | target = new ArcCurve((Arc)target); 43 | 44 | else if (t == typeof(Circle)) 45 | target = new ArcCurve((Circle)target); 46 | 47 | else if (t == typeof(Ellipse)) 48 | target = ((Ellipse)target).ToNurbsCurve(); 49 | 50 | else if (t == typeof(Box)) 51 | target = Brep.CreateFromBox((Box)target); 52 | 53 | else if (t == typeof(BoundingBox)) 54 | target = Brep.CreateFromBox((BoundingBox)target); 55 | 56 | else if (t == typeof(Rectangle3d)) 57 | target = ((Rectangle3d)target).ToNurbsCurve(); 58 | 59 | else if (target is Polyline) 60 | target = new PolylineCurve((Polyline)target); 61 | } 62 | 63 | return toReturn; 64 | } 65 | 66 | string IGH_TypeHint.TypeName { get { return "ghdoc Object when geometry (rhinoscriptsyntax)"; } } 67 | } 68 | 69 | [Guid("35915213-5534-4277-81B8-1BDC9E7383D2")] 70 | public class NoChangeHint : GH_NullHint, IGH_TypeHint 71 | { 72 | Guid IGH_TypeHint.HintID { get { return this.GetType().GUID; } } 73 | 74 | string IGH_TypeHint.TypeName { get { return "No Type Hint"; } } 75 | } 76 | 77 | 78 | static class PythonHints 79 | { 80 | static readonly Dictionary _new_marshallings = new Dictionary { 81 | { typeof(NewFloatHint).GUID, new NewFloatHint() }, 82 | { typeof(NewStrHint).GUID, new NewStrHint() }, 83 | { typeof(NoChangeHint).GUID, new NoChangeHint() }, 84 | { typeof(GhDocGuidHint).GUID, new GhDocGuidHint() }, 85 | }; 86 | 87 | 88 | static readonly Dictionary _old_to_rs = new Dictionary { 89 | { typeof(GH_DoubleHint_CS), typeof(NewFloatHint).GUID }, 90 | 91 | { typeof(GH_NullHint), typeof(GhDocGuidHint).GUID }, 92 | { typeof(DynamicHint), typeof(GhDocGuidHint).GUID }, 93 | 94 | { typeof(GH_Point3dHint), typeof(GhDocGuidHint).GUID }, 95 | 96 | { typeof(GH_ArcHint), typeof(GhDocGuidHint).GUID }, 97 | { typeof(SpecialArcHint), typeof(GhDocGuidHint).GUID }, 98 | 99 | { typeof(GH_BoxHint), typeof(GhDocGuidHint).GUID }, 100 | { typeof(SpecialBoxHint), typeof(GhDocGuidHint).GUID }, 101 | 102 | { typeof(GH_CircleHint), typeof(GhDocGuidHint).GUID }, 103 | { typeof(SpecialCircleHint), typeof(GhDocGuidHint).GUID }, 104 | 105 | { typeof(GH_LineHint), typeof(GhDocGuidHint).GUID }, 106 | { typeof(SpecialLineHint), typeof(GhDocGuidHint).GUID }, 107 | 108 | { typeof(GH_PolylineHint), typeof(GhDocGuidHint).GUID }, 109 | { typeof(SpecialPolylineHint), typeof(GhDocGuidHint).GUID }, 110 | 111 | { typeof(GH_CurveHint), typeof(GhDocGuidHint).GUID }, 112 | { typeof(GH_SurfaceHint), typeof(GhDocGuidHint).GUID }, 113 | { typeof(GH_MeshHint), typeof(GhDocGuidHint).GUID }, 114 | { typeof(GH_BrepHint), typeof(GhDocGuidHint).GUID }, 115 | { typeof(GH_GeometryBaseHint), typeof(GhDocGuidHint).GUID }, 116 | }; 117 | 118 | static readonly Dictionary _old_to_common = new Dictionary { 119 | { typeof(GH_DoubleHint_CS), typeof(NewFloatHint) }, 120 | 121 | { typeof(GH_NullHint), typeof(NoChangeHint) }, 122 | { typeof(DynamicHint), typeof(NoChangeHint) }, 123 | 124 | { typeof(SpecialArcHint), typeof(GH_ArcHint) }, 125 | { typeof(SpecialBoxHint), typeof(GH_BoxHint) }, 126 | { typeof(SpecialCircleHint), typeof(GH_CircleHint) }, 127 | { typeof(SpecialLineHint), typeof(GH_LineHint) }, 128 | { typeof(SpecialPolylineHint), typeof(GH_PolylineHint) }, 129 | }; 130 | 131 | 132 | public static bool ToNewRhinoscriptHint(IGH_TypeHint probe, out IGH_TypeHint newHint) 133 | { 134 | newHint = null; 135 | if (probe == null) return false; 136 | 137 | var probeType = probe.GetType(); 138 | 139 | if (_old_to_rs.ContainsKey(probeType)) 140 | { 141 | newHint = _new_marshallings[_old_to_rs[probeType]]; 142 | return true; 143 | } 144 | return false; 145 | } 146 | 147 | public static void ToNewRhinoCommonHint(Param_ScriptVariable sc) 148 | { 149 | if (sc == null || sc.TypeHint == null) return; 150 | 151 | Type probeType = sc.TypeHint.GetType(); 152 | 153 | if (_old_to_common.ContainsKey(probeType)) 154 | { 155 | var type = _old_to_common[probeType]; 156 | if (type != null) 157 | sc.TypeHint = System.Activator.CreateInstance(type) as IGH_TypeHint; 158 | } 159 | } 160 | } 161 | } -------------------------------------------------------------------------------- /Component/SafeComponent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using Grasshopper; 4 | using Grasshopper.Kernel; 5 | using System.Windows.Forms; 6 | 7 | namespace GhPython.Component 8 | { 9 | /// 10 | /// This is an abstract class which automatically calls its own destructor when the user deletes it or 11 | /// closes the document. It handles most cases well, and relies on the GC for any other case. Please use the standard constructor 12 | /// if you need to execute something also when the assembly loads, and the Initialize() method to setup any single component 13 | /// when it first lands and executes on the canvas. Remember to call base.Dispose(disposing) if you override Dispose(bool). 14 | /// 15 | public abstract class SafeComponent : GH_Component, IDisposable 16 | { 17 | GH_Document m_doc; 18 | 19 | bool m_initializationDone; 20 | bool m_orphan; 21 | bool m_locked; 22 | bool m_afterDisposal; 23 | 24 | /// 25 | /// Do not use this constructor for initialization, but always use the Initialize() method, which will run only once. 26 | /// This constructor is called more times at startup for indexing the picture and some other external reasons. 27 | /// 28 | protected SafeComponent(string name, string abbreviation, string description, string category, string subCategory) : 29 | base(name, abbreviation, description, category, subCategory) 30 | { 31 | if (Instances.DocumentServer.DocumentCount > 0) 32 | { 33 | m_doc = Instances.DocumentServer[0]; 34 | 35 | CheckIfSetupActionsAreNecessary(); 36 | } 37 | } 38 | 39 | protected GH_Document Doc 40 | { 41 | get 42 | { 43 | CheckIfSetupActionsAreNecessary(); 44 | return m_doc; 45 | } 46 | } 47 | 48 | public void CheckIfSetupActionsAreNecessary() 49 | { 50 | if (m_afterDisposal) return; 51 | 52 | if (m_orphan) 53 | { 54 | m_orphan = false; 55 | GC.ReRegisterForFinalize(this); 56 | } 57 | 58 | if (!m_initializationDone) 59 | { 60 | if (m_doc == null) 61 | { 62 | m_doc = OnPingDocument(); 63 | 64 | if (m_doc == null) return; 65 | } 66 | 67 | m_doc.ObjectsDeleted += GrasshopperObjectsDeleted; 68 | Instances.DocumentServer.DocumentRemoved += GrasshopperDocumentClosed; 69 | m_doc.SolutionStart += AfterDocumentChanged; 70 | 71 | m_initializationDone = true; 72 | Initialize(); 73 | } 74 | } 75 | 76 | protected sealed override void SolveInstance(IGH_DataAccess DA) 77 | { 78 | CheckIfSetupActionsAreNecessary(); 79 | SafeSolveInstance(DA); 80 | } 81 | 82 | protected abstract void SafeSolveInstance(IGH_DataAccess da); 83 | 84 | private void GrasshopperDocumentClosed(GH_DocumentServer sender, GH_Document doc) 85 | { 86 | if (doc != null && (m_doc != null && doc.DocumentID == m_doc.DocumentID)) 87 | { 88 | Dispose(); 89 | } 90 | } 91 | 92 | private void GrasshopperObjectsDeleted(object sender, GH_DocObjectEventArgs e) 93 | { 94 | if (e != null && e.Attributes != null) 95 | { 96 | for (int i = 0; i < e.ObjectCount; i++) 97 | { 98 | if (e.Attributes[i] != null && e.Attributes[i].InstanceGuid == this.InstanceGuid) 99 | { 100 | Dispose(); 101 | } 102 | Debug.Assert(e.Attributes[i] != null, "e.Attributes[i] is null"); 103 | } 104 | } 105 | Debug.Assert(e != null && e.Attributes != null, "e or e.Attributes is null"); 106 | } 107 | 108 | void AfterDocumentChanged(object sender, GH_SolutionEventArgs args) 109 | { 110 | 111 | if (this.Locked != m_locked) 112 | { 113 | m_locked = this.Locked; 114 | OnLockedChanged(m_locked); 115 | } 116 | } 117 | 118 | protected virtual void OnLockedChanged(bool nowIsLocked) 119 | { 120 | } 121 | 122 | private void DeregisterComponent() 123 | { 124 | if (m_doc != null && m_initializationDone) 125 | { 126 | m_doc.ObjectsDeleted -= GrasshopperObjectsDeleted; 127 | 128 | if (Instances.DocumentServer != null) 129 | Instances.DocumentServer.DocumentRemoved -= GrasshopperDocumentClosed; 130 | 131 | m_doc.SolutionStart -= AfterDocumentChanged; 132 | } 133 | } 134 | 135 | public override void RemovedFromDocument(GH_Document document) 136 | { 137 | base.RemovedFromDocument(document); 138 | 139 | Dispose(); 140 | } 141 | 142 | /// 143 | /// Initializes the component when it first executes and at no other earlier or later time. It runs once for each component 144 | /// 145 | protected virtual void Initialize() 146 | { 147 | } 148 | 149 | /// 150 | /// If you override this, be very sure you always call base.Dispose(disposing) or MyBase.Dispose(disposing) in 151 | /// Vb.Net from within your code. 152 | /// 153 | /// If disposing equals false, the method has been called by the 154 | /// runtime from inside the finalizer and you should not reference other objects. Only unmanaged resources 155 | /// can be disposed. 156 | protected virtual void Dispose(bool disposing) 157 | { 158 | m_afterDisposal = true; 159 | try 160 | { 161 | if (!m_orphan) 162 | { 163 | DeregisterComponent(); 164 | m_orphan = true; 165 | m_initializationDone = false; 166 | 167 | if (disposing) 168 | { 169 | GC.SuppressFinalize(this); 170 | } 171 | } 172 | } 173 | catch (Exception ex) 174 | { 175 | GhPython.Forms.PythonScriptForm.LastHandleException(ex); 176 | } 177 | } 178 | 179 | /// 180 | /// The IDisposable implementation. You do not normally need to call this. The creator of this object will call it. 181 | /// 182 | public void Dispose() 183 | { 184 | m_afterDisposal = true; 185 | Dispose(true); 186 | } 187 | 188 | ~SafeComponent() 189 | { 190 | Dispose(false); 191 | } 192 | } 193 | } -------------------------------------------------------------------------------- /package/components.py: -------------------------------------------------------------------------------- 1 | import clr 2 | clr.AddReference("Grasshopper") 3 | import Grasshopper as GH 4 | 5 | experimental_mode = False 6 | 7 | def __make_function__(helper): 8 | def component_function(*args, **kwargs): 9 | if experimental_mode: 10 | success, fastdata = helper.runfast(args, kwargs) 11 | if success: return fastdata 12 | 13 | comp = helper.proxy.CreateInstance() 14 | comp.ClearData() 15 | if args: 16 | for i, arg in enumerate(args): 17 | if arg is None: continue 18 | param = comp.Params.Input[i] 19 | param.PersistentData.Clear() 20 | if hasattr(arg, '__iter__'): #TODO deal with polyline, str 21 | [param.AddPersistentData(a) for a in arg] 22 | else: 23 | param.AddPersistentData(arg) 24 | if kwargs: 25 | for param in comp.Params.Input: 26 | name = param.Name.lower() 27 | if name in kwargs: 28 | param.PersistentData.Clear() 29 | arg = kwargs[name] 30 | if hasattr(arg, '__iter__'): #TODO deal with polyline, str 31 | [param.AddPersistentData(a) for a in arg] 32 | else: 33 | param.AddPersistentData(arg) 34 | doc = GH.Kernel.GH_Document() 35 | doc.AddObject(comp, False, 0) 36 | comp.CollectData() 37 | comp.ComputeData() 38 | output = helper.create_output(comp.Params) 39 | comp.ClearData() 40 | doc.Dispose() 41 | return output 42 | return component_function 43 | 44 | 45 | class namespace_object(object): 46 | def __init__(self): 47 | pass 48 | 49 | 50 | class function_helper(object): 51 | def __init__(self, proxy, name): 52 | self.proxy = proxy 53 | # obviosly hand picking components won't work for the long run, but this 54 | # lets me experiment with a small set to figure out the issues involved 55 | fast_components = ("MeshXRay", "Vector2Pt", "Line", "CurveClosestPoint") 56 | self.supports_fast = name in fast_components 57 | self.fast_component = None 58 | self.return_type = None 59 | 60 | def create_output(self, params, output_values=None): 61 | from collections import namedtuple 62 | if not output_values: 63 | output_values = [] 64 | for output in params.Output: 65 | data = output.VolatileData.AllData(True) 66 | #We could call Value, but ScriptVariable seems to do a better job 67 | v = [x.ScriptVariable() for x in data] 68 | if len(v)<1: 69 | output_values.append(None) 70 | elif len(v)==1: 71 | output_values.append(v[0]) 72 | else: 73 | output_values.append(v) 74 | if len(output_values)==1: return output_values[0] 75 | if self.return_type is None: 76 | names = [output.Name.lower() for output in params.Output] 77 | try: 78 | self.return_type = namedtuple('Output', names, rename=True) 79 | except: 80 | self.return_type = False 81 | if not self.return_type: return output_values 82 | return self.return_type(*output_values) 83 | 84 | def runfast(self, args, kwargs): 85 | if not self.supports_fast: return False, None 86 | if self.fast_component == None: 87 | self.fast_component = self.proxy.CreateInstance() 88 | import GhPython 89 | output = GhPython.ScriptHelpers.FastComponent.Run(self.fast_component, args, kwargs) 90 | if output: 91 | if len(output[0])==1: 92 | output = [a[0] for a in output] 93 | output = self.create_output(self.fast_component.Params, output) 94 | return True, output 95 | 96 | 97 | def __build_module(): 98 | def function_description(description, params): 99 | rc = ['',description, "Input:"] 100 | for param in params.Input: 101 | s = "\t{0} [{1}] - {2}" 102 | if param.Optional: 103 | s = "\t{0} (in, optional) [{1}] - {2}" 104 | rc.append(s.format(param.Name.lower(), param.TypeName, param.Description)) 105 | if params.Output.Count == 1: 106 | param = params.Output[0] 107 | rc.append("Returns: [{0}] - {1}".format(param.TypeName, param.Description)) 108 | elif params.Output.Count > 1: 109 | rc.append("Returns:") 110 | for out in params.Output: 111 | s = "\t{0} [{1}] - {2}" 112 | rc.append(s.format(out.Name.lower(), out.TypeName, out.Description)) 113 | return '\n'.join(rc) 114 | 115 | import sys, types, re 116 | core_module = sys.modules['ghpythonlib.components'] 117 | translate_from = u"|+-*\u2070\u00B9\u00B2\u00B3\u2074\u2075\u2076\u2077\u2078\u2079" 118 | translate_to = "X__x0123456789" 119 | transl = dict(zip(translate_from, translate_to)) 120 | for obj in GH.Instances.ComponentServer.ObjectProxies: 121 | if obj.Exposure == GH.Kernel.GH_Exposure.hidden or obj.Obsolete: 122 | continue 123 | t = clr.GetClrType(GH.Kernel.IGH_Component) 124 | if not (t.IsAssignableFrom(obj.Type)): 125 | continue 126 | m = core_module 127 | library_id = obj.LibraryGuid 128 | assembly = GH.Instances.ComponentServer.FindAssembly(library_id) 129 | if assembly is None: continue 130 | if not assembly.IsCoreLibrary: 131 | module_name = assembly.Assembly.GetName().Name.split('.', 1)[0] 132 | if module_name.upper().startswith("GH_"): module_name = module_name[3:] 133 | if module_name in core_module.__dict__: 134 | m = core_module.__dict__[module_name] 135 | else: 136 | m = namespace_object() 137 | setattr(core_module, module_name, m) 138 | name = obj.Desc.Name 139 | if "LEGACY" in name or "#" in name: continue 140 | name = re.sub("[^a-zA-Z0-9]", lambda match: transl[match.group()] if (match.group() in transl) else '', name) 141 | if not name[0].isalpha(): name = 'x' + name 142 | function = __make_function__(function_helper(obj, name)) 143 | setattr(m, name, function) 144 | comp = obj.CreateInstance() 145 | a = m.__dict__[name] 146 | a.__name__ = name 147 | a.__doc__ = function_description(obj.Desc.Description, comp.Params) 148 | 149 | 150 | __build_module() -------------------------------------------------------------------------------- /Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.269 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace GhPython.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("GhPython.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | internal static System.Drawing.Bitmap _checked { 64 | get { 65 | object obj = ResourceManager.GetObject("_checked", resourceCulture); 66 | return ((System.Drawing.Bitmap)(obj)); 67 | } 68 | } 69 | 70 | internal static System.Drawing.Bitmap _unchecked { 71 | get { 72 | object obj = ResourceManager.GetObject("_unchecked", resourceCulture); 73 | return ((System.Drawing.Bitmap)(obj)); 74 | } 75 | } 76 | 77 | /// 78 | /// Looks up a localized string similar to <p>This component allows to use both RhinoCommon and RhinoScript from within 79 | ///Grasshopper. Here some Q&amp;As.</p> 80 | /// 81 | ///<p><b>How can I use RhinoCommon?</b></p> 82 | ///<p>By importing from the Rhino module, for example by writing:</p> 83 | ///<pre style="font-size: smaller">from Rhino.Geometry import Point3d, Line</pre> 84 | ///<p>...and then assigning some new geometry to the results</p> 85 | ///<pre style="font-size: smaller">a = Line(Point3d(1, 2, 3), Point3d(10, 11, 12))</pre> 86 | /// 87 | ///<p><b>How can I use RhinoScript?</b></p> 88 | ///<p>By impo [rest of string was truncated]";. 89 | /// 90 | internal static string helpText { 91 | get { 92 | return ResourceManager.GetString("helpText", resourceCulture); 93 | } 94 | } 95 | 96 | internal static System.Drawing.Bitmap python { 97 | get { 98 | object obj = ResourceManager.GetObject("python", resourceCulture); 99 | return ((System.Drawing.Bitmap)(obj)); 100 | } 101 | } 102 | 103 | /// 104 | /// Looks up a localized string similar to import Rhino.Geometry as rg 105 | ///import math 106 | /// 107 | ///def Main(): 108 | /// global result 109 | /// result = [] 110 | /// SubdivideAndRotate(line, 0, result) 111 | /// 112 | ///def WeightedAvaragePts(pt1, pt2, pt1_part): 113 | /// rest = 1 - pt1_part 114 | /// return pt1 * rest + pt2 * pt1_part 115 | /// 116 | ///def SubdivideAndRotate(line, level, allLines): 117 | /// if level == maxLevel: 118 | /// allLines.append(line) 119 | /// return 120 | /// 121 | /// a = line.First #rg.Polyline 122 | /// d = line.Last 123 | /// b = WeightedAvaragePts(a, d, 1.0 / 3.0) 124 | /// c = WeightedAvaragePts(a, d, 2.0 / [rest of string was truncated]";. 125 | /// 126 | internal static string sampleCommon { 127 | get { 128 | return ResourceManager.GetString("sampleCommon", resourceCulture); 129 | } 130 | } 131 | 132 | /// 133 | /// Looks up a localized string similar to # sample script to show how to use this component and the rhinoscriptsyntax 134 | ///'''Constructs a sinusoidal series of circles. 135 | /// Inputs: 136 | /// x: The number of circles. (integer) 137 | /// y: The radius of each circle. (float) 138 | /// Outputs: 139 | /// a: The list of circles. (list of circle) 140 | /// b: The list of radii. (list of float) 141 | ///''' 142 | ///import math 143 | ///import rhinoscriptsyntax as rs 144 | /// 145 | ///if x is None: 146 | /// x = 24 # if nothing is connected to x, set x to something (24). 147 | ///if y is None: 148 | /// y = 0.3 # i [rest of string was truncated]";. 149 | /// 150 | internal static string sampleScript { 151 | get { 152 | return ResourceManager.GetString("sampleScript", resourceCulture); 153 | } 154 | } 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /Properties/Resources.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 122 | ..\images\python.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 123 | 124 | 125 | ..\images\checked.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 126 | 127 | 128 | ..\images\unchecked.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 129 | 130 | 131 | ..\samples\samplescript.py;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 132 | 133 | 134 | ..\Samples\helpText.html;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 135 | 136 | 137 | ..\Samples\sampleCommon.py;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 138 | 139 | -------------------------------------------------------------------------------- /ScriptHelpers/GhPyDataAccess.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Grasshopper.Kernel; 4 | 5 | namespace GhPython.ScriptHelpers 6 | { 7 | // See GH_StructureIterator in grasshopper for real implementation 8 | class GhPyDataAccess : IGH_DataAccess 9 | { 10 | readonly GH_Component m_component; 11 | readonly object[] m_output; 12 | readonly IList m_data; 13 | 14 | public GhPyDataAccess(GH_Component parent, IList inputData) 15 | { 16 | m_component = parent; 17 | m_data = inputData; 18 | int output_count = parent.Params.Output.Count; 19 | m_output = new object[output_count]; 20 | } 21 | 22 | public object[] Output 23 | { 24 | get { return m_output; } 25 | } 26 | 27 | 28 | public void AbortComponentSolution() 29 | { 30 | throw new NotImplementedException(); 31 | } 32 | 33 | public bool BlitData(int paramIndex, Grasshopper.Kernel.Data.GH_Structure tree, bool overwrite) where TQ : Grasshopper.Kernel.Types.IGH_Goo 34 | { 35 | throw new NotImplementedException(); 36 | } 37 | 38 | public void DisableGapLogic(int paramIndex) 39 | { 40 | throw new NotImplementedException(); 41 | } 42 | 43 | public void DisableGapLogic() 44 | { 45 | throw new NotImplementedException(); 46 | } 47 | 48 | public bool GetData(string name, ref T destination) 49 | { 50 | throw new NotImplementedException(); 51 | } 52 | 53 | public bool GetData(int index, ref T destination) 54 | { 55 | // If the parameter is empty, there is nothing to return. 56 | var data = m_data[index]; 57 | if (data == null) 58 | return false; 59 | 60 | // Cast/Convert the data 61 | if (CastData(data, out destination)) 62 | return true; 63 | 64 | //Bummer, someone screwed up, sure hope it's not me. 65 | // Dim t0 As String = MungeTypeNameForGUI(d_data.GetType.Name) 66 | // Dim t1 As String = MungeTypeNameForGUI(GetType(T).Name) 67 | // m_component.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, String.Format("Invalid cast: {0} » {1}", t0, t1)) 68 | return false; 69 | } 70 | 71 | 72 | public bool GetDataList(string name, List list) 73 | { 74 | throw new NotImplementedException(); 75 | } 76 | 77 | public bool GetDataList(int index, List list) 78 | { 79 | throw new NotImplementedException(); 80 | } 81 | 82 | public bool GetDataTree(string name, out Grasshopper.Kernel.Data.GH_Structure tree) where T : Grasshopper.Kernel.Types.IGH_Goo 83 | { 84 | throw new NotImplementedException(); 85 | } 86 | 87 | public bool GetDataTree(int index, out Grasshopper.Kernel.Data.GH_Structure tree) where T : Grasshopper.Kernel.Types.IGH_Goo 88 | { 89 | throw new NotImplementedException(); 90 | } 91 | 92 | public void IncrementIteration(IList data) 93 | { 94 | throw new NotImplementedException(); 95 | } 96 | 97 | public void IncrementIteration() 98 | { 99 | throw new NotImplementedException(); 100 | } 101 | 102 | public int Iteration 103 | { 104 | get 105 | { 106 | throw new NotImplementedException(); 107 | } 108 | } 109 | 110 | public int ParameterTargetIndex(int paramIndex) 111 | { 112 | throw new NotImplementedException(); 113 | } 114 | 115 | public Grasshopper.Kernel.Data.GH_Path ParameterTargetPath(int paramIndex) 116 | { 117 | throw new NotImplementedException(); 118 | } 119 | 120 | public bool SetData(string paramName, object data) 121 | { 122 | int index = m_component.Params.IndexOfOutputParam(paramName); 123 | return SetData(index, data); 124 | } 125 | 126 | public bool SetData(int paramIndex, object data, int itemIndexOverride) 127 | { 128 | throw new NotImplementedException(); 129 | } 130 | 131 | public bool SetData(int paramIndex, object data) 132 | { 133 | if (paramIndex < 0 || paramIndex >= m_output.Length) 134 | return false; 135 | m_output[paramIndex] = data; 136 | return true; 137 | } 138 | 139 | public bool SetDataList(string paramName, System.Collections.IEnumerable data) 140 | { 141 | throw new NotImplementedException(); 142 | } 143 | 144 | public bool SetDataList(int paramIndex, System.Collections.IEnumerable data, int listIndexOverride) 145 | { 146 | throw new NotImplementedException(); 147 | } 148 | 149 | public bool SetDataList(int paramIndex, System.Collections.IEnumerable data) 150 | { 151 | throw new NotImplementedException(); 152 | } 153 | 154 | public bool SetDataTree(int paramIndex, Grasshopper.Kernel.Data.IGH_Structure tree) 155 | { 156 | throw new NotImplementedException(); 157 | } 158 | 159 | public bool SetDataTree(int paramIndex, Grasshopper.Kernel.Data.IGH_DataTree tree) 160 | { 161 | throw new NotImplementedException(); 162 | } 163 | 164 | public int Util_CountNonNullRefs(List L) 165 | { 166 | throw new NotImplementedException(); 167 | } 168 | 169 | public int Util_CountNullRefs(List L) 170 | { 171 | throw new NotImplementedException(); 172 | } 173 | 174 | public bool Util_EnsureNonNullCount(List L, int N) 175 | { 176 | throw new NotImplementedException(); 177 | } 178 | 179 | public int Util_FirstNonNullItem(List L) 180 | { 181 | throw new NotImplementedException(); 182 | } 183 | 184 | public List Util_RemoveNullRefs(List L) 185 | { 186 | throw new NotImplementedException(); 187 | } 188 | 189 | /// 190 | /// Convert data from the unknown type to a target type. 191 | /// Conversion is optimized and will only duplicate data if the types are not the same. 192 | /// 193 | /// Target type of data conversion. 194 | /// Input, cannot be null. 195 | /// Output, is expected to be null. 196 | /// True on success, false on failure. 197 | private static bool CastData(object inputData, out T outputData) 198 | { 199 | if (inputData is T) 200 | { 201 | //Return a straight cast 202 | outputData = (T)inputData; 203 | return true; 204 | } 205 | else 206 | { 207 | //Call the CastTo method on the data, maybe it knows how to convert itself into T 208 | //(Although nothing indicates that [in] implements IGH_Goo, it is logically impossible 209 | //at the time of writing (september 02 2008) for it to be anything else.) 210 | var goo_data = (Grasshopper.Kernel.Types.IGH_Goo)inputData; 211 | if ((goo_data.CastTo(out outputData))) 212 | return true; 213 | 214 | //Looks like it didn't. If Destination implements IGH_Goo, perhaps it defines a conversion. 215 | if ((Grasshopper.Kernel.GH_TypeLib.t_gh_goo.IsAssignableFrom(typeof(T)))) 216 | { 217 | if ((outputData == null)) 218 | { 219 | //Destination is nothing, so we need to create a new instance of type T 220 | var temp_instance = (Grasshopper.Kernel.Types.IGH_Goo)System.Activator.CreateInstance(typeof(T)); 221 | if ((temp_instance.CastFrom(goo_data))) 222 | { 223 | outputData = (T)temp_instance; 224 | return true; 225 | } 226 | } 227 | else 228 | { 229 | //Destination is already filled in, so we can call the caster directly 230 | if (((Grasshopper.Kernel.Types.IGH_Goo)outputData).CastFrom(goo_data)) 231 | return true; 232 | } 233 | } 234 | } 235 | 236 | return false; 237 | } 238 | 239 | } 240 | } 241 | -------------------------------------------------------------------------------- /Component/PythonComponentAttributes.cs: -------------------------------------------------------------------------------- 1 | using GhPython.Forms; 2 | using Grasshopper.GUI; 3 | using Grasshopper.GUI.Canvas; 4 | using Grasshopper.Kernel.Attributes; 5 | using System.Drawing; 6 | using System.Drawing.Drawing2D; 7 | using System.Windows.Forms; 8 | 9 | namespace GhPython.Component 10 | { 11 | public class PythonComponentAttributes : GH_ComponentAttributes 12 | { 13 | private PythonScriptForm m_form; 14 | 15 | public PythonComponentAttributes(SafeComponent safeComponent) 16 | : base(safeComponent) 17 | { 18 | } 19 | 20 | public override GH_ObjectResponse RespondToMouseDoubleClick(GH_Canvas sender, GH_CanvasMouseEvent e) 21 | { 22 | OpenEditor(); 23 | return base.RespondToMouseDoubleClick(sender, e); 24 | } 25 | 26 | public void OpenEditor() 27 | { 28 | var attachedComp = this.Owner as ScriptingAncestorComponent; 29 | if (attachedComp != null && !attachedComp.Locked) 30 | { 31 | attachedComp.CheckIfSetupActionsAreNecessary(); 32 | 33 | if (m_form == null || m_form.IsDisposed) 34 | m_form = new PythonScriptForm(attachedComp); 35 | 36 | if (!m_form.Visible) 37 | { 38 | m_form.Show(Grasshopper.Instances.DocumentEditor); 39 | attachedComp.OnDisplayExpired(true); 40 | } 41 | else 42 | { 43 | m_form.Focus(); 44 | } 45 | } 46 | } 47 | 48 | public bool TryGetEditor(out Form editor) 49 | { 50 | if (m_form == null || m_form.IsDisposed) 51 | { 52 | editor = null; 53 | return false; 54 | } 55 | 56 | editor = m_form; 57 | return true; 58 | } 59 | 60 | internal void DisableLinkedEditor(bool close) 61 | { 62 | if (close && m_form != null && !m_form.IsDisposed) 63 | m_form.Disable(); 64 | 65 | m_form = null; 66 | } 67 | 68 | public bool TrySetLinkedEditorHelpText(string text) 69 | { 70 | if (m_form != null && !m_form.IsDisposed) 71 | { 72 | m_form.HelpText(text); 73 | return true; 74 | } 75 | return false; 76 | } 77 | 78 | protected override void Render(GH_Canvas canvas, System.Drawing.Graphics graphics, GH_CanvasChannel channel) 79 | { 80 | base.Render(canvas, graphics, channel); 81 | 82 | if (m_form == null || m_form.IsDisposed) return; 83 | 84 | if (channel == GH_CanvasChannel.Overlay && 85 | (canvas.DrawingMode == GH_CanvasMode.Export || 86 | canvas.DrawingMode == GH_CanvasMode.Control) 87 | ) 88 | { 89 | Rectangle targetRectangle; 90 | if (canvas.DrawingMode == GH_CanvasMode.Export) 91 | { 92 | System.Windows.Forms.Control editorControl = m_form.m_texteditor; 93 | if (editorControl == null) return; 94 | targetRectangle = editorControl.ClientRectangle; 95 | targetRectangle = m_form.RectangleToScreen(targetRectangle); 96 | } 97 | else 98 | { 99 | targetRectangle = m_form.DesktopBounds; 100 | } 101 | 102 | RectangleF windowOnCanvas; 103 | { 104 | targetRectangle.Inflate(-1, -1); 105 | 106 | var desktopForm = canvas.RectangleToClient(targetRectangle); 107 | windowOnCanvas = canvas.Viewport.UnprojectRectangle(desktopForm); 108 | } 109 | 110 | var transparent = Color.Transparent; 111 | 112 | var desk_tl = new PointF(windowOnCanvas.Left, windowOnCanvas.Top); 113 | var desk_tr = new PointF(windowOnCanvas.Right, windowOnCanvas.Top); 114 | var desk_bl = new PointF(windowOnCanvas.Left, windowOnCanvas.Bottom); 115 | var desk_br = new PointF(windowOnCanvas.Right, windowOnCanvas.Bottom); 116 | 117 | var comp_tl = new PointF(Bounds.Left, Bounds.Top); 118 | var comp_tr = new PointF(Bounds.Right, Bounds.Top); 119 | var comp_bl = new PointF(Bounds.Left, Bounds.Bottom); 120 | var comp_br = new PointF(Bounds.Right, Bounds.Bottom); 121 | 122 | if (Bounds.Top < windowOnCanvas.Top) 123 | BoxSide(graphics, Color.FromArgb(155,255,255,255), transparent, desk_tl, desk_tr, comp_tl, comp_tr); 124 | if (Bounds.Right > windowOnCanvas.Right) 125 | BoxSide(graphics, Color.FromArgb(155, 240, 240, 240), transparent, desk_tr, desk_br, comp_tr, comp_br); 126 | if (Bounds.Bottom > windowOnCanvas.Bottom) 127 | BoxSide(graphics, Color.FromArgb(155, 120, 120, 120), transparent, desk_bl, desk_br, comp_bl, comp_br); 128 | if (Bounds.Left < windowOnCanvas.Left) 129 | BoxSide(graphics, Color.FromArgb(155, 240, 240, 240), transparent, desk_tl, desk_bl, comp_tl, comp_bl); 130 | 131 | BoxEdge(graphics, Color.Black, Color.Transparent, 1, desk_tl, comp_tl, AnchorStyles.Top | AnchorStyles.Left); 132 | BoxEdge(graphics, Color.Black, Color.Transparent, 1, desk_tr, comp_tr, AnchorStyles.Top | AnchorStyles.Right); 133 | BoxEdge(graphics, Color.Black, Color.Transparent, 1, desk_br, comp_br, AnchorStyles.Bottom | AnchorStyles.Right); 134 | BoxEdge(graphics, Color.Black, Color.Transparent, 1, desk_bl, comp_bl, AnchorStyles.Bottom | AnchorStyles.Left); 135 | 136 | if (canvas.DrawingMode == GH_CanvasMode.Export) 137 | { 138 | System.Windows.Forms.Control editorControl = m_form.m_texteditor; 139 | if (editorControl == null) return; 140 | 141 | using (var bitmap = new Bitmap(editorControl.Width, editorControl.Height)) 142 | { 143 | editorControl.DrawToBitmap(bitmap, editorControl.Bounds); 144 | 145 | var ot = graphics.Transform; 146 | var loc = canvas.Viewport.ProjectPoint(windowOnCanvas.Location); 147 | 148 | graphics.ResetTransform(); 149 | 150 | graphics.DrawImage(bitmap, 151 | (int)loc.X, (int)loc.Y, 152 | editorControl.Width, editorControl.Height); 153 | 154 | graphics.Transform = ot; 155 | } 156 | } 157 | } 158 | } 159 | 160 | private static void BoxSide(Graphics graphics, Color from, Color to, 161 | PointF A, PointF B, PointF C, PointF D) 162 | { 163 | using (var gradientA = new LinearGradientBrush( 164 | new PointF(A.X != B.X ? 0 : (A.X + B.X) * 0.5f, A.X == B.X ? 0 : (A.Y + B.Y) * 0.5f), 165 | new PointF(A.X != B.X ? 0 : (C.X + D.X) * 0.5f, A.X == B.X ? 0 : (C.Y + D.Y) * 0.5f), 166 | from, to)) 167 | using (var path = new GraphicsPath()) 168 | { 169 | gradientA.WrapMode = WrapMode.TileFlipXY; 170 | path.AddLine(A, B); 171 | path.AddLine(B, D); 172 | path.AddLine(D, C); 173 | path.CloseFigure(); 174 | 175 | graphics.FillPath(gradientA, path); 176 | } 177 | } 178 | 179 | private static void BoxEdge(Graphics graphics, Color from, Color to, 180 | float size, PointF A, PointF B, AnchorStyles side) 181 | { 182 | using (var gradientA = new LinearGradientBrush(A, B, from, to)) 183 | using (var penA = new Pen(gradientA, size)) 184 | { 185 | bool visible = IsVisibleExtrusionEdge(B, A, side); 186 | if (!visible) 187 | { 188 | penA.DashStyle = DashStyle.Dash; 189 | penA.DashPattern = new float[] { 5, 5 }; 190 | penA.DashCap = DashCap.Triangle; 191 | } 192 | graphics.DrawLine(penA, A, B); 193 | } 194 | } 195 | 196 | private static bool IsVisibleExtrusionEdge(PointF back, PointF front, AnchorStyles sides) 197 | { 198 | bool toReturn = false; 199 | 200 | if ((sides & AnchorStyles.Top) == AnchorStyles.Top) 201 | toReturn |= back.Y < front.Y; 202 | else if ((sides & AnchorStyles.Bottom) == AnchorStyles.Bottom) 203 | toReturn |= back.Y > front.Y; 204 | 205 | if ((sides & AnchorStyles.Right) == AnchorStyles.Right) 206 | toReturn |= back.X > front.X; 207 | else if ((sides & AnchorStyles.Left) == AnchorStyles.Left) 208 | toReturn |= back.X < front.X; 209 | 210 | return toReturn; 211 | } 212 | } 213 | } -------------------------------------------------------------------------------- /GhPython.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Debug 5 | AnyCPU 6 | 9.0.30729 7 | 2.0 8 | {8955361B-7612-44DE-9B12-C081EC8C6F2E} 9 | Library 10 | Properties 11 | GhPython 12 | GhPython 13 | v4.0 14 | 512 15 | 16 | 17 | 18 | 19 | 3.5 20 | 21 | publish\ 22 | true 23 | Disk 24 | false 25 | Foreground 26 | 7 27 | Days 28 | false 29 | false 30 | true 31 | 0 32 | 1.0.0.%2a 33 | false 34 | false 35 | true 36 | 37 | 38 | 39 | 40 | true 41 | full 42 | false 43 | bin\ 44 | DEBUG;TRACE 45 | prompt 46 | 4 47 | 48 | 49 | pdbonly 50 | true 51 | bin\ 52 | TRACE 53 | prompt 54 | 4 55 | 56 | 57 | bin\ 58 | TRACE;DEBUG 59 | pdbonly 60 | true 61 | 62 | 63 | 64 | references\GH_IO.dll 65 | False 66 | 67 | 68 | references\Grasshopper.dll 69 | False 70 | 71 | 72 | 73 | references\RhinoCommon.dll 74 | False 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | Code 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | Form 107 | 108 | 109 | PythonScriptForm.cs 110 | 111 | 112 | 113 | 114 | True 115 | True 116 | Resources.resx 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | PythonScriptForm.cs 134 | 135 | 136 | ResXFileCodeGenerator 137 | Resources.Designer.cs 138 | Designer 139 | 140 | 141 | 142 | 143 | False 144 | .NET Framework 3.5 SP1 Client Profile 145 | false 146 | 147 | 148 | False 149 | .NET Framework 3.5 SP1 150 | true 151 | 152 | 153 | False 154 | Windows Installer 3.1 155 | true 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 178 | 179 | REM copy "$(TargetPath)" "$(TargetDir)$(ProjectName).gha" 180 | copy "$(TargetPath)" "%25appdata%25\Grasshopper\Libraries\$(ProjectName).gha" 181 | 182 | -------------------------------------------------------------------------------- /Component/DocStringUtils.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Text; 3 | using System.IO; 4 | using Grasshopper.Kernel; 5 | 6 | namespace GhPython.Component 7 | { 8 | /* 9 | # based on DocStrings as defined in 10 | # http://google-styleguide.googlecode.com/svn/trunk/pyguide.html#Comments 11 | """""" 12 | Title: Arithmetic Series 13 | Description: Computes the Sum of an Arithmetic Progression, or the 14 | sum of all numbers from F to L, included. 15 | Args: 16 | F: the first number included in the series. 17 | L: the last number included in the series. 18 | Returns: 19 | S: If F > L, then sum of all numbers [F,L]. 20 | If F = L, then 0. 21 | If F < L, then sum of all numbers (L,F). 22 | K: Not used. 23 | Help: 24 | See also the Gauss elementary school story: 25 | http://mathworld.wolfram.com/ArithmeticSeries.html 26 | """""" 27 | */ 28 | class DocStringUtils 29 | { 30 | public static bool FindApplyDocString(string code, ScriptingAncestorComponent component) 31 | { 32 | var reader = new StringReader(code); 33 | 34 | string line; 35 | for (; ; ) //proceeds to begin of docstrings, or leave method 36 | { 37 | line = reader.ReadLine(); 38 | if (line == null) return false; 39 | if (IsEmptyOrFullyCommentedOutLine(line)) continue; 40 | if (IsDocStringStart(line)) break; 41 | return false; 42 | } 43 | 44 | //strips the docstring start chars 45 | line = line.Substring(line.IndexOf(_docStringSeparator) + _docStringSeparator.Length); 46 | int firstLevelIndent = GetIndent(line); 47 | int secondLevelIndent = -1; 48 | 49 | string variable = "%description"; 50 | StringBuilder result = new StringBuilder(); 51 | KeywordType type = KeywordType.Description; 52 | 53 | do //consumes docstring lines and then leaves 54 | { 55 | int endSeparator = line.IndexOf(_docStringSeparator); 56 | if (endSeparator != -1) line = line.Substring(0, endSeparator); 57 | 58 | if (IsEmptyLine(line)) 59 | { 60 | if (endSeparator != -1) break; 61 | continue; 62 | } 63 | int newIndent = GetIndent(line); 64 | if (newIndent > firstLevelIndent) 65 | { 66 | if (secondLevelIndent == -1 || 67 | newIndent <= secondLevelIndent) //second level 68 | { 69 | //we could check for faulty indentation here 70 | secondLevelIndent = newIndent; 71 | 72 | string keyword; 73 | if (IsNewKeywordDeclared(line, out keyword)) 74 | { 75 | var nextType = type; 76 | string nextVariable = null; 77 | bool match = true; 78 | switch (keyword.ToUpperInvariant()) 79 | { 80 | case "ARG": 81 | case "ARGS": 82 | case "ARGUMENT": 83 | case "ARGUMENTS": 84 | case "INPUT": 85 | case "INPUTS": 86 | nextType = KeywordType.Argument; 87 | break; 88 | case "RETURN": 89 | case "RETURNS": 90 | case "OUTPUT": 91 | case "OUTPUTS": 92 | nextType = KeywordType.Return; 93 | break; 94 | case "HELP": 95 | case "REMARK": 96 | case "REMARKS": 97 | nextType = KeywordType.Help; 98 | nextVariable = "%help"; 99 | break; 100 | default: 101 | match = false; 102 | break; 103 | } 104 | 105 | if (match) 106 | { 107 | Send(variable, ref result, type, component); 108 | AddLine(result, line.Substring(line.IndexOf(":") + 1).TrimStart(_toTrim)); 109 | variable = nextVariable; 110 | type = nextType; 111 | } 112 | else 113 | AddLine(result, line); 114 | } 115 | else 116 | AddLine(result, line); 117 | } 118 | else //third level 119 | { 120 | string keyword; 121 | if (IsNewKeywordDeclared(line, out keyword) && (variable == null || !variable.StartsWith("%"))) 122 | { 123 | Send(variable, ref result, type, component); 124 | AddLine(result, line.Substring(line.IndexOf(":") + 1).TrimStart(_toTrim)); 125 | variable = keyword; 126 | } 127 | else 128 | AddLine(result, line.Trim(_toTrim)); 129 | } 130 | } 131 | else 132 | AddLine(result, line); 133 | if (endSeparator != -1) break; 134 | } 135 | while ((line = reader.ReadLine()) != null); 136 | 137 | Send(variable, ref result, type, component); 138 | return true; 139 | } 140 | 141 | private static void Send(string variable, ref StringBuilder result, KeywordType type, ScriptingAncestorComponent component) 142 | { 143 | if (variable != null) 144 | { 145 | switch (type) 146 | { 147 | case KeywordType.Description: 148 | component.Description = result.ToString(); 149 | break; 150 | case KeywordType.Argument: 151 | FindAndDescribe(component.Params.Input, variable, result.ToString()); 152 | break; 153 | case KeywordType.Return: 154 | FindAndDescribe(component.Params.Output, variable, result.ToString()); 155 | break; 156 | case KeywordType.Help: 157 | component.AdditionalHelpFromDocStrings = result.ToString(); 158 | break; 159 | } 160 | result = new StringBuilder(); 161 | } 162 | } 163 | 164 | private static void FindAndDescribe(List list, string variable, string p) 165 | { 166 | int i = list.FindIndex(match => match.NickName == variable); 167 | if (i != -1) 168 | { 169 | var item = list[i]; 170 | if (item != null) 171 | { 172 | item.Description = p; 173 | } 174 | } 175 | } 176 | 177 | enum KeywordType 178 | { 179 | Description, 180 | Argument, 181 | Return, 182 | Help, 183 | } 184 | 185 | private static void AddLine(StringBuilder result, string text) 186 | { 187 | if (result.Length != 0) result.AppendLine(); 188 | result.Append(text); 189 | } 190 | 191 | private static bool IsNewKeywordDeclared(string line, out string keyword) 192 | { 193 | keyword = null; 194 | string piece = line.TrimStart(_toTrim); 195 | int end = piece.IndexOf(":"); 196 | if (end == -1) return false; 197 | piece = piece.Substring(0, end).TrimEnd(_toTrim); 198 | if (piece.IndexOfAny(_toTrim) != -1) return false; 199 | keyword = piece; 200 | return true; 201 | } 202 | 203 | private static int GetIndent(string line) 204 | { 205 | int i; 206 | for (i = 0; i < line.Length; i++) 207 | if (!(line[i].Equals(' ') || line[i].Equals('\t'))) 208 | break; 209 | return i; 210 | } 211 | 212 | static readonly char[] _toTrim = new char[] { ' ', '\t' }; 213 | const string _docStringSeparator = "\"\"\""; 214 | 215 | private static bool IsDocStringStart(string line) 216 | { 217 | return line.TrimStart(_toTrim).StartsWith(_docStringSeparator); 218 | } 219 | 220 | private static bool IsEmptyLine(string line) 221 | { 222 | return line.TrimStart(_toTrim).Length == 0; 223 | } 224 | 225 | private static bool IsEmptyOrFullyCommentedOutLine(string line) 226 | { 227 | var after = line.TrimStart(_toTrim); 228 | if (after.Length == 0) 229 | return true; 230 | return after.IndexOf("#") == 0; 231 | } 232 | 233 | public static string Htmlify(string input) 234 | { 235 | string firstRepl = System.Text.RegularExpressions.Regex.Replace(input, "[<>&\"'\n\r]", 236 | t => 237 | { 238 | switch (t.Value) 239 | { 240 | case "<": 241 | return "<"; 242 | case ">": 243 | return ">"; 244 | case "&": 245 | return "&"; 246 | case "\"": 247 | return """; 248 | case "'": 249 | return "'"; 250 | case "\n": 251 | return "
"; 252 | case "\r": 253 | return string.Empty; 254 | } 255 | return string.Empty; 256 | }); 257 | 258 | return System.Text.RegularExpressions.Regex.Replace 259 | (firstRepl, 260 | "(http|https|ftp|sftp|mailto|skype):[A-Za-z0-9!*'\\(\\);:@&=+$,/?#\\[\\]\\-_.~]+", 261 | t => 262 | { 263 | string shortName = t.Value; 264 | if (t.Value.StartsWith("http")) 265 | shortName = shortName.Substring(7); 266 | if (t.Value.StartsWith("mailto")) 267 | shortName = shortName.Substring(7); 268 | 269 | return "" + shortName + ""; 271 | }); 272 | } 273 | } 274 | } -------------------------------------------------------------------------------- /Assemblies/PyghaLoader.cs: -------------------------------------------------------------------------------- 1 | #if GH_0_9 2 | 3 | using System; 4 | using GhPython.Forms; 5 | using Grasshopper.Kernel; 6 | using Rhino.Runtime; 7 | using System.IO; 8 | using System.Collections.Generic; 9 | using GhPython.Component; 10 | using System.Reflection; 11 | using System.Collections; 12 | using System.Windows.Forms; 13 | using System.Security; 14 | using Grasshopper; 15 | using System.Runtime.InteropServices; 16 | 17 | namespace GhPython.Assemblies 18 | { 19 | public class GhpyLoader : GH_AssemblyPriority 20 | { 21 | PythonEnvironment _gha_environment; 22 | 23 | public override GH_LoadingInstruction PriorityLoad() 24 | { 25 | try 26 | { 27 | _gha_environment = CreateEnvironment(); 28 | LoadExternalPythonAssemblies(); 29 | SetupMainDirListener(); 30 | } 31 | catch (Exception ex) 32 | { 33 | Global_Proc.ASSERT(Guid.Empty, "GhPython last exception boundary", ex); 34 | } 35 | return GH_LoadingInstruction.Proceed; 36 | } 37 | 38 | private PythonEnvironment CreateEnvironment() 39 | { 40 | var externalPy = PythonScript.Create(); 41 | return new PythonEnvironment(null, externalPy); 42 | } 43 | 44 | private void SetupMainDirListener() 45 | { 46 | if (Directory.Exists(GH_ComponentServer.GHA_AppDataDirectory)) 47 | { 48 | var watcher = GH_FileWatcher.CreateDirectoryWatcher(GH_ComponentServer.GHA_AppDataDirectory, "*.ghpy", GH_FileWatcherEvents.Created, 49 | (sender, filePath, change) => 50 | { 51 | try 52 | { 53 | if (change == WatcherChangeTypes.Created) 54 | { 55 | if (LoadOneAddon(_gha_environment, filePath)) 56 | { 57 | GH_ComponentServer.UpdateRibbonUI(); 58 | } 59 | } 60 | } 61 | catch (Exception ex) 62 | { 63 | Global_Proc.ASSERT(Guid.Empty, "GhPython last exception boundary", ex); 64 | } 65 | }); 66 | watcher.Active = true; 67 | } 68 | } 69 | 70 | private void LoadExternalPythonAssemblies() 71 | { 72 | var allGhas = GetAllPygha(); 73 | 74 | foreach (var path in allGhas) 75 | { 76 | LoadOneAddon(_gha_environment, path); 77 | } 78 | } 79 | 80 | 81 | static class ExternalUnsafe 82 | { 83 | [DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)] 84 | [return: MarshalAs(UnmanagedType.Bool)] 85 | private static extern bool DeleteFile(string name); 86 | 87 | const int FILE_ATTRIBUTE_DIRECTORY = 0x10; 88 | 89 | [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] 90 | static extern int GetFileAttributes(string lpFileName); 91 | 92 | public static bool HasZoneIdetifier(string fileName) 93 | { 94 | if (!File.Exists(fileName)) return false; 95 | var val = GetFileAttributes(fileName + ":Zone.Identifier"); 96 | return (FILE_ATTRIBUTE_DIRECTORY & val) != FILE_ATTRIBUTE_DIRECTORY; 97 | } 98 | 99 | public static bool Unblock(string fileName) 100 | { 101 | if (!File.Exists(fileName)) return false; 102 | return DeleteFile(fileName + ":Zone.Identifier"); 103 | } 104 | } 105 | 106 | 107 | private static bool LoadOneAddon(PythonEnvironment p, string path) 108 | { 109 | var engine = p.Engine as dynamic; 110 | var runtime = engine.Runtime; 111 | var ops = engine.Operations; 112 | 113 | if(ExternalUnsafe.HasZoneIdetifier(path)) 114 | { 115 | if (MessageBox.Show("A FILE IS BLOCKED: \n\n" + 116 | path + 117 | "\n\nBefore being able to use it, this file should be unblocked.\n" + 118 | "Do you want attempt to unblock it now?", "GhPython Assembly is blocked", 119 | MessageBoxButtons.YesNo, MessageBoxIcon.Asterisk, MessageBoxDefaultButton.Button2, 120 | MessageBoxOptions.DefaultDesktopOnly) == DialogResult.Yes) 121 | { 122 | if (!ExternalUnsafe.Unblock(path)) 123 | { 124 | Global_Proc.ASSERT(Guid.Empty, "You need to unblock \"" + path + "\" manually."); return false; 125 | } 126 | } 127 | } 128 | 129 | AssemblyName assName; 130 | try 131 | { 132 | assName = AssemblyName.GetAssemblyName(path); 133 | } 134 | catch (SecurityException ex) 135 | { 136 | Global_Proc.ASSERT(Guid.Empty, "You have not enough rights to load \"" + path + "\".", ex); return false; 137 | } 138 | catch (BadImageFormatException ex) 139 | { 140 | Global_Proc.ASSERT(Guid.Empty, "The assembly \"" + path + "\" has a bad format.", ex); return false; 141 | } 142 | catch (FileLoadException ex) 143 | { 144 | Global_Proc.ASSERT(Guid.Empty, "The assembly \"" + path + "\" is found but cannot be loaded.", ex); return false; 145 | } 146 | 147 | var appDomain = AppDomain.CreateDomain("Temp"); 148 | try 149 | { 150 | var farAssembly = appDomain.CreateInstanceFrom(path, "DLRCachedCode"); 151 | } 152 | catch (FileLoadException ex) 153 | { 154 | int error = Marshal.GetHRForException(ex); 155 | if (error == -0x40131515) 156 | { 157 | Global_Proc.ASSERT(Guid.Empty, "The file \"" + path + "\" is blocked.", ex); return false; 158 | } 159 | Global_Proc.ASSERT(Guid.Empty, "The assembly at \"" + path + "\" cannot be loaded.", ex); return false; 160 | } 161 | catch (BadImageFormatException ex) 162 | { 163 | Global_Proc.ASSERT(Guid.Empty, "This assembly \"" + path + "\" has a bad inner format.", ex); return false; 164 | } 165 | catch (TypeLoadException ex) 166 | { 167 | Global_Proc.ASSERT(Guid.Empty, "\"" + path + "\" is not a valid Python assembly. Please remove it.", ex); return false; 168 | } 169 | catch (MissingMethodException ex) 170 | { 171 | Global_Proc.ASSERT(Guid.Empty, "This assembly \"" + path + "\" is ruined.", ex); return false; 172 | } 173 | finally 174 | { 175 | if (appDomain != null) 176 | { 177 | AppDomain.Unload(appDomain); 178 | } 179 | } 180 | 181 | Assembly assembly = Assembly.LoadFile(path); 182 | var cachedCode = assembly.GetType("DLRCachedCode", false, false); 183 | 184 | if (cachedCode == null) return false; //should be already ruled out 185 | 186 | dynamic info = cachedCode.InvokeMember("GetScriptCodeInfo", 187 | BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Static, 188 | null, null, new object[0]); 189 | string[] modules = info.GetValue(2)[0]; 190 | 191 | runtime.LoadAssembly(assembly); 192 | 193 | bool toReturn = false; 194 | 195 | foreach (var module in modules) 196 | { 197 | var statement = "import " + module; 198 | p.Script.ExecuteScript(statement); 199 | 200 | dynamic ns = p.Script.GetVariable(module); 201 | 202 | var dict = ns.Get__dict__(); 203 | var vars = dict.Keys; 204 | 205 | foreach (var v in vars) 206 | { 207 | var text = v as string; 208 | 209 | if (text == null) continue; 210 | object o = dict[text]; 211 | 212 | if (o == null) continue; 213 | Type type = o.GetType(); 214 | 215 | if (type.FullName != "IronPython.Runtime.Types.PythonType") continue; 216 | 217 | var basesEnum = (IEnumerable)type.InvokeMember( 218 | "get_BaseTypes", 219 | BindingFlags.NonPublic | BindingFlags.InvokeMethod | BindingFlags.Instance, null, o, null); 220 | if (basesEnum == null) continue; 221 | 222 | foreach (var baseObj in basesEnum) 223 | { 224 | Type finalSystemType = (Type)baseObj.GetType().InvokeMember( 225 | "get_FinalSystemType", 226 | BindingFlags.NonPublic | BindingFlags.InvokeMethod | BindingFlags.Instance, null, baseObj, null); 227 | if (finalSystemType == null) continue; 228 | 229 | if (typeof(IGH_Component).IsAssignableFrom(finalSystemType)) 230 | { 231 | var instance = Instantiate(ops as object, o); 232 | var proxy = new PythonInstantiatorProxy(instance, o, ops as object, path); 233 | 234 | toReturn |= Grasshopper.GH_InstanceServer.ComponentServer.AddProxy(proxy); 235 | } 236 | } 237 | } 238 | 239 | p.Script.ExecuteScript("del " + module); 240 | } 241 | return toReturn; 242 | } 243 | 244 | private static IGH_Component Instantiate(object engineOperations, object pythonType) 245 | { 246 | return (engineOperations as dynamic).Invoke(pythonType); 247 | } 248 | 249 | private static IEnumerable GetAllPygha() 250 | { 251 | foreach (var path in GetPathsToBeSearched()) 252 | { 253 | string[] files = Directory.GetFiles(path, "*.ghpy", SearchOption.AllDirectories); 254 | if (files != null) 255 | { 256 | for (int i = 0; i < files.Length; i++) 257 | { 258 | if (files[i] != null) 259 | yield return files[i]; 260 | } 261 | } 262 | } 263 | } 264 | 265 | private static IEnumerable GetPathsToBeSearched() 266 | { 267 | var dirs = new Dictionary(); 268 | foreach (var path in GH_ComponentServer.GHA_Directories) 269 | { 270 | if (string.IsNullOrEmpty(path)) continue; 271 | var newPath = path; 272 | if (path.EndsWith("\\")) newPath = path.Substring(0, path.Length - 1); 273 | if (!Directory.Exists(newPath)) continue; 274 | var pathUp = newPath.ToUpperInvariant(); 275 | if (!dirs.ContainsKey(pathUp)) 276 | { 277 | dirs.Add(pathUp, null); 278 | yield return newPath; 279 | } 280 | } 281 | } 282 | } 283 | } 284 | 285 | #endif -------------------------------------------------------------------------------- /Component/PythonComponent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Grasshopper.Kernel; 3 | using Grasshopper.Kernel.Parameters; 4 | using GhPython.DocReplacement; 5 | using System.Windows.Forms; 6 | using System.Collections.Generic; 7 | using Grasshopper.Kernel.Parameters.Hints; 8 | using System.Runtime.InteropServices; 9 | 10 | namespace GhPython.Component 11 | { 12 | [Guid("CEAB6E56-CEEC-A646-84D5-363C57440969")] 13 | public class PythonComponent_OBSOLETE : ScriptingAncestorComponent, IGH_VarParamComponent 14 | { 15 | protected override void AddDefaultInput(GH_Component.GH_InputParamManager inputManager) 16 | { 17 | inputManager.AddParameter(ConstructVariable(GH_VarParamSide.Input, "x")); 18 | inputManager.AddParameter(ConstructVariable(GH_VarParamSide.Input, "y")); 19 | } 20 | 21 | protected override void AddDefaultOutput(GH_Component.GH_OutputParamManager outputManager) 22 | { 23 | outputManager.RegisterParam(ConstructVariable(GH_VarParamSide.Output, "a")); 24 | } 25 | 26 | public override Guid ComponentGuid 27 | { 28 | get { return typeof(PythonComponent_OBSOLETE).GUID; } 29 | } 30 | 31 | internal DocStorage DocStorageMode 32 | { 33 | get; 34 | set; 35 | } 36 | 37 | protected override void SetScriptTransientGlobals() 38 | { 39 | base.SetScriptTransientGlobals(); 40 | 41 | switch (DocStorageMode) 42 | { 43 | case DocStorage.InGrasshopperMemory: 44 | case DocStorage.AutomaticMarshal: 45 | { 46 | m_py.ScriptContextDoc = g_document; 47 | m_marshal = new OldComponentIOMarshal(g_document, this); 48 | m_py.SetVariable(DOCUMENT_NAME, g_document); 49 | m_py.SetIntellisenseVariable(DOCUMENT_NAME, g_document); 50 | break; 51 | } 52 | case DocStorage.InRhinoDoc: 53 | { 54 | m_py.ScriptContextDoc = Rhino.RhinoDoc.ActiveDoc; 55 | m_marshal = new OldComponentIOMarshal(Rhino.RhinoDoc.ActiveDoc, this); 56 | Rhino.RhinoDoc.ActiveDoc.UndoRecordingEnabled = true; 57 | if (m_py.ContainsVariable(DOCUMENT_NAME)) 58 | { 59 | m_py.RemoveVariable(DOCUMENT_NAME); 60 | m_py.SetIntellisenseVariable(DOCUMENT_NAME, null); 61 | } 62 | break; 63 | } 64 | default: 65 | { 66 | throw new ApplicationException("Unexpected DocStorage type."); 67 | } 68 | } 69 | } 70 | 71 | public override GH_Exposure Exposure 72 | { 73 | get { return GH_Exposure.hidden; } 74 | } 75 | 76 | public override void VariableParameterMaintenance() 77 | { 78 | ParametersModified(GH_VarParamSide.Input); 79 | ParametersModified(GH_VarParamSide.Output); 80 | } 81 | 82 | class DocSetter 83 | { 84 | public DocStorage NewDocStorage; 85 | public PythonComponent_OBSOLETE Component; 86 | 87 | public void SetDoc(object sender, EventArgs e) 88 | { 89 | try 90 | { 91 | Component.CheckIfSetupActionsAreNecessary(); 92 | 93 | Component.DocStorageMode = NewDocStorage; 94 | Component.SetScriptTransientGlobals(); 95 | Component.ExpireSolution(true); 96 | } 97 | catch (Exception ex) 98 | { 99 | GhPython.Forms.PythonScriptForm.LastHandleException(ex); 100 | } 101 | } 102 | } 103 | 104 | public ToolStripMenuItem GetTargetVariableMenuItem() 105 | { 106 | var result = new ToolStripMenuItem("&Rhinoscriptsyntax usage", null, new ToolStripItem[] 107 | { 108 | new ToolStripMenuItem("rhinoscriptsyntax / Automatically &marshal Guids", null, new DocSetter{ 109 | Component = this, NewDocStorage = DocStorage.AutomaticMarshal}.SetDoc) 110 | { 111 | ToolTipText = "Inputs and outputs accept Guids. The " + DOCUMENT_NAME + " variable is available for advanced use", 112 | }, 113 | new ToolStripMenuItem("RhinoCommon / Provide &" + DOCUMENT_NAME + " variable", null, new DocSetter{ 114 | Component = this, NewDocStorage = DocStorage.InGrasshopperMemory }.SetDoc) 115 | { 116 | ToolTipText = "Use this option to obtain the " + DOCUMENT_NAME + " variable in your script\nand be able to assign it to the outputs manually", 117 | }, 118 | new ToolStripMenuItem("Add to &Rhino document", null, new DocSetter{Component = this, NewDocStorage = DocStorage.InRhinoDoc}.SetDoc) 119 | { 120 | ToolTipText = "Use this option to choose to use the traditional Rhino document as output. Not recommanded", 121 | } 122 | }) 123 | { 124 | ToolTipText = "Choose where rhinoscriptsyntax functions have their effects", 125 | }; 126 | 127 | EventHandler update = (sender, args) => 128 | { 129 | result.DropDownItems[0].Image = GetCheckedImage(DocStorageMode == DocStorage.AutomaticMarshal); 130 | result.DropDownItems[1].Image = GetCheckedImage(DocStorageMode == DocStorage.InGrasshopperMemory); 131 | result.DropDownItems[2].Image = GetCheckedImage(DocStorageMode == DocStorage.InRhinoDoc); 132 | }; 133 | update(null, EventArgs.Empty); 134 | result.DropDownOpening += update; 135 | 136 | return result; 137 | } 138 | 139 | #region Members of IGH_VarParamComponent 140 | 141 | IGH_Param ConstructVariable(GH_VarParamSide side, string nickname) 142 | { 143 | if (side == GH_VarParamSide.Input) 144 | { 145 | var param = new Param_ScriptVariable(); 146 | if (!string.IsNullOrWhiteSpace(nickname)) 147 | param.NickName = nickname; 148 | FixGhInput(param); 149 | return param; 150 | } 151 | if (side == GH_VarParamSide.Output) 152 | { 153 | var param = new Param_GenericObject(); 154 | if (string.IsNullOrWhiteSpace(nickname)) 155 | param.Name = param.NickName; 156 | else 157 | { 158 | param.NickName = nickname; 159 | param.Name = String.Format("Result {0}", nickname); 160 | } 161 | param.Description = String.Format("Output parameter {0}", param.NickName); 162 | return param; 163 | } 164 | return null; 165 | } 166 | 167 | public IGH_Param ConstructVariable(GH_VarParamEventArgs e) 168 | { 169 | return ConstructVariable(e.Side, null); 170 | } 171 | 172 | public bool IsInputVariable 173 | { 174 | get { return true; } 175 | } 176 | 177 | public bool IsOutputVariable 178 | { 179 | get { return true; } 180 | } 181 | 182 | public bool IsVariableParam(GH_VarParamEventArgs e) 183 | { 184 | if(e.Side == GH_VarParamSide.Input) 185 | return e.Index > (HiddenCodeInput ? -1 : 0); 186 | else 187 | return e.Index > (HiddenOutOutput ? -1 : 0); 188 | } 189 | 190 | public void ManagerConstructed(GH_VarParamSide side, Grasshopper.GUI.GH_VariableParameterManager manager) 191 | { 192 | string pool = (side == GH_VarParamSide.Input) ? "xyzuvw" : "abcdef"; 193 | manager.NameConstructor = new Grasshopper.Kernel.GH_StringPattern(pool, 4); 194 | } 195 | 196 | public void ParametersModified(GH_VarParamSide side) 197 | { 198 | switch (side) 199 | { 200 | case GH_VarParamSide.Input: 201 | foreach (var i in Params.Input) 202 | { 203 | if (i is Param_ScriptVariable) 204 | FixGhInput(i as Param_ScriptVariable); 205 | } 206 | break; 207 | 208 | case GH_VarParamSide.Output: 209 | foreach (var i in Params.Input) 210 | { 211 | if (i is Param_GenericObject) 212 | { 213 | i.Name = i.NickName; 214 | i.Description = i.NickName; 215 | } 216 | } 217 | break; 218 | } 219 | } 220 | 221 | #endregion 222 | 223 | 224 | const string TargetDocIdentifier = "GhMemory"; 225 | 226 | public override bool Write(GH_IO.Serialization.GH_IWriter writer) 227 | { 228 | if (!Enum.IsDefined(typeof(DocStorage), DocStorageMode)) 229 | DocStorageMode = DocStorage.InGrasshopperMemory; 230 | writer.SetInt32(TargetDocIdentifier, (int)DocStorageMode); 231 | 232 | return base.Write(writer); 233 | } 234 | 235 | public override bool Read(GH_IO.Serialization.GH_IReader reader) 236 | { 237 | int val = -1; 238 | if (reader.TryGetInt32(TargetDocIdentifier, ref val)) 239 | DocStorageMode = (DocStorage)val; 240 | 241 | if (!Enum.IsDefined(typeof(DocStorage), DocStorageMode)) 242 | DocStorageMode = DocStorage.InGrasshopperMemory; 243 | 244 | return base.Read(reader); 245 | } 246 | 247 | public override bool AppendMenuItems(ToolStripDropDown iMenu) 248 | { 249 | var toReturn = base.AppendMenuItems(iMenu); 250 | 251 | { 252 | var tsi = GetTargetVariableMenuItem(); 253 | iMenu.Items.Insert(Math.Min(iMenu.Items.Count, 1), tsi); 254 | } 255 | 256 | return toReturn; 257 | } 258 | 259 | internal override void FixGhInput(Param_ScriptVariable i, bool alsoSetIfNecessary = true) 260 | { 261 | i.Name = string.Format("Variable {0}", i.NickName); 262 | i.Description = string.Format("Script Variable {0}", i.NickName); 263 | i.AllowTreeAccess = true; 264 | i.Optional = true; 265 | i.ShowHints = true; 266 | 267 | i.Hints = new List(); 268 | 269 | i.Hints.Add(new DynamicHint(this)); 270 | i.Hints.AddRange(PossibleHints); 271 | i.Hints.AddRange(new IGH_TypeHint[] 272 | { 273 | new SpecialBoxHint(this), 274 | new GH_HintSeparator(), 275 | new SpecialLineHint(this), 276 | new SpecialCircleHint(this), 277 | new SpecialArcHint(this), 278 | new SpecialPolylineHint(this) 279 | }); 280 | i.Hints.AddRange(AlreadyGeometryBaseHints); 281 | 282 | if (alsoSetIfNecessary && i.TypeHint == null) 283 | i.TypeHint = i.Hints[0]; 284 | } 285 | 286 | static readonly IGH_TypeHint[] AlreadyGeometryBaseHints = 287 | { 288 | new GH_CurveHint(), 289 | new GH_SurfaceHint(), 290 | new GH_BrepHint(), 291 | new GH_MeshHint(), 292 | new GH_GeometryBaseHint() 293 | }; 294 | } 295 | } -------------------------------------------------------------------------------- /Forms/PythonScriptForm.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 17, 17 122 | 123 | 124 | 132, 17 125 | 126 | 127 | 128 | 129 | AAABAAEAGBgAAAEAIACICQAAFgAAACgAAAAYAAAAMAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 130 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADy8vN/8vLzn/Ly8//y8vP/8fHy//Dw8f/w8PH/8PDx//Ly 131 | 8//y8vP/8vLz3/Ly83/y8vNfAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 132 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 133 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 134 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 135 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAFvW+Q9f1PtvYNH73znC/P8tv/7/Kr3//0jB+/9QwvufX8b5PwAA 136 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGjZ 137 | +p9F1P7/Ps///zfJ//8zxf//MMP//1/M//+J2P//QL7872rM+C8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA 138 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE3b/r9K2f//RNX//z7P//85y///NMb//4Pb 139 | ///B6///Nr7+/y++/T8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 140 | AAAAAAAAAAAAAFPi/79P3v//S9r//0TV//8+zv//O8z//zvI//8/x///Lb7+/zO//D8AAAAAAAAAAAAA 141 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL2cdT+neUM/p3lDL1nm/79W5P//UN///0va 142 | //9N1f3/Qc39fz3J/X85xv1/OcX8fzjB+083wPs/N8D7P3TN9x8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA 143 | AAAAAAAAuZNjv6x2N/+odDf/uZNm/4Tu/P9d6v//WOX//1Ph//9M2///SNj//0HS//87zP//Nsj//zLF 144 | //8twP//Kbz//y25/f+X2PY/AAAAAAAAAAAAAAAAAAAAAAAAAADg1MY/sXs6/7B5N/+rdjf/upNm/4Ls 145 | /P9g7f//Xuv//1fl//9U4///Tt3//0nY//9B0v//O8z//zbI//8yxf//LcD//ym8//9rzPi/AAAAAAAA 146 | AAAAAAAAAAAAAAAAAADCm21/tXw4/7B5N/+tdzf/topU/47d5/9g7f//YO3//17r//9X5f//VOP//07c 147 | //9I2P//Q9T//z7P//84yf//MsX//y/C//9Cwfv/AAAAAAAAAAAAAAAAAAAAAAAAAAC4gT1/uH44/7V8 148 | OP+xejf/r3k3/7mtkP+A5vb/YOv+/2Dt//9e6///Wuf//1Ti//9N3P//Sdj//0TV//8+zv//OMr//zLF 149 | //8zw/7/AAAAAAAAAAAAAAAAAAAAAAAAAAC7gTp/vIA4/7h+OP+zezf/r3k3/654N/+vgEn/tpBi/7GO 150 | ZP+wjWT/q4tk/6qLZf+pmn3/ns7V/1Ta/f9G1v//Ps///zrL//84yP3/AAAAAAAAAAAAAAAAAAAAAAAA 151 | AAC+j1Z/v4I4/7yAOP+2fDj/s3s3/695N/+rdjf/pnM3/6NyNv+cbTb/m2w2/5VqNv+Uajf/poZe/4PV 152 | 6P9M2///RdX//0HS//9Ozvv/AAAAAAAAAAAAAAAAAAAAAAAAAADSuptfwYQ5/76COP+6fzj/tHw3/7F6 153 | N/+ueDf/qXU3/6VzN/+gcDb/nG02/5hrNv+Uajf/lGs4/63Kx/9S4P//TNv//0jY//9y2PnfAAAAAAAA 154 | AAAAAAAAAAAAAAAAAAAAAAAAx5lg38GDOP+7gDj/uX44/7R8N/+veTf/rHc3/6d0N/+lczf/n282/5ts 155 | Nv+Vajb/lGo3/7LLxf9Y5f//U+L//07b/v9u1vdfAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAyqh/H8aZ 156 | Y3+9gjl/vIE4f7Z8OH+yejd/r3k3f6x3N3+qfUa/o3I2/55uNv+abDb/l2s2/625qJ9d6v9/VuT/f1/e 157 | +l8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALl+OL+1fDj/sXo3/654 158 | N/+tdzf/pXM3/6FwNv+cbTb/nG02/5xtNj8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 159 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAL6COL/Oomz/3sWn/7B5N/+ueDf/qnY3/6VzN/+gcDb/nG02/5xt 160 | Nj8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALyF 161 | Qb/Urn//7uPW/7N7N/+veTf/rXc3/6l1N/+lczf/pnc+/6mEVj8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA 162 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM2uiE/CkVXPv4pK/7V+O/+yfDr/r3o6/618 163 | Qf+ziVfvqn1NTwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 164 | AAAAAAAAAAAAAAAAAADe0cIPx6iCP7aERj+yf0M/sn9DP7WPYD/XybkvAAAAAAAAAAAAAAAAAAAAAAAA 165 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 166 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 167 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 168 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD8AB9B////Qf///0H/AH9B/wA/Qf8AP0H/AD9B+AAHQfAA 169 | A0HgAANB4AADQeAAA0HgAANB4AADQeAAA0HwAANB8AAHQf8AP0H/AD9B/wA/Qf8Af0H/gP9B////Qf// 170 | /0E= 171 | 172 | 173 | -------------------------------------------------------------------------------- /DocReplacement/GrasshopperDocument.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using Grasshopper; 5 | using Grasshopper.Kernel; 6 | using Rhino; 7 | using Rhino.Collections; 8 | using Rhino.Display; 9 | using Rhino.DocObjects; 10 | using Rhino.DocObjects.Tables; 11 | 12 | namespace GhPython.DocReplacement 13 | { 14 | public class GrasshopperDocument 15 | { 16 | readonly CustomTable _table = new CustomTable(); 17 | 18 | public RhinoList CommitIntoRhinoDocument() 19 | { 20 | RhinoList newGuids = new RhinoList(Objects.Count); 21 | 22 | foreach (var content in this.Objects.AttributedGeometries) 23 | { 24 | var geom = content.Geometry; 25 | var attr = content.Attributes; 26 | 27 | if (geom is IGH_BakeAwareData) 28 | { 29 | Guid guid; 30 | (geom as IGH_BakeAwareData).BakeGeometry(RhinoDoc.ActiveDoc, attr, out guid); 31 | if (!guid.Equals(Guid.Empty)) 32 | newGuids.Add(guid); 33 | } 34 | else 35 | throw new ApplicationException("UnexpectedObjectException. Please report this error to giulio@mcneel.com"); 36 | } 37 | 38 | return newGuids; 39 | } 40 | 41 | public object this[Guid id] 42 | { 43 | get 44 | { 45 | return Objects.Contains(id) ? Objects.Find(id).Geometry : null; 46 | } 47 | } 48 | 49 | 50 | public IEnumerable this[IEnumerable guids] 51 | { 52 | 53 | get 54 | { 55 | if (guids == null) 56 | throw new ArgumentNullException("guids", 57 | "Cannot obtain a null item or subset from " + GhPython.Component.ScriptingAncestorComponent.DOCUMENT_NAME); 58 | 59 | return SubSet(guids); 60 | } 61 | } 62 | 63 | public IEnumerable SubSet(IEnumerable guids) 64 | { 65 | if (guids == null) 66 | throw new ArgumentNullException("guids", 67 | "Cannot obtain a null item or subset from " + GhPython.Component.ScriptingAncestorComponent.DOCUMENT_NAME); 68 | 69 | foreach (var obj in guids) 70 | { 71 | if (obj is Guid) 72 | { 73 | var id = (Guid)obj; 74 | if (Objects.Contains(id)) 75 | yield return Objects.Find(id).Geometry; 76 | else 77 | yield return null; 78 | } 79 | else 80 | yield return null; 81 | } 82 | } 83 | 84 | public BitmapTable Bitmaps 85 | { 86 | get 87 | { 88 | throw CustomTable.NotSupportedExceptionHelp(); 89 | } 90 | } 91 | 92 | public DimStyleTable DimStyles 93 | { 94 | get 95 | { 96 | throw CustomTable.NotSupportedExceptionHelp(); 97 | } 98 | } 99 | 100 | public int DistanceDisplayPrecision 101 | { 102 | get 103 | { 104 | return RhinoDoc.ActiveDoc.DistanceDisplayPrecision; 105 | } 106 | } 107 | 108 | public FontTable Fonts 109 | { 110 | get 111 | { 112 | throw CustomTable.NotSupportedExceptionHelp(); 113 | } 114 | } 115 | 116 | public GroupTable Groups 117 | { 118 | get 119 | { 120 | throw CustomTable.NotSupportedExceptionHelp(); 121 | } 122 | } 123 | 124 | public InstanceDefinitionTable InstanceDefinitions 125 | { 126 | get 127 | { 128 | throw CustomTable.NotSupportedExceptionHelp(); 129 | } 130 | } 131 | 132 | public CustomTable Objects 133 | { 134 | get 135 | { 136 | return _table; 137 | } 138 | } 139 | 140 | public bool IsLocked 141 | { 142 | get 143 | { 144 | return false; 145 | } 146 | } 147 | 148 | public bool IsReadOnly 149 | { 150 | get 151 | { 152 | return false; 153 | } 154 | } 155 | 156 | public bool IsSendingMail 157 | { 158 | get 159 | { 160 | return RhinoDoc.ActiveDoc.IsSendingMail; 161 | } 162 | } 163 | 164 | public LayerTable Layers 165 | { 166 | get 167 | { 168 | throw CustomTable.NotSupportedExceptionHelp(); 169 | } 170 | } 171 | 172 | public MaterialTable Materials 173 | { 174 | get 175 | { 176 | throw CustomTable.NotSupportedExceptionHelp(); 177 | } 178 | } 179 | 180 | public double ModelAbsoluteTolerance 181 | { 182 | get 183 | { 184 | return RhinoDoc.ActiveDoc.ModelAbsoluteTolerance; 185 | } 186 | set 187 | { 188 | throw CustomTable.NotSupportedExceptionHelp(); 189 | } 190 | } 191 | 192 | public double ModelAngleToleranceDegrees 193 | { 194 | get 195 | { 196 | return RhinoDoc.ActiveDoc.ModelAngleToleranceDegrees; 197 | } 198 | set 199 | { 200 | throw CustomTable.NotSupportedExceptionHelp(); 201 | } 202 | } 203 | 204 | public double ModelAngleToleranceRadians 205 | { 206 | get 207 | { 208 | return RhinoDoc.ActiveDoc.ModelAngleToleranceRadians; 209 | } 210 | set 211 | { 212 | throw CustomTable.NotSupportedExceptionHelp(); 213 | } 214 | } 215 | 216 | public double ModelRelativeTolerance 217 | { 218 | get 219 | { 220 | return RhinoDoc.ActiveDoc.ModelRelativeTolerance; 221 | } 222 | set 223 | { 224 | throw CustomTable.NotSupportedExceptionHelp(); 225 | } 226 | } 227 | public UnitSystem ModelUnitSystem 228 | { 229 | get 230 | { 231 | return RhinoDoc.ActiveDoc.ModelUnitSystem; 232 | } 233 | set 234 | { 235 | throw CustomTable.NotSupportedExceptionHelp(); 236 | } 237 | } 238 | 239 | public bool Modified 240 | { 241 | get 242 | { 243 | return true; 244 | } 245 | set 246 | { 247 | throw CustomTable.NotSupportedExceptionHelp(); 248 | } 249 | } 250 | 251 | public string Name 252 | { 253 | get 254 | { 255 | return Instances.DocumentServer[0].DisplayName; 256 | } 257 | } 258 | public NamedConstructionPlaneTable NamedConstructionPlanes 259 | { 260 | get 261 | { 262 | throw CustomTable.NotSupportedExceptionHelp(); 263 | } 264 | } 265 | 266 | public NamedViewTable NamedViews 267 | { 268 | get 269 | { 270 | throw CustomTable.NotSupportedExceptionHelp(); 271 | } 272 | } 273 | public string Notes 274 | { 275 | get 276 | { 277 | return RhinoDoc.ActiveDoc.Notes; 278 | } 279 | set 280 | { 281 | throw CustomTable.NotSupportedExceptionHelp(); 282 | } 283 | } 284 | 285 | public double PageAbsoluteTolerance 286 | { 287 | get 288 | { 289 | return RhinoDoc.ActiveDoc.PageAbsoluteTolerance; 290 | } 291 | set 292 | { 293 | throw CustomTable.NotSupportedExceptionHelp(); 294 | } 295 | } 296 | 297 | public double PageAngleToleranceDegrees 298 | { 299 | get 300 | { 301 | return RhinoDoc.ActiveDoc.PageAngleToleranceDegrees; 302 | } 303 | set 304 | { 305 | throw CustomTable.NotSupportedExceptionHelp(); 306 | } 307 | } 308 | 309 | public double PageAngleToleranceRadians 310 | { 311 | get 312 | { 313 | return RhinoDoc.ActiveDoc.PageAngleToleranceRadians; 314 | } 315 | set 316 | { 317 | throw CustomTable.NotSupportedExceptionHelp(); 318 | } 319 | } 320 | 321 | 322 | /// 323 | /// Page space relative tolerance. 324 | /// 325 | public double PageRelativeTolerance 326 | { 327 | get 328 | { 329 | return RhinoDoc.ActiveDoc.PageRelativeTolerance; 330 | } 331 | set 332 | { 333 | throw CustomTable.NotSupportedExceptionHelp(); 334 | } 335 | } 336 | public UnitSystem PageUnitSystem 337 | { 338 | get 339 | { 340 | return RhinoDoc.ActiveDoc.PageUnitSystem; 341 | } 342 | set 343 | { 344 | throw CustomTable.NotSupportedExceptionHelp(); 345 | } 346 | } 347 | 348 | /// 349 | /// Returns the path of the currently loaded Grasshopper document (ghx file). 350 | /// 351 | public string Path 352 | { 353 | get 354 | { 355 | return Instances.DocumentServer[0].FilePath; 356 | } 357 | } 358 | public StringTable Strings 359 | { 360 | get 361 | { 362 | throw CustomTable.NotSupportedExceptionHelp(); 363 | } 364 | } 365 | 366 | /// 367 | /// name of the template file used to create this document. 368 | /// This is a runtime value only present if the document was newly created. 369 | /// 370 | public string TemplateFileUsed 371 | { 372 | get 373 | { 374 | return RhinoDoc.ActiveDoc.TemplateFileUsed; 375 | } 376 | } 377 | public bool UndoRecordingEnabled 378 | { 379 | get 380 | { 381 | return false; 382 | } 383 | set 384 | { 385 | if (value) 386 | throw CustomTable.NotSupportedExceptionHelp(); 387 | } 388 | } 389 | 390 | readonly GhViewTable _views = new GhViewTable(() => RhinoDoc.ActiveDoc.Views, false); 391 | public GhViewTable Views 392 | { 393 | get 394 | { 395 | return _views; 396 | } 397 | } 398 | } 399 | 400 | public class GhViewTable : IEnumerable 401 | { 402 | readonly Func _tableFunc; 403 | readonly bool _redraws; 404 | 405 | public GhViewTable(Func tableFunc, bool redraws) 406 | { 407 | _tableFunc = tableFunc; 408 | _redraws = redraws; 409 | } 410 | 411 | public RhinoView ActiveView 412 | { 413 | get 414 | { 415 | return _tableFunc().ActiveView; 416 | } 417 | set 418 | { 419 | _tableFunc().ActiveView = value; 420 | } 421 | } 422 | 423 | public object Document 424 | { 425 | get 426 | { 427 | return _tableFunc().Document; 428 | } 429 | } 430 | 431 | public bool RedrawEnabled 432 | { 433 | get 434 | { 435 | return _tableFunc().RedrawEnabled; 436 | } 437 | set 438 | { 439 | _tableFunc().RedrawEnabled = value; 440 | } 441 | } 442 | 443 | public RhinoPageView AddPageView(string title) 444 | { 445 | return _tableFunc().AddPageView(title); 446 | } 447 | 448 | public RhinoPageView AddPageView(string title, double pageWidth, double pageHeight) 449 | { 450 | return _tableFunc().AddPageView(title, pageWidth, pageHeight); 451 | } 452 | 453 | public void DefaultViewLayout() 454 | { 455 | _tableFunc().DefaultViewLayout(); 456 | } 457 | 458 | public RhinoView Find(Guid mainViewportId) 459 | { 460 | return Find(mainViewportId); 461 | } 462 | 463 | public RhinoView Find(string mainViewportName, bool compareCase) 464 | { 465 | return _tableFunc().Find(mainViewportName, compareCase); 466 | } 467 | 468 | public void FlashObjects(IEnumerable list, bool useSelectionColor) 469 | { 470 | _tableFunc().FlashObjects(list, useSelectionColor); 471 | } 472 | 473 | public void FourViewLayout(bool useMatchingViews) 474 | { 475 | _tableFunc().FourViewLayout(useMatchingViews); 476 | } 477 | 478 | public IEnumerator GetEnumerator() 479 | { 480 | return _tableFunc().GetEnumerator(); 481 | } 482 | 483 | IEnumerator IEnumerable.GetEnumerator() 484 | { 485 | return GetEnumerator(); 486 | } 487 | 488 | public RhinoPageView[] GetPageViews() 489 | { 490 | return _tableFunc().GetPageViews(); 491 | } 492 | 493 | public RhinoView[] GetStandardRhinoViews() 494 | { 495 | return _tableFunc().GetStandardRhinoViews(); 496 | } 497 | 498 | public RhinoView[] GetViewList(bool includeStandardViews, bool includePageViews) 499 | { 500 | return _tableFunc().GetViewList(includeStandardViews, includePageViews); 501 | } 502 | 503 | public void Redraw() 504 | { 505 | if (_redraws) 506 | _tableFunc().Redraw(); 507 | } 508 | 509 | public void ThreeViewLayout(bool useMatchingViews) 510 | { 511 | _tableFunc().ThreeViewLayout(useMatchingViews); 512 | } 513 | } 514 | } -------------------------------------------------------------------------------- /Component/ComponentIOMarshal.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using GhPython.DocReplacement; 5 | using Grasshopper; 6 | using Grasshopper.Kernel; 7 | using Grasshopper.Kernel.Data; 8 | using Grasshopper.Kernel.Parameters; 9 | using Grasshopper.Kernel.Types; 10 | using Rhino.Geometry; 11 | 12 | namespace GhPython.Component 13 | { 14 | abstract class ComponentIOMarshal 15 | { 16 | public abstract object GetInput(IGH_DataAccess DA, int i); 17 | public abstract void SetOutput(object o, IGH_DataAccess DA, int index); 18 | } 19 | 20 | sealed class NewComponentIOMarshal : ComponentIOMarshal 21 | { 22 | private readonly ZuiPythonComponent m_component; 23 | private readonly CustomTable m_objectTable; 24 | private readonly GrasshopperDocument m_document; 25 | 26 | public NewComponentIOMarshal(GrasshopperDocument document, ZuiPythonComponent component) 27 | { 28 | m_document = document; 29 | m_objectTable = m_document.Objects; 30 | m_component = component; 31 | } 32 | 33 | #region Inputs 34 | 35 | public override object GetInput(IGH_DataAccess DA, int i) 36 | { 37 | var input = (Param_ScriptVariable) m_component.Params.Input[i]; 38 | bool addIntoGhDoc = input.TypeHint is GhDocGuidHint; 39 | 40 | object o; 41 | switch (input.Access) 42 | { 43 | case GH_ParamAccess.item: 44 | o = GetItemFromParameter(DA, i, addIntoGhDoc); 45 | break; 46 | 47 | case GH_ParamAccess.list: 48 | o = GetListFromParameter(DA, i, addIntoGhDoc); 49 | break; 50 | 51 | case GH_ParamAccess.tree: 52 | o = GetTreeFromParameter(DA, i, addIntoGhDoc); 53 | break; 54 | 55 | default: 56 | throw new ApplicationException("Wrong parameter in variable access type"); 57 | } 58 | 59 | return o; 60 | } 61 | 62 | 63 | private object GetItemFromParameter(IGH_DataAccess DA, int index, bool addIntoGhDoc) 64 | { 65 | IGH_Goo destination = null; 66 | DA.GetData(index, ref destination); 67 | var toReturn = this.TypeCast(destination, index); 68 | 69 | DocumentSingle(ref toReturn, addIntoGhDoc); 70 | 71 | return toReturn; 72 | } 73 | 74 | private object GetListFromParameter(IGH_DataAccess DA, int index, bool addIntoGhDoc) 75 | { 76 | List list2 = new List(); 77 | DA.GetDataList(index, list2); 78 | IGH_TypeHint typeHint = ((Param_ScriptVariable) m_component.Params.Input[index]).TypeHint; 79 | var t = Type.GetType("IronPython.Runtime.List,IronPython"); 80 | IList list = Activator.CreateInstance(t) as IList; 81 | 82 | if (list != null) 83 | { 84 | for (int i = 0; i < list2.Count; i++) 85 | { 86 | object cast = this.TypeCast(list2[i], typeHint); 87 | DocumentSingle(ref cast, addIntoGhDoc); 88 | list.Add(cast); 89 | } 90 | } 91 | 92 | return list; 93 | } 94 | 95 | private object GetTreeFromParameter(IGH_DataAccess DA, int index, bool addIntoGhDoc) 96 | { 97 | GH_Structure structure; 98 | DA.GetDataTree(index, out structure); 99 | IGH_TypeHint typeHint = ((Param_ScriptVariable) m_component.Params.Input[index]).TypeHint; 100 | var tree = new DataTree(); 101 | 102 | for (int i = 0; i < structure.PathCount; i++) 103 | { 104 | GH_Path path = structure.get_Path(i); 105 | List list = structure.Branches[i]; 106 | List data = new List(); 107 | 108 | for (int j = 0; j < list.Count; j++) 109 | { 110 | object cast = this.TypeCast(list[j], typeHint); 111 | DocumentSingle(ref cast, addIntoGhDoc); 112 | 113 | data.Add(cast); 114 | } 115 | tree.AddRange(data, path); 116 | } 117 | return tree; 118 | } 119 | 120 | private object TypeCast(IGH_Goo data, int index) 121 | { 122 | Param_ScriptVariable variable = (Param_ScriptVariable) m_component.Params.Input[index]; 123 | return this.TypeCast(data, variable.TypeHint); 124 | } 125 | 126 | private object TypeCast(IGH_Goo data, IGH_TypeHint hint) 127 | { 128 | if (data == null) 129 | { 130 | return null; 131 | } 132 | if (hint == null) 133 | { 134 | return data.ScriptVariable(); 135 | } 136 | object objectValue = data.ScriptVariable(); 137 | object target; 138 | hint.Cast(objectValue, out target); 139 | return target; 140 | } 141 | 142 | public void DocumentSingle(ref object input, bool addIntoGhDoc) 143 | { 144 | if (addIntoGhDoc) 145 | { 146 | if (input is GeometryBase) 147 | { 148 | input = m_objectTable.__InternalAdd(input as dynamic); 149 | } 150 | else if (input is Point3d) 151 | { 152 | input = m_objectTable.AddPoint((Point3d) input); 153 | } 154 | } 155 | } 156 | 157 | #endregion 158 | 159 | 160 | #region Outputs 161 | 162 | public override void SetOutput(object o, IGH_DataAccess DA, int index) 163 | { 164 | if (o == null) 165 | return; 166 | 167 | if (o is GrasshopperDocument) 168 | { 169 | var ogh = o as GrasshopperDocument; 170 | DA.SetDataList(index, ogh.Objects.Geometries); 171 | ogh.Objects.Clear(); 172 | } 173 | else if (o is string) //string is IEnumerable, so we need to check first 174 | { 175 | DA.SetData(index, o); 176 | } 177 | else if (o is IEnumerable) 178 | { 179 | o = GeometryList(o as IEnumerable); 180 | DA.SetDataList(index, o as IEnumerable); 181 | } 182 | else if (o is IGH_DataTree) 183 | { 184 | try 185 | { 186 | o = (this as dynamic).GeometryTree(o as dynamic); 187 | } 188 | catch (Exception ex) 189 | { 190 | Rhino.Runtime.HostUtils.ExceptionReport(ex); 191 | } 192 | DA.SetDataTree(index, o as IGH_DataTree); 193 | } 194 | else if (o is System.Numerics.Complex) 195 | { 196 | // 8 August 2012 (S. Baer) - https://github.com/mcneel/ghpython/issues/17 197 | // Grasshopper doesn't internally support System.Numerics.Complex right now 198 | // and uses a built-in complex data structure. Convert to GH complex when 199 | // we run into System.Numeric.Complex 200 | System.Numerics.Complex cplx = (System.Numerics.Complex)o; 201 | DA.SetData(index, new Complex(cplx.Real, cplx.Imaginary)); 202 | } 203 | else 204 | { 205 | GeometrySingle(ref o); 206 | DA.SetData(index, o); 207 | } 208 | } 209 | 210 | private void GeometrySingle(ref object input) 211 | { 212 | if (input is Guid) 213 | { 214 | AttributedGeometry a = m_objectTable.Find((Guid) input); 215 | input = a.Geometry; 216 | } 217 | } 218 | 219 | private List GeometryList(IEnumerable output) 220 | { 221 | List newOutput = new List(); 222 | foreach (var o in output) 223 | { 224 | object toAdd = o; 225 | GeometrySingle(ref toAdd); 226 | newOutput.Add(toAdd); 227 | } 228 | return newOutput; 229 | } 230 | 231 | private IGH_DataTree GeometryTree(DataTree output) 232 | { 233 | DataTree newOutput = new DataTree(); 234 | for (int b = 0; b < output.BranchCount; b++) 235 | { 236 | var p = output.Path(b); 237 | var currentBranch = output.Branch(b); 238 | var newBranch = GeometryList(currentBranch); 239 | newOutput.AddRange(newBranch, p); 240 | } 241 | return newOutput; 242 | } 243 | 244 | #endregion 245 | } 246 | 247 | 248 | sealed class OldComponentIOMarshal : ComponentIOMarshal 249 | { 250 | private readonly dynamic _document; //GrasshopperDocument-like object 251 | private readonly dynamic _objectTable; //CustomTable-like object 252 | private readonly PythonComponent_OBSOLETE _component; 253 | 254 | 255 | public OldComponentIOMarshal(object document, PythonComponent_OBSOLETE component) 256 | { 257 | _document = document; 258 | _objectTable = _document.Objects; 259 | _component = component; 260 | } 261 | 262 | 263 | 264 | #region Inputs 265 | 266 | public override object GetInput(IGH_DataAccess DA, int i) 267 | { 268 | object o; 269 | switch (_component.Params.Input[i].Access) 270 | { 271 | case GH_ParamAccess.item: 272 | o = GetItemFromParameter(DA, i); 273 | break; 274 | 275 | case GH_ParamAccess.list: 276 | o = GetListFromParameter(DA, i); 277 | break; 278 | 279 | case GH_ParamAccess.tree: 280 | o = GetTreeFromParameter(DA, i); 281 | break; 282 | 283 | default: 284 | throw new ApplicationException("Wrong parameter in variable access type"); 285 | } 286 | 287 | return o; 288 | } 289 | 290 | 291 | private object GetItemFromParameter(IGH_DataAccess DA, int index) 292 | { 293 | IGH_Goo destination = null; 294 | DA.GetData(index, ref destination); 295 | var toReturn = this.TypeCast(destination, index); 296 | 297 | if (_component.DocStorageMode == DocStorage.AutomaticMarshal) 298 | DocumentSingle(ref toReturn); 299 | 300 | return toReturn; 301 | } 302 | 303 | private object GetListFromParameter(IGH_DataAccess DA, int index) 304 | { 305 | List list2 = new List(); 306 | DA.GetDataList(index, list2); 307 | IGH_TypeHint typeHint = ((Param_ScriptVariable) _component.Params.Input[index]).TypeHint; 308 | var t = Type.GetType("IronPython.Runtime.List,IronPython"); 309 | IList list = Activator.CreateInstance(t) as IList; 310 | 311 | if (_component.DocStorageMode != DocStorage.AutomaticMarshal) 312 | { 313 | for (int i = 0; i < list2.Count; i++) 314 | { 315 | list.Add(this.TypeCast(list2[i], typeHint)); 316 | } 317 | } 318 | else 319 | { 320 | for (int i = 0; i < list2.Count; i++) 321 | { 322 | object thisInput = this.TypeCast(list2[i], typeHint); 323 | DocumentSingle(ref thisInput); 324 | list.Add(thisInput); 325 | } 326 | } 327 | 328 | return list; 329 | } 330 | 331 | private object GetTreeFromParameter(IGH_DataAccess DA, int index) 332 | { 333 | GH_Structure structure; 334 | DA.GetDataTree(index, out structure); 335 | IGH_TypeHint typeHint = ((Param_ScriptVariable) _component.Params.Input[index]).TypeHint; 336 | var tree = new DataTree(); 337 | 338 | for (int i = 0; i < structure.PathCount; i++) 339 | { 340 | GH_Path path = structure.get_Path(i); 341 | List list = structure.Branches[i]; 342 | List data = new List(); 343 | 344 | for (int j = 0; j < list.Count; j++) 345 | { 346 | object cast = this.TypeCast(list[j], typeHint); 347 | 348 | if (_component.DocStorageMode == DocStorage.AutomaticMarshal) 349 | DocumentSingle(ref cast); 350 | 351 | data.Add(cast); 352 | } 353 | tree.AddRange(data, path); 354 | } 355 | return tree; 356 | } 357 | 358 | private object TypeCast(IGH_Goo data, int index) 359 | { 360 | Param_ScriptVariable variable = (Param_ScriptVariable) _component.Params.Input[index]; 361 | return this.TypeCast(data, variable.TypeHint); 362 | } 363 | 364 | private object TypeCast(IGH_Goo data, IGH_TypeHint hint) 365 | { 366 | if (data == null) 367 | { 368 | return null; 369 | } 370 | if (hint == null) 371 | { 372 | return data.ScriptVariable(); 373 | } 374 | object objectValue = data.ScriptVariable(); 375 | object target; 376 | hint.Cast(objectValue, out target); 377 | return target; 378 | } 379 | 380 | public void DocumentSingle(ref object input) 381 | { 382 | if (input is GeometryBase) 383 | { 384 | input = _objectTable.__InternalAdd(input as dynamic); 385 | } 386 | else if (input is Point3d) 387 | { 388 | input = _objectTable.__InternalAdd((Point3d) input); 389 | } 390 | } 391 | 392 | #endregion 393 | 394 | 395 | #region Outputs 396 | 397 | public override void SetOutput(object o, IGH_DataAccess DA, int index) 398 | { 399 | if (o == null) 400 | return; 401 | 402 | if (o is GrasshopperDocument) 403 | { 404 | var ogh = o as GrasshopperDocument; 405 | DA.SetDataList(index, ogh.Objects.Geometries); 406 | ogh.Objects.Clear(); 407 | } 408 | else if (o is string) //string is IEnumerable, so we need to check first 409 | { 410 | DA.SetData(index, o); 411 | } 412 | else if (o is IEnumerable) 413 | { 414 | if (_component.DocStorageMode == DocStorage.AutomaticMarshal) 415 | o = GeometryList(o as IEnumerable); 416 | DA.SetDataList(index, o as IEnumerable); 417 | } 418 | else if (o is IGH_DataTree) 419 | { 420 | if (_component.DocStorageMode == DocStorage.AutomaticMarshal) 421 | { 422 | try 423 | { 424 | o = (this as dynamic).GeometryTree(o as dynamic); 425 | } 426 | catch (Exception ex) 427 | { 428 | Rhino.Runtime.HostUtils.ExceptionReport(ex); 429 | } 430 | } 431 | DA.SetDataTree(index, o as IGH_DataTree); 432 | } 433 | else 434 | { 435 | if (_component.DocStorageMode == DocStorage.AutomaticMarshal) 436 | { 437 | GeometrySingle(ref o); 438 | } 439 | DA.SetData(index, o); 440 | } 441 | } 442 | 443 | private void GeometrySingle(ref object input) 444 | { 445 | if (input is Guid) 446 | { 447 | dynamic o = _objectTable.Find((Guid) input); 448 | if (o != null) 449 | { 450 | input = o.Geometry; 451 | } 452 | } 453 | } 454 | 455 | private List GeometryList(IEnumerable output) 456 | { 457 | List newOutput = new List(); 458 | foreach (var o in output) 459 | { 460 | object toAdd = o; 461 | GeometrySingle(ref toAdd); 462 | newOutput.Add(toAdd); 463 | } 464 | return newOutput; 465 | } 466 | 467 | private IGH_DataTree GeometryTree(DataTree output) 468 | { 469 | DataTree newOutput = new DataTree(); 470 | for (int b = 0; b < output.BranchCount; b++) 471 | { 472 | var p = output.Path(b); 473 | var currentBranch = output.Branch(b); 474 | var newBranch = GeometryList(currentBranch); 475 | newOutput.AddRange(newBranch, p); 476 | } 477 | return newOutput; 478 | } 479 | 480 | #endregion 481 | } 482 | } -------------------------------------------------------------------------------- /Forms/PythonScriptForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Diagnostics; 5 | using System.Drawing; 6 | using System.IO; 7 | using System.Reflection; 8 | using System.Text; 9 | using System.Windows.Forms; 10 | using GhPython.Component; 11 | using GhPython.Properties; 12 | using Grasshopper.GUI.HTML; 13 | using Grasshopper.Kernel; 14 | using Grasshopper.Kernel.Types; 15 | 16 | namespace GhPython.Forms 17 | { 18 | public partial class PythonScriptForm : Form 19 | { 20 | internal readonly Control m_texteditor; 21 | bool _showClosePrompt = true; 22 | string m_previous_script = null; 23 | 24 | /// 25 | /// The linked component. This field might be null. 26 | /// 27 | ScriptingAncestorComponent _component; 28 | 29 | // keep default constructor around to not "confuse" Visual Studio's designer 30 | public PythonScriptForm() 31 | : this(null) 32 | { 33 | } 34 | public PythonScriptForm(ScriptingAncestorComponent linkedComponent) 35 | { 36 | InitializeComponent(); 37 | 38 | _component = linkedComponent; 39 | 40 | if (_component != null) 41 | { 42 | m_texteditor = _component.CreateEditorControl(OnPythonHelp); 43 | this.splitContainer.Panel1.Controls.Add(m_texteditor); 44 | m_texteditor.Dock = DockStyle.Fill; 45 | 46 | m_texteditor.Text = _component.Code; 47 | m_previous_script = m_texteditor.Text; 48 | } 49 | 50 | versionLabel.Text = Assembly.GetExecutingAssembly().GetName().Version.ToString(); 51 | } 52 | 53 | private static bool IsOnScreen(Point pt) 54 | { 55 | foreach (var screen in Screen.AllScreens) 56 | if (screen.WorkingArea.Contains(pt)) 57 | return true; 58 | 59 | return false; 60 | } 61 | 62 | private void PythonScriptForm_Load(object sender, EventArgs e) 63 | { 64 | try 65 | { 66 | KeyDown += ScriptForm_KeyDown; 67 | HelpRequested += rhinoscriptsyntaxHelp; 68 | Move += PythonScriptForm_MoveResize; 69 | Resize += PythonScriptForm_MoveResize; 70 | Grasshopper.Instances.DocumentEditor.Move += PythonScriptForm_MoveResize; 71 | 72 | if (_component.DefaultEditorLocation != null && IsOnScreen(_component.DefaultEditorLocation.Value)) 73 | Location = _component.DefaultEditorLocation.Value; 74 | 75 | if (_component.DefaultEditorSize != Size.Empty) 76 | Size = _component.DefaultEditorSize; 77 | } 78 | catch (Exception ex) 79 | { 80 | LastHandleException(ex); 81 | } 82 | } 83 | 84 | void OnPythonHelp(string str) 85 | { 86 | richTextBox1.Text = str; 87 | } 88 | 89 | Dictionary _handlers; 90 | 91 | void ScriptForm_KeyDown(object sender, KeyEventArgs e) 92 | { 93 | if (m_texteditor == null) 94 | return; 95 | // 22 April 2011 - S. Baer 96 | // I realize this is very "hacky", but it will keep 97 | // things working until I move this logic into the control itself 98 | var mi = m_texteditor.GetType().GetMethod("ProcessKeyDown"); 99 | if (mi != null) 100 | mi.Invoke(m_texteditor, new object[] { e }); 101 | 102 | // 30 May 2012 - G. Piacentino 103 | // This is here for the same reason as the above: no win message pump. 104 | if (_handlers == null) 105 | { 106 | _handlers = new Dictionary { 107 | { Keys.Control | Keys.E, exportAs_Click }, 108 | { Keys.Control | Keys.I, importFrom_Click }, 109 | { Keys.F5, applyButton_Click }, 110 | { Keys.Control | Keys.F5, okButton_Click }, 111 | }; 112 | } 113 | 114 | if (_handlers.ContainsKey(e.KeyData)) 115 | _handlers[e.KeyData](sender, e); 116 | } 117 | 118 | void PythonScriptForm_MoveResize(object sender, EventArgs e) 119 | { 120 | if (_component == null) return; 121 | 122 | _component.OnDisplayExpired(true); 123 | } 124 | 125 | private void okButton_Click(object sender, EventArgs e) 126 | { 127 | try 128 | { 129 | SetDefinitionValue(true, true); 130 | } 131 | catch (Exception ex) 132 | { 133 | LastHandleException(ex); 134 | } 135 | } 136 | 137 | private void cancelButton_Click(object sender, EventArgs e) 138 | { 139 | try 140 | { 141 | Close(); 142 | } 143 | catch (Exception ex) 144 | { 145 | LastHandleException(ex); 146 | } 147 | } 148 | 149 | private void applyButton_Click(object sender, EventArgs e) 150 | { 151 | try 152 | { 153 | SetDefinitionValue(false, true); 154 | } 155 | catch (Exception ex) 156 | { 157 | LastHandleException(ex); 158 | } 159 | } 160 | 161 | private void SetDefinitionValue(bool close, bool expire) 162 | { 163 | if (_component != null) 164 | { 165 | var codeInput = _component.CodeInputParam; 166 | 167 | if (codeInput != null) 168 | { 169 | if (_component.IsCodeInputLinked()) 170 | { 171 | const string msg = "There is dynamic inherited input that overrides this components behaviour.\nPlease unlink the first input to see the result."; 172 | if (MessageBox.Show(msg, "Rhino.Python", MessageBoxButtons.OKCancel) == DialogResult.Cancel) 173 | return; 174 | } 175 | 176 | GH_Document ghd = _component.OnPingDocument(); 177 | if (ghd != null) 178 | ghd.UndoServer.PushUndoRecord("Python code changed", 179 | new Grasshopper.Kernel.Undo.Actions.GH_GenericObjectAction(codeInput)); 180 | 181 | codeInput.PersistentData.Clear(); 182 | string newCode = m_texteditor.Text; 183 | 184 | if (!string.IsNullOrEmpty(newCode)) 185 | { 186 | codeInput.SetPersistentData(new GH_String(newCode)); 187 | m_previous_script = newCode; 188 | } 189 | } 190 | else 191 | { 192 | GH_Document ghd = _component.OnPingDocument(); 193 | if (ghd != null) 194 | ghd.UndoServer.PushUndoRecord("Python code changed", 195 | new Grasshopper.Kernel.Undo.Actions.GH_GenericObjectAction(_component)); 196 | 197 | _component.Code = m_texteditor.Text; 198 | m_previous_script = m_texteditor.Text; 199 | } 200 | 201 | if (expire) 202 | _component.ExpireSolution(true); 203 | 204 | if (close) 205 | { 206 | _showClosePrompt = false; 207 | Close(); 208 | } 209 | } 210 | } 211 | 212 | public void HelpText(string input) 213 | { 214 | richTextBox1.Text = input; 215 | } 216 | 217 | protected override void OnClosing(CancelEventArgs e) 218 | { 219 | try 220 | { 221 | var textHasChanged = m_previous_script != m_texteditor.Text; 222 | 223 | if (_showClosePrompt && textHasChanged) 224 | { 225 | var result = MessageBox.Show("Do you want to apply before closing?", 226 | "Rhino.Python closing", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question); 227 | 228 | if (result == DialogResult.Yes) 229 | { 230 | SetDefinitionValue(false, true); 231 | } 232 | else if (result == DialogResult.Cancel) 233 | { 234 | e.Cancel = true; 235 | } 236 | } 237 | } 238 | catch (Exception ex) 239 | { 240 | LastHandleException(ex); 241 | } 242 | 243 | if (!e.Cancel) 244 | { 245 | if (_component != null) 246 | { 247 | var attributes = _component.Attributes; 248 | 249 | if (attributes != null) 250 | { 251 | attributes.DisableLinkedEditor(false); 252 | } 253 | 254 | //we need to remove origin hinting 255 | _component.OnDisplayExpired(true); 256 | 257 | //store last location 258 | _component.DefaultEditorLocation = Location; 259 | _component.DefaultEditorSize = (WindowState == FormWindowState.Normal) ? Size : RestoreBounds.Size; 260 | 261 | _component = null; 262 | } 263 | 264 | Grasshopper.Instances.DocumentEditor.Move -= PythonScriptForm_MoveResize; 265 | } 266 | 267 | base.OnClosing(e); 268 | } 269 | 270 | public void Disable() 271 | { 272 | _showClosePrompt = false; 273 | 274 | SuspendLayout(); 275 | okButton.Enabled = false; 276 | testButton.Enabled = false; 277 | 278 | this.Text += " (disabled)"; 279 | mainStatusText.Text = "Window is disabled because linked component was deleted."; 280 | 281 | _component = null; 282 | ResumeLayout(true); 283 | } 284 | 285 | public static void LastHandleException(Exception ex) 286 | { 287 | if (ex != null) 288 | { 289 | Rhino.Runtime.HostUtils.ExceptionReport(ex); 290 | 291 | // for now let's keep also the previous route open... 292 | MessageBox.Show("An error occurred in the Python script window.\nPlease send a screenshot of this to giulio@mcneel.com.\nThanks.\n\n" + ex, 293 | "Error in Python script window (" + ex.GetType().Name + ")", MessageBoxButtons.OK); 294 | } 295 | } 296 | 297 | private void importFrom_Click(object sender, EventArgs e) 298 | { 299 | try 300 | { 301 | using (var fd = new OpenFileDialog()) 302 | { 303 | fd.Filter = "Python files (*.py)|*.py|All files (*.*)|*.*"; 304 | fd.FilterIndex = 0; 305 | 306 | if (fd.ShowDialog() == DialogResult.OK) 307 | { 308 | string text = File.ReadAllText(fd.FileName); 309 | m_texteditor.Text = text; 310 | } 311 | } 312 | } 313 | catch (Exception ex) 314 | { 315 | LastHandleException(ex); 316 | } 317 | } 318 | 319 | private void exportAs_Click(object sender, EventArgs e) 320 | { 321 | try 322 | { 323 | using (var fd = new SaveFileDialog()) 324 | { 325 | fd.Filter = "Python files (*.py)|*.py|All files (*.*)|*.*"; 326 | fd.FilterIndex = 0; 327 | 328 | if (fd.ShowDialog() == DialogResult.OK) 329 | { 330 | File.WriteAllText(fd.FileName, m_texteditor.Text, Encoding.UTF8); 331 | } 332 | } 333 | } 334 | catch (Exception ex) 335 | { 336 | LastHandleException(ex); 337 | } 338 | } 339 | 340 | private void rhinoPythonWebsiteToolStripMenuItem_Click(object sender, EventArgs e) 341 | { 342 | try 343 | { 344 | Process.Start("http://python.rhino3d.com/"); 345 | } 346 | catch (Exception ex) 347 | { 348 | LastHandleException(ex); 349 | } 350 | } 351 | 352 | private void grasshopperForumToolStripMenuItem_Click(object sender, EventArgs e) 353 | { 354 | try 355 | { 356 | Process.Start("http://www.grasshopper3d.com/forum/"); 357 | } 358 | catch (Exception ex) 359 | { 360 | LastHandleException(ex); 361 | } 362 | } 363 | 364 | private void pythonDocumentationToolStripMenuItem_Click(object sender, EventArgs e) 365 | { 366 | try 367 | { 368 | Process.Start("http://docs.python.org/"); 369 | } 370 | catch (Exception ex) 371 | { 372 | LastHandleException(ex); 373 | } 374 | } 375 | 376 | private void rhinoscriptsyntaxHelp(object sender, EventArgs e) 377 | { 378 | try 379 | { 380 | var py = Rhino.Runtime.PythonScript.Create(); 381 | var a = py.GetType().Assembly; 382 | string dir = Path.GetDirectoryName(a.Location); 383 | string filename = Path.Combine(dir, "RhinoIronPython.chm"); 384 | 385 | if (System.IO.File.Exists(filename)) 386 | { 387 | var topic = GetCurrentWord(); 388 | const HelpNavigator mode = HelpNavigator.KeywordIndex; 389 | System.Windows.Forms.Help.ShowHelp(this, filename); 390 | 391 | // 2011 Aug 22 Giulio Piacentino 392 | // A second call is necessary as the first one opens with correct focus, 393 | // but passing arguments opens a window that disappears when it is not focused 394 | System.Windows.Forms.Help.ShowHelp(this, filename, mode, topic); 395 | } 396 | else 397 | throw new FileNotFoundException(string.Format("The Python help file does not exist in {0}", filename)); 398 | } 399 | catch (Exception ex) 400 | { 401 | LastHandleException(ex); 402 | } 403 | } 404 | 405 | private string GetCurrentWord() 406 | { 407 | try 408 | { 409 | var t = m_texteditor as dynamic; 410 | var actTxtCtrl = t.ActiveTextAreaControl; 411 | var caret = actTxtCtrl.Caret; 412 | var pos = caret.Position; 413 | object doc = actTxtCtrl.Document; 414 | int line = pos.Line; 415 | var mi = doc.GetType().GetMethod("GetLineSegment", BindingFlags.Public | BindingFlags.Instance); 416 | var seg = mi.Invoke(doc, new object[] { line }) as dynamic; 417 | var word = seg.GetWord(pos.Column); 418 | 419 | if (word != null) 420 | { 421 | string text = word.Word; 422 | return text; 423 | } 424 | } 425 | catch (Exception ex) 426 | { 427 | LastHandleException(ex); 428 | } 429 | return string.Empty; 430 | } 431 | 432 | private void rhinoscriptsyntaxBasicsToolStripMenuItem_Click(object sender, EventArgs e) 433 | { 434 | SetSample(Resources.sampleScript); 435 | } 436 | 437 | private void rhinoCommonBasicsToolStripMenuItem_Click(object sender, EventArgs e) 438 | { 439 | SetSample(Resources.sampleCommon); 440 | } 441 | 442 | private void SetSample(string sample) 443 | { 444 | try 445 | { 446 | if (!string.IsNullOrWhiteSpace(m_texteditor.Text)) 447 | { 448 | var result = MessageBox.Show("Open the sample will remove all changes.", 449 | "Sample opening", MessageBoxButtons.OKCancel, MessageBoxIcon.Question); 450 | 451 | if (result != System.Windows.Forms.DialogResult.OK) 452 | return; 453 | } 454 | 455 | m_texteditor.Text = sample; 456 | } 457 | catch (Exception ex) 458 | { 459 | LastHandleException(ex); 460 | } 461 | } 462 | 463 | private void ghPythonGrasshopperHelpToolStripMenuItem_Click(object sender, EventArgs e) 464 | { 465 | try 466 | { 467 | var helpForm = new GH_HtmlHelpPopup(); 468 | if (!helpForm.LoadObject(_component)) return; 469 | helpForm.SetLocation(Cursor.Position); 470 | helpForm.Show(Grasshopper.Instances.DocumentEditor); 471 | } 472 | catch (Exception ex) 473 | { 474 | LastHandleException(ex); 475 | } 476 | } 477 | } 478 | } -------------------------------------------------------------------------------- /Forms/PythonScriptForm.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace GhPython.Forms 2 | { 3 | partial class PythonScriptForm 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(PythonScriptForm)); 32 | this.menuStrip = new System.Windows.Forms.MenuStrip(); 33 | this.fileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 34 | this.closeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 35 | this.testToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 36 | this.applyAndCloseToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 37 | this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator(); 38 | this.openToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 39 | this.saveToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 40 | this.helpToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 41 | this.ghPythonGrasshopperHelpToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 42 | this.rhinoscriptsyntaxHelpToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 43 | this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem(); 44 | this.rhinoscriptsyntaxBasicsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 45 | this.rhinoCommonBasicsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 46 | this.toolStripSeparator3 = new System.Windows.Forms.ToolStripSeparator(); 47 | this.rhinoPythonWebsiteToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 48 | this.grasshopperForumToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 49 | this.toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator(); 50 | this.pythonDocumentationToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 51 | this.statusStrip = new System.Windows.Forms.StatusStrip(); 52 | this.mainStatusText = new System.Windows.Forms.ToolStripStatusLabel(); 53 | this.versionLabel = new System.Windows.Forms.ToolStripStatusLabel(); 54 | this.okButton = new System.Windows.Forms.Button(); 55 | this.cancelButton = new System.Windows.Forms.Button(); 56 | this.testButton = new System.Windows.Forms.Button(); 57 | this.panel1 = new System.Windows.Forms.Panel(); 58 | this.richTextBox1 = new System.Windows.Forms.RichTextBox(); 59 | this.splitContainer = new System.Windows.Forms.SplitContainer(); 60 | this.menuStrip.SuspendLayout(); 61 | this.statusStrip.SuspendLayout(); 62 | this.panel1.SuspendLayout(); 63 | ((System.ComponentModel.ISupportInitialize)(this.splitContainer)).BeginInit(); 64 | this.splitContainer.Panel2.SuspendLayout(); 65 | this.splitContainer.SuspendLayout(); 66 | this.SuspendLayout(); 67 | // 68 | // menuStrip 69 | // 70 | this.menuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { 71 | this.fileToolStripMenuItem, 72 | this.helpToolStripMenuItem}); 73 | this.menuStrip.Location = new System.Drawing.Point(0, 0); 74 | this.menuStrip.Name = "menuStrip"; 75 | this.menuStrip.Size = new System.Drawing.Size(542, 24); 76 | this.menuStrip.TabIndex = 0; 77 | this.menuStrip.Text = "menuStrip1"; 78 | // 79 | // fileToolStripMenuItem 80 | // 81 | this.fileToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { 82 | this.closeToolStripMenuItem, 83 | this.testToolStripMenuItem, 84 | this.applyAndCloseToolStripMenuItem, 85 | this.toolStripSeparator1, 86 | this.openToolStripMenuItem, 87 | this.saveToolStripMenuItem}); 88 | this.fileToolStripMenuItem.Name = "fileToolStripMenuItem"; 89 | this.fileToolStripMenuItem.Size = new System.Drawing.Size(37, 20); 90 | this.fileToolStripMenuItem.Text = "&File"; 91 | // 92 | // closeToolStripMenuItem 93 | // 94 | this.closeToolStripMenuItem.Name = "closeToolStripMenuItem"; 95 | this.closeToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Alt | System.Windows.Forms.Keys.F4))); 96 | this.closeToolStripMenuItem.Size = new System.Drawing.Size(224, 22); 97 | this.closeToolStripMenuItem.Text = "&Close"; 98 | this.closeToolStripMenuItem.Click += new System.EventHandler(this.cancelButton_Click); 99 | // 100 | // testToolStripMenuItem 101 | // 102 | this.testToolStripMenuItem.Name = "testToolStripMenuItem"; 103 | this.testToolStripMenuItem.ShortcutKeys = System.Windows.Forms.Keys.F5; 104 | this.testToolStripMenuItem.Size = new System.Drawing.Size(224, 22); 105 | this.testToolStripMenuItem.Text = "&Test"; 106 | this.testToolStripMenuItem.Click += new System.EventHandler(this.applyButton_Click); 107 | // 108 | // applyAndCloseToolStripMenuItem 109 | // 110 | this.applyAndCloseToolStripMenuItem.Name = "applyAndCloseToolStripMenuItem"; 111 | this.applyAndCloseToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.F5))); 112 | this.applyAndCloseToolStripMenuItem.Size = new System.Drawing.Size(224, 22); 113 | this.applyAndCloseToolStripMenuItem.Text = "&OK (Test and Close)"; 114 | this.applyAndCloseToolStripMenuItem.Click += new System.EventHandler(this.okButton_Click); 115 | // 116 | // toolStripSeparator1 117 | // 118 | this.toolStripSeparator1.Name = "toolStripSeparator1"; 119 | this.toolStripSeparator1.Size = new System.Drawing.Size(221, 6); 120 | // 121 | // openToolStripMenuItem 122 | // 123 | this.openToolStripMenuItem.Name = "openToolStripMenuItem"; 124 | this.openToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.I))); 125 | this.openToolStripMenuItem.Size = new System.Drawing.Size(224, 22); 126 | this.openToolStripMenuItem.Text = "&Import From..."; 127 | this.openToolStripMenuItem.Click += new System.EventHandler(this.importFrom_Click); 128 | // 129 | // saveToolStripMenuItem 130 | // 131 | this.saveToolStripMenuItem.Name = "saveToolStripMenuItem"; 132 | this.saveToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.E))); 133 | this.saveToolStripMenuItem.Size = new System.Drawing.Size(224, 22); 134 | this.saveToolStripMenuItem.Text = "&Export As...."; 135 | this.saveToolStripMenuItem.Click += new System.EventHandler(this.exportAs_Click); 136 | // 137 | // helpToolStripMenuItem 138 | // 139 | this.helpToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { 140 | this.ghPythonGrasshopperHelpToolStripMenuItem, 141 | this.rhinoscriptsyntaxHelpToolStripMenuItem, 142 | this.toolStripMenuItem1, 143 | this.toolStripSeparator3, 144 | this.rhinoPythonWebsiteToolStripMenuItem, 145 | this.grasshopperForumToolStripMenuItem, 146 | this.toolStripSeparator2, 147 | this.pythonDocumentationToolStripMenuItem}); 148 | this.helpToolStripMenuItem.Name = "helpToolStripMenuItem"; 149 | this.helpToolStripMenuItem.Size = new System.Drawing.Size(44, 20); 150 | this.helpToolStripMenuItem.Text = "&Help"; 151 | // 152 | // ghPythonGrasshopperHelpToolStripMenuItem 153 | // 154 | this.ghPythonGrasshopperHelpToolStripMenuItem.Name = "ghPythonGrasshopperHelpToolStripMenuItem"; 155 | this.ghPythonGrasshopperHelpToolStripMenuItem.Size = new System.Drawing.Size(229, 22); 156 | this.ghPythonGrasshopperHelpToolStripMenuItem.Text = "GhPython Component Help"; 157 | this.ghPythonGrasshopperHelpToolStripMenuItem.Click += new System.EventHandler(this.ghPythonGrasshopperHelpToolStripMenuItem_Click); 158 | // 159 | // rhinoscriptsyntaxHelpToolStripMenuItem 160 | // 161 | this.rhinoscriptsyntaxHelpToolStripMenuItem.Name = "rhinoscriptsyntaxHelpToolStripMenuItem"; 162 | this.rhinoscriptsyntaxHelpToolStripMenuItem.ShortcutKeys = System.Windows.Forms.Keys.F1; 163 | this.rhinoscriptsyntaxHelpToolStripMenuItem.Size = new System.Drawing.Size(229, 22); 164 | this.rhinoscriptsyntaxHelpToolStripMenuItem.Text = "&Help for rhinoscriptsyntax"; 165 | this.rhinoscriptsyntaxHelpToolStripMenuItem.Click += new System.EventHandler(this.rhinoscriptsyntaxHelp); 166 | // 167 | // toolStripMenuItem1 168 | // 169 | this.toolStripMenuItem1.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { 170 | this.rhinoscriptsyntaxBasicsToolStripMenuItem, 171 | this.rhinoCommonBasicsToolStripMenuItem}); 172 | this.toolStripMenuItem1.Name = "toolStripMenuItem1"; 173 | this.toolStripMenuItem1.Size = new System.Drawing.Size(229, 22); 174 | this.toolStripMenuItem1.Text = "&Samples"; 175 | // 176 | // rhinoscriptsyntaxBasicsToolStripMenuItem 177 | // 178 | this.rhinoscriptsyntaxBasicsToolStripMenuItem.Name = "rhinoscriptsyntaxBasicsToolStripMenuItem"; 179 | this.rhinoscriptsyntaxBasicsToolStripMenuItem.Size = new System.Drawing.Size(199, 22); 180 | this.rhinoscriptsyntaxBasicsToolStripMenuItem.Text = "rhinoscriptsyntax basics"; 181 | this.rhinoscriptsyntaxBasicsToolStripMenuItem.Click += new System.EventHandler(this.rhinoscriptsyntaxBasicsToolStripMenuItem_Click); 182 | // 183 | // rhinoCommonBasicsToolStripMenuItem 184 | // 185 | this.rhinoCommonBasicsToolStripMenuItem.Name = "rhinoCommonBasicsToolStripMenuItem"; 186 | this.rhinoCommonBasicsToolStripMenuItem.Size = new System.Drawing.Size(199, 22); 187 | this.rhinoCommonBasicsToolStripMenuItem.Text = "RhinoCommon basics"; 188 | this.rhinoCommonBasicsToolStripMenuItem.Click += new System.EventHandler(this.rhinoCommonBasicsToolStripMenuItem_Click); 189 | // 190 | // toolStripSeparator3 191 | // 192 | this.toolStripSeparator3.Name = "toolStripSeparator3"; 193 | this.toolStripSeparator3.Size = new System.Drawing.Size(226, 6); 194 | // 195 | // rhinoPythonWebsiteToolStripMenuItem 196 | // 197 | this.rhinoPythonWebsiteToolStripMenuItem.Name = "rhinoPythonWebsiteToolStripMenuItem"; 198 | this.rhinoPythonWebsiteToolStripMenuItem.Size = new System.Drawing.Size(229, 22); 199 | this.rhinoPythonWebsiteToolStripMenuItem.Text = "&Rhino.Python Forum"; 200 | this.rhinoPythonWebsiteToolStripMenuItem.Click += new System.EventHandler(this.rhinoPythonWebsiteToolStripMenuItem_Click); 201 | // 202 | // grasshopperForumToolStripMenuItem 203 | // 204 | this.grasshopperForumToolStripMenuItem.Name = "grasshopperForumToolStripMenuItem"; 205 | this.grasshopperForumToolStripMenuItem.Size = new System.Drawing.Size(229, 22); 206 | this.grasshopperForumToolStripMenuItem.Text = "&Grasshopper Forum"; 207 | this.grasshopperForumToolStripMenuItem.Click += new System.EventHandler(this.grasshopperForumToolStripMenuItem_Click); 208 | // 209 | // toolStripSeparator2 210 | // 211 | this.toolStripSeparator2.Name = "toolStripSeparator2"; 212 | this.toolStripSeparator2.Size = new System.Drawing.Size(226, 6); 213 | // 214 | // pythonDocumentationToolStripMenuItem 215 | // 216 | this.pythonDocumentationToolStripMenuItem.Name = "pythonDocumentationToolStripMenuItem"; 217 | this.pythonDocumentationToolStripMenuItem.Size = new System.Drawing.Size(229, 22); 218 | this.pythonDocumentationToolStripMenuItem.Text = "&Python.org Documentation"; 219 | this.pythonDocumentationToolStripMenuItem.Click += new System.EventHandler(this.pythonDocumentationToolStripMenuItem_Click); 220 | // 221 | // statusStrip 222 | // 223 | this.statusStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { 224 | this.mainStatusText, 225 | this.versionLabel}); 226 | this.statusStrip.Location = new System.Drawing.Point(0, 524); 227 | this.statusStrip.Name = "statusStrip"; 228 | this.statusStrip.Size = new System.Drawing.Size(542, 22); 229 | this.statusStrip.TabIndex = 1; 230 | this.statusStrip.Text = "statusStrip1"; 231 | // 232 | // mainStatusText 233 | // 234 | this.mainStatusText.Name = "mainStatusText"; 235 | this.mainStatusText.Size = new System.Drawing.Size(450, 17); 236 | this.mainStatusText.Spring = true; 237 | this.mainStatusText.Text = "..."; 238 | this.mainStatusText.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; 239 | // 240 | // versionLabel 241 | // 242 | this.versionLabel.Alignment = System.Windows.Forms.ToolStripItemAlignment.Right; 243 | this.versionLabel.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text; 244 | this.versionLabel.Enabled = false; 245 | this.versionLabel.Name = "versionLabel"; 246 | this.versionLabel.Size = new System.Drawing.Size(46, 17); 247 | this.versionLabel.Text = "Version"; 248 | this.versionLabel.TextAlign = System.Drawing.ContentAlignment.MiddleRight; 249 | // 250 | // okButton 251 | // 252 | this.okButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); 253 | this.okButton.Location = new System.Drawing.Point(374, 6); 254 | this.okButton.Name = "okButton"; 255 | this.okButton.Size = new System.Drawing.Size(75, 23); 256 | this.okButton.TabIndex = 0; 257 | this.okButton.Text = "OK"; 258 | this.okButton.UseVisualStyleBackColor = true; 259 | this.okButton.Click += new System.EventHandler(this.okButton_Click); 260 | // 261 | // cancelButton 262 | // 263 | this.cancelButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); 264 | this.cancelButton.Location = new System.Drawing.Point(455, 6); 265 | this.cancelButton.Name = "cancelButton"; 266 | this.cancelButton.Size = new System.Drawing.Size(75, 23); 267 | this.cancelButton.TabIndex = 1; 268 | this.cancelButton.Text = "Close"; 269 | this.cancelButton.UseVisualStyleBackColor = true; 270 | this.cancelButton.Click += new System.EventHandler(this.cancelButton_Click); 271 | // 272 | // testButton 273 | // 274 | this.testButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); 275 | this.testButton.Location = new System.Drawing.Point(3, 6); 276 | this.testButton.Name = "testButton"; 277 | this.testButton.Size = new System.Drawing.Size(75, 23); 278 | this.testButton.TabIndex = 2; 279 | this.testButton.Text = "Test"; 280 | this.testButton.UseVisualStyleBackColor = true; 281 | this.testButton.Click += new System.EventHandler(this.applyButton_Click); 282 | // 283 | // panel1 284 | // 285 | this.panel1.Controls.Add(this.testButton); 286 | this.panel1.Controls.Add(this.cancelButton); 287 | this.panel1.Controls.Add(this.okButton); 288 | this.panel1.Dock = System.Windows.Forms.DockStyle.Bottom; 289 | this.panel1.Location = new System.Drawing.Point(0, 488); 290 | this.panel1.Name = "panel1"; 291 | this.panel1.Size = new System.Drawing.Size(542, 36); 292 | this.panel1.TabIndex = 2; 293 | // 294 | // richTextBox1 295 | // 296 | this.richTextBox1.BorderStyle = System.Windows.Forms.BorderStyle.None; 297 | this.richTextBox1.Dock = System.Windows.Forms.DockStyle.Fill; 298 | this.richTextBox1.Location = new System.Drawing.Point(0, 0); 299 | this.richTextBox1.Name = "richTextBox1"; 300 | this.richTextBox1.ReadOnly = true; 301 | this.richTextBox1.Size = new System.Drawing.Size(538, 126); 302 | this.richTextBox1.TabIndex = 1; 303 | this.richTextBox1.Text = ""; 304 | // 305 | // splitContainer 306 | // 307 | this.splitContainer.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D; 308 | this.splitContainer.Dock = System.Windows.Forms.DockStyle.Fill; 309 | this.splitContainer.Location = new System.Drawing.Point(0, 24); 310 | this.splitContainer.Name = "splitContainer"; 311 | this.splitContainer.Orientation = System.Windows.Forms.Orientation.Horizontal; 312 | this.splitContainer.Panel1MinSize = 200; 313 | // 314 | // splitContainer.Panel2 315 | // 316 | this.splitContainer.Panel2.Controls.Add(this.richTextBox1); 317 | this.splitContainer.Size = new System.Drawing.Size(542, 464); 318 | this.splitContainer.SplitterDistance = 330; 319 | this.splitContainer.TabIndex = 3; 320 | // 321 | // PythonScriptForm 322 | // 323 | this.AcceptButton = this.okButton; 324 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 325 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 326 | this.ClientSize = new System.Drawing.Size(542, 546); 327 | this.Controls.Add(this.splitContainer); 328 | this.Controls.Add(this.panel1); 329 | this.Controls.Add(this.statusStrip); 330 | this.Controls.Add(this.menuStrip); 331 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.SizableToolWindow; 332 | this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); 333 | this.KeyPreview = true; 334 | this.MainMenuStrip = this.menuStrip; 335 | this.MinimumSize = new System.Drawing.Size(300, 400); 336 | this.Name = "PythonScriptForm"; 337 | this.Text = "Grasshopper Python Script Editor"; 338 | this.Load += new System.EventHandler(this.PythonScriptForm_Load); 339 | this.menuStrip.ResumeLayout(false); 340 | this.menuStrip.PerformLayout(); 341 | this.statusStrip.ResumeLayout(false); 342 | this.statusStrip.PerformLayout(); 343 | this.panel1.ResumeLayout(false); 344 | this.splitContainer.Panel2.ResumeLayout(false); 345 | ((System.ComponentModel.ISupportInitialize)(this.splitContainer)).EndInit(); 346 | this.splitContainer.ResumeLayout(false); 347 | this.ResumeLayout(false); 348 | this.PerformLayout(); 349 | 350 | } 351 | 352 | #endregion 353 | 354 | private System.Windows.Forms.MenuStrip menuStrip; 355 | private System.Windows.Forms.ToolStripMenuItem fileToolStripMenuItem; 356 | private System.Windows.Forms.ToolStripMenuItem openToolStripMenuItem; 357 | private System.Windows.Forms.ToolStripMenuItem saveToolStripMenuItem; 358 | private System.Windows.Forms.ToolStripMenuItem helpToolStripMenuItem; 359 | private System.Windows.Forms.ToolStripMenuItem rhinoPythonWebsiteToolStripMenuItem; 360 | private System.Windows.Forms.ToolStripMenuItem grasshopperForumToolStripMenuItem; 361 | private System.Windows.Forms.ToolStripMenuItem pythonDocumentationToolStripMenuItem; 362 | private System.Windows.Forms.StatusStrip statusStrip; 363 | private System.Windows.Forms.ToolStripStatusLabel versionLabel; 364 | private System.Windows.Forms.Button okButton; 365 | private System.Windows.Forms.Button cancelButton; 366 | private System.Windows.Forms.Button testButton; 367 | private System.Windows.Forms.Panel panel1; 368 | private System.Windows.Forms.RichTextBox richTextBox1; 369 | private System.Windows.Forms.SplitContainer splitContainer; 370 | private System.Windows.Forms.ToolStripStatusLabel mainStatusText; 371 | private System.Windows.Forms.ToolStripSeparator toolStripSeparator1; 372 | private System.Windows.Forms.ToolStripSeparator toolStripSeparator2; 373 | private System.Windows.Forms.ToolStripMenuItem closeToolStripMenuItem; 374 | private System.Windows.Forms.ToolStripMenuItem rhinoscriptsyntaxHelpToolStripMenuItem; 375 | private System.Windows.Forms.ToolStripSeparator toolStripSeparator3; 376 | private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem1; 377 | private System.Windows.Forms.ToolStripMenuItem rhinoscriptsyntaxBasicsToolStripMenuItem; 378 | private System.Windows.Forms.ToolStripMenuItem rhinoCommonBasicsToolStripMenuItem; 379 | private System.Windows.Forms.ToolStripMenuItem testToolStripMenuItem; 380 | private System.Windows.Forms.ToolStripMenuItem applyAndCloseToolStripMenuItem; 381 | private System.Windows.Forms.ToolStripMenuItem ghPythonGrasshopperHelpToolStripMenuItem; 382 | } 383 | } --------------------------------------------------------------------------------