├── .github ├── dependabot.yml └── workflows │ └── build.yml ├── .gitignore ├── LICENSE ├── README.md ├── dynamo_linter └── Sample Linter │ ├── extra │ ├── .gitignore │ ├── LinterSettings.xml │ └── SampleLinter_ExtensionDefinition.xml │ └── pkg.json ├── dynamo_package └── Dynamo Samples │ ├── dyf │ └── .gitignore │ ├── extra │ ├── .gitignore │ └── SampleExtension_ExtensionDefinition.xml │ └── pkg.json ├── dynamo_viewExtension └── Sample View Extension │ ├── extra │ └── SampleViewExtension_ViewExtensionDefinition.xml │ └── pkg.json └── src ├── AssemblySharedInfo.cs ├── Config └── CS.props ├── Directory.Build.props ├── DynamoSamples.sln ├── SampleExtension ├── Extension.cs ├── Properties │ └── AssemblyInfo.cs ├── SampleExtension.csproj └── SampleExtension_ExtensionDefinition.xml ├── SampleIntegration ├── Hog.cs ├── Properties │ └── AssemblyInfo.cs ├── SampleIntegration.csproj ├── SampleIntegration.sln └── TracedHog.cs ├── SampleLibraryTests ├── HelloDynamoSystemTest.dyn ├── HelloDynamoSystemTests.cs ├── HelloDynamoZeroTouchTests.cs ├── Properties │ └── AssemblyInfo.cs ├── RectangleUnitsExample.dyn ├── SampleLibraryTests.csproj ├── Setup.cs ├── TestServices.dll.config └── ZeroTouchUnitsSystemTests.cs ├── SampleLibraryUI ├── Controls │ ├── ButtonControl.xaml │ ├── ButtonControl.xaml.cs │ ├── SliderControl.xaml │ └── SliderControl.xaml.cs ├── Examples │ ├── ButtonCustomNodeModel.cs │ ├── DropDown.cs │ ├── LocalizedCustomNodeModel.cs │ └── SliderCustomNodeModel.cs ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ ├── Resources.en-US.Designer.cs │ ├── Resources.en-US.resx │ ├── Resources.es-ES.resx │ └── Resources.resx └── SampleLibraryUI.csproj ├── SampleLibraryZeroTouch ├── Examples │ ├── BasicExample.cs │ ├── ColorExample.cs │ ├── PeriodicUpdateExample.cs │ ├── TraceExample.cs │ └── TransformableExample.cs ├── Properties │ └── AssemblyInfo.cs ├── SampleLibraryZeroTouch.csproj ├── Utils │ └── SampleUtilities.cs ├── app.config └── dyns │ └── testPeriodicTransform.dyn ├── SampleLinter ├── LinterSettings.cs ├── LinterSettings.xml ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ ├── Resources.en-US.resx │ ├── Resources.es-ES.resx │ └── Resources.resx ├── Rules │ ├── NoGroupsLinterRule.cs │ ├── SampleDropdownInputLinterRule.cs │ └── SampleSliderInputLinterRule.cs ├── SampleLinter.cs ├── SampleLinter.csproj └── SampleLinter_ExtensionDefinition.xml ├── SampleViewExtension ├── Properties │ └── AssemblyInfo.cs ├── SampleViewExtension.cs ├── SampleViewExtension.csproj ├── SampleViewExtension_ViewExtensionDefinition.xml ├── SampleWindow.xaml ├── SampleWindow.xaml.cs └── SampleWindowViewModel.cs ├── SampleZeroTouchUnits ├── RectangleExample.cs └── SampleZeroTouchUnits.csproj └── build.xml /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 2 | 3 | version: 2 4 | updates: 5 | - package-ecosystem: "github-actions" 6 | directory: ".github/workflows" 7 | schedule: 8 | interval: "weekly" 9 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | # Build SampleIntegration.sln and DynamoSamples.sln with .NET 8.0 2 | name: Build 3 | 4 | on: 5 | push: 6 | branches: 7 | - master 8 | pull_request: 9 | 10 | jobs: 11 | build: 12 | runs-on: windows-latest 13 | steps: 14 | - name: Checkout DynamoSamples Repo 15 | uses: actions/checkout@v4 16 | with: 17 | path: DynamoSamples 18 | repository: DynamoDS/DynamoSamples 19 | - name: Setup dotnet 20 | uses: actions/setup-dotnet@v4 21 | with: 22 | dotnet-version: '8.0.x' 23 | - name: Disable problem matcher 24 | run: echo "::remove-matcher owner=csc::" 25 | - name: Setup msbuild 26 | uses: microsoft/setup-msbuild@v2 27 | - name: Install dependencies for SampleIntegration 28 | run: | 29 | dotnet restore ${{ github.workspace }}\DynamoSamples\src\SampleIntegration\SampleIntegration.sln /p:Configuration=Release --runtime=win-x64 30 | - name: Build SampleIntegration 31 | run: | 32 | msbuild ${{ github.workspace }}\DynamoSamples\src\SampleIntegration\SampleIntegration.sln /p:Configuration=Release 33 | - name: Look for Sample Integration 34 | run: | 35 | if (Test-Path -Path "${{ github.workspace }}\DynamoSamples\src\SampleIntegration\bin\Release\SampleIntegration.dll") { 36 | Write-Output "SampleIntegration.dll exists!" 37 | } else { 38 | Write-Error "SampleIntegration.dll was not found!" 39 | } 40 | - name: Install dependencies for DynamoSamples 41 | run: | 42 | dotnet restore ${{ github.workspace }}\DynamoSamples\src\DynamoSamples.sln /p:Configuration=Release --runtime=win-x64 43 | - name: Build DynamoSamples 44 | run: | 45 | msbuild ${{ github.workspace }}\DynamoSamples\src\DynamoSamples.sln /p:Configuration=Release 46 | - name: Look for Sample Packages 47 | run: | 48 | $paths = @( 49 | "${{ github.workspace }}\DynamoSamples\dynamo_linter\Sample Linter\bin\SampleLinter.dll", 50 | "${{ github.workspace }}\DynamoSamples\dynamo_package\Dynamo Samples\bin\SampleLibraryUI.dll", 51 | "${{ github.workspace }}\DynamoSamples\dynamo_package\Dynamo Samples\bin\SampleLibraryZeroTouch.dll", 52 | "${{ github.workspace }}\DynamoSamples\dynamo_package\Dynamo Samples\bin\SampleZeroTouchUnits.dll", 53 | "${{ github.workspace }}\DynamoSamples\dynamo_viewExtension\Sample View Extension\bin\SampleViewExtension.dll" 54 | ) 55 | 56 | foreach ($path in $paths) { 57 | if (Test-Path -Path $path) { 58 | Write-Output "$path exists!" 59 | } else { 60 | Write-Error "$path was not found!" 61 | } 62 | } 63 | - name: Get DynamoRuntime from s3 64 | run: | 65 | curl -o DynamoRuntime.zip https://downloads.dynamobuilds.com/DynamoCoreRuntime3.1.0.zip 66 | ls 67 | - name: Extract DynamoRuntime 68 | run: | 69 | 7z x DynamoRuntime.zip -o${{ github.workspace }}\DynamoSamples\src\SampleLibraryTests\bin\Release\DynamoRuntime 70 | 71 | - name: Run test with the dotnet CLI 72 | run: | 73 | dotnet test ${{ github.workspace }}\DynamoSamples\src\SampleLibraryTests -p:Configuration=Release --filter "TestCategory!=Failure&TestCategory!=NEEDS_GEOM_LIB" --logger "trx;LogFileName=results.trx" --results-directory ${{ github.workspace }}\DynamoSamples\TestResults 74 | - name: Upload build artifact 75 | uses: actions/upload-artifact@v4.3.3 76 | with: 77 | name: DynamoSamples 78 | path: ${{ github.workspace }}\DynamoSamples\dynamo_package 79 | retention-days: 7 80 | - name: Upload test artifact 81 | uses: actions/upload-artifact@v4.3.3 82 | with: 83 | name: TestResults 84 | path: ${{ github.workspace }}\DynamoSamples\TestResults 85 | retention-days: 1 86 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ################# 2 | ## Eclipse 3 | ################# 4 | 5 | *.pydevproject 6 | .project 7 | .metadata 8 | bin/ 9 | tmp/ 10 | *.tmp 11 | *.bak 12 | *.swp 13 | *~.nib 14 | local.properties 15 | .classpath 16 | .settings/ 17 | .loadpath 18 | 19 | # External tool builders 20 | .externalToolBuilders/ 21 | 22 | # Locally stored "Eclipse launch configurations" 23 | *.launch 24 | 25 | # CDT-specific 26 | .cproject 27 | 28 | # PDT-specific 29 | .buildpath 30 | 31 | 32 | ################# 33 | ## Visual Studio 34 | ################# 35 | 36 | ## Ignore Visual Studio temporary files, build results, and 37 | ## files generated by popular Visual Studio add-ons. 38 | 39 | # User-specific files 40 | *.suo 41 | *.user 42 | *.sln.docstates 43 | .vs 44 | 45 | # Build results 46 | 47 | [Dd]ebug/ 48 | [Rr]elease/ 49 | x64/ 50 | build/ 51 | [Bb]in/ 52 | [Oo]bj/ 53 | 54 | # MSTest test Results 55 | [Tt]est[Rr]esult*/ 56 | [Bb]uild[Ll]og.* 57 | 58 | *_i.c 59 | *_p.c 60 | *.ilk 61 | *.meta 62 | *.obj 63 | *.pch 64 | *.pdb 65 | *.pgc 66 | *.pgd 67 | *.rsp 68 | *.sbr 69 | *.tlb 70 | *.tli 71 | *.tlh 72 | *.tmp 73 | *.tmp_proj 74 | *.log 75 | *.vspscc 76 | *.vssscc 77 | .builds 78 | *.pidb 79 | *.log 80 | *.scc 81 | 82 | # Visual C++ cache files 83 | ipch/ 84 | *.aps 85 | *.ncb 86 | *.opensdf 87 | *.sdf 88 | *.cachefile 89 | 90 | # Visual Studio profiler 91 | *.psess 92 | *.vsp 93 | *.vspx 94 | 95 | # Guidance Automation Toolkit 96 | *.gpState 97 | 98 | # ReSharper is a .NET coding add-in 99 | _ReSharper*/ 100 | *.[Rr]e[Ss]harper 101 | 102 | # TeamCity is a build add-in 103 | _TeamCity* 104 | 105 | # DotCover is a Code Coverage Tool 106 | *.dotCover 107 | 108 | # NCrunch 109 | *.ncrunch* 110 | .*crunch*.local.xml 111 | 112 | # Installshield output folder 113 | [Ee]xpress/ 114 | 115 | # DocProject is a documentation generator add-in 116 | DocProject/buildhelp/ 117 | DocProject/Help/*.HxT 118 | DocProject/Help/*.HxC 119 | DocProject/Help/*.hhc 120 | DocProject/Help/*.hhk 121 | DocProject/Help/*.hhp 122 | DocProject/Help/Html2 123 | DocProject/Help/html 124 | 125 | # Click-Once directory 126 | publish/ 127 | 128 | # Publish Web Output 129 | *.Publish.xml 130 | *.pubxml 131 | *.publishproj 132 | 133 | # NuGet Packages Directory 134 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line 135 | #packages/ 136 | 137 | src/packages/ 138 | !src/packages/repositories.config 139 | 140 | # Windows Azure Build Output 141 | csx 142 | *.build.csdef 143 | 144 | # Windows Store app package directory 145 | AppPackages/ 146 | 147 | # Others 148 | sql/ 149 | *.Cache 150 | ClientBin/ 151 | [Ss]tyle[Cc]op.* 152 | ~$* 153 | *~ 154 | *.dbmdl 155 | *.[Pp]ublish.xml 156 | *.pfx 157 | *.publishsettings 158 | 159 | # RIA/Silverlight projects 160 | Generated_Code/ 161 | 162 | # Backup & report files from converting an old project file to a newer 163 | # Visual Studio version. Backup files are not needed, because we have git ;-) 164 | _UpgradeReport_Files/ 165 | Backup*/ 166 | UpgradeLog*.XML 167 | UpgradeLog*.htm 168 | 169 | # SQL Server files 170 | App_Data/*.mdf 171 | App_Data/*.ldf 172 | 173 | ############# 174 | ## Windows detritus 175 | ############# 176 | 177 | # Windows image file caches 178 | Thumbs.db 179 | ehthumbs.db 180 | 181 | # Folder config file 182 | Desktop.ini 183 | 184 | # Recycle Bin used on file shares 185 | $RECYCLE.BIN/ 186 | 187 | # Mac crap 188 | .DS_Store 189 | 190 | 191 | ############# 192 | ## Python 193 | ############# 194 | 195 | *.py[cod] 196 | 197 | # Packages 198 | *.egg 199 | *.egg-info 200 | dist/ 201 | build/ 202 | eggs/ 203 | parts/ 204 | var/ 205 | sdist/ 206 | develop-eggs/ 207 | .installed.cfg 208 | 209 | # Installer logs 210 | pip-log.txt 211 | 212 | # Unit test / coverage reports 213 | .coverage 214 | .tox 215 | 216 | #Translations 217 | *.mo 218 | 219 | #Mr Developer 220 | .mr.developer.cfg 221 | 222 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2024 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build](https://github.com/DynamoDS/DynamoSamples/actions/workflows/build.yml/badge.svg)](https://github.com/DynamoDS/DynamoSamples/actions/workflows/build.yml) 2 | 3 | ![Image](https://raw.github.com/ikeough/Dynamo/master/doc/distrib/Images/dynamo_logo_dark.png) 4 | 5 | # Dynamo Samples 6 | 7 | A collection of samples demonstrating how to develop libraries for Dynamo. 8 | 9 | These samples make use of the [Dynamo NuGet packages](https://www.nuget.org/packages?q=DynamoVisualProgramming). NuGet should take care of restoring these packages if they are not available on your system at build time. 10 | 11 | # Building the Samples 12 | 13 | ## Requirements 14 | 15 | - Visual Studio 2022 16 | - .NET8 17 | 18 | ## Instructions 19 | 20 | - Clone the repository. 21 | - Choose a branch: 22 | - The master branch of Dynamo Samples corresponds to the master branch of Dynamo. To build against a specific version, choose that version's branch or tag. i.e. 0.8.0, 0.9.0, etc. 23 | - Open `DynamoSamples.sln` with Visual Studio. 24 | - Build using the `Debug/Any CPU` configuration. 25 | - The `dynamo_package` folder at the root of the repository will now have the built libraries. The `Dynamo Samples` folder in that directory can be copied directly to your Dynamo packages directory:`C:\Users\\AppData\Roaming\Dynamo Core\\packages`. 26 | - To install the sample view extension the `SampleViewExtension\bin\debug` folder (or release) should contain 27 | - `SampleViewExtension.dll` which should be copied to your root Dynamo build location 28 | - `SampleViewExtension_ViewExtensionDefinition` which should be copied to the `viewExtensions` folder inside your root Dynamo build location 29 | - Run Dynamo. You should find `SampleLibraryUI` and `SampleLibraryZeroTouch` categories in your library and the `View` tab inside of Dynamo should now contain `Show View Extension Sample Window`. 30 | -------------------------------------------------------------------------------- /dynamo_linter/Sample Linter/extra/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DynamoDS/DynamoSamples/bc05df04c9ae2382ce14246a6dad1e7bafb8da16/dynamo_linter/Sample Linter/extra/.gitignore -------------------------------------------------------------------------------- /dynamo_linter/Sample Linter/extra/LinterSettings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 4 | -------------------------------------------------------------------------------- /dynamo_linter/Sample Linter/extra/SampleLinter_ExtensionDefinition.xml: -------------------------------------------------------------------------------- 1 |  2 | ..\bin\SampleLinter.dll 3 | SampleLinter.SampleLinter 4 | 5 | -------------------------------------------------------------------------------- /dynamo_linter/Sample Linter/pkg.json: -------------------------------------------------------------------------------- 1 | { 2 | "file_hash":null, 3 | "name":"Sample Linter Extension", 4 | "version":"2.0.1", 5 | "description":"Dynamo sample linter extension.", 6 | "group":"", 7 | "keywords":["dynamo","samples, view, extension, linter"], 8 | "dependencies":[], 9 | "license":"MIT", 10 | "contents":"", 11 | "engine_version":"2.0.1", 12 | "engine_metadata":"", 13 | "engine":"dynamo", 14 | "site_url": "http://dynamobim.org/", 15 | "repository_url": "https://github.com/DynamoDS/DynamoSamples", 16 | "node_libraries": [ ] 17 | } -------------------------------------------------------------------------------- /dynamo_package/Dynamo Samples/dyf/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DynamoDS/DynamoSamples/bc05df04c9ae2382ce14246a6dad1e7bafb8da16/dynamo_package/Dynamo Samples/dyf/.gitignore -------------------------------------------------------------------------------- /dynamo_package/Dynamo Samples/extra/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DynamoDS/DynamoSamples/bc05df04c9ae2382ce14246a6dad1e7bafb8da16/dynamo_package/Dynamo Samples/extra/.gitignore -------------------------------------------------------------------------------- /dynamo_package/Dynamo Samples/extra/SampleExtension_ExtensionDefinition.xml: -------------------------------------------------------------------------------- 1 |  2 | ..\bin\SampleExtension.dll 3 | SampleExtension.Extension 4 | 5 | -------------------------------------------------------------------------------- /dynamo_package/Dynamo Samples/pkg.json: -------------------------------------------------------------------------------- 1 | {"file_hash":null, 2 | "name":"Dynamo Samples", 3 | "version":"2.0.0", 4 | "description":"Dynamo code samples.", 5 | "group":"", 6 | "keywords":["dynamo","samples"], 7 | "dependencies":[], 8 | "license":"MIT", 9 | "contents":"", 10 | "engine_version":"2.0.0", 11 | "engine_metadata":"", 12 | "engine":"dynamo"} -------------------------------------------------------------------------------- /dynamo_viewExtension/Sample View Extension/extra/SampleViewExtension_ViewExtensionDefinition.xml: -------------------------------------------------------------------------------- 1 |  2 | ..\bin\SampleViewExtension.dll 3 | SampleViewExtension.SampleViewExtension 4 | 5 | -------------------------------------------------------------------------------- /dynamo_viewExtension/Sample View Extension/pkg.json: -------------------------------------------------------------------------------- 1 | { 2 | "file_hash":null, 3 | "name":"Sample View Extension", 4 | "version":"2.0.1", 5 | "description":"Dynamo sample view extension.", 6 | "group":"", 7 | "keywords":["dynamo","samples, view, extension, nodes"], 8 | "dependencies":[], 9 | "license":"MIT", 10 | "contents":"", 11 | "engine_version":"2.0.1", 12 | "engine_metadata":"", 13 | "engine":"dynamo", 14 | "site_url": "http://dynamobim.org/", 15 | "repository_url": "https://github.com/DynamoDS/DynamoSamples", 16 | "node_libraries": [ ] 17 | } -------------------------------------------------------------------------------- /src/AssemblySharedInfo.cs: -------------------------------------------------------------------------------- 1 |  2 | using System; 3 | using System.Reflection; 4 | using System.Resources; 5 | using System.Runtime.InteropServices; 6 | 7 | // General Information about an assembly is controlled through the following 8 | // set of attributes. Change these attribute values to modify the information 9 | // associated with an assembly. 10 | [assembly: AssemblyCompany("Autodesk, Inc")] 11 | [assembly: AssemblyProduct("Dynamo")] 12 | [assembly: AssemblyCopyright("Copyright © Autodesk, Inc 2015")] 13 | [assembly: AssemblyTrademark("")] 14 | 15 | //In order to begin building localizable applications, set 16 | //CultureYouAreCodingWith in your .csproj file 17 | //inside a . For example, if you are using US english 18 | //in your source files, set the to en-US. Then uncomment 19 | //the NeutralResourceLanguage attribute below. Update the "en-US" in 20 | //the line below to match the UICulture setting in the project file. 21 | 22 | [assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] 23 | 24 | // Make it easy to distinguish Debug and Release (i.e. Retail) builds; 25 | // for example, through the file properties window. 26 | #if DEBUG 27 | [assembly: AssemblyConfiguration("Debug")] 28 | [assembly: AssemblyDescription("Flavor=Debug")] // a.k.a. "Comments" 29 | #else 30 | [assembly: AssemblyConfiguration("Release")] 31 | [assembly: AssemblyDescription("Flavor=Release")] // a.k.a. "Comments" 32 | #endif 33 | 34 | [assembly: CLSCompliant(true)] 35 | 36 | // Setting ComVisible to false makes the types in this assembly not visible 37 | // to COM components. If you need to access a type in this assembly from 38 | // COM, set the ComVisible attribute to true on that type. 39 | [assembly: ComVisible(false)] 40 | 41 | // Note that the assembly version does not get incremented for every build 42 | // to avoid problems with assembly binding (or requiring a policy or 43 | // in the config file). 44 | // 45 | // The AssemblyFileVersionAttribute is incremented with every build in order 46 | // to distinguish one build from another. AssemblyFileVersion is specified 47 | // in AssemblyVersionInfo.cs so that it can be easily incremented by the 48 | // automated build process. 49 | [assembly: AssemblyVersion("0.8.2")] 50 | 51 | 52 | // By default, the "Product version" shown in the file properties window is 53 | // the same as the value specified for AssemblyFileVersionAttribute. 54 | // Set AssemblyInformationalVersionAttribute to be the same as 55 | // AssemblyVersionAttribute so that the "Product version" in the file 56 | // properties window matches the version displayed in the GAC shell extension. 57 | //[assembly: AssemblyInformationalVersion("1.0.0.0")] // a.k.a. "Product version" 58 | // Version information for an assembly consists of the following four values: 59 | // 60 | // Major Version 61 | // Minor Version 62 | // Build Number 63 | // Revision 64 | // 65 | // You can specify all the values or you can default the Build and Revision Numbers 66 | // by using the '*' as shown below: 67 | // [assembly: AssemblyVersion("1.0.*")] 68 | [assembly: AssemblyFileVersion("0.8.2")] 69 | -------------------------------------------------------------------------------- /src/Config/CS.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | Debug 4 | AnyCPU 5 | x64 6 | 512 7 | false 8 | false 9 | prompt 10 | 4 11 | false 12 | Library 13 | false 14 | None 15 | true 16 | false 17 | 18 | 19 | full 20 | 21 | 22 | true 23 | full 24 | false 25 | bin\Debug\ 26 | TRACE;DEBUG 27 | prompt 28 | 4 29 | false 30 | 31 | 32 | pdbonly 33 | true 34 | bin\Release\ 35 | TRACE 36 | prompt 37 | 4 38 | false 39 | 40 | 41 | -------------------------------------------------------------------------------- /src/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | $(MSBuildThisFileDirectory)\ 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/DynamoSamples.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.6.33815.320 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SampleLibraryTests", "SampleLibraryTests\SampleLibraryTests.csproj", "{933B8108-4E74-470A-86C7-4B7F633115B9}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SampleLibraryUI", "SampleLibraryUI\SampleLibraryUI.csproj", "{0A4B4EEA-8FAB-4AC8-90D4-27DBC5B0CF2A}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SampleLibraryZeroTouch", "SampleLibraryZeroTouch\SampleLibraryZeroTouch.csproj", "{BD13C4DC-9045-4E49-B637-B6182B0E3A7F}" 11 | EndProject 12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SampleViewExtension", "SampleViewExtension\SampleViewExtension.csproj", "{146EBF48-E7A0-4ABE-809D-D7F3059E4EE1}" 13 | EndProject 14 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SampleExtension", "SampleExtension\SampleExtension.csproj", "{8B27B070-8434-49C8-8D43-41A4AE53BC36}" 15 | EndProject 16 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SampleLinter", "SampleLinter\SampleLinter.csproj", "{5F559FDB-99B9-4F4A-9A91-C9EC94C771D8}" 17 | EndProject 18 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SampleZeroTouchUnits", "SampleZeroTouchUnits\SampleZeroTouchUnits.csproj", "{4F9ECB35-D321-482A-8ED4-CC8E9342AACE}" 19 | EndProject 20 | Global 21 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 22 | Debug|Any CPU = Debug|Any CPU 23 | Release|Any CPU = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 26 | {933B8108-4E74-470A-86C7-4B7F633115B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {933B8108-4E74-470A-86C7-4B7F633115B9}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {933B8108-4E74-470A-86C7-4B7F633115B9}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {933B8108-4E74-470A-86C7-4B7F633115B9}.Release|Any CPU.Build.0 = Release|Any CPU 30 | {0A4B4EEA-8FAB-4AC8-90D4-27DBC5B0CF2A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 31 | {0A4B4EEA-8FAB-4AC8-90D4-27DBC5B0CF2A}.Debug|Any CPU.Build.0 = Debug|Any CPU 32 | {0A4B4EEA-8FAB-4AC8-90D4-27DBC5B0CF2A}.Release|Any CPU.ActiveCfg = Release|Any CPU 33 | {0A4B4EEA-8FAB-4AC8-90D4-27DBC5B0CF2A}.Release|Any CPU.Build.0 = Release|Any CPU 34 | {BD13C4DC-9045-4E49-B637-B6182B0E3A7F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 35 | {BD13C4DC-9045-4E49-B637-B6182B0E3A7F}.Debug|Any CPU.Build.0 = Debug|Any CPU 36 | {BD13C4DC-9045-4E49-B637-B6182B0E3A7F}.Release|Any CPU.ActiveCfg = Release|Any CPU 37 | {BD13C4DC-9045-4E49-B637-B6182B0E3A7F}.Release|Any CPU.Build.0 = Release|Any CPU 38 | {146EBF48-E7A0-4ABE-809D-D7F3059E4EE1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 39 | {146EBF48-E7A0-4ABE-809D-D7F3059E4EE1}.Debug|Any CPU.Build.0 = Debug|Any CPU 40 | {146EBF48-E7A0-4ABE-809D-D7F3059E4EE1}.Release|Any CPU.ActiveCfg = Release|Any CPU 41 | {146EBF48-E7A0-4ABE-809D-D7F3059E4EE1}.Release|Any CPU.Build.0 = Release|Any CPU 42 | {8B27B070-8434-49C8-8D43-41A4AE53BC36}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 43 | {8B27B070-8434-49C8-8D43-41A4AE53BC36}.Debug|Any CPU.Build.0 = Debug|Any CPU 44 | {8B27B070-8434-49C8-8D43-41A4AE53BC36}.Release|Any CPU.ActiveCfg = Release|Any CPU 45 | {8B27B070-8434-49C8-8D43-41A4AE53BC36}.Release|Any CPU.Build.0 = Release|Any CPU 46 | {5F559FDB-99B9-4F4A-9A91-C9EC94C771D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 47 | {5F559FDB-99B9-4F4A-9A91-C9EC94C771D8}.Debug|Any CPU.Build.0 = Debug|Any CPU 48 | {5F559FDB-99B9-4F4A-9A91-C9EC94C771D8}.Release|Any CPU.ActiveCfg = Release|Any CPU 49 | {5F559FDB-99B9-4F4A-9A91-C9EC94C771D8}.Release|Any CPU.Build.0 = Release|Any CPU 50 | {4F9ECB35-D321-482A-8ED4-CC8E9342AACE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 51 | {4F9ECB35-D321-482A-8ED4-CC8E9342AACE}.Debug|Any CPU.Build.0 = Debug|Any CPU 52 | {4F9ECB35-D321-482A-8ED4-CC8E9342AACE}.Release|Any CPU.ActiveCfg = Release|Any CPU 53 | {4F9ECB35-D321-482A-8ED4-CC8E9342AACE}.Release|Any CPU.Build.0 = Release|Any CPU 54 | EndGlobalSection 55 | GlobalSection(SolutionProperties) = preSolution 56 | HideSolutionNode = FALSE 57 | EndGlobalSection 58 | EndGlobal 59 | -------------------------------------------------------------------------------- /src/SampleExtension/Extension.cs: -------------------------------------------------------------------------------- 1 | using Dynamo.Extensions; 2 | using Dynamo.Graph.Nodes; 3 | using Dynamo.Models; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Text; 8 | 9 | namespace SampleExtension 10 | { 11 | /// 12 | /// The Extension framework for Dynamo allows you to extend 13 | /// Dynamo by loading your own classes that can interact with Dynamo's API. 14 | /// An Extension has two components, an assembly containing your class and 15 | /// an xml manifest file telling Dynamo where to find your assembly. Extension 16 | /// manifests are loaded from the Dynamo/Extensions folder or from package/extra 17 | /// folders. 18 | /// 19 | /// This sample demonstrates a simple IExtension which tracks nodes added to the workspace. 20 | /// 21 | public class Extension : IExtension 22 | { 23 | public List nodes = new List(); 24 | public bool readyCalled = false; 25 | 26 | public string Name 27 | { 28 | get 29 | { 30 | return "testExtension"; 31 | } 32 | } 33 | 34 | public string UniqueId 35 | { 36 | get 37 | { 38 | return "49fee64a-4505-4f03-a6b6-0667a793f19a"; 39 | } 40 | } 41 | 42 | public void Dispose() 43 | { 44 | 45 | } 46 | /// 47 | /// Ready is called when the DynamoModel is finished being built, or when the extension is installed 48 | /// sometime after the DynamoModel is already built. ReadyParams provide access to references like the 49 | /// CurrentWorkspace. 50 | /// 51 | /// 52 | public void Ready(ReadyParams sp) 53 | { 54 | sp.CurrentWorkspaceModel.NodeAdded += CurrentWorkspaceModel_NodeAdded; 55 | this.readyCalled = true; 56 | } 57 | 58 | private void CurrentWorkspaceModel_NodeAdded(Dynamo.Graph.Nodes.NodeModel obj) 59 | { 60 | this.nodes.Add(obj); 61 | } 62 | 63 | public void Shutdown() 64 | { 65 | 66 | } 67 | 68 | public void Startup(StartupParams sp) 69 | { 70 | 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/SampleExtension/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("SampleExtension")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("SampleExtension")] 13 | [assembly: AssemblyCopyright("Copyright © 2018")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("8b27b070-8434-49c8-8d43-41a4ae53bc36")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /src/SampleExtension/SampleExtension.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | Debug 7 | SampleExtension 8 | SampleExtension 9 | net8.0 10 | 11 | 12 | true 13 | 14 | 15 | 16 | Always 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/SampleExtension/SampleExtension_ExtensionDefinition.xml: -------------------------------------------------------------------------------- 1 |  2 | ..\bin\SampleExtension.dll 3 | SampleExtension.Extension 4 | 5 | -------------------------------------------------------------------------------- /src/SampleIntegration/Hog.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | 7 | class HogManager 8 | { 9 | private static int hogID = 0; 10 | 11 | public static int GetNextUnusedID() 12 | { 13 | int next = hogID; 14 | hogID++; 15 | return next; 16 | } 17 | 18 | } 19 | 20 | public class Hog 21 | { 22 | 23 | public double X { get; set; } 24 | public double Y { get; set; } 25 | 26 | public int ID { get; private set; } 27 | 28 | private Hog(double x, double y) : this(x,y, HogManager.GetNextUnusedID()) 29 | { 30 | } 31 | 32 | private Hog(double x, double y, int id) 33 | { 34 | this.X = x; 35 | this.Y = y; 36 | this.ID = id; 37 | } 38 | 39 | public static Hog ByPoint(double x, double y) 40 | { 41 | return new Hog(x,y); 42 | } 43 | 44 | public override string ToString() 45 | { 46 | return String.Format("{0}: ({1}, {2})", ID, X, Y); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/SampleIntegration/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("SampleIntegration")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("SampleIntegration")] 13 | [assembly: AssemblyCopyright("Copyright © 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("9359ab8d-49a4-4ceb-ba22-264858d3a461")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /src/SampleIntegration/SampleIntegration.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | SampleIntegration 7 | SampleIntegration 8 | net8.0 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/SampleIntegration/SampleIntegration.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2012 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SampleIntegration", "SampleIntegration.csproj", "{5C06327E-B4AE-4909-AA0F-A0491A424BF0}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Any CPU = Debug|Any CPU 9 | Release|Any CPU = Release|Any CPU 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {5C06327E-B4AE-4909-AA0F-A0491A424BF0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 13 | {5C06327E-B4AE-4909-AA0F-A0491A424BF0}.Debug|Any CPU.Build.0 = Debug|Any CPU 14 | {5C06327E-B4AE-4909-AA0F-A0491A424BF0}.Release|Any CPU.ActiveCfg = Release|Any CPU 15 | {5C06327E-B4AE-4909-AA0F-A0491A424BF0}.Release|Any CPU.Build.0 = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /src/SampleIntegration/TracedHog.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Runtime.Serialization; 5 | using System.Text; 6 | using Dynamo.Events; 7 | using DynamoServices; 8 | using Newtonsoft.Json; 9 | 10 | class TracedHogManager 11 | { 12 | private static int hogID = 0; 13 | 14 | public static int GetNextUnusedID() 15 | { 16 | int next = hogID; 17 | hogID++; 18 | return next; 19 | } 20 | 21 | private static Dictionary hogDictionary = new Dictionary(); 22 | 23 | public static TracedHog GetHogByID(int id) 24 | { 25 | TracedHog ret; 26 | hogDictionary.TryGetValue(id, out ret); 27 | return ret; 28 | } 29 | 30 | public static void RegisterHogForID(int id, TracedHog hog) 31 | { 32 | if (hogDictionary.ContainsKey(id)) 33 | { 34 | hogDictionary[id] = hog; 35 | } 36 | else 37 | { 38 | hogDictionary.Add(id, hog); 39 | } 40 | 41 | } 42 | 43 | } 44 | 45 | [Serializable] 46 | public class HogID : ISerializable 47 | { 48 | public int IntID { get; set; } 49 | 50 | public void GetObjectData(SerializationInfo info, StreamingContext context) 51 | { 52 | info.AddValue("intID", IntID, typeof(int)); 53 | } 54 | 55 | public HogID() 56 | { 57 | IntID = int.MinValue; 58 | 59 | } 60 | 61 | /// 62 | /// Ctor used by the serialisation engine 63 | /// 64 | /// 65 | /// 66 | public HogID(SerializationInfo info, StreamingContext context) 67 | { 68 | IntID = (int)info.GetValue("intID", typeof(int)); 69 | 70 | } 71 | } 72 | 73 | public class TracedHog : IDisposable 74 | { 75 | //TODO(lukechurch): This really should have been moved into the attribute already 76 | private const string REVIT_TRACE_ID = "{0459D869-0C72-447F-96D8-08A7FB92214B}-REVIT"; 77 | 78 | public double X { get; set; } 79 | public double Y { get; set; } 80 | 81 | public int ID { get; private set; } 82 | 83 | private TracedHog(double x, double y) 84 | : this(x, y, TracedHogManager.GetNextUnusedID()) 85 | { 86 | } 87 | 88 | private TracedHog(double x, double y, int id) 89 | { 90 | 91 | this.X = x; 92 | this.Y = y; 93 | this.ID = id; 94 | 95 | TracedHogManager.RegisterHogForID(id, this); 96 | 97 | WorkspaceEvents.WorkspaceAdded += WorkspaceEventsWorkspaceAdded; 98 | } 99 | 100 | void WorkspaceEventsWorkspaceAdded(WorkspacesModificationEventArgs args) 101 | { 102 | // What does a hog do when a workspace is opened? 103 | } 104 | 105 | public static TracedHog ByPoint(double x, double y) 106 | { 107 | TracedHog tHog; 108 | 109 | HogID hid = JsonConvert.DeserializeObject(TraceUtils.GetTraceData(REVIT_TRACE_ID)); 110 | 111 | if (hid == null) 112 | { 113 | // Trace didn't give us a hog, it's a new one. 114 | tHog = new TracedHog(x, y); 115 | } 116 | else 117 | { 118 | tHog = TracedHogManager.GetHogByID(hid.IntID); 119 | } 120 | 121 | // Set the trace data on the return to be this hog. 122 | TraceUtils.SetTraceData(REVIT_TRACE_ID, JsonConvert.SerializeObject(new HogID { IntID = tHog.ID })); 123 | return tHog; 124 | } 125 | 126 | public override string ToString() 127 | { 128 | return String.Format("{0}: ({1}, {2})", ID, X, Y); 129 | } 130 | 131 | public void Dispose() 132 | { 133 | // Unhook the workspace event handler. 134 | WorkspaceEvents.WorkspaceAdded -= WorkspaceEventsWorkspaceAdded; 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /src/SampleLibraryTests/HelloDynamoSystemTest.dyn: -------------------------------------------------------------------------------- 1 | { 2 | "Uuid": "3c9d0464-8643-5ffe-96e5-ab1769818209", 3 | "IsCustomNode": false, 4 | "Description": "", 5 | "Name": "HelloDynamoSystemTest", 6 | "ElementResolver": { 7 | "ResolutionMap": {} 8 | }, 9 | "Inputs": [], 10 | "Outputs": [], 11 | "Nodes": [ 12 | { 13 | "ConcreteType": "CoreNodeModels.Watch, CoreNodeModels", 14 | "WatchWidth": 35.0, 15 | "WatchHeight": 38.0, 16 | "Id": "2c4cdf29f078497c86b8fed323f4b77d", 17 | "NodeType": "ExtensionNode", 18 | "Inputs": [ 19 | { 20 | "Id": "a249fef4a4ce43ed9fa47a4ace364c8c", 21 | "Name": "", 22 | "Description": "Node to show output from", 23 | "UsingDefaultValue": false, 24 | "Level": 2, 25 | "UseLevels": false, 26 | "KeepListStructure": false 27 | } 28 | ], 29 | "Outputs": [ 30 | { 31 | "Id": "6bb8cd0394254f268082f176f97a233a", 32 | "Name": "", 33 | "Description": "Node output", 34 | "UsingDefaultValue": false, 35 | "Level": 2, 36 | "UseLevels": false, 37 | "KeepListStructure": false 38 | } 39 | ], 40 | "Replication": "Disabled", 41 | "Description": "Visualizes a node's output" 42 | }, 43 | { 44 | "ConcreteType": "Dynamo.Graph.Nodes.ZeroTouch.DSFunction, DynamoCore", 45 | "Id": "4964a3edb14b46dd8e614d64fad42128", 46 | "NodeType": "FunctionNode", 47 | "Inputs": [ 48 | { 49 | "Id": "2e564722e153444292ce3cf2fd1ea4df", 50 | "Name": "x", 51 | "Description": "Integer value, double value or string\n\nvar[]..[]", 52 | "UsingDefaultValue": false, 53 | "Level": 2, 54 | "UseLevels": false, 55 | "KeepListStructure": false 56 | }, 57 | { 58 | "Id": "c878418229554a8081a2add69a669b4c", 59 | "Name": "y", 60 | "Description": "Integer value, double value or string\n\nvar[]..[]", 61 | "UsingDefaultValue": false, 62 | "Level": 2, 63 | "UseLevels": false, 64 | "KeepListStructure": false 65 | } 66 | ], 67 | "Outputs": [ 68 | { 69 | "Id": "f648d8c8b1b7407eb51174f21f2d4908", 70 | "Name": "var", 71 | "Description": "The sum of two input numbers, or the concatenation of two strings", 72 | "UsingDefaultValue": false, 73 | "Level": 2, 74 | "UseLevels": false, 75 | "KeepListStructure": false 76 | } 77 | ], 78 | "FunctionSignature": "+@var[]..[],var[]..[]", 79 | "Replication": "Auto", 80 | "Description": "Returns addition of x and y\n\n+ (x: var[]..[], y: var[]..[]): var[]..[]" 81 | }, 82 | { 83 | "ConcreteType": "CoreNodeModels.Input.DoubleInput, CoreNodeModels", 84 | "NumberType": "Double", 85 | "Id": "77af56fb6e37432485e008870d79cb40", 86 | "NodeType": "NumberInputNode", 87 | "Inputs": [], 88 | "Outputs": [ 89 | { 90 | "Id": "982234929f014a7dacf16d38836763a1", 91 | "Name": "", 92 | "Description": "Double", 93 | "UsingDefaultValue": false, 94 | "Level": 2, 95 | "UseLevels": false, 96 | "KeepListStructure": false 97 | } 98 | ], 99 | "Replication": "Disabled", 100 | "Description": "Creates a number", 101 | "InputValue": 21.0 102 | }, 103 | { 104 | "ConcreteType": "CoreNodeModels.Input.DoubleInput, CoreNodeModels", 105 | "NumberType": "Double", 106 | "Id": "a603bf1480404297bea85441d71645ed", 107 | "NodeType": "NumberInputNode", 108 | "Inputs": [], 109 | "Outputs": [ 110 | { 111 | "Id": "e57dc497431840b98db808aca08d846b", 112 | "Name": "", 113 | "Description": "Double", 114 | "UsingDefaultValue": false, 115 | "Level": 2, 116 | "UseLevels": false, 117 | "KeepListStructure": false 118 | } 119 | ], 120 | "Replication": "Disabled", 121 | "Description": "Creates a number", 122 | "InputValue": 21.0 123 | } 124 | ], 125 | "Connectors": [ 126 | { 127 | "Start": "f648d8c8b1b7407eb51174f21f2d4908", 128 | "End": "a249fef4a4ce43ed9fa47a4ace364c8c", 129 | "Id": "b47128bfe4304b74a01f7b8db90d2c34", 130 | "IsHidden": "False" 131 | }, 132 | { 133 | "Start": "982234929f014a7dacf16d38836763a1", 134 | "End": "2e564722e153444292ce3cf2fd1ea4df", 135 | "Id": "73b3eba3b10e4b1f86c836c5164e01e9", 136 | "IsHidden": "False" 137 | }, 138 | { 139 | "Start": "e57dc497431840b98db808aca08d846b", 140 | "End": "c878418229554a8081a2add69a669b4c", 141 | "Id": "0ebc660b634b4281814460827fd4fa78", 142 | "IsHidden": "False" 143 | } 144 | ], 145 | "Dependencies": [], 146 | "NodeLibraryDependencies": [], 147 | "EnableLegacyPolyCurveBehavior": null, 148 | "Thumbnail": null, 149 | "GraphDocumentationURL": null, 150 | "ExtensionWorkspaceData": [ 151 | { 152 | "ExtensionGuid": "28992e1d-abb9-417f-8b1b-05e053bee670", 153 | "Name": "Properties", 154 | "Version": "3.1", 155 | "Data": {} 156 | } 157 | ], 158 | "Author": "None provided", 159 | "Linting": { 160 | "activeLinter": "None", 161 | "activeLinterId": "7b75fb44-43fd-4631-a878-29f4d5d8399a", 162 | "warningCount": 0, 163 | "errorCount": 0 164 | }, 165 | "Bindings": [], 166 | "View": { 167 | "Dynamo": { 168 | "ScaleFactor": 1.0, 169 | "HasRunWithoutCrash": true, 170 | "IsVisibleInDynamoLibrary": true, 171 | "Version": "3.1.0.3755", 172 | "RunType": "Manual", 173 | "RunPeriod": "1000" 174 | }, 175 | "Camera": { 176 | "Name": "_Background Preview", 177 | "EyeX": -17.0, 178 | "EyeY": 24.0, 179 | "EyeZ": 50.0, 180 | "LookX": 12.0, 181 | "LookY": -13.0, 182 | "LookZ": -58.0, 183 | "UpX": 0.0, 184 | "UpY": 1.0, 185 | "UpZ": 0.0 186 | }, 187 | "ConnectorPins": [], 188 | "NodeViews": [ 189 | { 190 | "Id": "2c4cdf29f078497c86b8fed323f4b77d", 191 | "Name": "Watch", 192 | "IsSetAsInput": false, 193 | "IsSetAsOutput": false, 194 | "Excluded": false, 195 | "ShowGeometry": true, 196 | "X": 613.408069206988, 197 | "Y": 243.832684826672 198 | }, 199 | { 200 | "Id": "4964a3edb14b46dd8e614d64fad42128", 201 | "Name": "+", 202 | "IsSetAsInput": false, 203 | "IsSetAsOutput": false, 204 | "Excluded": false, 205 | "ShowGeometry": true, 206 | "X": 404.715400784895, 207 | "Y": 238.891755796865 208 | }, 209 | { 210 | "Id": "77af56fb6e37432485e008870d79cb40", 211 | "Name": "Number", 212 | "IsSetAsInput": false, 213 | "IsSetAsOutput": false, 214 | "Excluded": false, 215 | "ShowGeometry": true, 216 | "X": 159.40168436709547, 217 | "Y": 106.14571181066069 218 | }, 219 | { 220 | "Id": "a603bf1480404297bea85441d71645ed", 221 | "Name": "Number", 222 | "IsSetAsInput": false, 223 | "IsSetAsOutput": false, 224 | "Excluded": false, 225 | "ShowGeometry": true, 226 | "X": 157.2343691937667, 227 | "Y": 282.8144436335819 228 | } 229 | ], 230 | "Annotations": [], 231 | "X": 146.89726815586, 232 | "Y": 9.96610837046791, 233 | "Zoom": 1.05281788169755 234 | } 235 | } -------------------------------------------------------------------------------- /src/SampleLibraryTests/HelloDynamoSystemTests.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using SystemTestServices; 3 | 4 | using Autodesk.DesignScript.Runtime; 5 | using Dynamo.Graph.Nodes.ZeroTouch; 6 | using Dynamo.Tests; 7 | 8 | using NUnit.Framework; 9 | 10 | namespace SampleLibraryTests 11 | { 12 | /// 13 | /// HelloDynamoSystemTests is a test fixture that contains 14 | /// system tests for Dynamo. System tests test the entire 15 | /// Dynamo system including the UI. They do this by starting 16 | /// a session of Dynamo, then opening .dyn files, executing them 17 | /// and comparing the values returned from Dynamo with those 18 | /// stored on our test class. 19 | /// 20 | /// IMPORTANT! 21 | /// System tests have dependencies on Dynamo core dlls. In 22 | /// order for these tests to work, your test dll needs to be 23 | /// located in the Dynamo core directory. The project currently assumes 24 | /// that Dynamo is built in a directory adjacent to the DynamoSamples 25 | /// repository, so a relative path is set to the debug build folder for Dynamo. 26 | /// If your setup is different, then you will need to explicitly set the output path 27 | /// to your Dynamo installation directory. 28 | /// 29 | [TestFixture] 30 | [IsVisibleInDynamoLibrary(false)] 31 | public class HelloDynamoSystemTests : SystemTestBase 32 | { 33 | /// 34 | /// The GetLibrariesToPreload method can be overridden in your test 35 | /// suite to add libraries for preload. By default, SystemTestBase does 36 | /// not preload any libaries. This improves startup performance of Dynamo 37 | /// for testing, but may mean that your workflow will not operate as expected. 38 | /// Add the libaries that your workflow requires to the 'libraries' list. 39 | /// 40 | /// A list of Dynamo assemblies that will be loaded when Dynamo starts. 41 | protected override void GetLibrariesToPreload(List libraries) 42 | { 43 | // For example, if you wanted to load the geometry library, you 44 | // could uncomment the following line. 45 | 46 | //libraries.Add("ProtoGeometry.dll"); 47 | base.GetLibrariesToPreload(libraries); 48 | } 49 | 50 | // The RequiresSTA attribute is required by 51 | // NUNit to run tests that use the UI. 52 | [Test, Apartment(System.Threading.ApartmentState.STA)] 53 | public void HelloDynamoTest() 54 | { 55 | // HelloWorldSystemTest.dyn is a test .dyn file which 56 | // should be copied to the output directory, so it's available 57 | // for testing. You can also change this path to anywhere you 58 | // would like to get your test file from, but it has to be 59 | // a relative path from the dynamo core directory (the working directory). 60 | 61 | OpenAndRunDynamoDefinition(@".\HelloDynamoSystemTest.dyn"); 62 | 63 | // Ensure that the graph opened without any "dummy nodes". 64 | // Dummy nodes would appear if your graph had a node that 65 | // could not be found in the library. 66 | 67 | AssertNoDummyNodes(); 68 | 69 | // Get the first node of a certain type from the workspace. 70 | // DSFunction nodes are a type of node which wrap built-in functions 71 | // like the '+' function, which is what we're looking for. 72 | 73 | var addNode = Model.CurrentWorkspace.FirstNodeFromWorkspace(); 74 | Assert.NotNull(addNode); 75 | 76 | // Ensure that the value of that node after evaluation is 77 | // the value that we are looking for. 78 | Assert.AreEqual(addNode.GetValue(0, Model.EngineController).Data, 42); 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/SampleLibraryTests/HelloDynamoZeroTouchTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | using Autodesk.DesignScript.Geometry; 4 | using Autodesk.DesignScript.Runtime; 5 | 6 | using NUnit.Framework; 7 | 8 | using TestServices; 9 | 10 | namespace SampleLibraryTests 11 | { 12 | // -------------------------------------------------- 13 | // NOTES ON GEOMETRY TESTING: 14 | // 15 | // In order to use the Dynamo geometry library during 16 | // testing, the geometry library needs to be 17 | // initialized. If you inherit from the 18 | // GeometricTestBase class the initialization of the 19 | // geometry library will be handled for you. 20 | 21 | // In order to initialize the geometry library, Dynamo 22 | // needs to know where your base install of Dynamo is 23 | // located. Typically, a zero touch library doesn't 24 | // need to know anything about Dynamo. But, to 25 | // load the goemetry library we look in paths relative 26 | // to your core Dynamo installation to find binaries 27 | // that are required by the geometry library. To allow 28 | // you to build your library anywhere on your machine 29 | // we include a TestServices.dll.config file in the 30 | // output directory. You need to set the "value" 31 | // attribute in that config file to the base location 32 | // of Dynamo. 33 | 34 | // If you are making a library that does not utilize 35 | // Dynamo's geometry library, then you do not need to 36 | // inherit from GeometricTestBase, and you do not need 37 | // to supply a config file with the core Dynamo install 38 | // location. 39 | 40 | // Wiki => https://github.com/DynamoDS/Dynamo/wiki/Writing-Unit-Test-Libraries-for-Dynamo 41 | 42 | [TestFixture] 43 | [IsVisibleInDynamoLibrary(false)] 44 | class HelloDynamoZeroTouchTests : GeometricTestBase 45 | { 46 | [Test] 47 | [Category("NEEDS_GEOM_LIB")] 48 | public void PassingTest() 49 | { 50 | var myObject = Point.ByCoordinates(5, 5, 5); 51 | Assert.NotNull(myObject); 52 | } 53 | 54 | [Test] 55 | [Category("NEEDS_GEOM_LIB")] 56 | public void FailingTest() 57 | { 58 | var p1 = Point.ByCoordinates(0, 0, 0); 59 | var p2 = Point.ByCoordinates(0, 0, 0); 60 | Assert.Throws(()=>Line.ByStartPointEndPoint(p1,p2)); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/SampleLibraryTests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System.Reflection; 3 | using System.Runtime.InteropServices; 4 | using System.Threading; 5 | 6 | // General Information about an assembly is controlled through the following 7 | // set of attributes. Change these attribute values to modify the information 8 | // associated with an assembly. 9 | [assembly: AssemblyTitle("SampleLibraryTests")] 10 | [assembly: Guid("c3d8c6fc-62ad-4272-91a9-492be76577e5")] 11 | 12 | // The RequiresThread(ApartmentState.STA) attribute is required by 13 | // NUNit to run all tests, that use the UI, on the same thread. 14 | [assembly: RequiresThread(ApartmentState.STA)] -------------------------------------------------------------------------------- /src/SampleLibraryTests/SampleLibraryTests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | Debug 7 | SampleLibraryTests 8 | SampleLibraryTests 9 | 10 | net8.0-windows 11 | true 12 | 13 | 14 | 15 | PreserveNewest 16 | 17 | 18 | PreserveNewest 19 | 20 | 21 | Always 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/SampleLibraryTests/Setup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Configuration; 4 | using System.Globalization; 5 | using System.IO; 6 | using System.Reflection; 7 | using NUnit.Framework; 8 | 9 | 10 | [SetUpFixture] 11 | public class Setup 12 | { 13 | private string moduleRootFolder; 14 | List resolutionPaths; 15 | 16 | [OneTimeSetUp] 17 | public void RunBeforeAllTests() 18 | { 19 | var thisDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); 20 | var configPath = Path.Combine(thisDir, "TestServices.dll.config"); 21 | 22 | // Adjust the config file map because the config file 23 | // might not always be in the same directory as the dll. 24 | var map = new ExeConfigurationFileMap { ExeConfigFilename = configPath }; 25 | var config = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None); 26 | 27 | var element = config.AppSettings.Settings["DynamoBasePath"]; 28 | moduleRootFolder = element?.Value ?? string.Empty; 29 | 30 | if (string.IsNullOrEmpty(moduleRootFolder)) 31 | { 32 | throw new Exception("Missing DynamoBasePath in TestServices.dll.config. Please set the DynamoBasePath to a valid Dynamo bin folder."); 33 | } 34 | else if (!File.Exists(Path.Combine(moduleRootFolder, "DynamoCore.dll"))) 35 | { 36 | throw new Exception("Invalid DynamoBasePath in TestServices.dll.config. Please set the DynamoBasePath to a valid Dynamo bin folder."); 37 | } 38 | 39 | resolutionPaths = new List 40 | { 41 | // Search for nodes 42 | Path.Combine(moduleRootFolder, "nodes") 43 | }; 44 | AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve; ; 45 | } 46 | 47 | private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) 48 | { 49 | try 50 | { 51 | var targetAssemblyName = new AssemblyName(args.Name).Name + ".dll"; 52 | 53 | // First check the core path 54 | string assemblyPath = Path.Combine(moduleRootFolder, targetAssemblyName); 55 | if (File.Exists(assemblyPath)) 56 | { 57 | return Assembly.LoadFrom(assemblyPath); 58 | } 59 | 60 | // Then check all additional resolution paths 61 | foreach (var resolutionPath in resolutionPaths) 62 | { 63 | assemblyPath = Path.Combine(resolutionPath, targetAssemblyName); 64 | if (File.Exists(assemblyPath)) 65 | { 66 | return Assembly.LoadFrom(assemblyPath); 67 | } 68 | } 69 | 70 | return null; 71 | } 72 | catch (Exception ex) 73 | { 74 | throw new Exception(string.Format("There location of the assembly, " + 75 | "{0} could not be resolved for loading.", args.Name), ex); 76 | } 77 | } 78 | 79 | [OneTimeTearDown] 80 | public void RunAfterAllTests() 81 | { 82 | AppDomain.CurrentDomain.AssemblyResolve -= CurrentDomain_AssemblyResolve; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/SampleLibraryTests/TestServices.dll.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/SampleLibraryTests/ZeroTouchUnitsSystemTests.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using SystemTestServices; 3 | 4 | using Autodesk.DesignScript.Runtime; 5 | using Dynamo.Graph.Nodes.ZeroTouch; 6 | using Dynamo.Tests; 7 | 8 | using NUnit.Framework; 9 | 10 | namespace SampleLibraryTests 11 | { 12 | /// 13 | /// ZeroTouchUnitsSystemTests is a test fixture that contains 14 | /// system tests for Dynamo using Units APIs. System tests test the entire 15 | /// Dynamo system including the UI. They do this by starting 16 | /// a session of Dynamo, then opening .dyn files, executing them 17 | /// and comparing the values returned from Dynamo with those 18 | /// stored on our test class. 19 | /// 20 | /// IMPORTANT! 21 | /// System tests have dependencies on Dynamo core dlls. In 22 | /// order for these tests to work, your test dll needs to be 23 | /// located in the Dynamo core directory. The project currently assumes 24 | /// that Dynamo is built in a directory adjacent to the DynamoSamples 25 | /// repository, so a relative path is set to the debug build folder for Dynamo. 26 | /// If your setup is different, then you will need to explicitly set the output path 27 | /// to your Dynamo installation directory. 28 | /// 29 | [TestFixture] 30 | 31 | public class ZeroTouchUnitsSystemTests : SystemTestBase 32 | { 33 | protected override void GetLibrariesToPreload(List libraries) 34 | { 35 | libraries.Add("FunctionObject.ds"); 36 | libraries.Add("BuiltIn.ds"); 37 | libraries.Add("DSCoreNodes.dll"); 38 | libraries.Add("VMDataBridge.dll"); 39 | libraries.Add("DynamoConversions.dll"); 40 | libraries.Add("DynamoUnits.dll"); 41 | libraries.Add("DesignScriptBuiltin.dll"); 42 | libraries.Add("..\\..\\..\\..\\dynamo_package\\Dynamo Samples\\bin\\SampleZeroTouchUnits.dll"); 43 | base.GetLibrariesToPreload(libraries); 44 | } 45 | 46 | // The RequiresSTA attribute is required by 47 | // NUNit to run tests that use the UI. 48 | [Test, Apartment(System.Threading.ApartmentState.STA)] 49 | public void HelloRectangleUnitsTest() 50 | { 51 | // RectangleUnitsExample.dyn is a test .dyn file which 52 | // should be copied to the output directory, so it's available 53 | // for testing. You can also change this path to anywhere you 54 | // would like to get your test file from, but it has to be 55 | // a relative path from the dynamo core directory (the working directory). 56 | 57 | OpenAndRunDynamoDefinition(@".\RectangleUnitsExample.dyn"); 58 | 59 | // Ensure that the graph opened without any "dummy nodes". 60 | // Dummy nodes would appear if your graph had a node that 61 | // could not be found in the library. 62 | 63 | AssertNoDummyNodes(); 64 | 65 | // Get the nodes from the workspace. 66 | var out1 = Model.CurrentWorkspace.NodeFromWorkspace("{15b2e81d-84df-4a17-ae34-8ee982ab87d9}") as CoreNodeModels.Watch; 67 | var out2 = Model.CurrentWorkspace.NodeFromWorkspace("{77e2a5bb-3d46-4c56-94f4-44ea1e064deb}") as CoreNodeModels.Watch; 68 | var out3 = Model.CurrentWorkspace.NodeFromWorkspace("{bbb9d9f6-be8e-498e-8b9c-b8cae214c921}") as CoreNodeModels.Watch; 69 | Assert.NotNull(out1); 70 | Assert.NotNull(out2); 71 | Assert.NotNull(out3); 72 | 73 | // Ensure that the value of that node after evaluation is 74 | // the value that we are looking for. 75 | Assert.AreEqual(out1.CachedValue, 500); 76 | Assert.AreEqual(out2.CachedValue, 5); 77 | Assert.AreEqual(out3.CachedValue, "538.195520835486ft^2"); 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/SampleLibraryUI/Controls/ButtonControl.xaml: -------------------------------------------------------------------------------- 1 |  9 | 10 | 11 | 12 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/SampleLibraryUI/Controls/ButtonControl.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Controls; 2 | 3 | namespace SampleLibraryUI.Controls 4 | { 5 | /// 6 | /// Interaction logic for ButtonDynamoControl.xaml 7 | /// 8 | public partial class ButtonControl : UserControl 9 | { 10 | public ButtonControl() 11 | { 12 | InitializeComponent(); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/SampleLibraryUI/Controls/SliderControl.xaml: -------------------------------------------------------------------------------- 1 |  9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/SampleLibraryUI/Controls/SliderControl.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Controls; 2 | 3 | namespace SampleLibraryUI.Controls 4 | { 5 | /// 6 | /// Interaction logic for SliderControl.xaml 7 | /// 8 | public partial class SliderControl : UserControl 9 | { 10 | public SliderControl() 11 | { 12 | InitializeComponent(); 13 | } 14 | 15 | private void Slider_ValueChanged(object sender, System.Windows.RoutedPropertyChangedEventArgs e){ } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/SampleLibraryUI/Examples/DropDown.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using CoreNodeModels; 3 | using Dynamo.Graph.Nodes; 4 | using Dynamo.Utilities; 5 | using ProtoCore.AST.AssociativeAST; 6 | using Newtonsoft.Json; 7 | 8 | namespace SampleLibraryUI.Examples 9 | { 10 | [NodeName("Drop Down Example")] 11 | [NodeDescription("An example drop down node.")] 12 | [IsDesignScriptCompatible] 13 | public class DropDownExample : DSDropDownBase 14 | { 15 | public DropDownExample() : base("item"){} 16 | 17 | // Starting with Dynamo v2.0 you must add Json constructors for all nodeModel 18 | // derived nodes to support the move from an Xml to Json file format. Failing to 19 | // do so will result in incorrect ports being generated upon serialization/deserialization. 20 | // This constructor is called when opening a Json graph. We must also pass the deserialized 21 | // ports with the json constructor and then call the base class passing the ports as parameters. 22 | [JsonConstructor] 23 | public DropDownExample(IEnumerable inPorts, IEnumerable outPorts) : base("item", inPorts, outPorts) { } 24 | 25 | protected override SelectionState PopulateItemsCore(string currentSelection) 26 | { 27 | // The Items collection contains the elements 28 | // that appear in the list. For this example, we 29 | // clear the list before adding new items, but you 30 | // can also use the PopulateItems method to add items 31 | // to the list. 32 | 33 | Items.Clear(); 34 | 35 | // Create a number of DynamoDropDownItem objects 36 | // to store the items that we want to appear in our list. 37 | 38 | var newItems = new List() 39 | { 40 | new DynamoDropDownItem("Tywin", 0), 41 | new DynamoDropDownItem("Cersei", 1), 42 | new DynamoDropDownItem("Hodor",2) 43 | }; 44 | 45 | Items.AddRange(newItems); 46 | 47 | // Set the selected index to something other 48 | // than -1, the default, so that your list 49 | // has a pre-selection. 50 | 51 | SelectedIndex = 0; 52 | return SelectionState.Restore; 53 | } 54 | 55 | public override IEnumerable BuildOutputAst(List inputAstNodes) 56 | { 57 | // Build an AST node for the type of object contained in your Items collection. 58 | 59 | var intNode = AstFactory.BuildIntNode((int)Items[SelectedIndex].Item); 60 | var assign = AstFactory.BuildAssignment(GetAstIdentifierForOutputIndex(0), intNode); 61 | 62 | return new List {assign}; 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/SampleLibraryUI/Examples/LocalizedCustomNodeModel.cs: -------------------------------------------------------------------------------- 1 | using Dynamo.Graph.Nodes; 2 | using Newtonsoft.Json; 3 | using ProtoCore.AST.AssociativeAST; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace SampleLibraryUI.Examples 11 | { 12 | /// 13 | /// This example node uses .net .resx files and generated satellite assemblies to perform runtime lookup of localized content 14 | /// depending on the culture of the system Dynamo is running on. 15 | /// Read more: https://docs.microsoft.com/en-us/dotnet/framework/resources/creating-resource-files-for-desktop-apps 16 | /// You can use the -l "es-ES" flag when starting DynamoSandbox.exe to replace the English strings with Spanish ones. 17 | /// For more info on the CLI interface read more: https://github.com/DynamoDS/Dynamo/wiki/Dynamo-Command-Line-Interface 18 | /// 19 | [NodeName("LocalizedNode")] 20 | [NodeDescription("CustomNodeModelDescription", typeof(Properties.Resources))] 21 | [OutPortNames("string")] 22 | [OutPortTypes("string")] 23 | [IsDesignScriptCompatible] 24 | public class LocalizedCustomNodeModel : NodeModel 25 | { 26 | public LocalizedCustomNodeModel() 27 | { 28 | RegisterAllPorts(); 29 | } 30 | 31 | [JsonConstructor] 32 | public LocalizedCustomNodeModel(IEnumerable inPorts, IEnumerable outPorts) : base(inPorts, outPorts) { } 33 | 34 | public override IEnumerable BuildOutputAst(List inputAstNodes) 35 | { 36 | //return a localized string, that is defined in the resx file/resource assembly. 37 | return new List { AstFactory.BuildAssignment(this.AstIdentifierForPreview, AstFactory.BuildPrimitiveNodeFromObject(Properties.Resources.LocalStringResult)) }; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/SampleLibraryUI/Examples/SliderCustomNodeModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Windows; 4 | using Autodesk.DesignScript.Runtime; 5 | using Dynamo.Controls; 6 | using Dynamo.Graph.Nodes; 7 | using Dynamo.UI.Commands; 8 | using Dynamo.Wpf; 9 | using ProtoCore.AST.AssociativeAST; 10 | using SampleLibraryUI.Controls; 11 | using SampleLibraryUI.Properties; 12 | using SampleLibraryZeroTouch; 13 | using Newtonsoft.Json; 14 | 15 | namespace SampleLibraryUI.Examples 16 | { 17 | /* 18 | * This exmple shows how to create a UI node for Dynamo 19 | * which loads custom data-bound UI into the node's view 20 | * at run time. 21 | 22 | * Nodes with custom UI follow a different loading path 23 | * than zero touch nodes. The assembly which contains 24 | * this node needs to be located in the 'nodes' folder in 25 | * Dynamo in order to be loaded at startup. 26 | 27 | * Dynamo uses the MVVM model of programming, 28 | * in which the UI is data-bound to the view model, which 29 | * exposes data from the underlying model. Custom UI nodes 30 | * are a hybrid because NodeModel objects already have an 31 | * associated NodeViewModel which you should never need to 32 | * edit. So here we will create a data binding between 33 | * properties on our class and our custom UI. 34 | */ 35 | 36 | // The NodeName attribute is what will display on 37 | // top of the node in Dynamo 38 | [NodeName("Slider Custom Node Model")] 39 | // The NodeCategory attribute determines how your 40 | // node will be organized in the library. You can 41 | // specify your own category or by default the class 42 | // structure will be used. You can no longer 43 | // add packages or custom nodes to one of the 44 | // built-in OOTB library categories. 45 | [NodeCategory("SampleLibraryUI.Examples")] 46 | // The description will display in the tooltip 47 | // and in the help window for the node. 48 | [NodeDescription("A sample UI node which displays custom UI.")] 49 | // Specifying InPort and OutPort types simply 50 | // adds these types to the help window for the 51 | // node when hovering the name in the library. 52 | //[InPortTypes("double")] 53 | [OutPortTypes("double", "double")] 54 | // Add the IsDesignScriptCompatible attribute to ensure 55 | // that it gets loaded in Dynamo. 56 | [IsDesignScriptCompatible] 57 | public class SliderCustomNodeModel : NodeModel 58 | { 59 | #region private members 60 | 61 | private double sliderValue; 62 | 63 | #endregion 64 | 65 | #region properties 66 | 67 | /// 68 | /// A value that will be bound to our 69 | /// custom UI's slider. 70 | /// 71 | public double SliderValue 72 | { 73 | get { return sliderValue; } 74 | set 75 | { 76 | sliderValue = value; 77 | RaisePropertyChanged("SliderValue"); 78 | 79 | OnNodeModified(); 80 | } 81 | } 82 | 83 | #endregion 84 | 85 | #region constructor 86 | 87 | /// 88 | /// The constructor for a NodeModel is used to create 89 | /// the input and output ports and specify the argument 90 | /// lacing. It gets invoked when the node is added to 91 | /// the graph from the library or through copy/paste. 92 | /// 93 | public SliderCustomNodeModel() 94 | { 95 | // When you create a UI node, you need to do the 96 | // work of setting up the ports yourself. To do this, 97 | // you can populate the InPorts and the OutPorts 98 | // collections with PortData objects describing your ports. 99 | 100 | // Nodes can have an arbitrary number of inputs and outputs. 101 | // If you want more ports, just create more PortData objects. 102 | OutPorts.Add(new PortModel(PortType.Output, this, new PortData("upper value", "returns a 0-10 double value"))); 103 | OutPorts.Add(new PortModel(PortType.Output, this, new PortData("lower value", "returns a 0-100 double value"))); 104 | 105 | // This call is required to ensure that your ports are 106 | // properly created. 107 | RegisterAllPorts(); 108 | 109 | // The arugment lacing is the way in which Dynamo handles 110 | // inputs of lists. If you don't want your node to 111 | // support argument lacing, you can set this to LacingStrategy.Disabled. 112 | ArgumentLacing = LacingStrategy.Disabled; 113 | 114 | // Set initial slider value. 115 | sliderValue = 4; 116 | } 117 | 118 | // Starting with Dynamo v2.0 you must add Json constructors for all nodeModel 119 | // dervived nodes to support the move from an Xml to Json file format. Failing to 120 | // do so will result in incorrect ports being generated upon serialization/deserialization. 121 | // This constructor is called when opening a Json graph. 122 | [JsonConstructor] 123 | SliderCustomNodeModel(IEnumerable inPorts, IEnumerable outPorts) : base(inPorts, outPorts) { } 124 | 125 | #endregion 126 | 127 | #region public methods 128 | 129 | /// 130 | /// BuildOutputAst is where the outputs of this node are calculated. 131 | /// This method is used to do the work that a compiler usually does 132 | /// by parsing the inputs List inputAstNodes into an abstract syntax tree. 133 | /// 134 | /// 135 | /// 136 | [IsVisibleInDynamoLibrary(false)] 137 | public override IEnumerable BuildOutputAst(List inputAstNodes) 138 | { 139 | // When you create your own UI node you are responsible 140 | // for generating the abstract syntax tree (AST) nodes which 141 | // specify what methods are called, or how your data is passed 142 | // when execution occurs. 143 | 144 | // WARNING!!! 145 | // Do not throw an exception during AST creation. If you 146 | // need to convey a failure of this node, then use 147 | // AstFactory.BuildNullNode to pass out null. 148 | 149 | // We create a DoubleNode to wrap the value 'sliderValue' that 150 | // we've stored in a private member. 151 | 152 | var doubleNode = AstFactory.BuildDoubleNode(sliderValue); 153 | 154 | // A FunctionCallNode can be used to represent the calling of a 155 | // function in the AST. The method specified here must live in 156 | // a separate assembly and have been loaded by Dynamo at the time 157 | // that this AST is built. If the method can't be found, you'll get 158 | // a "De-referencing a non-pointer warning." 159 | 160 | var funcNode = AstFactory.BuildFunctionCall( 161 | new Func(SampleUtilities.MultiplyInputByNumber), 162 | new List(){doubleNode}); 163 | 164 | // Using the AstFactory class, we can build AstNode objects 165 | // that assign doubles, assign function calls, build expression lists, etc. 166 | return new[] 167 | { 168 | // In these assignments, GetAstIdentifierForOutputIndex finds 169 | // the unique identifier which represents an output on this node 170 | // and 'assigns' that variable the expression that you create. 171 | 172 | // For the first node, we'll just pass through the 173 | // input provided to this node. 174 | AstFactory.BuildAssignment( 175 | GetAstIdentifierForOutputIndex(0), AstFactory.BuildDoubleNode(sliderValue)), 176 | 177 | // For the second node, we'll build a double node that 178 | // passes along our value for multipled value. 179 | AstFactory.BuildAssignment( 180 | GetAstIdentifierForOutputIndex(1), funcNode) 181 | }; 182 | } 183 | 184 | #endregion 185 | } 186 | 187 | /// 188 | /// View customizer for CustomNodeModel Node Model. 189 | /// 190 | public class SliderCustomNodeModelNodeViewCustomization : INodeViewCustomization 191 | { 192 | /// 193 | /// At run-time, this method is called during the node 194 | /// creation. Here you can create custom UI elements and 195 | /// add them to the node view, but we recommend designing 196 | /// your UI declaratively using xaml, and binding it to 197 | /// properties on this node as the DataContext. 198 | /// 199 | /// The NodeModel representing the node's core logic. 200 | /// The NodeView representing the node in the graph. 201 | public void CustomizeView(SliderCustomNodeModel model, NodeView nodeView) 202 | { 203 | // The view variable is a reference to the node's view. 204 | // In the middle of the node is a grid called the InputGrid. 205 | // We reccommend putting your custom UI in this grid, as it has 206 | // been designed for this purpose. 207 | 208 | // Create an instance of our custom UI class (defined in xaml), 209 | // and put it into the input grid. 210 | var sliderControl = new SliderControl(); 211 | nodeView.inputGrid.Children.Add(sliderControl); 212 | 213 | // Set the data context for our control to be the node model. 214 | // Properties in this class which are data bound will raise 215 | // property change notifications which will update the UI. 216 | sliderControl.DataContext = model; 217 | } 218 | 219 | /// 220 | /// Here you can do any cleanup you require if you've assigned callbacks for particular 221 | /// UI events on your node. 222 | /// 223 | public void Dispose() { } 224 | } 225 | 226 | } 227 | -------------------------------------------------------------------------------- /src/SampleLibraryUI/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("SamplesLibraryUI")] 8 | [assembly: Guid("4c3c629f-e89e-45ae-aa07-bd7c86270ace")] 9 | -------------------------------------------------------------------------------- /src/SampleLibraryUI/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 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 SampleLibraryUI.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", "16.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("SampleLibraryUI.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 | /// 64 | /// Looks up a localized string similar to A sample UI node which displays custom UI.. 65 | /// 66 | internal static string CustomNodeModelDescription { 67 | get { 68 | return ResourceManager.GetString("CustomNodeModelDescription", resourceCulture); 69 | } 70 | } 71 | 72 | /// 73 | /// Looks up a localized string similar to Input a string.. 74 | /// 75 | internal static string CustomNodeModelPortDataInputToolTip { 76 | get { 77 | return ResourceManager.GetString("CustomNodeModelPortDataInputToolTip", resourceCulture); 78 | } 79 | } 80 | 81 | /// 82 | /// Looks up a localized string similar to A result.. 83 | /// 84 | internal static string CustomNodeModelPortDataOutputToolTip { 85 | get { 86 | return ResourceManager.GetString("CustomNodeModelPortDataOutputToolTip", resourceCulture); 87 | } 88 | } 89 | 90 | /// 91 | /// Looks up a localized string similar to I am a localized string.. 92 | /// 93 | internal static string LocalStringResult { 94 | get { 95 | return ResourceManager.GetString("LocalStringResult", resourceCulture); 96 | } 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/SampleLibraryUI/Properties/Resources.en-US.Designer.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DynamoDS/DynamoSamples/bc05df04c9ae2382ce14246a6dad1e7bafb8da16/src/SampleLibraryUI/Properties/Resources.en-US.Designer.cs -------------------------------------------------------------------------------- /src/SampleLibraryUI/Properties/Resources.en-US.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 | A sample UI node which displays custom UI. 122 | Description for Hello Dynamo 123 | 124 | 125 | Input a string. 126 | 127 | 128 | A result. 129 | 130 | 131 | I am a localized string. 132 | 133 | -------------------------------------------------------------------------------- /src/SampleLibraryUI/Properties/Resources.es-ES.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 | Un nodo de interfaz de usuario de muestra que muestra una interfaz de usuario personalizada. 122 | 123 | 124 | Soy una cadena localizada. 125 | 126 | -------------------------------------------------------------------------------- /src/SampleLibraryUI/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 | A sample UI node which displays custom UI. 122 | Description for Hello Dynamo 123 | 124 | 125 | Input a string. 126 | 127 | 128 | A result. 129 | 130 | 131 | I am a localized string. 132 | 133 | -------------------------------------------------------------------------------- /src/SampleLibraryUI/SampleLibraryUI.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | SampleLibraryUI 7 | SampleLibraryUI 8 | 9 | net8.0-windows 10 | true 11 | 12 | 13 | true 14 | bin\$(Configuration)\$(UICulture)\SampleLibraryUI.XML 15 | 16 | 17 | 18 | {bd13c4dc-9045-4e49-b637-b6182b0e3a7f} 19 | SampleLibraryZeroTouch 20 | False 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /src/SampleLibraryZeroTouch/Examples/BasicExample.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Autodesk.DesignScript.Geometry; 4 | using Autodesk.DesignScript.Interfaces; 5 | using Autodesk.DesignScript.Runtime; 6 | 7 | namespace Examples 8 | { 9 | /// 10 | /// The HelloDynamoZeroTouch class demonstrates 11 | /// how to create a class in a zero touch library 12 | /// which creates geometry, and exposes public 13 | /// methods and properties as nodes. 14 | /// 15 | public class BasicExample : IGraphicItem 16 | { 17 | //OPTIONAL: 18 | //IGraphicItem is an interface which allows your 19 | //class to participate in the rendering of geometry 20 | //to the background preview, and to Watch3D nodes. 21 | //You do not need to implement IGraphicItem unless 22 | //your node needs to draw geometry to the view. 23 | 24 | private Point point; 25 | 26 | //-------------------------------------------------- 27 | //A NOTE ON XML COMMENTS: 28 | 29 | //Dynamo uses the comments you've put on your code to 30 | //populate tooltips and help windows in the user 31 | //interface. In order to enable this behavior, your 32 | //project needs to be set to build xml 33 | //documentation. To do this: 34 | //1. Right click on your project in the solution explorer. 35 | //2. Select Properties. 36 | //3. Select the Build tab. 37 | //4. Check the XML Documentation box. 38 | 39 | //The generated xml file will be called the same 40 | //thing as your library, and needs to live along-side 41 | //your library to be picked up by the Dynamo loader. 42 | //-------------------------------------------------- 43 | 44 | /// 45 | /// Properties marked as public will show up as 46 | /// nodes in the Query section of the dynamo library. 47 | /// 48 | public double Awesome { get { return 42.0; } } 49 | 50 | /// 51 | /// The Point stored on the object. 52 | /// 53 | public Point Point { get { return point; } } 54 | 55 | /// 56 | /// Properties and methods marked as internal will not 57 | /// be visible in the Dynamo UI. 58 | /// 59 | internal double InvisibleProperty { get { return 42.0; } } 60 | 61 | /// 62 | /// Private methods, such as this constructor, 63 | /// will not be visible in the Dynamo library. 64 | /// 65 | /// The x coordinate. 66 | /// The y coordinate. 67 | /// The z coordinate. 68 | private BasicExample(double x, double y, double z) 69 | { 70 | point = Point.ByCoordinates(x, y, z); 71 | } 72 | 73 | /// 74 | /// Dynamo uses the pattern of static constructors. 75 | /// Don't forget to fill in the xml comments so that 76 | /// you will get help tips in the UI. You can also use 77 | /// default parameters, as we have here. With default 78 | /// parameters defined, you will not be required to attach 79 | /// any inputs to these ports in Dynamo. 80 | /// 81 | /// The x coordinate of the point. 82 | /// The y coordinate of the point. 83 | /// The z coordinate of the point. 84 | /// A HelloDynamoZeroTouch object. 85 | public static BasicExample Create(double x=42.0, double y=42.0, double z=42.0) 86 | { 87 | // Let's say in our example that the user is not allowed 88 | // to create an instance of this class if any of the 89 | // coordinates is less than zero. We check the parameters 90 | // here because passing to the private constructor, and 91 | // we throw an error if the parameters do not conform. 92 | 93 | // These exceptions will be shown in the error bubble 94 | // over the node, and the node will turn yellow. 95 | 96 | if (x < 0) 97 | { 98 | throw new ArgumentException("x"); 99 | } 100 | 101 | if (y < 0) 102 | { 103 | throw new ArgumentException("y"); 104 | } 105 | 106 | if (z < 0) 107 | { 108 | throw new ArgumentException("z"); 109 | } 110 | 111 | return new BasicExample(x, y, z); 112 | } 113 | 114 | /// 115 | /// Another example of a static constructor which 116 | /// uses a parameter with a default value. The default value 117 | /// is provided as a design script expression. 118 | /// 119 | /// A point. 120 | /// A BasicExample object. 121 | public static BasicExample Create([DefaultArgumentAttribute("Autodesk.DesignScript.Geometry.Point.ByCoordinates(5,5,5);")]Point point) 122 | { 123 | return new BasicExample(point.X, point.Y, point.Z); 124 | } 125 | 126 | /// 127 | /// The MultiReturn attribute can be used to specify 128 | /// that a node is a multi-out node. This node must return 129 | /// a Dictionary with its keys matching the attributes specified in the 130 | /// MultiReturn attribute. The names of the output ports 131 | /// match the attribute names if there are no XML returns tags. 132 | /// The returned dictionary displayed in the node preview is displayed 133 | /// in the order of its keys as specified in the MultiReturn attribute. 134 | /// 135 | /// 136 | [MultiReturn(new[] { "thing 1", "thing 2" })] 137 | public static Dictionary> MultiReturnExample() 138 | { 139 | return new Dictionary>() 140 | { 141 | { "thing 1", new List{"apple", "banana", "cat"} }, 142 | { "thing 2", new List{"Tywin", "Cersei", "Hodor"} } 143 | }; 144 | } 145 | 146 | /// 147 | /// The MultiReturn attribute can be used to specify 148 | /// that a node is a multi-out node. This node must return 149 | /// a Dictionary with its keys matching the attributes specified in the 150 | /// MultiReturn attribute. The names of the output ports 151 | /// match the XML returns tag only if they include descriptions. 152 | /// Otherwise the output ports will match the attribute names. 153 | /// The returned dictionary displayed in the node preview is displayed 154 | /// in the order of its keys as specified in the MultiReturn attribute. 155 | /// E.g. this node will display "thing one" and "thing two" in its output ports 156 | /// but it will show "thing 1" and "thing 2" in the node preview. 157 | /// 158 | /// first thing 159 | /// second thing 160 | [MultiReturn(new[] { "thing 1", "thing 2" })] 161 | public static Dictionary> MultiReturnExample2() 162 | { 163 | return new Dictionary>() 164 | { 165 | { "thing 1", new List{"apple", "banana", "cat"} }, 166 | { "thing 2", new List{"Tywin", "Cersei", "Hodor"} } 167 | }; 168 | } 169 | 170 | /// 171 | /// OPTIONAL: 172 | /// Overriding ToString allows you to control what is 173 | /// displayed whenever the object's string representation 174 | /// is used. For example, ToString is called when the 175 | /// object is displayed in a Watch node. 176 | /// 177 | /// The string representation of our object. 178 | public override string ToString() 179 | { 180 | return string.Format("HelloDynamoZeroTouch:{0},{1},{2}", point.X, point.Y, point.Z); 181 | } 182 | 183 | #region IGraphicItem interface 184 | 185 | /// 186 | /// The Tessellate method in the IGraphicItem interface allows 187 | /// you to specify what is drawn when dynamo's visualization is 188 | /// updated. 189 | /// 190 | [IsVisibleInDynamoLibrary(false)] 191 | public void Tessellate(IRenderPackage package, TessellationParameters parameters) 192 | { 193 | // This example contains information to draw a point 194 | package.AddPointVertex(point.X, point.Y, point.Z); 195 | package.AddPointVertexColor(255, 0, 0, 255); 196 | } 197 | 198 | #endregion 199 | } 200 | 201 | /// 202 | /// By decorating a class with the 203 | /// IsVisibleInDynamoLibrary attribute, and setting 204 | /// it to false, you are saying that you want this member 205 | /// to be available to the VM, but not be visible in the 206 | /// library view or search. 207 | /// 208 | /// By decorating a class with the SupressImportIntoVM 209 | /// attribute, you are saying that you do not want to import 210 | /// this class into Dynamo. BE CAREFUL! This class will then 211 | /// be unavailable to others that might reference it. In most 212 | /// cases, adding IsVisibleInDynamoLibrary(false) will suffice 213 | /// to hide your method from view without needing to disable 214 | /// its import completely. 215 | /// 216 | [SupressImportIntoVM] 217 | [IsVisibleInDynamoLibrary(false)] 218 | public class DoesNotImportClass 219 | { 220 | /// 221 | /// DoesNotImportClass constructor. 222 | /// 223 | public DoesNotImportClass(){} 224 | } 225 | } 226 | -------------------------------------------------------------------------------- /src/SampleLibraryZeroTouch/Examples/ColorExample.cs: -------------------------------------------------------------------------------- 1 | using Autodesk.DesignScript.Interfaces; 2 | using Autodesk.DesignScript.Runtime; 3 | 4 | namespace Examples 5 | { 6 | public class CustomRenderExample : IGraphicItem 7 | { 8 | private CustomRenderExample(){} 9 | 10 | /// 11 | /// Create an object which renders custom geometry. 12 | /// 13 | public static CustomRenderExample Create() 14 | { 15 | return new CustomRenderExample(); 16 | } 17 | 18 | [IsVisibleInDynamoLibrary(false)] 19 | public void Tessellate(IRenderPackage package, TessellationParameters parameters) 20 | { 21 | // Dynamo's renderer uses IRenderPackage objects 22 | // to store data for rendering. The Tessellate method 23 | // give you an IRenderPackage object which you can fill 24 | // with render data. 25 | 26 | // Set RequiresPerVertexColoration to let the renderer 27 | // know that you needs to use a per-vertex color shader. 28 | package.RequiresPerVertexColoration = true; 29 | 30 | AddColoredQuadToPackage(package); 31 | AddColoredLineToPackage(package); 32 | } 33 | 34 | private static void AddColoredQuadToPackage(IRenderPackage package) 35 | { 36 | // Triangle 1 37 | package.AddTriangleVertex(0, 0, 0); 38 | package.AddTriangleVertex(1, 0, 0); 39 | package.AddTriangleVertex(1, 1, 0); 40 | 41 | // For each vertex, add a color. 42 | package.AddTriangleVertexColor(255, 0, 0, 255); 43 | package.AddTriangleVertexColor(0, 255, 0, 255); 44 | package.AddTriangleVertexColor(0, 0, 255, 255); 45 | 46 | //Triangle 2 47 | package.AddTriangleVertex(0, 0, 0); 48 | package.AddTriangleVertex(1, 1, 0); 49 | package.AddTriangleVertex(0, 1, 0); 50 | package.AddTriangleVertexColor(255, 0, 0, 255); 51 | package.AddTriangleVertexColor(0, 255, 0, 255); 52 | package.AddTriangleVertexColor(0, 0, 255, 255); 53 | 54 | package.AddTriangleVertexNormal(0, 0, 1); 55 | package.AddTriangleVertexNormal(0, 0, 1); 56 | package.AddTriangleVertexNormal(0, 0, 1); 57 | package.AddTriangleVertexNormal(0, 0, 1); 58 | package.AddTriangleVertexNormal(0, 0, 1); 59 | package.AddTriangleVertexNormal(0, 0, 1); 60 | 61 | package.AddTriangleVertexUV(0, 0); 62 | package.AddTriangleVertexUV(0, 0); 63 | package.AddTriangleVertexUV(0, 0); 64 | package.AddTriangleVertexUV(0, 0); 65 | package.AddTriangleVertexUV(0, 0); 66 | package.AddTriangleVertexUV(0, 0); 67 | } 68 | 69 | private static void AddColoredLineToPackage(IRenderPackage package) 70 | { 71 | package.AddLineStripVertex(0,0,0); 72 | package.AddLineStripVertex(5,5,5); 73 | 74 | package.AddLineStripVertexColor(255,0,0,255); 75 | package.AddLineStripVertexColor(255,0,0,255); 76 | 77 | // Specify line segments by adding a line vertex count. 78 | // Ex. The above line has two vertices, so we add a line 79 | // vertex count of 2. If we had tessellated a curve with n 80 | // vertices, we would add a line vertex count of n. 81 | package.AddLineStripVertexCount(2); 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/SampleLibraryZeroTouch/Examples/PeriodicUpdateExample.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Autodesk.DesignScript.Geometry; 3 | using Autodesk.DesignScript.Interfaces; 4 | using Autodesk.DesignScript.Runtime; 5 | 6 | namespace Examples 7 | { 8 | // This sample demonstrates the use of the CanUpdatePeriodically 9 | // attribute. Placing an instance of the PeriodicUpdateExample.PointField 10 | // node in your workspace will enable the Periodic RunType in the run 11 | // settings control. This formula used to create the point field 12 | // requires a parameter, 't', that is incremented during each run. 13 | // This example also demonstrates how to use trace to store data that 14 | // you want to carry over between evaluations. 15 | public class PeriodicUpdateExample : IGraphicItem 16 | { 17 | private Point[,] vertexCoords; 18 | private const int width = 20; 19 | private const int length = 20; 20 | 21 | private PeriodicUpdateExample(double t, int id) 22 | { 23 | vertexCoords = new Point[width, length]; 24 | 25 | for (var x = 0; x < width; x += 1) 26 | { 27 | for (var y = 0; y < length; y += 1) 28 | { 29 | var z = Math.Sin(Math.Sqrt(Math.Pow(x, 2) + Math.Pow(y, 2)) - t); 30 | vertexCoords[x, y] = Point.ByCoordinates(x, y, z); 31 | } 32 | } 33 | 34 | t += 0.1; 35 | if (t > Math.PI * 2) t = 0.0; 36 | 37 | // Remember to store the updated object in the trace object manager, 38 | // so it's available to use the next time around. 39 | TraceableObjectManager.RegisterTraceableObjectForId(id, t); 40 | } 41 | 42 | // The CanUpdatePeriodicallyAttribute can be applied to methods in 43 | // your library which you want to enable the Periodic RunType in Dynamo 44 | // when exposed as nodes. 45 | /// 46 | /// Create a field of waving points that periodically updates. 47 | /// 48 | /// A PeriodicUpdateExample object. 49 | [CanUpdatePeriodically(true)] 50 | public static PeriodicUpdateExample PointField() 51 | { 52 | // See if the data for this object is in trace. 53 | var traceId = TraceableObjectManager.GetObjectIdFromTrace(); 54 | 55 | var t = 0.0; 56 | int id; 57 | if (traceId == null) 58 | { 59 | // If there's no id stored in trace for this object, 60 | // then grab the next unused trace id. 61 | id = TraceableObjectManager.GetNextUnusedID(); 62 | } 63 | else 64 | { 65 | // If there's and id stored in trace, then retrieve the object stored 66 | // with that id from the trace object manager. 67 | id = traceId.IntID; 68 | t = (double)TraceableObjectManager.GetTracedObjectById(traceId.IntID); 69 | } 70 | 71 | return new PeriodicUpdateExample(t, id); 72 | } 73 | 74 | [IsVisibleInDynamoLibrary(false)] 75 | public void Tessellate(IRenderPackage package, TessellationParameters parameters) 76 | { 77 | for (var i = 0; i < width - 1; i++) 78 | { 79 | for (var j = 0; j < length - 1; j++) 80 | { 81 | var a = vertexCoords[i, j]; 82 | var b = vertexCoords[i, j + 1]; 83 | var c = vertexCoords[i + 1, j]; 84 | var d = vertexCoords[i + 1, j + 1]; 85 | 86 | var v1 = Vector.ByTwoPoints(b, a).Cross(Vector.ByTwoPoints(c, b)).Normalized().Reverse(); 87 | var v2 = Vector.ByTwoPoints(c, d).Cross(Vector.ByTwoPoints(b, d)).Normalized().Reverse(); 88 | 89 | PushTriangleVertex(package, a, v1); 90 | PushTriangleVertex(package, b, v1); 91 | PushTriangleVertex(package, c, v1); 92 | 93 | PushTriangleVertex(package, d, v2); 94 | PushTriangleVertex(package, c, v2); 95 | PushTriangleVertex(package, b, v2); 96 | } 97 | } 98 | } 99 | 100 | private void PushTriangleVertex(IRenderPackage package, Point p, Vector n) 101 | { 102 | package.AddTriangleVertex(p.X, p.Y, p.Z); 103 | package.AddTriangleVertexColor(255, 255, 255, 255); 104 | package.AddTriangleVertexNormal(n.X, n.Y, n.Z); 105 | package.AddTriangleVertexUV(0, 0); 106 | } 107 | } 108 | } -------------------------------------------------------------------------------- /src/SampleLibraryZeroTouch/Examples/TraceExample.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Runtime.Serialization; 4 | using Autodesk.DesignScript.Runtime; 5 | using DynamoServices; 6 | using Newtonsoft.Json; 7 | 8 | namespace Examples 9 | { 10 | /// 11 | /// This is the item that we will store in our data store. 12 | /// 13 | [IsVisibleInDynamoLibrary(false)] 14 | public sealed class TraceExampleItem 15 | { 16 | public string Description { get; set; } 17 | 18 | public TraceExampleItem(string description) 19 | { 20 | Description = description; 21 | } 22 | 23 | public override string ToString() 24 | { 25 | return Description; 26 | } 27 | } 28 | 29 | /* 30 | * After a graph update, Dynamo typically disposes of all 31 | * objects created during the graph update. But what if there are 32 | * objects which are expensive to re-create, or which have other 33 | * associations in a host application? You wouldn't want those those objects 34 | * re-created on every graph update. For example, you might 35 | * have an external database whose records contain data which needs 36 | * to be re-applied to an object when it is created in Dynamo. 37 | * In this example, we use a wrapper class, TraceExampleWrapper, to create 38 | * TraceExampleItem objects which are stored in a static dictionary 39 | * (they could be stored in a database as well). On subsequent graph updates, 40 | * the objects will be retrieved from the data store using a trace id stored 41 | * in the trace cache. 42 | */ 43 | 44 | /// 45 | /// A class which contains methods to construct TraceExampleItem objects. 46 | /// 47 | [IsVisibleInDynamoLibrary(false)] 48 | public static class TraceExampleWrapper 49 | { 50 | /// 51 | /// Create a TraceExampleItem and store it in a static dictionary. 52 | /// 53 | public static TraceExampleItem ByString(string description) 54 | { 55 | // See if there is data for this object is in trace. 56 | var traceId = TraceableObjectManager.GetObjectIdFromTrace(); 57 | 58 | TraceExampleItem item = null; 59 | 60 | int id; 61 | if (traceId == null) 62 | { 63 | // If there's no id stored in trace for this object, 64 | // then grab the next unused trace id. 65 | id = TraceableObjectManager.GetNextUnusedID(); 66 | 67 | // Create an item 68 | item = new TraceExampleItem(description); 69 | 70 | // Remember to store the updated object in the trace object manager, 71 | // so it's available to use the next time around. 72 | TraceableObjectManager.RegisterTraceableObjectForId(id, item); 73 | } 74 | else 75 | { 76 | // If there's and id stored in trace, then retrieve the object stored 77 | // with that id from the trace object manager. 78 | item = (TraceExampleItem)TraceableObjectManager.GetTracedObjectById(traceId.IntID) 79 | ?? new TraceExampleItem(description); 80 | 81 | // Update the item 82 | item.Description = description; 83 | } 84 | 85 | return item; 86 | } 87 | } 88 | 89 | /* 90 | * The TraceableObjectManager class maintains a static 91 | * dictionary of objects keyed by their trace id. This 92 | * dictionary is where your objects are stored between 93 | * runs. At run-time, they are retrieved using the id 94 | * stored in trace. 95 | */ 96 | 97 | /// 98 | /// A class which maintains a static dictionary for storing 99 | /// objects, keyed by their trace id. 100 | /// 101 | [IsVisibleInDynamoLibrary(false)] 102 | public class TraceableObjectManager 103 | { 104 | private const string REVIT_TRACE_ID = "{0459D869-0C72-447F-96D8-08A7FB92214B}-REVIT"; 105 | 106 | private static int id = 0; 107 | 108 | public static int GetNextUnusedID() 109 | { 110 | var next = id; 111 | id++; 112 | return next; 113 | } 114 | 115 | private static Dictionary traceableObjectManager = new Dictionary(); 116 | 117 | public static TraceableId GetObjectIdFromTrace() 118 | { 119 | return JsonConvert.DeserializeObject(TraceUtils.GetTraceData(REVIT_TRACE_ID)); 120 | } 121 | 122 | public static object GetTracedObjectById(int id) 123 | { 124 | object ret; 125 | traceableObjectManager.TryGetValue(id, out ret); 126 | return ret; 127 | } 128 | 129 | public static void RegisterTraceableObjectForId(int id, object objectToTrace) 130 | { 131 | if (traceableObjectManager.ContainsKey(id)) 132 | { 133 | traceableObjectManager[id] = objectToTrace; 134 | } 135 | else 136 | { 137 | traceableObjectManager.Add(id, objectToTrace); 138 | 139 | TraceUtils.SetTraceData(REVIT_TRACE_ID, JsonConvert.SerializeObject(objectToTrace)); 140 | } 141 | } 142 | 143 | public static void Clear() 144 | { 145 | traceableObjectManager.Clear(); 146 | id = 0; 147 | } 148 | } 149 | 150 | [IsVisibleInDynamoLibrary(false)] 151 | [Serializable] 152 | public class TraceableId : ISerializable 153 | { 154 | public int IntID { get; set; } 155 | 156 | public void GetObjectData(SerializationInfo info, StreamingContext context) 157 | { 158 | info.AddValue("intID", IntID, typeof(int)); 159 | } 160 | 161 | public TraceableId(int id) 162 | { 163 | IntID = id; 164 | } 165 | 166 | /// 167 | /// Ctor used by the serialisation engine 168 | /// 169 | /// 170 | /// 171 | public TraceableId(SerializationInfo info, StreamingContext context) 172 | { 173 | IntID = (int)info.GetValue("intID", typeof(int)); 174 | } 175 | } 176 | } -------------------------------------------------------------------------------- /src/SampleLibraryZeroTouch/Examples/TransformableExample.cs: -------------------------------------------------------------------------------- 1 | using Autodesk.DesignScript.Geometry; 2 | using Autodesk.DesignScript.Interfaces; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace Examples 10 | { 11 | /// 12 | /// An object which knows how to draw itself in the background preview and uses a transform to take 13 | /// advantage of the GPU to alter that background visualization. The original geometry remains unaltered, 14 | /// only the visualization is transformed. 15 | /// 16 | public class TransformableExample : IGraphicItem 17 | { 18 | public Geometry Geometry { get; private set; } 19 | private CoordinateSystem transform { get; set; } 20 | 21 | //want to hide this constructor 22 | [Autodesk.DesignScript.Runtime.IsVisibleInDynamoLibrary(false)] 23 | public TransformableExample(Geometry geometry) 24 | { 25 | Geometry = geometry; 26 | //initial transform is just at the origin 27 | transform = CoordinateSystem.ByOrigin(0, 0, 0); 28 | } 29 | 30 | /// 31 | /// Create a TranformableExample class which stores a Geometry object and a Transform. 32 | /// 33 | /// a geometry object 34 | /// 35 | public static TransformableExample ByGeometry(Autodesk.DesignScript.Geometry.Geometry geometry) 36 | { 37 | var newTransformableThing = new TransformableExample(geometry); 38 | return newTransformableThing; 39 | } 40 | 41 | /// 42 | /// This method sets the transform on the object and returns a reference to the object so 43 | /// the tessellate method is called and the new visualization shows in the background preview. 44 | /// 45 | /// 46 | /// 47 | public TransformableExample TransformObject(CoordinateSystem transform) 48 | { 49 | this.transform = transform; 50 | return this; 51 | } 52 | 53 | /// 54 | /// This method is actually called by Dynamo when it attempts to render the TransformableExample. 55 | /// class. 56 | /// 57 | /// 58 | /// 59 | //hide this method from search 60 | [Autodesk.DesignScript.Runtime.IsVisibleInDynamoLibrary(false)] 61 | 62 | public void Tessellate(IRenderPackage package, TessellationParameters parameters) 63 | { 64 | //could increase performance further by cacheing this tesselation 65 | Geometry.Tessellate(package, parameters); 66 | 67 | //we use reflection here because this API was added in Dynamo 1.1 and might not exist for a user in Dynamo 1.0 68 | //if you do not care about ensuring comptability of your zero touch node with 1.0 you can just call SetTransform directly 69 | //by casting the rendering package to ITransformable. 70 | 71 | //look for the method SetTransform with the double[] argument list. 72 | var method = package.GetType(). 73 | GetMethod("SetTransform", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance, 74 | null, 75 | new[] { typeof(double[]) }, null); 76 | 77 | //if the method exists call it using our current transform. 78 | if (method != null) 79 | { 80 | method.Invoke(package, new object[] { new double[] 81 | {transform.XAxis.X,transform.XAxis.Y,transform.XAxis.Z,0, 82 | transform.YAxis.X,transform.YAxis.Y,transform.YAxis.Z,0, 83 | transform.ZAxis.X,transform.ZAxis.Y,transform.ZAxis.Z,0, 84 | transform.Origin.X,transform.Origin.Y,transform.Origin.Z,1 85 | }}); 86 | } 87 | 88 | } 89 | 90 | } 91 | 92 | public static class PeriodicIncrement 93 | { 94 | private static double value = 0; 95 | 96 | [Autodesk.DesignScript.Runtime.CanUpdatePeriodically(true)] 97 | public static double Increment() 98 | { 99 | value = value + 1; 100 | return value; 101 | } 102 | } 103 | 104 | } 105 | -------------------------------------------------------------------------------- /src/SampleLibraryZeroTouch/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("SampleLibraryZeroTouch")] 8 | [assembly: Guid("4e93ab1f-673b-4a3a-9b45-9b8347430d5d")] 9 | -------------------------------------------------------------------------------- /src/SampleLibraryZeroTouch/SampleLibraryZeroTouch.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | Properties 7 | SampleLibraryZeroTouch 8 | SampleLibraryZeroTouch 9 | net8.0 10 | 11 | 12 | true 13 | bin\$(Configuration)\SampleLibraryZeroTouch.XML 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/SampleLibraryZeroTouch/Utils/SampleUtilities.cs: -------------------------------------------------------------------------------- 1 | using Autodesk.DesignScript.Runtime; 2 | 3 | namespace SampleLibraryZeroTouch 4 | { 5 | /// 6 | /// A utility library containing methods that can be called 7 | /// from NodeModel nodes, or used as nodes in Dynamo. 8 | /// 9 | public static class SampleUtilities 10 | { 11 | [IsVisibleInDynamoLibrary(false)] 12 | public static double MultiplyInputByNumber(double input) 13 | { 14 | return input * 10; 15 | } 16 | 17 | [IsVisibleInDynamoLibrary(false)] 18 | public static string DescribeButtonMessage(string input) 19 | { 20 | return "Button displays: " + input; 21 | } 22 | 23 | [IsVisibleInDynamoLibrary(false)] 24 | public static string DescribeWindowMessage(string GUID, string input) 25 | { 26 | return "Window displays: Data bridge callback of node " + GUID.Substring(0, 5) + ": " + input; 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/SampleLibraryZeroTouch/app.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/SampleLibraryZeroTouch/dyns/testPeriodicTransform.dyn: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /src/SampleLinter/LinterSettings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Xml.Serialization; 8 | 9 | namespace SampleLinter 10 | { 11 | public class LinterSettings 12 | { 13 | [XmlElement("AllowedUngroupedNodes")] 14 | public int AllowedUngroupedNodes { get; set; } = 5; 15 | 16 | public static void SerializeModels(string filename, LinterSettings settings) 17 | { 18 | var xmls = new XmlSerializer(settings.GetType()); 19 | var writer = new StreamWriter(filename); 20 | xmls.Serialize(writer, settings); 21 | writer.Close(); 22 | } 23 | public static LinterSettings DeserializeModels(string filename) 24 | { 25 | var fs = new FileStream(filename, FileMode.Open); 26 | var xmls = new XmlSerializer(typeof(LinterSettings)); 27 | return (LinterSettings)xmls.Deserialize(fs); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/SampleLinter/LinterSettings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 4 | -------------------------------------------------------------------------------- /src/SampleLinter/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // Setting ComVisible to false makes the types in this assembly not visible 6 | // to COM components. If you need to access a type in this assembly from 7 | // COM, set the ComVisible attribute to true on that type. 8 | [assembly: ComVisible(false)] 9 | 10 | // The following GUID is for the ID of the typelib if this project is exposed to COM 11 | [assembly: Guid("2EBDA9A0-722E-4C88-826C-62111D4C2C60")] 12 | -------------------------------------------------------------------------------- /src/SampleLinter/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 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 SampleLinter.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", "17.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | public 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 | public 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("SampleLinter.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 | public static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// Looks up a localized string similar to If the placed dropdowns are needing to be inputs, remember to rename them and mark them as input. If you do not need these as inputs, consider an alternative node.. 65 | /// 66 | public static string DropdownCallToAction { 67 | get { 68 | return ResourceManager.GetString("DropdownCallToAction", resourceCulture); 69 | } 70 | } 71 | 72 | /// 73 | /// Looks up a localized string similar to You have dropdown nodes placed that are not inputs.. 74 | /// 75 | public static string DropdownDescription { 76 | get { 77 | return ResourceManager.GetString("DropdownDescription", resourceCulture); 78 | } 79 | } 80 | 81 | /// 82 | /// Looks up a localized string similar to You have nodes that are not in groups. Grouping your nodes is a best-practice when authoring Dynamo graphs. {0} nodes are allowed outside of groups based on the Linter Settings.. 83 | /// 84 | public static string NodesNotInGroupsCallToAction { 85 | get { 86 | return ResourceManager.GetString("NodesNotInGroupsCallToAction", resourceCulture); 87 | } 88 | } 89 | 90 | /// 91 | /// Looks up a localized string similar to There are {0} nodes that are not in groups.. 92 | /// 93 | public static string NodesNotInGroupsDescription { 94 | get { 95 | return ResourceManager.GetString("NodesNotInGroupsDescription", resourceCulture); 96 | } 97 | } 98 | 99 | /// 100 | /// Looks up a localized string similar to If the placed number sliders are needing to be inputs, remember to rename them and mark them as input. If you do not need these as inputs, consider an alternative node.. 101 | /// 102 | public static string SlidersCallToAction { 103 | get { 104 | return ResourceManager.GetString("SlidersCallToAction", resourceCulture); 105 | } 106 | } 107 | 108 | /// 109 | /// Looks up a localized string similar to You have number sliders placed that are not inputs.. 110 | /// 111 | public static string SlidersDescription { 112 | get { 113 | return ResourceManager.GetString("SlidersDescription", resourceCulture); 114 | } 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/SampleLinter/Properties/Resources.en-US.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 | If the placed dropdowns are needing to be inputs, remember to rename them and mark them as input. If you do not need these as inputs, consider an alternative node. 122 | 123 | 124 | You have dropdown nodes placed that are not inputs. 125 | 126 | 127 | You have nodes that are not in groups. Grouping your nodes is a best-practice when authoring Dynamo graphs. {0} nodes are allowed outside of groups based on the Linter Settings. 128 | 129 | 130 | There are {0} nodes that are not in groups. 131 | 132 | 133 | If the placed number sliders are needing to be inputs, remember to rename them and mark them as input. If you do not need these as inputs, consider an alternative node. 134 | 135 | 136 | You have number sliders placed that are not inputs. 137 | 138 | -------------------------------------------------------------------------------- /src/SampleLinter/Properties/Resources.es-ES.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 | Si los dropdowns desplegables colocados deben ser entradas, recuerde cambiarles el nombre y marcarlos como entrada. Si no los necesita como entradas, considere un node alternativo. 122 | 123 | 124 | Tiene dropdowns colocados que no son entradas. 125 | 126 | 127 | Tiene nodes que no están en grupos. Agrupar sus nodos es una práctica recomendada al crear gráficos de Dynamo. Se permiten {0} nodes fuera de los grupos según la configuración de Linter. 128 | 129 | 130 | Hay {0} nodes que no están en grupos. 131 | 132 | 133 | Si los controles deslizantes numéricos colocados deben ser entradas, recuerde cambiarles el nombre y marcarlos como entrada. Si no los necesita como entradas, considere un nodo alternativo. 134 | 135 | 136 | Tiene deslizadores sliders colocados que no son entradas. 137 | 138 | -------------------------------------------------------------------------------- /src/SampleLinter/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 | If the placed dropdowns are needing to be inputs, remember to rename them and mark them as input. If you do not need these as inputs, consider an alternative node. 122 | 123 | 124 | You have dropdown nodes placed that are not inputs. 125 | 126 | 127 | You have nodes that are not in groups. Grouping your nodes is a best-practice when authoring Dynamo graphs. {0} nodes are allowed outside of groups based on the Linter Settings. 128 | 129 | 130 | There are {0} nodes that are not in groups. 131 | 132 | 133 | If the placed number sliders are needing to be inputs, remember to rename them and mark them as input. If you do not need these as inputs, consider an alternative node. 134 | 135 | 136 | You have number sliders placed that are not inputs. 137 | 138 | -------------------------------------------------------------------------------- /src/SampleLinter/Rules/NoGroupsLinterRule.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using Dynamo.Graph.Nodes; 5 | using Dynamo.Graph.Workspaces; 6 | using Dynamo.Linting.Interfaces; 7 | using Dynamo.Linting.Rules; 8 | 9 | namespace SampleLinter.Rules 10 | { 11 | /// 12 | /// Having ungrouped nodes is a bad practice. This section allows the linter to flag this behavior based on linter settings in the extra folder in the extension directory. 13 | /// This example node uses .net .resx files and generated satellite assemblies to perform runtime lookup of localized content 14 | /// depending on the culture of the system Dynamo is running on. 15 | /// Read more: https://docs.microsoft.com/en-us/dotnet/framework/resources/creating-resource-files-for-desktop-apps 16 | /// You can use the -l "es-ES" flag when starting DynamoSandbox.exe to replace the English strings with Spanish ones. 17 | /// For more info on the CLI interface read more: https://github.com/DynamoDS/Dynamo/wiki/Dynamo-Command-Line-Interface 18 | /// 19 | public class NoGroupsLinterRule : GraphLinterRule 20 | { 21 | public override string Id => "EF17A093-4E94-4AE9-8876-18631396A23A"; //this id is unique to each linter rule 22 | public override SeverityCodesEnum SeverityCode => SeverityCodesEnum.Warning; 23 | 24 | public override string Description => 25 | string.Format(Properties.Resources.NodesNotInGroupsDescription, _nodesNotInGroups.Count); 26 | public override string CallToAction => string.Format(Properties.Resources.NodesNotInGroupsDescription, _ungroupedAllowed); 27 | 28 | //To store our ungrouped nodes for counts and checks 29 | private readonly List _nodesNotInGroups = new List(); 30 | 31 | //Allow the end-user to have a few nodes outside of groups. We don't want to be too overbearing. 32 | private readonly int _ungroupedAllowed; 33 | 34 | public NoGroupsLinterRule(LinterSettings linterSettings) 35 | { 36 | _ungroupedAllowed = linterSettings.AllowedUngroupedNodes; 37 | } 38 | 39 | public override List EvaluationTriggerEvents => 40 | new List() 41 | { 42 | "Modified" 43 | }; 44 | 45 | protected override Tuple> EvaluateFunction(WorkspaceModel workspaceModel, string changedEvent, NodeModel nodeModel = null) 46 | { 47 | //clear our list as we are reevaluating the graph 48 | _nodesNotInGroups.Clear(); 49 | 50 | if (workspaceModel != null) 51 | { 52 | //check each node for grouping 53 | foreach (var node in workspaceModel.Nodes) 54 | { 55 | CheckNodeForGroup(node, workspaceModel); 56 | } 57 | } 58 | 59 | var result = _nodesNotInGroups.Count > _ungroupedAllowed ? RuleEvaluationStatusEnum.Failed : RuleEvaluationStatusEnum.Passed; 60 | 61 | return new Tuple>(result, new HashSet()); 62 | } 63 | 64 | 65 | 66 | protected override List>> InitFunction(WorkspaceModel workspaceModel) 67 | { 68 | _nodesNotInGroups.Clear(); 69 | 70 | //create a list to hold results information. 71 | //The Tuple should be of a RuleEvaluationStatus and the name of the node 72 | List> results = new List>(); 73 | 74 | //Iterate over all the nodes in the workspace 75 | foreach (NodeModel node in workspaceModel.Nodes) 76 | { 77 | CheckNodeForGroup(node, workspaceModel); 78 | } 79 | 80 | return new List>> { EvaluateFunction(workspaceModel, "initialize") }; 81 | } 82 | 83 | private void CheckNodeForGroup(NodeModel nodeModel, WorkspaceModel workspaceModel) 84 | { 85 | //collect current groups from file 86 | var groups = workspaceModel.Annotations.ToList(); 87 | 88 | //if there are no groups, return all of the current nodes 89 | if (!groups.Any()) 90 | { 91 | _nodesNotInGroups.Clear(); 92 | _nodesNotInGroups.AddRange(workspaceModel.Nodes); 93 | 94 | return; 95 | }; 96 | 97 | //check if the node is in any of the groups. If not add it to our list. 98 | if (!groups.Any(g => g.Nodes.Any(n => n.GUID.Equals(nodeModel.GUID)))) 99 | { 100 | _nodesNotInGroups.Add(nodeModel); 101 | } 102 | //the node is in a group, remove it from the list if applicable 103 | else 104 | { 105 | _nodesNotInGroups.Remove(nodeModel); 106 | } 107 | } 108 | } 109 | 110 | 111 | } 112 | -------------------------------------------------------------------------------- /src/SampleLinter/Rules/SampleDropdownInputLinterRule.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Dynamo.Graph.Nodes; 4 | using Dynamo.Graph.Workspaces; 5 | using Dynamo.Linting.Interfaces; 6 | using Dynamo.Linting.Rules; 7 | 8 | namespace SampleLinter.Rules 9 | { 10 | /// 11 | /// Similar to the slider rule, but for dropdowns. If you aren't using it as an input, it is worth considering an alternative. 12 | /// Having ungrouped nodes is a bad practice. This section allows the linter to flag this behavior based on linter settings in the extra folder in the extension directory. 13 | /// This example node uses .net .resx files and generated satellite assemblies to perform runtime lookup of localized content 14 | /// depending on the culture of the system Dynamo is running on. 15 | /// Read more: https://docs.microsoft.com/en-us/dotnet/framework/resources/creating-resource-files-for-desktop-apps 16 | /// You can use the -l "es-ES" flag when starting DynamoSandbox.exe to replace the English strings with Spanish ones. 17 | /// For more info on the CLI interface read more: https://github.com/DynamoDS/Dynamo/wiki/Dynamo-Command-Line-Interface 18 | /// 19 | internal class SampleDropdownInputLinterRule : NodeLinterRule 20 | { 21 | public override string Id => "E4EC24B8-8F87-42B3-874F-A3DB3A69098A"; 22 | public override SeverityCodesEnum SeverityCode => SeverityCodesEnum.Warning; 23 | 24 | public override string Description => Properties.Resources.DropdownDescription; 25 | 26 | public override string CallToAction => Properties.Resources.DropdownDescription; 27 | 28 | public override List EvaluationTriggerEvents => 29 | new List() 30 | { 31 | nameof(NodeModel.IsSetAsInput), 32 | nameof(NodeModel.State), 33 | }; 34 | 35 | 36 | protected override RuleEvaluationStatusEnum EvaluateFunction(NodeModel nodeModel, string changedEvent) 37 | { 38 | if (nodeModel != null) 39 | { 40 | if (nodeModel.NodeType.Equals("ExtensionNode")) 41 | { 42 | if (!nodeModel.IsSetAsInput) 43 | { 44 | return RuleEvaluationStatusEnum.Failed; 45 | } 46 | } 47 | } 48 | 49 | return RuleEvaluationStatusEnum.Passed; 50 | } 51 | 52 | 53 | protected override List> InitFunction(WorkspaceModel workspaceModel) 54 | { 55 | //create a list to hold results information. 56 | //The Tuple should be of a RuleEvaluationStatus and the name of the node 57 | List> results = new List>(); 58 | 59 | //Iterate over all the nodes in the workspace 60 | foreach (NodeModel node in workspaceModel.Nodes) 61 | { 62 | //Call the Evaluate function 63 | var evaluationStatus = EvaluateFunction(node, "initialize"); 64 | 65 | //Check what happened for this node. If it passed the we continue 66 | if (evaluationStatus == RuleEvaluationStatusEnum.Passed) 67 | continue; 68 | 69 | //Create the tuple to return and add it to the result list 70 | var valueTuple = Tuple.Create(evaluationStatus, node.GUID.ToString()); 71 | results.Add(valueTuple); 72 | } 73 | 74 | return results; 75 | } 76 | } 77 | 78 | 79 | } 80 | -------------------------------------------------------------------------------- /src/SampleLinter/Rules/SampleSliderInputLinterRule.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using CoreNodeModels.Input; 4 | using Dynamo.Graph.Nodes; 5 | using Dynamo.Graph.Workspaces; 6 | using Dynamo.Linting.Interfaces; 7 | using Dynamo.Linting.Rules; 8 | 9 | namespace SampleLinter.Rules 10 | { 11 | /// 12 | /// This rule alerts the end user that they might want to do so if the slider is not input or renamed. If a slider is not being used as input, it is typically unnecessary and a number node or a code block would suffice. 13 | /// 14 | internal class SampleSliderInputLinterRule : NodeLinterRule 15 | { 16 | public override string Id => "54EFD003-FF02-41B6-9F2E-52216BA23844"; 17 | public override SeverityCodesEnum SeverityCode => SeverityCodesEnum.Warning; 18 | 19 | public override string Description => Properties.Resources.SlidersDescription; 20 | 21 | public override string CallToAction => Properties.Resources.SlidersCallToAction; 22 | 23 | public override List EvaluationTriggerEvents => 24 | new List() 25 | { 26 | nameof(NodeModel.IsSetAsInput), 27 | nameof(NodeModel.State), 28 | }; 29 | 30 | 31 | protected override RuleEvaluationStatusEnum EvaluateFunction(NodeModel nodeModel, string changedEvent) 32 | { 33 | if (nodeModel != null) 34 | { 35 | if (nodeModel is DoubleSlider || (nodeModel is IntegerSlider64Bit)) 36 | { 37 | if (!nodeModel.IsSetAsInput) 38 | { 39 | return RuleEvaluationStatusEnum.Failed; 40 | } 41 | } 42 | } 43 | 44 | return RuleEvaluationStatusEnum.Passed; 45 | } 46 | 47 | 48 | protected override List> InitFunction(WorkspaceModel workspaceModel) 49 | { 50 | //create a list to hold results information. 51 | //The Tuple should be of a RuleEvaluationStatus and the name of the node 52 | List> results = new List>(); 53 | 54 | //Iterate over all the nodes in the workspace 55 | foreach (NodeModel node in workspaceModel.Nodes) 56 | { 57 | //Call the Evaluate function 58 | var evaluationStatus = EvaluateFunction(node, "initialize"); 59 | 60 | //Check what happened for this node. If it passed the we continue 61 | if (evaluationStatus == RuleEvaluationStatusEnum.Passed) 62 | continue; 63 | 64 | //Create the tuple to return and add it to the result list 65 | var valueTuple = Tuple.Create(evaluationStatus, node.GUID.ToString()); 66 | results.Add(valueTuple); 67 | } 68 | 69 | return results; 70 | } 71 | } 72 | 73 | 74 | } 75 | -------------------------------------------------------------------------------- /src/SampleLinter/SampleLinter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using Dynamo.Extensions; 4 | using Dynamo.Logging; 5 | using SampleLinter.Rules; 6 | 7 | namespace SampleLinter 8 | { 9 | public class SampleLinter : LinterExtensionBase 10 | { 11 | public override string UniqueId => "44BAAD49-4750-47BE-AB60-61DD30962FAE"; //this is unique to this linter 12 | public override string Name => "Sample Linter"; 13 | 14 | 15 | private SampleSliderInputLinterRule _sliderInputRule; 16 | private SampleDropdownInputLinterRule _DropdownRule; 17 | private NoGroupsLinterRule _noGroupsRule; 18 | 19 | private LinterSettings _linterSettings; 20 | 21 | public override void Ready(ReadyParams rp) 22 | { 23 | //load our settings 24 | var extensionDirectory = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location)?.Replace("bin","extra"); 25 | var settingsFile = Path.Combine(extensionDirectory, "LinterSettings.xml"); 26 | //if the settings file exists, use it, if not load with default 5 ungrouped allowed 27 | _linterSettings = File.Exists(settingsFile) ? LinterSettings.DeserializeModels(settingsFile) : new LinterSettings(){AllowedUngroupedNodes = 5}; 28 | 29 | 30 | //since we are inheriting from the LinterExtensionBase we need to mark it as ready here 31 | base.Ready(rp); 32 | 33 | //add each of our rules to the linter 34 | _sliderInputRule = new SampleSliderInputLinterRule(); 35 | AddLinterRule(_sliderInputRule); 36 | 37 | _DropdownRule = new SampleDropdownInputLinterRule(); 38 | AddLinterRule(_DropdownRule); 39 | 40 | _noGroupsRule = new NoGroupsLinterRule(_linterSettings); 41 | AddLinterRule(_noGroupsRule); 42 | } 43 | 44 | 45 | 46 | 47 | public override void Shutdown() 48 | { 49 | RemoveLinterRule(_sliderInputRule); 50 | RemoveLinterRule(_DropdownRule); 51 | RemoveLinterRule(_noGroupsRule); 52 | } 53 | 54 | 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/SampleLinter/SampleLinter.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | SampleLinter 7 | SampleLinter 8 | Copyright © 2023 9 | 2.0.1.0 10 | 2.0.1.0 11 | net8.0 12 | 13 | 14 | true 15 | bin\$(Configuration)\ 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | Always 25 | 26 | 27 | Always 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /src/SampleLinter/SampleLinter_ExtensionDefinition.xml: -------------------------------------------------------------------------------- 1 |  2 | ..\bin\SampleLinter.dll 3 | SampleLinter.SampleLinter 4 | 5 | -------------------------------------------------------------------------------- /src/SampleViewExtension/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("SampleViewExtension")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("SampleViewExtension")] 13 | [assembly: AssemblyCopyright("Copyright © 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("146ebf48-e7a0-4abe-809d-d7f3059e4ee1")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("2.0.1.0")] 36 | [assembly: AssemblyFileVersion("2.0.1.0")] 37 | -------------------------------------------------------------------------------- /src/SampleViewExtension/SampleViewExtension.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows; 3 | using System.Windows.Controls; 4 | using Dynamo.Wpf.Extensions; 5 | 6 | namespace SampleViewExtension 7 | { 8 | /// 9 | /// The View Extension framework for Dynamo allows you to extend 10 | /// the Dynamo UI by registering custom MenuItems. A ViewExtension has 11 | /// two components, an assembly containing a class that implements 12 | /// IViewExtension or extends ViewExtensionBase, and a ViewExtensionDefinition 13 | /// XML file used to instruct Dynamo where to find the class containing the 14 | /// View Extension implementation. The ViewExtensionDefinition XML file must 15 | /// be located in your [dynamo]\viewExtensions folder. 16 | /// 17 | /// This sample demonstrates a View Extension implementation which inherits from 18 | /// ViewExtensionBase. It adds a user interface to Dynamo's extension sidebar 19 | /// when its MenuItem is clicked. 20 | /// The Window created tracks the number of nodes in the current workspace, 21 | /// by handling the workspace's NodeAdded and NodeRemoved events. 22 | /// 23 | public class SampleViewExtension : ViewExtensionBase 24 | { 25 | private MenuItem sampleMenuItem; 26 | 27 | public override void Dispose() 28 | { 29 | } 30 | 31 | public override void Startup(ViewStartupParams p) 32 | { 33 | } 34 | 35 | public override void Loaded(ViewLoadedParams p) 36 | { 37 | // Save a reference to your loaded parameters. 38 | // You'll need these later when you want to use 39 | // the supplied workspaces 40 | 41 | var viewModel = new SampleWindowViewModel(p); 42 | var window = new SampleWindow 43 | { 44 | // Set the data context for the main grid in the window. 45 | MainGrid = { DataContext = viewModel }, 46 | 47 | // Set the owner of the window to the Dynamo window. 48 | Owner = p.DynamoWindow 49 | }; 50 | 51 | sampleMenuItem = new MenuItem { Header = "Show View Extension Sample Window", IsCheckable = true }; 52 | sampleMenuItem.Checked += (sender, args) => p.AddToExtensionsSideBar(this, window); 53 | sampleMenuItem.Unchecked += (sender, args) => p.CloseExtensioninInSideBar(this); 54 | p.AddExtensionMenuItem(sampleMenuItem); 55 | } 56 | 57 | public override void Shutdown() 58 | { 59 | } 60 | 61 | public override void Closed() 62 | { 63 | if (sampleMenuItem != null) 64 | { 65 | sampleMenuItem.IsChecked = false; 66 | } 67 | } 68 | 69 | public override string UniqueId 70 | { 71 | get 72 | { 73 | return "61BB15A8-9B6B-4AB0-8D75-F7C34E0B9112"; 74 | } 75 | } 76 | 77 | public override string Name 78 | { 79 | get 80 | { 81 | return "Sample View Extension"; 82 | } 83 | } 84 | 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/SampleViewExtension/SampleViewExtension.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | SampleViewExtension 7 | SampleViewExtension 8 | 9 | net8.0-windows 10 | true 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | Always 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/SampleViewExtension/SampleViewExtension_ViewExtensionDefinition.xml: -------------------------------------------------------------------------------- 1 |  2 | ..\bin\SampleViewExtension.dll 3 | SampleViewExtension.SampleViewExtension 4 | 5 | -------------------------------------------------------------------------------- /src/SampleViewExtension/SampleWindow.xaml: -------------------------------------------------------------------------------- 1 |  10 | 13 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/SampleViewExtension/SampleWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | 3 | namespace SampleViewExtension 4 | { 5 | /// 6 | /// Interaction logic for SampleWindow.xaml 7 | /// 8 | public partial class SampleWindow : Window 9 | { 10 | public SampleWindow() 11 | { 12 | InitializeComponent(); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/SampleViewExtension/SampleWindowViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Dynamo.Core; 3 | using Dynamo.Extensions; 4 | using Dynamo.Graph.Nodes; 5 | 6 | namespace SampleViewExtension 7 | { 8 | public class SampleWindowViewModel : NotificationObject, IDisposable 9 | { 10 | private string activeNodeTypes; 11 | private ReadyParams readyParams; 12 | 13 | // Displays active nodes in the workspace 14 | public string ActiveNodeTypes 15 | { 16 | get 17 | { 18 | activeNodeTypes = getNodeTypes(); 19 | return activeNodeTypes; 20 | } 21 | } 22 | 23 | // Helper function that builds string of active nodes 24 | public string getNodeTypes() 25 | { 26 | string output = "Active nodes:\n"; 27 | 28 | foreach (NodeModel node in readyParams.CurrentWorkspaceModel.Nodes) 29 | { 30 | string nickName = node.Name; 31 | output += nickName + "\n"; 32 | } 33 | 34 | return output; 35 | } 36 | 37 | public SampleWindowViewModel(ReadyParams p) 38 | { 39 | readyParams = p; 40 | p.CurrentWorkspaceModel.NodeAdded += CurrentWorkspaceModel_NodesChanged; 41 | p.CurrentWorkspaceModel.NodeRemoved += CurrentWorkspaceModel_NodesChanged; 42 | } 43 | 44 | private void CurrentWorkspaceModel_NodesChanged(NodeModel obj) 45 | { 46 | RaisePropertyChanged("ActiveNodeTypes"); 47 | } 48 | 49 | public void Dispose() 50 | { 51 | readyParams.CurrentWorkspaceModel.NodeAdded -= CurrentWorkspaceModel_NodesChanged; 52 | readyParams.CurrentWorkspaceModel.NodeRemoved -= CurrentWorkspaceModel_NodesChanged; 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/SampleZeroTouchUnits/RectangleExample.cs: -------------------------------------------------------------------------------- 1 | using Autodesk.DesignScript.Interfaces; 2 | using Autodesk.DesignScript.Runtime; 3 | using System.Collections.Generic; 4 | using System; 5 | using DynamoUnits; 6 | using Dynamo.Graph.Nodes.CustomNodes; 7 | 8 | namespace SampleZeroTouchUnits 9 | { 10 | /// 11 | /// The RectangleExample class demonstrates 12 | /// how to use the Dynamo Units API to convert between units. 13 | /// 14 | public class RectangleExample 15 | { 16 | const string meters = "autodesk.unit.unit:meters"; 17 | const string meters2 = "autodesk.unit.unit:squareMeters"; 18 | 19 | /// 20 | /// The Length value 21 | /// 22 | private readonly double Length; 23 | 24 | /// 25 | /// The Width value 26 | /// 27 | private readonly double Width; 28 | 29 | private Unit LengthUnit; 30 | private Unit WidthUnit; 31 | private Unit AreaUnit; 32 | 33 | /// 34 | /// Creates an instance of RectangleExample with all units defaulted to metric 35 | /// 36 | /// The width of RectangleExample, defaulted to meters 37 | /// The length of RectangleExample, defaulted to meters 38 | public RectangleExample(double width, double length) 39 | { 40 | Length = length; 41 | Width = width; 42 | LengthUnit = Unit.ByTypeID($"{meters}-1.0.1"); 43 | WidthUnit = Unit.ByTypeID($"{meters}-1.0.1"); 44 | AreaUnit = Unit.ByTypeID($"{meters2}-1.0.1"); 45 | } 46 | 47 | /// 48 | /// Creates an instance of RectangleExample with customizable untis 49 | /// 50 | /// The width of RectangleExample 51 | /// The length of RectangleExample 52 | /// The unit for width 53 | /// The unit for length 54 | public RectangleExample(double width, double length, Unit widthUnit, Unit lengthUnit) 55 | { 56 | Width = width; 57 | Length = length; 58 | 59 | LengthUnit = lengthUnit; 60 | WidthUnit = widthUnit; 61 | 62 | AreaUnit = Unit.ByTypeID($"{meters2}-1.0.1"); 63 | } 64 | 65 | /// 66 | /// Get the length converted to a target unit. 67 | /// 68 | /// The target unit. Defaults to null 69 | /// 70 | /// 71 | public double GetLength(Unit targetUnit = null) 72 | { 73 | targetUnit ??= LengthUnit; 74 | ArgumentNullException.ThrowIfNull(targetUnit); 75 | 76 | if (!Unit.AreUnitsConvertible(LengthUnit, targetUnit)) 77 | { 78 | throw new ArgumentException($"{LengthUnit} is not convertible to {targetUnit}"); 79 | } 80 | 81 | var output = Utilities.ConvertByUnits(Length, LengthUnit, targetUnit); 82 | return output; 83 | } 84 | 85 | /// 86 | /// Get the width converted to a target unit. 87 | /// 88 | /// The target unit. Defaults to null 89 | /// 90 | /// 91 | public double GetWidth(Unit targetUnit) 92 | { 93 | targetUnit ??= WidthUnit; 94 | ArgumentNullException.ThrowIfNull(targetUnit); 95 | if (!Unit.AreUnitsConvertible(WidthUnit, targetUnit)) 96 | { 97 | throw new ArgumentException($"{LengthUnit} is not convertible to {targetUnit}"); 98 | } 99 | 100 | var output = Utilities.ConvertByUnits(Length, WidthUnit, targetUnit); 101 | return output; 102 | } 103 | 104 | string GetFirstSymbolText(Unit unit) 105 | { 106 | var symbols = DynamoUnits.Symbol.SymbolsByUnit(unit); 107 | foreach (var symbol in symbols) 108 | { 109 | return symbol.Text; 110 | } 111 | return string.Empty; 112 | } 113 | 114 | /// 115 | /// Get the area of the rectangle. Computed as width * length 116 | /// 117 | /// The target unit for the area value, defaults to null 118 | /// A string containing the area value and unit symbol. Ex. "100ft^2" 119 | /// 120 | public string GetArea(Unit targetUnit = null) 121 | { 122 | targetUnit ??= AreaUnit; 123 | if (!Unit.AreUnitsConvertible(AreaUnit, targetUnit)) 124 | { 125 | throw new ArgumentException($"{targetUnit.Name} is not a valid area unit"); 126 | } 127 | 128 | double area = Utilities.ParseExpressionByUnit(targetUnit, $"{Length}{GetFirstSymbolText(LengthUnit)} * {Width}{GetFirstSymbolText(WidthUnit)}"); 129 | return $"{area}{GetFirstSymbolText(targetUnit)}"; 130 | } 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/SampleZeroTouchUnits/SampleZeroTouchUnits.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | Properties 7 | SampleZeroTouchUnits 8 | SampleZeroTouchUnits 9 | net8.0 10 | 11 | 12 | true 13 | bin\$(Configuration)\SampleZeroTouchUnits.XML 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/build.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | DynamoSamples.sln 8 | 9 | 10 | 11 | 12 | Configuration=Release;Platform=Any CPU 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | --------------------------------------------------------------------------------